Compare commits
13 Commits
revert-mod
...
fix-storyb
Author | SHA1 | Date | |
---|---|---|---|
![]() |
5d4ab609f5 | ||
![]() |
0370b4dfab | ||
![]() |
a516557bb6 | ||
![]() |
7c4e2b658d | ||
![]() |
bb2eb57a35 | ||
![]() |
698fa84b5a | ||
![]() |
2184323ae7 | ||
![]() |
0ba5edc6aa | ||
![]() |
3fde3fbc4d | ||
![]() |
24a0063af0 | ||
![]() |
74e565b71c | ||
![]() |
6ed7d1a76e | ||
![]() |
c277934328 |
@@ -30,10 +30,6 @@ url: https://example.tld/
|
|||||||
# The port that your Misskey server should listen on.
|
# The port that your Misskey server should listen on.
|
||||||
port: 3000
|
port: 3000
|
||||||
|
|
||||||
# You can also use UNIX domain socket.
|
|
||||||
# socket: /path/to/misskey.sock
|
|
||||||
# chmodSocket: '777'
|
|
||||||
|
|
||||||
# ┌──────────────────────────┐
|
# ┌──────────────────────────┐
|
||||||
#───┘ PostgreSQL configuration └────────────────────────────────
|
#───┘ PostgreSQL configuration └────────────────────────────────
|
||||||
|
|
||||||
@@ -82,8 +78,6 @@ redis:
|
|||||||
#pass: example-pass
|
#pass: example-pass
|
||||||
#prefix: example-prefix
|
#prefix: example-prefix
|
||||||
#db: 1
|
#db: 1
|
||||||
# You can specify more ioredis options...
|
|
||||||
#username: example-username
|
|
||||||
|
|
||||||
#redisForPubsub:
|
#redisForPubsub:
|
||||||
# host: localhost
|
# host: localhost
|
||||||
@@ -92,8 +86,6 @@ redis:
|
|||||||
# #pass: example-pass
|
# #pass: example-pass
|
||||||
# #prefix: example-prefix
|
# #prefix: example-prefix
|
||||||
# #db: 1
|
# #db: 1
|
||||||
# # You can specify more ioredis options...
|
|
||||||
# #username: example-username
|
|
||||||
|
|
||||||
#redisForJobQueue:
|
#redisForJobQueue:
|
||||||
# host: localhost
|
# host: localhost
|
||||||
@@ -102,8 +94,6 @@ redis:
|
|||||||
# #pass: example-pass
|
# #pass: example-pass
|
||||||
# #prefix: example-prefix
|
# #prefix: example-prefix
|
||||||
# #db: 1
|
# #db: 1
|
||||||
# # You can specify more ioredis options...
|
|
||||||
# #username: example-username
|
|
||||||
|
|
||||||
# ┌───────────────────────────┐
|
# ┌───────────────────────────┐
|
||||||
#───┘ MeiliSearch configuration └─────────────────────────────
|
#───┘ MeiliSearch configuration └─────────────────────────────
|
||||||
@@ -114,7 +104,6 @@ redis:
|
|||||||
# apiKey: ''
|
# apiKey: ''
|
||||||
# ssl: true
|
# ssl: true
|
||||||
# index: ''
|
# index: ''
|
||||||
# scope: local
|
|
||||||
|
|
||||||
# ┌───────────────┐
|
# ┌───────────────┐
|
||||||
#───┘ ID generation └───────────────────────────────────────────
|
#───┘ ID generation └───────────────────────────────────────────
|
||||||
|
48
CHANGELOG.md
48
CHANGELOG.md
@@ -8,30 +8,13 @@
|
|||||||
-
|
-
|
||||||
|
|
||||||
### Server
|
### Server
|
||||||
- Fix: 外部サーバーの投稿がタイムラインに表示されないことがある問題を修正
|
-
|
||||||
|
|
||||||
-->
|
-->
|
||||||
|
|
||||||
## 13.x.x (unreleased)
|
## 13.x.x (unreleased)
|
||||||
|
|
||||||
### General
|
### General
|
||||||
-
|
|
||||||
|
|
||||||
### Client
|
|
||||||
- リストTLで、ユーザーが追加・削除されてもTLを初期化しないように
|
|
||||||
- Fix: モバイル表示のときページ下部がナビゲーションバーに隠れる問題を修正
|
|
||||||
- Fix: Selecting all emojis in Custom emoji is impossible
|
|
||||||
|
|
||||||
### Server
|
|
||||||
- Fix: APIのオフセットが壊れていたせいで「もっと見る」でもっと見れない問題を修正
|
|
||||||
|
|
||||||
## 13.14.1
|
|
||||||
|
|
||||||
### General
|
|
||||||
- 招待機能を改善しました
|
|
||||||
* 過去に発行した招待コードを確認できるようになりました
|
|
||||||
* ロールごとに招待コードの発行数制限と制限対象期間、有効期限を設定できるようになりました
|
|
||||||
* 招待コードを作成したユーザーと使用したユーザーを確認できるようになりました
|
|
||||||
- ユーザーにロールが期限付きでアサインされている場合、その期限をユーザーのモデレーションページで確認できるようになりました
|
|
||||||
- identicon生成を無効にしてパフォーマンスを向上させることができるようになりました
|
- identicon生成を無効にしてパフォーマンスを向上させることができるようになりました
|
||||||
- サーバーのマシン情報の公開を無効にしてパフォーマンスを向上させることができるようになりました
|
- サーバーのマシン情報の公開を無効にしてパフォーマンスを向上させることができるようになりました
|
||||||
|
|
||||||
@@ -39,25 +22,15 @@
|
|||||||
- deck UIのカラムのメニューからアンテナとリストの編集画面を開けるように
|
- deck UIのカラムのメニューからアンテナとリストの編集画面を開けるように
|
||||||
- ドライブファイルのメニューで画像をクロップできるように
|
- ドライブファイルのメニューで画像をクロップできるように
|
||||||
- 画像を動画と同様に簡単に隠せるように
|
- 画像を動画と同様に簡単に隠せるように
|
||||||
- Enhance: ノートの埋め込みが複数画像と動画を表示されるように
|
|
||||||
- オリジナル画像を保持せずにアップロードする場合webpでアップロードされるように(Safari以外)
|
- オリジナル画像を保持せずにアップロードする場合webpでアップロードされるように(Safari以外)
|
||||||
- 見たことのあるRenoteを省略して表示をオンのときに自分のnoteのrenoteを省略するように
|
- 見たことのあるRenoteを省略して表示をオンのときに自分のnoteのrenoteを省略するように
|
||||||
- フォルダーやファイルに対しても開発者モード使用時、IDをコピーできるように
|
- フォルダーやファイルに対しても開発者モード使用時、IDをコピーできるように
|
||||||
- 引用対象を「もっと見る」で展開した場合、「閉じる」で畳めるように
|
- 引用対象を「もっと見る」で展開した場合、「閉じる」で畳めるように
|
||||||
- プロフィールURLをコピーできるボタンを追加 #11190
|
- プロフィールURLをコピーできるボタンを追加 #11190
|
||||||
- `CURRENT_URL`で現在表示中のURLを取得できるように(AiScript)
|
|
||||||
- ユーザーのContextMenuに「アンテナに追加」ボタンを追加
|
- ユーザーのContextMenuに「アンテナに追加」ボタンを追加
|
||||||
- フォローやお気に入り登録をしていないチャンネルを開く時は概要ページを開くように
|
- フォローやお気に入り登録をしていないチャンネルを開く時は概要ページを開くように
|
||||||
- 画面ビューワをタップした場合、マウスクリックと同様に画像ビューワを閉じるように
|
- 画面ビューワをタップした場合、マウスクリックと同様に画像ビューワを閉じるように
|
||||||
- オフライン時の画面にリロードボタンを追加
|
- オフライン時の画面にリロードボタンを追加
|
||||||
- Renote時に公開範囲のデフォルト設定が適用されるように
|
|
||||||
- Deckで非ルートページにアクセスした際に簡易UIで表示しない設定を追加
|
|
||||||
- ロール設定画面でロールIDを確認できるように
|
|
||||||
- コンテキストメニュー表示時のパフォーマンスを改善
|
|
||||||
- フォロー/フォロワー非公開時の表示を改善
|
|
||||||
- 本文にMFMが含まれている場合に自動でたたまれる機能が、返信先や引用RNにも適用されるように
|
|
||||||
- position は対象外になりました
|
|
||||||
- AiScriptを0.15.0に更新
|
|
||||||
- Fix: サーバーメトリクスが90度傾いている
|
- Fix: サーバーメトリクスが90度傾いている
|
||||||
- Fix: 非ログイン時にクレデンシャルが必要なページに行くとエラーが出る問題を修正
|
- Fix: 非ログイン時にクレデンシャルが必要なページに行くとエラーが出る問題を修正
|
||||||
- Fix: sparkle内にリンクを入れるとクリック不能になる問題の修正
|
- Fix: sparkle内にリンクを入れるとクリック不能になる問題の修正
|
||||||
@@ -66,27 +39,14 @@
|
|||||||
- Fix: フォルダーのページネーションが機能しない #11180
|
- Fix: フォルダーのページネーションが機能しない #11180
|
||||||
- Fix: 長い文章を投稿する際、プレビューが画面からはみ出る問題を修正
|
- Fix: 長い文章を投稿する際、プレビューが画面からはみ出る問題を修正
|
||||||
- Fix: システムフォント設定が正しく反映されない問題を修正
|
- Fix: システムフォント設定が正しく反映されない問題を修正
|
||||||
- Fix: アンケート終了時のプッシュ通知が正しく表示されない問題を修正
|
|
||||||
- Fix: MasterVolumeが0の時だけでなく各通知音の音量設定が0のときも、HTMLAudioElement.playが実行されないように変更
|
|
||||||
|
|
||||||
### Server
|
### Server
|
||||||
- JSON.parse の回数を削減することで、ストリーミングのパフォーマンスを向上しました
|
- JSON.parse の回数を削減することで、ストリーミングのパフォーマンスを向上しました
|
||||||
- nsfwjs のモデルロードを排他することで、重複ロードによってメモリ使用量が増加しないように
|
- nsfwjs のモデルロードを排他することで、重複ロードによってメモリ使用量が増加しないように
|
||||||
- 連合の配送ジョブのパフォーマンスを向上(ロック機構の見直し、Redisキャッシュの活用)
|
- 連合の配送ジョブのパフォーマンスを向上(ロック機構の見直し、Redisキャッシュの活用)
|
||||||
|
- 全体的なDBクエリのパフォーマンスを向上
|
||||||
- featuredノートのsignedGet回数を減らしました
|
- featuredノートのsignedGet回数を減らしました
|
||||||
- ActivityPubの署名用鍵長を2048bitに変更しパフォーマンスを向上(新規アカウントのみ)
|
- リモートサーバーからのNSFW映像のキャッシュだけを無効化できるオプションを追加しました
|
||||||
- リモートサーバーのセンシティブなファイルのキャッシュだけを無効化できるオプションを追加
|
|
||||||
- MeilisearchにIndexするノートの範囲を設定できるように
|
|
||||||
- Export notes with file detail
|
|
||||||
- Add unix socket support
|
|
||||||
- 設定ファイルでioredisの全てのオプションを指定可能に
|
|
||||||
- Fix: エクスポートしたカスタム絵文字のzipが大きいと読み込めない問題を修正
|
|
||||||
- Fix: リモートサーバーに無意味なActivityPubの配信を行うことがあるのを修正
|
|
||||||
- Fix: Remove Meilisearch index when notes are deleted
|
|
||||||
- Fix: 非英語環境でのPostgreSQLのエラーハンドリングを修正
|
|
||||||
- Fix: インスタンスのアイコンがbase64の場合の挙動を修正
|
|
||||||
- Fix: ローカルの `Person` を指す `acct` URI を解析するときのバグを修正しました
|
|
||||||
- Fix: 無効化されたアンテナが再度有効化されないことがある問題を修正
|
|
||||||
|
|
||||||
## 13.13.2
|
## 13.13.2
|
||||||
|
|
||||||
|
@@ -214,13 +214,30 @@ Misskey uses [Storybook](https://storybook.js.org/) for UI development.
|
|||||||
|
|
||||||
### Setup & Run
|
### Setup & Run
|
||||||
|
|
||||||
#### Setup
|
#### Universal
|
||||||
|
|
||||||
|
##### Setup
|
||||||
|
|
||||||
|
```bash
|
||||||
|
pnpm --filter misskey-js build
|
||||||
|
pnpm --filter frontend tsc -p .storybook && (node packages/frontend/.storybook/preload-locale.js & node packages/frontend/.storybook/preload-theme.js)
|
||||||
|
```
|
||||||
|
|
||||||
|
##### Run
|
||||||
|
|
||||||
|
```bash
|
||||||
|
node packages/frontend/.storybook/generate.js && pnpm --filter frontend storybook dev
|
||||||
|
```
|
||||||
|
|
||||||
|
#### macOS & Linux
|
||||||
|
|
||||||
|
##### Setup
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
pnpm --filter misskey-js build
|
pnpm --filter misskey-js build
|
||||||
```
|
```
|
||||||
|
|
||||||
#### Run
|
##### Run
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
pnpm --filter frontend storybook-dev
|
pnpm --filter frontend storybook-dev
|
||||||
|
@@ -54,7 +54,6 @@ describe('After setup instance', () => {
|
|||||||
cy.get('[data-cy-signup]').click();
|
cy.get('[data-cy-signup]').click();
|
||||||
cy.get('[data-cy-signup-rules-continue]').should('be.disabled');
|
cy.get('[data-cy-signup-rules-continue]').should('be.disabled');
|
||||||
cy.get('[data-cy-signup-rules-notes-agree] [data-cy-switch-toggle]').click();
|
cy.get('[data-cy-signup-rules-notes-agree] [data-cy-switch-toggle]').click();
|
||||||
cy.get('[data-cy-modal-dialog-ok]').click();
|
|
||||||
cy.get('[data-cy-signup-rules-continue]').should('not.be.disabled');
|
cy.get('[data-cy-signup-rules-continue]').should('not.be.disabled');
|
||||||
cy.get('[data-cy-signup-rules-continue]').click();
|
cy.get('[data-cy-signup-rules-continue]').click();
|
||||||
|
|
||||||
@@ -79,7 +78,6 @@ describe('After setup instance', () => {
|
|||||||
cy.get('[data-cy-signup]').click();
|
cy.get('[data-cy-signup]').click();
|
||||||
cy.get('[data-cy-signup-rules-continue]').should('be.disabled');
|
cy.get('[data-cy-signup-rules-continue]').should('be.disabled');
|
||||||
cy.get('[data-cy-signup-rules-notes-agree] [data-cy-switch-toggle]').click();
|
cy.get('[data-cy-signup-rules-notes-agree] [data-cy-switch-toggle]').click();
|
||||||
cy.get('[data-cy-modal-dialog-ok]').click();
|
|
||||||
cy.get('[data-cy-signup-rules-continue]').should('not.be.disabled');
|
cy.get('[data-cy-signup-rules-continue]').should('not.be.disabled');
|
||||||
cy.get('[data-cy-signup-rules-continue]').click();
|
cy.get('[data-cy-signup-rules-continue]').click();
|
||||||
|
|
||||||
|
@@ -41,23 +41,19 @@ unfavorite: "إزالة من المفضلة"
|
|||||||
favorited: "أُضيف إلى المفضلة."
|
favorited: "أُضيف إلى المفضلة."
|
||||||
alreadyFavorited: "تمت إضافته بالفعل إلى المفضلة."
|
alreadyFavorited: "تمت إضافته بالفعل إلى المفضلة."
|
||||||
cantFavorite: "تعذرت الإضافة إلى المفضلة."
|
cantFavorite: "تعذرت الإضافة إلى المفضلة."
|
||||||
pin: "ثبتها على الصفحة الشخصية"
|
pin: "دبّسها على الصفحة الشخصية"
|
||||||
unpin: "فكها من ملفك الشخصي"
|
unpin: "ألغ تدبيسها من ملفك الشخصي"
|
||||||
copyContent: "انسخ المحتوى"
|
copyContent: "انسخ المحتوى"
|
||||||
copyLink: "انسخ الرابط"
|
copyLink: "انسخ الرابط"
|
||||||
delete: "حذف"
|
delete: "حذف"
|
||||||
deleteAndEdit: "إزالة وإعادة الصياغة"
|
deleteAndEdit: "إزالة وإعادة الصياغة"
|
||||||
deleteAndEditConfirm: "أمتأكد من حذف الملاحظة؟ ستفقد كل مشاركاتها، والتفاعلات، والردود عليها."
|
deleteAndEditConfirm: "أمتأكد من حذف الملاحظة؟ ستفقد كل مشاركاتها، والتفاعلات، والردود عليها."
|
||||||
addToList: "أضفه إلى قائمة"
|
addToList: "أضفه إلى قائمة"
|
||||||
addToAntenna: "أضف إلى هوائي"
|
|
||||||
sendMessage: "أرسل رسالة"
|
sendMessage: "أرسل رسالة"
|
||||||
copyRSS: "انسخ رابط RSS"
|
copyRSS: "انسخ رابط RSS"
|
||||||
copyUsername: "انسخ اسم المستخدم"
|
copyUsername: "انسخ اسم المستخدم"
|
||||||
copyUserId: "انسخ معرف المستخدم"
|
copyUserId: "انسخ معرف المستخدم"
|
||||||
copyNoteId: "انسخ معرف الملاحظة"
|
copyNoteId: "انسخ معرف الملاحظة"
|
||||||
copyFileId: "انسخ معرّف الملف"
|
|
||||||
copyFolderId: "انسخ معرّف المجلد"
|
|
||||||
copyProfileUrl: "انسخ رابط الملف الشخصي"
|
|
||||||
searchUser: "ابحث عن مستخدمين"
|
searchUser: "ابحث عن مستخدمين"
|
||||||
reply: "رد"
|
reply: "رد"
|
||||||
loadMore: "عرض المزيد"
|
loadMore: "عرض المزيد"
|
||||||
@@ -112,8 +108,8 @@ cantReRenote: "لا يمكنك إعادة نشر ملاحظة معاد نشره
|
|||||||
quote: "اقتبس"
|
quote: "اقتبس"
|
||||||
inChannelRenote: "إعادة نشر في قناة"
|
inChannelRenote: "إعادة نشر في قناة"
|
||||||
inChannelQuote: "اقتباس في قناة"
|
inChannelQuote: "اقتباس في قناة"
|
||||||
pinnedNote: "ملاحظة مثبتة"
|
pinnedNote: "ملاحظة مدبسة"
|
||||||
pinned: "ثبتها على الصفحة الشخصية"
|
pinned: "دبّسها على الصفحة الشخصية"
|
||||||
you: "أنت"
|
you: "أنت"
|
||||||
clickToShow: "اضغط للعرض"
|
clickToShow: "اضغط للعرض"
|
||||||
sensitive: "محتوى حساس"
|
sensitive: "محتوى حساس"
|
||||||
@@ -140,10 +136,8 @@ unblockConfirm: "أمتأكد من إلغاء حجب هذا الحساب؟"
|
|||||||
suspendConfirm: "أمتأكد من تعليق الحساب؟"
|
suspendConfirm: "أمتأكد من تعليق الحساب؟"
|
||||||
unsuspendConfirm: "أمتأكد من إلغاء تعليق؟"
|
unsuspendConfirm: "أمتأكد من إلغاء تعليق؟"
|
||||||
selectList: "اختر قائمة"
|
selectList: "اختر قائمة"
|
||||||
editList: "عدّل القائمة"
|
|
||||||
selectChannel: "اختر قناة"
|
selectChannel: "اختر قناة"
|
||||||
selectAntenna: "اختر هوائيًا"
|
selectAntenna: "اختر هوائيًا"
|
||||||
editAntenna: "عدّل الهوائي"
|
|
||||||
selectWidget: "اختر ودجة"
|
selectWidget: "اختر ودجة"
|
||||||
editWidgets: "عدّل الودجات"
|
editWidgets: "عدّل الودجات"
|
||||||
editWidgetsExit: "تم"
|
editWidgetsExit: "تم"
|
||||||
@@ -214,7 +208,7 @@ blockedUsers: "الحسابات المحجوبة"
|
|||||||
noUsers: "ليس هناك مستخدمون"
|
noUsers: "ليس هناك مستخدمون"
|
||||||
editProfile: "تعديل الملف التعريفي"
|
editProfile: "تعديل الملف التعريفي"
|
||||||
noteDeleteConfirm: "هل تريد حذف هذه الملاحظة؟"
|
noteDeleteConfirm: "هل تريد حذف هذه الملاحظة؟"
|
||||||
pinLimitExceeded: "لا يمكنك تثبيت الملاحظات بعد الآن."
|
pinLimitExceeded: "لا يمكنك تدبيس الملاحظات بعد الآن."
|
||||||
intro: "لقد انتهت عملية تنصيب Misskey. الرجاء إنشاء حساب إداري."
|
intro: "لقد انتهت عملية تنصيب Misskey. الرجاء إنشاء حساب إداري."
|
||||||
done: "تمّ"
|
done: "تمّ"
|
||||||
processing: "المعالجة جارية"
|
processing: "المعالجة جارية"
|
||||||
@@ -313,7 +307,6 @@ copyUrl: "انسخ الرابط"
|
|||||||
rename: "إعادة التسمية"
|
rename: "إعادة التسمية"
|
||||||
avatar: "الصورة الرمزية"
|
avatar: "الصورة الرمزية"
|
||||||
banner: "الصورة الرأسية"
|
banner: "الصورة الرأسية"
|
||||||
displayOfSensitiveMedia: "عرض المحتوى الحساس"
|
|
||||||
whenServerDisconnected: "عند فقدان الاتصال بالخادم"
|
whenServerDisconnected: "عند فقدان الاتصال بالخادم"
|
||||||
disconnectedFromServer: "قُطِع الإتصال بالخادم"
|
disconnectedFromServer: "قُطِع الإتصال بالخادم"
|
||||||
reload: "انعش"
|
reload: "انعش"
|
||||||
@@ -352,12 +345,12 @@ iconUrl: "رابط الأيقونة"
|
|||||||
bannerUrl: "رابط صورة اللافتة"
|
bannerUrl: "رابط صورة اللافتة"
|
||||||
backgroundImageUrl: "رابط صورة الخلفية"
|
backgroundImageUrl: "رابط صورة الخلفية"
|
||||||
basicInfo: "المعلومات الأساسية "
|
basicInfo: "المعلومات الأساسية "
|
||||||
pinnedUsers: "المستخدمون المثبتون"
|
pinnedUsers: "المستخدمون المدبسون"
|
||||||
pinnedUsersDescription: "قائمة المستخدمين المثبتين في لسان \"استكشف\" ، اجعل كل اسم مستخدم في سطر لوحده."
|
pinnedUsersDescription: "قائمة المستخدمين المدبسين في لسان \"استكشف\" ، اجعل كل اسم مستخدم في سطر لوحده."
|
||||||
pinnedPages: "الصفحات المثبتة"
|
pinnedPages: "الصفحات المدبسة"
|
||||||
pinnedPagesDescription: "أدخل مسار الصفحات التي تريد تثبيتها في أعلى هذا الموقع، اجعل كل مسار في سطر لوحده."
|
pinnedPagesDescription: "أدخل مسار الصفحات التي تريد تدبيسها في أعلى هذا الموقع، اجعل كل مسار في سطر لوحده."
|
||||||
pinnedClipId: "معرّف المشبك المثبت"
|
pinnedClipId: "معرّف المشبك المدبس"
|
||||||
pinnedNotes: "ملاحظة مثبتة"
|
pinnedNotes: "ملاحظة مدبسة"
|
||||||
hcaptcha: "hCaptcha"
|
hcaptcha: "hCaptcha"
|
||||||
enableHcaptcha: "فعّل hCaptcha"
|
enableHcaptcha: "فعّل hCaptcha"
|
||||||
hcaptchaSiteKey: "مفتاح الموقع"
|
hcaptchaSiteKey: "مفتاح الموقع"
|
||||||
@@ -736,7 +729,7 @@ unlikeConfirm: "أتريد إلغاء إعجابك؟"
|
|||||||
fullView: "ملء الشاشة"
|
fullView: "ملء الشاشة"
|
||||||
quitFullView: "اخرج من وضع ملء للشاشة"
|
quitFullView: "اخرج من وضع ملء للشاشة"
|
||||||
addDescription: "أضف وصفًا"
|
addDescription: "أضف وصفًا"
|
||||||
userPagePinTip: "لعرض ملاحظة هنا اختر \"ثبتها على الصفحة الشخصية\" من قائمة تلك الملاحظة."
|
userPagePinTip: "لعرض ملاحظة هنا اختر \"دبسها على الصفحة الشخصية\" من قائمة تلك الملاحظة."
|
||||||
notSpecifiedMentionWarning: "في الملاحظة ذكر لمستخدمين لن يستلموها."
|
notSpecifiedMentionWarning: "في الملاحظة ذكر لمستخدمين لن يستلموها."
|
||||||
info: "عن"
|
info: "عن"
|
||||||
userInfo: "معلومات المستخدم"
|
userInfo: "معلومات المستخدم"
|
||||||
@@ -842,9 +835,6 @@ oneDay: "يوم"
|
|||||||
oneWeek: "أسبوع"
|
oneWeek: "أسبوع"
|
||||||
oneMonth: "شهر"
|
oneMonth: "شهر"
|
||||||
failedToFetchAccountInformation: "تعذر جلب معلومات الحساب"
|
failedToFetchAccountInformation: "تعذر جلب معلومات الحساب"
|
||||||
cropImage: "اقتصاص الصورة"
|
|
||||||
cropImageAsk: "أتريد اقتصاص هذه الصورة"
|
|
||||||
cropYes: "اقتص"
|
|
||||||
cropNo: "استخدمها كما هي"
|
cropNo: "استخدمها كما هي"
|
||||||
file: "الملفات"
|
file: "الملفات"
|
||||||
recentNHours: "آخر {n} ساعة"
|
recentNHours: "آخر {n} ساعة"
|
||||||
@@ -855,12 +845,10 @@ recommended: "مقترح"
|
|||||||
driveCapOverrideLabel: "غيّر حجم قرص التخزين لهذا المستخدم"
|
driveCapOverrideLabel: "غيّر حجم قرص التخزين لهذا المستخدم"
|
||||||
driveCapOverrideCaption: "أعد الحجم إلى القيمة الافتراضية بإدخال 0 أو أقل."
|
driveCapOverrideCaption: "أعد الحجم إلى القيمة الافتراضية بإدخال 0 أو أقل."
|
||||||
requireAdminForView: "لاستعراض هذه الصفحة وجب عليك الولوج كمدير."
|
requireAdminForView: "لاستعراض هذه الصفحة وجب عليك الولوج كمدير."
|
||||||
isSystemAccount: "حساب أنشأه النظام ويُدار من قِبله."
|
|
||||||
typeToConfirm: "أدخل {x} للتأكيد"
|
typeToConfirm: "أدخل {x} للتأكيد"
|
||||||
deleteAccount: "احذف الحساب"
|
deleteAccount: "احذف الحساب"
|
||||||
document: "التوثيق"
|
document: "التوثيق"
|
||||||
numberOfPageCache: "عدد الصفحات المخزنة مؤقتًا"
|
numberOfPageCache: "عدد الصفحات المخزنة مؤقتًا"
|
||||||
numberOfPageCacheDescription: "رفع الرقم سيسحن تجربة المستخدم لكن سيرفع استهلاك الذاكرة."
|
|
||||||
logoutConfirm: "أتريد الخروج؟"
|
logoutConfirm: "أتريد الخروج؟"
|
||||||
lastActiveDate: "آخر استخدام"
|
lastActiveDate: "آخر استخدام"
|
||||||
statusbar: "شريط الحالة"
|
statusbar: "شريط الحالة"
|
||||||
@@ -919,7 +907,6 @@ color: "اللون"
|
|||||||
manageCustomEmojis: "إدارة الإيموجي المخصصة"
|
manageCustomEmojis: "إدارة الإيموجي المخصصة"
|
||||||
youCannotCreateAnymore: "وصلت لسقف الإنشاء."
|
youCannotCreateAnymore: "وصلت لسقف الإنشاء."
|
||||||
cannotPerformTemporary: "غير متاح مؤقتاً"
|
cannotPerformTemporary: "غير متاح مؤقتاً"
|
||||||
invalidParamError: "معاملات غير صالحة"
|
|
||||||
permissionDeniedError: "رُفضة العملية"
|
permissionDeniedError: "رُفضة العملية"
|
||||||
preset: "إعدادات مسبقة"
|
preset: "إعدادات مسبقة"
|
||||||
selectFromPresets: "اختر من الإعدادات المسبقة"
|
selectFromPresets: "اختر من الإعدادات المسبقة"
|
||||||
@@ -993,10 +980,6 @@ _initialAccountSetting:
|
|||||||
profileSetting: "إعدادات الملف الشخصي"
|
profileSetting: "إعدادات الملف الشخصي"
|
||||||
privacySetting: "إعدادات الخصوصية"
|
privacySetting: "إعدادات الخصوصية"
|
||||||
theseSettingsCanEditLater: "يمكنك تغيير هذه الإعدادات لاحقًا."
|
theseSettingsCanEditLater: "يمكنك تغيير هذه الإعدادات لاحقًا."
|
||||||
skipAreYouSure: "أتريد تخطي إعداد الملف الشخصي؟"
|
|
||||||
laterAreYouSure: "أتريد إعداد الملف الشخصي لاحقًا؟"
|
|
||||||
_serverRules:
|
|
||||||
description: "مجموعة من القواعد لعرضها عند التسجيل، من المستحسن كتابة ملخصٍ للشروط الخدمة."
|
|
||||||
_accountMigration:
|
_accountMigration:
|
||||||
moveFrom: "انقل حسابًا آخر لهذا الحساب"
|
moveFrom: "انقل حسابًا آخر لهذا الحساب"
|
||||||
moveFromLabel: "الحساب الأصلي #{n}"
|
moveFromLabel: "الحساب الأصلي #{n}"
|
||||||
@@ -1080,7 +1063,6 @@ _role:
|
|||||||
high: "عالية"
|
high: "عالية"
|
||||||
_options:
|
_options:
|
||||||
canManageCustomEmojis: "إدارة الإيموجي المخصصة"
|
canManageCustomEmojis: "إدارة الإيموجي المخصصة"
|
||||||
pinMax: "حد عدد الملاحظات المثبتة"
|
|
||||||
_condition:
|
_condition:
|
||||||
isLocal: "مستخدم محلي"
|
isLocal: "مستخدم محلي"
|
||||||
isRemote: "مستخدم بعيد"
|
isRemote: "مستخدم بعيد"
|
||||||
@@ -1457,7 +1439,7 @@ _pages:
|
|||||||
url: "رابط الصفحة"
|
url: "رابط الصفحة"
|
||||||
summary: "ملخص الصفحة"
|
summary: "ملخص الصفحة"
|
||||||
alignCenter: "توسيط العناصر"
|
alignCenter: "توسيط العناصر"
|
||||||
hideTitleWhenPinned: "اخف عنوان الصفحة عند تثبيتها في ملف الشخصي"
|
hideTitleWhenPinned: "اخف عنوان الصفحة عند تدبيسها في ملف الشخصي"
|
||||||
font: "الخط"
|
font: "الخط"
|
||||||
fontSerif: "Serif"
|
fontSerif: "Serif"
|
||||||
fontSansSerif: "Sans Serif"
|
fontSansSerif: "Sans Serif"
|
||||||
|
@@ -2,7 +2,6 @@
|
|||||||
_lang_: "Čeština"
|
_lang_: "Čeština"
|
||||||
headlineMisskey: "Síť propojená poznámkami"
|
headlineMisskey: "Síť propojená poznámkami"
|
||||||
introMisskey: "Vítejte! Misskey je otevřený a decentralizovaný microblogový servis.\n\"Poznámkami\" můžete sdílet co se zrovna děje se všemi ve Vašem okolí. 📡\nPomocí \"reakcí\" můžete sdílet své názory a pocity na ostatní poznámky. 👍\nPojďte objevovat nový svět! 🚀"
|
introMisskey: "Vítejte! Misskey je otevřený a decentralizovaný microblogový servis.\n\"Poznámkami\" můžete sdílet co se zrovna děje se všemi ve Vašem okolí. 📡\nPomocí \"reakcí\" můžete sdílet své názory a pocity na ostatní poznámky. 👍\nPojďte objevovat nový svět! 🚀"
|
||||||
poweredByMisskeyDescription: "{name} je jeden ze serverů využívající open source platformu <b>Misskey<b> (nazývaná \"Misskey instance\")."
|
|
||||||
monthAndDay: "{day}. {month}."
|
monthAndDay: "{day}. {month}."
|
||||||
search: "Vyhledávání"
|
search: "Vyhledávání"
|
||||||
notifications: "Oznámení"
|
notifications: "Oznámení"
|
||||||
@@ -49,15 +48,8 @@ delete: "Smazat"
|
|||||||
deleteAndEdit: "Smazat a upravit"
|
deleteAndEdit: "Smazat a upravit"
|
||||||
deleteAndEditConfirm: "Jste si jistí že chcete smazat tuto poznámku a editovat ji? Ztratíte tím všechny reakce, sdílení a odpovědi na ni."
|
deleteAndEditConfirm: "Jste si jistí že chcete smazat tuto poznámku a editovat ji? Ztratíte tím všechny reakce, sdílení a odpovědi na ni."
|
||||||
addToList: "Přidat do seznamu"
|
addToList: "Přidat do seznamu"
|
||||||
addToAntenna: "Přidat do antény"
|
|
||||||
sendMessage: "Odeslat zprávu"
|
sendMessage: "Odeslat zprávu"
|
||||||
copyRSS: "Kopírovat RSS"
|
|
||||||
copyUsername: "Kopírovat uživatelské jméno"
|
copyUsername: "Kopírovat uživatelské jméno"
|
||||||
copyUserId: "Kopírovat ID uživatele"
|
|
||||||
copyNoteId: "Kopírovat ID poznámky"
|
|
||||||
copyFileId: "Kopírovat ID souboru"
|
|
||||||
copyFolderId: "Kopírovat ID složky"
|
|
||||||
copyProfileUrl: "Kopírovat URL profilu"
|
|
||||||
searchUser: "Vyhledat uživatele"
|
searchUser: "Vyhledat uživatele"
|
||||||
reply: "Odpovědět"
|
reply: "Odpovědět"
|
||||||
loadMore: "Zobrazit více"
|
loadMore: "Zobrazit více"
|
||||||
@@ -68,7 +60,6 @@ receiveFollowRequest: "Žádost o sledování přijata"
|
|||||||
followRequestAccepted: "Žádost o sledování přijata"
|
followRequestAccepted: "Žádost o sledování přijata"
|
||||||
mention: "Zmínění"
|
mention: "Zmínění"
|
||||||
mentions: "Zmínění"
|
mentions: "Zmínění"
|
||||||
directNotes: "Přímé poznámky"
|
|
||||||
importAndExport: "Import a export"
|
importAndExport: "Import a export"
|
||||||
import: "Importovat"
|
import: "Importovat"
|
||||||
export: "Exportovat"
|
export: "Exportovat"
|
||||||
@@ -91,7 +82,6 @@ error: "Chyba"
|
|||||||
somethingHappened: "Jejda. Něco se nepovedlo."
|
somethingHappened: "Jejda. Něco se nepovedlo."
|
||||||
retry: "Opakovat"
|
retry: "Opakovat"
|
||||||
pageLoadError: "Nepodařilo se načíst stránku"
|
pageLoadError: "Nepodařilo se načíst stránku"
|
||||||
pageLoadErrorDescription: "Tohle je obvykle způsobeno chybou sítě nebo mezipaměti prohlížeče. Zkuste vymazat mezipaměť a po chvíli čekání to zkuste znovu."
|
|
||||||
serverIsDead: "Server neodpovídá. Počkejte chvíli a zkuste to znovu."
|
serverIsDead: "Server neodpovídá. Počkejte chvíli a zkuste to znovu."
|
||||||
youShouldUpgradeClient: "Pro zobrazení této stránky obnovte stránku pro aktualizaci klienta."
|
youShouldUpgradeClient: "Pro zobrazení této stránky obnovte stránku pro aktualizaci klienta."
|
||||||
enterListName: "Jméno seznamu"
|
enterListName: "Jméno seznamu"
|
||||||
@@ -110,8 +100,6 @@ renoted: "Přeposláno"
|
|||||||
cantRenote: "Tento příspěvek nelze přeposlat."
|
cantRenote: "Tento příspěvek nelze přeposlat."
|
||||||
cantReRenote: "Odpověď nemůže být odstraněna."
|
cantReRenote: "Odpověď nemůže být odstraněna."
|
||||||
quote: "Citovat"
|
quote: "Citovat"
|
||||||
inChannelRenote: "Přeposlání v kanálu"
|
|
||||||
inChannelQuote: "Citace v kanálu"
|
|
||||||
pinnedNote: "Připnutá poznámka"
|
pinnedNote: "Připnutá poznámka"
|
||||||
pinned: "Připnout"
|
pinned: "Připnout"
|
||||||
you: "Vy"
|
you: "Vy"
|
||||||
@@ -120,7 +108,6 @@ sensitive: "NSFW"
|
|||||||
add: "Přidat"
|
add: "Přidat"
|
||||||
reaction: "Reakce"
|
reaction: "Reakce"
|
||||||
reactions: "Reakce"
|
reactions: "Reakce"
|
||||||
reactionSetting: "Reakce zobrazené ve výběru reakcí"
|
|
||||||
reactionSettingDescription2: "Přetažením změníte pořadí, kliknutím smažete, zmáčkněte \"+\" k přidání"
|
reactionSettingDescription2: "Přetažením změníte pořadí, kliknutím smažete, zmáčkněte \"+\" k přidání"
|
||||||
rememberNoteVisibility: "Zapamatovat nastavení zobrazení poznámky"
|
rememberNoteVisibility: "Zapamatovat nastavení zobrazení poznámky"
|
||||||
attachCancel: "Odstranit přílohu"
|
attachCancel: "Odstranit přílohu"
|
||||||
@@ -129,8 +116,6 @@ unmarkAsSensitive: "Odznačit jako NSFW"
|
|||||||
enterFileName: "Zadejte název souboru"
|
enterFileName: "Zadejte název souboru"
|
||||||
mute: "Ztlumit"
|
mute: "Ztlumit"
|
||||||
unmute: "Odmlčet"
|
unmute: "Odmlčet"
|
||||||
renoteMute: "Ztlumit poznámky"
|
|
||||||
renoteUnmute: "Zrušit ztlumení poznámek"
|
|
||||||
block: "Zablokovat"
|
block: "Zablokovat"
|
||||||
unblock: "Odblokovat"
|
unblock: "Odblokovat"
|
||||||
suspend: "Zmrazit"
|
suspend: "Zmrazit"
|
||||||
@@ -140,10 +125,7 @@ unblockConfirm: "Jste si jistí že chcete odblokovat tento účet?"
|
|||||||
suspendConfirm: "Jste si jistí že chcete suspendovat tenhle účet?"
|
suspendConfirm: "Jste si jistí že chcete suspendovat tenhle účet?"
|
||||||
unsuspendConfirm: "Jste si jistí že chcete obnovit tenhle účet?"
|
unsuspendConfirm: "Jste si jistí že chcete obnovit tenhle účet?"
|
||||||
selectList: "Vybrat seznam"
|
selectList: "Vybrat seznam"
|
||||||
editList: "Upravit seznam"
|
|
||||||
selectChannel: "Vybrat kanál"
|
|
||||||
selectAntenna: "Vyberte Anténu"
|
selectAntenna: "Vyberte Anténu"
|
||||||
editAntenna: "Upravit anténu"
|
|
||||||
selectWidget: "Zvolte widget"
|
selectWidget: "Zvolte widget"
|
||||||
editWidgets: "Upravit widget"
|
editWidgets: "Upravit widget"
|
||||||
editWidgetsExit: "Hotovo"
|
editWidgetsExit: "Hotovo"
|
||||||
@@ -156,8 +138,6 @@ addEmoji: "Přidat emoji"
|
|||||||
settingGuide: "Doporučené nastavení"
|
settingGuide: "Doporučené nastavení"
|
||||||
cacheRemoteFiles: "Ukládání vzdálených souborů do mezipaměti"
|
cacheRemoteFiles: "Ukládání vzdálených souborů do mezipaměti"
|
||||||
cacheRemoteFilesDescription: "Zakázání tohoto nastavení způsobí, že vzdálené soubory budou odkazovány přímo, místo aby byly ukládány do mezipaměti. Tím se ušetří úložiště na serveru, ale zvýší se provoz, protože se negenerují miniatury."
|
cacheRemoteFilesDescription: "Zakázání tohoto nastavení způsobí, že vzdálené soubory budou odkazovány přímo, místo aby byly ukládány do mezipaměti. Tím se ušetří úložiště na serveru, ale zvýší se provoz, protože se negenerují miniatury."
|
||||||
cacheRemoteSensitiveFiles: "Uložit do mezipaměti vzdálené citlivé soubory"
|
|
||||||
cacheRemoteSensitiveFilesDescription: "Když je tohle nastavení zrušeno, tak jsou vzdálené citlivé soubory načítány přímo ze vzdálených instancí bez uložení do mezipaměti."
|
|
||||||
flagAsBot: "Tento účet je bot"
|
flagAsBot: "Tento účet je bot"
|
||||||
flagAsBotDescription: "Pokud je tento účet kontrolován programem zaškrtněte tuto možnost. To označí tento účet jako bot pro ostatní vývojáře a zabrání tak nekonečným interakcím s ostatními boty a upraví Misskey systém aby se choval k tomuhle účtu jako bot."
|
flagAsBotDescription: "Pokud je tento účet kontrolován programem zaškrtněte tuto možnost. To označí tento účet jako bot pro ostatní vývojáře a zabrání tak nekonečným interakcím s ostatními boty a upraví Misskey systém aby se choval k tomuhle účtu jako bot."
|
||||||
flagAsCat: "Tenhle účet je kočka"
|
flagAsCat: "Tenhle účet je kočka"
|
||||||
@@ -166,7 +146,6 @@ flagShowTimelineReplies: "Zobrazovat odpovědi na časové ose"
|
|||||||
flagShowTimelineRepliesDescription: "Je-li zapnuto, zobrazí odpovědi uživatelů na poznámky jiných uživatelů na vaší časové ose."
|
flagShowTimelineRepliesDescription: "Je-li zapnuto, zobrazí odpovědi uživatelů na poznámky jiných uživatelů na vaší časové ose."
|
||||||
autoAcceptFollowed: "Automaticky akceptovat následování od účtů které sledujete"
|
autoAcceptFollowed: "Automaticky akceptovat následování od účtů které sledujete"
|
||||||
addAccount: "Přidat účet"
|
addAccount: "Přidat účet"
|
||||||
reloadAccountsList: "Obnovit list účtů"
|
|
||||||
loginFailed: "Přihlášení se nezdařilo."
|
loginFailed: "Přihlášení se nezdařilo."
|
||||||
showOnRemote: "Více na původním profilu"
|
showOnRemote: "Více na původním profilu"
|
||||||
general: "Obecně"
|
general: "Obecně"
|
||||||
@@ -207,26 +186,17 @@ instanceInfo: "Informace o instanci"
|
|||||||
statistics: "Statistiky"
|
statistics: "Statistiky"
|
||||||
clearQueue: "Vyčistit frontu"
|
clearQueue: "Vyčistit frontu"
|
||||||
clearQueueConfirmTitle: "Jste si jisti že zrušit všechny úlohy ve frontě?"
|
clearQueueConfirmTitle: "Jste si jisti že zrušit všechny úlohy ve frontě?"
|
||||||
clearQueueConfirmText: "Jakékoliv nedoručené poznámky ve frontě nebudou sdružovány. Většinou tahle operace není zapotřebí."
|
|
||||||
clearCachedFiles: "Vyprázdnit mezipaměť"
|
clearCachedFiles: "Vyprázdnit mezipaměť"
|
||||||
clearCachedFilesConfirm: "Jste jistí že chcete smazat všechny vzdálené soubory v mezipaměti?"
|
|
||||||
blockedInstances: "Blokované instance"
|
blockedInstances: "Blokované instance"
|
||||||
blockedInstancesDescription: "Vypište názvy hostitelů instancí, které chcete blokovat odděleně řádkovými zlomky. Uvedené instance již nebudou moci s touto instancí komunikovat."
|
|
||||||
muteAndBlock: "Ztlumení a blokování"
|
|
||||||
mutedUsers: "Zltumení uživatelé"
|
|
||||||
blockedUsers: "Blokovaní uživatelé"
|
|
||||||
noUsers: "Žádní uživatelé"
|
noUsers: "Žádní uživatelé"
|
||||||
editProfile: "Upravit můj profil"
|
editProfile: "Upravit můj profil"
|
||||||
noteDeleteConfirm: "Jste si jistí že chcete smazat tuhle poznámku?"
|
|
||||||
pinLimitExceeded: "Nemůžete připnout další poznámky."
|
pinLimitExceeded: "Nemůžete připnout další poznámky."
|
||||||
intro: "Instalace Misskey byla dokončena! Prosím vytvořte admina."
|
intro: "Instalace Misskey byla dokončena! Prosím vytvořte admina."
|
||||||
done: "Hotovo"
|
done: "Hotovo"
|
||||||
processing: "Zpracovávám"
|
processing: "Zpracovávám"
|
||||||
preview: "Náhled"
|
preview: "Náhled"
|
||||||
default: "Výchozí"
|
default: "Výchozí"
|
||||||
defaultValueIs: "Základní hodnota: {value}"
|
|
||||||
noCustomEmojis: "Bez Emoji"
|
noCustomEmojis: "Bez Emoji"
|
||||||
federating: "Sdružování"
|
|
||||||
blocked: "Blokováno"
|
blocked: "Blokováno"
|
||||||
suspended: "Suspendováno"
|
suspended: "Suspendováno"
|
||||||
all: "Vše"
|
all: "Vše"
|
||||||
@@ -247,7 +217,6 @@ more: "Více!"
|
|||||||
featured: "Oblíbené poznámky"
|
featured: "Oblíbené poznámky"
|
||||||
usernameOrUserId: "Uživatelské jméno nebo uživatelské id"
|
usernameOrUserId: "Uživatelské jméno nebo uživatelské id"
|
||||||
noSuchUser: "Uživatel nebyl nalezen"
|
noSuchUser: "Uživatel nebyl nalezen"
|
||||||
lookup: "Vyhledat"
|
|
||||||
announcements: "Oznámení"
|
announcements: "Oznámení"
|
||||||
imageUrl: "URL obrázku"
|
imageUrl: "URL obrázku"
|
||||||
remove: "Smazat"
|
remove: "Smazat"
|
||||||
@@ -258,13 +227,10 @@ resetAreYouSure: "Opravdu resetovat?"
|
|||||||
saved: "Uloženo"
|
saved: "Uloženo"
|
||||||
messaging: "Zprávy"
|
messaging: "Zprávy"
|
||||||
upload: "Nahrát soubory"
|
upload: "Nahrát soubory"
|
||||||
keepOriginalUploading: "Ponechat originální obrázek"
|
|
||||||
keepOriginalUploadingDescription: "Uloží původní nahraný obrázek jak je. Pokud je to vypnuté, vygeneruje se zobrazení verze na webu při nahrátí."
|
|
||||||
fromDrive: "Z disku"
|
fromDrive: "Z disku"
|
||||||
fromUrl: "Z URL"
|
fromUrl: "Z URL"
|
||||||
uploadFromUrl: "Nahrát z URL adresy"
|
uploadFromUrl: "Nahrát z URL adresy"
|
||||||
uploadFromUrlDescription: "URL adresa souboru, který chcete nahrát"
|
uploadFromUrlDescription: "URL adresa souboru, který chcete nahrát"
|
||||||
uploadFromUrlRequested: "Upload zažádán"
|
|
||||||
uploadFromUrlMayTakeTime: "Může trvat nějakou dobu, dokud nebude dokončeno nahrávání."
|
uploadFromUrlMayTakeTime: "Může trvat nějakou dobu, dokud nebude dokončeno nahrávání."
|
||||||
explore: "Objevovat"
|
explore: "Objevovat"
|
||||||
messageRead: "Přečtené"
|
messageRead: "Přečtené"
|
||||||
@@ -272,10 +238,6 @@ noMoreHistory: "To je vše"
|
|||||||
startMessaging: "Zahájit chat"
|
startMessaging: "Zahájit chat"
|
||||||
nUsersRead: "přečteno {n} uživateli"
|
nUsersRead: "přečteno {n} uživateli"
|
||||||
agreeTo: "Souhlasím s {0}"
|
agreeTo: "Souhlasím s {0}"
|
||||||
agree: "Souhlasím"
|
|
||||||
agreeBelow: "Souhlasím s následným"
|
|
||||||
basicNotesBeforeCreateAccount: "Důležité poznámky"
|
|
||||||
termsOfService: "Podmínky užívání"
|
|
||||||
start: "Začít"
|
start: "Začít"
|
||||||
home: "Domů"
|
home: "Domů"
|
||||||
remoteUserCaution: "Tyto informace nemusí být aktuální jelikož uživatel je ze vzdálené instance."
|
remoteUserCaution: "Tyto informace nemusí být aktuální jelikož uživatel je ze vzdálené instance."
|
||||||
@@ -306,24 +268,17 @@ createFolder: "Vytvořit složku"
|
|||||||
renameFolder: "Přejmenovat složku"
|
renameFolder: "Přejmenovat složku"
|
||||||
deleteFolder: "Odstranit složku"
|
deleteFolder: "Odstranit složku"
|
||||||
addFile: "Přidat soubor"
|
addFile: "Přidat soubor"
|
||||||
emptyDrive: "Váš disk je prázdný"
|
|
||||||
emptyFolder: "Tato složka je prázdná"
|
emptyFolder: "Tato složka je prázdná"
|
||||||
unableToDelete: "Nelze smazat"
|
unableToDelete: "Nelze smazat"
|
||||||
inputNewFileName: "Zadejte nový název"
|
inputNewFileName: "Zadejte nový název"
|
||||||
inputNewDescription: "Zadejte nový popisek"
|
|
||||||
inputNewFolderName: "Zadejte název nové složky"
|
inputNewFolderName: "Zadejte název nové složky"
|
||||||
circularReferenceFolder: "Koncová složka je podsložka složky, kterou chcete přesunout."
|
|
||||||
hasChildFilesOrFolders: "Nemůžete odstranit složku, která není prázdná."
|
|
||||||
copyUrl: "Kopírovat URL"
|
copyUrl: "Kopírovat URL"
|
||||||
rename: "Přejmenovat"
|
rename: "Přejmenovat"
|
||||||
avatar: "Avatar"
|
avatar: "Avatar"
|
||||||
banner: "Baner"
|
banner: "Baner"
|
||||||
displayOfSensitiveMedia: "Zobrazit citlivé média"
|
|
||||||
whenServerDisconnected: "Když ztratíte spojení se serverem"
|
|
||||||
disconnectedFromServer: "Spojení bylo přerušeno"
|
disconnectedFromServer: "Spojení bylo přerušeno"
|
||||||
reload: "Aktualizovat"
|
reload: "Aktualizovat"
|
||||||
doNothing: "Ignorovat"
|
doNothing: "Ignorovat"
|
||||||
reloadConfirm: "Chcete obnovit časovou osu?"
|
|
||||||
watch: "Sledovat"
|
watch: "Sledovat"
|
||||||
unwatch: "Přestat sledovat"
|
unwatch: "Přestat sledovat"
|
||||||
accept: "Souhlasím"
|
accept: "Souhlasím"
|
||||||
@@ -346,22 +301,15 @@ connectService: "Připojit"
|
|||||||
disconnectService: "Odpojit"
|
disconnectService: "Odpojit"
|
||||||
enableLocalTimeline: "Povolit lokální čas"
|
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é."
|
|
||||||
registration: "Registrace"
|
registration: "Registrace"
|
||||||
enableRegistration: "Povolit registraci novým uživatelům"
|
enableRegistration: "Povolit registraci novým uživatelům"
|
||||||
invite: "Pozvat"
|
invite: "Pozvat"
|
||||||
driveCapacityPerLocalAccount: "Kapacita disku na lokálního uživatele"
|
|
||||||
driveCapacityPerRemoteAccount: "Kapacita disku na vzdáleného uživatele"
|
|
||||||
inMb: "V megabajtech"
|
inMb: "V megabajtech"
|
||||||
iconUrl: "Favicon URL"
|
iconUrl: "Favicon URL"
|
||||||
bannerUrl: "Baner URL"
|
bannerUrl: "Baner URL"
|
||||||
backgroundImageUrl: "Adresa URL obrázku pozadí"
|
backgroundImageUrl: "Adresa URL obrázku pozadí"
|
||||||
basicInfo: "Základní informace"
|
basicInfo: "Základní informace"
|
||||||
pinnedUsers: "Připnutí uživatelé"
|
pinnedUsers: "Připnutí uživatelé"
|
||||||
pinnedUsersDescription: "Seznam uživatelských přezdívek oddělených řádkami bude připnutý v záložce \"Objevit\"."
|
|
||||||
pinnedPages: "Připnutý stránky"
|
|
||||||
pinnedPagesDescription: "Zadejte cesty stránek oddělené řádkami, které si přejete mít přípnutý na vrcholu téhle instance."
|
|
||||||
pinnedClipId: "ID připnutého klipu"
|
|
||||||
pinnedNotes: "Připnutá poznámka"
|
pinnedNotes: "Připnutá poznámka"
|
||||||
hcaptcha: "hCaptcha"
|
hcaptcha: "hCaptcha"
|
||||||
enableHcaptcha: "Aktivovat hCaptchu"
|
enableHcaptcha: "Aktivovat hCaptchu"
|
||||||
@@ -371,56 +319,30 @@ recaptcha: "reCAPTCHA"
|
|||||||
enableRecaptcha: "Zapnout ReCAPTCHu"
|
enableRecaptcha: "Zapnout ReCAPTCHu"
|
||||||
recaptchaSiteKey: "Klíč stránky"
|
recaptchaSiteKey: "Klíč stránky"
|
||||||
recaptchaSecretKey: "Tajný Klíč (Secret Key)"
|
recaptchaSecretKey: "Tajný Klíč (Secret Key)"
|
||||||
turnstile: "Turnstile"
|
|
||||||
enableTurnstile: "Povolit Turnstile"
|
|
||||||
turnstileSiteKey: "Klíč stránky"
|
turnstileSiteKey: "Klíč stránky"
|
||||||
turnstileSecretKey: "Tajný Klíč (Secret Key)"
|
turnstileSecretKey: "Tajný Klíč (Secret Key)"
|
||||||
avoidMultiCaptchaConfirm: "Používání několik Captcha systému může způsobit konflikt mezi nimi. Chtěli byste vypnout ostatní aktivní Captcha systémy? Pokud je chcete nechat zapnuté, stiskněte zrušit."
|
|
||||||
antennas: "Antény"
|
antennas: "Antény"
|
||||||
manageAntennas: "Spravovat Antény"
|
manageAntennas: "Spravovat Antény"
|
||||||
name: "Jméno"
|
name: "Jméno"
|
||||||
antennaSource: "Zdroj Antény"
|
antennaSource: "Zdroj Antény"
|
||||||
antennaKeywords: "Klíčová slova na poslech"
|
|
||||||
antennaExcludeKeywords: "Vyloučená klíčová slova"
|
|
||||||
antennaKeywordsDescription: "Oddělte mezerami pro AND kondice nebo řádkami pro OR kondice."
|
|
||||||
notifyAntenna: "Upozornit na nové poznámky"
|
|
||||||
withFileAntenna: "Poznámky jenom se souborama"
|
|
||||||
enableServiceworker: "Povolit ServiceWorker"
|
enableServiceworker: "Povolit ServiceWorker"
|
||||||
antennaUsersDescription: "Vypsat jednoho uživatele na řádek"
|
|
||||||
caseSensitive: "Rozlišuje malá a velká písmena"
|
caseSensitive: "Rozlišuje malá a velká písmena"
|
||||||
withReplies: "Zahrnout odpovědi"
|
|
||||||
connectedTo: "Následující účty jsou připojeny"
|
connectedTo: "Následující účty jsou připojeny"
|
||||||
notesAndReplies: "Poznámky a odpovědi"
|
notesAndReplies: "Poznámky a odpovědi"
|
||||||
withFiles: "Včetně souborů"
|
withFiles: "Včetně souborů"
|
||||||
silence: "Ztlumení"
|
|
||||||
silenceConfirm: "Jste si jistí že chcete ztlumit tohoto uživatele?"
|
|
||||||
unsilence: "Zrušit ztlumení"
|
|
||||||
unsilenceConfirm: "Jste jistí že chcete vrátit zltumení tohoto uživatele?"
|
|
||||||
popularUsers: "Populární uživatelé"
|
popularUsers: "Populární uživatelé"
|
||||||
recentlyUpdatedUsers: "Nedávno aktívni uživatelé"
|
recentlyUpdatedUsers: "Nedávno aktívni uživatelé"
|
||||||
recentlyRegisteredUsers: "Nově připojený uživatelé"
|
|
||||||
recentlyDiscoveredUsers: "Nově objevený uživatelé"
|
|
||||||
exploreUsersCount: "Existuje {count} uživatelů"
|
|
||||||
exploreFediverse: "Objevovat Fediverse"
|
|
||||||
popularTags: "Populární tagy"
|
popularTags: "Populární tagy"
|
||||||
userList: "Seznamy"
|
userList: "Seznamy"
|
||||||
about: "Informace"
|
about: "Informace"
|
||||||
aboutMisskey: "O Misskey"
|
aboutMisskey: "O Misskey"
|
||||||
administrator: "Administrátor"
|
administrator: "Administrátor"
|
||||||
token: "Token"
|
token: "Token"
|
||||||
2fa: "Dvoufázové ověření"
|
|
||||||
totp: "Ověřovací aplikace"
|
|
||||||
totpDescription: "Použít ověřovací aplikaci pro použití jednorázových hesel"
|
|
||||||
moderator: "Moderátor"
|
moderator: "Moderátor"
|
||||||
moderation: "Moderování"
|
|
||||||
nUsersMentioned: "{n} uživatelů zmínilo"
|
nUsersMentioned: "{n} uživatelů zmínilo"
|
||||||
securityKeyAndPasskey: "Bezpečnostní klíče a tokeny"
|
|
||||||
securityKey: "Bezpečnostní klíč"
|
securityKey: "Bezpečnostní klíč"
|
||||||
lastUsed: "Naposledy použito"
|
lastUsed: "Naposledy použito"
|
||||||
lastUsedAt: "Naposledy použito: {t}"
|
|
||||||
unregister: "Odstranit"
|
unregister: "Odstranit"
|
||||||
passwordLessLogin: "Přihlášení bez hesla"
|
|
||||||
passwordLessLoginDescription: "Umožní bez-heslové přihlášení pomocí bezpečnostního klíče či tokenu"
|
|
||||||
resetPassword: "Resetovat heslo"
|
resetPassword: "Resetovat heslo"
|
||||||
newPasswordIs: "Nové heslo je \"{password}\""
|
newPasswordIs: "Nové heslo je \"{password}\""
|
||||||
reduceUiAnimation: "Snížit UI animace"
|
reduceUiAnimation: "Snížit UI animace"
|
||||||
@@ -469,25 +391,14 @@ or: "Nebo"
|
|||||||
language: "Jazyk"
|
language: "Jazyk"
|
||||||
uiLanguage: "Jazyk uživatelského rozhraní"
|
uiLanguage: "Jazyk uživatelského rozhraní"
|
||||||
aboutX: "O {x}"
|
aboutX: "O {x}"
|
||||||
emojiStyle: "Styl emoji"
|
|
||||||
native: "Výchozí"
|
|
||||||
disableDrawer: "Nepoužívat šuplíkové menu"
|
|
||||||
showNoteActionsOnlyHover: "Zobrazit akce poznámky jenom při naběhnutí myši"
|
|
||||||
noHistory: "Žádná historie"
|
noHistory: "Žádná historie"
|
||||||
signinHistory: "Historie přihlášení"
|
signinHistory: "Historie přihlášení"
|
||||||
enableAdvancedMfm: "Zapnout pokročilé MFM"
|
|
||||||
enableAnimatedMfm: "Zapnout animované MFM"
|
|
||||||
doing: "Procesuju..."
|
|
||||||
category: "Kategorie"
|
category: "Kategorie"
|
||||||
tags: "Štítky"
|
tags: "Štítky"
|
||||||
docSource: "Zdroj tohoto dokumentu"
|
|
||||||
createAccount: "Vytvořit účet"
|
createAccount: "Vytvořit účet"
|
||||||
existingAccount: "Existující účet"
|
existingAccount: "Existující účet"
|
||||||
regenerate: "Obnovit"
|
regenerate: "Obnovit"
|
||||||
fontSize: "Velikost písma"
|
fontSize: "Velikost písma"
|
||||||
mediaListWithOneImageAppearance: "Výška seznamu médií s jedním obrázkem"
|
|
||||||
limitTo: "Omezeno na {x}"
|
|
||||||
noFollowRequests: "Nemáte žádné žádosti o sledování"
|
|
||||||
openImageInNewTab: "Otevřít obrázek v novém panelu"
|
openImageInNewTab: "Otevřít obrázek v novém panelu"
|
||||||
dashboard: "Přehled"
|
dashboard: "Přehled"
|
||||||
local: "Lokální"
|
local: "Lokální"
|
||||||
@@ -501,35 +412,15 @@ accountSettings: "Nastavení účtu"
|
|||||||
promotion: "Propagace"
|
promotion: "Propagace"
|
||||||
promote: "Propagovat"
|
promote: "Propagovat"
|
||||||
numberOfDays: "Počet dní"
|
numberOfDays: "Počet dní"
|
||||||
hideThisNote: "Skrýt tuto poznámku"
|
|
||||||
showFeaturedNotesInTimeline: "Zobrazit významné poznámky v časové ose"
|
|
||||||
objectStorage: "Úložiště objektů"
|
|
||||||
useObjectStorage: "Použít úložiště objektů"
|
|
||||||
objectStorageBaseUrl: "Base URL"
|
objectStorageBaseUrl: "Base URL"
|
||||||
objectStorageBaseUrlDesc: "URL použitá jako reference. Upřesněte URL vlastní CDN nebo Proxy pokud používáte jeden z nich. Pro S3 použijte 'https://<bucket>.s3.amazonaws.com' a pro GCS nebo ekvivalentní služby použijte 'https://storage.googleapis.com/<bucket>', apd."
|
|
||||||
objectStorageBucket: "Bucket"
|
objectStorageBucket: "Bucket"
|
||||||
objectStorageBucketDesc: "Prosím upřesněte název bucketu používaný poskytovatelem."
|
|
||||||
objectStoragePrefix: "Předpona"
|
objectStoragePrefix: "Předpona"
|
||||||
objectStoragePrefixDesc: "Soubory budou ukládány pod složkama s tímhle prefixem."
|
|
||||||
objectStorageEndpoint: "Endpoint"
|
objectStorageEndpoint: "Endpoint"
|
||||||
objectStorageEndpointDesc: "Ponechte tohle prázdné pokud používáte AWS S3, jinak upřesněte endpoint jako \"<host>\" nebo \"<host>:<port>\", podle toho jakou službu používáte."
|
|
||||||
objectStorageRegion: "Región"
|
objectStorageRegion: "Región"
|
||||||
objectStorageRegionDesc: "Upřesněte region jako například \"xx-east-1\". Pokud vlastní služba nerozlišuje mezi regiony, zadejte \"us-east-1\". Zanechte prázdné pokud používáte AWS konfiguraci či proměnné veličiny."
|
|
||||||
objectStorageUseSSL: "Použít SSL"
|
objectStorageUseSSL: "Použít SSL"
|
||||||
objectStorageUseSSLDesc: "Vypněte to pokud nebudete používat HTTPS pro API připojení"
|
|
||||||
objectStorageUseProxy: "Připojení skrze Proxy"
|
|
||||||
objectStorageUseProxyDesc: "Vypněte to pokud nebudete používat Proxy pro API připojení."
|
|
||||||
objectStorageSetPublicRead: "Při nahrátí nastavit na \"public-read\""
|
|
||||||
s3ForcePathStyleDesc: "Pokud je povolena funkce s3ForcePathStyle, musí být název Bucketu zahrnut do cesty k adrese URL, nikoli do názvu hostitele adresy URL. Toto nastavení může být nutné povolit při používání služeb, jako je například samostatně hostovaná instance Minio."
|
|
||||||
serverLogs: "Logy serveru"
|
|
||||||
deleteAll: "Smazat vše"
|
deleteAll: "Smazat vše"
|
||||||
showFixedPostForm: "Zobrazit formulář pro nové příspěvky nad časovou osou"
|
showFixedPostForm: "Zobrazit formulář pro nové příspěvky nad časovou osou"
|
||||||
showFixedPostFormInChannel: "Zobrazit vkládací formulář na vrcholu časové osy (Kanály)"
|
|
||||||
newNoteRecived: "Jsou k dispozici nové poznámky"
|
|
||||||
sounds: "Zvuky"
|
|
||||||
sound: "Zvuky"
|
|
||||||
listen: "Poslouchat"
|
listen: "Poslouchat"
|
||||||
none: "Žádný"
|
|
||||||
showInPage: "Zobrazit na stránce"
|
showInPage: "Zobrazit na stránce"
|
||||||
popout: "Pop-out"
|
popout: "Pop-out"
|
||||||
volume: "Hlasitost"
|
volume: "Hlasitost"
|
||||||
@@ -542,61 +433,29 @@ install: "Nainstalovat"
|
|||||||
uninstall: "Odinstalovat"
|
uninstall: "Odinstalovat"
|
||||||
installedApps: "Autorizované aplikace"
|
installedApps: "Autorizované aplikace"
|
||||||
nothing: "Nic nebylo nalezeno"
|
nothing: "Nic nebylo nalezeno"
|
||||||
installedDate: "Datum autorizace"
|
|
||||||
lastUsedDate: "Poslední použití"
|
lastUsedDate: "Poslední použití"
|
||||||
state: "Stav"
|
state: "Stav"
|
||||||
sort: "Seřadit"
|
sort: "Seřadit"
|
||||||
ascendingOrder: "Vzestupně"
|
ascendingOrder: "Vzestupně"
|
||||||
descendingOrder: "Sestupně"
|
descendingOrder: "Sestupně"
|
||||||
scratchpad: "Zápisník"
|
scratchpad: "Zápisník"
|
||||||
scratchpadDescription: "Scratchpad poskytuje rozhraní pro AiScript experimenty. Můžete psát, spustit či zkontrolovat výsledky jeho interakce s Misskey."
|
|
||||||
output: "Výstup"
|
output: "Výstup"
|
||||||
script: "Skript"
|
script: "Skript"
|
||||||
disablePagesScript: "Vypnout AiScript na stránkách"
|
|
||||||
updateRemoteUser: "Aktualizovat informace o vzdáleném účtu"
|
updateRemoteUser: "Aktualizovat informace o vzdáleném účtu"
|
||||||
deleteAllFiles: "Smazat všechny soubory"
|
deleteAllFiles: "Smazat všechny soubory"
|
||||||
deleteAllFilesConfirm: "Jste si jistí že chcete smazat všechny soubory?"
|
deleteAllFilesConfirm: "Jste si jistí že chcete smazat všechny soubory?"
|
||||||
removeAllFollowing: "Přestat sledovat všechny sledované uživatele"
|
|
||||||
removeAllFollowingDescription: "Spuštěním přestanete sledovat všechny účty z {host}. Prosíme spustěte tohle v případě že instance už neexistuje. "
|
|
||||||
userSuspended: "Tomuto uživateli byl pozastaven účet."
|
userSuspended: "Tomuto uživateli byl pozastaven účet."
|
||||||
userSilenced: "Tenhle uživatel je umlčen."
|
|
||||||
yourAccountSuspendedTitle: "Tenhle účet je zmrazený"
|
|
||||||
yourAccountSuspendedDescription: "Tenhle účet byl zmrazen z důvodu porušení smluvní podmínky serveru. Pro přesnější informace kontaktujte administrátora. Prosíme nezakládejte si nový účet."
|
|
||||||
tokenRevoked: "Nesprávný token"
|
|
||||||
tokenRevokedDescription: "Tenhle token vyprchal. Prosíme přihlašte se znova."
|
|
||||||
accountDeleted: "Účet smazán"
|
|
||||||
accountDeletedDescription: "Tenhle účet byl smazán."
|
|
||||||
menu: "Menu"
|
menu: "Menu"
|
||||||
divider: "Dělící čára"
|
divider: "Dělící čára"
|
||||||
addItem: "Přidat položku"
|
addItem: "Přidat položku"
|
||||||
rearrange: "Přeřadit"
|
|
||||||
relays: "Relay"
|
relays: "Relay"
|
||||||
addRelay: "Přidat Relay"
|
addRelay: "Přidat Relay"
|
||||||
inboxUrl: "Inbox URL"
|
inboxUrl: "Inbox URL"
|
||||||
addedRelays: "Přidané přenosy"
|
|
||||||
serviceworkerInfo: "Musí být zapnut pro push notifikace."
|
|
||||||
deletedNote: "Odstraněné příspěvky"
|
deletedNote: "Odstraněné příspěvky"
|
||||||
invisibleNote: "Skryté příspěvky"
|
invisibleNote: "Skryté příspěvky"
|
||||||
enableInfiniteScroll: "Automaticky načítat více"
|
|
||||||
visibility: "Viditelnost"
|
|
||||||
poll: "Anketa"
|
|
||||||
useCw: "Schovat obsah"
|
|
||||||
enablePlayer: "Otevřít video přehrávač"
|
|
||||||
disablePlayer: "Zavřít video přehrávač"
|
|
||||||
expandTweet: "Rozbalit tweet"
|
|
||||||
themeEditor: "Editor témat"
|
|
||||||
description: "Popis"
|
description: "Popis"
|
||||||
describeFile: "Přidat popisek"
|
|
||||||
enterFileDescription: "Vložit popisek"
|
|
||||||
author: "Autor"
|
author: "Autor"
|
||||||
leaveConfirm: "Máte neuložené změny. Opravdu je chcete zahodit?"
|
|
||||||
manage: "Administrace"
|
manage: "Administrace"
|
||||||
plugins: "Pluginy"
|
|
||||||
preferencesBackups: "Zálohy nastavení"
|
|
||||||
deck: "Deck"
|
|
||||||
undeck: "Opustit Deck"
|
|
||||||
useBlurEffectForModal: "Použít efekt rozostření na okna"
|
|
||||||
useFullReactionPicker: "Používat plnou velikost výběru emoji"
|
|
||||||
width: "Šířka"
|
width: "Šířka"
|
||||||
height: "Výška"
|
height: "Výška"
|
||||||
large: "Velké"
|
large: "Velké"
|
||||||
@@ -606,13 +465,10 @@ generateAccessToken: "Vygenerovat přístupový token"
|
|||||||
permission: "Oprávnění"
|
permission: "Oprávnění"
|
||||||
enableAll: "Povolit vše"
|
enableAll: "Povolit vše"
|
||||||
disableAll: "Vypnout vše"
|
disableAll: "Vypnout vše"
|
||||||
tokenRequested: "Povolit přístup k účtu"
|
|
||||||
pluginTokenRequestedDescription: "Tenhle plugin bude moct používat oprávnění nastavená zde."
|
|
||||||
notificationType: "Typy oznámení"
|
notificationType: "Typy oznámení"
|
||||||
edit: "Upravit"
|
edit: "Upravit"
|
||||||
emailServer: "Mailový server"
|
emailServer: "Mailový server"
|
||||||
enableEmail: "Zapnout email dystribuci"
|
enableEmail: "Zapnout email dystribuci"
|
||||||
emailConfigInfo: "Používá se na ověření emailové adresy během registrace nebo při zapomenutí hesla."
|
|
||||||
email: "Email"
|
email: "Email"
|
||||||
emailAddress: "Emailová adresa"
|
emailAddress: "Emailová adresa"
|
||||||
smtpConfig: "Konfigurace SMTP serveru"
|
smtpConfig: "Konfigurace SMTP serveru"
|
||||||
@@ -620,15 +476,8 @@ smtpHost: "Hostitel"
|
|||||||
smtpPort: "Port"
|
smtpPort: "Port"
|
||||||
smtpUser: "Uživatelské jméno"
|
smtpUser: "Uživatelské jméno"
|
||||||
smtpPass: "Heslo"
|
smtpPass: "Heslo"
|
||||||
emptyToDisableSmtpAuth: "Zanechte uživatelské jméno a heslo prázdné pro vypnutí SMTP verifikace."
|
|
||||||
smtpSecure: "Použít implicitní SSL/TLS pro SMTP připojení"
|
|
||||||
smtpSecureInfo: "Toto vypněte pokud používáte STARTTLS"
|
smtpSecureInfo: "Toto vypněte pokud používáte STARTTLS"
|
||||||
testEmail: "Otestovat doručení emailů"
|
testEmail: "Otestovat doručení emailů"
|
||||||
wordMute: "Ztlumené slova"
|
|
||||||
regexpError: "Chyba v regulérním výrazu"
|
|
||||||
regexpErrorDescription: "Došlo k chybě v regulérním výrazu v řádku {line} tabulky {tab} ztlumených slov:"
|
|
||||||
instanceMute: "Ztlumené instance"
|
|
||||||
userSaysSomething: "{name} řekl/a něco"
|
|
||||||
makeActive: "Aktivovat"
|
makeActive: "Aktivovat"
|
||||||
display: "Zobrazit"
|
display: "Zobrazit"
|
||||||
copy: "Kopírovat"
|
copy: "Kopírovat"
|
||||||
@@ -640,66 +489,21 @@ database: "Databáze"
|
|||||||
channel: "Kanály"
|
channel: "Kanály"
|
||||||
create: "Vytvořit"
|
create: "Vytvořit"
|
||||||
notificationSetting: "Nastavení oznámení"
|
notificationSetting: "Nastavení oznámení"
|
||||||
notificationSettingDesc: "Vyberte typy oznámení k zobrazení."
|
|
||||||
useGlobalSetting: "Použít globální nastavení"
|
useGlobalSetting: "Použít globální nastavení"
|
||||||
useGlobalSettingDesc: "Pokud je to zapnuté, tak nastavení oznámení účtu bude použito. Pokud je to vypnuté, tak se bude moct použít jednotlivá nastavení."
|
|
||||||
other: "Ostatní"
|
other: "Ostatní"
|
||||||
regenerateLoginToken: "Přegenerovat přihlašovací token"
|
|
||||||
regenerateLoginTokenDescription: "Přegeneruje token interně používaný během přihlášení. Běžně tahle akce není nutná. Pokud bude token přegenerovaný, tak se všechna přihlášená zařízení odhlásí."
|
|
||||||
setMultipleBySeparatingWithSpace: "Oddělení více položek mezerami."
|
|
||||||
fileIdOrUrl: "ID nebo URL souboru"
|
fileIdOrUrl: "ID nebo URL souboru"
|
||||||
behavior: "Chování"
|
behavior: "Chování"
|
||||||
sample: "Ukázka"
|
sample: "Ukázka"
|
||||||
abuseReports: "Nahlášení"
|
|
||||||
reportAbuse: "Nahlášení"
|
|
||||||
reportAbuseOf: "Nahlásit {name}"
|
|
||||||
fillAbuseReportDescription: "Prosíme vyplňte všechny detaily ohledně tohodle nahlášení. Pokud jde o specifickou poznámku, prosíme o přiložení její URL."
|
|
||||||
abuseReported: "Nahlášení bylo odesláno. Děkujeme převelice."
|
|
||||||
reporter: "Nahlásil"
|
|
||||||
reporteeOrigin: "Původ nahlášení"
|
|
||||||
reporterOrigin: "Původ nahlasovače"
|
|
||||||
forwardReport: "Přeposlat nahlášení do vzdálené instance"
|
|
||||||
send: "Odeslat"
|
send: "Odeslat"
|
||||||
openInNewTab: "Otevřít v nové kartě"
|
openInNewTab: "Otevřít v nové kartě"
|
||||||
openInSideView: "Otevřít v bočním panelu"
|
|
||||||
defaultNavigationBehaviour: "Výchozí chování navigace"
|
|
||||||
instanceTicker: "Informace instance o poznámkách"
|
|
||||||
waitingFor: "Čeká se na {x}"
|
|
||||||
random: "Náhodně"
|
random: "Náhodně"
|
||||||
system: "Systém"
|
system: "Systém"
|
||||||
switchUi: "Přepnout UI"
|
|
||||||
desktop: "Plocha"
|
desktop: "Plocha"
|
||||||
clip: "Oříznout"
|
clip: "Oříznout"
|
||||||
createNew: "Vytvořit nový"
|
createNew: "Vytvořit nový"
|
||||||
optional: "Volitelné"
|
optional: "Volitelné"
|
||||||
createNewClip: "Vytvořit nový klip"
|
|
||||||
unclip: "Odepnout"
|
|
||||||
confirmToUnclipAlreadyClippedNote: "Tahle poznámku je už součásti \"{name}\" klipu. Chcete ji místo toho odepnout z tohodle klipu?"
|
|
||||||
public: "Veřejný"
|
|
||||||
i18nInfo: "Misskey je překládán do jiných jazyků dobrovolníkama. Můžete pomoci na {link}."
|
|
||||||
manageAccessTokens: "Spravovat přístupové tokeny"
|
|
||||||
accountInfo: "Informace o účtu"
|
|
||||||
notesCount: "Počet poznámek"
|
|
||||||
repliesCount: "Počet odeslaných odpovědí"
|
|
||||||
renotesCount: "Počet přeposlaných poznámek"
|
|
||||||
repliedCount: "Počet přijatých odpovědí"
|
|
||||||
renotedCount: "Počet přijatých přeposlaných poznámek"
|
|
||||||
followingCount: "Počet sledovaných účtů"
|
|
||||||
followersCount: "Počet sledujících"
|
|
||||||
sentReactionsCount: "Počet odeslaných reakcí"
|
|
||||||
receivedReactionsCount: "Počet přijatých reakcí"
|
|
||||||
pollVotesCount: "Počet odeslaných anketových hlasů"
|
|
||||||
pollVotedCount: "Počet přijatých anketových hlasů"
|
|
||||||
yes: "Ano"
|
yes: "Ano"
|
||||||
no: "Ne"
|
no: "Ne"
|
||||||
driveFilesCount: "Počet souborů na disku"
|
|
||||||
driveUsage: "Využití disku"
|
|
||||||
noCrawle: "Odmítat indexování crawleru"
|
|
||||||
lockedAccountInfo: "Pokud nenastavíte viditelnost poznámek na \"Pouze pro sledující\", budou poznámky viditelné všem i přesto že vyžadujete manuální potvrzení pro sledování."
|
|
||||||
alwaysMarkSensitive: "Výchozně označovat jako citlivý"
|
|
||||||
loadRawImages: "Načítat originální obrázky místo náhledů"
|
|
||||||
disableShowingAnimatedImages: "Nepřehrávat animované obrázky"
|
|
||||||
verificationEmailSent: "Ověřovací email byl zaslán. Ověření dokončíte kliknutím na odkaz v emailu."
|
|
||||||
notSet: "Není nastaveno"
|
notSet: "Není nastaveno"
|
||||||
emailVerified: "Váš e-mail byl ověřen"
|
emailVerified: "Váš e-mail byl ověřen"
|
||||||
contact: "Kontakt"
|
contact: "Kontakt"
|
||||||
|
@@ -49,7 +49,6 @@ delete: "Löschen"
|
|||||||
deleteAndEdit: "Löschen und Bearbeiten"
|
deleteAndEdit: "Löschen und Bearbeiten"
|
||||||
deleteAndEditConfirm: "Möchtest du diese Notiz wirklich löschen und bearbeiten? Alle Reaktionen, Renotes und Antworten dieser Notiz werden verloren gehen."
|
deleteAndEditConfirm: "Möchtest du diese Notiz wirklich löschen und bearbeiten? Alle Reaktionen, Renotes und Antworten dieser Notiz werden verloren gehen."
|
||||||
addToList: "Zu Liste hinzufügen"
|
addToList: "Zu Liste hinzufügen"
|
||||||
addToAntenna: "Zu Antenne hinzufügen"
|
|
||||||
sendMessage: "Nachricht senden"
|
sendMessage: "Nachricht senden"
|
||||||
copyRSS: "RSS kopieren"
|
copyRSS: "RSS kopieren"
|
||||||
copyUsername: "Benutzernamen kopieren"
|
copyUsername: "Benutzernamen kopieren"
|
||||||
@@ -57,7 +56,6 @@ copyUserId: "Benutzer-ID kopieren"
|
|||||||
copyNoteId: "Notiz-ID kopieren"
|
copyNoteId: "Notiz-ID kopieren"
|
||||||
copyFileId: "Datei-ID kopieren"
|
copyFileId: "Datei-ID kopieren"
|
||||||
copyFolderId: "Ordner-ID kopieren"
|
copyFolderId: "Ordner-ID kopieren"
|
||||||
copyProfileUrl: "Profil-URL kopieren"
|
|
||||||
searchUser: "Nach einem Benutzer suchen"
|
searchUser: "Nach einem Benutzer suchen"
|
||||||
reply: "Antworten"
|
reply: "Antworten"
|
||||||
loadMore: "Mehr laden"
|
loadMore: "Mehr laden"
|
||||||
@@ -156,8 +154,6 @@ addEmoji: "Emoji hinzufügen"
|
|||||||
settingGuide: "Empfohlene Einstellung"
|
settingGuide: "Empfohlene Einstellung"
|
||||||
cacheRemoteFiles: "Dateien von fremden Instanzen im Cache speichern"
|
cacheRemoteFiles: "Dateien von fremden Instanzen im Cache speichern"
|
||||||
cacheRemoteFilesDescription: "Ist diese Einstellung deaktiviert, so werden Dateien fremder Instanzen direkt von dort geladen. Hierdurch wird Speicherplatz auf diesem Server gespart, aber durch fehlende Generierung von Vorschaubildern mehr Bandbreite verwendet."
|
cacheRemoteFilesDescription: "Ist diese Einstellung deaktiviert, so werden Dateien fremder Instanzen direkt von dort geladen. Hierdurch wird Speicherplatz auf diesem Server gespart, aber durch fehlende Generierung von Vorschaubildern mehr Bandbreite verwendet."
|
||||||
cacheRemoteSensitiveFiles: "Sensitive Dateien von fremden Instanzen im Cache speichern"
|
|
||||||
cacheRemoteSensitiveFilesDescription: "Ist diese Einstellung deaktiviert, so werden sensitive Dateien fremder Instanzen direkt von dort ohne Zwischenspeicherung geladen."
|
|
||||||
flagAsBot: "Als Bot markieren"
|
flagAsBot: "Als Bot markieren"
|
||||||
flagAsBotDescription: "Aktiviere diese Option, falls dieses Benutzerkonto durch ein Programm gesteuert wird. Falls aktiviert, agiert es als Flag für andere Entwickler zur Verhinderung von endlosen Kettenreaktionen mit anderen Bots und lässt Misskeys interne Systeme dieses Benutzerkonto als Bot behandeln."
|
flagAsBotDescription: "Aktiviere diese Option, falls dieses Benutzerkonto durch ein Programm gesteuert wird. Falls aktiviert, agiert es als Flag für andere Entwickler zur Verhinderung von endlosen Kettenreaktionen mit anderen Bots und lässt Misskeys interne Systeme dieses Benutzerkonto als Bot behandeln."
|
||||||
flagAsCat: "Als Katze markieren"
|
flagAsCat: "Als Katze markieren"
|
||||||
@@ -1074,26 +1070,6 @@ branding: "Branding"
|
|||||||
enableServerMachineStats: "Hardwareinformationen des Servers veröffentlichen"
|
enableServerMachineStats: "Hardwareinformationen des Servers veröffentlichen"
|
||||||
enableIdenticonGeneration: "Generierung von Benutzer-Identicons aktivieren"
|
enableIdenticonGeneration: "Generierung von Benutzer-Identicons aktivieren"
|
||||||
turnOffToImprovePerformance: "Deaktivierung kann zu höherer Leistung führen."
|
turnOffToImprovePerformance: "Deaktivierung kann zu höherer Leistung führen."
|
||||||
createInviteCode: "Einladung erstellen"
|
|
||||||
createWithOptions: "Einladung mit Optionen erstellen"
|
|
||||||
createCount: "Einladungsanzahl"
|
|
||||||
inviteCodeCreated: "Einladung erstellt"
|
|
||||||
inviteLimitExceeded: "Du hast das Maximum an erstellbaren Einladungen erreicht."
|
|
||||||
createLimitRemaining: "Erstellbare Einladungen: Noch {limit}"
|
|
||||||
inviteLimitResetCycle: "Am {time} wird dies auf {limit} zurückgesetzt."
|
|
||||||
expirationDate: "Ablaufdatum"
|
|
||||||
noExpirationDate: "Keins"
|
|
||||||
inviteCodeUsedAt: "Einladung verwendet am"
|
|
||||||
registeredUserUsingInviteCode: "Einladung verwendet von"
|
|
||||||
waitingForMailAuth: "Bestätigungsemail ausstehend"
|
|
||||||
inviteCodeCreator: "Einladung erstellt von"
|
|
||||||
usedAt: "Benutzt am"
|
|
||||||
unused: "Unbenutzt"
|
|
||||||
used: "Benutzt"
|
|
||||||
expired: "Abgelaufen"
|
|
||||||
doYouAgree: "Zustimmen?"
|
|
||||||
beSureToReadThisAsItIsImportant: "Lies bitte diese wichtige Informationen."
|
|
||||||
iHaveReadXCarefullyAndAgree: "Ich habe den Text \"{x}\" gelesen und stimme zu."
|
|
||||||
_initialAccountSetting:
|
_initialAccountSetting:
|
||||||
accountCreated: "Dein Konto wurde erfolgreich erstellt!"
|
accountCreated: "Dein Konto wurde erfolgreich erstellt!"
|
||||||
letsStartAccountSetup: "Lass uns nun dein Konto einrichten."
|
letsStartAccountSetup: "Lass uns nun dein Konto einrichten."
|
||||||
@@ -1404,9 +1380,6 @@ _role:
|
|||||||
ltlAvailable: "Kann auf die lokale Chronik zugreifen"
|
ltlAvailable: "Kann auf die lokale Chronik zugreifen"
|
||||||
canPublicNote: "Kann öffentliche Notizen erstellen"
|
canPublicNote: "Kann öffentliche Notizen erstellen"
|
||||||
canInvite: "Erstellung von Einladungscodes für diese Instanz"
|
canInvite: "Erstellung von Einladungscodes für diese Instanz"
|
||||||
inviteLimit: "Maximalanzahl an Einladungen"
|
|
||||||
inviteLimitCycle: "Zyklus des Einladungslimits"
|
|
||||||
inviteExpirationTime: "Gültigkeitsdauer von Einladungen"
|
|
||||||
canManageCustomEmojis: "Benutzerdefinierte Emojis verwalten"
|
canManageCustomEmojis: "Benutzerdefinierte Emojis verwalten"
|
||||||
driveCapacity: "Drive-Kapazität"
|
driveCapacity: "Drive-Kapazität"
|
||||||
alwaysMarkNsfw: "Dateien immer als NSFW markieren"
|
alwaysMarkNsfw: "Dateien immer als NSFW markieren"
|
||||||
@@ -1999,7 +1972,6 @@ _deck:
|
|||||||
introduction: "Erstelle eine auf dich zugeschneiderte Benutzeroberfläche durch das Aneinanderreihen von Spalten!"
|
introduction: "Erstelle eine auf dich zugeschneiderte Benutzeroberfläche durch das Aneinanderreihen von Spalten!"
|
||||||
introduction2: "Klicke auf das + rechts um wann immer du möchtest neue Spalten hinzuzufügen."
|
introduction2: "Klicke auf das + rechts um wann immer du möchtest neue Spalten hinzuzufügen."
|
||||||
widgetsIntroduction: "Drücke bitte \"Widgets bearbeiten\" im Spaltenmenü und füge ein Widget hinzu."
|
widgetsIntroduction: "Drücke bitte \"Widgets bearbeiten\" im Spaltenmenü und füge ein Widget hinzu."
|
||||||
useSimpleUiForNonRootPages: "Simple Benutzeroberfläche für navigierte Seiten verwenden"
|
|
||||||
_columns:
|
_columns:
|
||||||
main: "Hauptspalte"
|
main: "Hauptspalte"
|
||||||
widgets: "Widgets"
|
widgets: "Widgets"
|
||||||
|
@@ -49,7 +49,6 @@ delete: "Delete"
|
|||||||
deleteAndEdit: "Delete and edit"
|
deleteAndEdit: "Delete and edit"
|
||||||
deleteAndEditConfirm: "Are you sure you want to delete this note and edit it? You will lose all reactions, renotes and replies to it."
|
deleteAndEditConfirm: "Are you sure you want to delete this note and edit it? You will lose all reactions, renotes and replies to it."
|
||||||
addToList: "Add to list"
|
addToList: "Add to list"
|
||||||
addToAntenna: "Add to antenna"
|
|
||||||
sendMessage: "Send a message"
|
sendMessage: "Send a message"
|
||||||
copyRSS: "Copy RSS"
|
copyRSS: "Copy RSS"
|
||||||
copyUsername: "Copy username"
|
copyUsername: "Copy username"
|
||||||
@@ -57,7 +56,6 @@ copyUserId: "Copy user ID"
|
|||||||
copyNoteId: "Copy note ID"
|
copyNoteId: "Copy note ID"
|
||||||
copyFileId: "Copy file ID"
|
copyFileId: "Copy file ID"
|
||||||
copyFolderId: "Copy folder ID"
|
copyFolderId: "Copy folder ID"
|
||||||
copyProfileUrl: "Copy profile URL"
|
|
||||||
searchUser: "Search for a user"
|
searchUser: "Search for a user"
|
||||||
reply: "Reply"
|
reply: "Reply"
|
||||||
loadMore: "Load more"
|
loadMore: "Load more"
|
||||||
@@ -156,8 +154,6 @@ addEmoji: "Add an emoji"
|
|||||||
settingGuide: "Recommended settings"
|
settingGuide: "Recommended settings"
|
||||||
cacheRemoteFiles: "Cache remote files"
|
cacheRemoteFiles: "Cache remote files"
|
||||||
cacheRemoteFilesDescription: "When this setting is disabled, remote files are loaded directly from the remote instance. Disabling this will decrease storage usage, but increase traffic, as thumbnails will not be generated."
|
cacheRemoteFilesDescription: "When this setting is disabled, remote files are loaded directly from the remote instance. Disabling this will decrease storage usage, but increase traffic, as thumbnails will not be generated."
|
||||||
cacheRemoteSensitiveFiles: "Cache sensitive remote files"
|
|
||||||
cacheRemoteSensitiveFilesDescription: "When this setting is disabled, sensitive remote files are loaded directly from the remote instance without caching."
|
|
||||||
flagAsBot: "Mark this account as a bot"
|
flagAsBot: "Mark this account as a bot"
|
||||||
flagAsBotDescription: "Enable this option if this account is controlled by a program. If enabled, it will act as a flag for other developers to prevent endless interaction chains with other bots and adjust Misskey's internal systems to treat this account as a bot."
|
flagAsBotDescription: "Enable this option if this account is controlled by a program. If enabled, it will act as a flag for other developers to prevent endless interaction chains with other bots and adjust Misskey's internal systems to treat this account as a bot."
|
||||||
flagAsCat: "Mark this account as a cat"
|
flagAsCat: "Mark this account as a cat"
|
||||||
@@ -1074,26 +1070,6 @@ branding: "Branding"
|
|||||||
enableServerMachineStats: "Publish server hardware stats"
|
enableServerMachineStats: "Publish server hardware stats"
|
||||||
enableIdenticonGeneration: "Enable user identicon generation"
|
enableIdenticonGeneration: "Enable user identicon generation"
|
||||||
turnOffToImprovePerformance: "Turning this off can increase performance."
|
turnOffToImprovePerformance: "Turning this off can increase performance."
|
||||||
createInviteCode: "Generate invite"
|
|
||||||
createWithOptions: "Generate with options"
|
|
||||||
createCount: "Invite count"
|
|
||||||
inviteCodeCreated: "Invite generated"
|
|
||||||
inviteLimitExceeded: "You've exceeded the limit of invites you can generate."
|
|
||||||
createLimitRemaining: "Invite limit: {limit} remaining"
|
|
||||||
inviteLimitResetCycle: "This limit will reset to {limit} at {time}."
|
|
||||||
expirationDate: "Expiration date"
|
|
||||||
noExpirationDate: "No expiration"
|
|
||||||
inviteCodeUsedAt: "Invite code used at"
|
|
||||||
registeredUserUsingInviteCode: "Invite used by"
|
|
||||||
waitingForMailAuth: "Email verification pending"
|
|
||||||
inviteCodeCreator: "Invite created by"
|
|
||||||
usedAt: "Used at"
|
|
||||||
unused: "Unused"
|
|
||||||
used: "Used"
|
|
||||||
expired: "Expired"
|
|
||||||
doYouAgree: "Agree?"
|
|
||||||
beSureToReadThisAsItIsImportant: "Please read this important information."
|
|
||||||
iHaveReadXCarefullyAndAgree: "I have read the text \"{x}\" and agree."
|
|
||||||
_initialAccountSetting:
|
_initialAccountSetting:
|
||||||
accountCreated: "Your account was successfully created!"
|
accountCreated: "Your account was successfully created!"
|
||||||
letsStartAccountSetup: "For starters, let's set up your profile."
|
letsStartAccountSetup: "For starters, let's set up your profile."
|
||||||
@@ -1404,9 +1380,6 @@ _role:
|
|||||||
ltlAvailable: "Can view the local timeline"
|
ltlAvailable: "Can view the local timeline"
|
||||||
canPublicNote: "Can send public notes"
|
canPublicNote: "Can send public notes"
|
||||||
canInvite: "Can create instance invite codes"
|
canInvite: "Can create instance invite codes"
|
||||||
inviteLimit: "Invite limit"
|
|
||||||
inviteLimitCycle: "Invite limit cooldown"
|
|
||||||
inviteExpirationTime: "Invite expiration interval"
|
|
||||||
canManageCustomEmojis: "Can manage custom emojis"
|
canManageCustomEmojis: "Can manage custom emojis"
|
||||||
driveCapacity: "Drive capacity"
|
driveCapacity: "Drive capacity"
|
||||||
alwaysMarkNsfw: "Always mark files as NSFW"
|
alwaysMarkNsfw: "Always mark files as NSFW"
|
||||||
@@ -1999,7 +1972,6 @@ _deck:
|
|||||||
introduction: "Create the perfect interface for you by arranging columns freely!"
|
introduction: "Create the perfect interface for you by arranging columns freely!"
|
||||||
introduction2: "Click on the + on the right of the screen to add new colums whenever you want."
|
introduction2: "Click on the + on the right of the screen to add new colums whenever you want."
|
||||||
widgetsIntroduction: "Please select \"Edit widgets\" in the column menu and add a widget."
|
widgetsIntroduction: "Please select \"Edit widgets\" in the column menu and add a widget."
|
||||||
useSimpleUiForNonRootPages: "Use simple UI for navigated pages"
|
|
||||||
_columns:
|
_columns:
|
||||||
main: "Main"
|
main: "Main"
|
||||||
widgets: "Widgets"
|
widgets: "Widgets"
|
||||||
|
@@ -49,15 +49,11 @@ delete: "Borrar"
|
|||||||
deleteAndEdit: "Borrar y editar"
|
deleteAndEdit: "Borrar y editar"
|
||||||
deleteAndEditConfirm: "¿Estás seguro de que quieres borrar esta nota y editarla? Perderás todas las reacciones, renotas y respuestas."
|
deleteAndEditConfirm: "¿Estás seguro de que quieres borrar esta nota y editarla? Perderás todas las reacciones, renotas y respuestas."
|
||||||
addToList: "Agregar a lista"
|
addToList: "Agregar a lista"
|
||||||
addToAntenna: "Añadir a la antena"
|
|
||||||
sendMessage: "Enviar un mensaje"
|
sendMessage: "Enviar un mensaje"
|
||||||
copyRSS: "Copiar RSS"
|
copyRSS: "Copiar RSS"
|
||||||
copyUsername: "Copiar nombre de usuario"
|
copyUsername: "Copiar nombre de usuario"
|
||||||
copyUserId: "Copiar ID del usuario"
|
copyUserId: "Copiar ID del usuario"
|
||||||
copyNoteId: "Copiar ID de la nota"
|
copyNoteId: "Copiar ID de la nota"
|
||||||
copyFileId: "Copiar un archivo ID"
|
|
||||||
copyFolderId: "Copiar carpeta ID"
|
|
||||||
copyProfileUrl: "Copiar la URL del perfil"
|
|
||||||
searchUser: "Buscar un usuario"
|
searchUser: "Buscar un usuario"
|
||||||
reply: "Responder"
|
reply: "Responder"
|
||||||
loadMore: "Ver más"
|
loadMore: "Ver más"
|
||||||
@@ -156,8 +152,6 @@ addEmoji: "Agregar emoji"
|
|||||||
settingGuide: "Configuración sugerida"
|
settingGuide: "Configuración sugerida"
|
||||||
cacheRemoteFiles: "Mantener en cache los archivos remotos"
|
cacheRemoteFiles: "Mantener en cache los archivos remotos"
|
||||||
cacheRemoteFilesDescription: "Si desactiva esta configuración, Los archivos remotos se cargarán desde el link directo sin usar la caché. Con eso se puede ahorrar almacenamiento del servidor, pero eso aumentará el tráfico al no crear miniaturas."
|
cacheRemoteFilesDescription: "Si desactiva esta configuración, Los archivos remotos se cargarán desde el link directo sin usar la caché. Con eso se puede ahorrar almacenamiento del servidor, pero eso aumentará el tráfico al no crear miniaturas."
|
||||||
cacheRemoteSensitiveFiles: "Cachear archivos remotos sensibles"
|
|
||||||
cacheRemoteSensitiveFilesDescription: "Cuando esta opción está desactivada, los archivos remotos sensibles son cargador directamente de la instancia origen sin ser cacheados."
|
|
||||||
flagAsBot: "Esta cuenta es un bot"
|
flagAsBot: "Esta cuenta es un bot"
|
||||||
flagAsBotDescription: "En caso de que esta cuenta fuera usada por un programa, active esta opción. Al hacerlo, esta opción servirá para otros desarrolladores para evitar cadenas infinitas de reacciones, y ajustará los sistemas internos de Misskey para que trate a esta cuenta como un bot."
|
flagAsBotDescription: "En caso de que esta cuenta fuera usada por un programa, active esta opción. Al hacerlo, esta opción servirá para otros desarrolladores para evitar cadenas infinitas de reacciones, y ajustará los sistemas internos de Misskey para que trate a esta cuenta como un bot."
|
||||||
flagAsCat: "Esta cuenta es un gato"
|
flagAsCat: "Esta cuenta es un gato"
|
||||||
@@ -319,7 +313,6 @@ copyUrl: "Copiar URL"
|
|||||||
rename: "Renombrar"
|
rename: "Renombrar"
|
||||||
avatar: "Avatar"
|
avatar: "Avatar"
|
||||||
banner: "Banner"
|
banner: "Banner"
|
||||||
displayOfSensitiveMedia: "Mostrar contenido sensible"
|
|
||||||
whenServerDisconnected: "Cuando se pierda la conexión con el servidor"
|
whenServerDisconnected: "Cuando se pierda la conexión con el servidor"
|
||||||
disconnectedFromServer: "Desconectado del servidor"
|
disconnectedFromServer: "Desconectado del servidor"
|
||||||
reload: "Recargar"
|
reload: "Recargar"
|
||||||
@@ -854,7 +847,7 @@ manageAccounts: "Administrar cuenta"
|
|||||||
makeReactionsPublic: "Hacer el historial de reacciones público"
|
makeReactionsPublic: "Hacer el historial de reacciones público"
|
||||||
makeReactionsPublicDescription: "Todas las reacciones que hayas hecho serán públicamente visibles."
|
makeReactionsPublicDescription: "Todas las reacciones que hayas hecho serán públicamente visibles."
|
||||||
classic: "Clásico"
|
classic: "Clásico"
|
||||||
muteThread: "Silenciar hilo"
|
muteThread: "Ocultar hilo"
|
||||||
unmuteThread: "Mostrar hilo"
|
unmuteThread: "Mostrar hilo"
|
||||||
ffVisibility: "Visibilidad de seguidores y seguidos"
|
ffVisibility: "Visibilidad de seguidores y seguidos"
|
||||||
ffVisibilityDescription: "Puedes configurar quien puede ver a quienes sigues y quienes te siguen"
|
ffVisibilityDescription: "Puedes configurar quien puede ver a quienes sigues y quienes te siguen"
|
||||||
@@ -1001,12 +994,10 @@ reactionAcceptance: "Aceptación de reacciones"
|
|||||||
likeOnly: "Sólo 'me gusta'"
|
likeOnly: "Sólo 'me gusta'"
|
||||||
likeOnlyForRemote: "Sólo reacciones de instancias remotas"
|
likeOnlyForRemote: "Sólo reacciones de instancias remotas"
|
||||||
nonSensitiveOnly: "Solo no sensible"
|
nonSensitiveOnly: "Solo no sensible"
|
||||||
nonSensitiveOnlyForLocalLikeOnlyForRemote: "Sólo no contenido sensible (sólo me gusta en remote)"
|
|
||||||
rolesAssignedToMe: "Roles asignados a mí"
|
rolesAssignedToMe: "Roles asignados a mí"
|
||||||
resetPasswordConfirm: "¿Realmente quieres cambiar la contraseña?"
|
resetPasswordConfirm: "¿Realmente quieres cambiar la contraseña?"
|
||||||
sensitiveWords: "Palabras sensibles"
|
sensitiveWords: "Palabras sensibles"
|
||||||
sensitiveWordsDescription: "La visibilidad de todas las notas que contienen cualquiera de las palabras configuradas serán puestas en \"Inicio\" automáticamente. Puedes enumerás varias separándolas con saltos de línea"
|
sensitiveWordsDescription: "La visibilidad de todas las notas que contienen cualquiera de las palabras configuradas serán puestas en \"Inicio\" automáticamente. Puedes enumerás varias separándolas con saltos de línea"
|
||||||
sensitiveWordsDescription2: "Si se usan espacios se crearán expresiones AND y las palabras subsecuentes con barras inclinadas se convertirán en expresiones regulares."
|
|
||||||
notesSearchNotAvailable: "No se puede buscar una nota"
|
notesSearchNotAvailable: "No se puede buscar una nota"
|
||||||
license: "Licencia"
|
license: "Licencia"
|
||||||
unfavoriteConfirm: "¿Desea quitar de favoritos?"
|
unfavoriteConfirm: "¿Desea quitar de favoritos?"
|
||||||
@@ -1026,74 +1017,25 @@ dataSaver: "Ahorro de datos"
|
|||||||
accountMigration: "Migración de cuenta"
|
accountMigration: "Migración de cuenta"
|
||||||
accountMoved: "Este usuario se movió a una nueva cuenta:"
|
accountMoved: "Este usuario se movió a una nueva cuenta:"
|
||||||
accountMovedShort: "Esta cuenta ha sido migrada."
|
accountMovedShort: "Esta cuenta ha sido migrada."
|
||||||
operationForbidden: "Operación prohibida"
|
|
||||||
forceShowAds: "Siempre mostrar anuncios"
|
|
||||||
addMemo: "Añadir nota"
|
addMemo: "Añadir nota"
|
||||||
editMemo: "Editar nota"
|
editMemo: "Editar nota"
|
||||||
reactionsList: "Lista de reacciones"
|
reactionsList: "Lista de reacciones"
|
||||||
renotesList: "Renotas"
|
renotesList: "Renotas"
|
||||||
notificationDisplay: "Notificaciones"
|
|
||||||
leftTop: "Arriba a la izquierda"
|
|
||||||
rightTop: "Arriba a la derecha"
|
|
||||||
leftBottom: "Abajo a la izquierda"
|
|
||||||
rightBottom: "Abajo a la derecha"
|
|
||||||
stackAxis: "Dirección de apilado"
|
stackAxis: "Dirección de apilado"
|
||||||
vertical: "Vertical"
|
|
||||||
horizontal: "Horizontal"
|
horizontal: "Horizontal"
|
||||||
position: "Posición"
|
position: "Posición"
|
||||||
serverRules: "Reglas del servidor"
|
serverRules: "Reglas del servidor"
|
||||||
pleaseConfirmBelowBeforeSignup: "Por favor confirma antes de continuar el registro"
|
|
||||||
pleaseAgreeAllToContinue: "Tienes que estar de acuerdo con los campos anteriores para contnuar."
|
|
||||||
continue: "Continuar"
|
continue: "Continuar"
|
||||||
preservedUsernames: "Nombre de usuario reservado"
|
preservedUsernames: "Nombre de usuario reservado"
|
||||||
preservedUsernamesDescription: "La lista de nombres de usuario para reservar tienen que separarse con saltos de línea.\nEstos estarán indisponibles durante la creación de cuentas, pero pueden ser usados para que los administradores puedan crear esas cuentas manualmente. Las cuentas existentes con esos nombres de usuario no se verán afectadas."
|
|
||||||
createNoteFromTheFile: "Componer una nota desde éste archivo"
|
|
||||||
archive: "Archivo"
|
archive: "Archivo"
|
||||||
channelArchiveConfirmTitle: "¿Seguro de archivar {name}?"
|
channelArchiveConfirmTitle: "¿Seguro de archivar {name}?"
|
||||||
channelArchiveConfirmDescription: "Un canal archivado no aparecerá en la lista de canales ni en los resultados. Las nuevas publicaciones tampoco serán añadidas."
|
|
||||||
thisChannelArchived: "El canal ha sido archivado."
|
|
||||||
displayOfNote: "Mostrar notas"
|
|
||||||
initialAccountSetting: "Configración inicial de su cuenta\nか\nConfigración de inicio"
|
|
||||||
youFollowing: "Siguiendo"
|
youFollowing: "Siguiendo"
|
||||||
preventAiLearning: "Rechazar el uso en el Aprendizaje de Máquinas. (IA Generativa)"
|
|
||||||
preventAiLearningDescription: "Pedirle a las arañas (crawlers) no usar los textos publicados o imágenes en el aprendizaje automático (IA Predictiva / Generativa). Ésto se logra añadiendo una marca respuesta HTML con la cadena \"noai\" al cantenido. Una prevención total no podría lograrse sólo usando ésta marca, ya que puede ser simplemente ignorada."
|
|
||||||
options: "Opción"
|
options: "Opción"
|
||||||
specifyUser: "Especificar usuario"
|
|
||||||
failedToPreviewUrl: "No se pudo generar la vista previa"
|
|
||||||
update: "Actualizar"
|
update: "Actualizar"
|
||||||
rolesThatCanBeUsedThisEmojiAsReaction: "Roles que pueden usar este emoji como reacción"
|
|
||||||
rolesThatCanBeUsedThisEmojiAsReactionEmptyDescription: "Si no se especifican roles, cualquiera podrá usar éste emoji como reacción."
|
|
||||||
rolesThatCanBeUsedThisEmojiAsReactionPublicRoleWarn: "Éstos roles deben ser públicos."
|
|
||||||
cancelReactionConfirm: "¿Realmente quieres eliminar la reacción?"
|
|
||||||
changeReactionConfirm: "¿Realmente quieres cambiar la reacción?"
|
|
||||||
later: "Ahora no"
|
|
||||||
goToMisskey: "ir a Misskey"
|
|
||||||
additionalEmojiDictionary: "Diccionario adicional de Emoji"
|
|
||||||
installed: "Instalado"
|
installed: "Instalado"
|
||||||
branding: "Marca"
|
branding: "Marca"
|
||||||
enableServerMachineStats: "Publicar estadísticas de hardware del servidor"
|
enableServerMachineStats: "Publicar estadísticas de hardware del servidor"
|
||||||
enableIdenticonGeneration: "Activar generación de identicon por usuario"
|
enableIdenticonGeneration: "Activar generación de identicon por usuario"
|
||||||
turnOffToImprovePerformance: "Desactivar esto puede aumentar el rendimiento."
|
|
||||||
createInviteCode: "Generar invitación"
|
|
||||||
createWithOptions: "Generar con opciones"
|
|
||||||
createCount: "Conteo de invitaciones"
|
|
||||||
inviteCodeCreated: "Invitación generada"
|
|
||||||
inviteLimitExceeded: "Has excedido el límite de invitaciones que puedes generar."
|
|
||||||
createLimitRemaining: "Límite de invitaciones: quedan {limit}"
|
|
||||||
inviteLimitResetCycle: "El límite ha sido reiniciado a {limit} por {time}."
|
|
||||||
expirationDate: "Fecha de caducidad"
|
|
||||||
noExpirationDate: "Sin caducidad"
|
|
||||||
inviteCodeUsedAt: "Código de invitación usado el"
|
|
||||||
registeredUserUsingInviteCode: "Invitación usada por"
|
|
||||||
waitingForMailAuth: "Verificación de correo pendiente"
|
|
||||||
inviteCodeCreator: "Invitación creada por"
|
|
||||||
usedAt: "Usada el"
|
|
||||||
unused: "Sin usar"
|
|
||||||
used: "Usada"
|
|
||||||
expired: "Caducada"
|
|
||||||
doYouAgree: "¿Está de acuerdo?"
|
|
||||||
beSureToReadThisAsItIsImportant: "Por favor lea esto que es importante"
|
|
||||||
iHaveReadXCarefullyAndAgree: "He leído el texto {x} y estoy de acuerdo"
|
|
||||||
_initialAccountSetting:
|
_initialAccountSetting:
|
||||||
accountCreated: "¡La cuenta ha sido creada!"
|
accountCreated: "¡La cuenta ha sido creada!"
|
||||||
letsStartAccountSetup: "Para empezar, creemos tu perfil."
|
letsStartAccountSetup: "Para empezar, creemos tu perfil."
|
||||||
@@ -1103,28 +1045,14 @@ _initialAccountSetting:
|
|||||||
theseSettingsCanEditLater: "Puedes cambiar estos ajustes más tarde."
|
theseSettingsCanEditLater: "Puedes cambiar estos ajustes más tarde."
|
||||||
youCanEditMoreSettingsInSettingsPageLater: "Desde la pestaña de \"Configuración\" puedes modificar más ajustes. Asegúrate de visitarla después."
|
youCanEditMoreSettingsInSettingsPageLater: "Desde la pestaña de \"Configuración\" puedes modificar más ajustes. Asegúrate de visitarla después."
|
||||||
followUsers: "Comienza a seguir a usuarios que te interesen para construir tu línea de tiempo."
|
followUsers: "Comienza a seguir a usuarios que te interesen para construir tu línea de tiempo."
|
||||||
pushNotificationDescription: "Habilitar las notificaciones push te permitirá recibir notificaciones de {name} directamente en tu dispositivo."
|
|
||||||
initialAccountSettingCompleted: "¡Configuración del perfil completada!"
|
|
||||||
haveFun: "¡Disfruta de {name}!"
|
|
||||||
ifYouNeedLearnMore: "Si quieres aprender cómo usar {name} (Misskey), por favor, visita {link}."
|
|
||||||
skipAreYouSure: "¿Realmente quieres saltarte la configuración del perfil?"
|
|
||||||
laterAreYouSure: "¿Realmente quieres configurar tu perfil después?"
|
|
||||||
_serverRules:
|
|
||||||
description: "Un conjunto de reglas que serán mostradas antes del registro. Configurar un sumario de términos de servicio es recomendado."
|
|
||||||
_accountMigration:
|
_accountMigration:
|
||||||
moveFrom: "Trasladar de otra cuenta a ésta"
|
moveFrom: "Trasladar de otra cuenta a ésta"
|
||||||
moveFromSub: "Crear un alias para otra cuenta."
|
|
||||||
moveFromLabel: "Cuenta desde la que se realiza el traslado:"
|
moveFromLabel: "Cuenta desde la que se realiza el traslado:"
|
||||||
moveFromDescription: "Si quieres transferir seguidores de otra cuenta a esta cuenta y trasladarlos, tendrás que crear un alias aquí. Asegúrate de crearlo antes de realizar el traslado. Introduce la cuenta desde la que estás moviendo los seguidores así: @person@instance.com"
|
moveFromDescription: "Si quieres transferir seguidores de otra cuenta a esta cuenta y trasladarlos, tendrás que crear un alias aquí. Asegúrate de crearlo antes de realizar el traslado. Introduce la cuenta desde la que estás moviendo los seguidores así: @person@instance.com"
|
||||||
moveTo: "Mover esta cuenta a una nueva"
|
moveTo: "Mover esta cuenta a una nueva"
|
||||||
moveToLabel: "Cuenta destino:"
|
moveToLabel: "Cuenta destino:"
|
||||||
moveCannotBeUndone: "La migración de la cuenta no puede ser revertida."
|
|
||||||
moveAccountDescription: "Esta operación no puede deshacerse. En primer lugar, asegúrese de haber creado un alias para esta cuenta en la cuenta a la que se va a trasladar. Después de crear el alias, introduzca la cuenta a la que se está trasladando de la siguiente manera: @person@instance.com"
|
moveAccountDescription: "Esta operación no puede deshacerse. En primer lugar, asegúrese de haber creado un alias para esta cuenta en la cuenta a la que se va a trasladar. Después de crear el alias, introduzca la cuenta a la que se está trasladando de la siguiente manera: @person@instance.com"
|
||||||
moveAccountHowTo: "Para migrar, primero crea un alias para ésta cuenta en la cuenta a donde te moverás.\nDespués de crear el alias, ingresa la cuenta a mover de la siguiente forma:\n@usuario@servidor.ejempo.com"
|
|
||||||
startMigration: "Migrar"
|
|
||||||
migrationConfirm: "¿Estás seguro de que quieres mover esta cuenta a {account}? Una vez trasladada, no podrás deshacer el traslado y no podrás volver a utilizar la cuenta original.\n\nAdemás, compruebe que ha configurado un alias en el destino del traslado."
|
migrationConfirm: "¿Estás seguro de que quieres mover esta cuenta a {account}? Una vez trasladada, no podrás deshacer el traslado y no podrás volver a utilizar la cuenta original.\n\nAdemás, compruebe que ha configurado un alias en el destino del traslado."
|
||||||
movedAndCannotBeUndone: "\nLa migración decuenta ha sido completada.\nNo se puede revertir éste proceso."
|
|
||||||
postMigrationNote: "Ésta cuenta dejará de seguir a todas las cuentas en las siguientes 24 horas después de que finalice la migración.\nEl número de seguidos y seguidores serán 0. Para evitar que Para evitar que tus seguidores dejen de ver las publicaciones, todas serán marcadas como \"sólo seguidores\"."
|
|
||||||
movedTo: "Cuenta destino:"
|
movedTo: "Cuenta destino:"
|
||||||
_achievements:
|
_achievements:
|
||||||
earnedAt: "Desbloqueado el"
|
earnedAt: "Desbloqueado el"
|
||||||
@@ -1299,7 +1227,6 @@ _achievements:
|
|||||||
description: "30 minutos dedicados a Misskey"
|
description: "30 minutos dedicados a Misskey"
|
||||||
_client60min:
|
_client60min:
|
||||||
title: "Viendo mucho Misskey."
|
title: "Viendo mucho Misskey."
|
||||||
description: "Dejar abierto Misskey por al menos 60 minutos"
|
|
||||||
_noteDeletedWithin1min:
|
_noteDeletedWithin1min:
|
||||||
title: "Ah... Mejor no..."
|
title: "Ah... Mejor no..."
|
||||||
description: "Borrar una nota antes que de pase 1 minuto"
|
description: "Borrar una nota antes que de pase 1 minuto"
|
||||||
@@ -1388,8 +1315,6 @@ _role:
|
|||||||
iconUrl: "URL del ícono"
|
iconUrl: "URL del ícono"
|
||||||
asBadge: "Mostrar como emblema"
|
asBadge: "Mostrar como emblema"
|
||||||
descriptionOfAsBadge: "Este ícono de rol se mostrará a lado del nombre de usuario cuando este rol se encuentre activo."
|
descriptionOfAsBadge: "Este ícono de rol se mostrará a lado del nombre de usuario cuando este rol se encuentre activo."
|
||||||
isExplorable: "Hacer el rol explorable"
|
|
||||||
descriptionOfIsExplorable: "La línea de tiempo de éste rol y la lista de usuarios serán públicos si se activa.."
|
|
||||||
displayOrder: "Posición"
|
displayOrder: "Posición"
|
||||||
descriptionOfDisplayOrder: "Entre más alto el número, mayor es la posición en la interfaz."
|
descriptionOfDisplayOrder: "Entre más alto el número, mayor es la posición en la interfaz."
|
||||||
canEditMembersByModerator: "Permitir a los moderadores editar los miembros"
|
canEditMembersByModerator: "Permitir a los moderadores editar los miembros"
|
||||||
@@ -1404,12 +1329,8 @@ _role:
|
|||||||
ltlAvailable: "Explorar la línea de tiempo local"
|
ltlAvailable: "Explorar la línea de tiempo local"
|
||||||
canPublicNote: "Permitir la publicación"
|
canPublicNote: "Permitir la publicación"
|
||||||
canInvite: "Puede crear códigos de invitación"
|
canInvite: "Puede crear códigos de invitación"
|
||||||
inviteLimit: "Límite de invitaciones"
|
|
||||||
inviteLimitCycle: "Enfriamiento del límite de invitaciones"
|
|
||||||
inviteExpirationTime: "Intervalo de caducidad de invitaciones"
|
|
||||||
canManageCustomEmojis: "Administrar emojis personalizados"
|
canManageCustomEmojis: "Administrar emojis personalizados"
|
||||||
driveCapacity: "Capacidad del drive"
|
driveCapacity: "Capacidad del drive"
|
||||||
alwaysMarkNsfw: "Siempre marcar archivos como NSFW"
|
|
||||||
pinMax: "Máximo de notas fijadas"
|
pinMax: "Máximo de notas fijadas"
|
||||||
antennaMax: "Máximo de antenas"
|
antennaMax: "Máximo de antenas"
|
||||||
wordMuteMax: "Máximo de caracteres en palabras silenciadas"
|
wordMuteMax: "Máximo de caracteres en palabras silenciadas"
|
||||||
@@ -1469,7 +1390,6 @@ _ad:
|
|||||||
back: "Deseleccionar"
|
back: "Deseleccionar"
|
||||||
reduceFrequencyOfThisAd: "Mostrar menos este anuncio."
|
reduceFrequencyOfThisAd: "Mostrar menos este anuncio."
|
||||||
hide: "No mostrar"
|
hide: "No mostrar"
|
||||||
timezoneinfo: "El día de la semana está determidado por la zona horaria del servidor."
|
|
||||||
_forgotPassword:
|
_forgotPassword:
|
||||||
enterEmail: "Ingrese el correo usado para registrar la cuenta. Se enviará un link para resetear la contraseña."
|
enterEmail: "Ingrese el correo usado para registrar la cuenta. Se enviará un link para resetear la contraseña."
|
||||||
ifNoEmail: "Si no utilizó un correo para crear la cuenta, contáctese con el administrador."
|
ifNoEmail: "Si no utilizó un correo para crear la cuenta, contáctese con el administrador."
|
||||||
@@ -1521,10 +1441,6 @@ _aboutMisskey:
|
|||||||
donate: "Donar a Misskey"
|
donate: "Donar a Misskey"
|
||||||
morePatrons: "Muchas más personas nos apoyan. Muchas gracias🥰"
|
morePatrons: "Muchas más personas nos apoyan. Muchas gracias🥰"
|
||||||
patrons: "Patrocinadores"
|
patrons: "Patrocinadores"
|
||||||
_displayOfSensitiveMedia:
|
|
||||||
respect: "Esconder medios marcados como sensibles"
|
|
||||||
ignore: "Mostrar medios marcados como sensibles"
|
|
||||||
force: "Esconder todala multimedia"
|
|
||||||
_instanceTicker:
|
_instanceTicker:
|
||||||
none: "No mostrar"
|
none: "No mostrar"
|
||||||
remote: "Mostrar a usuarios remotos"
|
remote: "Mostrar a usuarios remotos"
|
||||||
@@ -1543,8 +1459,6 @@ _channel:
|
|||||||
following: "Siguiendo"
|
following: "Siguiendo"
|
||||||
usersCount: "{n} participantes"
|
usersCount: "{n} participantes"
|
||||||
notesCount: "{n} notas"
|
notesCount: "{n} notas"
|
||||||
nameAndDescription: "Nombre y descripción"
|
|
||||||
nameOnly: "Sólo nombre"
|
|
||||||
_menuDisplay:
|
_menuDisplay:
|
||||||
sideFull: "Horizontal"
|
sideFull: "Horizontal"
|
||||||
sideIcon: "Horizontal (ícono)"
|
sideIcon: "Horizontal (ícono)"
|
||||||
@@ -1663,13 +1577,6 @@ _time:
|
|||||||
hour: "Horas"
|
hour: "Horas"
|
||||||
day: "Días"
|
day: "Días"
|
||||||
_timelineTutorial:
|
_timelineTutorial:
|
||||||
title: "Cómo usar Misskey"
|
|
||||||
step1_1: "Ésta es la \"línea de tiempo\". Todas las \"notas\" que sean publicadas en {name} serán mostradas cronológicamente aquí."
|
|
||||||
step1_2: "Hay varias líneas de tiempo. Por ejemplo, la línea temporal \"Inicio\" contiene las notas de otros usuarios que sigues, y la línea \"Local\" contandrá las notas de todos los usuarios de {name}."
|
|
||||||
step2_1: "Ahora probemos publicar una nota. Puedes hacerlo presionando el botón que tiene un ícono de lápiz."
|
|
||||||
step2_2: "¿Qué tal si escribimos una introducción? o sólo un \"¡Hola {name}!\" ¿No te apetece?"
|
|
||||||
step3_1: "¿Terminaste de publicar tu primera nota?"
|
|
||||||
step3_2: "Tu primera nota ahora se mostrará en tu línea de tiempo."
|
|
||||||
step4_1: "También puedes añadir \"Reacciones\" a notas."
|
step4_1: "También puedes añadir \"Reacciones\" a notas."
|
||||||
step4_2: "Para añadir una reacción selecciona el botón \"+\" en la nota y escoge el emoji que quieras para reaccionar."
|
step4_2: "Para añadir una reacción selecciona el botón \"+\" en la nota y escoge el emoji que quieras para reaccionar."
|
||||||
_2fa:
|
_2fa:
|
||||||
@@ -1999,7 +1906,6 @@ _deck:
|
|||||||
introduction: "¡Crea la interfaz perfecta para tí organizando las columnas libremente!"
|
introduction: "¡Crea la interfaz perfecta para tí organizando las columnas libremente!"
|
||||||
introduction2: "Presiona en la + de la derecha de la pantalla para añadir nuevas columnas donde quieras."
|
introduction2: "Presiona en la + de la derecha de la pantalla para añadir nuevas columnas donde quieras."
|
||||||
widgetsIntroduction: "Por favor selecciona \"Editar Widgets\" en el menú columna y agrega un widget."
|
widgetsIntroduction: "Por favor selecciona \"Editar Widgets\" en el menú columna y agrega un widget."
|
||||||
useSimpleUiForNonRootPages: "Mostrar páginas no pertenecientes a la raíz con la interfaz simple"
|
|
||||||
_columns:
|
_columns:
|
||||||
main: "Principal"
|
main: "Principal"
|
||||||
widgets: "Widgets"
|
widgets: "Widgets"
|
||||||
@@ -2010,7 +1916,6 @@ _deck:
|
|||||||
channel: "Canal"
|
channel: "Canal"
|
||||||
mentions: "Menciones"
|
mentions: "Menciones"
|
||||||
direct: "Notas directas"
|
direct: "Notas directas"
|
||||||
roleTimeline: "Linea de tiempo del rol"
|
|
||||||
_dialog:
|
_dialog:
|
||||||
charactersExceeded: "¡Has excedido el límite de caracteres! Actualmente {current} de {max}."
|
charactersExceeded: "¡Has excedido el límite de caracteres! Actualmente {current} de {max}."
|
||||||
charactersBelow: "¡Estás por debajo del límite de caracteres! Actualmente {current} de {min}."
|
charactersBelow: "¡Estás por debajo del límite de caracteres! Actualmente {current} de {min}."
|
||||||
|
@@ -49,15 +49,9 @@ delete: "Supprimer"
|
|||||||
deleteAndEdit: "Supprimer et réécrire"
|
deleteAndEdit: "Supprimer et réécrire"
|
||||||
deleteAndEditConfirm: "Êtes-vous sûr·e de vouloir supprimer cette note et la reformuler ? Vous perdrez toutes les réactions, renotes et réponses y afférentes."
|
deleteAndEditConfirm: "Êtes-vous sûr·e de vouloir supprimer cette note et la reformuler ? Vous perdrez toutes les réactions, renotes et réponses y afférentes."
|
||||||
addToList: "Ajouter à une liste"
|
addToList: "Ajouter à une liste"
|
||||||
addToAntenna: "Ajouter à l’antenne"
|
|
||||||
sendMessage: "Envoyer un message"
|
sendMessage: "Envoyer un message"
|
||||||
copyRSS: "Copier le RSS"
|
copyRSS: "Copier le RSS"
|
||||||
copyUsername: "Copier le nom d’utilisateur·rice"
|
copyUsername: "Copier le nom d’utilisateur·rice"
|
||||||
copyUserId: "Copier l'identifiant de l'utilisateur"
|
|
||||||
copyNoteId: "Copier l'identifiant de la note"
|
|
||||||
copyFileId: "Copier l'identifiant du fichier"
|
|
||||||
copyFolderId: "Copier l'identifiant du dossier"
|
|
||||||
copyProfileUrl: "Copier l'URL du profil"
|
|
||||||
searchUser: "Chercher un·e utilisateur·rice"
|
searchUser: "Chercher un·e utilisateur·rice"
|
||||||
reply: "Répondre"
|
reply: "Répondre"
|
||||||
loadMore: "Afficher plus …"
|
loadMore: "Afficher plus …"
|
||||||
@@ -140,7 +134,6 @@ unsuspendConfirm: "Êtes-vous sûr·e de vouloir annuler la suspension de ce com
|
|||||||
selectList: "Sélectionner une liste"
|
selectList: "Sélectionner une 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"
|
|
||||||
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"
|
||||||
@@ -153,8 +146,6 @@ addEmoji: "Ajouter un émoji"
|
|||||||
settingGuide: "Configuration proposée"
|
settingGuide: "Configuration proposée"
|
||||||
cacheRemoteFiles: "Mise en cache des fichiers distants"
|
cacheRemoteFiles: "Mise en cache des fichiers distants"
|
||||||
cacheRemoteFilesDescription: "Lorsque cette option est désactivée, les fichiers distants sont chargés directement depuis l’instance distante. La désactiver diminuera certes l’utilisation de l’espace de stockage local mais augmentera le trafic réseau puisque les miniatures ne seront plus générées."
|
cacheRemoteFilesDescription: "Lorsque cette option est désactivée, les fichiers distants sont chargés directement depuis l’instance distante. La désactiver diminuera certes l’utilisation de l’espace de stockage local mais augmentera le trafic réseau puisque les miniatures ne seront plus générées."
|
||||||
cacheRemoteSensitiveFiles: "Mettre en cache les fichiers distants sensibles"
|
|
||||||
cacheRemoteSensitiveFilesDescription: "Si vous désactivez ce paramètre, les fichiers sensibles distants ne seront pas mis en cache et un lien direct sera utilisé à la place"
|
|
||||||
flagAsBot: "Ce compte est un robot"
|
flagAsBot: "Ce compte est un robot"
|
||||||
flagAsBotDescription: "Si ce compte est géré de manière automatisée, choisissez cette option. Si elle est activée, elle agira comme un marqueur pour les autres développeurs afin d'éviter des chaînes d'interaction sans fin avec d'autres robots et d'ajuster les systèmes internes de Misskey pour traiter ce compte comme un robot."
|
flagAsBotDescription: "Si ce compte est géré de manière automatisée, choisissez cette option. Si elle est activée, elle agira comme un marqueur pour les autres développeurs afin d'éviter des chaînes d'interaction sans fin avec d'autres robots et d'ajuster les systèmes internes de Misskey pour traiter ce compte comme un robot."
|
||||||
flagAsCat: "Ce compte est un chat"
|
flagAsCat: "Ce compte est un chat"
|
||||||
@@ -163,7 +154,6 @@ flagShowTimelineReplies: "Afficher les réponses dans le fil"
|
|||||||
flagShowTimelineRepliesDescription: "Affiche les réponses des utilisateurs aux notes des autres utilisateurs dans la timeline si cette option est activée."
|
flagShowTimelineRepliesDescription: "Affiche les réponses des utilisateurs aux notes des autres utilisateurs dans la timeline si cette option est activée."
|
||||||
autoAcceptFollowed: "Accepter automatiquement les demandes d’abonnement venant d’utilisateur·rice·s que vous suivez"
|
autoAcceptFollowed: "Accepter automatiquement les demandes d’abonnement venant d’utilisateur·rice·s que vous suivez"
|
||||||
addAccount: "Ajouter un compte"
|
addAccount: "Ajouter un compte"
|
||||||
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"
|
||||||
general: "Général"
|
general: "Général"
|
||||||
@@ -270,8 +260,6 @@ noMoreHistory: "Il n’y a plus d’historique"
|
|||||||
startMessaging: "Commencer à discuter"
|
startMessaging: "Commencer à discuter"
|
||||||
nUsersRead: "Lu par {n} personnes"
|
nUsersRead: "Lu par {n} personnes"
|
||||||
agreeTo: "J’accepte {0}"
|
agreeTo: "J’accepte {0}"
|
||||||
agree: "Accepter"
|
|
||||||
termsOfService: "Conditions d'utilisation"
|
|
||||||
start: "Commencer"
|
start: "Commencer"
|
||||||
home: "Principal"
|
home: "Principal"
|
||||||
remoteUserCaution: "Les informations de ce compte risqueraient d’être incomplètes du fait que l’utilisateur·rice provient d’une instance distante."
|
remoteUserCaution: "Les informations de ce compte risqueraient d’être incomplètes du fait que l’utilisateur·rice provient d’une instance distante."
|
||||||
@@ -314,7 +302,6 @@ copyUrl: "Copier l’URL"
|
|||||||
rename: "Renommer"
|
rename: "Renommer"
|
||||||
avatar: "Avatar"
|
avatar: "Avatar"
|
||||||
banner: "Bannière"
|
banner: "Bannière"
|
||||||
displayOfSensitiveMedia: "Afficher les médias sensibles"
|
|
||||||
whenServerDisconnected: "Lorsque la connexion au serveur est perdue"
|
whenServerDisconnected: "Lorsque la connexion au serveur est perdue"
|
||||||
disconnectedFromServer: "Déconnecté·e du serveur"
|
disconnectedFromServer: "Déconnecté·e du serveur"
|
||||||
reload: "Rafraîchir"
|
reload: "Rafraîchir"
|
||||||
@@ -404,15 +391,11 @@ about: "Informations"
|
|||||||
aboutMisskey: "À propos de Misskey"
|
aboutMisskey: "À propos de Misskey"
|
||||||
administrator: "Administrateur"
|
administrator: "Administrateur"
|
||||||
token: "Jeton"
|
token: "Jeton"
|
||||||
2fa: "Authentification à deux facteurs"
|
|
||||||
totp: "Application d'authentification"
|
|
||||||
totpDescription: "Entrez 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"
|
||||||
nUsersMentioned: "{n} utilisateur·rice·s mentionné·e·s"
|
nUsersMentioned: "{n} utilisateur·rice·s mentionné·e·s"
|
||||||
securityKey: "Clé de sécurité"
|
securityKey: "Clé de sécurité"
|
||||||
lastUsed: "Dernier utilisé"
|
lastUsed: "Dernier utilisé"
|
||||||
lastUsedAt: "Dernière utilisation : {t}"
|
|
||||||
unregister: "Se désinscrire"
|
unregister: "Se désinscrire"
|
||||||
passwordLessLogin: "Se connecter sans mot de passe"
|
passwordLessLogin: "Se connecter sans mot de passe"
|
||||||
resetPassword: "Réinitialiser le mot de passe"
|
resetPassword: "Réinitialiser le mot de passe"
|
||||||
@@ -550,14 +533,9 @@ userSuspended: "Cet·te utilisateur·rice a été suspendu·e."
|
|||||||
userSilenced: "Cette utilisateur·trice a été mis·e en sourdine."
|
userSilenced: "Cette utilisateur·trice a été mis·e en sourdine."
|
||||||
yourAccountSuspendedTitle: "Ce compte est suspendu"
|
yourAccountSuspendedTitle: "Ce compte est suspendu"
|
||||||
yourAccountSuspendedDescription: "Ce compte est suspendu car vous avez enfreint les conditions d'utilisation de l'instance, ou pour un motif similaire. Si vous souhaitez connaître en détail les raisons de cette suspension, renseignez-vous auprès de l'administrateur·rice de votre instance. Merci de ne pas créer de nouveau compte."
|
yourAccountSuspendedDescription: "Ce compte est suspendu car vous avez enfreint les conditions d'utilisation de l'instance, ou pour un motif similaire. Si vous souhaitez connaître en détail les raisons de cette suspension, renseignez-vous auprès de l'administrateur·rice de votre instance. Merci de ne pas créer de nouveau compte."
|
||||||
tokenRevoked: "Ce jeton est invalide."
|
|
||||||
tokenRevokedDescription: "Votre jeton de connexion a expiré. Veuillez vous reconnecter."
|
|
||||||
accountDeleted: "Compte supprimé"
|
|
||||||
accountDeletedDescription: "Ce compte a été supprimé."
|
|
||||||
menu: "Menu"
|
menu: "Menu"
|
||||||
divider: "Séparateur"
|
divider: "Séparateur"
|
||||||
addItem: "Ajouter un élément"
|
addItem: "Ajouter un élément"
|
||||||
rearrange: "Trier par"
|
|
||||||
relays: "Relais"
|
relays: "Relais"
|
||||||
addRelay: "Ajouter un relais"
|
addRelay: "Ajouter un relais"
|
||||||
inboxUrl: "Inbox URL"
|
inboxUrl: "Inbox URL"
|
||||||
@@ -699,8 +677,6 @@ contact: "Contact"
|
|||||||
useSystemFont: "Utiliser la police par défaut du système"
|
useSystemFont: "Utiliser la police par défaut du système"
|
||||||
clips: "Clips"
|
clips: "Clips"
|
||||||
experimentalFeatures: "Fonctionnalités expérimentales"
|
experimentalFeatures: "Fonctionnalités expérimentales"
|
||||||
experimental: "Expérimental"
|
|
||||||
thisIsExperimentalFeature: "Ceci est une fonctionnalité expérimentale. Il y a une possibilité que les spécifications changent ou qu'elle ne fonctionne pas correctement."
|
|
||||||
developer: "Développeur"
|
developer: "Développeur"
|
||||||
makeExplorable: "Rendre le compte visible sur la page \"Découvrir\"."
|
makeExplorable: "Rendre le compte visible sur la page \"Découvrir\"."
|
||||||
makeExplorableDescription: "Si vous désactivez cette option, votre compte n'apparaîtra pas sur la page \"Découvrir\"."
|
makeExplorableDescription: "Si vous désactivez cette option, votre compte n'apparaîtra pas sur la page \"Découvrir\"."
|
||||||
@@ -785,7 +761,6 @@ noMaintainerInformationWarning: "Informations administrateur non configurées."
|
|||||||
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"
|
||||||
postToHashtag: "Publier avec ce hashtag"
|
|
||||||
gallery: "Galerie"
|
gallery: "Galerie"
|
||||||
recentPosts: "Les plus récentes"
|
recentPosts: "Les plus récentes"
|
||||||
popularPosts: "Les plus consultées"
|
popularPosts: "Les plus consultées"
|
||||||
@@ -824,7 +799,6 @@ lastCommunication: "Dernière communication"
|
|||||||
resolved: "Résolu"
|
resolved: "Résolu"
|
||||||
unresolved: "En attente"
|
unresolved: "En attente"
|
||||||
breakFollow: "Ne plus suivre"
|
breakFollow: "Ne plus suivre"
|
||||||
breakFollowConfirm: "Êtes-vous sûr de vouloir vous désabonner ?"
|
|
||||||
itsOn: "Activé"
|
itsOn: "Activé"
|
||||||
itsOff: "Désactivé"
|
itsOff: "Désactivé"
|
||||||
emailRequiredForSignup: "Une adresse e-mail est nécessaire pour créer un compte"
|
emailRequiredForSignup: "Une adresse e-mail est nécessaire pour créer un compte"
|
||||||
|
@@ -51,7 +51,11 @@ export default function generateDTS() {
|
|||||||
ts.NodeFlags.Const | ts.NodeFlags.Ambient | ts.NodeFlags.ContextFlags,
|
ts.NodeFlags.Const | ts.NodeFlags.Ambient | ts.NodeFlags.ContextFlags,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
ts.factory.createExportDefault(ts.factory.createIdentifier('locales')),
|
ts.factory.createExportAssignment(
|
||||||
|
undefined,
|
||||||
|
true,
|
||||||
|
ts.factory.createIdentifier('locales'),
|
||||||
|
),
|
||||||
];
|
];
|
||||||
const printed = ts.createPrinter({
|
const printed = ts.createPrinter({
|
||||||
newLine: ts.NewLineKind.LineFeed,
|
newLine: ts.NewLineKind.LineFeed,
|
||||||
|
@@ -1 +0,0 @@
|
|||||||
---
|
|
24
locales/index.d.ts
vendored
24
locales/index.d.ts
vendored
@@ -1077,26 +1077,6 @@ export interface Locale {
|
|||||||
"enableServerMachineStats": string;
|
"enableServerMachineStats": string;
|
||||||
"enableIdenticonGeneration": string;
|
"enableIdenticonGeneration": string;
|
||||||
"turnOffToImprovePerformance": string;
|
"turnOffToImprovePerformance": string;
|
||||||
"createInviteCode": string;
|
|
||||||
"createWithOptions": string;
|
|
||||||
"createCount": string;
|
|
||||||
"inviteCodeCreated": string;
|
|
||||||
"inviteLimitExceeded": string;
|
|
||||||
"createLimitRemaining": string;
|
|
||||||
"inviteLimitResetCycle": string;
|
|
||||||
"expirationDate": string;
|
|
||||||
"noExpirationDate": string;
|
|
||||||
"inviteCodeUsedAt": string;
|
|
||||||
"registeredUserUsingInviteCode": string;
|
|
||||||
"waitingForMailAuth": string;
|
|
||||||
"inviteCodeCreator": string;
|
|
||||||
"usedAt": string;
|
|
||||||
"unused": string;
|
|
||||||
"used": string;
|
|
||||||
"expired": string;
|
|
||||||
"doYouAgree": string;
|
|
||||||
"beSureToReadThisAsItIsImportant": string;
|
|
||||||
"iHaveReadXCarefullyAndAgree": string;
|
|
||||||
"_initialAccountSetting": {
|
"_initialAccountSetting": {
|
||||||
"accountCreated": string;
|
"accountCreated": string;
|
||||||
"letsStartAccountSetup": string;
|
"letsStartAccountSetup": string;
|
||||||
@@ -1487,9 +1467,6 @@ export interface Locale {
|
|||||||
"ltlAvailable": string;
|
"ltlAvailable": string;
|
||||||
"canPublicNote": string;
|
"canPublicNote": string;
|
||||||
"canInvite": string;
|
"canInvite": string;
|
||||||
"inviteLimit": string;
|
|
||||||
"inviteLimitCycle": string;
|
|
||||||
"inviteExpirationTime": string;
|
|
||||||
"canManageCustomEmojis": string;
|
"canManageCustomEmojis": string;
|
||||||
"driveCapacity": string;
|
"driveCapacity": string;
|
||||||
"alwaysMarkNsfw": string;
|
"alwaysMarkNsfw": string;
|
||||||
@@ -2138,7 +2115,6 @@ export interface Locale {
|
|||||||
"introduction": string;
|
"introduction": string;
|
||||||
"introduction2": string;
|
"introduction2": string;
|
||||||
"widgetsIntroduction": string;
|
"widgetsIntroduction": string;
|
||||||
"useSimpleUiForNonRootPages": string;
|
|
||||||
"_columns": {
|
"_columns": {
|
||||||
"main": string;
|
"main": string;
|
||||||
"widgets": string;
|
"widgets": string;
|
||||||
|
@@ -49,15 +49,11 @@ delete: "Elimina"
|
|||||||
deleteAndEdit: "Elimina e modifica"
|
deleteAndEdit: "Elimina e modifica"
|
||||||
deleteAndEditConfirm: "Vuoi davvero cancellare questa nota e scriverla di nuovo? Verranno eliminate anche tutte le reazioni, rinote e risposte collegate."
|
deleteAndEditConfirm: "Vuoi davvero cancellare questa nota e scriverla di nuovo? Verranno eliminate anche tutte le reazioni, rinote e risposte collegate."
|
||||||
addToList: "Aggiungi alla lista"
|
addToList: "Aggiungi alla lista"
|
||||||
addToAntenna: "Aggiungi all'antenna"
|
|
||||||
sendMessage: "Invia messaggio"
|
sendMessage: "Invia messaggio"
|
||||||
copyRSS: "Copia RSS"
|
copyRSS: "Copia RSS"
|
||||||
copyUsername: "Copia nome utente"
|
copyUsername: "Copia nome utente"
|
||||||
copyUserId: "Copia ID del profilo"
|
copyUserId: "Copia ID del profilo"
|
||||||
copyNoteId: "Copia ID della Nota"
|
copyNoteId: "Copia ID della Nota"
|
||||||
copyFileId: "Copia ID del file"
|
|
||||||
copyFolderId: "Copia ID della cartella"
|
|
||||||
copyProfileUrl: "Copia URL del profilo"
|
|
||||||
searchUser: "Cerca profilo"
|
searchUser: "Cerca profilo"
|
||||||
reply: "Rispondi"
|
reply: "Rispondi"
|
||||||
loadMore: "Mostra di più"
|
loadMore: "Mostra di più"
|
||||||
@@ -140,10 +136,8 @@ unblockConfirm: "Vuoi davvero sbloccare il profilo?"
|
|||||||
suspendConfirm: "Vuoi sospendere questo profilo?"
|
suspendConfirm: "Vuoi sospendere questo profilo?"
|
||||||
unsuspendConfirm: "Vuoi revocare la sospensione si questo profilo?"
|
unsuspendConfirm: "Vuoi revocare la sospensione si questo profilo?"
|
||||||
selectList: "Seleziona una lista"
|
selectList: "Seleziona una lista"
|
||||||
editList: "Modifica Lista"
|
|
||||||
selectChannel: "Seleziona canale"
|
selectChannel: "Seleziona canale"
|
||||||
selectAntenna: "Scegli un'antenna"
|
selectAntenna: "Scegli un'antenna"
|
||||||
editAntenna: "Modifica Antenna"
|
|
||||||
selectWidget: "Seleziona il riquadro"
|
selectWidget: "Seleziona il riquadro"
|
||||||
editWidgets: "Modifica i riquadri"
|
editWidgets: "Modifica i riquadri"
|
||||||
editWidgetsExit: "Conferma le modifiche"
|
editWidgetsExit: "Conferma le modifiche"
|
||||||
@@ -156,8 +150,6 @@ addEmoji: "Aggiungi un emoji"
|
|||||||
settingGuide: "Configurazione suggerita"
|
settingGuide: "Configurazione suggerita"
|
||||||
cacheRemoteFiles: "Memorizza i file remoti nella cache"
|
cacheRemoteFiles: "Memorizza i file remoti nella cache"
|
||||||
cacheRemoteFilesDescription: "Disabilitando questa opzione, i file remoti verranno linkati direttamente senza essere memorizzati nella cache. Sarà possibile risparmiare spazio di archiviazione sul server, ma il traffico aumenterà in quanto non verranno generate anteprime."
|
cacheRemoteFilesDescription: "Disabilitando questa opzione, i file remoti verranno linkati direttamente senza essere memorizzati nella cache. Sarà possibile risparmiare spazio di archiviazione sul server, ma il traffico aumenterà in quanto non verranno generate anteprime."
|
||||||
cacheRemoteSensitiveFiles: "Memorizza nella cache i file sensibili remoti"
|
|
||||||
cacheRemoteSensitiveFilesDescription: "Disattivando questa opzione, i file sensibili verranno caricati direttamente dall'istanza remota senza essere salvati dal server."
|
|
||||||
flagAsBot: "Io sono un robot"
|
flagAsBot: "Io sono un robot"
|
||||||
flagAsBotDescription: "Attiva questo campo se il profilo esegue principalmente operazioni automatiche. L'attivazione segnala agli altri sviluppatori come comportarsi per evitare catene d’interazione infinite con altri bot. I sistemi interni di Misskey si adegueranno al fine di trattare questo profilo come bot."
|
flagAsBotDescription: "Attiva questo campo se il profilo esegue principalmente operazioni automatiche. L'attivazione segnala agli altri sviluppatori come comportarsi per evitare catene d’interazione infinite con altri bot. I sistemi interni di Misskey si adegueranno al fine di trattare questo profilo come bot."
|
||||||
flagAsCat: "Sono un gatto"
|
flagAsCat: "Sono un gatto"
|
||||||
@@ -319,7 +311,6 @@ copyUrl: "Copia URL"
|
|||||||
rename: "Modifica nome"
|
rename: "Modifica nome"
|
||||||
avatar: "Foto del profilo"
|
avatar: "Foto del profilo"
|
||||||
banner: "Intestazione"
|
banner: "Intestazione"
|
||||||
displayOfSensitiveMedia: "Visibilità dei media sensibili"
|
|
||||||
whenServerDisconnected: "Quando la connessione col server è persa"
|
whenServerDisconnected: "Quando la connessione col server è persa"
|
||||||
disconnectedFromServer: "Il server si è disconnesso"
|
disconnectedFromServer: "Il server si è disconnesso"
|
||||||
reload: "Ricarica"
|
reload: "Ricarica"
|
||||||
@@ -779,10 +770,10 @@ info: "Informazioni"
|
|||||||
userInfo: "Informazioni utente"
|
userInfo: "Informazioni utente"
|
||||||
unknown: "Sconosciuto"
|
unknown: "Sconosciuto"
|
||||||
onlineStatus: "Stato di connessione"
|
onlineStatus: "Stato di connessione"
|
||||||
hideOnlineStatus: "Modalità invisibile"
|
hideOnlineStatus: "Stato invisibile"
|
||||||
hideOnlineStatusDescription: "Attivando questa opzione potresti ridurre l'usabilità di alcune funzioni, come la ricerca."
|
hideOnlineStatusDescription: "Abilitare l'opzione di stato invisibile può guastare la praticità di singole funzioni, come la ricerca."
|
||||||
online: "Online"
|
online: "Online"
|
||||||
active: "Attività"
|
active: "Attiv@"
|
||||||
offline: "Offline"
|
offline: "Offline"
|
||||||
notRecommended: "Sconsigliato"
|
notRecommended: "Sconsigliato"
|
||||||
botProtection: "Protezione contro i bot"
|
botProtection: "Protezione contro i bot"
|
||||||
@@ -856,8 +847,8 @@ makeReactionsPublicDescription: "La lista delle reazioni che avete fatto è a di
|
|||||||
classic: "Classico"
|
classic: "Classico"
|
||||||
muteThread: "Silenzia la conversazione"
|
muteThread: "Silenzia la conversazione"
|
||||||
unmuteThread: "Riattiva la conversazione"
|
unmuteThread: "Riattiva la conversazione"
|
||||||
ffVisibility: "Visibilità delle connessioni"
|
ffVisibility: "Ambito pubblico del collegamento"
|
||||||
ffVisibilityDescription: "Puoi scegliere a chi mostrare le tue relazioni con altri profili nel fediverso."
|
ffVisibilityDescription: "È possibile impostare la portata pubblica delle informazioni sui propri follower/seguaci."
|
||||||
continueThread: "Altri thread."
|
continueThread: "Altri thread."
|
||||||
deleteAccountConfirm: "Così verrà eliminato il profilo. Vuoi procedere?"
|
deleteAccountConfirm: "Così verrà eliminato il profilo. Vuoi procedere?"
|
||||||
incorrectPassword: "La password è errata."
|
incorrectPassword: "La password è errata."
|
||||||
@@ -1073,24 +1064,6 @@ installed: "Installazione avvenuta"
|
|||||||
branding: "Branding"
|
branding: "Branding"
|
||||||
enableServerMachineStats: "Pubblicare le informazioni sul server"
|
enableServerMachineStats: "Pubblicare le informazioni sul server"
|
||||||
enableIdenticonGeneration: "Generazione automatica delle Identicon"
|
enableIdenticonGeneration: "Generazione automatica delle Identicon"
|
||||||
turnOffToImprovePerformance: "Disattiva, per migliorare le prestazioni"
|
|
||||||
createInviteCode: "Genera codice di invito"
|
|
||||||
createWithOptions: "Genera con opzioni"
|
|
||||||
createCount: "Conteggio inviti"
|
|
||||||
inviteCodeCreated: "Inviti generati"
|
|
||||||
inviteLimitExceeded: "Hai raggiunto il numero massimo di codici invito generabili."
|
|
||||||
createLimitRemaining: "Inviti generabili: {limit} rimanenti"
|
|
||||||
inviteLimitResetCycle: "Alle {time}, il limite verrà ripristinato a {limit}"
|
|
||||||
expirationDate: "Scadenza"
|
|
||||||
noExpirationDate: "Perpetuo"
|
|
||||||
inviteCodeUsedAt: "Codice di invito usato alle"
|
|
||||||
registeredUserUsingInviteCode: "Codice di invito usato da"
|
|
||||||
waitingForMailAuth: "In attesa della verifica email"
|
|
||||||
inviteCodeCreator: "Codice di invito creato da"
|
|
||||||
usedAt: "Usato alle"
|
|
||||||
unused: "Inutilizzato"
|
|
||||||
used: "Utilizzato"
|
|
||||||
expired: "Scaduto"
|
|
||||||
_initialAccountSetting:
|
_initialAccountSetting:
|
||||||
accountCreated: "Il tuo profilo è stato creato!"
|
accountCreated: "Il tuo profilo è stato creato!"
|
||||||
letsStartAccountSetup: "Per iniziare, impostiamo il tuo profilo."
|
letsStartAccountSetup: "Per iniziare, impostiamo il tuo profilo."
|
||||||
@@ -1401,9 +1374,6 @@ _role:
|
|||||||
ltlAvailable: "Disponibilità della Timeline Locale"
|
ltlAvailable: "Disponibilità della Timeline Locale"
|
||||||
canPublicNote: "Può scrivere Note con Visibilità Pubblica"
|
canPublicNote: "Può scrivere Note con Visibilità Pubblica"
|
||||||
canInvite: "Genera codici di invito all'istanza"
|
canInvite: "Genera codici di invito all'istanza"
|
||||||
inviteLimit: "Limite di codici invito"
|
|
||||||
inviteLimitCycle: "Intervallo di emissione del codice di invito"
|
|
||||||
inviteExpirationTime: "Scadenza del codice di invito"
|
|
||||||
canManageCustomEmojis: "Gestire le emoji personalizzate"
|
canManageCustomEmojis: "Gestire le emoji personalizzate"
|
||||||
driveCapacity: "Capienza del Drive"
|
driveCapacity: "Capienza del Drive"
|
||||||
alwaysMarkNsfw: "Imposta sempre come NSFW"
|
alwaysMarkNsfw: "Imposta sempre come NSFW"
|
||||||
@@ -1466,7 +1436,6 @@ _ad:
|
|||||||
back: "Indietro"
|
back: "Indietro"
|
||||||
reduceFrequencyOfThisAd: "Visualizza questa pubblicità meno spesso"
|
reduceFrequencyOfThisAd: "Visualizza questa pubblicità meno spesso"
|
||||||
hide: "Nascondi"
|
hide: "Nascondi"
|
||||||
timezoneinfo: "Il giorno della settimana è determinato in base al fuso orario del server."
|
|
||||||
_forgotPassword:
|
_forgotPassword:
|
||||||
enterEmail: "Inserisci l'indirizzo di posta elettronica che hai registrato nel tuo profilo. Il collegamento necessario per ripristinare la password verrà inviato a questo indirizzo."
|
enterEmail: "Inserisci l'indirizzo di posta elettronica che hai registrato nel tuo profilo. Il collegamento necessario per ripristinare la password verrà inviato a questo indirizzo."
|
||||||
ifNoEmail: "Se il tuo indirizzo email non risulta registrato, contatta l'amministrazione dell'istanza."
|
ifNoEmail: "Se il tuo indirizzo email non risulta registrato, contatta l'amministrazione dell'istanza."
|
||||||
@@ -1518,10 +1487,6 @@ _aboutMisskey:
|
|||||||
donate: "Sostieni Misskey"
|
donate: "Sostieni Misskey"
|
||||||
morePatrons: "Apprezziamo sinceramente il supporto di tante altre persone. Grazie mille! 🥰"
|
morePatrons: "Apprezziamo sinceramente il supporto di tante altre persone. Grazie mille! 🥰"
|
||||||
patrons: "Sostenitori"
|
patrons: "Sostenitori"
|
||||||
_displayOfSensitiveMedia:
|
|
||||||
respect: "Nascondere i media sensibili"
|
|
||||||
ignore: "Non nascondere i media sensibili"
|
|
||||||
force: "Nascondi tutti i media"
|
|
||||||
_instanceTicker:
|
_instanceTicker:
|
||||||
none: "Nascondi"
|
none: "Nascondi"
|
||||||
remote: "Mostra solo per i profili remoti"
|
remote: "Mostra solo per i profili remoti"
|
||||||
@@ -1996,7 +1961,6 @@ _deck:
|
|||||||
introduction: "Combinate le colonne per creare la vostra interfaccia!"
|
introduction: "Combinate le colonne per creare la vostra interfaccia!"
|
||||||
introduction2: "È possibile aggiungere colonne in qualsiasi momento premendo + sulla destra dello schermo."
|
introduction2: "È possibile aggiungere colonne in qualsiasi momento premendo + sulla destra dello schermo."
|
||||||
widgetsIntroduction: "Dal menu della colonna, selezionare \"Modifica i riquadri\" per aggiungere un un riquadro con funzionalità"
|
widgetsIntroduction: "Dal menu della colonna, selezionare \"Modifica i riquadri\" per aggiungere un un riquadro con funzionalità"
|
||||||
useSimpleUiForNonRootPages: "Visualizza sotto pagine con interfaccia web semplice"
|
|
||||||
_columns:
|
_columns:
|
||||||
main: "Principale"
|
main: "Principale"
|
||||||
widgets: "Riquadri"
|
widgets: "Riquadri"
|
||||||
|
@@ -156,8 +156,8 @@ addEmoji: "絵文字を追加"
|
|||||||
settingGuide: "おすすめ設定"
|
settingGuide: "おすすめ設定"
|
||||||
cacheRemoteFiles: "リモートのファイルをキャッシュする"
|
cacheRemoteFiles: "リモートのファイルをキャッシュする"
|
||||||
cacheRemoteFilesDescription: "この設定を無効にすると、リモートファイルをキャッシュせず直リンクするようになります。サーバーのストレージを節約できますが、サムネイルが生成されないので通信量が増加します。"
|
cacheRemoteFilesDescription: "この設定を無効にすると、リモートファイルをキャッシュせず直リンクするようになります。サーバーのストレージを節約できますが、サムネイルが生成されないので通信量が増加します。"
|
||||||
cacheRemoteSensitiveFiles: "リモートのセンシティブなファイルをキャッシュする"
|
cacheRemoteSensitiveFiles: "リモートのNSFWファイルをキャッシュする"
|
||||||
cacheRemoteSensitiveFilesDescription: "この設定を無効にすると、リモートのセンシティブなファイルはキャッシュせず直リンクするようになります。"
|
cacheRemoteSensitiveFilesDescription: "この設定を無効にすると、リモートのNSFWファイルだけはキャッシュせず直リンクするようになります。"
|
||||||
flagAsBot: "Botとして設定"
|
flagAsBot: "Botとして設定"
|
||||||
flagAsBotDescription: "このアカウントがプログラムによって運用される場合は、このフラグをオンにします。オンにすると、反応の連鎖を防ぐためのフラグとして他の開発者に役立ったり、Misskeyのシステム上での扱いがBotに合ったものになります。"
|
flagAsBotDescription: "このアカウントがプログラムによって運用される場合は、このフラグをオンにします。オンにすると、反応の連鎖を防ぐためのフラグとして他の開発者に役立ったり、Misskeyのシステム上での扱いがBotに合ったものになります。"
|
||||||
flagAsCat: "にゃああああああああああああああ!!!!!!!!!!!!"
|
flagAsCat: "にゃああああああああああああああ!!!!!!!!!!!!"
|
||||||
@@ -1042,7 +1042,7 @@ vertical: "縦"
|
|||||||
horizontal: "横"
|
horizontal: "横"
|
||||||
position: "位置"
|
position: "位置"
|
||||||
serverRules: "サーバールール"
|
serverRules: "サーバールール"
|
||||||
pleaseConfirmBelowBeforeSignup: "このサーバーに登録するには、以下の内容を確認し同意する必要があります。"
|
pleaseConfirmBelowBeforeSignup: "このサーバーに登録する前に、以下を確認してください。"
|
||||||
pleaseAgreeAllToContinue: "続けるには、全ての「同意する」にチェックが入っている必要があります。"
|
pleaseAgreeAllToContinue: "続けるには、全ての「同意する」にチェックが入っている必要があります。"
|
||||||
continue: "続ける"
|
continue: "続ける"
|
||||||
preservedUsernames: "予約ユーザー名"
|
preservedUsernames: "予約ユーザー名"
|
||||||
@@ -1074,26 +1074,6 @@ branding: "ブランディング"
|
|||||||
enableServerMachineStats: "サーバーのマシン情報を公開する"
|
enableServerMachineStats: "サーバーのマシン情報を公開する"
|
||||||
enableIdenticonGeneration: "ユーザーごとのIdenticon生成を有効にする"
|
enableIdenticonGeneration: "ユーザーごとのIdenticon生成を有効にする"
|
||||||
turnOffToImprovePerformance: "オフにするとパフォーマンスが向上します。"
|
turnOffToImprovePerformance: "オフにするとパフォーマンスが向上します。"
|
||||||
createInviteCode: "招待コードを作成"
|
|
||||||
createWithOptions: "オプションを指定して作成"
|
|
||||||
createCount: "作成数"
|
|
||||||
inviteCodeCreated: "招待コードを作成しました"
|
|
||||||
inviteLimitExceeded: "作成できる招待コードの数が上限に達しています。"
|
|
||||||
createLimitRemaining: "作成できる招待コード: 残り {limit} 個"
|
|
||||||
inviteLimitResetCycle: "{time}で最大 {limit} 個の招待コードを作成できます。"
|
|
||||||
expirationDate: "有効期限"
|
|
||||||
noExpirationDate: "有効期限を設けない"
|
|
||||||
inviteCodeUsedAt: "招待コードが使用された日時"
|
|
||||||
registeredUserUsingInviteCode: "招待コードを使用したユーザー"
|
|
||||||
waitingForMailAuth: "メール認証待ち"
|
|
||||||
inviteCodeCreator: "招待コードを作成したユーザー"
|
|
||||||
usedAt: "使用日時"
|
|
||||||
unused: "未使用"
|
|
||||||
used: "使用済み"
|
|
||||||
expired: "期限切れ"
|
|
||||||
doYouAgree: "同意しますか?"
|
|
||||||
beSureToReadThisAsItIsImportant: "重要ですので必ずお読みください。"
|
|
||||||
iHaveReadXCarefullyAndAgree: "「{x}」の内容をよく読み、同意します。"
|
|
||||||
|
|
||||||
_initialAccountSetting:
|
_initialAccountSetting:
|
||||||
accountCreated: "アカウントの作成が完了しました!"
|
accountCreated: "アカウントの作成が完了しました!"
|
||||||
@@ -1409,9 +1389,6 @@ _role:
|
|||||||
ltlAvailable: "ローカルタイムラインの閲覧"
|
ltlAvailable: "ローカルタイムラインの閲覧"
|
||||||
canPublicNote: "パブリック投稿の許可"
|
canPublicNote: "パブリック投稿の許可"
|
||||||
canInvite: "サーバー招待コードの発行"
|
canInvite: "サーバー招待コードの発行"
|
||||||
inviteLimit: "招待コードの作成可能数"
|
|
||||||
inviteLimitCycle: "招待コードの発行間隔"
|
|
||||||
inviteExpirationTime: "招待コードの有効期限"
|
|
||||||
canManageCustomEmojis: "カスタム絵文字の管理"
|
canManageCustomEmojis: "カスタム絵文字の管理"
|
||||||
driveCapacity: "ドライブ容量"
|
driveCapacity: "ドライブ容量"
|
||||||
alwaysMarkNsfw: "ファイルにNSFWを常に付与"
|
alwaysMarkNsfw: "ファイルにNSFWを常に付与"
|
||||||
@@ -2053,7 +2030,6 @@ _deck:
|
|||||||
introduction: "カラムを組み合わせて自分だけのインターフェイスを作りましょう!"
|
introduction: "カラムを組み合わせて自分だけのインターフェイスを作りましょう!"
|
||||||
introduction2: "画面の右にある + を押して、いつでもカラムを追加できます。"
|
introduction2: "画面の右にある + を押して、いつでもカラムを追加できます。"
|
||||||
widgetsIntroduction: "カラムのメニューから、「ウィジェットの編集」を選択してウィジェットを追加してください"
|
widgetsIntroduction: "カラムのメニューから、「ウィジェットの編集」を選択してウィジェットを追加してください"
|
||||||
useSimpleUiForNonRootPages: "非ルートページは簡易UIで表示"
|
|
||||||
|
|
||||||
_columns:
|
_columns:
|
||||||
main: "メイン"
|
main: "メイン"
|
||||||
|
@@ -49,15 +49,11 @@ delete: "ほかす"
|
|||||||
deleteAndEdit: "ほかして直す"
|
deleteAndEdit: "ほかして直す"
|
||||||
deleteAndEditConfirm: "このノートをほかしてもっかい直す?このノートへのツッコミ、Renote、返信も全部消えるんやけどそれでもええん?"
|
deleteAndEditConfirm: "このノートをほかしてもっかい直す?このノートへのツッコミ、Renote、返信も全部消えるんやけどそれでもええん?"
|
||||||
addToList: "リストに入れたる"
|
addToList: "リストに入れたる"
|
||||||
addToAntenna: "アンテナに追加"
|
|
||||||
sendMessage: "メッセージを送る"
|
sendMessage: "メッセージを送る"
|
||||||
copyRSS: "RSSをコピー"
|
copyRSS: "RSSをコピー"
|
||||||
copyUsername: "ユーザー名をコピー"
|
copyUsername: "ユーザー名をコピー"
|
||||||
copyUserId: "ユーザーIDをコピー"
|
copyUserId: "ユーザーIDをコピー"
|
||||||
copyNoteId: "ノートIDをコピー"
|
copyNoteId: "ノートIDをコピー"
|
||||||
copyFileId: "ファイルIDをコピー"
|
|
||||||
copyFolderId: "フォルダーIDをコピー"
|
|
||||||
copyProfileUrl: "プロフィールURLをコピー"
|
|
||||||
searchUser: "ユーザーを検索"
|
searchUser: "ユーザーを検索"
|
||||||
reply: "返事"
|
reply: "返事"
|
||||||
loadMore: "まだまだあるで!"
|
loadMore: "まだまだあるで!"
|
||||||
@@ -156,8 +152,6 @@ addEmoji: "絵文字を追加"
|
|||||||
settingGuide: "ええ感じの設定"
|
settingGuide: "ええ感じの設定"
|
||||||
cacheRemoteFiles: "リモートのファイルをキャッシュする"
|
cacheRemoteFiles: "リモートのファイルをキャッシュする"
|
||||||
cacheRemoteFilesDescription: "この設定を切っとったら、リモートファイルをキャッシュせんと直リンクするようになるで。サーバーの容量は節約できるけど、サムネイルを作らんなるから通信量が増えるで。"
|
cacheRemoteFilesDescription: "この設定を切っとったら、リモートファイルをキャッシュせんと直リンクするようになるで。サーバーの容量は節約できるけど、サムネイルを作らんなるから通信量が増えるで。"
|
||||||
cacheRemoteSensitiveFiles: "リモートのセンシティブなファイルをキャッシュする"
|
|
||||||
cacheRemoteSensitiveFilesDescription: "この設定を無効にすると、リモートのセンシティブなファイルはキャッシュせず直リンクするようになるで。"
|
|
||||||
flagAsBot: "Botにするで"
|
flagAsBot: "Botにするで"
|
||||||
flagAsBotDescription: "もしこのアカウントをプログラム使うて運用するんやったら、このフラグをオンにしてや。オンにすれば、反応がバーッて連鎖せんように開発者が使うたり、Misskeyのシステム上での扱いがBotに合ったもんになるからな。"
|
flagAsBotDescription: "もしこのアカウントをプログラム使うて運用するんやったら、このフラグをオンにしてや。オンにすれば、反応がバーッて連鎖せんように開発者が使うたり、Misskeyのシステム上での扱いがBotに合ったもんになるからな。"
|
||||||
flagAsCat: "Catやで"
|
flagAsCat: "Catやで"
|
||||||
@@ -319,7 +313,6 @@ copyUrl: "URLをコピー"
|
|||||||
rename: "名前を変えるで"
|
rename: "名前を変えるで"
|
||||||
avatar: "アイコン"
|
avatar: "アイコン"
|
||||||
banner: "バナー"
|
banner: "バナー"
|
||||||
displayOfSensitiveMedia: "センシティブなメディアの表示"
|
|
||||||
whenServerDisconnected: "サーバーとの接続が失くなってしもうたとき"
|
whenServerDisconnected: "サーバーとの接続が失くなってしもうたとき"
|
||||||
disconnectedFromServer: "サーバーが機嫌悪いねん"
|
disconnectedFromServer: "サーバーが機嫌悪いねん"
|
||||||
reload: "リロード"
|
reload: "リロード"
|
||||||
@@ -1073,27 +1066,6 @@ installed: "インストール済み"
|
|||||||
branding: "あ"
|
branding: "あ"
|
||||||
enableServerMachineStats: "サーバーのマシン情報見せびらかすで"
|
enableServerMachineStats: "サーバーのマシン情報見せびらかすで"
|
||||||
enableIdenticonGeneration: "ユーザーごとのIdenticon生成を有効にする"
|
enableIdenticonGeneration: "ユーザーごとのIdenticon生成を有効にする"
|
||||||
turnOffToImprovePerformance: "オフにしたらえらい軽うなるで。"
|
|
||||||
createInviteCode: "招待コードを作成"
|
|
||||||
createWithOptions: "オプションを指定して作成"
|
|
||||||
createCount: "作成数"
|
|
||||||
inviteCodeCreated: "招待コード作ったで"
|
|
||||||
inviteLimitExceeded: "招待コード作りすぎやで。"
|
|
||||||
createLimitRemaining: "作成できる招待コード: 残り {limit} 個やで"
|
|
||||||
inviteLimitResetCycle: "{time}で最大 {limit} 個の招待コードを作成できるで。"
|
|
||||||
expirationDate: "有効期限"
|
|
||||||
noExpirationDate: "有効期限を設けへん"
|
|
||||||
inviteCodeUsedAt: "招待コードが使用された日時"
|
|
||||||
registeredUserUsingInviteCode: "招待コードを使用したユーザー"
|
|
||||||
waitingForMailAuth: "メール認証待ち"
|
|
||||||
inviteCodeCreator: "招待コードを作成したユーザー"
|
|
||||||
usedAt: "使用日時"
|
|
||||||
unused: "つこてへん"
|
|
||||||
used: "もうつこてる"
|
|
||||||
expired: "期限切れ"
|
|
||||||
doYouAgree: "同意するんか?"
|
|
||||||
beSureToReadThisAsItIsImportant: "重要やから絶対読んでや。"
|
|
||||||
iHaveReadXCarefullyAndAgree: "「{x}」の内容をよう読んで、同意するで。"
|
|
||||||
_initialAccountSetting:
|
_initialAccountSetting:
|
||||||
accountCreated: "アカウント作り終わったで。"
|
accountCreated: "アカウント作り終わったで。"
|
||||||
letsStartAccountSetup: "アカウントの初期設定をしよか。"
|
letsStartAccountSetup: "アカウントの初期設定をしよか。"
|
||||||
@@ -1404,9 +1376,6 @@ _role:
|
|||||||
ltlAvailable: "ローカルタイムラインの閲覧"
|
ltlAvailable: "ローカルタイムラインの閲覧"
|
||||||
canPublicNote: "パブリック投稿の許可"
|
canPublicNote: "パブリック投稿の許可"
|
||||||
canInvite: "サーバー招待コードの発行"
|
canInvite: "サーバー招待コードの発行"
|
||||||
inviteLimit: "招待コードの作成可能数"
|
|
||||||
inviteLimitCycle: "招待コードの発行間隔"
|
|
||||||
inviteExpirationTime: "招待コードの有効期限"
|
|
||||||
canManageCustomEmojis: "カスタム絵文字の管理"
|
canManageCustomEmojis: "カスタム絵文字の管理"
|
||||||
driveCapacity: "ドライブ容量"
|
driveCapacity: "ドライブ容量"
|
||||||
alwaysMarkNsfw: "勝手にファイルにNSFWをくっつける"
|
alwaysMarkNsfw: "勝手にファイルにNSFWをくっつける"
|
||||||
@@ -1469,7 +1438,6 @@ _ad:
|
|||||||
back: "戻る"
|
back: "戻る"
|
||||||
reduceFrequencyOfThisAd: "この広告の表示頻度を下げるで"
|
reduceFrequencyOfThisAd: "この広告の表示頻度を下げるで"
|
||||||
hide: "表示せん"
|
hide: "表示せん"
|
||||||
timezoneinfo: "曜日はサーバーのタイムゾーンを元に指定されるで。"
|
|
||||||
_forgotPassword:
|
_forgotPassword:
|
||||||
enterEmail: "アカウントに登録したメールアドレスをここに入力してや。そのアドレス宛に、パスワードリセット用のリンクが送られるから待っててな~。"
|
enterEmail: "アカウントに登録したメールアドレスをここに入力してや。そのアドレス宛に、パスワードリセット用のリンクが送られるから待っててな~。"
|
||||||
ifNoEmail: "メールアドレスを登録してへんのやったら、管理者まで教えてな~。"
|
ifNoEmail: "メールアドレスを登録してへんのやったら、管理者まで教えてな~。"
|
||||||
@@ -1521,10 +1489,6 @@ _aboutMisskey:
|
|||||||
donate: "Misskeyに寄付"
|
donate: "Misskeyに寄付"
|
||||||
morePatrons: "他にもぎょうさんの人からサポートしてもろてんねん。ほんまおおきに🥰"
|
morePatrons: "他にもぎょうさんの人からサポートしてもろてんねん。ほんまおおきに🥰"
|
||||||
patrons: "支援者"
|
patrons: "支援者"
|
||||||
_displayOfSensitiveMedia:
|
|
||||||
respect: "きわどいのは見とうない"
|
|
||||||
ignore: "きわどいのも見たい"
|
|
||||||
force: "常にメディアを隠すで"
|
|
||||||
_instanceTicker:
|
_instanceTicker:
|
||||||
none: "表示せん"
|
none: "表示せん"
|
||||||
remote: "リモートユーザーに表示"
|
remote: "リモートユーザーに表示"
|
||||||
@@ -1999,7 +1963,6 @@ _deck:
|
|||||||
introduction: "カラムを組み合わせて自分だけのインターフェイスを作りましょ!"
|
introduction: "カラムを組み合わせて自分だけのインターフェイスを作りましょ!"
|
||||||
introduction2: "画面の右にある + を押して、いつでもカラムを追加できるで。"
|
introduction2: "画面の右にある + を押して、いつでもカラムを追加できるで。"
|
||||||
widgetsIntroduction: "カラムのメニューから、「ウィジェットの編集」を選んでウィジェットを追加してなー"
|
widgetsIntroduction: "カラムのメニューから、「ウィジェットの編集」を選んでウィジェットを追加してなー"
|
||||||
useSimpleUiForNonRootPages: "非ルートページは簡易UIで表示"
|
|
||||||
_columns:
|
_columns:
|
||||||
main: "メイン"
|
main: "メイン"
|
||||||
widgets: "ウィジェット"
|
widgets: "ウィジェット"
|
||||||
|
@@ -40,7 +40,7 @@ favorites: "즐겨찾기"
|
|||||||
unfavorite: "즐겨찾기에서 제거"
|
unfavorite: "즐겨찾기에서 제거"
|
||||||
favorited: "즐겨찾기에 등록했습니다"
|
favorited: "즐겨찾기에 등록했습니다"
|
||||||
alreadyFavorited: "이미 즐겨찾기에 등록되어 있습니다"
|
alreadyFavorited: "이미 즐겨찾기에 등록되어 있습니다"
|
||||||
cantFavorite: "즐겨찾기에 등록하지 못했습니다"
|
cantFavorite: "즐겨찾기에 등록하지 못했습니다."
|
||||||
pin: "프로필에 고정"
|
pin: "프로필에 고정"
|
||||||
unpin: "프로필에서 고정 해제"
|
unpin: "프로필에서 고정 해제"
|
||||||
copyContent: "내용 복사"
|
copyContent: "내용 복사"
|
||||||
@@ -49,15 +49,11 @@ delete: "삭제"
|
|||||||
deleteAndEdit: "삭제 후 편집"
|
deleteAndEdit: "삭제 후 편집"
|
||||||
deleteAndEditConfirm: "이 노트를 삭제한 뒤 다시 편집하시겠습니까? 이 노트에 대한 리액션, 리노트, 답글 또한 모두 삭제됩니다."
|
deleteAndEditConfirm: "이 노트를 삭제한 뒤 다시 편집하시겠습니까? 이 노트에 대한 리액션, 리노트, 답글 또한 모두 삭제됩니다."
|
||||||
addToList: "리스트에 추가"
|
addToList: "리스트에 추가"
|
||||||
addToAntenna: "안테나에 추가"
|
|
||||||
sendMessage: "메시지 보내기"
|
sendMessage: "메시지 보내기"
|
||||||
copyRSS: "RSS 복사"
|
copyRSS: "RSS 복사"
|
||||||
copyUsername: "유저명 복사"
|
copyUsername: "유저명 복사"
|
||||||
copyUserId: "유저 ID 복사"
|
copyUserId: "유저 ID 복사"
|
||||||
copyNoteId: "노트 ID 복사"
|
copyNoteId: "노트 ID 복사"
|
||||||
copyFileId: "파일 ID 복사"
|
|
||||||
copyFolderId: "폴더 ID 복사"
|
|
||||||
copyProfileUrl: "프로필 URL 복사"
|
|
||||||
searchUser: "사용자 검색"
|
searchUser: "사용자 검색"
|
||||||
reply: "답글"
|
reply: "답글"
|
||||||
loadMore: "더 보기"
|
loadMore: "더 보기"
|
||||||
@@ -108,7 +104,7 @@ renote: "리노트"
|
|||||||
unrenote: "리노트 취소"
|
unrenote: "리노트 취소"
|
||||||
renoted: "리노트했습니다"
|
renoted: "리노트했습니다"
|
||||||
cantRenote: "이 게시물은 리노트 할 수 없습니다."
|
cantRenote: "이 게시물은 리노트 할 수 없습니다."
|
||||||
cantReRenote: "리노트를 리노트할 수 없습니다."
|
cantReRenote: "리노트를 리노트 할 수 없습니다."
|
||||||
quote: "인용"
|
quote: "인용"
|
||||||
inChannelRenote: "채널 내 리노트"
|
inChannelRenote: "채널 내 리노트"
|
||||||
inChannelQuote: "채널 내 인용"
|
inChannelQuote: "채널 내 인용"
|
||||||
@@ -116,7 +112,7 @@ pinnedNote: "고정해놓은 노트"
|
|||||||
pinned: "프로필에 고정"
|
pinned: "프로필에 고정"
|
||||||
you: "당신"
|
you: "당신"
|
||||||
clickToShow: "클릭하여 보기"
|
clickToShow: "클릭하여 보기"
|
||||||
sensitive: "열람 주의"
|
sensitive: "열람주의"
|
||||||
add: "추가"
|
add: "추가"
|
||||||
reaction: "리액션"
|
reaction: "리액션"
|
||||||
reactions: "리액션"
|
reactions: "리액션"
|
||||||
@@ -156,12 +152,10 @@ addEmoji: "이모지 추가"
|
|||||||
settingGuide: "추천 설정"
|
settingGuide: "추천 설정"
|
||||||
cacheRemoteFiles: "리모트 파일을 캐시"
|
cacheRemoteFiles: "리모트 파일을 캐시"
|
||||||
cacheRemoteFilesDescription: "이 설정을 해지하면 리모트 파일을 캐시하지 않고 해당 파일을 직접 링크하게 됩니다. 그에 따라 서버의 저장 공간을 절약할 수 있지만, 썸네일이 생성되지 않기 때문에 통신량이 증가합니다."
|
cacheRemoteFilesDescription: "이 설정을 해지하면 리모트 파일을 캐시하지 않고 해당 파일을 직접 링크하게 됩니다. 그에 따라 서버의 저장 공간을 절약할 수 있지만, 썸네일이 생성되지 않기 때문에 통신량이 증가합니다."
|
||||||
cacheRemoteSensitiveFiles: "리모트의 민감한 파일을 캐시"
|
|
||||||
cacheRemoteSensitiveFilesDescription: "이 설정을 비활성화하면 리모트의 민감한 파일은 캐시하지 않고 리모트에서 직접 가져오도록 합니다."
|
|
||||||
flagAsBot: "나는 봇입니다"
|
flagAsBot: "나는 봇입니다"
|
||||||
flagAsBotDescription: "이 계정을 자동화된 수단으로 운용할 경우에 활성화해 주세요. 이 플래그를 활성화하면, 다른 봇이 이를 참고하여 봇 끼리의 무한 연쇄 반응을 회피하거나, 이 계정의 시스템 상에서의 취급이 Bot 운영에 최적화되는 등의 변화가 생깁니다."
|
flagAsBotDescription: "이 계정을 자동화된 수단으로 운용할 경우에 활성화해 주세요. 이 플래그를 활성화하면, 다른 봇이 이를 참고하여 봇 끼리의 무한 연쇄 반응을 회피하거나, 이 계정의 시스템 상에서의 취급이 Bot 운영에 최적화되는 등의 변화가 생깁니다."
|
||||||
flagAsCat: "나는 고양이다냥"
|
flagAsCat: "나는 고양이다냥"
|
||||||
flagAsCatDescription: "이 계정이 고양이라면 활성화해 주세요."
|
flagAsCatDescription: "이 계정이 고양이라면 활성화 해주세요."
|
||||||
flagShowTimelineReplies: "타임라인에 노트의 답글을 표시하기"
|
flagShowTimelineReplies: "타임라인에 노트의 답글을 표시하기"
|
||||||
flagShowTimelineRepliesDescription: "이 설정을 활성화하면 타임라인에 다른 유저 간의 답글을 표시합니다."
|
flagShowTimelineRepliesDescription: "이 설정을 활성화하면 타임라인에 다른 유저 간의 답글을 표시합니다."
|
||||||
autoAcceptFollowed: "팔로우 중인 유저로부터의 팔로우 요청을 자동 수락"
|
autoAcceptFollowed: "팔로우 중인 유저로부터의 팔로우 요청을 자동 수락"
|
||||||
@@ -207,7 +201,7 @@ instanceInfo: "서버 정보"
|
|||||||
statistics: "통계"
|
statistics: "통계"
|
||||||
clearQueue: "대기열 비우기"
|
clearQueue: "대기열 비우기"
|
||||||
clearQueueConfirmTitle: "대기열을 비우시겠습니까?"
|
clearQueueConfirmTitle: "대기열을 비우시겠습니까?"
|
||||||
clearQueueConfirmText: "대기열에 남아 있는 노트는 더 이상 연합되지 않습니다. 보통의 경우 이 작업은 필요하지 않습니다."
|
clearQueueConfirmText: "대기열에 남아 있는 노트는 더이상 연합되지 않습니다. 보통의 경우 이 작업은 필요하지 않습니다."
|
||||||
clearCachedFiles: "캐시 비우기"
|
clearCachedFiles: "캐시 비우기"
|
||||||
clearCachedFilesConfirm: "캐시된 리모트 파일을 모두 삭제하시겠습니까?"
|
clearCachedFilesConfirm: "캐시된 리모트 파일을 모두 삭제하시겠습니까?"
|
||||||
blockedInstances: "차단된 서버"
|
blockedInstances: "차단된 서버"
|
||||||
@@ -319,7 +313,6 @@ copyUrl: "URL 복사"
|
|||||||
rename: "이름 변경"
|
rename: "이름 변경"
|
||||||
avatar: "아바타"
|
avatar: "아바타"
|
||||||
banner: "배너"
|
banner: "배너"
|
||||||
displayOfSensitiveMedia: "민감한 미디어 표시"
|
|
||||||
whenServerDisconnected: "서버와의 접속이 끊겼을 때"
|
whenServerDisconnected: "서버와의 접속이 끊겼을 때"
|
||||||
disconnectedFromServer: "서버와의 연결이 끊어졌습니다"
|
disconnectedFromServer: "서버와의 연결이 끊어졌습니다"
|
||||||
reload: "새로고침"
|
reload: "새로고침"
|
||||||
@@ -1073,24 +1066,6 @@ installed: "설치됨"
|
|||||||
branding: "브랜딩"
|
branding: "브랜딩"
|
||||||
enableServerMachineStats: "서버의 머신 사양을 공개하기"
|
enableServerMachineStats: "서버의 머신 사양을 공개하기"
|
||||||
enableIdenticonGeneration: "유저마다의 Identicon 생성 유효화"
|
enableIdenticonGeneration: "유저마다의 Identicon 생성 유효화"
|
||||||
turnOffToImprovePerformance: "이 기능을 끄면 성능이 향상될 수 있습니다."
|
|
||||||
createInviteCode: "초대 코드 생성"
|
|
||||||
createWithOptions: "옵션을 지정하여 생성"
|
|
||||||
createCount: "초대 수"
|
|
||||||
inviteCodeCreated: "초대 코드 생성됨"
|
|
||||||
inviteLimitExceeded: "초대 코드 생성 한도를 초과했습니다."
|
|
||||||
createLimitRemaining: "초대 한도: {limit}회 남음"
|
|
||||||
inviteLimitResetCycle: " {time}시간 이내에 최대 {limit}개의 초대 코드를 생성할 수 있습니다."
|
|
||||||
expirationDate: "만료 날짜"
|
|
||||||
noExpirationDate: "만료기간 없음"
|
|
||||||
inviteCodeUsedAt: "다음에 사용된 초대 코드"
|
|
||||||
registeredUserUsingInviteCode: "초대 코드 사용 대상"
|
|
||||||
waitingForMailAuth: "이메일 인증 보류 중"
|
|
||||||
inviteCodeCreator: "초대 코드 생성자"
|
|
||||||
usedAt: "사용 시각"
|
|
||||||
unused: "사용되지 않음"
|
|
||||||
used: "사용됨"
|
|
||||||
expired: "만료됨"
|
|
||||||
_initialAccountSetting:
|
_initialAccountSetting:
|
||||||
accountCreated: "계정 생성이 완료되었습니다!"
|
accountCreated: "계정 생성이 완료되었습니다!"
|
||||||
letsStartAccountSetup: "계정의 초기 설정을 진행합니다."
|
letsStartAccountSetup: "계정의 초기 설정을 진행합니다."
|
||||||
@@ -1401,9 +1376,6 @@ _role:
|
|||||||
ltlAvailable: "로컬 타임라인 보이기"
|
ltlAvailable: "로컬 타임라인 보이기"
|
||||||
canPublicNote: "공개 노트 허용"
|
canPublicNote: "공개 노트 허용"
|
||||||
canInvite: "서버 초대 코드 발행"
|
canInvite: "서버 초대 코드 발행"
|
||||||
inviteLimit: "초대 한도"
|
|
||||||
inviteLimitCycle: "초대 발급 간격"
|
|
||||||
inviteExpirationTime: "초대 만료 기간"
|
|
||||||
canManageCustomEmojis: "커스텀 이모지 관리"
|
canManageCustomEmojis: "커스텀 이모지 관리"
|
||||||
driveCapacity: "드라이브 용량"
|
driveCapacity: "드라이브 용량"
|
||||||
alwaysMarkNsfw: "파일을 항상 NSFW로 지정"
|
alwaysMarkNsfw: "파일을 항상 NSFW로 지정"
|
||||||
@@ -1466,7 +1438,6 @@ _ad:
|
|||||||
back: "뒤로"
|
back: "뒤로"
|
||||||
reduceFrequencyOfThisAd: "이 광고의 표시 빈도 낮추기"
|
reduceFrequencyOfThisAd: "이 광고의 표시 빈도 낮추기"
|
||||||
hide: "보이지 않음"
|
hide: "보이지 않음"
|
||||||
timezoneinfo: "요일은 서버의 표준 시간대에 따라 결정됩니다."
|
|
||||||
_forgotPassword:
|
_forgotPassword:
|
||||||
enterEmail: "여기에 계정에 등록한 메일 주소를 입력해 주세요. 입력한 메일 주소로 비밀번호 재설정 링크를 발송합니다."
|
enterEmail: "여기에 계정에 등록한 메일 주소를 입력해 주세요. 입력한 메일 주소로 비밀번호 재설정 링크를 발송합니다."
|
||||||
ifNoEmail: "메일 주소를 등록하지 않은 경우, 관리자에 문의해 주십시오."
|
ifNoEmail: "메일 주소를 등록하지 않은 경우, 관리자에 문의해 주십시오."
|
||||||
@@ -1518,10 +1489,6 @@ _aboutMisskey:
|
|||||||
donate: "Misskey에 기부하기"
|
donate: "Misskey에 기부하기"
|
||||||
morePatrons: "이 외에도 다른 많은 분들이 도움을 주시고 계십니다. 감사합니다🥰"
|
morePatrons: "이 외에도 다른 많은 분들이 도움을 주시고 계십니다. 감사합니다🥰"
|
||||||
patrons: "후원자"
|
patrons: "후원자"
|
||||||
_displayOfSensitiveMedia:
|
|
||||||
respect: "민감한 콘텐츠로 표시된 미디어 숨기기"
|
|
||||||
ignore: "민감한 콘텐츠로 표시된 미디어 보이기"
|
|
||||||
force: "미디어 항상 숨기기"
|
|
||||||
_instanceTicker:
|
_instanceTicker:
|
||||||
none: "보이지 않음"
|
none: "보이지 않음"
|
||||||
remote: "리모트 유저에게만 보이기"
|
remote: "리모트 유저에게만 보이기"
|
||||||
@@ -1996,7 +1963,6 @@ _deck:
|
|||||||
introduction: "칼럼을 조합해서 나만의 인터페이스를 구성해 보아요!"
|
introduction: "칼럼을 조합해서 나만의 인터페이스를 구성해 보아요!"
|
||||||
introduction2: "나중에라도 화면 우측의 + 버튼을 눌러 새 칼럼을 추가할 수 있습니다."
|
introduction2: "나중에라도 화면 우측의 + 버튼을 눌러 새 칼럼을 추가할 수 있습니다."
|
||||||
widgetsIntroduction: "칼럼 메뉴의 \"위젯 편집\"에서 위젯을 추가해 주세요"
|
widgetsIntroduction: "칼럼 메뉴의 \"위젯 편집\"에서 위젯을 추가해 주세요"
|
||||||
useSimpleUiForNonRootPages: "루트 이외의 페이지로 접속한 경우 UI 간략화하기"
|
|
||||||
_columns:
|
_columns:
|
||||||
main: "메인"
|
main: "메인"
|
||||||
widgets: "위젯"
|
widgets: "위젯"
|
||||||
|
@@ -20,7 +20,6 @@ noNotes: "ບໍ່ມີຫມາຍເຫດ"
|
|||||||
noNotifications: "ບໍ່ມີການແຈ້ງເຕືອນ"
|
noNotifications: "ບໍ່ມີການແຈ້ງເຕືອນ"
|
||||||
instance: "ອີນສະແຕນ"
|
instance: "ອີນສະແຕນ"
|
||||||
settings: "ກຳນົດຄ່າ"
|
settings: "ກຳນົດຄ່າ"
|
||||||
notificationSettings: "ຕັ້ງຄ່າການແຈ້ງເຕືອນ"
|
|
||||||
basicSettings: "ການຕັ້ງຄ່າພື້ນຖານ"
|
basicSettings: "ການຕັ້ງຄ່າພື້ນຖານ"
|
||||||
otherSettings: "ການຕັ້ງຄ່າອື່ນໆ"
|
otherSettings: "ການຕັ້ງຄ່າອື່ນໆ"
|
||||||
openInWindow: "ເປີດຢູ່ໃນປ່ອງຢ້ຽມ"
|
openInWindow: "ເປີດຢູ່ໃນປ່ອງຢ້ຽມ"
|
||||||
@@ -49,15 +48,9 @@ delete: "ລຶບ"
|
|||||||
deleteAndEdit: "ລົບແລະແກ້ໄຂ"
|
deleteAndEdit: "ລົບແລະແກ້ໄຂ"
|
||||||
deleteAndEditConfirm: "ເຈົ້າແນ່ໃຈບໍ່? ທີ່ທ່ານຕ້ອງການທີ່ຈະລຶບບັນທຶກນີ້ແລະແກ້ໄຂມັນ ທ່ານອາດຈະສູນເສຍການໂຕ້ຕອບ, ບັນທຶກ, ແລະການຕອບກັບທັງໝົດ"
|
deleteAndEditConfirm: "ເຈົ້າແນ່ໃຈບໍ່? ທີ່ທ່ານຕ້ອງການທີ່ຈະລຶບບັນທຶກນີ້ແລະແກ້ໄຂມັນ ທ່ານອາດຈະສູນເສຍການໂຕ້ຕອບ, ບັນທຶກ, ແລະການຕອບກັບທັງໝົດ"
|
||||||
addToList: "ເພີ່ມໃສ່ລາຍຊື່"
|
addToList: "ເພີ່ມໃສ່ລາຍຊື່"
|
||||||
addToAntenna: "ເພີ່ມໃສ່ເສົາອາກາດ"
|
|
||||||
sendMessage: "ສົ່ງຂໍ້ຄວາມ"
|
sendMessage: "ສົ່ງຂໍ້ຄວາມ"
|
||||||
copyRSS: "ສຳເນົາ RSS"
|
copyRSS: "ສຳເນົາ RSS"
|
||||||
copyUsername: "ສຳເນົາຊື່ຜູ້ໃຊ້"
|
copyUsername: "ສຳເນົາຊື່ຜູ້ໃຊ້"
|
||||||
copyUserId: "ສຳເນົາ ID ຜູ້ໃຊ້"
|
|
||||||
copyNoteId: "ສຳເນົາ ID ບັນທຶກ"
|
|
||||||
copyFileId: "ສຳເນົາ ID ໄຟລ໌"
|
|
||||||
copyFolderId: "ສຳເນົາ ID ໂຟນເດີ"
|
|
||||||
copyProfileUrl: "ສຳເນົາ URL ໂປຣໄຟລ໌"
|
|
||||||
searchUser: "ຄົ້ນຫາຜູ້ໃຊ້"
|
searchUser: "ຄົ້ນຫາຜູ້ໃຊ້"
|
||||||
reply: "ຕອບໄປທີ"
|
reply: "ຕອບໄປທີ"
|
||||||
loadMore: "ໂຫຼດເພີ່ມເຕີມ"
|
loadMore: "ໂຫຼດເພີ່ມເຕີມ"
|
||||||
@@ -116,7 +109,6 @@ sensitive: "NSFW"
|
|||||||
add: "ເພີ່ມ"
|
add: "ເພີ່ມ"
|
||||||
reaction: "ປະຕິກິລິຍາ"
|
reaction: "ປະຕິກິລິຍາ"
|
||||||
reactions: "ປະຕິກິລິຍາ"
|
reactions: "ປະຕິກິລິຍາ"
|
||||||
attachCancel: "ເອົາໄຟລ໌ແນບ"
|
|
||||||
mute: "ປີດສຽງ"
|
mute: "ປີດສຽງ"
|
||||||
unmute: "ເປີດສຽງ"
|
unmute: "ເປີດສຽງ"
|
||||||
block: "ບ໋ອກ"
|
block: "ບ໋ອກ"
|
||||||
@@ -124,10 +116,6 @@ unblock: "ຍົກເລີກກາຮົບລັອກ"
|
|||||||
suspend: "ລະງັບ"
|
suspend: "ລະງັບ"
|
||||||
unsuspend: "ເຊົາລະງັບ"
|
unsuspend: "ເຊົາລະງັບ"
|
||||||
selectList: "ເລືອກບັນຊີລາຍການ"
|
selectList: "ເລືອກບັນຊີລາຍການ"
|
||||||
editList: "ແກ້ໄຂລາຍຊື່"
|
|
||||||
selectChannel: "ເລືອກຊ່ອງ"
|
|
||||||
selectAntenna: "ເລືອກເສົາອາກາດ"
|
|
||||||
editAntenna: "ແກ້ໄຂເສົາອາກາດ"
|
|
||||||
selectWidget: "ເລືອກວິກເຈັດ"
|
selectWidget: "ເລືອກວິກເຈັດ"
|
||||||
editWidgets: "ແກ້ໄຂ Widget"
|
editWidgets: "ແກ້ໄຂ Widget"
|
||||||
editWidgetsExit: "ສຳເລັດແລ້ວ"
|
editWidgetsExit: "ສຳເລັດແລ້ວ"
|
||||||
@@ -137,7 +125,6 @@ emojis: "ອີໂມຈິ"
|
|||||||
emojiName: "ຊື່ Emoji"
|
emojiName: "ຊື່ Emoji"
|
||||||
emojiUrl: "URL ອີໂມຈິ"
|
emojiUrl: "URL ອີໂມຈິ"
|
||||||
addEmoji: "ຕື່ມອີໂມຈິ"
|
addEmoji: "ຕື່ມອີໂມຈິ"
|
||||||
settingGuide: "ການຕັ້ງຄ່າທີ່ແນະນໍາ"
|
|
||||||
flagAsBot: "ໝາຍບັນຊີນີ້ເປັນບັອດ"
|
flagAsBot: "ໝາຍບັນຊີນີ້ເປັນບັອດ"
|
||||||
flagAsCat: "ໝາຍບັນຊີນີ້ເປັນແມວ"
|
flagAsCat: "ໝາຍບັນຊີນີ້ເປັນແມວ"
|
||||||
flagAsCatDescription: "ເປີດໃຊ້ຕົວເລືອກນີ້ເພື່ອໝາຍບັນຊີນີ້ເປັນແມວ"
|
flagAsCatDescription: "ເປີດໃຊ້ຕົວເລືອກນີ້ເພື່ອໝາຍບັນຊີນີ້ເປັນແມວ"
|
||||||
@@ -146,13 +133,10 @@ flagShowTimelineRepliesDescription: "ສະແດງການຕອບກັບ
|
|||||||
autoAcceptFollowed: "ອະນຸມັດອັດຕະໂນມັດຕາມຄຳຮ້ອງຂໍຈາກຜູ້ໃຊ້ທີ່ທ່ານກຳລັງຕິດຕາມຢູ່"
|
autoAcceptFollowed: "ອະນຸມັດອັດຕະໂນມັດຕາມຄຳຮ້ອງຂໍຈາກຜູ້ໃຊ້ທີ່ທ່ານກຳລັງຕິດຕາມຢູ່"
|
||||||
addAccount: "ເພີ່ມບັນຊີ"
|
addAccount: "ເພີ່ມບັນຊີ"
|
||||||
loginFailed: "ການເຂົ້າສູ່ລະບົບບໍ່ສຳເລັດ"
|
loginFailed: "ການເຂົ້າສູ່ລະບົບບໍ່ສຳເລັດ"
|
||||||
showOnRemote: "ເບິ່ງຢູ່ໃນຕົວຢ່າງໄລຍະໄກ"
|
|
||||||
general: "ທົ່ວໄປ"
|
general: "ທົ່ວໄປ"
|
||||||
wallpaper: "ພາບພື້ນຫລັງ"
|
wallpaper: "ພາບພື້ນຫລັງ"
|
||||||
setWallpaper: "ຕັ້ງເປັນພາບພື້ນຫຼັງ"
|
setWallpaper: "ຕັ້ງເປັນພາບພື້ນຫຼັງ"
|
||||||
removeWallpaper: "ລຶບຮູບວໍເປເປີອອກ"
|
|
||||||
searchWith: "ຊອກຫາ: {q}"
|
searchWith: "ຊອກຫາ: {q}"
|
||||||
youHaveNoLists: "ທ່ານບໍ່ມີລາຍການໃດໆ"
|
|
||||||
proxyAccount: "ບັນຊີພຣັອກຊີ"
|
proxyAccount: "ບັນຊີພຣັອກຊີ"
|
||||||
host: "ໂຮດສ"
|
host: "ໂຮດສ"
|
||||||
selectUser: "ເລືອກຜູ້ໃຊ້"
|
selectUser: "ເລືອກຜູ້ໃຊ້"
|
||||||
@@ -171,9 +155,7 @@ operations: "ການດຳເນີນງານ"
|
|||||||
software: "ຊອບແວ"
|
software: "ຊອບແວ"
|
||||||
version: "ສະບັບ"
|
version: "ສະບັບ"
|
||||||
metadata: "Metadata"
|
metadata: "Metadata"
|
||||||
withNFiles: "{n} ໄຟລ໌(s)"
|
|
||||||
monitor: "ຈໍພາບ"
|
monitor: "ຈໍພາບ"
|
||||||
jobQueue: "ຄິວວຽກ"
|
|
||||||
cpuAndMemory: "CPU ແລະ ຫນ່ວຍຄວາມຈໍາ"
|
cpuAndMemory: "CPU ແລະ ຫນ່ວຍຄວາມຈໍາ"
|
||||||
network: "ເຄືອຂ່າຍ"
|
network: "ເຄືອຂ່າຍ"
|
||||||
disk: "ດິສກ໌"
|
disk: "ດິສກ໌"
|
||||||
@@ -361,7 +343,6 @@ _widgets:
|
|||||||
timeline: "ເສັ້ນກຳນົດເວລາ"
|
timeline: "ເສັ້ນກຳນົດເວລາ"
|
||||||
activity: "ກິດຈະກຳ"
|
activity: "ກິດຈະກຳ"
|
||||||
federation: "ສະຫະພັນ"
|
federation: "ສະຫະພັນ"
|
||||||
jobQueue: "ຄິວວຽກ"
|
|
||||||
_userList:
|
_userList:
|
||||||
chooseList: "ເລືອກບັນຊີລາຍການ"
|
chooseList: "ເລືອກບັນຊີລາຍການ"
|
||||||
_cw:
|
_cw:
|
||||||
|
@@ -20,7 +20,6 @@ noNotes: "Geen notities"
|
|||||||
noNotifications: "Geen meldingen"
|
noNotifications: "Geen meldingen"
|
||||||
instance: "Server"
|
instance: "Server"
|
||||||
settings: "Instellingen"
|
settings: "Instellingen"
|
||||||
notificationSettings: "Notificatie instellingen"
|
|
||||||
basicSettings: "Basisinstellingen"
|
basicSettings: "Basisinstellingen"
|
||||||
otherSettings: "Overige instellingen"
|
otherSettings: "Overige instellingen"
|
||||||
openInWindow: "In een venster openen"
|
openInWindow: "In een venster openen"
|
||||||
@@ -49,15 +48,8 @@ delete: "Verwijderen"
|
|||||||
deleteAndEdit: "Verwijderen en bewerken"
|
deleteAndEdit: "Verwijderen en bewerken"
|
||||||
deleteAndEditConfirm: "Weet je zeker dat je deze notitie wilt verwijderen en dan bewerken? Je verliest alle reacties, herdelingen en antwoorden erop."
|
deleteAndEditConfirm: "Weet je zeker dat je deze notitie wilt verwijderen en dan bewerken? Je verliest alle reacties, herdelingen en antwoorden erop."
|
||||||
addToList: "Aan lijst toevoegen"
|
addToList: "Aan lijst toevoegen"
|
||||||
addToAntenna: "Voeg toe aan antenne"
|
|
||||||
sendMessage: "Verstuur bericht"
|
sendMessage: "Verstuur bericht"
|
||||||
copyRSS: "Kopieer RSS"
|
|
||||||
copyUsername: "Kopiëren gebruikersnaam "
|
copyUsername: "Kopiëren gebruikersnaam "
|
||||||
copyUserId: "Kopieer gebruiker ID"
|
|
||||||
copyNoteId: "Kopieer notitie ID"
|
|
||||||
copyFileId: "Kopieer veld ID"
|
|
||||||
copyFolderId: "Kopieer folder ID"
|
|
||||||
copyProfileUrl: "Kopieer profiel URL"
|
|
||||||
searchUser: "Zoeken een gebruiker"
|
searchUser: "Zoeken een gebruiker"
|
||||||
reply: "Antwoord"
|
reply: "Antwoord"
|
||||||
loadMore: "Laad meer"
|
loadMore: "Laad meer"
|
||||||
|
File diff suppressed because it is too large
Load Diff
@@ -49,15 +49,11 @@ delete: "Удалить"
|
|||||||
deleteAndEdit: "Удалить и отредактировать"
|
deleteAndEdit: "Удалить и отредактировать"
|
||||||
deleteAndEditConfirm: "Удалить эту заметку и создать отредактированную? Все реакции, ссылки и ответы на существующую будут будут потеряны."
|
deleteAndEditConfirm: "Удалить эту заметку и создать отредактированную? Все реакции, ссылки и ответы на существующую будут будут потеряны."
|
||||||
addToList: "Добавить в список"
|
addToList: "Добавить в список"
|
||||||
addToAntenna: "Добавить к антенне"
|
|
||||||
sendMessage: "Отправить сообщение"
|
sendMessage: "Отправить сообщение"
|
||||||
copyRSS: "Скопировать RSS"
|
copyRSS: "Скопировать RSS"
|
||||||
copyUsername: "Скопировать имя пользователя"
|
copyUsername: "Скопировать имя пользователя"
|
||||||
copyUserId: "Скопировать ID пользователя"
|
copyUserId: "Скопировать ID пользователя"
|
||||||
copyNoteId: "Скопировать ID заметки"
|
copyNoteId: "Скопировать ID заметки"
|
||||||
copyFileId: "Скопировать ID файла"
|
|
||||||
copyFolderId: "Скопировать ID папки"
|
|
||||||
copyProfileUrl: "Скопировать URL профиля "
|
|
||||||
searchUser: "Поиск людей"
|
searchUser: "Поиск людей"
|
||||||
reply: "Ответить"
|
reply: "Ответить"
|
||||||
loadMore: "Показать еще"
|
loadMore: "Показать еще"
|
||||||
@@ -140,10 +136,8 @@ unblockConfirm: "Разблокировать этот аккаунт?"
|
|||||||
suspendConfirm: "Заморозить этот аккаунт?"
|
suspendConfirm: "Заморозить этот аккаунт?"
|
||||||
unsuspendConfirm: "Разморозить этот аккаунт?"
|
unsuspendConfirm: "Разморозить этот аккаунт?"
|
||||||
selectList: "Выберите список"
|
selectList: "Выберите список"
|
||||||
editList: "Редактировать список"
|
|
||||||
selectChannel: "Выберите канал"
|
selectChannel: "Выберите канал"
|
||||||
selectAntenna: "Выберите антенну"
|
selectAntenna: "Выберите антенну"
|
||||||
editAntenna: "Редактировать антенну"
|
|
||||||
selectWidget: "Выберите виджет"
|
selectWidget: "Выберите виджет"
|
||||||
editWidgets: "Редактировать виджеты"
|
editWidgets: "Редактировать виджеты"
|
||||||
editWidgetsExit: "Готово"
|
editWidgetsExit: "Готово"
|
||||||
@@ -156,8 +150,6 @@ addEmoji: "Добавить эмодзи"
|
|||||||
settingGuide: "Рекомендуемые настройки"
|
settingGuide: "Рекомендуемые настройки"
|
||||||
cacheRemoteFiles: "Кешировать внешние файлы"
|
cacheRemoteFiles: "Кешировать внешние файлы"
|
||||||
cacheRemoteFilesDescription: "Когда эта настройка отключена, файлы с других сайтов будут загружаться прямо оттуда. Это сэкономит место на сервере, но увеличит трафик, так как не будут создаваться эскизы."
|
cacheRemoteFilesDescription: "Когда эта настройка отключена, файлы с других сайтов будут загружаться прямо оттуда. Это сэкономит место на сервере, но увеличит трафик, так как не будут создаваться эскизы."
|
||||||
cacheRemoteSensitiveFiles: "Кешировать внешние файлы"
|
|
||||||
cacheRemoteSensitiveFilesDescription: "Описание удаленных внешних файлов в кэше"
|
|
||||||
flagAsBot: "Аккаунт бота"
|
flagAsBot: "Аккаунт бота"
|
||||||
flagAsBotDescription: "Включите, если этот аккаунт управляется программой. Это позволит системе Misskey учитывать это, а также поможет разработчикам других ботов предотвратить бесконечные циклы взаимодействия."
|
flagAsBotDescription: "Включите, если этот аккаунт управляется программой. Это позволит системе Misskey учитывать это, а также поможет разработчикам других ботов предотвратить бесконечные циклы взаимодействия."
|
||||||
flagAsCat: "Аккаунт кота"
|
flagAsCat: "Аккаунт кота"
|
||||||
@@ -319,7 +311,6 @@ copyUrl: "Копировать ссылку"
|
|||||||
rename: "Переименовать"
|
rename: "Переименовать"
|
||||||
avatar: "Аватар"
|
avatar: "Аватар"
|
||||||
banner: "Шапка"
|
banner: "Шапка"
|
||||||
displayOfSensitiveMedia: "Определение деликатного контента"
|
|
||||||
whenServerDisconnected: "Когда соединение с сервером потеряно"
|
whenServerDisconnected: "Когда соединение с сервером потеряно"
|
||||||
disconnectedFromServer: "Разорвано соединение с сервером"
|
disconnectedFromServer: "Разорвано соединение с сервером"
|
||||||
reload: "Перезагрузить"
|
reload: "Перезагрузить"
|
||||||
@@ -844,8 +835,6 @@ breakFollow: "Отписка"
|
|||||||
breakFollowConfirm: "Удалить из подписок пользователя ?"
|
breakFollowConfirm: "Удалить из подписок пользователя ?"
|
||||||
itsOn: "Включено"
|
itsOn: "Включено"
|
||||||
itsOff: "Выключено"
|
itsOff: "Выключено"
|
||||||
on: "Вкл"
|
|
||||||
off: "Выкл"
|
|
||||||
emailRequiredForSignup: "Для регистрации учётной записи нужен адрес электронной почты"
|
emailRequiredForSignup: "Для регистрации учётной записи нужен адрес электронной почты"
|
||||||
unread: "Непрочитанное"
|
unread: "Непрочитанное"
|
||||||
filter: "Фильтры"
|
filter: "Фильтры"
|
||||||
@@ -1000,7 +989,6 @@ cannotBeChangedLater: "Это нельзя изменить позже"
|
|||||||
reactionAcceptance: "Принятие реакций"
|
reactionAcceptance: "Принятие реакций"
|
||||||
likeOnly: "Только лайки"
|
likeOnly: "Только лайки"
|
||||||
likeOnlyForRemote: "Только лайки с удалённых серверов"
|
likeOnlyForRemote: "Только лайки с удалённых серверов"
|
||||||
nonSensitiveOnly: "Безопасный серфинг"
|
|
||||||
rolesAssignedToMe: "Мои роли"
|
rolesAssignedToMe: "Мои роли"
|
||||||
resetPasswordConfirm: "Сбросить пароль?"
|
resetPasswordConfirm: "Сбросить пароль?"
|
||||||
sensitiveWords: "Чувствительные слова"
|
sensitiveWords: "Чувствительные слова"
|
||||||
@@ -1021,15 +1009,7 @@ noteIdOrUrl: "ID или ссылка на заметку"
|
|||||||
video: "Видео"
|
video: "Видео"
|
||||||
videos: "Видео"
|
videos: "Видео"
|
||||||
dataSaver: "Экономия трафика"
|
dataSaver: "Экономия трафика"
|
||||||
accountMigration: "Перенести учётную запись"
|
|
||||||
accountMoved: "Учетная запись перенесена"
|
|
||||||
operationForbidden: "Эта операция невозможна."
|
|
||||||
addMemo: "Добавить заметку"
|
|
||||||
editMemo: "Редактировать заметку"
|
|
||||||
reactionsList: "Реакции"
|
|
||||||
renotesList: "Репосты"
|
renotesList: "Репосты"
|
||||||
notificationDisplay: "Отображение уведомления"
|
|
||||||
leftTop: "Верхний левый угол"
|
|
||||||
horizontal: "Сбоку"
|
horizontal: "Сбоку"
|
||||||
youFollowing: "Подписки"
|
youFollowing: "Подписки"
|
||||||
options: "Настройки ролей"
|
options: "Настройки ролей"
|
||||||
|
@@ -20,7 +20,6 @@ noNotes: "Inga noteringar"
|
|||||||
noNotifications: "Inga notifikationer"
|
noNotifications: "Inga notifikationer"
|
||||||
instance: "Instanser"
|
instance: "Instanser"
|
||||||
settings: "Inställningar"
|
settings: "Inställningar"
|
||||||
notificationSettings: "Notifieringsinställningar"
|
|
||||||
basicSettings: "Basinställningar"
|
basicSettings: "Basinställningar"
|
||||||
otherSettings: "Andra inställningar"
|
otherSettings: "Andra inställningar"
|
||||||
openInWindow: "Öppna i ett fönster"
|
openInWindow: "Öppna i ett fönster"
|
||||||
@@ -54,8 +53,6 @@ copyRSS: "Kopiera RSS"
|
|||||||
copyUsername: "Kopiera användarnamn"
|
copyUsername: "Kopiera användarnamn"
|
||||||
copyUserId: "Kopiera användar-ID"
|
copyUserId: "Kopiera användar-ID"
|
||||||
copyNoteId: "Kopiera noter-ID"
|
copyNoteId: "Kopiera noter-ID"
|
||||||
copyFileId: "Kopiera Fil-ID"
|
|
||||||
copyFolderId: "Kopiera mapp-ID"
|
|
||||||
searchUser: "Sök användare"
|
searchUser: "Sök användare"
|
||||||
reply: "Svara"
|
reply: "Svara"
|
||||||
loadMore: "Ladda mer"
|
loadMore: "Ladda mer"
|
||||||
@@ -109,7 +106,6 @@ cantRenote: "Inlägget kunde inte bli omnoterat."
|
|||||||
cantReRenote: "En omnotering kan inte bli omnoterad."
|
cantReRenote: "En omnotering kan inte bli omnoterad."
|
||||||
quote: "Citat"
|
quote: "Citat"
|
||||||
inChannelRenote: "Omnotera inom kanalen"
|
inChannelRenote: "Omnotera inom kanalen"
|
||||||
inChannelQuote: "I kanal citat"
|
|
||||||
pinnedNote: "Fästad not"
|
pinnedNote: "Fästad not"
|
||||||
pinned: "Fäst till profil"
|
pinned: "Fäst till profil"
|
||||||
you: "Du"
|
you: "Du"
|
||||||
@@ -313,7 +309,6 @@ banner: "Banner"
|
|||||||
reload: "Ladda om"
|
reload: "Ladda om"
|
||||||
doNothing: "Ignorera"
|
doNothing: "Ignorera"
|
||||||
reloadConfirm: "Vill du ladda om tidslinjen?"
|
reloadConfirm: "Vill du ladda om tidslinjen?"
|
||||||
watch: "Titta"
|
|
||||||
accept: "Tillåt"
|
accept: "Tillåt"
|
||||||
reject: "Neka"
|
reject: "Neka"
|
||||||
normal: "Normal"
|
normal: "Normal"
|
||||||
@@ -339,22 +334,13 @@ invite: "Inbjudan"
|
|||||||
inMb: "I megabyte"
|
inMb: "I megabyte"
|
||||||
iconUrl: "URL till profilbilden"
|
iconUrl: "URL till profilbilden"
|
||||||
bannerUrl: "URL till banner-bilden"
|
bannerUrl: "URL till banner-bilden"
|
||||||
basicInfo: "Grundläggande info"
|
|
||||||
pinnedUsers: "Fästa användare"
|
|
||||||
pinnedPages: "Fästa sidor"
|
|
||||||
pinnedNotes: "Fästad not"
|
pinnedNotes: "Fästad not"
|
||||||
hcaptcha: "hCaptcha"
|
hcaptcha: "hCaptcha"
|
||||||
enableHcaptcha: "Aktivera hCaptcha"
|
enableHcaptcha: "Aktivera hCaptcha"
|
||||||
hcaptchaSiteKey: "Webbplatsnyckel"
|
hcaptchaSiteKey: "Webbplatsnyckel"
|
||||||
hcaptchaSecretKey: "Hemlig nyckel"
|
|
||||||
recaptcha: "reCAPTCHA"
|
recaptcha: "reCAPTCHA"
|
||||||
enableRecaptcha: "Aktivera reCAPTCHA"
|
enableRecaptcha: "Aktivera reCAPTCHA"
|
||||||
recaptchaSiteKey: "Webbplatsnyckel"
|
|
||||||
recaptchaSecretKey: "Hemlig nyckel"
|
|
||||||
turnstile: "Turnstile"
|
|
||||||
enableTurnstile: "Aktivera Turnstile"
|
enableTurnstile: "Aktivera Turnstile"
|
||||||
turnstileSiteKey: "Webbplatsnyckel"
|
|
||||||
turnstileSecretKey: "Hemlig nyckel"
|
|
||||||
antennas: "Antenner"
|
antennas: "Antenner"
|
||||||
manageAntennas: "Hantera Antenner"
|
manageAntennas: "Hantera Antenner"
|
||||||
name: "Namn"
|
name: "Namn"
|
||||||
@@ -366,7 +352,6 @@ notifyAntenna: "Notifiera om nya noter"
|
|||||||
withFileAntenna: "Endast noter med filer"
|
withFileAntenna: "Endast noter med filer"
|
||||||
enableServiceworker: "Aktivera pushnotiser i denna webbläsaren"
|
enableServiceworker: "Aktivera pushnotiser i denna webbläsaren"
|
||||||
antennaUsersDescription: "Ange ett användarnamn per linje"
|
antennaUsersDescription: "Ange ett användarnamn per linje"
|
||||||
withReplies: "Med svar"
|
|
||||||
notesAndReplies: "Inlägg och svar"
|
notesAndReplies: "Inlägg och svar"
|
||||||
silence: "Tystnad"
|
silence: "Tystnad"
|
||||||
recentlyUpdatedUsers: "Nyligen aktiva användare"
|
recentlyUpdatedUsers: "Nyligen aktiva användare"
|
||||||
@@ -377,9 +362,6 @@ userList: "Listor"
|
|||||||
about: "Om"
|
about: "Om"
|
||||||
aboutMisskey: "Om Misskey"
|
aboutMisskey: "Om Misskey"
|
||||||
administrator: "Administratör"
|
administrator: "Administratör"
|
||||||
2fa: "Tvåfaktorsautentisering"
|
|
||||||
totp: "Autentiseringsapp"
|
|
||||||
moderator: "Moderator"
|
|
||||||
passwordLessLogin: "Lösenordsfri inloggning"
|
passwordLessLogin: "Lösenordsfri inloggning"
|
||||||
passwordLessLoginDescription: "Tillåter lösenordsfri inloggning med endast en säkerhetsnyckel eller en passkey."
|
passwordLessLoginDescription: "Tillåter lösenordsfri inloggning med endast en säkerhetsnyckel eller en passkey."
|
||||||
resetPassword: "Återställ Lösenord"
|
resetPassword: "Återställ Lösenord"
|
||||||
@@ -389,13 +371,10 @@ help: "Hjälp"
|
|||||||
close: "Stäng"
|
close: "Stäng"
|
||||||
invites: "Inbjudan"
|
invites: "Inbjudan"
|
||||||
members: "Medlemmar"
|
members: "Medlemmar"
|
||||||
transfer: "Överför"
|
|
||||||
text: "Text"
|
text: "Text"
|
||||||
enable: "Aktivera"
|
enable: "Aktivera"
|
||||||
next: "Nästa"
|
next: "Nästa"
|
||||||
invitations: "Inbjudan"
|
invitations: "Inbjudan"
|
||||||
invitationCode: "Inbjudningskod"
|
|
||||||
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"
|
||||||
@@ -484,7 +463,6 @@ windowMinimize: "Minimera"
|
|||||||
windowRestore: "Återställ"
|
windowRestore: "Återställ"
|
||||||
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!"
|
||||||
resetPasswordConfirm: "Återställ verkligen ditt lösenord?"
|
resetPasswordConfirm: "Återställ verkligen ditt lösenord?"
|
||||||
dataSaver: "Databesparing"
|
|
||||||
_achievements:
|
_achievements:
|
||||||
_types:
|
_types:
|
||||||
_open3windows:
|
_open3windows:
|
||||||
|
@@ -1,9 +1,9 @@
|
|||||||
---
|
---
|
||||||
_lang_: "ภาษาไทย"
|
_lang_: "ภาษาไทย"
|
||||||
headlineMisskey: "เชื่อมต่อระบบ Network ด้วย Note"
|
headlineMisskey: "เชื่อมต่อเครือข่ายโดยโน้ต"
|
||||||
introMisskey: "ยินดีต้อนรับทุกคนจ้า! Misskey คือ บริการไมโครบล็อกกิ้ง (MicroBlogging) แบบกระจายศูนย์อำนาจ (Decentralized) \n\nเขียน \"โน้ต (Note)\" เพื่อส่งต่อเรื่องราวของคุณให้ทั้งโลกได้รับรู้📡\nและอย่าลืมที่จะ \"React\" กับเรื่องราวของคนอื่น ๆ ด้วย! 👍\n\nมุ่งสู่โลกใบใหม่กันเถอะ🚀"
|
introMisskey: "ยินดีต้อนรับจ้าาา! Misskey เป็นบริการไมโครบล็อกโอเพ่นซอร์ส แบบการกระจายอำนาจ\nสร้าง \"โน้ต\" เพื่อแบ่งปันความคิดของคุณกับทุกคนรอบตัวคุณกันเถอะ 📡\nด้วยการ \"รีแอคชั่นผู้คน\" คุณยังสามารถแสดงความรู้สึกของคุณเกี่ยวกับบันทึกของทุกคนได้อย่างรวดเร็ว 👍\n\nแล้วมาท่องสำรวจโลกใบใหม่กันเถอะ! 🚀"
|
||||||
poweredByMisskeyDescription: "{name} เป็นส่วนหนึ่งในบริการที่ถูกขับเคลื่อนโดยแพลตฟอร์มโอเพ่นซอร์ส <b>Misskey</b> (เรียกว่า \"อินสแตนซ์ Misskey\")"
|
poweredByMisskeyDescription: "{name} เป็นส่วนหนึ่งในบริการที่ถูกขับเคลื่อนโดยแพลตฟอร์มโอเพ่นซอร์ส <b>Misskey</b> (เรียกว่า \"อินสแตนซ์ Misskey\")"
|
||||||
monthAndDay: "{month}/{day}"
|
monthAndDay: "{เดือน}/{วัน}"
|
||||||
search: "ค้นหา"
|
search: "ค้นหา"
|
||||||
notifications: "การเเจ้งเตือน"
|
notifications: "การเเจ้งเตือน"
|
||||||
username: "ชื่อผู้ใช้"
|
username: "ชื่อผู้ใช้"
|
||||||
@@ -15,7 +15,7 @@ gotIt: "เข้าใจแล้ว !"
|
|||||||
cancel: "ยกเลิก"
|
cancel: "ยกเลิก"
|
||||||
noThankYou: "ไม่เป็นไร"
|
noThankYou: "ไม่เป็นไร"
|
||||||
enterUsername: "ใส่ชื่อผู้ใช้"
|
enterUsername: "ใส่ชื่อผู้ใช้"
|
||||||
renotedBy: "รีโน้ตโดย {user}"
|
renotedBy: "รีโน้ตโดย {ผู้ใช้}"
|
||||||
noNotes: "ไม่มีโน้ต"
|
noNotes: "ไม่มีโน้ต"
|
||||||
noNotifications: "ไม่มีการแจ้งเตือน"
|
noNotifications: "ไม่มีการแจ้งเตือน"
|
||||||
instance: "อินสแตนซ์"
|
instance: "อินสแตนซ์"
|
||||||
@@ -49,15 +49,11 @@ delete: "ลบ"
|
|||||||
deleteAndEdit: "ลบและแก้ไข"
|
deleteAndEdit: "ลบและแก้ไข"
|
||||||
deleteAndEditConfirm: "นายแน่ใจแล้วเหรอ? ว่าต้องการลบโน้ตนี้และแก้ไข คุณอาจจะสูญเสียการโต้ตอบ, โน้ต, และการตอบกลับทั้งหมดได้นะ"
|
deleteAndEditConfirm: "นายแน่ใจแล้วเหรอ? ว่าต้องการลบโน้ตนี้และแก้ไข คุณอาจจะสูญเสียการโต้ตอบ, โน้ต, และการตอบกลับทั้งหมดได้นะ"
|
||||||
addToList: "เพิ่มในลิสต์"
|
addToList: "เพิ่มในลิสต์"
|
||||||
addToAntenna: "เพิ่มไปยังเสาอากาศ"
|
|
||||||
sendMessage: "ส่งข้อความ"
|
sendMessage: "ส่งข้อความ"
|
||||||
copyRSS: "คัดลอก RSS"
|
copyRSS: "คัดลอก RSS"
|
||||||
copyUsername: "คัดลอกชื่อผู้ใช้"
|
copyUsername: "คัดลอกชื่อผู้ใช้"
|
||||||
copyUserId: "คัดลอก ID ผู้ใช้"
|
copyUserId: "คัดลอก ID ผู้ใช้"
|
||||||
copyNoteId: "คัดลอก ID โน้ต "
|
copyNoteId: "คัดลอก ID โน้ต "
|
||||||
copyFileId: "คัดลอกไฟล์ ID"
|
|
||||||
copyFolderId: "คัดลอกโฟลเดอร์ ID"
|
|
||||||
copyProfileUrl: "คัดลอกโปรไฟล์ URL"
|
|
||||||
searchUser: "ค้นหาผู้ใช้งาน"
|
searchUser: "ค้นหาผู้ใช้งาน"
|
||||||
reply: "ตอบกลับ"
|
reply: "ตอบกลับ"
|
||||||
loadMore: "โหลดเพิ่มเติม"
|
loadMore: "โหลดเพิ่มเติม"
|
||||||
@@ -98,7 +94,7 @@ enterListName: "ใส่ชื่อสำหรับรายการลิ
|
|||||||
privacy: "ความเป็นส่วนตัว"
|
privacy: "ความเป็นส่วนตัว"
|
||||||
makeFollowManuallyApprove: "ติดตามคำขอที่ต้องได้รับการอนุมัติ"
|
makeFollowManuallyApprove: "ติดตามคำขอที่ต้องได้รับการอนุมัติ"
|
||||||
defaultNoteVisibility: "การมองเห็นที่เป็นค่าเริ่มต้น"
|
defaultNoteVisibility: "การมองเห็นที่เป็นค่าเริ่มต้น"
|
||||||
follow: "ติดตาม"
|
follow: "กำลังติดตาม"
|
||||||
followRequest: "ส่งคำขอติดตาม"
|
followRequest: "ส่งคำขอติดตาม"
|
||||||
followRequests: "ส่งคำขอติดตาม"
|
followRequests: "ส่งคำขอติดตาม"
|
||||||
unfollow: "เลิกติดตาม"
|
unfollow: "เลิกติดตาม"
|
||||||
@@ -156,8 +152,6 @@ addEmoji: "แทรกอีโมจิ"
|
|||||||
settingGuide: "การตั้งค่าที่แนะนำ"
|
settingGuide: "การตั้งค่าที่แนะนำ"
|
||||||
cacheRemoteFiles: "แคชไฟล์ระยะไกล"
|
cacheRemoteFiles: "แคชไฟล์ระยะไกล"
|
||||||
cacheRemoteFilesDescription: "เมื่อปิดใช้งานการตั้งค่านี้ ไฟล์ระยะไกลนั้นจะถูกโหลดโดยตรงจากอินสแตนซ์ระยะไกล แต่กรณีการปิดใช้งานนี้จะช่วยลดปริมาณการใช้พื้นที่จัดเก็บข้อมูล แต่เพิ่มปริมาณการใช้งาน เพราะเนื่องจากจะไม่มีการสร้างภาพขนาดย่อ"
|
cacheRemoteFilesDescription: "เมื่อปิดใช้งานการตั้งค่านี้ ไฟล์ระยะไกลนั้นจะถูกโหลดโดยตรงจากอินสแตนซ์ระยะไกล แต่กรณีการปิดใช้งานนี้จะช่วยลดปริมาณการใช้พื้นที่จัดเก็บข้อมูล แต่เพิ่มปริมาณการใช้งาน เพราะเนื่องจากจะไม่มีการสร้างภาพขนาดย่อ"
|
||||||
cacheRemoteSensitiveFiles: "ไฟล์ระยะไกลที่มีความละเอียดอ่อนแคช"
|
|
||||||
cacheRemoteSensitiveFilesDescription: "เมื่อปิดการใช้งานแล้วการตั้งค่านี้ ไฟล์รีโมตที่มีความละเอียดอ่อนนั้นจะถูกโหลดโดยตรงจากอินสแตนซ์ระยะไกลโดยที่ไม่มีการแคช"
|
|
||||||
flagAsBot: "ทำเครื่องหมายบอกว่าบัญชีนี้เป็นบอท"
|
flagAsBot: "ทำเครื่องหมายบอกว่าบัญชีนี้เป็นบอท"
|
||||||
flagAsBotDescription: "การเปิดใช้งานตัวเลือกนี้หากบัญชีนี้ถูกควบคุมโดยนักเขียนโปรแกรม หรือ ถ้าหากเปิดใช้งาน มันจะทำหน้าที่เป็นแฟล็กสำหรับนักพัฒนารายอื่นๆ และเพื่อป้องกันการโต้ตอบแบบไม่มีที่สิ้นสุดกับบอทตัวอื่นๆ และยังสามารถปรับเปลี่ยนระบบภายในของ Misskey เพื่อปฏิบัติต่อบัญชีนี้เป็นบอท"
|
flagAsBotDescription: "การเปิดใช้งานตัวเลือกนี้หากบัญชีนี้ถูกควบคุมโดยนักเขียนโปรแกรม หรือ ถ้าหากเปิดใช้งาน มันจะทำหน้าที่เป็นแฟล็กสำหรับนักพัฒนารายอื่นๆ และเพื่อป้องกันการโต้ตอบแบบไม่มีที่สิ้นสุดกับบอทตัวอื่นๆ และยังสามารถปรับเปลี่ยนระบบภายในของ Misskey เพื่อปฏิบัติต่อบัญชีนี้เป็นบอท"
|
||||||
flagAsCat: "ทำเครื่องหมายบอกว่าบัญชีนี้เป็นแมว"
|
flagAsCat: "ทำเครื่องหมายบอกว่าบัญชีนี้เป็นแมว"
|
||||||
@@ -183,7 +177,7 @@ selectUser: "เลือกผู้ใช้งาน"
|
|||||||
recipient: "ผู้รับ"
|
recipient: "ผู้รับ"
|
||||||
annotation: "ความคิดเห็น"
|
annotation: "ความคิดเห็น"
|
||||||
federation: "เฟดิเวิร์ส"
|
federation: "เฟดิเวิร์ส"
|
||||||
instances: "Server"
|
instances: "ตัวอย่าง"
|
||||||
registeredAt: "จดทะเบียนที่"
|
registeredAt: "จดทะเบียนที่"
|
||||||
latestRequestReceivedAt: "ได้รับคำขอล่าสุดไปแล้ว"
|
latestRequestReceivedAt: "ได้รับคำขอล่าสุดไปแล้ว"
|
||||||
latestStatus: "สถานะล่าสุด"
|
latestStatus: "สถานะล่าสุด"
|
||||||
@@ -319,7 +313,6 @@ copyUrl: "คัดลอก URL"
|
|||||||
rename: "เปลี่ยนชื่อ"
|
rename: "เปลี่ยนชื่อ"
|
||||||
avatar: "ไอคอน"
|
avatar: "ไอคอน"
|
||||||
banner: "แบนเนอร์"
|
banner: "แบนเนอร์"
|
||||||
displayOfSensitiveMedia: "แสดงผลสื่อละเอียดอ่อน"
|
|
||||||
whenServerDisconnected: "สูญเสียการเชื่อมต่อกับเซิร์ฟเวอร์"
|
whenServerDisconnected: "สูญเสียการเชื่อมต่อกับเซิร์ฟเวอร์"
|
||||||
disconnectedFromServer: "ถูกตัดการเชื่อมต่อออกจากเซิร์ฟเวอร์"
|
disconnectedFromServer: "ถูกตัดการเชื่อมต่อออกจากเซิร์ฟเวอร์"
|
||||||
reload: "รีโหลด"
|
reload: "รีโหลด"
|
||||||
@@ -338,9 +331,9 @@ tosUrl: "เงื่อนไขการให้บริการ URL"
|
|||||||
thisYear: "ปีนี้"
|
thisYear: "ปีนี้"
|
||||||
thisMonth: "เดือนนี้"
|
thisMonth: "เดือนนี้"
|
||||||
today: "วันนี้"
|
today: "วันนี้"
|
||||||
dayX: "{day}"
|
dayX: "{วัน}"
|
||||||
monthX: "เดือน {month}"
|
monthX: "{เดือน}"
|
||||||
yearX: "{year}"
|
yearX: "{ปี}"
|
||||||
pages: "หน้า"
|
pages: "หน้า"
|
||||||
integration: "รวบรวม"
|
integration: "รวบรวม"
|
||||||
connectService: "เชื่อมต่อ"
|
connectService: "เชื่อมต่อ"
|
||||||
@@ -1050,19 +1043,16 @@ preservedUsernamesDescription: "ลิสต์ชื่อผู้ใช้ท
|
|||||||
createNoteFromTheFile: "เรียบเรียงโน้ตจากไฟล์นี้"
|
createNoteFromTheFile: "เรียบเรียงโน้ตจากไฟล์นี้"
|
||||||
archive: "เก็บถาวร"
|
archive: "เก็บถาวร"
|
||||||
channelArchiveConfirmTitle: "เก็บถาวรจริงๆ {name} มั้ย?"
|
channelArchiveConfirmTitle: "เก็บถาวรจริงๆ {name} มั้ย?"
|
||||||
channelArchiveConfirmDescription: "ช่องที่ถูกเก็บถาวรแล้วนั้นจะไม่ปรากฏในรายการช่องหรือผลการค้นหานั้นอีกต่อไปไม่สามารถเพิ่มโพสต์ใหม่ได้อีกต่อไปนะ"
|
|
||||||
thisChannelArchived: "ช่องนี้ถูกเก็บถาวรแล้วนะ"
|
thisChannelArchived: "ช่องนี้ถูกเก็บถาวรแล้วนะ"
|
||||||
displayOfNote: "การแสดงโน้ต"
|
displayOfNote: "การแสดงโน้ต"
|
||||||
initialAccountSetting: "ตั้งค่าโปรไฟล์"
|
initialAccountSetting: "ตั้งค่าโปรไฟล์"
|
||||||
youFollowing: "ติดตามแล้ว"
|
youFollowing: "ติดตามแล้ว"
|
||||||
preventAiLearning: "ปฏิเสธการใช้งาน ในการเรียนรู้ของเครื่อง (Generative AI)"
|
preventAiLearning: "ปฏิเสธการใช้งาน ในการเรียนรู้ของเครื่อง (Generative AI)"
|
||||||
preventAiLearningDescription: "การส่งคำร้องขอโปรแกรมรวบรวมข้อมูลไม่ให้ใช้ข้อความที่โพสต์หรือรูปภาพ ฯลฯ ในชุดข้อมูลแมชชีนเลิร์นนิง (Predictive / Generative AI) สิ่งนี้นั้นทำได้โดยการเพิ่มแฟล็กการตอบสนอง \"noai\" HTML ให้กับเนื้อหาที่เกี่ยวข้อง แต่อย่างไรก็ตามแล้ว การป้องกันโดยสมบูรณ์นั้นไม่สามารถทำได้ผ่านแฟล็กนี้เนื่องจากอาจจะทำให้ถูกเพิกเฉยได้"
|
|
||||||
options: "ตัวเลือกบทบาท"
|
options: "ตัวเลือกบทบาท"
|
||||||
specifyUser: "ผู้ใช้เฉพาะ"
|
specifyUser: "ผู้ใช้เฉพาะ"
|
||||||
failedToPreviewUrl: "ไม่สามารถดูตัวอย่างได้"
|
failedToPreviewUrl: "ไม่สามารถดูตัวอย่างได้"
|
||||||
update: "อัปเดต"
|
update: "อัปเดต"
|
||||||
rolesThatCanBeUsedThisEmojiAsReaction: "บทบาทที่สามารถใช้อิโมจินี้เป็นรีแอคชั่นได้"
|
rolesThatCanBeUsedThisEmojiAsReaction: "บทบาทที่สามารถใช้อิโมจินี้เป็นรีแอคชั่นได้"
|
||||||
rolesThatCanBeUsedThisEmojiAsReactionEmptyDescription: "ถ้าหากไม่ได้ระบุบทบาท ทุกคนนั้นก็สามารถใช้อิโมจินี้เป็นการแสดงความรู้สึกได้นะ"
|
|
||||||
rolesThatCanBeUsedThisEmojiAsReactionPublicRoleWarn: "บทบาทเหล่านี้ต้องเป็นสาธารณะ"
|
rolesThatCanBeUsedThisEmojiAsReactionPublicRoleWarn: "บทบาทเหล่านี้ต้องเป็นสาธารณะ"
|
||||||
cancelReactionConfirm: "ต้องการลบรีแอคชั่นของคุณจริงๆหรอ?"
|
cancelReactionConfirm: "ต้องการลบรีแอคชั่นของคุณจริงๆหรอ?"
|
||||||
changeReactionConfirm: "ต้องการเปลี่ยนรีแอคชั่นของคุณจริงๆหรอ?"
|
changeReactionConfirm: "ต้องการเปลี่ยนรีแอคชั่นของคุณจริงๆหรอ?"
|
||||||
@@ -1074,26 +1064,6 @@ branding: "แบรนดิ้ง"
|
|||||||
enableServerMachineStats: "เผยแพร่สถานะฮาร์ดแวร์ของเซิร์ฟเวอร์"
|
enableServerMachineStats: "เผยแพร่สถานะฮาร์ดแวร์ของเซิร์ฟเวอร์"
|
||||||
enableIdenticonGeneration: "เปิดใช้งานผู้ใช้สร้างตัวระบุ"
|
enableIdenticonGeneration: "เปิดใช้งานผู้ใช้สร้างตัวระบุ"
|
||||||
turnOffToImprovePerformance: "การปิดส่วนนี้สามารถเพิ่มประสิทธิภาพได้"
|
turnOffToImprovePerformance: "การปิดส่วนนี้สามารถเพิ่มประสิทธิภาพได้"
|
||||||
createInviteCode: "สร้างคำเชิญ"
|
|
||||||
createWithOptions: "สร้างด้วยตัวเลือก"
|
|
||||||
createCount: "จำนวนการเชิญ"
|
|
||||||
inviteCodeCreated: "สร้างคำเชิญแล้ว"
|
|
||||||
inviteLimitExceeded: "คุณสร้างคำเชิญเกินถึงขีดจำกัดแล้วนะ"
|
|
||||||
createLimitRemaining: "ขีดจำกัดการเชิญ: {limit} ที่เหลืออยู่"
|
|
||||||
inviteLimitResetCycle: "ขีดจำกัดนี้จะถูกรีเซ็ตเป็น {limit} ที่ {time}."
|
|
||||||
expirationDate: "วันที่หมดอายุ"
|
|
||||||
noExpirationDate: "ไม่มีหมดอายุ"
|
|
||||||
inviteCodeUsedAt: "รหัสคำเชิญใช้แล้วที่"
|
|
||||||
registeredUserUsingInviteCode: "ใช้คำเชิญแล้วโดย"
|
|
||||||
waitingForMailAuth: "กำลังรอการยืนยันอีเมล"
|
|
||||||
inviteCodeCreator: "สร้างการเชิญแล้วโดย"
|
|
||||||
usedAt: "ใช้แล้วที่"
|
|
||||||
unused: "ไม่ใช้แล้ว"
|
|
||||||
used: "ใช้แล้ว"
|
|
||||||
expired: "หมดอายุแล้ว"
|
|
||||||
doYouAgree: "ยอมรับมั้ย?"
|
|
||||||
beSureToReadThisAsItIsImportant: "กรุณาอ่านข้อมูลที่สำคัญอันนี้"
|
|
||||||
iHaveReadXCarefullyAndAgree: "ฉันได้อ่านข้อความ \"{x}\" และยินยอม"
|
|
||||||
_initialAccountSetting:
|
_initialAccountSetting:
|
||||||
accountCreated: "คุณได้สร้างบัญชีของคุณสำเร็จเรียบร้อยแล้ว!"
|
accountCreated: "คุณได้สร้างบัญชีของคุณสำเร็จเรียบร้อยแล้ว!"
|
||||||
letsStartAccountSetup: "สำหรับผู้เริ่มต้นมาตั้งค่าโปรไฟล์ของคุณกันเถอะ"
|
letsStartAccountSetup: "สำหรับผู้เริ่มต้นมาตั้งค่าโปรไฟล์ของคุณกันเถอะ"
|
||||||
@@ -1101,12 +1071,8 @@ _initialAccountSetting:
|
|||||||
profileSetting: "ตั้งค่าโปรไฟล์"
|
profileSetting: "ตั้งค่าโปรไฟล์"
|
||||||
privacySetting: "ตั้งค่าความเป็นส่วนตัว"
|
privacySetting: "ตั้งค่าความเป็นส่วนตัว"
|
||||||
theseSettingsCanEditLater: "คุณสามารถเปลี่ยนการตั้งค่าเหล่านี้ได้ในภายหลังได้ตลอดเวลานะ"
|
theseSettingsCanEditLater: "คุณสามารถเปลี่ยนการตั้งค่าเหล่านี้ได้ในภายหลังได้ตลอดเวลานะ"
|
||||||
youCanEditMoreSettingsInSettingsPageLater: "ยังมีการตั้งค่าอื่นๆ อีกมากมายที่คุณนั้นสามารถกำหนดค่าได้จาก \"การตั้งค่า\" เพื่อให้แน่ใจว่าได้เยี่ยมชมมันได้ภายหลังนะ"
|
|
||||||
followUsers: "ลองติดตามผู้ใช้บางคนที่คุณอาจจะสนใจเพื่อสร้างไทม์ไลน์ของคุณสิ !"
|
|
||||||
pushNotificationDescription: "กำลังเปิดใช้งานการแจ้งเตือนแบบพุชจะช่วยให้คุณได้รับการแจ้งเตือนจาก {name} โดยตรงบนอุปกรณ์ของคุณนะ"
|
|
||||||
initialAccountSettingCompleted: "ตั้งค่าโปรไฟล์เสร็จสมบูรณ์แล้ว!"
|
initialAccountSettingCompleted: "ตั้งค่าโปรไฟล์เสร็จสมบูรณ์แล้ว!"
|
||||||
haveFun: "สนุกกับ {name}!"
|
haveFun: "สนุกกับ {name}!"
|
||||||
ifYouNeedLearnMore: "ถ้าหากคุณต้องการเรียนรู้เพิ่มเติมเกี่ยวกับวิธีใช้ {ชื่อ} (Misskey) กรุณาไปที่ {link}"
|
|
||||||
skipAreYouSure: "ต้องการข้ามการตั้งค่าโปรไฟล์จริงๆแบบนั้นหรอ?"
|
skipAreYouSure: "ต้องการข้ามการตั้งค่าโปรไฟล์จริงๆแบบนั้นหรอ?"
|
||||||
laterAreYouSure: "ต้องการตั้งค่าโปรไฟล์ในภายหลังจริงๆอย่างงั้นหรอ?"
|
laterAreYouSure: "ต้องการตั้งค่าโปรไฟล์ในภายหลังจริงๆอย่างงั้นหรอ?"
|
||||||
_serverRules:
|
_serverRules:
|
||||||
@@ -1404,9 +1370,6 @@ _role:
|
|||||||
ltlAvailable: "การดูไทม์ไลน์ในท้องถิ่น"
|
ltlAvailable: "การดูไทม์ไลน์ในท้องถิ่น"
|
||||||
canPublicNote: "สามารถส่งโน้ตสาธารณะ"
|
canPublicNote: "สามารถส่งโน้ตสาธารณะ"
|
||||||
canInvite: "สร้างรหัสเชิญอินสแตนซ์"
|
canInvite: "สร้างรหัสเชิญอินสแตนซ์"
|
||||||
inviteLimit: "จำกัดการเชิญ"
|
|
||||||
inviteLimitCycle: "จำกัดการเชิญไว้คูลดาวน์"
|
|
||||||
inviteExpirationTime: "วันหมดอายุของรหัสการเชิญ"
|
|
||||||
canManageCustomEmojis: "จัดการอีโมจิแบบกำหนดเอง"
|
canManageCustomEmojis: "จัดการอีโมจิแบบกำหนดเอง"
|
||||||
driveCapacity: "ความจุของไดรฟ์"
|
driveCapacity: "ความจุของไดรฟ์"
|
||||||
alwaysMarkNsfw: "ทำเครื่องหมายไฟล์ว่าเป็น NSFW เสมอ"
|
alwaysMarkNsfw: "ทำเครื่องหมายไฟล์ว่าเป็น NSFW เสมอ"
|
||||||
@@ -1521,10 +1484,6 @@ _aboutMisskey:
|
|||||||
donate: "บริจาคให้กับ Misskey"
|
donate: "บริจาคให้กับ Misskey"
|
||||||
morePatrons: "เราขอขอบคุณสำหรับความช่วยเหลือจากผู้ช่วยอื่นๆ ที่ไม่ได้ระบุไว้ที่นี่นะ ขอขอบคุณ! 🥰"
|
morePatrons: "เราขอขอบคุณสำหรับความช่วยเหลือจากผู้ช่วยอื่นๆ ที่ไม่ได้ระบุไว้ที่นี่นะ ขอขอบคุณ! 🥰"
|
||||||
patrons: "สมาชิกพันธมิตร"
|
patrons: "สมาชิกพันธมิตร"
|
||||||
_displayOfSensitiveMedia:
|
|
||||||
respect: "ซ่อนสื่อทำเครื่องหมายบอกว่าละเอียดอ่อน"
|
|
||||||
ignore: "แสดงผลสื่อทำเครื่องหมายบอกว่าละเอียดอ่อน"
|
|
||||||
force: "ซ่อนสื่อทั้งหมด"
|
|
||||||
_instanceTicker:
|
_instanceTicker:
|
||||||
none: "ไม่ต้องแสดง"
|
none: "ไม่ต้องแสดง"
|
||||||
remote: "แสดงสำหรับผู้ใช้ระยะไกล"
|
remote: "แสดงสำหรับผู้ใช้ระยะไกล"
|
||||||
@@ -1664,8 +1623,6 @@ _time:
|
|||||||
day: "วัน"
|
day: "วัน"
|
||||||
_timelineTutorial:
|
_timelineTutorial:
|
||||||
title: "วิธีใช้งาน Misskey"
|
title: "วิธีใช้งาน Misskey"
|
||||||
step1_1: "นี่คือ \"ไทม์ไลน์\" \"โน้ต\" ทั้งหมดที่ส่งใน {name} จะแสดงรายการตามลำดับเวลาที่นี่นะ"
|
|
||||||
step1_2: "อาจจะมีไทม์ไลน์ที่แตกต่างกันเล็กน้อยยกตัวอย่างเช่น \"ไทม์ไลน์หน้าแรก\" จะมีโน้ตของผู้ใช้ที่คุณติดตามและ \"ไทม์ไลน์ท้องถิ่น\" จะมีโน้ตจากผู้ใช้ทั้งหมดของ {name}"
|
|
||||||
step2_1: "มาลองโพสต์โน้ตต่อไปกัน คุณสามารถทำได้โดยการกดปุ่มที่มีไอคอนดินสอ"
|
step2_1: "มาลองโพสต์โน้ตต่อไปกัน คุณสามารถทำได้โดยการกดปุ่มที่มีไอคอนดินสอ"
|
||||||
step2_2: "ยังไงไหนลองเขียนแนะนำตัวเองหรือแค่ \"สวัสดี {name}!\" ถ้าคุณไม่รู้สึกเหมือนมัน?"
|
step2_2: "ยังไงไหนลองเขียนแนะนำตัวเองหรือแค่ \"สวัสดี {name}!\" ถ้าคุณไม่รู้สึกเหมือนมัน?"
|
||||||
step3_1: "เสร็จสิ้นการโพสต์โน้ตย่อแรกของคุณแล้วอย่างงั้นหรอ?"
|
step3_1: "เสร็จสิ้นการโพสต์โน้ตย่อแรกของคุณแล้วอย่างงั้นหรอ?"
|
||||||
@@ -1999,7 +1956,6 @@ _deck:
|
|||||||
introduction: "สร้างอินเทอร์เฟซที่สมบูรณ์แบบสำหรับคุณโดยจัดเรียงคอลัมน์ได้อย่างอิสระ!"
|
introduction: "สร้างอินเทอร์เฟซที่สมบูรณ์แบบสำหรับคุณโดยจัดเรียงคอลัมน์ได้อย่างอิสระ!"
|
||||||
introduction2: "คลิกที่เครื่องหมาย + ทางขวาของหน้าจอเพื่อเพิ่มคอลัมน์ใหม่ทุกครั้งที่คุณต้องการ"
|
introduction2: "คลิกที่เครื่องหมาย + ทางขวาของหน้าจอเพื่อเพิ่มคอลัมน์ใหม่ทุกครั้งที่คุณต้องการ"
|
||||||
widgetsIntroduction: "กรุณาเลือก \"แก้ไขวิดเจ็ต\" ในเมนูคอลัมน์และเพิ่มวิดเจ็ต"
|
widgetsIntroduction: "กรุณาเลือก \"แก้ไขวิดเจ็ต\" ในเมนูคอลัมน์และเพิ่มวิดเจ็ต"
|
||||||
useSimpleUiForNonRootPages: "แสดง UI ของ Root Page อย่างง่าย "
|
|
||||||
_columns:
|
_columns:
|
||||||
main: "หลัก"
|
main: "หลัก"
|
||||||
widgets: "วิดเจ็ต"
|
widgets: "วิดเจ็ต"
|
||||||
|
@@ -1,6 +1,5 @@
|
|||||||
---
|
---
|
||||||
_lang_: "Türkçe"
|
_lang_: "Türkçe"
|
||||||
headlineMisskey: "Notlarla bağlanmış bir ağ"
|
|
||||||
introMisskey: "Açık kaynaklı bir dağıtılmış mikroblog hizmeti olan Misskey'e hoş geldiniz.\nMisskey, neler olup bittiğini paylaşmak ve herkese sizden bahsetmek için \"notlar\" oluşturmanıza olanak tanıyan, açık kaynaklı, dağıtılmış bir mikroblog hizmetidir.\nHerkesin notlarına kendi tepkilerinizi hızlıca eklemek için \"Tepkiler\" özelliğini de kullanabilirsiniz👍.\nYeni bir dünyayı keşfedin🚀."
|
introMisskey: "Açık kaynaklı bir dağıtılmış mikroblog hizmeti olan Misskey'e hoş geldiniz.\nMisskey, neler olup bittiğini paylaşmak ve herkese sizden bahsetmek için \"notlar\" oluşturmanıza olanak tanıyan, açık kaynaklı, dağıtılmış bir mikroblog hizmetidir.\nHerkesin notlarına kendi tepkilerinizi hızlıca eklemek için \"Tepkiler\" özelliğini de kullanabilirsiniz👍.\nYeni bir dünyayı keşfedin🚀."
|
||||||
poweredByMisskeyDescription: "name}Açık kaynak bir platform\n<b>Misskey</b>Dünya'nın en sunucularında biri。"
|
poweredByMisskeyDescription: "name}Açık kaynak bir platform\n<b>Misskey</b>Dünya'nın en sunucularında biri。"
|
||||||
monthAndDay: "{month}Ay {day}Gün"
|
monthAndDay: "{month}Ay {day}Gün"
|
||||||
@@ -12,9 +11,7 @@ forgotPassword: "şifremi unuttum"
|
|||||||
ok: "TAMAM"
|
ok: "TAMAM"
|
||||||
gotIt: "Anladım"
|
gotIt: "Anladım"
|
||||||
cancel: "İptal"
|
cancel: "İptal"
|
||||||
noThankYou: "Hayır, teşekkürler"
|
|
||||||
enterUsername: "Kullanıcı adınızı giriniz"
|
enterUsername: "Kullanıcı adınızı giriniz"
|
||||||
renotedBy: "{user} tarafından Renotelandı"
|
|
||||||
noNotes: "Notlar mevcut değil."
|
noNotes: "Notlar mevcut değil."
|
||||||
noNotifications: "Bildirim bulunmuyor"
|
noNotifications: "Bildirim bulunmuyor"
|
||||||
instance: "Sunucu"
|
instance: "Sunucu"
|
||||||
@@ -48,35 +45,15 @@ delete: "Sil"
|
|||||||
deleteAndEdit: "Sil ve yeniden düzenle"
|
deleteAndEdit: "Sil ve yeniden düzenle"
|
||||||
deleteAndEditConfirm: "Bu notu silip yeniden düzenlemek istiyor musunuz? Bu nota ilişkin tüm Tepkiler, Yeniden Notlar ve Yanıtlar da silinecektir."
|
deleteAndEditConfirm: "Bu notu silip yeniden düzenlemek istiyor musunuz? Bu nota ilişkin tüm Tepkiler, Yeniden Notlar ve Yanıtlar da silinecektir."
|
||||||
addToList: "Listeye ekle"
|
addToList: "Listeye ekle"
|
||||||
addToAntenna: "Antene ekle"
|
|
||||||
sendMessage: "Mesaj Gönder"
|
sendMessage: "Mesaj Gönder"
|
||||||
copyRSS: "RSSKopyala"
|
copyRSS: "RSSKopyala"
|
||||||
copyUsername: "Kullanıcı Adını Kopyala"
|
copyUsername: "Kullanıcı Adını Kopyala"
|
||||||
copyUserId: "KullanıcıyıKopyala"
|
copyUserId: "KullanıcıyıKopyala"
|
||||||
copyNoteId: "Kimlik notunu kopyala"
|
copyNoteId: "Kimlik notunu kopyala"
|
||||||
copyFileId: "Dosya ID'sini kopyala"
|
|
||||||
copyFolderId: "Klasör ID'sini kopyala"
|
|
||||||
copyProfileUrl: "Profil URL'sini kopyala"
|
|
||||||
searchUser: "Kullanıcıları ara"
|
searchUser: "Kullanıcıları ara"
|
||||||
reply: "yanıt"
|
reply: "yanıt"
|
||||||
loadMore: "Devamını yükle"
|
loadMore: "Devamını yükle"
|
||||||
showMore: "Devamını yükle"
|
showMore: "Devamını yükle"
|
||||||
showLess: "Kapat"
|
|
||||||
youGotNewFollower: "seni takip etti"
|
|
||||||
receiveFollowRequest: "Takip isteği alındı"
|
|
||||||
followRequestAccepted: "Takip isteği kabul edildi"
|
|
||||||
mention: "Bahset"
|
|
||||||
mentions: "Bahsetmeler"
|
|
||||||
directNotes: "Kişisel mesajlar"
|
|
||||||
importAndExport: "İçeri/Dışarı aktar"
|
|
||||||
import: "İçeri aktar"
|
|
||||||
export: "Dışa aktar"
|
|
||||||
files: "Dosyalar"
|
|
||||||
download: "İndir"
|
|
||||||
driveFileDeleteConfirm: "\"{name}\" dosyası silinsin mi? Dosya kullanıldığı tüm notlardan kaybolacaktır."
|
|
||||||
unfollowConfirm: "{name} takipten çıkarılsın mı?"
|
|
||||||
exportRequested: "Dışa aktarım talep ettiniz. Bu biraz zaman alabilir. İşlem bitince Sürücünüze eklenecektir."
|
|
||||||
importRequested: "Dışa aktarım talep ettiniz. Bu işlem biraz zaman alabilir."
|
|
||||||
lists: "Listeler"
|
lists: "Listeler"
|
||||||
noLists: "Liste yok"
|
noLists: "Liste yok"
|
||||||
note: "not"
|
note: "not"
|
||||||
@@ -87,16 +64,6 @@ followsYou: "seni takip ediyor"
|
|||||||
createList: "Liste oluştur"
|
createList: "Liste oluştur"
|
||||||
manageLists: "Yönetici Listeleri"
|
manageLists: "Yönetici Listeleri"
|
||||||
error: "hata"
|
error: "hata"
|
||||||
somethingHappened: "Bir hata oluştu"
|
|
||||||
retry: "Tekrar dene"
|
|
||||||
pageLoadError: "Sayfa yüklenemedi."
|
|
||||||
pageLoadErrorDescription: "Bu genelde ağ veya tarayıcı ön belleği hatalarından olur. Lütfen ön belleği temizlemeyi veya birkaç dakika beklemeyi ve sayfayı yenilemeyi deneyin."
|
|
||||||
serverIsDead: "Sunucu yanıt vermiyor. Birkaç dakika sonra tekrar deneyin."
|
|
||||||
youShouldUpgradeClient: "Sayfayı görüntülemek için yenileyin."
|
|
||||||
enterListName: "Liste ismi"
|
|
||||||
privacy: "Gizlilik"
|
|
||||||
makeFollowManuallyApprove: "Takip istekleri elle onaylansın"
|
|
||||||
defaultNoteVisibility: "Varsayılan görünürlük"
|
|
||||||
follow: "takipçi"
|
follow: "takipçi"
|
||||||
followRequest: "Takip isteği"
|
followRequest: "Takip isteği"
|
||||||
followRequests: "Takip istekleri"
|
followRequests: "Takip istekleri"
|
||||||
@@ -109,24 +76,9 @@ renoted: "yeniden adlandırılmış"
|
|||||||
cantRenote: "Ayrılamama"
|
cantRenote: "Ayrılamama"
|
||||||
cantReRenote: "not alabilirmiyim"
|
cantReRenote: "not alabilirmiyim"
|
||||||
quote: "alıntı"
|
quote: "alıntı"
|
||||||
inChannelRenote: "Kanal içi Renote"
|
|
||||||
inChannelQuote: "Kanal içi Alıntı"
|
|
||||||
pinnedNote: "Sabitlenen"
|
pinnedNote: "Sabitlenen"
|
||||||
pinned: "Sabitlenmiş"
|
pinned: "Sabitlenmiş"
|
||||||
you: "sen"
|
you: "sen"
|
||||||
clickToShow: "Görüntülemek için tıkla"
|
|
||||||
sensitive: "Hassas içerik"
|
|
||||||
add: "Ekle"
|
|
||||||
reaction: "Tepkiler"
|
|
||||||
reactions: "Tepkiler"
|
|
||||||
reactionSetting: "Palette görünecek tepkiler"
|
|
||||||
reactionSettingDescription2: "Sıralamak için sürükleyin, silmek için tıklayın, eklemek için \"+\" tuşuna tıklayın."
|
|
||||||
rememberNoteVisibility: "Görünürlük ayarlarını hatırla"
|
|
||||||
attachCancel: "Eki sil"
|
|
||||||
markAsSensitive: "Hassas içerik olarak işaretle"
|
|
||||||
unmarkAsSensitive: "Hassas içerik işaretini kaldır"
|
|
||||||
enterFileName: "Dosya ismini gir"
|
|
||||||
mute: "Gizle"
|
|
||||||
unmute: "sesi aç"
|
unmute: "sesi aç"
|
||||||
renoteMute: "sesi kapat"
|
renoteMute: "sesi kapat"
|
||||||
renoteUnmute: "sesi açmayı iptal et"
|
renoteUnmute: "sesi açmayı iptal et"
|
||||||
@@ -136,280 +88,46 @@ suspend: "askıya al"
|
|||||||
unsuspend: "askıya alma"
|
unsuspend: "askıya alma"
|
||||||
blockConfirm: "Onayı engelle"
|
blockConfirm: "Onayı engelle"
|
||||||
unblockConfirm: "engellemeyi kaldır onayla"
|
unblockConfirm: "engellemeyi kaldır onayla"
|
||||||
suspendConfirm: "Hesap askıya alınsın mı?"
|
|
||||||
unsuspendConfirm: "Hesap askıdan kaldırılsın mı"
|
|
||||||
selectList: "Bir liste seç"
|
|
||||||
editList: "Listeyi düzenle"
|
|
||||||
selectChannel: "Kanal seç"
|
selectChannel: "Kanal seç"
|
||||||
selectAntenna: "Bir anten seç"
|
|
||||||
editAntenna: "Anteni düzenle"
|
|
||||||
selectWidget: "Araç seç"
|
|
||||||
editWidgets: "Araçları düzenle"
|
|
||||||
editWidgetsExit: "Tamam"
|
|
||||||
customEmojis: "Özel Emoji"
|
|
||||||
emoji: "Emoji"
|
|
||||||
emojis: "Emoji"
|
|
||||||
emojiName: "Emoji adı"
|
|
||||||
emojiUrl: "Emoji URL'si"
|
|
||||||
addEmoji: "Emoji ekle"
|
|
||||||
settingGuide: "Önerilen ayarlar"
|
|
||||||
cacheRemoteFiles: "Uzak dosyalar ön belleğe alınsın"
|
|
||||||
cacheRemoteFilesDescription: "Bu ayar açık olduğunda diğer sitelerin dosyaları doğrudan uzak sunucudan yüklenecektir. Bu ayarı kapatmak depolama kullanımını azaltacak ama küçük resimler oluşturulmadığından trafiği arttıracaktır."
|
|
||||||
cacheRemoteSensitiveFiles: "Hassas uzak dosyalar ön belleğe alınsın"
|
|
||||||
cacheRemoteSensitiveFilesDescription: "Bu ayar kapalı olduğunda hassas uzak dosyalar ön belleğe alınmadan doğrudan uzak sunucudan yüklenecektir."
|
|
||||||
flagAsBot: "Bot olarak işaretle"
|
flagAsBot: "Bot olarak işaretle"
|
||||||
flagAsBotDescription: "Bu seçeneği hesap bir program tarafından kontrol ediliyorsa işaretleyin. Bu, diğer geliştiricilerin sonsuz etkileşim zincirleri oluşturmasını engellemeye yardımcı olur ve Misskey'in iç sisteminin hesaba bir bot gibi davranmasını sağlar."
|
|
||||||
flagAsCat: "Kedi hesabı"
|
|
||||||
flagAsCatDescription: "Kedi hesabı"
|
|
||||||
flagShowTimelineReplies: "Zaman akışında notlara gelen cevapları göster"
|
|
||||||
flagShowTimelineRepliesDescription: "Açık olduğu durumda, zaman akışında kullanıcıların başkalarına verdiği cevaplar gözükür."
|
|
||||||
autoAcceptFollowed: "Takip edilen hesapların takip isteklerini kabul et"
|
|
||||||
addAccount: "Hesap ekle"
|
|
||||||
reloadAccountsList: "Hesap listesini güncelle"
|
|
||||||
loginFailed: "Giriş başarısız oldu"
|
|
||||||
showOnRemote: "Uzak sunucuda görüntüle"
|
|
||||||
general: "Genel"
|
|
||||||
wallpaper: "Duvar kağıdı"
|
|
||||||
setWallpaper: "Duvar kağıdını ayarla"
|
|
||||||
removeWallpaper: "Duvar kağıdını sil"
|
|
||||||
searchWith: "Arama: {q}"
|
|
||||||
youHaveNoLists: "Hiç listeniz yok"
|
|
||||||
followConfirm: "{name} takip edilsin mi?"
|
|
||||||
proxyAccount: "Vekil hesabı"
|
|
||||||
proxyAccountDescription: "Proxy hesabı, belirli koşullar altında kullanıcılar için uzaktan takipçi işlevi gören bir hesaptır. Örneğin, bir kullanıcı listeye bir uzak kullanıcı eklediğinde, o kullanıcıyı takip eden yerel bir kullanıcı yoksa uzak kullanıcının etkinliği örneğe teslim edilmeyecektir, dolayısıyla bunun yerine proxy hesabı takip edilecektir."
|
|
||||||
host: "Sağlayıcı"
|
|
||||||
selectUser: "Kullanıcı seç"
|
|
||||||
recipient: "Kime"
|
|
||||||
annotation: "Açıklamalar"
|
|
||||||
federation: "Federasyon"
|
|
||||||
instances: "Sunucu"
|
instances: "Sunucu"
|
||||||
registeredAt: "Katılma tarihi"
|
|
||||||
latestRequestReceivedAt: "Alınan son talep"
|
|
||||||
latestStatus: "En son durum"
|
|
||||||
storageUsage: "Depolama kullanımı"
|
|
||||||
charts: "Çizelgeler"
|
|
||||||
perHour: "Saatlik"
|
|
||||||
perDay: "Günlük"
|
|
||||||
stopActivityDelivery: "Durum güncellemelerini gönderme"
|
|
||||||
blockThisInstance: "Bu sunucuyu engelle"
|
|
||||||
operations: "İşlemler"
|
|
||||||
software: "Yazılımlar"
|
|
||||||
version: "Sürüm"
|
|
||||||
metadata: "Meta Verileri"
|
|
||||||
withNFiles: "{n} tane dosya"
|
|
||||||
monitor: "Monitör"
|
|
||||||
jobQueue: "İşlem sırası"
|
|
||||||
cpuAndMemory: "İşlemci ve Hafıza"
|
|
||||||
network: "Ağ"
|
|
||||||
disk: "Disk"
|
|
||||||
instanceInfo: "Sunucu Bilgisi"
|
|
||||||
statistics: "İstatistikler"
|
|
||||||
clearQueue: "Sırayı temizle"
|
|
||||||
clearQueueConfirmTitle: "Sıra silinsin mi?"
|
|
||||||
clearQueueConfirmText: "Sırada kalan hiçbir şey iletilmeyecek. Genelde bu işlem gerekli değildir."
|
|
||||||
clearCachedFiles: "Ön belleği temizle"
|
|
||||||
clearCachedFilesConfirm: "Ön belleğe alınmış tüm uzak sunucu dosyaları silinsin mi?"
|
|
||||||
blockedInstances: "Engellenen sunucular"
|
|
||||||
blockedInstancesDescription: "Engellemek istediğiniz sunucuların alan adlarını satır sonlarıyla ayırarak yazın. Yazılan sunucular bu sunucuyla iletişime geçemeyecek."
|
|
||||||
muteAndBlock: "Susturma ve Engelleme"
|
|
||||||
mutedUsers: "Susturulan kullanıcılar"
|
|
||||||
blockedUsers: "Engellenen kullanıcılar"
|
|
||||||
noUsers: "Kullanıcı yok"
|
|
||||||
editProfile: "Profili düzenle"
|
|
||||||
noteDeleteConfirm: "Bu notu silmek istediğinizden emin misiniz?"
|
|
||||||
pinLimitExceeded: "Daha fazla not sabitlenemez"
|
|
||||||
intro: "Misskey yüklemesi tamamlandı! Lütfen yönetici hesabını oluşturun."
|
|
||||||
done: "Tamamlandı"
|
|
||||||
preview: "Önizleme"
|
|
||||||
default: "Varsayılan"
|
|
||||||
defaultValueIs: "Varsayılan: {value}"
|
|
||||||
noCustomEmojis: "Emoji bulunamadı"
|
|
||||||
noJobs: "Hiç işlem yok"
|
|
||||||
federating: "Federe ediliyor"
|
|
||||||
blocked: "Engellenmiş"
|
|
||||||
suspended: "Askıya alınmış"
|
|
||||||
all: "Tümü"
|
|
||||||
subscribing: "Abonelik"
|
|
||||||
publishing: "Paylaşım"
|
|
||||||
notResponding: "Cevap yok"
|
|
||||||
instanceFollowing: "Sunucuda takip edenler"
|
|
||||||
instanceFollowers: "Sunucu takipçileri"
|
|
||||||
instanceUsers: "Sunucu kullanıcıları"
|
|
||||||
changePassword: "Şifreyi değiştir"
|
|
||||||
security: "Güvenlik"
|
|
||||||
retypedNotMatch: "Girişler uyuşmuyor."
|
|
||||||
currentPassword: "Geçerli şifre"
|
|
||||||
newPassword: "Yeni şifre"
|
|
||||||
newPasswordRetype: "Yeni şifre (tekrar)"
|
|
||||||
attachFile: "Dosya ekle"
|
|
||||||
more: "Daha!"
|
|
||||||
featured: "Öne Çıkan"
|
|
||||||
usernameOrUserId: "Kullanıcı adı veya ID'si"
|
|
||||||
noSuchUser: "Kullanıcı bulunamadı"
|
|
||||||
lookup: "Sorgu"
|
|
||||||
announcements: "Duyurular"
|
|
||||||
imageUrl: "Görsel URL'si"
|
|
||||||
remove: "Sil"
|
remove: "Sil"
|
||||||
removed: "Silindi"
|
|
||||||
removeAreYouSure: "\"{x}\" silmek istediğinizden emin misiniz?"
|
|
||||||
deleteAreYouSure: "\"{x}\" silmek istediğinizden emin misiniz?"
|
|
||||||
resetAreYouSure: "Sıfırlansın mı?"
|
|
||||||
saved: "Kaydedildi"
|
|
||||||
messaging: "Mesajlar"
|
|
||||||
upload: "Yükle"
|
|
||||||
keepOriginalUploading: "Orijinal görseli koru"
|
|
||||||
keepOriginalUploadingDescription: "Orijinal olarak yüklenen görüntüyü olduğu gibi kaydeder. Kapatılırsa, yükleme sırasında web'de görüntülenecek bir sürüm oluşturulur."
|
|
||||||
fromUrl: "Bağlantıdan"
|
|
||||||
uploadFromUrl: "Bağlantıdan yükle"
|
|
||||||
uploadFromUrlDescription: "Yüklemek istediğiniz dosyanın bağlantısı"
|
|
||||||
uploadFromUrlRequested: "Yükleme talep edildi"
|
|
||||||
uploadFromUrlMayTakeTime: "Yüklemenin tamamlanması biraz süre alabilir."
|
|
||||||
explore: "Keşfet"
|
|
||||||
messageRead: "Okundu"
|
|
||||||
noMoreHistory: "Bundan öncesi yok"
|
|
||||||
startMessaging: "Yeni bir sohbet başlat"
|
|
||||||
nUsersRead: "{n} kişi okudu"
|
|
||||||
agreeTo: "Kabul Ediyorum: {0}"
|
|
||||||
agree: "Kabul Et"
|
|
||||||
agreeBelow: "Aşağıdakileri kabul ederim"
|
|
||||||
basicNotesBeforeCreateAccount: "Önemli notlar"
|
|
||||||
termsOfService: "Şartlar ve Koşullar"
|
|
||||||
start: "Başla"
|
|
||||||
home: "Ana sayfa"
|
|
||||||
remoteUserCaution: "Bu kullanıcı bir uzak sunucudan olduğu için alınan bilgiler tam olmayabilir."
|
|
||||||
activity: "Etkinlik"
|
|
||||||
images: "Görseller"
|
|
||||||
image: "Görseller"
|
|
||||||
birthday: "Doğum günü"
|
|
||||||
yearsOld: "{age} yaşında"
|
|
||||||
registeredDate: "Kayıt tarihi"
|
|
||||||
location: "Konum"
|
|
||||||
theme: "Temalar"
|
|
||||||
themeForLightMode: "Aydınlık Tema"
|
|
||||||
themeForDarkMode: "Karanlık Tema"
|
|
||||||
light: "Aydınlık"
|
|
||||||
dark: "Karanlık"
|
|
||||||
lightThemes: "Aydınlık Temalar"
|
|
||||||
darkThemes: "Karanlık Temalar"
|
|
||||||
syncDeviceDarkMode: "Sistem Koyu Modu ile senkronize et"
|
|
||||||
drive: "Sürücü"
|
|
||||||
fileName: "Dosya adı"
|
|
||||||
selectFile: "Dosya seç"
|
|
||||||
selectFiles: "Dosya seç"
|
|
||||||
selectFolder: "Klasör seç"
|
|
||||||
selectFolders: "Klasör seç"
|
|
||||||
renameFile: "Dosyayı yeniden adlandır"
|
|
||||||
folderName: "Klasör adı"
|
|
||||||
createFolder: "Klasör oluştur"
|
|
||||||
renameFolder: "Klasörü Yeniden Adlandır"
|
|
||||||
deleteFolder: "Klasörü sil"
|
|
||||||
addFile: "Dosya ekle"
|
|
||||||
emptyDrive: "Sürücü boş"
|
|
||||||
hasChildFilesOrFolders: "Klasör boş olmadığından silinemiyor"
|
|
||||||
doNothing: "Bir şey yapma"
|
|
||||||
reloadConfirm: "Zaman akışı yenilensin mi?"
|
|
||||||
maintainerName: "Yönetici ismi"
|
|
||||||
monthX: "{month} ay"
|
|
||||||
enableRegistration: "Kayıtlara izin ver"
|
|
||||||
pinnedNotes: "Sabitlenen"
|
pinnedNotes: "Sabitlenen"
|
||||||
manageAntennas: "Anten ayarları"
|
|
||||||
userList: "Listeler"
|
userList: "Listeler"
|
||||||
resetPassword: "Şifre sıfırlama"
|
|
||||||
noMessagesYet: "Şimdilik mesaj yok"
|
|
||||||
details: "Detaylar"
|
|
||||||
deck: "Güverte"
|
|
||||||
smtpHost: "Sağlayıcı"
|
|
||||||
smtpUser: "Kullanıcı Adı"
|
smtpUser: "Kullanıcı Adı"
|
||||||
smtpPass: "Şifre"
|
smtpPass: "Şifre"
|
||||||
notificationSetting: "Bildirim ayarları"
|
|
||||||
noCrawleDescription: "Arama motorlarından profilinde, notlarında, sayfalarında vb. dolaşılmamasını ve dizine eklememesini talep et."
|
|
||||||
clearCache: "Ön belleği temizle"
|
|
||||||
onlineUsersCount: "{n} kullanıcı çevrim içi"
|
|
||||||
user: "Kullanıcı"
|
user: "Kullanıcı"
|
||||||
global: "Küresel"
|
|
||||||
squareAvatars: "Kare avatarlar"
|
|
||||||
searchByGoogle: "Arama"
|
searchByGoogle: "Arama"
|
||||||
file: "Dosyalar"
|
|
||||||
pushNotification: "Push bildirimleri"
|
|
||||||
subscribePushNotification: "Push bildirimlerini etkinleştir"
|
|
||||||
unsubscribePushNotification: "Push bildirimlerini kapat"
|
|
||||||
pushNotificationAlreadySubscribed: "Push bildirimleri zaten açık"
|
|
||||||
pushNotificationNotSupported: "Push bildirimleri sunucu veya tarayıcı tarafından desteklenmiyor"
|
|
||||||
noRole: "Rol bulunamadı"
|
|
||||||
color: "Renk"
|
|
||||||
addMemo: "Kısa not ekle"
|
|
||||||
_accountDelete:
|
|
||||||
started: "Silme işlemi başlatıldı"
|
|
||||||
_email:
|
|
||||||
_follow:
|
|
||||||
title: "seni takip etti"
|
|
||||||
_theme:
|
_theme:
|
||||||
color: "Renk"
|
|
||||||
keys:
|
keys:
|
||||||
mention: "Bahset"
|
|
||||||
renote: "vazgeçme"
|
renote: "vazgeçme"
|
||||||
_sfx:
|
_sfx:
|
||||||
note: "notlar"
|
note: "notlar"
|
||||||
notification: "Bildirim"
|
notification: "Bildirim"
|
||||||
chat: "Mesajlar"
|
|
||||||
_2fa:
|
|
||||||
renewTOTPCancel: "Hayır, teşekkürler"
|
|
||||||
_permissions:
|
|
||||||
"read:blocks": "Engellenen hesapları gör"
|
|
||||||
"write:blocks": "Engellenen hesap listesini düzenle"
|
|
||||||
_widgets:
|
_widgets:
|
||||||
profile: "Profil"
|
profile: "Profil"
|
||||||
instanceInfo: "Sunucu Bilgisi"
|
|
||||||
notifications: "Bildirim"
|
notifications: "Bildirim"
|
||||||
timeline: "Zaman çizelgesi"
|
timeline: "Zaman çizelgesi"
|
||||||
calendar: "Takvim"
|
|
||||||
clock: "Saat"
|
|
||||||
activity: "Etkinlik"
|
|
||||||
federation: "Federasyon"
|
|
||||||
jobQueue: "İşlem sırası"
|
|
||||||
_userList:
|
|
||||||
chooseList: "Bir liste seç"
|
|
||||||
_cw:
|
_cw:
|
||||||
show: "Devamını yükle"
|
show: "Devamını yükle"
|
||||||
_poll:
|
|
||||||
vote: "Oy kullan"
|
|
||||||
_visibility:
|
_visibility:
|
||||||
publicDescription: "Herkese açık"
|
|
||||||
home: "Ana sayfa"
|
|
||||||
followers: "takipçi"
|
followers: "takipçi"
|
||||||
_profile:
|
_profile:
|
||||||
username: "Kullanıcı Adı"
|
username: "Kullanıcı Adı"
|
||||||
_exportOrImport:
|
_exportOrImport:
|
||||||
followingList: "takipçi"
|
followingList: "takipçi"
|
||||||
muteList: "Gizle"
|
|
||||||
blockingList: "engelle"
|
blockingList: "engelle"
|
||||||
userLists: "Listeler"
|
userLists: "Listeler"
|
||||||
_charts:
|
|
||||||
federation: "Federasyon"
|
|
||||||
_timelines:
|
|
||||||
home: "Ana sayfa"
|
|
||||||
global: "Küresel"
|
|
||||||
_pages:
|
|
||||||
blocks:
|
|
||||||
image: "Görseller"
|
|
||||||
_notification:
|
_notification:
|
||||||
youWereFollowed: "seni takip etti"
|
|
||||||
unreadAntennaNote: "{name} anteni"
|
|
||||||
_types:
|
_types:
|
||||||
follow: "takipçi"
|
follow: "takipçi"
|
||||||
mention: "Bahset"
|
|
||||||
renote: "vazgeçme"
|
renote: "vazgeçme"
|
||||||
quote: "alıntı"
|
quote: "alıntı"
|
||||||
reaction: "Tepkiler"
|
|
||||||
receiveFollowRequest: "Takip isteği alındı"
|
|
||||||
followRequestAccepted: "Takip isteği kabul edildi"
|
|
||||||
_actions:
|
_actions:
|
||||||
reply: "yanıt"
|
reply: "yanıt"
|
||||||
renote: "vazgeçme"
|
renote: "vazgeçme"
|
||||||
_deck:
|
_deck:
|
||||||
configureColumn: "Sütun seçenekleri"
|
|
||||||
_columns:
|
_columns:
|
||||||
notifications: "Bildirim"
|
notifications: "Bildirim"
|
||||||
tl: "Zaman çizelgesi"
|
tl: "Zaman çizelgesi"
|
||||||
list: "Listeler"
|
list: "Listeler"
|
||||||
mentions: "Bahsetmeler"
|
|
||||||
|
@@ -1,634 +0,0 @@
|
|||||||
---
|
|
||||||
_lang_: "O'zbek tili "
|
|
||||||
headlineMisskey: "Qaydlar bilan bog'langan tarmoq"
|
|
||||||
introMisskey: "Xush kelibsiz! Misskey ochiq kodli, markazlashmagan mikroblogging xizmati.\nO'zingizni fikrlaringizni atrofingizdagilar bilan ulashish uchun \"Qaydlar\" yarating. 📡\nUstiga-ustak, \"Reaktsiyalar\" yordamida siz boshqalarning xatlari haqidagi o'zingizni xissiyotlaringizni tez ravishda bildiring. 👍\nQani, yangi dunyoni kashf qilaylik! 🚀"
|
|
||||||
poweredByMisskeyDescription: "{name} ochiq manbali <b>Misskey</b>(\"Misskey instance\" deb ataladi) platformasi tomonidan qurilgan servislardan biri. "
|
|
||||||
monthAndDay: "{day}/{month}"
|
|
||||||
search: "Izlash"
|
|
||||||
notifications: "Xabarnomalar"
|
|
||||||
username: "Foydalanuvchi nomi"
|
|
||||||
password: "Parol"
|
|
||||||
forgotPassword: "Parolni unutib qo'ydim"
|
|
||||||
fetchingAsApObject: "Fediversedan olib kelinmoqda..."
|
|
||||||
ok: "Ho'p"
|
|
||||||
gotIt: "Tushunarli!"
|
|
||||||
cancel: "Bekor qilish"
|
|
||||||
noThankYou: "Hozir emas"
|
|
||||||
enterUsername: "Foydalanuvchini nomini kiriting"
|
|
||||||
renotedBy: "{user} tomonidan qayta qayd etildi"
|
|
||||||
noNotes: "Qaydlar mavjud emas"
|
|
||||||
noNotifications: "Xabarnomalar mavjud emas"
|
|
||||||
instance: "Server"
|
|
||||||
settings: "Sozalamalar"
|
|
||||||
notificationSettings: "Xabarnomalar sozlamalari"
|
|
||||||
basicSettings: "Asosiy sozlamalar"
|
|
||||||
otherSettings: "Qo‘shimcha sozlamalar"
|
|
||||||
openInWindow: "Yangi oynada ochish"
|
|
||||||
profile: "Profil"
|
|
||||||
timeline: "Xronologiya"
|
|
||||||
noAccountDescription: "Ushbu foydalanuvchi hali o'zi haqida ma'lumot yozmagan."
|
|
||||||
login: "Kirish"
|
|
||||||
loggingIn: "Kirilmoqda"
|
|
||||||
logout: "Chiqish"
|
|
||||||
signup: "Ro'yxatdan o'tish"
|
|
||||||
uploading: "Yuklanmoqda..."
|
|
||||||
save: "Saqlash"
|
|
||||||
users: "Foydalanuvchilar"
|
|
||||||
addUser: "Foydalanuvchi qo'shish"
|
|
||||||
favorite: "Sevimli"
|
|
||||||
favorites: "Sevimli"
|
|
||||||
unfavorite: "Sevimlidan chiqarish"
|
|
||||||
favorited: "sevimli"
|
|
||||||
alreadyFavorited: "allaqachon sevimlilar orasida"
|
|
||||||
cantFavorite: "sevimlilarga qo'shib bo'lmadi"
|
|
||||||
pin: "Profilga qadab qo'yish"
|
|
||||||
unpin: "Profildan olib tashlash"
|
|
||||||
copyContent: "Tarkibini nusxalash"
|
|
||||||
copyLink: "Havolani nuxalash"
|
|
||||||
delete: "O'chirib tashlash"
|
|
||||||
deleteAndEdit: "O'chirish va tahrirlash"
|
|
||||||
deleteAndEditConfirm: "O'chirib, tahrirlamoqchiligingizga ishonchingiz komilmi? Siz bu qaydga tegishli barcha reaktsiyalar, qayta qaydlar va javoblarni yo'qotasiz."
|
|
||||||
addToList: "Ro‘yxatga qo‘shish"
|
|
||||||
addToAntenna: "Antennaga qo'shish"
|
|
||||||
sendMessage: "Xabar yuborish"
|
|
||||||
copyRSS: "RSS'ni nusxalash"
|
|
||||||
copyUsername: "Foydalanuvchi nomini nusxalash"
|
|
||||||
copyUserId: "Foydalanuvchi IDsini nusxalash"
|
|
||||||
copyNoteId: "Qayd IDsini ko'chirish"
|
|
||||||
copyFileId: "Fayl ID raqamini nusxalash"
|
|
||||||
copyFolderId: "Jild ID raqamini nusxalash"
|
|
||||||
copyProfileUrl: "Profil manzilini nusxalash"
|
|
||||||
searchUser: "Foydalanuvchini izlash"
|
|
||||||
reply: "Javob berish"
|
|
||||||
loadMore: "Ko‘proq ko‘rish"
|
|
||||||
showMore: "Ko‘proq ko‘rish"
|
|
||||||
showLess: "Yopish"
|
|
||||||
youGotNewFollower: "sizga obuna bo'ldi"
|
|
||||||
receiveFollowRequest: "Obuna bo'lishga ruxsat qabul qilindi"
|
|
||||||
followRequestAccepted: "Obuna bo'lishga ruxsat berildi"
|
|
||||||
mention: "Murojat"
|
|
||||||
mentions: "Eslatib o'tish"
|
|
||||||
directNotes: "Bevosita qaydlar"
|
|
||||||
importAndExport: "Import/eksport"
|
|
||||||
import: "Import"
|
|
||||||
export: "Eksport"
|
|
||||||
files: "Fayllar"
|
|
||||||
download: "Yuklab olish"
|
|
||||||
driveFileDeleteConfirm: "\"{name}\" o'chirib tashlamoqchimisiz? Buni ishlatadihan kontentni hammasidan o'chadi"
|
|
||||||
unfollowConfirm: "{name}ga obunani bekor qilmoqchimisiz?"
|
|
||||||
exportRequested: "Eksport so'raldi. Bu ozgina vaqt olishi mumkin. Tugatilgandan so'ng sizning Diskingizga qo'shiladi"
|
|
||||||
importRequested: "Import so'raldi. Bu ozgina vaqt olishi mumkin."
|
|
||||||
lists: "Ro'yxatlar"
|
|
||||||
noLists: "Hech qanday ro'yxatlar mavjud emas"
|
|
||||||
note: "Qayd"
|
|
||||||
notes: "Qaydlar"
|
|
||||||
following: "Obuna bo‘lish"
|
|
||||||
followers: "Obunachilar"
|
|
||||||
followsYou: "Sizning obunachingiz."
|
|
||||||
createList: "Ro'yxat yaratish"
|
|
||||||
manageLists: "Ro'yxatlarni boshqarish."
|
|
||||||
error: "Xato"
|
|
||||||
somethingHappened: "Xatolik yuz berdi"
|
|
||||||
retry: "Qayta urinib ko'rish"
|
|
||||||
pageLoadError: "Sahifani yuklayotganda xatolik yuz berdi"
|
|
||||||
pageLoadErrorDescription: "Buni odatda tarmoq muammolari yoki browser keshi keltirib chiqaradi. Keshni tozalab, keyinroq urinib ko'ring"
|
|
||||||
serverIsDead: "Server javob bermayabdi. Iltimos kuting va keyinroq urinib ko'ring"
|
|
||||||
youShouldUpgradeClient: "Iltimos, ushbu sahifani ko'rish uchun sahifani yangilang."
|
|
||||||
enterListName: "Ro'yxatga nom kiriting"
|
|
||||||
privacy: "Maxfiylik"
|
|
||||||
makeFollowManuallyApprove: "Yopiq akkaunt"
|
|
||||||
follow: "Obuna bo‘lish"
|
|
||||||
followRequest: "Obuna bo'lish uchun ruxsat olish"
|
|
||||||
followRequests: "Obuna bo'lmoqchilar"
|
|
||||||
unfollow: "obunani bker qilish"
|
|
||||||
followRequestPending: "obuna bo'lishga ruxsat kutilmoqda"
|
|
||||||
enterEmoji: "Emojini kiriting"
|
|
||||||
renote: "Qayta qaydetish"
|
|
||||||
unrenote: "Qayta qayd etishni bekor qilish"
|
|
||||||
renoted: "Qayta qaydetildi"
|
|
||||||
cantRenote: "Qyta qayd etish mumkin emas"
|
|
||||||
quote: "Iqtibos keltirish"
|
|
||||||
inChannelRenote: "Faqat kanalga qayta qayd etish"
|
|
||||||
inChannelQuote: "Kanaldagi eslatmalar"
|
|
||||||
pinnedNote: "Qadanlgan qayd"
|
|
||||||
pinned: "Profilga qadab qo'yish"
|
|
||||||
you: "Siz"
|
|
||||||
clickToShow: "Ko'rsatish uchun bosing"
|
|
||||||
sensitive: "Sezuvchan"
|
|
||||||
add: "Qo'shish"
|
|
||||||
reaction: "Reaktsiyalar"
|
|
||||||
reactions: "Reaktsiyalar"
|
|
||||||
reactionSetting: "Reaksiyalar ro'yxatingiz "
|
|
||||||
rememberNoteVisibility: "Qaydning ko'rinish sozlamarini eslab qolish"
|
|
||||||
attachCancel: "Qo'shimchani olib tashlash"
|
|
||||||
enterFileName: "Fayl nomini kiriting"
|
|
||||||
mute: "Ovozni o‘chirish"
|
|
||||||
unmute: "Ovozni yoqish"
|
|
||||||
renoteMute: "Qayta qaydlarni ovozini o'chirish"
|
|
||||||
renoteUnmute: "Qayta qaydlarni ovozini yoqish"
|
|
||||||
block: "Bloklash"
|
|
||||||
unblock: "Blokdan chiqarish"
|
|
||||||
suspend: "To'xtatish"
|
|
||||||
unsuspend: "Blokdan chiqarish"
|
|
||||||
blockConfirm: "Haqiqatdan ham quyidagi hisobni bloklashni xohlaysizmi? "
|
|
||||||
unblockConfirm: "Haqiqatdan ham quyidagi hisobni blokdan chiqarishni xohlaysizmi? "
|
|
||||||
suspendConfirm: "Bu hisobni to‘xtatib qo‘ymoqchi ekanligingizga ishonchingiz komilmi?"
|
|
||||||
unsuspendConfirm: "Tasdiqlashni to'xtatib turish"
|
|
||||||
selectList: "Ro'yxat tanlash"
|
|
||||||
editList: "Roʻyxatni tahrirlash"
|
|
||||||
selectChannel: "Kanalni tanlang"
|
|
||||||
selectAntenna: "Antennani tanlang"
|
|
||||||
editAntenna: "Antennani tahrirlang"
|
|
||||||
selectWidget: "Vidjet tanlash"
|
|
||||||
editWidgets: "Vidjetni tahrirlash"
|
|
||||||
editWidgetsExit: "Tugadi"
|
|
||||||
customEmojis: "Maxsus emoji"
|
|
||||||
emoji: "Emoji"
|
|
||||||
emojis: "Emoji"
|
|
||||||
emojiName: "Emoji nomi"
|
|
||||||
emojiUrl: "Emoji URL'i"
|
|
||||||
addEmoji: "Emoji qo'shish"
|
|
||||||
settingGuide: "Tavsiya qilingan sozlamalar"
|
|
||||||
cacheRemoteFiles: "Tashqi fayllarni keshlash"
|
|
||||||
cacheRemoteFilesDescription: "Ushbu sozlama o'chirilgan bo'lsa tashqi fayllar bevosita tashqi serverdan yuklanadi. Buni o'chirish ombor ishlatilishini kamaytiradi, lekin traffikni ko'paytiradi, chunki eskizlar generatsiya qilinmaydi."
|
|
||||||
cacheRemoteSensitiveFiles: "Tashqi fayllarni keshlash"
|
|
||||||
flagAsBot: "Ushbu akkauntni bot sifatida belgilash"
|
|
||||||
flagAsBotDescription: "Agar bu akkaunt bot tomonidan boshqaralayotgan bo'ls, bu sozlamani yoqing. Sozlama yoqilganda, boshqa foydalanuvchilar uchun belgi sifatida ishlaydi, va Misskey ichki tizimlari bu akkauntni bot ekanini biladi."
|
|
||||||
flagAsCat: "Bu akkauntni mushuk sifatida belgilash"
|
|
||||||
flagAsCatDescription: "Ushbu akkauntni mushuk sifatida belgilash uchun ushbu sozlamani yoqing."
|
|
||||||
flagShowTimelineReplies: "Javbolarni xronogoliya bo'yicha ko'rsatish"
|
|
||||||
addAccount: "Akkaunt qo'shish"
|
|
||||||
reloadAccountsList: "Hisoblar ro'yxatini yangilash"
|
|
||||||
loginFailed: "Tizimga kirishda xatolik yuz berdi"
|
|
||||||
showOnRemote: "Masofaviy boshqaruvni ko'rish"
|
|
||||||
general: "Asosiy"
|
|
||||||
wallpaper: "Fon rasmi"
|
|
||||||
setWallpaper: "Fon rasmini o'rnatish"
|
|
||||||
removeWallpaper: "Fon rasmini olib tashlash"
|
|
||||||
searchWith: "Izlash: {q}"
|
|
||||||
youHaveNoLists: "Sizda hech qanday ro'yxatlar mavjud emas"
|
|
||||||
followConfirm: "{name} ga obuna bo'lmoqchimisiz?"
|
|
||||||
proxyAccount: "Proksi hisob"
|
|
||||||
host: "Host"
|
|
||||||
selectUser: "Foydalanuvchini tanlang"
|
|
||||||
recipient: "Qabul qiluvchi"
|
|
||||||
annotation: "Izohlar"
|
|
||||||
federation: "Federatsiya"
|
|
||||||
instances: "Serverlar"
|
|
||||||
registeredAt: "Ro'yhatdan o'tgan"
|
|
||||||
latestStatus: "So'nggi holat"
|
|
||||||
storageUsage: "Ishlatilgan xotira"
|
|
||||||
charts: "Diagrammalar"
|
|
||||||
perHour: "Soatbay"
|
|
||||||
perDay: "Kunbay"
|
|
||||||
stopActivityDelivery: "Faollikni jo'natishi to'xtatish"
|
|
||||||
blockThisInstance: "Ko;rsatilgan serverni bloklash"
|
|
||||||
operations: "Amallar"
|
|
||||||
software: "Dastur"
|
|
||||||
version: "Versiya"
|
|
||||||
metadata: "Meta ma'lumot"
|
|
||||||
withNFiles: "{n} ta fayl(lar)"
|
|
||||||
monitor: "Kuzatish"
|
|
||||||
jobQueue: "Vazifalar navbati"
|
|
||||||
cpuAndMemory: "CPU va Xotira"
|
|
||||||
network: "Tarmoq"
|
|
||||||
disk: "Disk"
|
|
||||||
instanceInfo: "Instans haqida ma'lumot"
|
|
||||||
statistics: "Statistika"
|
|
||||||
clearQueue: "Navbatni tozalash"
|
|
||||||
clearQueueConfirmTitle: "Navbatni tozalamoqchimisiz?"
|
|
||||||
clearCachedFiles: "Keshni tozalash"
|
|
||||||
blockedInstances: "Bloklangan serverlar"
|
|
||||||
muteAndBlock: "Ovozsiz va Bloklangan"
|
|
||||||
mutedUsers: "Ovozsiz foydalanuvchilar"
|
|
||||||
blockedUsers: "Bloklangan foydalanuvchilar"
|
|
||||||
noUsers: "Foydalanuvchilar yo‘q"
|
|
||||||
editProfile: "Profilni o'zgartirish"
|
|
||||||
noteDeleteConfirm: "Haqiqatan ham bu qaydni oʻchirib tashlamoqchimisiz?"
|
|
||||||
pinLimitExceeded: "Siz boshqa qaydlarni mahkamlay olmaysiz"
|
|
||||||
intro: "Misskeyni o'rnatish tugallandi! Iltimos, administrator foydalanuvchi yarating."
|
|
||||||
done: "Bajarildi"
|
|
||||||
processing: "Amaliyotda"
|
|
||||||
preview: "Ko'rish"
|
|
||||||
default: "Odatiy"
|
|
||||||
defaultValueIs: "Sukut bo'yicha: {value}"
|
|
||||||
noCustomEmojis: "Emojilar mavjud emas"
|
|
||||||
noJobs: "Vazifalar yo'q"
|
|
||||||
blocked: "Bloklangan"
|
|
||||||
suspended: "To'xtatilgan"
|
|
||||||
all: "Barcha"
|
|
||||||
subscribing: "Obuna bo'lish"
|
|
||||||
publishing: "Yuborilmoqda"
|
|
||||||
notResponding: "Javob bermayapti"
|
|
||||||
changePassword: "Parolni o‘zgartirish"
|
|
||||||
security: "Xavfsizlik"
|
|
||||||
retypedNotMatch: "Maydonlar mos kelmayapti"
|
|
||||||
currentPassword: "Joriy parol"
|
|
||||||
newPassword: "Yangi parol"
|
|
||||||
newPasswordRetype: "Yangi parolni boshqatdan tering"
|
|
||||||
attachFile: "Fayl biriktirish"
|
|
||||||
more: "Ko'proq!"
|
|
||||||
noSuchUser: "Foydalanuvchi topilmadi"
|
|
||||||
lookup: "So'rov"
|
|
||||||
announcements: "Bildirishnomalar"
|
|
||||||
imageUrl: "Rasm URL"
|
|
||||||
remove: "O'chirib tashlash"
|
|
||||||
removed: "Muvaffaqiyatli o'chirildi"
|
|
||||||
removeAreYouSure: "“{x}”ni olib tashlamoqchi ekanligingizga ishonchingiz komilmi?"
|
|
||||||
deleteAreYouSure: "“{x}”ni chindan ham yo'q qilmoqchimisiz?"
|
|
||||||
resetAreYouSure: "Haqiqatan ham qayta tiklansinmi?"
|
|
||||||
saved: "Saqlandi"
|
|
||||||
messaging: "Suhbat"
|
|
||||||
upload: "Yuklash"
|
|
||||||
keepOriginalUploading: "Asl rasmni saqlang"
|
|
||||||
uploadFromUrlDescription: "Yuklamoqchi bo'lgan faylingizga havola"
|
|
||||||
explore: "Ko'rib chiqish"
|
|
||||||
messageRead: "O‘qildi"
|
|
||||||
startMessaging: "Yangi suhbatni boshlash"
|
|
||||||
nUsersRead: "{n} tomonidan o'qildi"
|
|
||||||
agreeTo: "Men {0} ga roziman"
|
|
||||||
agree: "Rozi bo'lish"
|
|
||||||
agreeBelow: "Men quyidagilarga roziman"
|
|
||||||
basicNotesBeforeCreateAccount: "Muhim qaydlar"
|
|
||||||
termsOfService: "Foydalanish shartlari"
|
|
||||||
start: "Boshlash"
|
|
||||||
home: "Bosh sahifa"
|
|
||||||
activity: "Faollik"
|
|
||||||
images: "Rasmlar"
|
|
||||||
image: "Rasm"
|
|
||||||
birthday: "Tug'ilgan kun"
|
|
||||||
yearsOld: "{age} yashar"
|
|
||||||
registeredDate: "Ro'yxatdan o'tgan sanasi"
|
|
||||||
location: "Manzil"
|
|
||||||
theme: "Rang sxemasi"
|
|
||||||
themeForLightMode: "Yorug' rejim uchun rang sxemasi"
|
|
||||||
themeForDarkMode: "Qorong'i rejim uchun rang sxemasi"
|
|
||||||
light: "Yorug'"
|
|
||||||
dark: "Qorongʻi"
|
|
||||||
lightThemes: "Yorug‘ rang sxemasi"
|
|
||||||
darkThemes: "Qorong'i rang sxemasi"
|
|
||||||
drive: "Disk"
|
|
||||||
fileName: "Fayl nomi"
|
|
||||||
selectFile: "Faylni tanlang"
|
|
||||||
selectFiles: "Fayllarni tanlang"
|
|
||||||
selectFolder: "Jildni tanlang"
|
|
||||||
selectFolders: "Jildlarni tanlang"
|
|
||||||
renameFile: "Faylni nomini tahrirlash"
|
|
||||||
folderName: "Jild nomi"
|
|
||||||
createFolder: "Papka qo'shish"
|
|
||||||
renameFolder: "Papka nomini o‘zgartirish"
|
|
||||||
deleteFolder: "Papkani o‘chirish"
|
|
||||||
addFile: "Fayl qo‘shish"
|
|
||||||
emptyDrive: "Diskingiz bo'sh"
|
|
||||||
emptyFolder: "Ushbu papka bo'sh"
|
|
||||||
unableToDelete: "O'chirilmadi"
|
|
||||||
inputNewFileName: "Yangi fayl nomini kiriting"
|
|
||||||
inputNewFolderName: "Yangi papka nomini kiriting"
|
|
||||||
copyUrl: "Bog'lamadan nusxa olish"
|
|
||||||
rename: "Qayta nomlash"
|
|
||||||
avatar: "Avatar"
|
|
||||||
banner: "Banner"
|
|
||||||
disconnectedFromServer: "Server bilan ulanish uzulib qoldi"
|
|
||||||
reload: "Yangilash"
|
|
||||||
doNothing: "E'tiborsiz qoldirish"
|
|
||||||
reloadConfirm: "Timeline'ni yangilashni xohlaysizmi?"
|
|
||||||
watch: "Kuzatmoq"
|
|
||||||
unwatch: "Kuzatishni to'xtatish"
|
|
||||||
accept: "Ruxsat"
|
|
||||||
reject: "Rad etish"
|
|
||||||
normal: "Yaxshi"
|
|
||||||
instanceName: "Server nomi"
|
|
||||||
instanceDescription: "Server tavsifi"
|
|
||||||
maintainerName: "Qo'llab-quvvatlovchi"
|
|
||||||
maintainerEmail: "Administratorning elektron pochtasi"
|
|
||||||
tosUrl: "Foydalanish shartlariga havola"
|
|
||||||
thisYear: "Joriy yil"
|
|
||||||
thisMonth: "Shu oy"
|
|
||||||
today: "Bugun"
|
|
||||||
dayX: "{day}"
|
|
||||||
monthX: "{month}"
|
|
||||||
yearX: "{year}"
|
|
||||||
pages: "Sahifalar"
|
|
||||||
integration: "Integratsiya"
|
|
||||||
connectService: "Ulash"
|
|
||||||
disconnectService: "Uzish"
|
|
||||||
enableLocalTimeline: "Mahalliy vaqt mintaqasini yoqing"
|
|
||||||
enableGlobalTimeline: "Global vaqt mintaqasini yoqing"
|
|
||||||
registration: "Ro'yxatdan o'tish"
|
|
||||||
enableRegistration: "Ro'yxatdan o'tishni yoqing"
|
|
||||||
invite: "Taklif qilish"
|
|
||||||
inMb: "Megabaytlarda"
|
|
||||||
basicInfo: "Asosiy ma'lumot"
|
|
||||||
pinnedUsers: "Qadalgan foydalanuvchilar"
|
|
||||||
pinnedPages: "Qadalgan Sahifalar"
|
|
||||||
pinnedNotes: "Qadanlgan qayd"
|
|
||||||
hcaptcha: "hCaptcha"
|
|
||||||
enableHcaptcha: "hCaptchani yoqish"
|
|
||||||
hcaptchaSiteKey: "Sayt kaliti"
|
|
||||||
hcaptchaSecretKey: "Mahfiy kalit"
|
|
||||||
recaptcha: "reCAPTCHA"
|
|
||||||
enableRecaptcha: "reCAPTCHA ni yoqish"
|
|
||||||
recaptchaSiteKey: "Sayt kaliti"
|
|
||||||
recaptchaSecretKey: "Maxfiy kalit"
|
|
||||||
turnstileSiteKey: "Sayt kaliti"
|
|
||||||
turnstileSecretKey: "Maxfiy kalit"
|
|
||||||
antennas: "Antennalar"
|
|
||||||
manageAntennas: "Antennalarni boshqarish"
|
|
||||||
name: "Ism"
|
|
||||||
antennaSource: "Antenna manbai"
|
|
||||||
silence: "Sukunat"
|
|
||||||
exploreUsersCount: "{count} ta foydalanuvchi bor"
|
|
||||||
popularTags: "Ommabop teglar"
|
|
||||||
userList: "Ro'yxatlar"
|
|
||||||
about: "Haqida"
|
|
||||||
aboutMisskey: "Misskey haqida"
|
|
||||||
administrator: "Administrator"
|
|
||||||
token: "Tasdiqlash"
|
|
||||||
2fa: "Ikki faktorli autentifikatsiya"
|
|
||||||
totp: "Autentifikatsiya ilovasi"
|
|
||||||
totpDescription: "Bir martalik parollarni kiritish uchun autentifikatsiya ilovasidan foydalaning"
|
|
||||||
moderator: "Moderator"
|
|
||||||
resetPassword: "Parolni tiklash"
|
|
||||||
share: "Yuborish"
|
|
||||||
notFound: "Topilmadi"
|
|
||||||
uploadFolder: "Jildni yuklash"
|
|
||||||
cacheClear: "Keshni tozalash"
|
|
||||||
help: "Yordam"
|
|
||||||
inputMessageHere: "Xabar kiriting"
|
|
||||||
close: "Yopish"
|
|
||||||
invites: "Taklif qilish"
|
|
||||||
members: "A'zolar"
|
|
||||||
title: "Sarlavha"
|
|
||||||
text: "Matn"
|
|
||||||
enable: "Yoqish"
|
|
||||||
invitations: "Taklif qilish"
|
|
||||||
dashboard: "Boshqaruv paneli"
|
|
||||||
local: "Mahalliy"
|
|
||||||
total: "Jami"
|
|
||||||
weekOverWeekChanges: "Oxirgi haftadagi o'zgarishlar"
|
|
||||||
dayOverDayChanges: "Kecha bo'lgan o'zgarishlar"
|
|
||||||
appearance: "Tasgqi ko'rinish"
|
|
||||||
clientSettings: "Klient sozlamalari"
|
|
||||||
accountSettings: "Profil sozlamalari"
|
|
||||||
sounds: "Tovushlar"
|
|
||||||
sound: "ovoz"
|
|
||||||
none: "Hechnima"
|
|
||||||
volume: "Ovoz balandligi"
|
|
||||||
details: "Batafsil"
|
|
||||||
output: "Chiqish"
|
|
||||||
menu: "Menyu"
|
|
||||||
divider: "Ajratrmoq"
|
|
||||||
addItem: "Element qo'shish"
|
|
||||||
themeEditor: "Rang sxemasi muharriri"
|
|
||||||
enableAll: "Yoqish"
|
|
||||||
edit: "Tahrirlash"
|
|
||||||
email: "Email"
|
|
||||||
smtpHost: "Host"
|
|
||||||
smtpUser: "Foydalanuvchi nomi"
|
|
||||||
smtpPass: "Parol"
|
|
||||||
copy: "Nusxa olish"
|
|
||||||
notificationSetting: "Bildirishnoma sozlamalari"
|
|
||||||
other: "Qo‘shimcha"
|
|
||||||
behavior: "Hatti-harakatlar"
|
|
||||||
sample: "Namuna"
|
|
||||||
public: "Ommaviy"
|
|
||||||
clearCache: "Keshni tozalash"
|
|
||||||
onlineUsersCount: "Faol userlar"
|
|
||||||
myTheme: "Mening rang sxemam"
|
|
||||||
backgroundColor: "Fon"
|
|
||||||
accentColor: "Urg'u"
|
|
||||||
textColor: "Matn"
|
|
||||||
info: "Haqida"
|
|
||||||
user: "Foydalanuvchilar"
|
|
||||||
global: "Global"
|
|
||||||
squareAvatars: "Kvadrat avatarkalar"
|
|
||||||
searchByGoogle: "Izlash"
|
|
||||||
indefinitely: "Hech qachon"
|
|
||||||
file: "Fayllar"
|
|
||||||
label: "Yorliq"
|
|
||||||
color: "Rang"
|
|
||||||
_achievements:
|
|
||||||
_types:
|
|
||||||
_viewInstanceChart:
|
|
||||||
title: "Tahlilchi"
|
|
||||||
_ad:
|
|
||||||
hide: "Boshqa ko'rsatilmasin"
|
|
||||||
_email:
|
|
||||||
_follow:
|
|
||||||
title: "sizga obuna bo'ldi"
|
|
||||||
_registry:
|
|
||||||
key: "Kalit"
|
|
||||||
keys: "Kalit"
|
|
||||||
_instanceTicker:
|
|
||||||
none: "Boshqa ko'rsatilmasin"
|
|
||||||
always: "Doimo ko'rsatilsin"
|
|
||||||
_theme:
|
|
||||||
install: "Rang sxemasini o'rnatish"
|
|
||||||
manage: "Rang sxemalarini boshqarish"
|
|
||||||
code: "Rang sxemasining kodi"
|
|
||||||
description: "Tavsif"
|
|
||||||
installed: "{name} o'rnatildi"
|
|
||||||
installedThemes: "O'rnatilgan rang sxemalari"
|
|
||||||
alreadyInstalled: "Ushbu rang sxemasi allaqachon o'rnatilgan"
|
|
||||||
invalid: "Ushbu rang sxemasining formati yaroqsiz"
|
|
||||||
make: "Rang sxemasini yasash"
|
|
||||||
base: "Asos"
|
|
||||||
addConstant: "O'zgarmas qo'shish"
|
|
||||||
constant: "O'zgarmas"
|
|
||||||
color: "Rang"
|
|
||||||
key: "Kalit"
|
|
||||||
func: "Funksiyalar"
|
|
||||||
funcKind: "Funksiya turi"
|
|
||||||
argument: "Argument"
|
|
||||||
darken: "Qoraytirish"
|
|
||||||
lighten: "Yoritish"
|
|
||||||
inputConstantName: "Ushbu o'zgarmas uchun nom kiriting"
|
|
||||||
deleteConstantConfirm: "Siz rostdan ham {const} o'zgarmasni o'chirmoqchimisiz?"
|
|
||||||
keys:
|
|
||||||
accent: "Urg'u"
|
|
||||||
bg: "Fon"
|
|
||||||
fg: "Matn"
|
|
||||||
focus: "Fokus"
|
|
||||||
panel: "Panel"
|
|
||||||
shadow: "Soya"
|
|
||||||
header: "Sarlavha"
|
|
||||||
navBg: "Yon panel foni"
|
|
||||||
navFg: "Yon panel matni"
|
|
||||||
mention: "Murojat"
|
|
||||||
renote: "Qayta qaydetish"
|
|
||||||
divider: "Ajratrmoq"
|
|
||||||
accentDarken: "Urg'u (Qoraytirilgan)"
|
|
||||||
accentLighten: "Urg'u (Yoritilgan)"
|
|
||||||
fgHighlighted: "Belgilangan matn"
|
|
||||||
_sfx:
|
|
||||||
note: "Qaydlar"
|
|
||||||
notification: "Xabarnomalar"
|
|
||||||
chat: "Suhbat"
|
|
||||||
_2fa:
|
|
||||||
renewTOTPCancel: "Hozir emas"
|
|
||||||
_permissions:
|
|
||||||
"read:blocks": "Bloklangan foydalanuvchilar roʻyxatini koʻring"
|
|
||||||
"write:blocks": "Bloklangan foydalanuvchilar roʻyxatini tahrirlang"
|
|
||||||
_weekday:
|
|
||||||
saturday: "Shanba"
|
|
||||||
_widgets:
|
|
||||||
profile: "Profil"
|
|
||||||
instanceInfo: "Instans haqida ma'lumot"
|
|
||||||
notifications: "Xabarnomalar"
|
|
||||||
timeline: "Xronologiya"
|
|
||||||
clock: "Soat"
|
|
||||||
activity: "Faollik"
|
|
||||||
photos: "Rasmlar"
|
|
||||||
digitalClock: "Raqamli soat"
|
|
||||||
unixClock: "UNIX soat"
|
|
||||||
federation: "Federatsiya"
|
|
||||||
button: "Tugma"
|
|
||||||
jobQueue: "Vazifalar navbati"
|
|
||||||
_userList:
|
|
||||||
chooseList: "Ro'yxat tanlash"
|
|
||||||
_cw:
|
|
||||||
show: "Ko‘proq ko‘rish"
|
|
||||||
chars: "{count} ta belgi(lar)"
|
|
||||||
files: "{count} ta fayl(lar)"
|
|
||||||
_poll:
|
|
||||||
noOnlyOneChoice: "Kamida ikkita tanvol kerak"
|
|
||||||
infinite: "Hech qachon"
|
|
||||||
at: "...da tugatish"
|
|
||||||
after: "...dan keyin tugatish"
|
|
||||||
deadlineTime: "Vaqt"
|
|
||||||
duration: "Davomiylik"
|
|
||||||
votesCount: "{n} ovozlar"
|
|
||||||
totalVotes: "Umuman {n} ovozlar"
|
|
||||||
vote: "Ovoz berish"
|
|
||||||
showResult: "Natijalarni ko'rish"
|
|
||||||
voted: "Ovoz berildi"
|
|
||||||
closed: "Yakunladi"
|
|
||||||
remainingDays: "{d} kun {h} soat qoldi"
|
|
||||||
remainingHours: "{h} soat {m} daqiqa qoldi"
|
|
||||||
remainingMinutes: "{m} daqiqa {s} sekund qoldi"
|
|
||||||
remainingSeconds: "{s} sekund qoldi"
|
|
||||||
_visibility:
|
|
||||||
public: "Ommaviy"
|
|
||||||
publicDescription: "Sizning ovozingiz barcha foydalanuvchilarga ko'rinadi"
|
|
||||||
home: "Bosh sahifa"
|
|
||||||
followers: "Obunachilar"
|
|
||||||
specified: "Bevosita"
|
|
||||||
_profile:
|
|
||||||
name: "Ism"
|
|
||||||
username: "Foydalanuvchi nomi"
|
|
||||||
description: "Biografiya"
|
|
||||||
metadata: "Qo'shimcha ma'lumot"
|
|
||||||
metadataLabel: "Yorliq"
|
|
||||||
metadataContent: "Tarkib"
|
|
||||||
changeBanner: "Bannerni o'zgartirish"
|
|
||||||
_exportOrImport:
|
|
||||||
allNotes: "Barcha qaydlar"
|
|
||||||
followingList: "Obuna bo‘lish"
|
|
||||||
muteList: "Ovozni o‘chirish"
|
|
||||||
blockingList: "Bloklangan foydalanuvchilar"
|
|
||||||
userLists: "Ro'yxatlar"
|
|
||||||
_charts:
|
|
||||||
federation: "Federatsiya"
|
|
||||||
apRequest: "So'rovlar"
|
|
||||||
usersTotal: "Foydalanuvchilarning umumiy soni"
|
|
||||||
activeUsers: "Faol foydalanuvchilar"
|
|
||||||
notesTotal: "Qaydlarning umumiy soni"
|
|
||||||
filesTotal: "Fayllarning umumiy soni"
|
|
||||||
_instanceCharts:
|
|
||||||
requests: "So'rovlar"
|
|
||||||
notes: "Qaydlar sonidagi farq"
|
|
||||||
cacheSize: "Kesh hajmidagi farq"
|
|
||||||
files: "Fayllar sonidagi farq"
|
|
||||||
_timelines:
|
|
||||||
home: "Bosh sahifa"
|
|
||||||
local: "Mahalliy"
|
|
||||||
social: "Ijtimoiy"
|
|
||||||
global: "Global"
|
|
||||||
_play:
|
|
||||||
featured: "Mashhur"
|
|
||||||
title: "Sarlavha"
|
|
||||||
script: "Skript"
|
|
||||||
summary: "Tavsif"
|
|
||||||
_pages:
|
|
||||||
newPage: "Yangi Sahifa yaratish"
|
|
||||||
editPage: "Ushbu Sahifani tahrirlash"
|
|
||||||
created: "Sahifa muvaffaqiyatli yaratildi"
|
|
||||||
updated: "Sahifa muvaffaqiyatli tahrirlandi"
|
|
||||||
deleted: "Sahifa muvaffaqiyatli o'chirildi"
|
|
||||||
pageSetting: "Sahifa sozlamalari"
|
|
||||||
nameAlreadyExists: "Ko'rsatilgan Sahifa URL'i allaqachon mavjud"
|
|
||||||
invalidNameTitle: "Ko'rsatilgan Sahifa URL'i yaroqsiz"
|
|
||||||
editThisPage: "Ushbu Sahifani tahrirlash"
|
|
||||||
viewPage: "Sizning Sahifalaringizni ko'rish"
|
|
||||||
my: "Mening Sahifalarim"
|
|
||||||
featured: "Mashhur"
|
|
||||||
contents: "Tarkib"
|
|
||||||
title: "Sarlavha"
|
|
||||||
url: "Sahifa URL'i"
|
|
||||||
summary: "Sahifa bayoni"
|
|
||||||
font: "Shrift"
|
|
||||||
fontSerif: "Serif"
|
|
||||||
fontSansSerif: "Sans Serif"
|
|
||||||
selectType: "Turni tanlang"
|
|
||||||
contentBlocks: "Tarkib"
|
|
||||||
blocks:
|
|
||||||
text: "Matn"
|
|
||||||
textarea: "Matn maydoni"
|
|
||||||
section: "Bo'lim"
|
|
||||||
image: "Rasmlar"
|
|
||||||
button: "Tugma"
|
|
||||||
note: "Biriktirilgan qayd"
|
|
||||||
_note:
|
|
||||||
id: "Qayd ID"
|
|
||||||
detailed: "Batafsil ko'rinishi"
|
|
||||||
_relayStatus:
|
|
||||||
requesting: "Kutilmoqda"
|
|
||||||
accepted: "Tasdiqlandi"
|
|
||||||
rejected: "Rad etildi"
|
|
||||||
_notification:
|
|
||||||
fileUploaded: "Fayl muvaffaqiyatli yuklandi"
|
|
||||||
youGotMention: "{name} sizni eslab o'tdi"
|
|
||||||
youGotReply: "{name} sizga javob berdi"
|
|
||||||
youGotQuote: "{name} sizdan iqtibos keltirdi"
|
|
||||||
youRenoted: "{name} dan qayta qayd qilish"
|
|
||||||
youWereFollowed: "sizga obuna bo'ldi"
|
|
||||||
unreadAntennaNote: "Antenna {name}"
|
|
||||||
_types:
|
|
||||||
all: "Barchasi"
|
|
||||||
follow: "Obuna bo‘lish"
|
|
||||||
mention: "Murojat"
|
|
||||||
renote: "Qayta qaydetish"
|
|
||||||
quote: "Iqtibos keltirish"
|
|
||||||
reaction: "Reaktsiyalar"
|
|
||||||
receiveFollowRequest: "Qabul qilingan kuzatuv so'rovlari"
|
|
||||||
_actions:
|
|
||||||
reply: "Javob berish"
|
|
||||||
renote: "Qayta qayd qilish"
|
|
||||||
_deck:
|
|
||||||
alwaysShowMainColumn: "Har doim asosiy ustunni ko'rsatish"
|
|
||||||
columnAlign: "Ustunlarni tekislash"
|
|
||||||
addColumn: "Ustun qo'shish"
|
|
||||||
configureColumn: "Ustun sozlamalari"
|
|
||||||
swapLeft: "Chapdagi ustun bilan joyni almashtirish"
|
|
||||||
swapRight: "O'ngdagi ustun bilan joyni almashtirish"
|
|
||||||
swapUp: "Yuqoridagi ustun bilan joyni almashtirish"
|
|
||||||
swapDown: "Quyidagi ustun bilan joyni almashtirish"
|
|
||||||
profile: "Profil"
|
|
||||||
newProfile: "Yangi profil"
|
|
||||||
deleteProfile: "Profilni o‘chirib tashlash"
|
|
||||||
_columns:
|
|
||||||
main: "Asosiy"
|
|
||||||
notifications: "Xabarnomalar"
|
|
||||||
tl: "Xronologiya"
|
|
||||||
antenna: "Antennalar"
|
|
||||||
list: "Ro‘yxat"
|
|
||||||
channel: "Kanal"
|
|
||||||
mentions: "Eslatib o'tish"
|
|
||||||
direct: "Bevosita qaydlar"
|
|
||||||
roleTimeline: "Rol xronologiyasi"
|
|
||||||
_webhookSettings:
|
|
||||||
name: "Ism"
|
|
||||||
active: "Yoqilgan"
|
|
||||||
_events:
|
|
||||||
renote: "Qayta qayd qilinganda"
|
|
||||||
mention: "Eslanganda"
|
|
@@ -49,15 +49,11 @@ delete: "删除"
|
|||||||
deleteAndEdit: "删除并编辑"
|
deleteAndEdit: "删除并编辑"
|
||||||
deleteAndEditConfirm: "要删除此帖并再次编辑吗?对此帖的所有回应、转发和回复也将被删除。"
|
deleteAndEditConfirm: "要删除此帖并再次编辑吗?对此帖的所有回应、转发和回复也将被删除。"
|
||||||
addToList: "添加至列表"
|
addToList: "添加至列表"
|
||||||
addToAntenna: "添加到天线"
|
|
||||||
sendMessage: "发送"
|
sendMessage: "发送"
|
||||||
copyRSS: "复制RSS"
|
copyRSS: "复制RSS"
|
||||||
copyUsername: "复制用户名"
|
copyUsername: "复制用户名"
|
||||||
copyUserId: "复制用户 ID"
|
copyUserId: "复制用户 ID"
|
||||||
copyNoteId: "复制帖子 ID"
|
copyNoteId: "复制帖子 ID"
|
||||||
copyFileId: "复制文件ID"
|
|
||||||
copyFolderId: "复制文件夹ID"
|
|
||||||
copyProfileUrl: "复制配置文件URL"
|
|
||||||
searchUser: "搜索用户"
|
searchUser: "搜索用户"
|
||||||
reply: "回复"
|
reply: "回复"
|
||||||
loadMore: "查看更多"
|
loadMore: "查看更多"
|
||||||
@@ -156,8 +152,6 @@ addEmoji: "添加表情符号"
|
|||||||
settingGuide: "推荐配置"
|
settingGuide: "推荐配置"
|
||||||
cacheRemoteFiles: "缓存远程文件"
|
cacheRemoteFiles: "缓存远程文件"
|
||||||
cacheRemoteFilesDescription: "当禁用此设定时远程文件将直接从远程服务器载入。禁用后会减小储存空间需求,但是会增加流量,因为缩略图不会被生成。"
|
cacheRemoteFilesDescription: "当禁用此设定时远程文件将直接从远程服务器载入。禁用后会减小储存空间需求,但是会增加流量,因为缩略图不会被生成。"
|
||||||
cacheRemoteSensitiveFiles: "缓存远程敏感媒体文件"
|
|
||||||
cacheRemoteSensitiveFilesDescription: "如果禁用这项设定,远程服务器的敏感媒体将不会被缓存,而是直接链接。"
|
|
||||||
flagAsBot: "这是一个机器人账号"
|
flagAsBot: "这是一个机器人账号"
|
||||||
flagAsBotDescription: "如果此账户由程序控制,请启用此项。启用后,此标志可以帮助其他开发人员防止机器人之间产生无限互动的行为,并让 Misskey 的内部系统将此账户识别为机器人。"
|
flagAsBotDescription: "如果此账户由程序控制,请启用此项。启用后,此标志可以帮助其他开发人员防止机器人之间产生无限互动的行为,并让 Misskey 的内部系统将此账户识别为机器人。"
|
||||||
flagAsCat: "将这个账户设定为一只猫"
|
flagAsCat: "将这个账户设定为一只猫"
|
||||||
@@ -319,7 +313,6 @@ copyUrl: "复制链接"
|
|||||||
rename: "重命名"
|
rename: "重命名"
|
||||||
avatar: "头像"
|
avatar: "头像"
|
||||||
banner: "横幅"
|
banner: "横幅"
|
||||||
displayOfSensitiveMedia: "显示敏感媒体"
|
|
||||||
whenServerDisconnected: "与服务器连接中断时"
|
whenServerDisconnected: "与服务器连接中断时"
|
||||||
disconnectedFromServer: "已和服务器断开连接"
|
disconnectedFromServer: "已和服务器断开连接"
|
||||||
reload: "重新加载"
|
reload: "重新加载"
|
||||||
@@ -1073,27 +1066,6 @@ installed: "已安装"
|
|||||||
branding: "品牌"
|
branding: "品牌"
|
||||||
enableServerMachineStats: "公开服务器硬件统计信息"
|
enableServerMachineStats: "公开服务器硬件统计信息"
|
||||||
enableIdenticonGeneration: "启用生成用户 Identicon"
|
enableIdenticonGeneration: "启用生成用户 Identicon"
|
||||||
turnOffToImprovePerformance: "关闭该选项可以提高性能。"
|
|
||||||
createInviteCode: "发行邀请码"
|
|
||||||
createWithOptions: "使用选项来创建"
|
|
||||||
createCount: "发行数"
|
|
||||||
inviteCodeCreated: "已创建邀请码"
|
|
||||||
inviteLimitExceeded: "可供发行的邀请码已达上限。"
|
|
||||||
createLimitRemaining: "可供发行的邀请码:剩余{limit}个"
|
|
||||||
inviteLimitResetCycle: "可以在{time}内发行最多{limit}个邀请码。"
|
|
||||||
expirationDate: "有效日期"
|
|
||||||
noExpirationDate: "不设置有效日期"
|
|
||||||
inviteCodeUsedAt: "邀请码被使用的日期和时间"
|
|
||||||
registeredUserUsingInviteCode: "使用了邀请码的用户"
|
|
||||||
waitingForMailAuth: "等待验证电子邮件"
|
|
||||||
inviteCodeCreator: "发行邀请码的用户"
|
|
||||||
usedAt: "使用时间"
|
|
||||||
unused: "未使用"
|
|
||||||
used: "已使用"
|
|
||||||
expired: "已过期"
|
|
||||||
doYouAgree: "你同意吗?"
|
|
||||||
beSureToReadThisAsItIsImportant: "请好好阅读,这真的很重要。"
|
|
||||||
iHaveReadXCarefullyAndAgree: "我已经仔细阅读并同意了「{x}」的内容。"
|
|
||||||
_initialAccountSetting:
|
_initialAccountSetting:
|
||||||
accountCreated: "账户创建完成了!"
|
accountCreated: "账户创建完成了!"
|
||||||
letsStartAccountSetup: "来进行帐户的初始设置吧。"
|
letsStartAccountSetup: "来进行帐户的初始设置吧。"
|
||||||
@@ -1181,53 +1153,53 @@ _achievements:
|
|||||||
flavor: "真的有那么多可以写的东西吗?"
|
flavor: "真的有那么多可以写的东西吗?"
|
||||||
_login3:
|
_login3:
|
||||||
title: "初学者 I"
|
title: "初学者 I"
|
||||||
description: "累计登录 3 天"
|
description: "连续登录 3 天"
|
||||||
flavor: "今天开始我就是 Misskist!"
|
flavor: "今天开始我就是 Misskist!"
|
||||||
_login7:
|
_login7:
|
||||||
title: "初学者 II"
|
title: "初学者 II"
|
||||||
description: "累计登录 7 天"
|
description: "连续登录 7 天"
|
||||||
flavor: "您开始习惯了吗?"
|
flavor: "您开始习惯了吗?"
|
||||||
_login15:
|
_login15:
|
||||||
title: "初学者 III"
|
title: "初学者 III"
|
||||||
description: "累计登录 15 天"
|
description: "连续登录 15 天"
|
||||||
_login30:
|
_login30:
|
||||||
title: "Misskist Ⅰ"
|
title: "Misskist Ⅰ"
|
||||||
description: "累计登录 30 天"
|
description: "连续登录 30 天"
|
||||||
_login60:
|
_login60:
|
||||||
title: "Misskist Ⅱ"
|
title: "Misskist Ⅱ"
|
||||||
description: "累计登录 60 天"
|
description: "连续登录 60 天"
|
||||||
_login100:
|
_login100:
|
||||||
title: "Misskist Ⅲ"
|
title: "Misskist Ⅲ"
|
||||||
description: "累计登入 100 天"
|
description: "总登入 100 天"
|
||||||
flavor: "那个用户,是 Misskist 喔"
|
flavor: "那个用户,是 Misskist 喔"
|
||||||
_login200:
|
_login200:
|
||||||
title: "定期联系Ⅰ"
|
title: "定期联系Ⅰ"
|
||||||
description: "累计登录 200 天"
|
description: "总登录天数 200 天"
|
||||||
_login300:
|
_login300:
|
||||||
title: "定期联系Ⅱ"
|
title: "定期联系Ⅱ"
|
||||||
description: "累计登录 300 天"
|
description: "总登录天数 300 天"
|
||||||
_login400:
|
_login400:
|
||||||
title: "定期联系Ⅲ"
|
title: "定期联系Ⅲ"
|
||||||
description: "累计登录 400 天"
|
description: "总登录天数 400 天"
|
||||||
_login500:
|
_login500:
|
||||||
title: "老熟人Ⅰ"
|
title: "老熟人Ⅰ"
|
||||||
description: "累计登录 500 天"
|
description: "总登录天数 500 天"
|
||||||
flavor: "诸君,我喜欢贴文"
|
flavor: "诸君,我喜欢贴文"
|
||||||
_login600:
|
_login600:
|
||||||
title: "老熟人Ⅱ"
|
title: "老熟人Ⅱ"
|
||||||
description: "累计登录 600 天"
|
description: "总登录天数 600 天"
|
||||||
_login700:
|
_login700:
|
||||||
title: "老熟人Ⅲ"
|
title: "老熟人Ⅲ"
|
||||||
description: "累计登录 700 天"
|
description: "总登录天数 700 天"
|
||||||
_login800:
|
_login800:
|
||||||
title: "帖子大师 Ⅰ"
|
title: "帖子大师 Ⅰ"
|
||||||
description: "累计登录 800 天"
|
description: "总登录天数 800 天"
|
||||||
_login900:
|
_login900:
|
||||||
title: "帖子大师 Ⅱ"
|
title: "帖子大师 Ⅱ"
|
||||||
description: "累计登录 900 天"
|
description: "总登录天数 900 天"
|
||||||
_login1000:
|
_login1000:
|
||||||
title: "帖子大师 Ⅲ"
|
title: "帖子大师 Ⅲ"
|
||||||
description: "累计登录 1000 天"
|
description: "总登录天数 1000 天"
|
||||||
flavor: "感谢您使用 Misskey!"
|
flavor: "感谢您使用 Misskey!"
|
||||||
_noteClipped1:
|
_noteClipped1:
|
||||||
title: "忍不住要收藏到便签"
|
title: "忍不住要收藏到便签"
|
||||||
@@ -1404,9 +1376,6 @@ _role:
|
|||||||
ltlAvailable: "查看本地时间线"
|
ltlAvailable: "查看本地时间线"
|
||||||
canPublicNote: "允许公开发帖"
|
canPublicNote: "允许公开发帖"
|
||||||
canInvite: "发放服务器邀请码"
|
canInvite: "发放服务器邀请码"
|
||||||
inviteLimit: "可发行邀请码的数量"
|
|
||||||
inviteLimitCycle: "邀请码的发行间隔"
|
|
||||||
inviteExpirationTime: "邀请码的有效日期"
|
|
||||||
canManageCustomEmojis: "管理自定义表情符号"
|
canManageCustomEmojis: "管理自定义表情符号"
|
||||||
driveCapacity: "网盘容量"
|
driveCapacity: "网盘容量"
|
||||||
alwaysMarkNsfw: "总是将文件标记为 NSFW"
|
alwaysMarkNsfw: "总是将文件标记为 NSFW"
|
||||||
@@ -1469,7 +1438,6 @@ _ad:
|
|||||||
back: "返回"
|
back: "返回"
|
||||||
reduceFrequencyOfThisAd: "减少此广告的频率"
|
reduceFrequencyOfThisAd: "减少此广告的频率"
|
||||||
hide: "不显示"
|
hide: "不显示"
|
||||||
timezoneinfo: "星期几是由服务器的时区所指定的。"
|
|
||||||
_forgotPassword:
|
_forgotPassword:
|
||||||
enterEmail: "请输入您设置的电子邮箱地址,密码重置链接将发送至该邮箱上。"
|
enterEmail: "请输入您设置的电子邮箱地址,密码重置链接将发送至该邮箱上。"
|
||||||
ifNoEmail: "如果您没有设置电子邮件地址,请联系管理员。"
|
ifNoEmail: "如果您没有设置电子邮件地址,请联系管理员。"
|
||||||
@@ -1521,10 +1489,6 @@ _aboutMisskey:
|
|||||||
donate: "赞助 Misskey"
|
donate: "赞助 Misskey"
|
||||||
morePatrons: "还有很多其它的人也在支持我们,非常感谢🥰"
|
morePatrons: "还有很多其它的人也在支持我们,非常感谢🥰"
|
||||||
patrons: "支持者"
|
patrons: "支持者"
|
||||||
_displayOfSensitiveMedia:
|
|
||||||
respect: "隐藏敏感媒体"
|
|
||||||
ignore: "显示敏感媒体"
|
|
||||||
force: "隐藏所有内容"
|
|
||||||
_instanceTicker:
|
_instanceTicker:
|
||||||
none: "不显示"
|
none: "不显示"
|
||||||
remote: "仅远程用户"
|
remote: "仅远程用户"
|
||||||
@@ -1999,7 +1963,6 @@ _deck:
|
|||||||
introduction: "将各列进行组合以创建您自己的界面!"
|
introduction: "将各列进行组合以创建您自己的界面!"
|
||||||
introduction2: "您可以随时通过屏幕右侧的 + 来添加列"
|
introduction2: "您可以随时通过屏幕右侧的 + 来添加列"
|
||||||
widgetsIntroduction: "从列菜单中,选择“小工具编辑”来添加小工具"
|
widgetsIntroduction: "从列菜单中,选择“小工具编辑”来添加小工具"
|
||||||
useSimpleUiForNonRootPages: "用简易UI表示非根页面"
|
|
||||||
_columns:
|
_columns:
|
||||||
main: "主列"
|
main: "主列"
|
||||||
widgets: "小工具"
|
widgets: "小工具"
|
||||||
|
File diff suppressed because it is too large
Load Diff
@@ -1,12 +1,12 @@
|
|||||||
{
|
{
|
||||||
"name": "misskey",
|
"name": "misskey",
|
||||||
"version": "13.14.1",
|
"version": "13.14.0-beta.2",
|
||||||
"codename": "nasubi",
|
"codename": "nasubi",
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/misskey-dev/misskey.git"
|
"url": "https://github.com/misskey-dev/misskey.git"
|
||||||
},
|
},
|
||||||
"packageManager": "pnpm@8.6.9",
|
"packageManager": "pnpm@8.6.0",
|
||||||
"workspaces": [
|
"workspaces": [
|
||||||
"packages/frontend",
|
"packages/frontend",
|
||||||
"packages/backend",
|
"packages/backend",
|
||||||
@@ -59,8 +59,8 @@
|
|||||||
"@typescript-eslint/eslint-plugin": "5.61.0",
|
"@typescript-eslint/eslint-plugin": "5.61.0",
|
||||||
"@typescript-eslint/parser": "5.61.0",
|
"@typescript-eslint/parser": "5.61.0",
|
||||||
"cross-env": "7.0.3",
|
"cross-env": "7.0.3",
|
||||||
"cypress": "12.17.1",
|
"cypress": "12.17.0",
|
||||||
"eslint": "8.45.0",
|
"eslint": "8.44.0",
|
||||||
"start-server-and-test": "2.0.0"
|
"start-server-and-test": "2.0.0"
|
||||||
},
|
},
|
||||||
"optionalDependencies": {
|
"optionalDependencies": {
|
||||||
|
@@ -2,7 +2,14 @@ import Redis from 'ioredis';
|
|||||||
import { loadConfig } from './built/config.js';
|
import { loadConfig } from './built/config.js';
|
||||||
|
|
||||||
const config = loadConfig();
|
const config = loadConfig();
|
||||||
const redis = new Redis(config.redis);
|
const redis = new Redis({
|
||||||
|
port: config.redis.port,
|
||||||
|
host: config.redis.host,
|
||||||
|
family: config.redis.family == null ? 0 : config.redis.family,
|
||||||
|
password: config.redis.pass,
|
||||||
|
keyPrefix: `${config.redis.prefix}:`,
|
||||||
|
db: config.redis.db ?? 0,
|
||||||
|
});
|
||||||
|
|
||||||
redis.on('connect', () => redis.disconnect());
|
redis.on('connect', () => redis.disconnect());
|
||||||
redis.on('error', (e) => {
|
redis.on('error', (e) => {
|
||||||
|
@@ -1,25 +0,0 @@
|
|||||||
export class RefactorInviteSystem1688720440658 {
|
|
||||||
name = 'RefactorInviteSystem1688720440658'
|
|
||||||
|
|
||||||
async up(queryRunner) {
|
|
||||||
await queryRunner.query(`ALTER TABLE "registration_ticket" ADD "expiresAt" TIMESTAMP WITH TIME ZONE`);
|
|
||||||
await queryRunner.query(`ALTER TABLE "registration_ticket" ADD "usedAt" TIMESTAMP WITH TIME ZONE`);
|
|
||||||
await queryRunner.query(`ALTER TABLE "registration_ticket" ADD "pendingUserId" character varying(32)`);
|
|
||||||
await queryRunner.query(`ALTER TABLE "registration_ticket" ADD "createdById" character varying(32)`);
|
|
||||||
await queryRunner.query(`ALTER TABLE "registration_ticket" ADD "usedById" character varying(32)`);
|
|
||||||
await queryRunner.query(`ALTER TABLE "registration_ticket" ADD CONSTRAINT "UQ_b6f93f2f30bdbb9a5ebdc7c7189" UNIQUE ("usedById")`);
|
|
||||||
await queryRunner.query(`ALTER TABLE "registration_ticket" ADD CONSTRAINT "FK_beba993576db0261a15364ea96e" FOREIGN KEY ("createdById") REFERENCES "user"("id") ON DELETE CASCADE ON UPDATE NO ACTION`);
|
|
||||||
await queryRunner.query(`ALTER TABLE "registration_ticket" ADD CONSTRAINT "FK_b6f93f2f30bdbb9a5ebdc7c7189" FOREIGN KEY ("usedById") REFERENCES "user"("id") ON DELETE CASCADE ON UPDATE NO ACTION`);
|
|
||||||
}
|
|
||||||
|
|
||||||
async down(queryRunner) {
|
|
||||||
await queryRunner.query(`ALTER TABLE "registration_ticket" DROP CONSTRAINT "FK_b6f93f2f30bdbb9a5ebdc7c7189"`);
|
|
||||||
await queryRunner.query(`ALTER TABLE "registration_ticket" DROP CONSTRAINT "FK_beba993576db0261a15364ea96e"`);
|
|
||||||
await queryRunner.query(`ALTER TABLE "registration_ticket" DROP CONSTRAINT "UQ_b6f93f2f30bdbb9a5ebdc7c7189"`);
|
|
||||||
await queryRunner.query(`ALTER TABLE "registration_ticket" DROP COLUMN "usedById"`);
|
|
||||||
await queryRunner.query(`ALTER TABLE "registration_ticket" DROP COLUMN "createdById"`);
|
|
||||||
await queryRunner.query(`ALTER TABLE "registration_ticket" DROP COLUMN "pendingUserId"`);
|
|
||||||
await queryRunner.query(`ALTER TABLE "registration_ticket" DROP COLUMN "usedAt"`);
|
|
||||||
await queryRunner.query(`ALTER TABLE "registration_ticket" DROP COLUMN "expiresAt"`);
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1,13 +0,0 @@
|
|||||||
export class AddIndexToRelations1688880985544 {
|
|
||||||
name = 'AddIndexToRelations1688880985544'
|
|
||||||
|
|
||||||
async up(queryRunner) {
|
|
||||||
await queryRunner.query(`CREATE INDEX "IDX_beba993576db0261a15364ea96" ON "registration_ticket" ("createdById") `);
|
|
||||||
await queryRunner.query(`CREATE INDEX "IDX_b6f93f2f30bdbb9a5ebdc7c718" ON "registration_ticket" ("usedById") `);
|
|
||||||
}
|
|
||||||
|
|
||||||
async down(queryRunner) {
|
|
||||||
await queryRunner.query(`DROP INDEX "public"."IDX_b6f93f2f30bdbb9a5ebdc7c718"`);
|
|
||||||
await queryRunner.query(`DROP INDEX "public"."IDX_beba993576db0261a15364ea96"`);
|
|
||||||
}
|
|
||||||
}
|
|
@@ -57,42 +57,44 @@
|
|||||||
"@aws-sdk/client-s3": "3.367.0",
|
"@aws-sdk/client-s3": "3.367.0",
|
||||||
"@aws-sdk/lib-storage": "3.367.0",
|
"@aws-sdk/lib-storage": "3.367.0",
|
||||||
"@aws-sdk/node-http-handler": "3.360.0",
|
"@aws-sdk/node-http-handler": "3.360.0",
|
||||||
"@bull-board/api": "5.6.1",
|
"@bull-board/api": "5.6.0",
|
||||||
"@bull-board/fastify": "5.6.1",
|
"@bull-board/fastify": "5.6.0",
|
||||||
"@bull-board/ui": "5.6.1",
|
"@bull-board/ui": "5.6.0",
|
||||||
"@discordapp/twemoji": "14.1.2",
|
"@discordapp/twemoji": "14.1.2",
|
||||||
"@fastify/accepts": "4.2.0",
|
"@fastify/accepts": "4.2.0",
|
||||||
"@fastify/cookie": "8.3.0",
|
"@fastify/cookie": "8.3.0",
|
||||||
"@fastify/cors": "8.3.0",
|
"@fastify/cors": "8.3.0",
|
||||||
"@fastify/http-proxy": "9.2.1",
|
"@fastify/http-proxy": "9.2.1",
|
||||||
"@fastify/multipart": "7.7.1",
|
"@fastify/multipart": "7.7.0",
|
||||||
"@fastify/static": "6.10.2",
|
"@fastify/static": "6.10.2",
|
||||||
"@fastify/view": "8.0.0",
|
"@fastify/view": "8.0.0",
|
||||||
"@nestjs/common": "10.1.0",
|
"@nestjs/common": "10.0.5",
|
||||||
"@nestjs/core": "10.1.0",
|
"@nestjs/core": "10.0.5",
|
||||||
"@nestjs/testing": "10.1.0",
|
"@nestjs/testing": "10.0.5",
|
||||||
"@peertube/http-signature": "1.7.0",
|
"@peertube/http-signature": "1.7.0",
|
||||||
"@sinonjs/fake-timers": "10.3.0",
|
"@sinonjs/fake-timers": "10.3.0",
|
||||||
"@swc/cli": "0.1.62",
|
"@swc/cli": "0.1.62",
|
||||||
"@swc/core": "1.3.70",
|
"@swc/core": "1.3.68",
|
||||||
"accepts": "1.3.8",
|
"accepts": "1.3.8",
|
||||||
"ajv": "8.12.0",
|
"ajv": "8.12.0",
|
||||||
"archiver": "5.3.1",
|
"archiver": "5.3.1",
|
||||||
"async-mutex": "^0.4.0",
|
"async-mutex": "^0.4.0",
|
||||||
|
"autwh": "0.1.0",
|
||||||
"bcryptjs": "2.4.3",
|
"bcryptjs": "2.4.3",
|
||||||
"blurhash": "2.0.5",
|
"blurhash": "2.0.5",
|
||||||
"bullmq": "4.4.0",
|
"bullmq": "4.2.0",
|
||||||
"cacheable-lookup": "7.0.0",
|
"cacheable-lookup": "7.0.0",
|
||||||
"cbor": "9.0.0",
|
"cbor": "9.0.0",
|
||||||
"chalk": "5.3.0",
|
"chalk": "5.2.0",
|
||||||
"chalk-template": "1.1.0",
|
"chalk-template": "0.4.0",
|
||||||
"chokidar": "3.5.3",
|
"chokidar": "3.5.3",
|
||||||
"cli-highlight": "2.1.11",
|
"cli-highlight": "2.1.11",
|
||||||
"color-convert": "2.0.1",
|
"color-convert": "2.0.1",
|
||||||
"content-disposition": "0.5.4",
|
"content-disposition": "0.5.4",
|
||||||
"date-fns": "2.30.0",
|
"date-fns": "2.30.0",
|
||||||
"deep-email-validator": "0.1.21",
|
"deep-email-validator": "0.1.21",
|
||||||
"fastify": "4.20.0",
|
"escape-regexp": "0.0.1",
|
||||||
|
"fastify": "4.19.2",
|
||||||
"feed": "4.2.2",
|
"feed": "4.2.2",
|
||||||
"file-type": "18.5.0",
|
"file-type": "18.5.0",
|
||||||
"fluent-ffmpeg": "2.1.2",
|
"fluent-ffmpeg": "2.1.2",
|
||||||
@@ -137,15 +139,16 @@
|
|||||||
"rename": "1.0.4",
|
"rename": "1.0.4",
|
||||||
"rss-parser": "3.13.0",
|
"rss-parser": "3.13.0",
|
||||||
"rxjs": "7.8.1",
|
"rxjs": "7.8.1",
|
||||||
|
"s-age": "1.1.2",
|
||||||
"sanitize-html": "2.11.0",
|
"sanitize-html": "2.11.0",
|
||||||
"semver": "7.5.4",
|
"semver": "7.5.3",
|
||||||
"sharp": "0.32.3",
|
"sharp": "0.32.1",
|
||||||
"sharp-read-bmp": "github:misskey-dev/sharp-read-bmp",
|
"sharp-read-bmp": "github:misskey-dev/sharp-read-bmp",
|
||||||
"slacc": "0.0.9",
|
"slacc": "0.0.9",
|
||||||
"strict-event-emitter-types": "2.0.0",
|
"strict-event-emitter-types": "2.0.0",
|
||||||
"stringz": "2.1.0",
|
"stringz": "2.1.0",
|
||||||
"summaly": "github:misskey-dev/summaly",
|
"summaly": "github:misskey-dev/summaly",
|
||||||
"systeminformation": "5.18.7",
|
"systeminformation": "5.18.6",
|
||||||
"tinycolor2": "1.6.0",
|
"tinycolor2": "1.6.0",
|
||||||
"tmp": "0.2.1",
|
"tmp": "0.2.1",
|
||||||
"tsc-alias": "1.8.7",
|
"tsc-alias": "1.8.7",
|
||||||
@@ -154,6 +157,8 @@
|
|||||||
"typeorm": "0.3.17",
|
"typeorm": "0.3.17",
|
||||||
"typescript": "5.1.6",
|
"typescript": "5.1.6",
|
||||||
"ulid": "2.3.0",
|
"ulid": "2.3.0",
|
||||||
|
"unzipper": "0.10.14",
|
||||||
|
"uuid": "9.0.0",
|
||||||
"vary": "1.1.2",
|
"vary": "1.1.2",
|
||||||
"web-push": "3.6.3",
|
"web-push": "3.6.3",
|
||||||
"ws": "8.13.0",
|
"ws": "8.13.0",
|
||||||
@@ -168,15 +173,16 @@
|
|||||||
"@types/cbor": "6.0.0",
|
"@types/cbor": "6.0.0",
|
||||||
"@types/color-convert": "2.0.0",
|
"@types/color-convert": "2.0.0",
|
||||||
"@types/content-disposition": "0.5.5",
|
"@types/content-disposition": "0.5.5",
|
||||||
|
"@types/escape-regexp": "0.0.1",
|
||||||
"@types/fluent-ffmpeg": "2.1.21",
|
"@types/fluent-ffmpeg": "2.1.21",
|
||||||
"@types/jest": "29.5.3",
|
"@types/jest": "29.5.2",
|
||||||
"@types/js-yaml": "4.0.5",
|
"@types/js-yaml": "4.0.5",
|
||||||
"@types/jsdom": "21.1.1",
|
"@types/jsdom": "21.1.1",
|
||||||
"@types/jsonld": "1.5.9",
|
"@types/jsonld": "1.5.9",
|
||||||
"@types/jsrsasign": "10.5.8",
|
"@types/jsrsasign": "10.5.8",
|
||||||
"@types/mime-types": "2.1.1",
|
"@types/mime-types": "2.1.1",
|
||||||
"@types/ms": "^0.7.31",
|
"@types/ms": "^0.7.31",
|
||||||
"@types/node": "20.4.2",
|
"@types/node": "20.4.0",
|
||||||
"@types/node-fetch": "3.0.3",
|
"@types/node-fetch": "3.0.3",
|
||||||
"@types/nodemailer": "6.4.8",
|
"@types/nodemailer": "6.4.8",
|
||||||
"@types/oauth": "0.9.1",
|
"@types/oauth": "0.9.1",
|
||||||
@@ -186,6 +192,7 @@
|
|||||||
"@types/qrcode": "1.5.1",
|
"@types/qrcode": "1.5.1",
|
||||||
"@types/random-seed": "0.3.3",
|
"@types/random-seed": "0.3.3",
|
||||||
"@types/ratelimiter": "3.4.4",
|
"@types/ratelimiter": "3.4.4",
|
||||||
|
"@types/redis": "4.0.11",
|
||||||
"@types/rename": "1.0.4",
|
"@types/rename": "1.0.4",
|
||||||
"@types/sanitize-html": "2.9.0",
|
"@types/sanitize-html": "2.9.0",
|
||||||
"@types/semver": "7.5.0",
|
"@types/semver": "7.5.0",
|
||||||
@@ -193,14 +200,17 @@
|
|||||||
"@types/sinonjs__fake-timers": "8.1.2",
|
"@types/sinonjs__fake-timers": "8.1.2",
|
||||||
"@types/tinycolor2": "1.4.3",
|
"@types/tinycolor2": "1.4.3",
|
||||||
"@types/tmp": "0.2.3",
|
"@types/tmp": "0.2.3",
|
||||||
|
"@types/unzipper": "0.10.6",
|
||||||
|
"@types/uuid": "9.0.2",
|
||||||
"@types/vary": "1.1.0",
|
"@types/vary": "1.1.0",
|
||||||
"@types/web-push": "3.3.2",
|
"@types/web-push": "3.3.2",
|
||||||
|
"@types/websocket": "1.0.5",
|
||||||
"@types/ws": "8.5.5",
|
"@types/ws": "8.5.5",
|
||||||
"@typescript-eslint/eslint-plugin": "5.61.0",
|
"@typescript-eslint/eslint-plugin": "5.61.0",
|
||||||
"@typescript-eslint/parser": "5.61.0",
|
"@typescript-eslint/parser": "5.61.0",
|
||||||
"aws-sdk-client-mock": "3.0.0",
|
"aws-sdk-client-mock": "3.0.0",
|
||||||
"cross-env": "7.0.3",
|
"cross-env": "7.0.3",
|
||||||
"eslint": "8.45.0",
|
"eslint": "8.44.0",
|
||||||
"eslint-plugin-import": "2.27.5",
|
"eslint-plugin-import": "2.27.5",
|
||||||
"execa": "7.1.1",
|
"execa": "7.1.1",
|
||||||
"jest": "29.6.1",
|
"jest": "29.6.1",
|
||||||
|
@@ -41,7 +41,14 @@ const $meilisearch: Provider = {
|
|||||||
const $redis: Provider = {
|
const $redis: Provider = {
|
||||||
provide: DI.redis,
|
provide: DI.redis,
|
||||||
useFactory: (config: Config) => {
|
useFactory: (config: Config) => {
|
||||||
return new Redis.Redis(config.redis);
|
return new Redis.Redis({
|
||||||
|
port: config.redis.port,
|
||||||
|
host: config.redis.host,
|
||||||
|
family: config.redis.family == null ? 0 : config.redis.family,
|
||||||
|
password: config.redis.pass,
|
||||||
|
keyPrefix: `${config.redis.prefix}:`,
|
||||||
|
db: config.redis.db ?? 0,
|
||||||
|
});
|
||||||
},
|
},
|
||||||
inject: [DI.config],
|
inject: [DI.config],
|
||||||
};
|
};
|
||||||
@@ -49,7 +56,14 @@ const $redis: Provider = {
|
|||||||
const $redisForPub: Provider = {
|
const $redisForPub: Provider = {
|
||||||
provide: DI.redisForPub,
|
provide: DI.redisForPub,
|
||||||
useFactory: (config: Config) => {
|
useFactory: (config: Config) => {
|
||||||
const redis = new Redis.Redis(config.redisForPubsub);
|
const redis = new Redis.Redis({
|
||||||
|
port: config.redisForPubsub.port,
|
||||||
|
host: config.redisForPubsub.host,
|
||||||
|
family: config.redisForPubsub.family == null ? 0 : config.redisForPubsub.family,
|
||||||
|
password: config.redisForPubsub.pass,
|
||||||
|
keyPrefix: `${config.redisForPubsub.prefix}:`,
|
||||||
|
db: config.redisForPubsub.db ?? 0,
|
||||||
|
});
|
||||||
return redis;
|
return redis;
|
||||||
},
|
},
|
||||||
inject: [DI.config],
|
inject: [DI.config],
|
||||||
@@ -58,7 +72,14 @@ const $redisForPub: Provider = {
|
|||||||
const $redisForSub: Provider = {
|
const $redisForSub: Provider = {
|
||||||
provide: DI.redisForSub,
|
provide: DI.redisForSub,
|
||||||
useFactory: (config: Config) => {
|
useFactory: (config: Config) => {
|
||||||
const redis = new Redis.Redis(config.redisForPubsub);
|
const redis = new Redis.Redis({
|
||||||
|
port: config.redisForPubsub.port,
|
||||||
|
host: config.redisForPubsub.host,
|
||||||
|
family: config.redisForPubsub.family == null ? 0 : config.redisForPubsub.family,
|
||||||
|
password: config.redisForPubsub.pass,
|
||||||
|
keyPrefix: `${config.redisForPubsub.prefix}:`,
|
||||||
|
db: config.redisForPubsub.db ?? 0,
|
||||||
|
});
|
||||||
redis.subscribe(config.host);
|
redis.subscribe(config.host);
|
||||||
return redis;
|
return redis;
|
||||||
},
|
},
|
||||||
|
@@ -31,7 +31,7 @@ function greet() {
|
|||||||
console.log(themeColor(' | |_|___ ___| |_ ___ _ _ '));
|
console.log(themeColor(' | |_|___ ___| |_ ___ _ _ '));
|
||||||
console.log(themeColor(' | | | | |_ -|_ -| \'_| -_| | |'));
|
console.log(themeColor(' | | | | |_ -|_ -| \'_| -_| | |'));
|
||||||
console.log(themeColor(' |_|_|_|_|___|___|_,_|___|_ |'));
|
console.log(themeColor(' |_|_|_|_|___|___|_,_|___|_ |'));
|
||||||
console.log(' ' + chalk.gray(v) + themeColor(' |___|\n'.substring(v.length)));
|
console.log(' ' + chalk.gray(v) + themeColor(' |___|\n'.substr(v.length)));
|
||||||
//#endregion
|
//#endregion
|
||||||
|
|
||||||
console.log(' Misskey is an open-source decentralized microblogging platform.');
|
console.log(' Misskey is an open-source decentralized microblogging platform.');
|
||||||
@@ -78,7 +78,7 @@ export async function masterMain() {
|
|||||||
await spawnWorkers(config.clusterLimit);
|
await spawnWorkers(config.clusterLimit);
|
||||||
}
|
}
|
||||||
|
|
||||||
bootLogger.succ(config.socket ? `Now listening on socket ${config.socket} on ${config.url}` : `Now listening on port ${config.port} on ${config.url}`, null, true);
|
bootLogger.succ(`Now listening on port ${config.port} on ${config.url}`, null, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
function showEnvironment(): void {
|
function showEnvironment(): void {
|
||||||
|
@@ -6,16 +6,6 @@ import * as fs from 'node:fs';
|
|||||||
import { fileURLToPath } from 'node:url';
|
import { fileURLToPath } from 'node:url';
|
||||||
import { dirname, resolve } from 'node:path';
|
import { dirname, resolve } from 'node:path';
|
||||||
import * as yaml from 'js-yaml';
|
import * as yaml from 'js-yaml';
|
||||||
import type { RedisOptions } from 'ioredis';
|
|
||||||
|
|
||||||
type RedisOptionsSource = Partial<RedisOptions> & {
|
|
||||||
host: string;
|
|
||||||
port: number;
|
|
||||||
family?: number;
|
|
||||||
pass: string;
|
|
||||||
db?: number;
|
|
||||||
prefix?: string;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ユーザーが設定する必要のある情報
|
* ユーザーが設定する必要のある情報
|
||||||
@@ -24,9 +14,7 @@ export type Source = {
|
|||||||
repository_url?: string;
|
repository_url?: string;
|
||||||
feedback_url?: string;
|
feedback_url?: string;
|
||||||
url: string;
|
url: string;
|
||||||
port?: number;
|
port: number;
|
||||||
socket?: string;
|
|
||||||
chmodSocket?: string;
|
|
||||||
disableHsts?: boolean;
|
disableHsts?: boolean;
|
||||||
db: {
|
db: {
|
||||||
host: string;
|
host: string;
|
||||||
@@ -45,16 +33,36 @@ export type Source = {
|
|||||||
user: string;
|
user: string;
|
||||||
pass: string;
|
pass: string;
|
||||||
}[];
|
}[];
|
||||||
redis: RedisOptionsSource;
|
redis: {
|
||||||
redisForPubsub?: RedisOptionsSource;
|
host: string;
|
||||||
redisForJobQueue?: RedisOptionsSource;
|
port: number;
|
||||||
|
family?: number;
|
||||||
|
pass: string;
|
||||||
|
db?: number;
|
||||||
|
prefix?: string;
|
||||||
|
};
|
||||||
|
redisForPubsub?: {
|
||||||
|
host: string;
|
||||||
|
port: number;
|
||||||
|
family?: number;
|
||||||
|
pass: string;
|
||||||
|
db?: number;
|
||||||
|
prefix?: string;
|
||||||
|
};
|
||||||
|
redisForJobQueue?: {
|
||||||
|
host: string;
|
||||||
|
port: number;
|
||||||
|
family?: number;
|
||||||
|
pass: string;
|
||||||
|
db?: number;
|
||||||
|
prefix?: string;
|
||||||
|
};
|
||||||
meilisearch?: {
|
meilisearch?: {
|
||||||
host: string;
|
host: string;
|
||||||
port: string;
|
port: string;
|
||||||
apiKey: string;
|
apiKey: string;
|
||||||
ssl?: boolean;
|
ssl?: boolean;
|
||||||
index: string;
|
index: string;
|
||||||
scope?: 'local' | 'global' | string[];
|
|
||||||
};
|
};
|
||||||
|
|
||||||
proxy?: string;
|
proxy?: string;
|
||||||
@@ -108,9 +116,8 @@ export type Mixin = {
|
|||||||
mediaProxy: string;
|
mediaProxy: string;
|
||||||
externalMediaProxyEnabled: boolean;
|
externalMediaProxyEnabled: boolean;
|
||||||
videoThumbnailGenerator: string | null;
|
videoThumbnailGenerator: string | null;
|
||||||
redis: RedisOptions & RedisOptionsSource;
|
redisForPubsub: NonNullable<Source['redisForPubsub']>;
|
||||||
redisForPubsub: RedisOptions & RedisOptionsSource;
|
redisForJobQueue: NonNullable<Source['redisForJobQueue']>;
|
||||||
redisForJobQueue: RedisOptions & RedisOptionsSource;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export type Config = Source & Mixin;
|
export type Config = Source & Mixin;
|
||||||
@@ -172,9 +179,9 @@ export function loadConfig() {
|
|||||||
config.videoThumbnailGenerator.endsWith('/') ? config.videoThumbnailGenerator.substring(0, config.videoThumbnailGenerator.length - 1) : config.videoThumbnailGenerator
|
config.videoThumbnailGenerator.endsWith('/') ? config.videoThumbnailGenerator.substring(0, config.videoThumbnailGenerator.length - 1) : config.videoThumbnailGenerator
|
||||||
: null;
|
: null;
|
||||||
|
|
||||||
mixin.redis = convertRedisOptions(config.redis, mixin.host);
|
if (!config.redis.prefix) config.redis.prefix = mixin.host;
|
||||||
mixin.redisForPubsub = config.redisForPubsub ? convertRedisOptions(config.redisForPubsub, mixin.host) : mixin.redis;
|
if (config.redisForPubsub == null) config.redisForPubsub = config.redis;
|
||||||
mixin.redisForJobQueue = config.redisForJobQueue ? convertRedisOptions(config.redisForJobQueue, mixin.host) : mixin.redis;
|
if (config.redisForJobQueue == null) config.redisForJobQueue = config.redis;
|
||||||
|
|
||||||
return Object.assign(config, mixin);
|
return Object.assign(config, mixin);
|
||||||
}
|
}
|
||||||
@@ -186,14 +193,3 @@ function tryCreateUrl(url: string) {
|
|||||||
throw new Error(`url="${url}" is not a valid URL.`);
|
throw new Error(`url="${url}" is not a valid URL.`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function convertRedisOptions(options: RedisOptionsSource, host: string): RedisOptions & RedisOptionsSource {
|
|
||||||
return {
|
|
||||||
...options,
|
|
||||||
password: options.pass,
|
|
||||||
prefix: options.prefix ?? host,
|
|
||||||
family: options.family == null ? 0 : options.family,
|
|
||||||
keyPrefix: `${options.prefix ?? host}:`,
|
|
||||||
db: options.db ?? 0,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
@@ -4,9 +4,10 @@ import { IsNull, In, MoreThan, Not } from 'typeorm';
|
|||||||
import { bindThis } from '@/decorators.js';
|
import { bindThis } from '@/decorators.js';
|
||||||
import { DI } from '@/di-symbols.js';
|
import { DI } from '@/di-symbols.js';
|
||||||
import type { Config } from '@/config.js';
|
import type { Config } from '@/config.js';
|
||||||
import type { LocalUser, RemoteUser, User } from '@/models/entities/User.js';
|
import type { LocalUser, RemoteUser } from '@/models/entities/User.js';
|
||||||
import type { BlockingsRepository, FollowingsRepository, InstancesRepository, Muting, MutingsRepository, UserListJoiningsRepository, UsersRepository } from '@/models/index.js';
|
import type { BlockingsRepository, FollowingsRepository, InstancesRepository, Muting, MutingsRepository, UserListJoiningsRepository, UsersRepository } from '@/models/index.js';
|
||||||
import type { RelationshipJobData, ThinUser } from '@/queue/types.js';
|
import type { RelationshipJobData, ThinUser } from '@/queue/types.js';
|
||||||
|
import type { User } from '@/models/entities/User.js';
|
||||||
|
|
||||||
import { IdService } from '@/core/IdService.js';
|
import { IdService } from '@/core/IdService.js';
|
||||||
import { GlobalEventService } from '@/core/GlobalEventService.js';
|
import { GlobalEventService } from '@/core/GlobalEventService.js';
|
||||||
|
@@ -81,7 +81,6 @@ import { GalleryLikeEntityService } from './entities/GalleryLikeEntityService.js
|
|||||||
import { GalleryPostEntityService } from './entities/GalleryPostEntityService.js';
|
import { GalleryPostEntityService } from './entities/GalleryPostEntityService.js';
|
||||||
import { HashtagEntityService } from './entities/HashtagEntityService.js';
|
import { HashtagEntityService } from './entities/HashtagEntityService.js';
|
||||||
import { InstanceEntityService } from './entities/InstanceEntityService.js';
|
import { InstanceEntityService } from './entities/InstanceEntityService.js';
|
||||||
import { InviteCodeEntityService } from './entities/InviteCodeEntityService.js';
|
|
||||||
import { ModerationLogEntityService } from './entities/ModerationLogEntityService.js';
|
import { ModerationLogEntityService } from './entities/ModerationLogEntityService.js';
|
||||||
import { MutingEntityService } from './entities/MutingEntityService.js';
|
import { MutingEntityService } from './entities/MutingEntityService.js';
|
||||||
import { RenoteMutingEntityService } from './entities/RenoteMutingEntityService.js';
|
import { RenoteMutingEntityService } from './entities/RenoteMutingEntityService.js';
|
||||||
@@ -206,7 +205,6 @@ const $GalleryLikeEntityService: Provider = { provide: 'GalleryLikeEntityService
|
|||||||
const $GalleryPostEntityService: Provider = { provide: 'GalleryPostEntityService', useExisting: GalleryPostEntityService };
|
const $GalleryPostEntityService: Provider = { provide: 'GalleryPostEntityService', useExisting: GalleryPostEntityService };
|
||||||
const $HashtagEntityService: Provider = { provide: 'HashtagEntityService', useExisting: HashtagEntityService };
|
const $HashtagEntityService: Provider = { provide: 'HashtagEntityService', useExisting: HashtagEntityService };
|
||||||
const $InstanceEntityService: Provider = { provide: 'InstanceEntityService', useExisting: InstanceEntityService };
|
const $InstanceEntityService: Provider = { provide: 'InstanceEntityService', useExisting: InstanceEntityService };
|
||||||
const $InviteCodeEntityService: Provider = { provide: 'InviteCodeEntityService', useExisting: InviteCodeEntityService };
|
|
||||||
const $ModerationLogEntityService: Provider = { provide: 'ModerationLogEntityService', useExisting: ModerationLogEntityService };
|
const $ModerationLogEntityService: Provider = { provide: 'ModerationLogEntityService', useExisting: ModerationLogEntityService };
|
||||||
const $MutingEntityService: Provider = { provide: 'MutingEntityService', useExisting: MutingEntityService };
|
const $MutingEntityService: Provider = { provide: 'MutingEntityService', useExisting: MutingEntityService };
|
||||||
const $RenoteMutingEntityService: Provider = { provide: 'RenoteMutingEntityService', useExisting: RenoteMutingEntityService };
|
const $RenoteMutingEntityService: Provider = { provide: 'RenoteMutingEntityService', useExisting: RenoteMutingEntityService };
|
||||||
@@ -331,7 +329,6 @@ const $ApQuestionService: Provider = { provide: 'ApQuestionService', useExisting
|
|||||||
GalleryPostEntityService,
|
GalleryPostEntityService,
|
||||||
HashtagEntityService,
|
HashtagEntityService,
|
||||||
InstanceEntityService,
|
InstanceEntityService,
|
||||||
InviteCodeEntityService,
|
|
||||||
ModerationLogEntityService,
|
ModerationLogEntityService,
|
||||||
MutingEntityService,
|
MutingEntityService,
|
||||||
RenoteMutingEntityService,
|
RenoteMutingEntityService,
|
||||||
@@ -451,7 +448,6 @@ const $ApQuestionService: Provider = { provide: 'ApQuestionService', useExisting
|
|||||||
$GalleryPostEntityService,
|
$GalleryPostEntityService,
|
||||||
$HashtagEntityService,
|
$HashtagEntityService,
|
||||||
$InstanceEntityService,
|
$InstanceEntityService,
|
||||||
$InviteCodeEntityService,
|
|
||||||
$ModerationLogEntityService,
|
$ModerationLogEntityService,
|
||||||
$MutingEntityService,
|
$MutingEntityService,
|
||||||
$RenoteMutingEntityService,
|
$RenoteMutingEntityService,
|
||||||
@@ -571,7 +567,6 @@ const $ApQuestionService: Provider = { provide: 'ApQuestionService', useExisting
|
|||||||
GalleryPostEntityService,
|
GalleryPostEntityService,
|
||||||
HashtagEntityService,
|
HashtagEntityService,
|
||||||
InstanceEntityService,
|
InstanceEntityService,
|
||||||
InviteCodeEntityService,
|
|
||||||
ModerationLogEntityService,
|
ModerationLogEntityService,
|
||||||
MutingEntityService,
|
MutingEntityService,
|
||||||
RenoteMutingEntityService,
|
RenoteMutingEntityService,
|
||||||
@@ -690,7 +685,6 @@ const $ApQuestionService: Provider = { provide: 'ApQuestionService', useExisting
|
|||||||
$GalleryPostEntityService,
|
$GalleryPostEntityService,
|
||||||
$HashtagEntityService,
|
$HashtagEntityService,
|
||||||
$InstanceEntityService,
|
$InstanceEntityService,
|
||||||
$InviteCodeEntityService,
|
|
||||||
$ModerationLogEntityService,
|
$ModerationLogEntityService,
|
||||||
$MutingEntityService,
|
$MutingEntityService,
|
||||||
$RenoteMutingEntityService,
|
$RenoteMutingEntityService,
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
import { randomUUID } from 'node:crypto';
|
|
||||||
import { Inject, Injectable } from '@nestjs/common';
|
import { Inject, Injectable } from '@nestjs/common';
|
||||||
import bcrypt from 'bcryptjs';
|
import bcrypt from 'bcryptjs';
|
||||||
|
import { v4 as uuid } from 'uuid';
|
||||||
import { IsNull, DataSource } from 'typeorm';
|
import { IsNull, DataSource } from 'typeorm';
|
||||||
import { genRsaKeyPair } from '@/misc/gen-key-pair.js';
|
import { genRsaKeyPair } from '@/misc/gen-key-pair.js';
|
||||||
import { User } from '@/models/entities/User.js';
|
import { User } from '@/models/entities/User.js';
|
||||||
@@ -24,7 +24,7 @@ export class CreateSystemUserService {
|
|||||||
|
|
||||||
@bindThis
|
@bindThis
|
||||||
public async createSystemUser(username: string): Promise<User> {
|
public async createSystemUser(username: string): Promise<User> {
|
||||||
const password = randomUUID();
|
const password = uuid();
|
||||||
|
|
||||||
// Generate hash of password
|
// Generate hash of password
|
||||||
const salt = await bcrypt.genSalt(8);
|
const salt = await bcrypt.genSalt(8);
|
||||||
@@ -33,7 +33,7 @@ export class CreateSystemUserService {
|
|||||||
// Generate secret
|
// Generate secret
|
||||||
const secret = generateNativeUserToken();
|
const secret = generateNativeUserToken();
|
||||||
|
|
||||||
const keyPair = await genRsaKeyPair();
|
const keyPair = await genRsaKeyPair(4096);
|
||||||
|
|
||||||
let account!: User;
|
let account!: User;
|
||||||
|
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
import { randomUUID } from 'node:crypto';
|
|
||||||
import * as fs from 'node:fs';
|
import * as fs from 'node:fs';
|
||||||
import { Inject, Injectable } from '@nestjs/common';
|
import { Inject, Injectable } from '@nestjs/common';
|
||||||
|
import { v4 as uuid } from 'uuid';
|
||||||
import sharp from 'sharp';
|
import sharp from 'sharp';
|
||||||
import { sharpBmp } from 'sharp-read-bmp';
|
import { sharpBmp } from 'sharp-read-bmp';
|
||||||
import { IsNull } from 'typeorm';
|
import { IsNull } from 'typeorm';
|
||||||
@@ -162,7 +162,7 @@ export class DriveService {
|
|||||||
?? `${ meta.objectStorageUseSSL ? 'https' : 'http' }://${ meta.objectStorageEndpoint }${ meta.objectStoragePort ? `:${meta.objectStoragePort}` : '' }/${ meta.objectStorageBucket }`;
|
?? `${ meta.objectStorageUseSSL ? 'https' : 'http' }://${ meta.objectStorageEndpoint }${ meta.objectStoragePort ? `:${meta.objectStoragePort}` : '' }/${ meta.objectStorageBucket }`;
|
||||||
|
|
||||||
// for original
|
// for original
|
||||||
const key = `${meta.objectStoragePrefix}/${randomUUID()}${ext}`;
|
const key = `${meta.objectStoragePrefix}/${uuid()}${ext}`;
|
||||||
const url = `${ baseUrl }/${ key }`;
|
const url = `${ baseUrl }/${ key }`;
|
||||||
|
|
||||||
// for alts
|
// for alts
|
||||||
@@ -179,7 +179,7 @@ export class DriveService {
|
|||||||
];
|
];
|
||||||
|
|
||||||
if (alts.webpublic) {
|
if (alts.webpublic) {
|
||||||
webpublicKey = `${meta.objectStoragePrefix}/webpublic-${randomUUID()}.${alts.webpublic.ext}`;
|
webpublicKey = `${meta.objectStoragePrefix}/webpublic-${uuid()}.${alts.webpublic.ext}`;
|
||||||
webpublicUrl = `${ baseUrl }/${ webpublicKey }`;
|
webpublicUrl = `${ baseUrl }/${ webpublicKey }`;
|
||||||
|
|
||||||
this.registerLogger.info(`uploading webpublic: ${webpublicKey}`);
|
this.registerLogger.info(`uploading webpublic: ${webpublicKey}`);
|
||||||
@@ -187,7 +187,7 @@ export class DriveService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (alts.thumbnail) {
|
if (alts.thumbnail) {
|
||||||
thumbnailKey = `${meta.objectStoragePrefix}/thumbnail-${randomUUID()}.${alts.thumbnail.ext}`;
|
thumbnailKey = `${meta.objectStoragePrefix}/thumbnail-${uuid()}.${alts.thumbnail.ext}`;
|
||||||
thumbnailUrl = `${ baseUrl }/${ thumbnailKey }`;
|
thumbnailUrl = `${ baseUrl }/${ thumbnailKey }`;
|
||||||
|
|
||||||
this.registerLogger.info(`uploading thumbnail: ${thumbnailKey}`);
|
this.registerLogger.info(`uploading thumbnail: ${thumbnailKey}`);
|
||||||
@@ -212,9 +212,9 @@ export class DriveService {
|
|||||||
|
|
||||||
return await this.driveFilesRepository.insert(file).then(x => this.driveFilesRepository.findOneByOrFail(x.identifiers[0]));
|
return await this.driveFilesRepository.insert(file).then(x => this.driveFilesRepository.findOneByOrFail(x.identifiers[0]));
|
||||||
} else { // use internal storage
|
} else { // use internal storage
|
||||||
const accessKey = randomUUID();
|
const accessKey = uuid();
|
||||||
const thumbnailAccessKey = 'thumbnail-' + randomUUID();
|
const thumbnailAccessKey = 'thumbnail-' + uuid();
|
||||||
const webpublicAccessKey = 'webpublic-' + randomUUID();
|
const webpublicAccessKey = 'webpublic-' + uuid();
|
||||||
|
|
||||||
const url = this.internalStorageService.saveFromPath(accessKey, path);
|
const url = this.internalStorageService.saveFromPath(accessKey, path);
|
||||||
|
|
||||||
@@ -584,9 +584,9 @@ export class DriveService {
|
|||||||
if (isLink) {
|
if (isLink) {
|
||||||
file.url = url;
|
file.url = url;
|
||||||
// ローカルプロキシ用
|
// ローカルプロキシ用
|
||||||
file.accessKey = randomUUID();
|
file.accessKey = uuid();
|
||||||
file.thumbnailAccessKey = 'thumbnail-' + randomUUID();
|
file.thumbnailAccessKey = 'thumbnail-' + uuid();
|
||||||
file.webpublicAccessKey = 'webpublic-' + randomUUID();
|
file.webpublicAccessKey = 'webpublic-' + uuid();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -713,9 +713,9 @@ export class DriveService {
|
|||||||
webpublicUrl: null,
|
webpublicUrl: null,
|
||||||
storedInternal: false,
|
storedInternal: false,
|
||||||
// ローカルプロキシ用
|
// ローカルプロキシ用
|
||||||
accessKey: randomUUID(),
|
accessKey: uuid(),
|
||||||
thumbnailAccessKey: 'thumbnail-' + randomUUID(),
|
thumbnailAccessKey: 'thumbnail-' + uuid(),
|
||||||
webpublicAccessKey: 'webpublic-' + randomUUID(),
|
webpublicAccessKey: 'webpublic-' + uuid(),
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
this.driveFilesRepository.delete(file.id);
|
this.driveFilesRepository.delete(file.id);
|
||||||
|
@@ -2,7 +2,6 @@ import { URL } from 'node:url';
|
|||||||
import { Inject, Injectable } from '@nestjs/common';
|
import { Inject, Injectable } from '@nestjs/common';
|
||||||
import { JSDOM } from 'jsdom';
|
import { JSDOM } from 'jsdom';
|
||||||
import tinycolor from 'tinycolor2';
|
import tinycolor from 'tinycolor2';
|
||||||
import * as Redis from 'ioredis';
|
|
||||||
import type { Instance } from '@/models/entities/Instance.js';
|
import type { Instance } from '@/models/entities/Instance.js';
|
||||||
import type Logger from '@/logger.js';
|
import type Logger from '@/logger.js';
|
||||||
import { DI } from '@/di-symbols.js';
|
import { DI } from '@/di-symbols.js';
|
||||||
@@ -11,6 +10,7 @@ import { HttpRequestService } from '@/core/HttpRequestService.js';
|
|||||||
import { bindThis } from '@/decorators.js';
|
import { bindThis } from '@/decorators.js';
|
||||||
import { FederatedInstanceService } from '@/core/FederatedInstanceService.js';
|
import { FederatedInstanceService } from '@/core/FederatedInstanceService.js';
|
||||||
import type { DOMWindow } from 'jsdom';
|
import type { DOMWindow } from 'jsdom';
|
||||||
|
import * as Redis from 'ioredis';
|
||||||
|
|
||||||
type NodeInfo = {
|
type NodeInfo = {
|
||||||
openRegistrations?: unknown;
|
openRegistrations?: unknown;
|
||||||
|
@@ -1,6 +1,5 @@
|
|||||||
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 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';
|
||||||
@@ -47,14 +46,14 @@ export class HttpRequestService {
|
|||||||
this.http = new http.Agent({
|
this.http = new http.Agent({
|
||||||
keepAlive: true,
|
keepAlive: true,
|
||||||
keepAliveMsecs: 30 * 1000,
|
keepAliveMsecs: 30 * 1000,
|
||||||
lookup: cache.lookup as unknown as net.LookupFunction,
|
lookup: cache.lookup,
|
||||||
});
|
} as http.AgentOptions);
|
||||||
|
|
||||||
this.https = new https.Agent({
|
this.https = new https.Agent({
|
||||||
keepAlive: true,
|
keepAlive: true,
|
||||||
keepAliveMsecs: 30 * 1000,
|
keepAliveMsecs: 30 * 1000,
|
||||||
lookup: cache.lookup as unknown as net.LookupFunction,
|
lookup: cache.lookup,
|
||||||
});
|
} as https.AgentOptions);
|
||||||
|
|
||||||
const maxSockets = Math.max(256, config.deliverJobConcurrency ?? 128);
|
const maxSockets = Math.max(256, config.deliverJobConcurrency ?? 128);
|
||||||
|
|
||||||
@@ -145,7 +144,7 @@ export class HttpRequestService {
|
|||||||
method: args.method ?? 'GET',
|
method: args.method ?? 'GET',
|
||||||
headers: {
|
headers: {
|
||||||
'User-Agent': this.config.userAgent,
|
'User-Agent': this.config.userAgent,
|
||||||
...(args.headers ?? {}),
|
...(args.headers ?? {})
|
||||||
},
|
},
|
||||||
body: args.body,
|
body: args.body,
|
||||||
size: args.size ?? 10 * 1024 * 1024,
|
size: args.size ?? 10 * 1024 * 1024,
|
||||||
|
@@ -574,7 +574,7 @@ export class NoteCreateService implements OnApplicationShutdown {
|
|||||||
where: {
|
where: {
|
||||||
userId: data.reply.userId,
|
userId: data.reply.userId,
|
||||||
threadId: data.reply.threadId ?? data.reply.id,
|
threadId: data.reply.threadId ?? data.reply.id,
|
||||||
},
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!isThreadMuted) {
|
if (!isThreadMuted) {
|
||||||
|
@@ -1,5 +1,5 @@
|
|||||||
import { randomUUID } from 'node:crypto';
|
|
||||||
import { Inject, Injectable } from '@nestjs/common';
|
import { Inject, Injectable } from '@nestjs/common';
|
||||||
|
import { v4 as uuid } from 'uuid';
|
||||||
import type { IActivity } from '@/core/activitypub/type.js';
|
import type { IActivity } from '@/core/activitypub/type.js';
|
||||||
import type { DriveFile } from '@/models/entities/DriveFile.js';
|
import type { DriveFile } from '@/models/entities/DriveFile.js';
|
||||||
import type { Webhook, webhookEventTypes } from '@/models/entities/Webhook.js';
|
import type { Webhook, webhookEventTypes } from '@/models/entities/Webhook.js';
|
||||||
@@ -108,7 +108,7 @@ export class QueueService {
|
|||||||
removeOnFail: true,
|
removeOnFail: true,
|
||||||
};
|
};
|
||||||
|
|
||||||
await this.deliverQueue.addBulk(Array.from(inboxes.entries(), d => ({
|
await this.deliverQueue.addBulk(Array.from(inboxes.entries()).map(d => ({
|
||||||
name: d[0],
|
name: d[0],
|
||||||
data: {
|
data: {
|
||||||
user,
|
user,
|
||||||
@@ -416,7 +416,7 @@ export class QueueService {
|
|||||||
to: webhook.url,
|
to: webhook.url,
|
||||||
secret: webhook.secret,
|
secret: webhook.secret,
|
||||||
createdAt: Date.now(),
|
createdAt: Date.now(),
|
||||||
eventId: randomUUID(),
|
eventId: uuid(),
|
||||||
};
|
};
|
||||||
|
|
||||||
return this.webhookDeliverQueue.add(webhook.id, data, {
|
return this.webhookDeliverQueue.add(webhook.id, data, {
|
||||||
|
@@ -8,9 +8,8 @@ import type { LocalUser, RemoteUser } from '@/models/entities/User.js';
|
|||||||
import type { Config } from '@/config.js';
|
import type { Config } from '@/config.js';
|
||||||
import type Logger from '@/logger.js';
|
import type Logger from '@/logger.js';
|
||||||
import { UtilityService } from '@/core/UtilityService.js';
|
import { UtilityService } from '@/core/UtilityService.js';
|
||||||
import { ILink, WebfingerService } from '@/core/WebfingerService.js';
|
import { WebfingerService } from '@/core/WebfingerService.js';
|
||||||
import { RemoteLoggerService } from '@/core/RemoteLoggerService.js';
|
import { RemoteLoggerService } from '@/core/RemoteLoggerService.js';
|
||||||
import { ApDbResolverService } from '@/core/activitypub/ApDbResolverService.js';
|
|
||||||
import { ApPersonService } from '@/core/activitypub/models/ApPersonService.js';
|
import { ApPersonService } from '@/core/activitypub/models/ApPersonService.js';
|
||||||
import { bindThis } from '@/decorators.js';
|
import { bindThis } from '@/decorators.js';
|
||||||
|
|
||||||
@@ -28,7 +27,6 @@ export class RemoteUserResolveService {
|
|||||||
private utilityService: UtilityService,
|
private utilityService: UtilityService,
|
||||||
private webfingerService: WebfingerService,
|
private webfingerService: WebfingerService,
|
||||||
private remoteLoggerService: RemoteLoggerService,
|
private remoteLoggerService: RemoteLoggerService,
|
||||||
private apDbResolverService: ApDbResolverService,
|
|
||||||
private apPersonService: ApPersonService,
|
private apPersonService: ApPersonService,
|
||||||
) {
|
) {
|
||||||
this.logger = this.remoteLoggerService.logger.createSubLogger('resolve-user');
|
this.logger = this.remoteLoggerService.logger.createSubLogger('resolve-user');
|
||||||
@@ -69,27 +67,11 @@ export class RemoteUserResolveService {
|
|||||||
if (user == null) {
|
if (user == null) {
|
||||||
const self = await this.resolveSelf(acctLower);
|
const self = await this.resolveSelf(acctLower);
|
||||||
|
|
||||||
if (self.href.startsWith(this.config.url)) {
|
|
||||||
const local = this.apDbResolverService.parseUri(self.href);
|
|
||||||
if (local.local && local.type === 'users') {
|
|
||||||
// the LR points to local
|
|
||||||
return (await this.apDbResolverService
|
|
||||||
.getUserFromApId(self.href)
|
|
||||||
.then((u) => {
|
|
||||||
if (u == null) {
|
|
||||||
throw new Error('local user not found');
|
|
||||||
} else {
|
|
||||||
return u;
|
|
||||||
}
|
|
||||||
})) as LocalUser;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
this.logger.succ(`return new remote user: ${chalk.magenta(acctLower)}`);
|
this.logger.succ(`return new remote user: ${chalk.magenta(acctLower)}`);
|
||||||
return await this.apPersonService.createPerson(self.href);
|
return await this.apPersonService.createPerson(self.href);
|
||||||
}
|
}
|
||||||
|
|
||||||
// ユーザー情報が古い場合は、WebFingerからやりなおして返す
|
// ユーザー情報が古い場合は、WebFilgerからやりなおして返す
|
||||||
if (user.lastFetchedAt == null || Date.now() - user.lastFetchedAt.getTime() > 1000 * 60 * 60 * 24) {
|
if (user.lastFetchedAt == null || Date.now() - user.lastFetchedAt.getTime() > 1000 * 60 * 60 * 24) {
|
||||||
// 繋がらないインスタンスに何回も試行するのを防ぐ, 後続の同様処理の連続試行を防ぐ ため 試行前にも更新する
|
// 繋がらないインスタンスに何回も試行するのを防ぐ, 後続の同様処理の連続試行を防ぐ ため 試行前にも更新する
|
||||||
await this.usersRepository.update(user.id, {
|
await this.usersRepository.update(user.id, {
|
||||||
@@ -137,7 +119,7 @@ export class RemoteUserResolveService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@bindThis
|
@bindThis
|
||||||
private async resolveSelf(acctLower: string): Promise<ILink> {
|
private async resolveSelf(acctLower: string) {
|
||||||
this.logger.info(`WebFinger for ${chalk.yellow(acctLower)}`);
|
this.logger.info(`WebFinger for ${chalk.yellow(acctLower)}`);
|
||||||
const finger = await this.webfingerService.webfinger(acctLower).catch(err => {
|
const finger = await this.webfingerService.webfinger(acctLower).catch(err => {
|
||||||
this.logger.error(`Failed to WebFinger for ${chalk.yellow(acctLower)}: ${ err.statusCode ?? err.message }`);
|
this.logger.error(`Failed to WebFinger for ${chalk.yellow(acctLower)}: ${ err.statusCode ?? err.message }`);
|
||||||
|
@@ -21,9 +21,6 @@ export type RolePolicies = {
|
|||||||
ltlAvailable: boolean;
|
ltlAvailable: boolean;
|
||||||
canPublicNote: boolean;
|
canPublicNote: boolean;
|
||||||
canInvite: boolean;
|
canInvite: boolean;
|
||||||
inviteLimit: number;
|
|
||||||
inviteLimitCycle: number;
|
|
||||||
inviteExpirationTime: number;
|
|
||||||
canManageCustomEmojis: boolean;
|
canManageCustomEmojis: boolean;
|
||||||
canSearchNotes: boolean;
|
canSearchNotes: boolean;
|
||||||
canHideAds: boolean;
|
canHideAds: boolean;
|
||||||
@@ -45,9 +42,6 @@ export const DEFAULT_POLICIES: RolePolicies = {
|
|||||||
ltlAvailable: true,
|
ltlAvailable: true,
|
||||||
canPublicNote: true,
|
canPublicNote: true,
|
||||||
canInvite: false,
|
canInvite: false,
|
||||||
inviteLimit: 0,
|
|
||||||
inviteLimitCycle: 60 * 24 * 7,
|
|
||||||
inviteExpirationTime: 0,
|
|
||||||
canManageCustomEmojis: false,
|
canManageCustomEmojis: false,
|
||||||
canSearchNotes: false,
|
canSearchNotes: false,
|
||||||
canHideAds: false,
|
canHideAds: false,
|
||||||
@@ -220,19 +214,14 @@ export class RoleService implements OnApplicationShutdown {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@bindThis
|
@bindThis
|
||||||
public async getUserAssigns(userId: User['id']) {
|
public async getUserRoles(userId: User['id']) {
|
||||||
const now = Date.now();
|
const now = Date.now();
|
||||||
let assigns = await this.roleAssignmentByUserIdCache.fetch(userId, () => this.roleAssignmentsRepository.findBy({ userId }));
|
let assigns = await this.roleAssignmentByUserIdCache.fetch(userId, () => this.roleAssignmentsRepository.findBy({ userId }));
|
||||||
// 期限切れのロールを除外
|
// 期限切れのロールを除外
|
||||||
assigns = assigns.filter(a => a.expiresAt == null || (a.expiresAt.getTime() > now));
|
assigns = assigns.filter(a => a.expiresAt == null || (a.expiresAt.getTime() > now));
|
||||||
return assigns;
|
const assignedRoleIds = assigns.map(x => x.roleId);
|
||||||
}
|
|
||||||
|
|
||||||
@bindThis
|
|
||||||
public async getUserRoles(userId: User['id']) {
|
|
||||||
const roles = await this.rolesCache.fetch(() => this.rolesRepository.findBy({}));
|
const roles = await this.rolesCache.fetch(() => this.rolesRepository.findBy({}));
|
||||||
const assigns = await this.getUserAssigns(userId);
|
const assignedRoles = roles.filter(r => assignedRoleIds.includes(r.id));
|
||||||
const assignedRoles = roles.filter(r => assigns.map(x => x.roleId).includes(r.id));
|
|
||||||
const user = roles.some(r => r.target === 'conditional') ? await this.cacheService.findUserById(userId) : null;
|
const user = roles.some(r => r.target === 'conditional') ? await this.cacheService.findUserById(userId) : null;
|
||||||
const matchedCondRoles = roles.filter(r => r.target === 'conditional' && this.evalCond(user!, r.condFormula));
|
const matchedCondRoles = roles.filter(r => r.target === 'conditional' && this.evalCond(user!, r.condFormula));
|
||||||
return [...assignedRoles, ...matchedCondRoles];
|
return [...assignedRoles, ...matchedCondRoles];
|
||||||
@@ -288,9 +277,6 @@ export class RoleService implements OnApplicationShutdown {
|
|||||||
ltlAvailable: calc('ltlAvailable', vs => vs.some(v => v === true)),
|
ltlAvailable: calc('ltlAvailable', vs => vs.some(v => v === true)),
|
||||||
canPublicNote: calc('canPublicNote', vs => vs.some(v => v === true)),
|
canPublicNote: calc('canPublicNote', vs => vs.some(v => v === true)),
|
||||||
canInvite: calc('canInvite', vs => vs.some(v => v === true)),
|
canInvite: calc('canInvite', vs => vs.some(v => v === true)),
|
||||||
inviteLimit: calc('inviteLimit', vs => Math.max(...vs)),
|
|
||||||
inviteLimitCycle: calc('inviteLimitCycle', vs => Math.max(...vs)),
|
|
||||||
inviteExpirationTime: calc('inviteExpirationTime', vs => Math.max(...vs)),
|
|
||||||
canManageCustomEmojis: calc('canManageCustomEmojis', vs => vs.some(v => v === true)),
|
canManageCustomEmojis: calc('canManageCustomEmojis', vs => vs.some(v => v === true)),
|
||||||
canSearchNotes: calc('canSearchNotes', vs => vs.some(v => v === true)),
|
canSearchNotes: calc('canSearchNotes', vs => vs.some(v => v === true)),
|
||||||
canHideAds: calc('canHideAds', vs => vs.some(v => v === true)),
|
canHideAds: calc('canHideAds', vs => vs.some(v => v === true)),
|
||||||
|
@@ -52,7 +52,6 @@ function compileQuery(q: Q): string {
|
|||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class SearchService {
|
export class SearchService {
|
||||||
private readonly meilisearchIndexScope: 'local' | 'global' | string[] = 'local';
|
|
||||||
private meilisearchNoteIndex: Index | null = null;
|
private meilisearchNoteIndex: Index | null = null;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
@@ -93,10 +92,6 @@ export class SearchService {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (config.meilisearch?.scope) {
|
|
||||||
this.meilisearchIndexScope = config.meilisearch.scope;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@bindThis
|
@bindThis
|
||||||
@@ -105,22 +100,7 @@ export class SearchService {
|
|||||||
if (!['home', 'public'].includes(note.visibility)) return;
|
if (!['home', 'public'].includes(note.visibility)) return;
|
||||||
|
|
||||||
if (this.meilisearch) {
|
if (this.meilisearch) {
|
||||||
switch (this.meilisearchIndexScope) {
|
this.meilisearchNoteIndex!.addDocuments([{
|
||||||
case 'global':
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'local':
|
|
||||||
if (note.userHost == null) break;
|
|
||||||
return;
|
|
||||||
|
|
||||||
default: {
|
|
||||||
if (note.userHost == null) break;
|
|
||||||
if (this.meilisearchIndexScope.includes(note.userHost)) break;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
await this.meilisearchNoteIndex?.addDocuments([{
|
|
||||||
id: note.id,
|
id: note.id,
|
||||||
createdAt: note.createdAt.getTime(),
|
createdAt: note.createdAt.getTime(),
|
||||||
userId: note.userId,
|
userId: note.userId,
|
||||||
|
@@ -92,7 +92,7 @@ export class SignupService {
|
|||||||
|
|
||||||
const keyPair = await new Promise<string[]>((res, rej) =>
|
const keyPair = await new Promise<string[]>((res, rej) =>
|
||||||
generateKeyPair('rsa', {
|
generateKeyPair('rsa', {
|
||||||
modulusLength: 2048,
|
modulusLength: 4096,
|
||||||
publicKeyEncoding: {
|
publicKeyEncoding: {
|
||||||
type: 'spki',
|
type: 'spki',
|
||||||
format: 'pem',
|
format: 'pem',
|
||||||
|
@@ -1,6 +1,5 @@
|
|||||||
import { Inject, Injectable, OnModuleInit, forwardRef } from '@nestjs/common';
|
import { Inject, Injectable, OnModuleInit, forwardRef } from '@nestjs/common';
|
||||||
import { ModuleRef } from '@nestjs/core';
|
import { ModuleRef } from '@nestjs/core';
|
||||||
import { IsNull } from 'typeorm';
|
|
||||||
import type { LocalUser, PartialLocalUser, PartialRemoteUser, RemoteUser, User } from '@/models/entities/User.js';
|
import type { LocalUser, PartialLocalUser, PartialRemoteUser, RemoteUser, User } from '@/models/entities/User.js';
|
||||||
import { IdentifiableError } from '@/misc/identifiable-error.js';
|
import { IdentifiableError } from '@/misc/identifiable-error.js';
|
||||||
import { QueueService } from '@/core/QueueService.js';
|
import { QueueService } from '@/core/QueueService.js';
|
||||||
@@ -22,8 +21,9 @@ import { UserBlockingService } from '@/core/UserBlockingService.js';
|
|||||||
import { MetaService } from '@/core/MetaService.js';
|
import { MetaService } from '@/core/MetaService.js';
|
||||||
import { CacheService } from '@/core/CacheService.js';
|
import { CacheService } from '@/core/CacheService.js';
|
||||||
import type { Config } from '@/config.js';
|
import type { Config } from '@/config.js';
|
||||||
import { AccountMoveService } from '@/core/AccountMoveService.js';
|
|
||||||
import Logger from '../logger.js';
|
import Logger from '../logger.js';
|
||||||
|
import { IsNull } from 'typeorm';
|
||||||
|
import { AccountMoveService } from '@/core/AccountMoveService.js';
|
||||||
|
|
||||||
const logger = new Logger('following/create');
|
const logger = new Logger('following/create');
|
||||||
|
|
||||||
@@ -322,7 +322,7 @@ export class UserFollowingService implements OnModuleInit {
|
|||||||
where: {
|
where: {
|
||||||
followerId: follower.id,
|
followerId: follower.id,
|
||||||
followeeId: followee.id,
|
followeeId: followee.id,
|
||||||
},
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
if (following === null || !following.follower || !following.followee) {
|
if (following === null || !following.follower || !following.followee) {
|
||||||
@@ -412,8 +412,8 @@ export class UserFollowingService implements OnModuleInit {
|
|||||||
followerId: user.id,
|
followerId: user.id,
|
||||||
followee: {
|
followee: {
|
||||||
movedToUri: IsNull(),
|
movedToUri: IsNull(),
|
||||||
},
|
}
|
||||||
},
|
}
|
||||||
});
|
});
|
||||||
const nonMovedFollowers = await this.followingsRepository.count({
|
const nonMovedFollowers = await this.followingsRepository.count({
|
||||||
relations: {
|
relations: {
|
||||||
@@ -423,8 +423,8 @@ export class UserFollowingService implements OnModuleInit {
|
|||||||
followeeId: user.id,
|
followeeId: user.id,
|
||||||
follower: {
|
follower: {
|
||||||
movedToUri: IsNull(),
|
movedToUri: IsNull(),
|
||||||
},
|
}
|
||||||
},
|
}
|
||||||
});
|
});
|
||||||
await this.usersRepository.update(
|
await this.usersRepository.update(
|
||||||
{ id: user.id },
|
{ id: user.id },
|
||||||
@@ -646,7 +646,7 @@ export class UserFollowingService implements OnModuleInit {
|
|||||||
where: {
|
where: {
|
||||||
followeeId: followee.id,
|
followeeId: followee.id,
|
||||||
followerId: follower.id,
|
followerId: follower.id,
|
||||||
},
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!following || !following.followee || !following.follower) return;
|
if (!following || !following.followee || !following.follower) return;
|
||||||
|
@@ -52,7 +52,7 @@ export class VideoProcessingService {
|
|||||||
query({
|
query({
|
||||||
thumbnail: '1',
|
thumbnail: '1',
|
||||||
url,
|
url,
|
||||||
}),
|
})
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -6,12 +6,12 @@ import { query as urlQuery } from '@/misc/prelude/url.js';
|
|||||||
import { HttpRequestService } from '@/core/HttpRequestService.js';
|
import { HttpRequestService } from '@/core/HttpRequestService.js';
|
||||||
import { bindThis } from '@/decorators.js';
|
import { bindThis } from '@/decorators.js';
|
||||||
|
|
||||||
export type ILink = {
|
type ILink = {
|
||||||
href: string;
|
href: string;
|
||||||
rel?: string;
|
rel?: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type IWebFinger = {
|
type IWebFinger = {
|
||||||
links: ILink[];
|
links: ILink[];
|
||||||
subject: string;
|
subject: string;
|
||||||
};
|
};
|
||||||
|
@@ -16,8 +16,6 @@ type AudienceInfo = {
|
|||||||
visibleUsers: User[],
|
visibleUsers: User[],
|
||||||
};
|
};
|
||||||
|
|
||||||
type GroupedAudience = Record<'public' | 'followers' | 'other', string[]>;
|
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class ApAudienceService {
|
export class ApAudienceService {
|
||||||
constructor(
|
constructor(
|
||||||
@@ -69,11 +67,11 @@ export class ApAudienceService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@bindThis
|
@bindThis
|
||||||
private groupingAudience(ids: string[], actor: RemoteUser): GroupedAudience {
|
private groupingAudience(ids: string[], actor: RemoteUser) {
|
||||||
const groups: GroupedAudience = {
|
const groups = {
|
||||||
public: [],
|
public: [] as string[],
|
||||||
followers: [],
|
followers: [] as string[],
|
||||||
other: [],
|
other: [] as string[],
|
||||||
};
|
};
|
||||||
|
|
||||||
for (const id of ids) {
|
for (const id of ids) {
|
||||||
@@ -92,16 +90,18 @@ export class ApAudienceService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@bindThis
|
@bindThis
|
||||||
private isPublic(id: string): boolean {
|
private isPublic(id: string) {
|
||||||
return [
|
return [
|
||||||
'https://www.w3.org/ns/activitystreams#Public',
|
'https://www.w3.org/ns/activitystreams#Public',
|
||||||
'as:Public',
|
'as#Public',
|
||||||
'Public',
|
'Public',
|
||||||
].includes(id);
|
].includes(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
@bindThis
|
@bindThis
|
||||||
private isFollowers(id: string, actor: RemoteUser): boolean {
|
private isFollowers(id: string, actor: RemoteUser) {
|
||||||
return id === (actor.followersUri ?? `${actor.uri}/followers`);
|
return (
|
||||||
|
id === (actor.followersUri ?? `${actor.uri}/followers`)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -99,15 +99,13 @@ export class ApDbResolverService implements OnApplicationShutdown {
|
|||||||
if (parsed.local) {
|
if (parsed.local) {
|
||||||
if (parsed.type !== 'users') return null;
|
if (parsed.type !== 'users') return null;
|
||||||
|
|
||||||
return await this.cacheService.userByIdCache.fetchMaybe(
|
return await this.cacheService.userByIdCache.fetchMaybe(parsed.id, () => this.usersRepository.findOneBy({
|
||||||
parsed.id,
|
id: parsed.id,
|
||||||
() => this.usersRepository.findOneBy({ id: parsed.id }).then(x => x ?? undefined),
|
}).then(x => x ?? undefined)) as LocalUser | undefined ?? null;
|
||||||
) as LocalUser | undefined ?? null;
|
|
||||||
} else {
|
} else {
|
||||||
return await this.cacheService.uriPersonCache.fetch(
|
return await this.cacheService.uriPersonCache.fetch(parsed.uri, () => this.usersRepository.findOneBy({
|
||||||
parsed.uri,
|
uri: parsed.uri,
|
||||||
() => this.usersRepository.findOneBy({ uri: parsed.uri }),
|
})) as RemoteUser | null;
|
||||||
) as RemoteUser | null;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -147,11 +145,9 @@ export class ApDbResolverService implements OnApplicationShutdown {
|
|||||||
} | null> {
|
} | null> {
|
||||||
const user = await this.apPersonService.resolvePerson(uri) as RemoteUser;
|
const user = await this.apPersonService.resolvePerson(uri) as RemoteUser;
|
||||||
|
|
||||||
const key = await this.publicKeyByUserIdCache.fetch(
|
if (user == null) return null;
|
||||||
user.id,
|
|
||||||
() => this.userPublickeysRepository.findOneBy({ userId: user.id }),
|
const key = await this.publicKeyByUserIdCache.fetch(user.id, () => this.userPublickeysRepository.findOneBy({ userId: user.id }), v => v != null);
|
||||||
v => v != null,
|
|
||||||
);
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
user,
|
user,
|
||||||
|
@@ -29,121 +29,6 @@ const isFollowers = (recipe: IRecipe): recipe is IFollowersRecipe =>
|
|||||||
const isDirect = (recipe: IRecipe): recipe is IDirectRecipe =>
|
const isDirect = (recipe: IRecipe): recipe is IDirectRecipe =>
|
||||||
recipe.type === 'Direct';
|
recipe.type === 'Direct';
|
||||||
|
|
||||||
class DeliverManager {
|
|
||||||
private actor: ThinUser;
|
|
||||||
private activity: IActivity | null;
|
|
||||||
private recipes: IRecipe[] = [];
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructor
|
|
||||||
* @param userEntityService
|
|
||||||
* @param followingsRepository
|
|
||||||
* @param queueService
|
|
||||||
* @param actor Actor
|
|
||||||
* @param activity Activity to deliver
|
|
||||||
*/
|
|
||||||
constructor(
|
|
||||||
private userEntityService: UserEntityService,
|
|
||||||
private followingsRepository: FollowingsRepository,
|
|
||||||
private queueService: QueueService,
|
|
||||||
|
|
||||||
actor: { id: User['id']; host: null; },
|
|
||||||
activity: IActivity | null,
|
|
||||||
) {
|
|
||||||
// 型で弾いてはいるが一応ローカルユーザーかチェック
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
|
||||||
if (actor.host != null) throw new Error('actor.host must be null');
|
|
||||||
|
|
||||||
// パフォーマンス向上のためキューに突っ込むのはidのみに絞る
|
|
||||||
this.actor = {
|
|
||||||
id: actor.id,
|
|
||||||
};
|
|
||||||
this.activity = activity;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Add recipe for followers deliver
|
|
||||||
*/
|
|
||||||
@bindThis
|
|
||||||
public addFollowersRecipe(): void {
|
|
||||||
const deliver: IFollowersRecipe = {
|
|
||||||
type: 'Followers',
|
|
||||||
};
|
|
||||||
|
|
||||||
this.addRecipe(deliver);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Add recipe for direct deliver
|
|
||||||
* @param to To
|
|
||||||
*/
|
|
||||||
@bindThis
|
|
||||||
public addDirectRecipe(to: RemoteUser): void {
|
|
||||||
const recipe: IDirectRecipe = {
|
|
||||||
type: 'Direct',
|
|
||||||
to,
|
|
||||||
};
|
|
||||||
|
|
||||||
this.addRecipe(recipe);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Add recipe
|
|
||||||
* @param recipe Recipe
|
|
||||||
*/
|
|
||||||
@bindThis
|
|
||||||
public addRecipe(recipe: IRecipe): void {
|
|
||||||
this.recipes.push(recipe);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Execute delivers
|
|
||||||
*/
|
|
||||||
@bindThis
|
|
||||||
public async execute(): Promise<void> {
|
|
||||||
// The value flags whether it is shared or not.
|
|
||||||
// key: inbox URL, value: whether it is sharedInbox
|
|
||||||
const inboxes = new Map<string, boolean>();
|
|
||||||
|
|
||||||
// build inbox list
|
|
||||||
// Process follower recipes first to avoid duplication when processing direct recipes later.
|
|
||||||
if (this.recipes.some(r => isFollowers(r))) {
|
|
||||||
// followers deliver
|
|
||||||
// TODO: SELECT DISTINCT ON ("followerSharedInbox") "followerSharedInbox" みたいな問い合わせにすればよりパフォーマンス向上できそう
|
|
||||||
// ただ、sharedInboxがnullなリモートユーザーも稀におり、その対応ができなさそう?
|
|
||||||
const followers = await this.followingsRepository.find({
|
|
||||||
where: {
|
|
||||||
followeeId: this.actor.id,
|
|
||||||
followerHost: Not(IsNull()),
|
|
||||||
},
|
|
||||||
select: {
|
|
||||||
followerSharedInbox: true,
|
|
||||||
followerInbox: true,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
for (const following of followers) {
|
|
||||||
const inbox = following.followerSharedInbox ?? following.followerInbox;
|
|
||||||
if (inbox === null) throw new Error('inbox is null');
|
|
||||||
inboxes.set(inbox, following.followerSharedInbox != null);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (const recipe of this.recipes.filter(isDirect)) {
|
|
||||||
// check that shared inbox has not been added yet
|
|
||||||
if (recipe.to.sharedInbox !== null && inboxes.has(recipe.to.sharedInbox)) continue;
|
|
||||||
|
|
||||||
// check that they actually have an inbox
|
|
||||||
if (recipe.to.inbox === null) continue;
|
|
||||||
|
|
||||||
inboxes.set(recipe.to.inbox, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
// deliver
|
|
||||||
this.queueService.deliverMany(this.actor, this.activity, inboxes);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class ApDeliverManagerService {
|
export class ApDeliverManagerService {
|
||||||
constructor(
|
constructor(
|
||||||
@@ -167,7 +52,7 @@ export class ApDeliverManagerService {
|
|||||||
* @param activity Activity
|
* @param activity Activity
|
||||||
*/
|
*/
|
||||||
@bindThis
|
@bindThis
|
||||||
public async deliverToFollowers(actor: { id: LocalUser['id']; host: null; }, activity: IActivity): Promise<void> {
|
public async deliverToFollowers(actor: { id: LocalUser['id']; host: null; }, activity: IActivity) {
|
||||||
const manager = new DeliverManager(
|
const manager = new DeliverManager(
|
||||||
this.userEntityService,
|
this.userEntityService,
|
||||||
this.followingsRepository,
|
this.followingsRepository,
|
||||||
@@ -186,7 +71,7 @@ export class ApDeliverManagerService {
|
|||||||
* @param to Target user
|
* @param to Target user
|
||||||
*/
|
*/
|
||||||
@bindThis
|
@bindThis
|
||||||
public async deliverToUser(actor: { id: LocalUser['id']; host: null; }, activity: IActivity, to: RemoteUser): Promise<void> {
|
public async deliverToUser(actor: { id: LocalUser['id']; host: null; }, activity: IActivity, to: RemoteUser) {
|
||||||
const manager = new DeliverManager(
|
const manager = new DeliverManager(
|
||||||
this.userEntityService,
|
this.userEntityService,
|
||||||
this.followingsRepository,
|
this.followingsRepository,
|
||||||
@@ -199,7 +84,7 @@ export class ApDeliverManagerService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@bindThis
|
@bindThis
|
||||||
public createDeliverManager(actor: { id: User['id']; host: null; }, activity: IActivity | null): DeliverManager {
|
public createDeliverManager(actor: { id: User['id']; host: null; }, activity: IActivity | null) {
|
||||||
return new DeliverManager(
|
return new DeliverManager(
|
||||||
this.userEntityService,
|
this.userEntityService,
|
||||||
this.followingsRepository,
|
this.followingsRepository,
|
||||||
@@ -210,3 +95,123 @@ export class ApDeliverManagerService {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class DeliverManager {
|
||||||
|
private actor: ThinUser;
|
||||||
|
private activity: IActivity | null;
|
||||||
|
private recipes: IRecipe[] = [];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor
|
||||||
|
* @param userEntityService
|
||||||
|
* @param followingsRepository
|
||||||
|
* @param queueService
|
||||||
|
* @param actor Actor
|
||||||
|
* @param activity Activity to deliver
|
||||||
|
*/
|
||||||
|
constructor(
|
||||||
|
private userEntityService: UserEntityService,
|
||||||
|
private followingsRepository: FollowingsRepository,
|
||||||
|
private queueService: QueueService,
|
||||||
|
|
||||||
|
actor: { id: User['id']; host: null; },
|
||||||
|
activity: IActivity | null,
|
||||||
|
) {
|
||||||
|
// 型で弾いてはいるが一応ローカルユーザーかチェック
|
||||||
|
if (actor.host != null) throw new Error('actor.host must be null');
|
||||||
|
|
||||||
|
// パフォーマンス向上のためキューに突っ込むのはidのみに絞る
|
||||||
|
this.actor = {
|
||||||
|
id: actor.id,
|
||||||
|
};
|
||||||
|
this.activity = activity;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add recipe for followers deliver
|
||||||
|
*/
|
||||||
|
@bindThis
|
||||||
|
public addFollowersRecipe() {
|
||||||
|
const deliver = {
|
||||||
|
type: 'Followers',
|
||||||
|
} as IFollowersRecipe;
|
||||||
|
|
||||||
|
this.addRecipe(deliver);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add recipe for direct deliver
|
||||||
|
* @param to To
|
||||||
|
*/
|
||||||
|
@bindThis
|
||||||
|
public addDirectRecipe(to: RemoteUser) {
|
||||||
|
const recipe = {
|
||||||
|
type: 'Direct',
|
||||||
|
to,
|
||||||
|
} as IDirectRecipe;
|
||||||
|
|
||||||
|
this.addRecipe(recipe);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add recipe
|
||||||
|
* @param recipe Recipe
|
||||||
|
*/
|
||||||
|
@bindThis
|
||||||
|
public addRecipe(recipe: IRecipe) {
|
||||||
|
this.recipes.push(recipe);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Execute delivers
|
||||||
|
*/
|
||||||
|
@bindThis
|
||||||
|
public async execute() {
|
||||||
|
// The value flags whether it is shared or not.
|
||||||
|
// key: inbox URL, value: whether it is sharedInbox
|
||||||
|
const inboxes = new Map<string, boolean>();
|
||||||
|
|
||||||
|
/*
|
||||||
|
build inbox list
|
||||||
|
|
||||||
|
Process follower recipes first to avoid duplication when processing
|
||||||
|
direct recipes later.
|
||||||
|
*/
|
||||||
|
if (this.recipes.some(r => isFollowers(r))) {
|
||||||
|
// followers deliver
|
||||||
|
// TODO: SELECT DISTINCT ON ("followerSharedInbox") "followerSharedInbox" みたいな問い合わせにすればよりパフォーマンス向上できそう
|
||||||
|
// ただ、sharedInboxがnullなリモートユーザーも稀におり、その対応ができなさそう?
|
||||||
|
const followers = await this.followingsRepository.find({
|
||||||
|
where: {
|
||||||
|
followeeId: this.actor.id,
|
||||||
|
followerHost: Not(IsNull()),
|
||||||
|
},
|
||||||
|
select: {
|
||||||
|
followerSharedInbox: true,
|
||||||
|
followerInbox: true,
|
||||||
|
},
|
||||||
|
}) as {
|
||||||
|
followerSharedInbox: string | null;
|
||||||
|
followerInbox: string;
|
||||||
|
}[];
|
||||||
|
|
||||||
|
for (const following of followers) {
|
||||||
|
const inbox = following.followerSharedInbox ?? following.followerInbox;
|
||||||
|
inboxes.set(inbox, following.followerSharedInbox != null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.recipes.filter((recipe): recipe is IDirectRecipe =>
|
||||||
|
// followers recipes have already been processed
|
||||||
|
isDirect(recipe)
|
||||||
|
// check that shared inbox has not been added yet
|
||||||
|
&& !(recipe.to.sharedInbox && inboxes.has(recipe.to.sharedInbox))
|
||||||
|
// check that they actually have an inbox
|
||||||
|
&& recipe.to.inbox != null,
|
||||||
|
)
|
||||||
|
.forEach(recipe => inboxes.set(recipe.to.inbox!, false));
|
||||||
|
|
||||||
|
// deliver
|
||||||
|
this.queueService.deliverMany(this.actor, this.activity, inboxes);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@@ -21,10 +21,10 @@ import { CacheService } from '@/core/CacheService.js';
|
|||||||
import { NoteEntityService } from '@/core/entities/NoteEntityService.js';
|
import { NoteEntityService } from '@/core/entities/NoteEntityService.js';
|
||||||
import { UserEntityService } from '@/core/entities/UserEntityService.js';
|
import { UserEntityService } from '@/core/entities/UserEntityService.js';
|
||||||
import { QueueService } from '@/core/QueueService.js';
|
import { QueueService } from '@/core/QueueService.js';
|
||||||
import type { UsersRepository, NotesRepository, FollowingsRepository, AbuseUserReportsRepository, FollowRequestsRepository } from '@/models/index.js';
|
import type { UsersRepository, NotesRepository, FollowingsRepository, AbuseUserReportsRepository, FollowRequestsRepository, } from '@/models/index.js';
|
||||||
import { bindThis } from '@/decorators.js';
|
import { bindThis } from '@/decorators.js';
|
||||||
import type { RemoteUser } from '@/models/entities/User.js';
|
import type { RemoteUser } from '@/models/entities/User.js';
|
||||||
import { getApHrefNullable, getApId, getApIds, getApType, isAccept, isActor, isAdd, isAnnounce, isBlock, isCollection, isCollectionOrOrderedCollection, isCreate, isDelete, isFlag, isFollow, isLike, isMove, isPost, isReject, isRemove, isTombstone, isUndo, isUpdate, validActor, validPost } from './type.js';
|
import { getApHrefNullable, getApId, getApIds, getApType, getOneApHrefNullable, isAccept, isActor, isAdd, isAnnounce, isBlock, isCollection, isCollectionOrOrderedCollection, isCreate, isDelete, isFlag, isFollow, isLike, isMove, isPost, isReject, isRemove, isTombstone, isUndo, isUpdate, validActor, validPost } from './type.js';
|
||||||
import { ApNoteService } from './models/ApNoteService.js';
|
import { ApNoteService } from './models/ApNoteService.js';
|
||||||
import { ApLoggerService } from './ApLoggerService.js';
|
import { ApLoggerService } from './ApLoggerService.js';
|
||||||
import { ApDbResolverService } from './ApDbResolverService.js';
|
import { ApDbResolverService } from './ApDbResolverService.js';
|
||||||
@@ -86,7 +86,7 @@ export class ApInboxService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@bindThis
|
@bindThis
|
||||||
public async performActivity(actor: RemoteUser, activity: IObject): Promise<void> {
|
public async performActivity(actor: RemoteUser, activity: IObject) {
|
||||||
if (isCollectionOrOrderedCollection(activity)) {
|
if (isCollectionOrOrderedCollection(activity)) {
|
||||||
const resolver = this.apResolverService.createResolver();
|
const resolver = this.apResolverService.createResolver();
|
||||||
for (const item of toArray(isCollection(activity) ? activity.items : activity.orderedItems)) {
|
for (const item of toArray(isCollection(activity) ? activity.items : activity.orderedItems)) {
|
||||||
@@ -107,7 +107,7 @@ export class ApInboxService {
|
|||||||
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(() => {
|
||||||
this.apPersonService.updatePerson(actor.uri);
|
this.apPersonService.updatePerson(actor.uri!);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -229,7 +229,7 @@ export class ApInboxService {
|
|||||||
|
|
||||||
@bindThis
|
@bindThis
|
||||||
private async add(actor: RemoteUser, activity: IAdd): Promise<void> {
|
private async add(actor: RemoteUser, activity: IAdd): Promise<void> {
|
||||||
if (actor.uri !== activity.actor) {
|
if ('actor' in activity && actor.uri !== activity.actor) {
|
||||||
throw new Error('invalid actor');
|
throw new Error('invalid actor');
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -273,7 +273,7 @@ export class ApInboxService {
|
|||||||
const unlock = await this.appLockService.getApLock(uri);
|
const unlock = await this.appLockService.getApLock(uri);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// 既に同じURIを持つものが登録されていないかチェック
|
// 既に同じURIを持つものが登録されていないかチェック
|
||||||
const exist = await this.apNoteService.fetchNote(uri);
|
const exist = await this.apNoteService.fetchNote(uri);
|
||||||
if (exist) {
|
if (exist) {
|
||||||
return;
|
return;
|
||||||
@@ -292,7 +292,7 @@ export class ApInboxService {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.logger.warn(`Error in announce target ${targetUri} - ${err.statusCode}`);
|
this.logger.warn(`Error in announce target ${targetUri} - ${err.statusCode ?? err}`);
|
||||||
}
|
}
|
||||||
throw err;
|
throw err;
|
||||||
}
|
}
|
||||||
@@ -409,7 +409,7 @@ export class ApInboxService {
|
|||||||
|
|
||||||
@bindThis
|
@bindThis
|
||||||
private async delete(actor: RemoteUser, activity: IDelete): Promise<string> {
|
private async delete(actor: RemoteUser, activity: IDelete): Promise<string> {
|
||||||
if (actor.uri !== activity.actor) {
|
if ('actor' in activity && actor.uri !== activity.actor) {
|
||||||
throw new Error('invalid actor');
|
throw new Error('invalid actor');
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -420,7 +420,7 @@ export class ApInboxService {
|
|||||||
// typeが不明だけど、どうせ消えてるのでremote resolveしない
|
// typeが不明だけど、どうせ消えてるのでremote resolveしない
|
||||||
formerType = undefined;
|
formerType = undefined;
|
||||||
} else {
|
} else {
|
||||||
const object = activity.object;
|
const object = activity.object as IObject;
|
||||||
if (isTombstone(object)) {
|
if (isTombstone(object)) {
|
||||||
formerType = toSingle(object.formerType);
|
formerType = toSingle(object.formerType);
|
||||||
} else {
|
} else {
|
||||||
@@ -503,10 +503,7 @@ export class ApInboxService {
|
|||||||
// 対象ユーザーは一番最初のユーザー として あとはコメントとして格納する
|
// 対象ユーザーは一番最初のユーザー として あとはコメントとして格納する
|
||||||
const uris = getApIds(activity.object);
|
const uris = getApIds(activity.object);
|
||||||
|
|
||||||
const userIds = uris
|
const userIds = uris.filter(uri => uri.startsWith(this.config.url + '/users/')).map(uri => uri.split('/').pop()!);
|
||||||
.filter(uri => uri.startsWith(this.config.url + '/users/'))
|
|
||||||
.map(uri => uri.split('/').at(-1))
|
|
||||||
.filter((userId): userId is string => userId !== undefined);
|
|
||||||
const users = await this.usersRepository.findBy({
|
const users = await this.usersRepository.findBy({
|
||||||
id: In(userIds),
|
id: In(userIds),
|
||||||
});
|
});
|
||||||
@@ -569,7 +566,7 @@ export class ApInboxService {
|
|||||||
|
|
||||||
@bindThis
|
@bindThis
|
||||||
private async remove(actor: RemoteUser, activity: IRemove): Promise<void> {
|
private async remove(actor: RemoteUser, activity: IRemove): Promise<void> {
|
||||||
if (actor.uri !== activity.actor) {
|
if ('actor' in activity && actor.uri !== activity.actor) {
|
||||||
throw new Error('invalid actor');
|
throw new Error('invalid actor');
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -589,7 +586,7 @@ export class ApInboxService {
|
|||||||
|
|
||||||
@bindThis
|
@bindThis
|
||||||
private async undo(actor: RemoteUser, activity: IUndo): Promise<string> {
|
private async undo(actor: RemoteUser, activity: IUndo): Promise<string> {
|
||||||
if (actor.uri !== activity.actor) {
|
if ('actor' in activity && actor.uri !== activity.actor) {
|
||||||
throw new Error('invalid actor');
|
throw new Error('invalid actor');
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -722,7 +719,7 @@ export class ApInboxService {
|
|||||||
|
|
||||||
@bindThis
|
@bindThis
|
||||||
private async update(actor: RemoteUser, activity: IUpdate): Promise<string> {
|
private async update(actor: RemoteUser, activity: IUpdate): Promise<string> {
|
||||||
if (actor.uri !== activity.actor) {
|
if ('actor' in activity && actor.uri !== activity.actor) {
|
||||||
return 'skip: invalid actor';
|
return 'skip: invalid actor';
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -736,7 +733,7 @@ export class ApInboxService {
|
|||||||
});
|
});
|
||||||
|
|
||||||
if (isActor(object)) {
|
if (isActor(object)) {
|
||||||
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, resolver).catch(err => console.error(err));
|
||||||
|
@@ -4,9 +4,9 @@ import { DI } from '@/di-symbols.js';
|
|||||||
import type { Config } from '@/config.js';
|
import type { Config } from '@/config.js';
|
||||||
import { MfmService } from '@/core/MfmService.js';
|
import { MfmService } from '@/core/MfmService.js';
|
||||||
import type { Note } from '@/models/entities/Note.js';
|
import type { Note } from '@/models/entities/Note.js';
|
||||||
import { bindThis } from '@/decorators.js';
|
|
||||||
import { extractApHashtagObjects } from './models/tag.js';
|
import { extractApHashtagObjects } from './models/tag.js';
|
||||||
import type { IObject } from './type.js';
|
import type { IObject } from './type.js';
|
||||||
|
import { bindThis } from '@/decorators.js';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class ApMfmService {
|
export class ApMfmService {
|
||||||
@@ -19,13 +19,14 @@ export class ApMfmService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@bindThis
|
@bindThis
|
||||||
public htmlToMfm(html: string, tag?: IObject | IObject[]): string {
|
public htmlToMfm(html: string, tag?: IObject | IObject[]) {
|
||||||
const hashtagNames = extractApHashtagObjects(tag).map(x => x.name);
|
const hashtagNames = extractApHashtagObjects(tag).map(x => x.name).filter((x): x is string => x != null);
|
||||||
|
|
||||||
return this.mfmService.fromHtml(html, hashtagNames);
|
return this.mfmService.fromHtml(html, hashtagNames);
|
||||||
}
|
}
|
||||||
|
|
||||||
@bindThis
|
@bindThis
|
||||||
public getNoteHtml(note: Note): string | null {
|
public getNoteHtml(note: Note) {
|
||||||
if (!note.text) return '';
|
if (!note.text) return '';
|
||||||
return this.mfmService.toHtml(mfm.parse(note.text), JSON.parse(note.mentionedRemoteUsers));
|
return this.mfmService.toHtml(mfm.parse(note.text), JSON.parse(note.mentionedRemoteUsers));
|
||||||
}
|
}
|
||||||
|
@@ -1,6 +1,7 @@
|
|||||||
import { createPublicKey, randomUUID } from 'node:crypto';
|
import { createPublicKey } from 'node:crypto';
|
||||||
import { Inject, Injectable } from '@nestjs/common';
|
import { Inject, Injectable } from '@nestjs/common';
|
||||||
import { In } from 'typeorm';
|
import { In, IsNull } from 'typeorm';
|
||||||
|
import { v4 as uuid } from 'uuid';
|
||||||
import * as mfm from 'mfm-js';
|
import * as mfm from 'mfm-js';
|
||||||
import { DI } from '@/di-symbols.js';
|
import { DI } from '@/di-symbols.js';
|
||||||
import type { Config } from '@/config.js';
|
import type { Config } from '@/config.js';
|
||||||
@@ -25,6 +26,7 @@ import { isNotNull } from '@/misc/is-not-null.js';
|
|||||||
import { LdSignatureService } from './LdSignatureService.js';
|
import { LdSignatureService } from './LdSignatureService.js';
|
||||||
import { ApMfmService } from './ApMfmService.js';
|
import { ApMfmService } from './ApMfmService.js';
|
||||||
import type { IAccept, IActivity, IAdd, IAnnounce, IApDocument, IApEmoji, IApHashtag, IApImage, IApMention, IBlock, ICreate, IDelete, IFlag, IFollow, IKey, ILike, IMove, IObject, IPost, IQuestion, IReject, IRemove, ITombstone, IUndo, IUpdate } from './type.js';
|
import type { IAccept, IActivity, IAdd, IAnnounce, IApDocument, IApEmoji, IApHashtag, IApImage, IApMention, IBlock, ICreate, IDelete, IFlag, IFollow, IKey, ILike, IMove, IObject, IPost, IQuestion, IReject, IRemove, ITombstone, IUndo, IUpdate } from './type.js';
|
||||||
|
import type { IIdentifier } from './models/identifier.js';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class ApRendererService {
|
export class ApRendererService {
|
||||||
@@ -61,7 +63,7 @@ export class ApRendererService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@bindThis
|
@bindThis
|
||||||
public renderAccept(object: string | IObject, user: { id: User['id']; host: null }): IAccept {
|
public renderAccept(object: any, user: { id: User['id']; host: null }): IAccept {
|
||||||
return {
|
return {
|
||||||
type: 'Accept',
|
type: 'Accept',
|
||||||
actor: this.userEntityService.genLocalUserUri(user.id),
|
actor: this.userEntityService.genLocalUserUri(user.id),
|
||||||
@@ -70,7 +72,7 @@ export class ApRendererService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@bindThis
|
@bindThis
|
||||||
public renderAdd(user: LocalUser, target: string | IObject | undefined, object: string | IObject): IAdd {
|
public renderAdd(user: LocalUser, target: any, object: any): IAdd {
|
||||||
return {
|
return {
|
||||||
type: 'Add',
|
type: 'Add',
|
||||||
actor: this.userEntityService.genLocalUserUri(user.id),
|
actor: this.userEntityService.genLocalUserUri(user.id),
|
||||||
@@ -80,7 +82,7 @@ export class ApRendererService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@bindThis
|
@bindThis
|
||||||
public renderAnnounce(object: string | IObject, note: Note): IAnnounce {
|
public renderAnnounce(object: any, note: Note): IAnnounce {
|
||||||
const attributedTo = this.userEntityService.genLocalUserUri(note.userId);
|
const attributedTo = this.userEntityService.genLocalUserUri(note.userId);
|
||||||
|
|
||||||
let to: string[] = [];
|
let to: string[] = [];
|
||||||
@@ -131,13 +133,13 @@ export class ApRendererService {
|
|||||||
|
|
||||||
@bindThis
|
@bindThis
|
||||||
public renderCreate(object: IObject, note: Note): ICreate {
|
public renderCreate(object: IObject, note: Note): ICreate {
|
||||||
const activity: ICreate = {
|
const activity = {
|
||||||
id: `${this.config.url}/notes/${note.id}/activity`,
|
id: `${this.config.url}/notes/${note.id}/activity`,
|
||||||
actor: this.userEntityService.genLocalUserUri(note.userId),
|
actor: this.userEntityService.genLocalUserUri(note.userId),
|
||||||
type: 'Create',
|
type: 'Create',
|
||||||
published: note.createdAt.toISOString(),
|
published: note.createdAt.toISOString(),
|
||||||
object,
|
object,
|
||||||
};
|
} as ICreate;
|
||||||
|
|
||||||
if (object.to) activity.to = object.to;
|
if (object.to) activity.to = object.to;
|
||||||
if (object.cc) activity.cc = object.cc;
|
if (object.cc) activity.cc = object.cc;
|
||||||
@@ -207,7 +209,7 @@ export class ApRendererService {
|
|||||||
* @param id Follower|Followee ID
|
* @param id Follower|Followee ID
|
||||||
*/
|
*/
|
||||||
@bindThis
|
@bindThis
|
||||||
public async renderFollowUser(id: User['id']): Promise<string> {
|
public async renderFollowUser(id: User['id']) {
|
||||||
const user = await this.usersRepository.findOneByOrFail({ id: id }) as PartialLocalUser | PartialRemoteUser;
|
const user = await this.usersRepository.findOneByOrFail({ id: id }) as PartialLocalUser | PartialRemoteUser;
|
||||||
return this.userEntityService.getUserUri(user);
|
return this.userEntityService.getUserUri(user);
|
||||||
}
|
}
|
||||||
@@ -221,8 +223,8 @@ export class ApRendererService {
|
|||||||
return {
|
return {
|
||||||
id: requestId ?? `${this.config.url}/follows/${follower.id}/${followee.id}`,
|
id: requestId ?? `${this.config.url}/follows/${follower.id}/${followee.id}`,
|
||||||
type: 'Follow',
|
type: 'Follow',
|
||||||
actor: this.userEntityService.getUserUri(follower),
|
actor: this.userEntityService.getUserUri(follower)!,
|
||||||
object: this.userEntityService.getUserUri(followee),
|
object: this.userEntityService.getUserUri(followee)!,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -262,14 +264,14 @@ export class ApRendererService {
|
|||||||
public async renderLike(noteReaction: NoteReaction, note: { uri: string | null }): Promise<ILike> {
|
public async renderLike(noteReaction: NoteReaction, note: { uri: string | null }): Promise<ILike> {
|
||||||
const reaction = noteReaction.reaction;
|
const reaction = noteReaction.reaction;
|
||||||
|
|
||||||
const object: ILike = {
|
const object = {
|
||||||
type: 'Like',
|
type: 'Like',
|
||||||
id: `${this.config.url}/likes/${noteReaction.id}`,
|
id: `${this.config.url}/likes/${noteReaction.id}`,
|
||||||
actor: `${this.config.url}/users/${noteReaction.userId}`,
|
actor: `${this.config.url}/users/${noteReaction.userId}`,
|
||||||
object: note.uri ? note.uri : `${this.config.url}/notes/${noteReaction.noteId}`,
|
object: note.uri ? note.uri : `${this.config.url}/notes/${noteReaction.noteId}`,
|
||||||
content: reaction,
|
content: reaction,
|
||||||
_misskey_reaction: reaction,
|
_misskey_reaction: reaction,
|
||||||
};
|
} as ILike;
|
||||||
|
|
||||||
if (reaction.startsWith(':')) {
|
if (reaction.startsWith(':')) {
|
||||||
const name = reaction.replaceAll(':', '');
|
const name = reaction.replaceAll(':', '');
|
||||||
@@ -285,7 +287,7 @@ export class ApRendererService {
|
|||||||
public renderMention(mention: PartialLocalUser | PartialRemoteUser): IApMention {
|
public renderMention(mention: PartialLocalUser | PartialRemoteUser): IApMention {
|
||||||
return {
|
return {
|
||||||
type: 'Mention',
|
type: 'Mention',
|
||||||
href: this.userEntityService.getUserUri(mention),
|
href: this.userEntityService.getUserUri(mention)!,
|
||||||
name: this.userEntityService.isRemoteUser(mention) ? `@${mention.username}@${mention.host}` : `@${(mention as LocalUser).username}`,
|
name: this.userEntityService.isRemoteUser(mention) ? `@${mention.username}@${mention.host}` : `@${(mention as LocalUser).username}`,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -295,8 +297,8 @@ export class ApRendererService {
|
|||||||
src: PartialLocalUser | PartialRemoteUser,
|
src: PartialLocalUser | PartialRemoteUser,
|
||||||
dst: PartialLocalUser | PartialRemoteUser,
|
dst: PartialLocalUser | PartialRemoteUser,
|
||||||
): IMove {
|
): IMove {
|
||||||
const actor = this.userEntityService.getUserUri(src);
|
const actor = this.userEntityService.getUserUri(src)!;
|
||||||
const target = this.userEntityService.getUserUri(dst);
|
const target = this.userEntityService.getUserUri(dst)!;
|
||||||
return {
|
return {
|
||||||
id: `${this.config.url}/moves/${src.id}/${dst.id}`,
|
id: `${this.config.url}/moves/${src.id}/${dst.id}`,
|
||||||
actor,
|
actor,
|
||||||
@@ -308,10 +310,10 @@ export class ApRendererService {
|
|||||||
|
|
||||||
@bindThis
|
@bindThis
|
||||||
public async renderNote(note: Note, dive = true): Promise<IPost> {
|
public async renderNote(note: Note, dive = true): Promise<IPost> {
|
||||||
const getPromisedFiles = async (ids: string[]): Promise<DriveFile[]> => {
|
const getPromisedFiles = async (ids: string[]) => {
|
||||||
if (ids.length === 0) return [];
|
if (!ids || ids.length === 0) return [];
|
||||||
const items = await this.driveFilesRepository.findBy({ id: In(ids) });
|
const items = await this.driveFilesRepository.findBy({ id: In(ids) });
|
||||||
return ids.map(id => items.find(item => item.id === id)).filter((item): item is DriveFile => item != null);
|
return ids.map(id => items.find(item => item.id === id)).filter(item => item != null) as DriveFile[];
|
||||||
};
|
};
|
||||||
|
|
||||||
let inReplyTo;
|
let inReplyTo;
|
||||||
@@ -373,7 +375,7 @@ export class ApRendererService {
|
|||||||
id: In(note.mentions),
|
id: In(note.mentions),
|
||||||
}) : [];
|
}) : [];
|
||||||
|
|
||||||
const hashtagTags = note.tags.map(tag => this.renderHashtag(tag));
|
const hashtagTags = (note.tags ?? []).map(tag => this.renderHashtag(tag));
|
||||||
const mentionTags = mentionedUsers.map(u => this.renderMention(u as LocalUser | RemoteUser));
|
const mentionTags = mentionedUsers.map(u => this.renderMention(u as LocalUser | RemoteUser));
|
||||||
|
|
||||||
const files = await getPromisedFiles(note.fileIds);
|
const files = await getPromisedFiles(note.fileIds);
|
||||||
@@ -449,26 +451,37 @@ export class ApRendererService {
|
|||||||
@bindThis
|
@bindThis
|
||||||
public async renderPerson(user: LocalUser) {
|
public async renderPerson(user: LocalUser) {
|
||||||
const id = this.userEntityService.genLocalUserUri(user.id);
|
const id = this.userEntityService.genLocalUserUri(user.id);
|
||||||
const isSystem = user.username.includes('.');
|
const isSystem = !!user.username.match(/\./);
|
||||||
|
|
||||||
const [avatar, banner, profile] = await Promise.all([
|
const [avatar, banner, profile] = await Promise.all([
|
||||||
user.avatarId ? this.driveFilesRepository.findOneBy({ id: user.avatarId }) : undefined,
|
user.avatarId ? this.driveFilesRepository.findOneBy({ id: user.avatarId }) : Promise.resolve(undefined),
|
||||||
user.bannerId ? this.driveFilesRepository.findOneBy({ id: user.bannerId }) : undefined,
|
user.bannerId ? this.driveFilesRepository.findOneBy({ id: user.bannerId }) : Promise.resolve(undefined),
|
||||||
this.userProfilesRepository.findOneByOrFail({ userId: user.id }),
|
this.userProfilesRepository.findOneByOrFail({ userId: user.id }),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
const attachment = profile.fields.map(field => ({
|
const attachment: {
|
||||||
type: 'PropertyValue',
|
type: 'PropertyValue',
|
||||||
name: field.name,
|
name: string,
|
||||||
value: /^https?:/.test(field.value)
|
value: string,
|
||||||
? `<a href="${new URL(field.value).href}" rel="me nofollow noopener" target="_blank">${new URL(field.value).href}</a>`
|
identifier?: IIdentifier,
|
||||||
: field.value,
|
}[] = [];
|
||||||
}));
|
|
||||||
|
if (profile.fields) {
|
||||||
|
for (const field of profile.fields) {
|
||||||
|
attachment.push({
|
||||||
|
type: 'PropertyValue',
|
||||||
|
name: field.name,
|
||||||
|
value: (field.value != null && field.value.match(/^https?:/))
|
||||||
|
? `<a href="${new URL(field.value).href}" rel="me nofollow noopener" target="_blank">${new URL(field.value).href}</a>`
|
||||||
|
: field.value,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const emojis = await this.getEmojis(user.emojis);
|
const emojis = await this.getEmojis(user.emojis);
|
||||||
const apemojis = emojis.filter(emoji => !emoji.localOnly).map(emoji => this.renderEmoji(emoji));
|
const apemojis = emojis.filter(emoji => !emoji.localOnly).map(emoji => this.renderEmoji(emoji));
|
||||||
|
|
||||||
const hashtagTags = user.tags.map(tag => this.renderHashtag(tag));
|
const hashtagTags = (user.tags ?? []).map(tag => this.renderHashtag(tag));
|
||||||
|
|
||||||
const tag = [
|
const tag = [
|
||||||
...apemojis,
|
...apemojis,
|
||||||
@@ -477,7 +490,7 @@ export class ApRendererService {
|
|||||||
|
|
||||||
const keypair = await this.userKeypairService.getUserKeypair(user.id);
|
const keypair = await this.userKeypairService.getUserKeypair(user.id);
|
||||||
|
|
||||||
const person: any = {
|
const person = {
|
||||||
type: isSystem ? 'Application' : user.isBot ? 'Service' : 'Person',
|
type: isSystem ? 'Application' : user.isBot ? 'Service' : 'Person',
|
||||||
id,
|
id,
|
||||||
inbox: `${id}/inbox`,
|
inbox: `${id}/inbox`,
|
||||||
@@ -495,11 +508,11 @@ export class ApRendererService {
|
|||||||
image: banner ? this.renderImage(banner) : null,
|
image: banner ? this.renderImage(banner) : null,
|
||||||
tag,
|
tag,
|
||||||
manuallyApprovesFollowers: user.isLocked,
|
manuallyApprovesFollowers: user.isLocked,
|
||||||
discoverable: user.isExplorable,
|
discoverable: !!user.isExplorable,
|
||||||
publicKey: this.renderKey(user, keypair, '#main-key'),
|
publicKey: this.renderKey(user, keypair, '#main-key'),
|
||||||
isCat: user.isCat,
|
isCat: user.isCat,
|
||||||
attachment: attachment.length ? attachment : undefined,
|
attachment: attachment.length ? attachment : undefined,
|
||||||
};
|
} as any;
|
||||||
|
|
||||||
if (user.movedToUri) {
|
if (user.movedToUri) {
|
||||||
person.movedTo = user.movedToUri;
|
person.movedTo = user.movedToUri;
|
||||||
@@ -539,7 +552,7 @@ export class ApRendererService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@bindThis
|
@bindThis
|
||||||
public renderReject(object: string | IObject, user: { id: User['id'] }): IReject {
|
public renderReject(object: any, user: { id: User['id'] }): IReject {
|
||||||
return {
|
return {
|
||||||
type: 'Reject',
|
type: 'Reject',
|
||||||
actor: this.userEntityService.genLocalUserUri(user.id),
|
actor: this.userEntityService.genLocalUserUri(user.id),
|
||||||
@@ -548,7 +561,7 @@ export class ApRendererService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@bindThis
|
@bindThis
|
||||||
public renderRemove(user: { id: User['id'] }, target: string | IObject | undefined, object: string | IObject): IRemove {
|
public renderRemove(user: { id: User['id'] }, target: any, object: any): IRemove {
|
||||||
return {
|
return {
|
||||||
type: 'Remove',
|
type: 'Remove',
|
||||||
actor: this.userEntityService.genLocalUserUri(user.id),
|
actor: this.userEntityService.genLocalUserUri(user.id),
|
||||||
@@ -566,8 +579,8 @@ export class ApRendererService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@bindThis
|
@bindThis
|
||||||
public renderUndo(object: string | IObject, user: { id: User['id'] }): IUndo {
|
public renderUndo(object: any, user: { id: User['id'] }): IUndo {
|
||||||
const id = typeof object !== 'string' && typeof object.id === 'string' && object.id.startsWith(this.config.url) ? `${object.id}/undo` : undefined;
|
const id = typeof object.id === 'string' && object.id.startsWith(this.config.url) ? `${object.id}/undo` : undefined;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
type: 'Undo',
|
type: 'Undo',
|
||||||
@@ -579,7 +592,7 @@ export class ApRendererService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@bindThis
|
@bindThis
|
||||||
public renderUpdate(object: string | IObject, user: { id: User['id'] }): IUpdate {
|
public renderUpdate(object: any, user: { id: User['id'] }): IUpdate {
|
||||||
return {
|
return {
|
||||||
id: `${this.config.url}/users/${user.id}#updates/${new Date().getTime()}`,
|
id: `${this.config.url}/users/${user.id}#updates/${new Date().getTime()}`,
|
||||||
actor: this.userEntityService.genLocalUserUri(user.id),
|
actor: this.userEntityService.genLocalUserUri(user.id),
|
||||||
@@ -612,7 +625,7 @@ export class ApRendererService {
|
|||||||
@bindThis
|
@bindThis
|
||||||
public addContext<T extends IObject>(x: T): T & { '@context': any; id: string; } {
|
public addContext<T extends IObject>(x: T): T & { '@context': any; id: string; } {
|
||||||
if (typeof x === 'object' && x.id == null) {
|
if (typeof x === 'object' && x.id == null) {
|
||||||
x.id = `${this.config.url}/${randomUUID()}`;
|
x.id = `${this.config.url}/${uuid()}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
return Object.assign({
|
return Object.assign({
|
||||||
@@ -645,7 +658,7 @@ export class ApRendererService {
|
|||||||
vcard: 'http://www.w3.org/2006/vcard/ns#',
|
vcard: 'http://www.w3.org/2006/vcard/ns#',
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
}, x as T & { id: string });
|
}, x as T & { id: string; });
|
||||||
}
|
}
|
||||||
|
|
||||||
@bindThis
|
@bindThis
|
||||||
@@ -670,13 +683,13 @@ export class ApRendererService {
|
|||||||
*/
|
*/
|
||||||
@bindThis
|
@bindThis
|
||||||
public renderOrderedCollectionPage(id: string, totalItems: any, orderedItems: any, partOf: string, prev?: string, next?: string) {
|
public renderOrderedCollectionPage(id: string, totalItems: any, orderedItems: any, partOf: string, prev?: string, next?: string) {
|
||||||
const page: any = {
|
const page = {
|
||||||
id,
|
id,
|
||||||
partOf,
|
partOf,
|
||||||
type: 'OrderedCollectionPage',
|
type: 'OrderedCollectionPage',
|
||||||
totalItems,
|
totalItems,
|
||||||
orderedItems,
|
orderedItems,
|
||||||
};
|
} as any;
|
||||||
|
|
||||||
if (prev) page.prev = prev;
|
if (prev) page.prev = prev;
|
||||||
if (next) page.next = next;
|
if (next) page.next = next;
|
||||||
@@ -693,7 +706,7 @@ export class ApRendererService {
|
|||||||
* @param orderedItems attached objects (optional)
|
* @param orderedItems attached objects (optional)
|
||||||
*/
|
*/
|
||||||
@bindThis
|
@bindThis
|
||||||
public renderOrderedCollection(id: string, totalItems: number, first?: string, last?: string, orderedItems?: IObject[]) {
|
public renderOrderedCollection(id: string | null, totalItems: any, first?: string, last?: string, orderedItems?: IObject[]) {
|
||||||
const page: any = {
|
const page: any = {
|
||||||
id,
|
id,
|
||||||
type: 'OrderedCollection',
|
type: 'OrderedCollection',
|
||||||
@@ -709,7 +722,7 @@ export class ApRendererService {
|
|||||||
|
|
||||||
@bindThis
|
@bindThis
|
||||||
private async getEmojis(names: string[]): Promise<Emoji[]> {
|
private async getEmojis(names: string[]): Promise<Emoji[]> {
|
||||||
if (names.length === 0) return [];
|
if (names == null || names.length === 0) return [];
|
||||||
|
|
||||||
const allEmojis = await this.customEmojiService.localEmojisCache.fetch();
|
const allEmojis = await this.customEmojiService.localEmojisCache.fetch();
|
||||||
const emojis = names.map(name => allEmojis.get(name)).filter(isNotNull);
|
const emojis = names.map(name => allEmojis.get(name)).filter(isNotNull);
|
||||||
|
@@ -140,7 +140,7 @@ export class ApRequestService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@bindThis
|
@bindThis
|
||||||
public async signedPost(user: { id: User['id'] }, url: string, object: unknown): Promise<void> {
|
public async signedPost(user: { id: User['id'] }, url: string, object: any) {
|
||||||
const body = JSON.stringify(object);
|
const body = JSON.stringify(object);
|
||||||
|
|
||||||
const keypair = await this.userKeypairService.getUserKeypair(user.id);
|
const keypair = await this.userKeypairService.getUserKeypair(user.id);
|
||||||
@@ -169,7 +169,7 @@ export class ApRequestService {
|
|||||||
* @param url URL to fetch
|
* @param url URL to fetch
|
||||||
*/
|
*/
|
||||||
@bindThis
|
@bindThis
|
||||||
public async signedGet(url: string, user: { id: User['id'] }): Promise<unknown> {
|
public async signedGet(url: string, user: { id: User['id'] }) {
|
||||||
const keypair = await this.userKeypairService.getUserKeypair(user.id);
|
const keypair = await this.userKeypairService.getUserKeypair(user.id);
|
||||||
|
|
||||||
const req = ApRequestCreator.createSignedGet({
|
const req = ApRequestCreator.createSignedGet({
|
||||||
|
@@ -61,6 +61,10 @@ export class Resolver {
|
|||||||
|
|
||||||
@bindThis
|
@bindThis
|
||||||
public async resolve(value: string | IObject): Promise<IObject> {
|
public async resolve(value: string | IObject): Promise<IObject> {
|
||||||
|
if (value == null) {
|
||||||
|
throw new Error('resolvee is null (or undefined)');
|
||||||
|
}
|
||||||
|
|
||||||
if (typeof value !== 'string') {
|
if (typeof value !== 'string') {
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
@@ -100,11 +104,11 @@ export class Resolver {
|
|||||||
? await this.apRequestService.signedGet(value, this.user) as IObject
|
? await this.apRequestService.signedGet(value, this.user) as IObject
|
||||||
: await this.httpRequestService.getJson(value, 'application/activity+json, application/ld+json')) as IObject;
|
: await this.httpRequestService.getJson(value, 'application/activity+json, application/ld+json')) as IObject;
|
||||||
|
|
||||||
if (
|
if (object == null || (
|
||||||
Array.isArray(object['@context']) ?
|
Array.isArray(object['@context']) ?
|
||||||
!(object['@context'] as unknown[]).includes('https://www.w3.org/ns/activitystreams') :
|
!(object['@context'] as unknown[]).includes('https://www.w3.org/ns/activitystreams') :
|
||||||
object['@context'] !== 'https://www.w3.org/ns/activitystreams'
|
object['@context'] !== 'https://www.w3.org/ns/activitystreams'
|
||||||
) {
|
)) {
|
||||||
throw new Error('invalid response');
|
throw new Error('invalid response');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -3,8 +3,6 @@ import { Injectable } from '@nestjs/common';
|
|||||||
import { HttpRequestService } from '@/core/HttpRequestService.js';
|
import { HttpRequestService } from '@/core/HttpRequestService.js';
|
||||||
import { bindThis } from '@/decorators.js';
|
import { bindThis } from '@/decorators.js';
|
||||||
import { CONTEXTS } from './misc/contexts.js';
|
import { CONTEXTS } from './misc/contexts.js';
|
||||||
import type { JsonLdDocument } from 'jsonld';
|
|
||||||
import type { JsonLd, RemoteDocument } from 'jsonld/jsonld-spec.js';
|
|
||||||
|
|
||||||
// RsaSignature2017 based from https://github.com/transmute-industries/RsaSignature2017
|
// RsaSignature2017 based from https://github.com/transmute-industries/RsaSignature2017
|
||||||
|
|
||||||
@@ -20,21 +18,22 @@ class LdSignature {
|
|||||||
|
|
||||||
@bindThis
|
@bindThis
|
||||||
public async signRsaSignature2017(data: any, privateKey: string, creator: string, domain?: string, created?: Date): Promise<any> {
|
public async signRsaSignature2017(data: any, privateKey: string, creator: string, domain?: string, created?: Date): Promise<any> {
|
||||||
const options: {
|
const options = {
|
||||||
|
type: 'RsaSignature2017',
|
||||||
|
creator,
|
||||||
|
domain,
|
||||||
|
nonce: crypto.randomBytes(16).toString('hex'),
|
||||||
|
created: (created ?? new Date()).toISOString(),
|
||||||
|
} as {
|
||||||
type: string;
|
type: string;
|
||||||
creator: string;
|
creator: string;
|
||||||
domain?: string;
|
domain?: string;
|
||||||
nonce: string;
|
nonce: string;
|
||||||
created: string;
|
created: string;
|
||||||
} = {
|
|
||||||
type: 'RsaSignature2017',
|
|
||||||
creator,
|
|
||||||
nonce: crypto.randomBytes(16).toString('hex'),
|
|
||||||
created: (created ?? new Date()).toISOString(),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
if (domain) {
|
if (!domain) {
|
||||||
options.domain = domain;
|
delete options.domain;
|
||||||
}
|
}
|
||||||
|
|
||||||
const toBeSigned = await this.createVerifyData(data, options);
|
const toBeSigned = await this.createVerifyData(data, options);
|
||||||
@@ -63,7 +62,7 @@ class LdSignature {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@bindThis
|
@bindThis
|
||||||
public async createVerifyData(data: any, options: any): Promise<string> {
|
public async createVerifyData(data: any, options: any) {
|
||||||
const transformedOptions = {
|
const transformedOptions = {
|
||||||
...options,
|
...options,
|
||||||
'@context': 'https://w3id.org/identity/v1',
|
'@context': 'https://w3id.org/identity/v1',
|
||||||
@@ -83,7 +82,7 @@ class LdSignature {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@bindThis
|
@bindThis
|
||||||
public async normalize(data: JsonLdDocument): Promise<string> {
|
public async normalize(data: any) {
|
||||||
const customLoader = this.getLoader();
|
const customLoader = this.getLoader();
|
||||||
// XXX: Importing jsonld dynamically since Jest frequently fails to import it statically
|
// XXX: Importing jsonld dynamically since Jest frequently fails to import it statically
|
||||||
// https://github.com/misskey-dev/misskey/pull/9894#discussion_r1103753595
|
// https://github.com/misskey-dev/misskey/pull/9894#discussion_r1103753595
|
||||||
@@ -94,14 +93,14 @@ class LdSignature {
|
|||||||
|
|
||||||
@bindThis
|
@bindThis
|
||||||
private getLoader() {
|
private getLoader() {
|
||||||
return async (url: string): Promise<RemoteDocument> => {
|
return async (url: string): Promise<any> => {
|
||||||
if (!/^https?:\/\//.test(url)) throw new Error(`Invalid URL ${url}`);
|
if (!url.match('^https?\:\/\/')) throw new Error(`Invalid URL ${url}`);
|
||||||
|
|
||||||
if (this.preLoad) {
|
if (this.preLoad) {
|
||||||
if (url in CONTEXTS) {
|
if (url in CONTEXTS) {
|
||||||
if (this.debug) console.debug(`HIT: ${url}`);
|
if (this.debug) console.debug(`HIT: ${url}`);
|
||||||
return {
|
return {
|
||||||
contextUrl: undefined,
|
contextUrl: null,
|
||||||
document: CONTEXTS[url],
|
document: CONTEXTS[url],
|
||||||
documentUrl: url,
|
documentUrl: url,
|
||||||
};
|
};
|
||||||
@@ -111,7 +110,7 @@ class LdSignature {
|
|||||||
if (this.debug) console.debug(`MISS: ${url}`);
|
if (this.debug) console.debug(`MISS: ${url}`);
|
||||||
const document = await this.fetchDocument(url);
|
const document = await this.fetchDocument(url);
|
||||||
return {
|
return {
|
||||||
contextUrl: undefined,
|
contextUrl: null,
|
||||||
document: document,
|
document: document,
|
||||||
documentUrl: url,
|
documentUrl: url,
|
||||||
};
|
};
|
||||||
@@ -119,17 +118,13 @@ class LdSignature {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@bindThis
|
@bindThis
|
||||||
private async fetchDocument(url: string): Promise<JsonLd> {
|
private async fetchDocument(url: string) {
|
||||||
const json = await this.httpRequestService.send(
|
const json = await this.httpRequestService.send(url, {
|
||||||
url,
|
headers: {
|
||||||
{
|
Accept: 'application/ld+json, application/json',
|
||||||
headers: {
|
|
||||||
Accept: 'application/ld+json, application/json',
|
|
||||||
},
|
|
||||||
timeout: this.loderTimeout,
|
|
||||||
},
|
},
|
||||||
{ throwErrorWhenResponseNotOk: false },
|
timeout: this.loderTimeout,
|
||||||
).then(res => {
|
}, { throwErrorWhenResponseNotOk: false }).then(res => {
|
||||||
if (!res.ok) {
|
if (!res.ok) {
|
||||||
throw new Error(`${res.status} ${res.statusText}`);
|
throw new Error(`${res.status} ${res.statusText}`);
|
||||||
} else {
|
} else {
|
||||||
@@ -137,7 +132,7 @@ class LdSignature {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
return json as JsonLd;
|
return json;
|
||||||
}
|
}
|
||||||
|
|
||||||
@bindThis
|
@bindThis
|
||||||
|
@@ -1,5 +1,3 @@
|
|||||||
import type { JsonLd } from 'jsonld/jsonld-spec.js';
|
|
||||||
|
|
||||||
/* eslint:disable:quotemark indent */
|
/* eslint:disable:quotemark indent */
|
||||||
const id_v1 = {
|
const id_v1 = {
|
||||||
'@context': {
|
'@context': {
|
||||||
@@ -88,7 +86,7 @@ const id_v1 = {
|
|||||||
'accessControl': { '@id': 'perm:accessControl', '@type': '@id' },
|
'accessControl': { '@id': 'perm:accessControl', '@type': '@id' },
|
||||||
'writePermission': { '@id': 'perm:writePermission', '@type': '@id' },
|
'writePermission': { '@id': 'perm:writePermission', '@type': '@id' },
|
||||||
},
|
},
|
||||||
} satisfies JsonLd;
|
};
|
||||||
|
|
||||||
const security_v1 = {
|
const security_v1 = {
|
||||||
'@context': {
|
'@context': {
|
||||||
@@ -139,7 +137,7 @@ const security_v1 = {
|
|||||||
'signatureAlgorithm': 'sec:signingAlgorithm',
|
'signatureAlgorithm': 'sec:signingAlgorithm',
|
||||||
'signatureValue': 'sec:signatureValue',
|
'signatureValue': 'sec:signatureValue',
|
||||||
},
|
},
|
||||||
} satisfies JsonLd;
|
};
|
||||||
|
|
||||||
const activitystreams = {
|
const activitystreams = {
|
||||||
'@context': {
|
'@context': {
|
||||||
@@ -519,9 +517,9 @@ const activitystreams = {
|
|||||||
'@type': '@id',
|
'@type': '@id',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
} satisfies JsonLd;
|
};
|
||||||
|
|
||||||
export const CONTEXTS: Record<string, JsonLd> = {
|
export const CONTEXTS: Record<string, unknown> = {
|
||||||
'https://w3id.org/identity/v1': id_v1,
|
'https://w3id.org/identity/v1': id_v1,
|
||||||
'https://w3id.org/security/v1': security_v1,
|
'https://w3id.org/security/v1': security_v1,
|
||||||
'https://www.w3.org/ns/activitystreams': activitystreams,
|
'https://www.w3.org/ns/activitystreams': activitystreams,
|
||||||
|
@@ -200,7 +200,7 @@ export class ApNoteService {
|
|||||||
| { status: 'ok'; res: Note }
|
| { status: 'ok'; res: Note }
|
||||||
| { status: 'permerror' | 'temperror' }
|
| { status: 'permerror' | 'temperror' }
|
||||||
> => {
|
> => {
|
||||||
if (!/^https?:/.test(uri)) return { status: 'permerror' };
|
if (!uri.match(/^https?:/)) return { status: 'permerror' };
|
||||||
try {
|
try {
|
||||||
const res = await this.resolveNote(uri);
|
const res = await this.resolveNote(uri);
|
||||||
if (res == null) return { status: 'permerror' };
|
if (res == null) return { status: 'permerror' };
|
||||||
|
@@ -220,23 +220,6 @@ export class ApPersonService implements OnModuleInit {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private async resolveAvatarAndBanner(user: RemoteUser, icon: any, image: any): Promise<Pick<RemoteUser, 'avatarId' | 'bannerId' | 'avatarUrl' | 'bannerUrl' | 'avatarBlurhash' | 'bannerBlurhash'>> {
|
|
||||||
const [avatar, banner] = await Promise.all([icon, image].map(img => {
|
|
||||||
if (img == null) return null;
|
|
||||||
if (user == null) throw new Error('failed to create user: user is null');
|
|
||||||
return this.apImageService.resolveImage(user, img).catch(() => null);
|
|
||||||
}));
|
|
||||||
|
|
||||||
return {
|
|
||||||
avatarId: avatar?.id ?? null,
|
|
||||||
bannerId: banner?.id ?? null,
|
|
||||||
avatarUrl: avatar ? this.driveFileEntityService.getPublicUrl(avatar, 'avatar') : null,
|
|
||||||
bannerUrl: banner ? this.driveFileEntityService.getPublicUrl(banner) : null,
|
|
||||||
avatarBlurhash: avatar?.blurhash ?? null,
|
|
||||||
bannerBlurhash: banner?.blurhash ?? null,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Personを作成します。
|
* Personを作成します。
|
||||||
*/
|
*/
|
||||||
@@ -276,16 +259,6 @@ export class ApPersonService implements OnModuleInit {
|
|||||||
|
|
||||||
// Create user
|
// Create user
|
||||||
let user: RemoteUser | null = null;
|
let user: RemoteUser | null = null;
|
||||||
|
|
||||||
//#region カスタム絵文字取得
|
|
||||||
const emojis = await this.apNoteService.extractEmojis(person.tag ?? [], host)
|
|
||||||
.then(_emojis => _emojis.map(emoji => emoji.name))
|
|
||||||
.catch(err => {
|
|
||||||
this.logger.error(`error occured while fetching user emojis`, { stack: err });
|
|
||||||
return [];
|
|
||||||
});
|
|
||||||
//#endregion
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Start transaction
|
// Start transaction
|
||||||
await this.db.transaction(async transactionalEntityManager => {
|
await this.db.transaction(async transactionalEntityManager => {
|
||||||
@@ -312,7 +285,6 @@ export class ApPersonService implements OnModuleInit {
|
|||||||
tags,
|
tags,
|
||||||
isBot,
|
isBot,
|
||||||
isCat: (person as any).isCat === true,
|
isCat: (person as any).isCat === true,
|
||||||
emojis,
|
|
||||||
})) as RemoteUser;
|
})) as RemoteUser;
|
||||||
|
|
||||||
await transactionalEntityManager.save(new UserProfile({
|
await transactionalEntityManager.save(new UserProfile({
|
||||||
@@ -349,9 +321,6 @@ 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');
|
||||||
|
|
||||||
// Register to the cache
|
|
||||||
this.cacheService.uriPersonCache.set(user.uri, user);
|
|
||||||
|
|
||||||
// Register host
|
// Register host
|
||||||
this.federatedInstanceService.fetch(host).then(async i => {
|
this.federatedInstanceService.fetch(host).then(async i => {
|
||||||
this.instancesRepository.increment({ id: i.id }, 'usersCount', 1);
|
this.instancesRepository.increment({ id: i.id }, 'usersCount', 1);
|
||||||
@@ -367,16 +336,45 @@ export class ApPersonService implements OnModuleInit {
|
|||||||
this.hashtagService.updateUsertags(user, tags);
|
this.hashtagService.updateUsertags(user, tags);
|
||||||
|
|
||||||
//#region アバターとヘッダー画像をフェッチ
|
//#region アバターとヘッダー画像をフェッチ
|
||||||
try {
|
const [avatar, banner] = await Promise.all([person.icon, person.image].map(img => {
|
||||||
const updates = await this.resolveAvatarAndBanner(user, person.icon, person.image);
|
if (img == null) return null;
|
||||||
await this.usersRepository.update(user.id, updates);
|
if (user == null) throw new Error('failed to create user: user is null');
|
||||||
user = { ...user, ...updates };
|
return this.apImageService.resolveImage(user, img).catch(() => null);
|
||||||
|
}));
|
||||||
|
|
||||||
// Register to the cache
|
const avatarId = avatar?.id ?? null;
|
||||||
this.cacheService.uriPersonCache.set(user.uri, user);
|
const bannerId = banner?.id ?? null;
|
||||||
} catch (err) {
|
const avatarUrl = avatar ? this.driveFileEntityService.getPublicUrl(avatar, 'avatar') : null;
|
||||||
this.logger.error('error occured while fetching user avatar/banner', { stack: err });
|
const bannerUrl = banner ? this.driveFileEntityService.getPublicUrl(banner) : null;
|
||||||
}
|
const avatarBlurhash = avatar?.blurhash ?? null;
|
||||||
|
const bannerBlurhash = banner?.blurhash ?? null;
|
||||||
|
|
||||||
|
await this.usersRepository.update(user.id, {
|
||||||
|
avatarId,
|
||||||
|
bannerId,
|
||||||
|
avatarUrl,
|
||||||
|
bannerUrl,
|
||||||
|
avatarBlurhash,
|
||||||
|
bannerBlurhash,
|
||||||
|
});
|
||||||
|
|
||||||
|
user.avatarId = avatarId;
|
||||||
|
user.bannerId = bannerId;
|
||||||
|
user.avatarUrl = avatarUrl;
|
||||||
|
user.bannerUrl = bannerUrl;
|
||||||
|
user.avatarBlurhash = avatarBlurhash;
|
||||||
|
user.bannerBlurhash = bannerBlurhash;
|
||||||
|
//#endregion
|
||||||
|
|
||||||
|
//#region カスタム絵文字取得
|
||||||
|
const emojis = await this.apNoteService.extractEmojis(person.tag ?? [], host).catch(err => {
|
||||||
|
this.logger.info(`extractEmojis: ${err}`);
|
||||||
|
return [];
|
||||||
|
});
|
||||||
|
|
||||||
|
const emojiNames = emojis.map(emoji => emoji.name);
|
||||||
|
|
||||||
|
await this.usersRepository.update(user.id, { emojis: emojiNames });
|
||||||
//#endregion
|
//#endregion
|
||||||
|
|
||||||
await this.updateFeatured(user.id, resolver).catch(err => this.logger.error(err));
|
await this.updateFeatured(user.id, resolver).catch(err => this.logger.error(err));
|
||||||
@@ -402,7 +400,7 @@ export class ApPersonService implements OnModuleInit {
|
|||||||
if (uri.startsWith(`${this.config.url}/`)) return;
|
if (uri.startsWith(`${this.config.url}/`)) return;
|
||||||
|
|
||||||
//#region このサーバーに既に登録されているか
|
//#region このサーバーに既に登録されているか
|
||||||
const exist = await this.fetchPerson(uri) as RemoteUser | null;
|
const exist = await this.usersRepository.findOneBy({ uri }) as RemoteUser | null;
|
||||||
if (exist === null) return;
|
if (exist === null) return;
|
||||||
//#endregion
|
//#endregion
|
||||||
|
|
||||||
@@ -415,6 +413,12 @@ export class ApPersonService implements OnModuleInit {
|
|||||||
|
|
||||||
this.logger.info(`Updating the Person: ${person.id}`);
|
this.logger.info(`Updating the Person: ${person.id}`);
|
||||||
|
|
||||||
|
// アバターとヘッダー画像をフェッチ
|
||||||
|
const [avatar, banner] = await Promise.all([person.icon, person.image].map(img => {
|
||||||
|
if (img == null) return null;
|
||||||
|
return this.apImageService.resolveImage(exist, img).catch(() => null);
|
||||||
|
}));
|
||||||
|
|
||||||
// カスタム絵文字取得
|
// カスタム絵文字取得
|
||||||
const emojis = await this.apNoteService.extractEmojis(person.tag ?? [], exist.host).catch(e => {
|
const emojis = await this.apNoteService.extractEmojis(person.tag ?? [], exist.host).catch(e => {
|
||||||
this.logger.info(`extractEmojis: ${e}`);
|
this.logger.info(`extractEmojis: ${e}`);
|
||||||
@@ -450,7 +454,6 @@ export class ApPersonService implements OnModuleInit {
|
|||||||
movedToUri: person.movedTo ?? null,
|
movedToUri: person.movedTo ?? null,
|
||||||
alsoKnownAs: person.alsoKnownAs ?? null,
|
alsoKnownAs: person.alsoKnownAs ?? null,
|
||||||
isExplorable: person.discoverable,
|
isExplorable: person.discoverable,
|
||||||
...(await this.resolveAvatarAndBanner(exist, person.icon, person.image).catch(() => ({}))),
|
|
||||||
} as Partial<RemoteUser> & Pick<RemoteUser, 'isBot' | 'isCat' | 'isLocked' | 'movedToUri' | 'alsoKnownAs' | 'isExplorable'>;
|
} as Partial<RemoteUser> & Pick<RemoteUser, 'isBot' | 'isCat' | 'isLocked' | 'movedToUri' | 'alsoKnownAs' | 'isExplorable'>;
|
||||||
|
|
||||||
const moving = ((): boolean => {
|
const moving = ((): boolean => {
|
||||||
@@ -473,6 +476,18 @@ export class ApPersonService implements OnModuleInit {
|
|||||||
|
|
||||||
if (moving) updates.movedAt = new Date();
|
if (moving) updates.movedAt = new Date();
|
||||||
|
|
||||||
|
if (avatar) {
|
||||||
|
updates.avatarId = avatar.id;
|
||||||
|
updates.avatarUrl = this.driveFileEntityService.getPublicUrl(avatar, 'avatar');
|
||||||
|
updates.avatarBlurhash = avatar.blurhash;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (banner) {
|
||||||
|
updates.bannerId = banner.id;
|
||||||
|
updates.bannerUrl = this.driveFileEntityService.getPublicUrl(banner);
|
||||||
|
updates.bannerBlurhash = banner.blurhash;
|
||||||
|
}
|
||||||
|
|
||||||
// Update user
|
// Update user
|
||||||
await this.usersRepository.update(exist.id, updates);
|
await this.usersRepository.update(exist.id, updates);
|
||||||
|
|
||||||
|
@@ -194,6 +194,7 @@ export interface IApPropertyValue extends IObject {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const isPropertyValue = (object: IObject): object is IApPropertyValue =>
|
export const isPropertyValue = (object: IObject): object is IApPropertyValue =>
|
||||||
|
object &&
|
||||||
getApType(object) === 'PropertyValue' &&
|
getApType(object) === 'PropertyValue' &&
|
||||||
typeof object.name === 'string' &&
|
typeof object.name === 'string' &&
|
||||||
'value' in object &&
|
'value' in object &&
|
||||||
|
@@ -254,7 +254,7 @@ export default abstract class Chart<T extends Schema> {
|
|||||||
private convertRawRecord(x: RawRecord<T>): KVs<T> {
|
private convertRawRecord(x: RawRecord<T>): KVs<T> {
|
||||||
const kvs = {} as Record<string, number>;
|
const kvs = {} as Record<string, number>;
|
||||||
for (const k of Object.keys(x).filter((k) => k.startsWith(COLUMN_PREFIX)) as (keyof Columns<T>)[]) {
|
for (const k of Object.keys(x).filter((k) => k.startsWith(COLUMN_PREFIX)) as (keyof Columns<T>)[]) {
|
||||||
kvs[(k as string).substring(COLUMN_PREFIX.length).split(COLUMN_DELIMITER).join('.')] = x[k] as unknown as number;
|
kvs[(k as string).substr(COLUMN_PREFIX.length).split(COLUMN_DELIMITER).join('.')] = x[k] as unknown as number;
|
||||||
}
|
}
|
||||||
return kvs as KVs<T>;
|
return kvs as KVs<T>;
|
||||||
}
|
}
|
||||||
@@ -627,7 +627,7 @@ export default abstract class Chart<T extends Schema> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 要求された範囲の最も古い箇所に位置するログが存在しなかったら
|
// 要求された範囲の最も古い箇所に位置するログが存在しなかったら
|
||||||
} else if (!isTimeSame(new Date(logs.at(-1)!.date * 1000), gt)) {
|
} else if (!isTimeSame(new Date(logs[logs.length - 1].date * 1000), gt)) {
|
||||||
// 要求された範囲の最も古い箇所時点での最も新しいログを持ってきて末尾に追加する
|
// 要求された範囲の最も古い箇所時点での最も新しいログを持ってきて末尾に追加する
|
||||||
// (隙間埋めできないため)
|
// (隙間埋めできないため)
|
||||||
const outdatedLog = await repository.findOne({
|
const outdatedLog = await repository.findOne({
|
||||||
|
@@ -3,8 +3,8 @@ import { DI } from '@/di-symbols.js';
|
|||||||
import type { AbuseUserReportsRepository } from '@/models/index.js';
|
import type { AbuseUserReportsRepository } from '@/models/index.js';
|
||||||
import { awaitAll } from '@/misc/prelude/await-all.js';
|
import { awaitAll } from '@/misc/prelude/await-all.js';
|
||||||
import type { AbuseUserReport } from '@/models/entities/AbuseUserReport.js';
|
import type { AbuseUserReport } from '@/models/entities/AbuseUserReport.js';
|
||||||
import { bindThis } from '@/decorators.js';
|
|
||||||
import { UserEntityService } from './UserEntityService.js';
|
import { UserEntityService } from './UserEntityService.js';
|
||||||
|
import { bindThis } from '@/decorators.js';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class AbuseUserReportEntityService {
|
export class AbuseUserReportEntityService {
|
||||||
|
@@ -4,8 +4,8 @@ import type { AuthSessionsRepository } from '@/models/index.js';
|
|||||||
import { awaitAll } from '@/misc/prelude/await-all.js';
|
import { awaitAll } from '@/misc/prelude/await-all.js';
|
||||||
import type { AuthSession } from '@/models/entities/AuthSession.js';
|
import type { AuthSession } from '@/models/entities/AuthSession.js';
|
||||||
import type { User } from '@/models/entities/User.js';
|
import type { User } from '@/models/entities/User.js';
|
||||||
import { bindThis } from '@/decorators.js';
|
|
||||||
import { AppEntityService } from './AppEntityService.js';
|
import { AppEntityService } from './AppEntityService.js';
|
||||||
|
import { bindThis } from '@/decorators.js';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class AuthSessionEntityService {
|
export class AuthSessionEntityService {
|
||||||
|
@@ -50,7 +50,7 @@ export class ChannelEntityService {
|
|||||||
const hasUnreadNote = meId ? await this.noteUnreadsRepository.exist({
|
const hasUnreadNote = meId ? await this.noteUnreadsRepository.exist({
|
||||||
where: {
|
where: {
|
||||||
noteChannelId: channel.id,
|
noteChannelId: channel.id,
|
||||||
userId: meId,
|
userId: meId
|
||||||
},
|
},
|
||||||
}) : undefined;
|
}) : undefined;
|
||||||
|
|
||||||
|
@@ -4,8 +4,8 @@ import type { FollowRequestsRepository } from '@/models/index.js';
|
|||||||
import type { } from '@/models/entities/Blocking.js';
|
import type { } from '@/models/entities/Blocking.js';
|
||||||
import type { User } from '@/models/entities/User.js';
|
import type { User } from '@/models/entities/User.js';
|
||||||
import type { FollowRequest } from '@/models/entities/FollowRequest.js';
|
import type { FollowRequest } from '@/models/entities/FollowRequest.js';
|
||||||
import { bindThis } from '@/decorators.js';
|
|
||||||
import { UserEntityService } from './UserEntityService.js';
|
import { UserEntityService } from './UserEntityService.js';
|
||||||
|
import { bindThis } from '@/decorators.js';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class FollowRequestEntityService {
|
export class FollowRequestEntityService {
|
||||||
|
@@ -3,8 +3,8 @@ import { DI } from '@/di-symbols.js';
|
|||||||
import type { GalleryLikesRepository } from '@/models/index.js';
|
import type { GalleryLikesRepository } from '@/models/index.js';
|
||||||
import type { } from '@/models/entities/Blocking.js';
|
import type { } from '@/models/entities/Blocking.js';
|
||||||
import type { GalleryLike } from '@/models/entities/GalleryLike.js';
|
import type { GalleryLike } from '@/models/entities/GalleryLike.js';
|
||||||
import { bindThis } from '@/decorators.js';
|
|
||||||
import { GalleryPostEntityService } from './GalleryPostEntityService.js';
|
import { GalleryPostEntityService } from './GalleryPostEntityService.js';
|
||||||
|
import { bindThis } from '@/decorators.js';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class GalleryLikeEntityService {
|
export class GalleryLikeEntityService {
|
||||||
|
@@ -1,52 +0,0 @@
|
|||||||
import { Inject, Injectable } from '@nestjs/common';
|
|
||||||
import { DI } from '@/di-symbols.js';
|
|
||||||
import type { RegistrationTicketsRepository } from '@/models/index.js';
|
|
||||||
import { awaitAll } from '@/misc/prelude/await-all.js';
|
|
||||||
import type { Packed } from '@/misc/json-schema.js';
|
|
||||||
import type { User } from '@/models/entities/User.js';
|
|
||||||
import type { RegistrationTicket } from '@/models/entities/RegistrationTicket.js';
|
|
||||||
import { bindThis } from '@/decorators.js';
|
|
||||||
import { UserEntityService } from './UserEntityService.js';
|
|
||||||
|
|
||||||
@Injectable()
|
|
||||||
export class InviteCodeEntityService {
|
|
||||||
constructor(
|
|
||||||
@Inject(DI.registrationTicketsRepository)
|
|
||||||
private registrationTicketsRepository: RegistrationTicketsRepository,
|
|
||||||
|
|
||||||
private userEntityService: UserEntityService,
|
|
||||||
) {
|
|
||||||
}
|
|
||||||
|
|
||||||
@bindThis
|
|
||||||
public async pack(
|
|
||||||
src: RegistrationTicket['id'] | RegistrationTicket,
|
|
||||||
me?: { id: User['id'] } | null | undefined,
|
|
||||||
): Promise<Packed<'InviteCode'>> {
|
|
||||||
const target = typeof src === 'object' ? src : await this.registrationTicketsRepository.findOneOrFail({
|
|
||||||
where: {
|
|
||||||
id: src,
|
|
||||||
},
|
|
||||||
relations: ['createdBy', 'usedBy'],
|
|
||||||
});
|
|
||||||
|
|
||||||
return await awaitAll({
|
|
||||||
id: target.id,
|
|
||||||
code: target.code,
|
|
||||||
expiresAt: target.expiresAt ? target.expiresAt.toISOString() : null,
|
|
||||||
createdAt: target.createdAt.toISOString(),
|
|
||||||
createdBy: target.createdBy ? await this.userEntityService.pack(target.createdBy, me) : null,
|
|
||||||
usedBy: target.usedBy ? await this.userEntityService.pack(target.usedBy, me) : null,
|
|
||||||
usedAt: target.usedAt ? target.usedAt.toISOString() : null,
|
|
||||||
used: !!target.usedAt,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@bindThis
|
|
||||||
public packMany(
|
|
||||||
targets: any[],
|
|
||||||
me: { id: User['id'] },
|
|
||||||
) {
|
|
||||||
return Promise.all(targets.map(x => this.pack(x, me)));
|
|
||||||
}
|
|
||||||
}
|
|
@@ -4,8 +4,8 @@ import type { ModerationLogsRepository } from '@/models/index.js';
|
|||||||
import { awaitAll } from '@/misc/prelude/await-all.js';
|
import { awaitAll } from '@/misc/prelude/await-all.js';
|
||||||
import type { } from '@/models/entities/Blocking.js';
|
import type { } from '@/models/entities/Blocking.js';
|
||||||
import type { ModerationLog } from '@/models/entities/ModerationLog.js';
|
import type { ModerationLog } from '@/models/entities/ModerationLog.js';
|
||||||
import { bindThis } from '@/decorators.js';
|
|
||||||
import { UserEntityService } from './UserEntityService.js';
|
import { UserEntityService } from './UserEntityService.js';
|
||||||
|
import { bindThis } from '@/decorators.js';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class ModerationLogEntityService {
|
export class ModerationLogEntityService {
|
||||||
|
@@ -4,8 +4,8 @@ import type { NoteFavoritesRepository } from '@/models/index.js';
|
|||||||
import type { } from '@/models/entities/Blocking.js';
|
import type { } from '@/models/entities/Blocking.js';
|
||||||
import type { User } from '@/models/entities/User.js';
|
import type { User } from '@/models/entities/User.js';
|
||||||
import type { NoteFavorite } from '@/models/entities/NoteFavorite.js';
|
import type { NoteFavorite } from '@/models/entities/NoteFavorite.js';
|
||||||
import { bindThis } from '@/decorators.js';
|
|
||||||
import { NoteEntityService } from './NoteEntityService.js';
|
import { NoteEntityService } from './NoteEntityService.js';
|
||||||
|
import { bindThis } from '@/decorators.js';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class NoteFavoriteEntityService {
|
export class NoteFavoriteEntityService {
|
||||||
|
@@ -4,8 +4,8 @@ import type { PageLikesRepository } from '@/models/index.js';
|
|||||||
import type { } from '@/models/entities/Blocking.js';
|
import type { } from '@/models/entities/Blocking.js';
|
||||||
import type { User } from '@/models/entities/User.js';
|
import type { User } from '@/models/entities/User.js';
|
||||||
import type { PageLike } from '@/models/entities/PageLike.js';
|
import type { PageLike } from '@/models/entities/PageLike.js';
|
||||||
import { bindThis } from '@/decorators.js';
|
|
||||||
import { PageEntityService } from './PageEntityService.js';
|
import { PageEntityService } from './PageEntityService.js';
|
||||||
|
import { bindThis } from '@/decorators.js';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class PageLikeEntityService {
|
export class PageLikeEntityService {
|
||||||
|
@@ -3,8 +3,8 @@ import { DI } from '@/di-symbols.js';
|
|||||||
import type { SigninsRepository } from '@/models/index.js';
|
import type { SigninsRepository } from '@/models/index.js';
|
||||||
import type { } from '@/models/entities/Blocking.js';
|
import type { } from '@/models/entities/Blocking.js';
|
||||||
import type { Signin } from '@/models/entities/Signin.js';
|
import type { Signin } from '@/models/entities/Signin.js';
|
||||||
import { bindThis } from '@/decorators.js';
|
|
||||||
import { UserEntityService } from './UserEntityService.js';
|
import { UserEntityService } from './UserEntityService.js';
|
||||||
|
import { bindThis } from '@/decorators.js';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class SigninEntityService {
|
export class SigninEntityService {
|
||||||
|
@@ -4,7 +4,7 @@ export type Acct = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export function parse(acct: string): Acct {
|
export function parse(acct: string): Acct {
|
||||||
if (acct.startsWith('@')) acct = acct.substring(1);
|
if (acct.startsWith('@')) acct = acct.substr(1);
|
||||||
const split = acct.split('@', 2);
|
const split = acct.split('@', 2);
|
||||||
return { username: split[0], host: split[1] ?? null };
|
return { username: split[0], host: split[1] ?? null };
|
||||||
}
|
}
|
||||||
|
@@ -1,11 +1,11 @@
|
|||||||
import { Writable, WritableOptions } from 'node:stream';
|
import { Writable, WritableOptions } from "node:stream";
|
||||||
|
|
||||||
export class DevNull extends Writable implements NodeJS.WritableStream {
|
export class DevNull extends Writable implements NodeJS.WritableStream {
|
||||||
constructor(opts?: WritableOptions) {
|
constructor(opts?: WritableOptions) {
|
||||||
super(opts);
|
super(opts);
|
||||||
}
|
}
|
||||||
|
|
||||||
_write (chunk: any, encoding: BufferEncoding, cb: (err?: Error | null) => void) {
|
_write (chunk: any, encoding: BufferEncoding, cb: (err?: Error | null) => void) {
|
||||||
setImmediate(cb);
|
setImmediate(cb);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,20 +0,0 @@
|
|||||||
import { secureRndstr } from './secure-rndstr.js';
|
|
||||||
|
|
||||||
const CHARS = '23456789ABCDEFGHJKLMNPQRSTUVWXYZ'; // [0-9A-Z] w/o [01IO] (32 patterns)
|
|
||||||
|
|
||||||
export function generateInviteCode(): string {
|
|
||||||
const code = secureRndstr(8, {
|
|
||||||
chars: CHARS,
|
|
||||||
});
|
|
||||||
|
|
||||||
const uniqueId = [];
|
|
||||||
let n = Math.floor(Date.now() / 1000 / 60);
|
|
||||||
while (true) {
|
|
||||||
uniqueId.push(CHARS[n % CHARS.length]);
|
|
||||||
const t = Math.floor(n / CHARS.length);
|
|
||||||
if (!t) break;
|
|
||||||
n = t;
|
|
||||||
}
|
|
||||||
|
|
||||||
return code + uniqueId.reverse().join('');
|
|
||||||
}
|
|
@@ -5,10 +5,10 @@ const CHARS = '0123456789ABCDEFGHJKMNPQRSTVWXYZ';
|
|||||||
export const ulidRegExp = /^[0123456789ABCDEFGHJKMNPQRSTVWXYZ]{26}$/;
|
export const ulidRegExp = /^[0123456789ABCDEFGHJKMNPQRSTVWXYZ]{26}$/;
|
||||||
|
|
||||||
export function parseUlid(id: string): { date: Date; } {
|
export function parseUlid(id: string): { date: Date; } {
|
||||||
const timestamp = id.slice(0, 10);
|
const timestamp = id.slice(0, 10);
|
||||||
let time = 0;
|
let time = 0;
|
||||||
for (let i = 0; i < 10; i++) {
|
for (let i = 0; i < 10; i++) {
|
||||||
time = time * 32 + CHARS.indexOf(timestamp[i]);
|
time = time * 32 + CHARS.indexOf(timestamp[i]);
|
||||||
}
|
}
|
||||||
return { date: new Date(time) };
|
return { date: new Date(time) };
|
||||||
}
|
}
|
||||||
|
@@ -19,7 +19,6 @@ import { packedRenoteMutingSchema } from '@/models/json-schema/renote-muting.js'
|
|||||||
import { packedBlockingSchema } from '@/models/json-schema/blocking.js';
|
import { packedBlockingSchema } from '@/models/json-schema/blocking.js';
|
||||||
import { packedNoteReactionSchema } from '@/models/json-schema/note-reaction.js';
|
import { packedNoteReactionSchema } from '@/models/json-schema/note-reaction.js';
|
||||||
import { packedHashtagSchema } from '@/models/json-schema/hashtag.js';
|
import { packedHashtagSchema } from '@/models/json-schema/hashtag.js';
|
||||||
import { packedInviteCodeSchema } from '@/models/json-schema/invite-code.js';
|
|
||||||
import { packedPageSchema } from '@/models/json-schema/page.js';
|
import { packedPageSchema } from '@/models/json-schema/page.js';
|
||||||
import { packedNoteFavoriteSchema } from '@/models/json-schema/note-favorite.js';
|
import { packedNoteFavoriteSchema } from '@/models/json-schema/note-favorite.js';
|
||||||
import { packedChannelSchema } from '@/models/json-schema/channel.js';
|
import { packedChannelSchema } from '@/models/json-schema/channel.js';
|
||||||
@@ -53,7 +52,6 @@ export const refs = {
|
|||||||
RenoteMuting: packedRenoteMutingSchema,
|
RenoteMuting: packedRenoteMutingSchema,
|
||||||
Blocking: packedBlockingSchema,
|
Blocking: packedBlockingSchema,
|
||||||
Hashtag: packedHashtagSchema,
|
Hashtag: packedHashtagSchema,
|
||||||
InviteCode: packedInviteCodeSchema,
|
|
||||||
Page: packedPageSchema,
|
Page: packedPageSchema,
|
||||||
Channel: packedChannelSchema,
|
Channel: packedChannelSchema,
|
||||||
QueueCount: packedQueueCountSchema,
|
QueueCount: packedQueueCountSchema,
|
||||||
|
@@ -67,9 +67,8 @@ export function maximum(xs: number[]): number {
|
|||||||
export function groupBy<T>(f: EndoRelation<T>, xs: T[]): T[][] {
|
export function groupBy<T>(f: EndoRelation<T>, xs: T[]): T[][] {
|
||||||
const groups = [] as T[][];
|
const groups = [] as T[][];
|
||||||
for (const x of xs) {
|
for (const x of xs) {
|
||||||
const lastGroup = groups.at(-1);
|
if (groups.length !== 0 && f(groups[groups.length - 1][0], x)) {
|
||||||
if (lastGroup !== undefined && f(lastGroup[0], x)) {
|
groups[groups.length - 1].push(x);
|
||||||
lastGroup.push(x);
|
|
||||||
} else {
|
} else {
|
||||||
groups.push([x]);
|
groups.push([x]);
|
||||||
}
|
}
|
||||||
|
@@ -10,7 +10,7 @@ export async function awaitAll<T>(obj: Promiseable<T>): Promise<T> {
|
|||||||
const resolvedValues = await Promise.all(values.map(value =>
|
const resolvedValues = await Promise.all(values.map(value =>
|
||||||
(!value || !value.constructor || value.constructor.name !== 'Object')
|
(!value || !value.constructor || value.constructor.name !== 'Object')
|
||||||
? value
|
? value
|
||||||
: awaitAll(value),
|
: awaitAll(value)
|
||||||
));
|
));
|
||||||
|
|
||||||
for (let i = 0; i < keys.length; i++) {
|
for (let i = 0; i < keys.length; i++) {
|
||||||
|
@@ -1,60 +1,17 @@
|
|||||||
import { PrimaryColumn, Entity, Index, Column, ManyToOne, JoinColumn, OneToOne } from 'typeorm';
|
import { PrimaryColumn, Entity, Index, Column } from 'typeorm';
|
||||||
import { id } from '../id.js';
|
import { id } from '../id.js';
|
||||||
import { User } from './User.js';
|
|
||||||
|
|
||||||
@Entity()
|
@Entity()
|
||||||
export class RegistrationTicket {
|
export class RegistrationTicket {
|
||||||
@PrimaryColumn(id())
|
@PrimaryColumn(id())
|
||||||
public id: string;
|
public id: string;
|
||||||
|
|
||||||
|
@Column('timestamp with time zone')
|
||||||
|
public createdAt: Date;
|
||||||
|
|
||||||
@Index({ unique: true })
|
@Index({ unique: true })
|
||||||
@Column('varchar', {
|
@Column('varchar', {
|
||||||
length: 64,
|
length: 64,
|
||||||
})
|
})
|
||||||
public code: string;
|
public code: string;
|
||||||
|
|
||||||
@Column('timestamp with time zone', {
|
|
||||||
nullable: true,
|
|
||||||
})
|
|
||||||
public expiresAt: Date | null;
|
|
||||||
|
|
||||||
@Column('timestamp with time zone')
|
|
||||||
public createdAt: Date;
|
|
||||||
|
|
||||||
@ManyToOne(type => User, {
|
|
||||||
onDelete: 'CASCADE',
|
|
||||||
})
|
|
||||||
@JoinColumn()
|
|
||||||
public createdBy: User | null;
|
|
||||||
|
|
||||||
@Index()
|
|
||||||
@Column({
|
|
||||||
...id(),
|
|
||||||
nullable: true,
|
|
||||||
})
|
|
||||||
public createdById: User['id'] | null;
|
|
||||||
|
|
||||||
@OneToOne(type => User, {
|
|
||||||
onDelete: 'CASCADE',
|
|
||||||
})
|
|
||||||
@JoinColumn()
|
|
||||||
public usedBy: User | null;
|
|
||||||
|
|
||||||
@Index()
|
|
||||||
@Column({
|
|
||||||
...id(),
|
|
||||||
nullable: true,
|
|
||||||
})
|
|
||||||
public usedById: User['id'] | null;
|
|
||||||
|
|
||||||
@Column('timestamp with time zone', {
|
|
||||||
nullable: true,
|
|
||||||
})
|
|
||||||
public usedAt: Date | null;
|
|
||||||
|
|
||||||
@Column('varchar', {
|
|
||||||
length: 32,
|
|
||||||
nullable: true,
|
|
||||||
})
|
|
||||||
public pendingUserId: string | null;
|
|
||||||
}
|
}
|
||||||
|
@@ -49,6 +49,7 @@ import { User } from '@/models/entities/User.js';
|
|||||||
import { UserIp } from '@/models/entities/UserIp.js';
|
import { UserIp } from '@/models/entities/UserIp.js';
|
||||||
import { UserKeypair } from '@/models/entities/UserKeypair.js';
|
import { UserKeypair } from '@/models/entities/UserKeypair.js';
|
||||||
import { UserList } from '@/models/entities/UserList.js';
|
import { UserList } from '@/models/entities/UserList.js';
|
||||||
|
import { UserListFavorite } from './entities/UserListFavorite.js';
|
||||||
import { UserListJoining } from '@/models/entities/UserListJoining.js';
|
import { UserListJoining } from '@/models/entities/UserListJoining.js';
|
||||||
import { UserNotePining } from '@/models/entities/UserNotePining.js';
|
import { UserNotePining } from '@/models/entities/UserNotePining.js';
|
||||||
import { UserPending } from '@/models/entities/UserPending.js';
|
import { UserPending } from '@/models/entities/UserPending.js';
|
||||||
@@ -63,7 +64,6 @@ import { Role } from '@/models/entities/Role.js';
|
|||||||
import { RoleAssignment } from '@/models/entities/RoleAssignment.js';
|
import { RoleAssignment } from '@/models/entities/RoleAssignment.js';
|
||||||
import { Flash } from '@/models/entities/Flash.js';
|
import { Flash } from '@/models/entities/Flash.js';
|
||||||
import { FlashLike } from '@/models/entities/FlashLike.js';
|
import { FlashLike } from '@/models/entities/FlashLike.js';
|
||||||
import { UserListFavorite } from './entities/UserListFavorite.js';
|
|
||||||
import type { Repository } from 'typeorm';
|
import type { Repository } from 'typeorm';
|
||||||
|
|
||||||
export {
|
export {
|
||||||
|
@@ -1,45 +0,0 @@
|
|||||||
export const packedInviteCodeSchema = {
|
|
||||||
type: 'object',
|
|
||||||
properties: {
|
|
||||||
id: {
|
|
||||||
type: 'string',
|
|
||||||
optional: false, nullable: false,
|
|
||||||
format: 'id',
|
|
||||||
example: 'xxxxxxxxxx',
|
|
||||||
},
|
|
||||||
code: {
|
|
||||||
type: 'string',
|
|
||||||
optional: false, nullable: false,
|
|
||||||
example: 'GR6S02ERUA5VR',
|
|
||||||
},
|
|
||||||
expiresAt: {
|
|
||||||
type: 'string',
|
|
||||||
optional: false, nullable: true,
|
|
||||||
format: 'date-time',
|
|
||||||
},
|
|
||||||
createdAt: {
|
|
||||||
type: 'string',
|
|
||||||
optional: false, nullable: false,
|
|
||||||
format: 'date-time',
|
|
||||||
},
|
|
||||||
createdBy: {
|
|
||||||
type: 'object',
|
|
||||||
optional: false, nullable: true,
|
|
||||||
ref: 'UserLite',
|
|
||||||
},
|
|
||||||
usedBy: {
|
|
||||||
type: 'object',
|
|
||||||
optional: false, nullable: true,
|
|
||||||
ref: 'UserLite',
|
|
||||||
},
|
|
||||||
usedAt: {
|
|
||||||
type: 'string',
|
|
||||||
optional: false, nullable: true,
|
|
||||||
format: 'date-time',
|
|
||||||
},
|
|
||||||
used: {
|
|
||||||
type: 'boolean',
|
|
||||||
optional: false, nullable: false,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
} as const;
|
|
@@ -15,8 +15,11 @@ export const QUEUE = {
|
|||||||
export function baseQueueOptions(config: Config, queueName: typeof QUEUE[keyof typeof QUEUE]): Bull.QueueOptions {
|
export function baseQueueOptions(config: Config, queueName: typeof QUEUE[keyof typeof QUEUE]): Bull.QueueOptions {
|
||||||
return {
|
return {
|
||||||
connection: {
|
connection: {
|
||||||
...config.redisForJobQueue,
|
port: config.redisForJobQueue.port,
|
||||||
keyPrefix: undefined
|
host: config.redisForJobQueue.host,
|
||||||
|
family: config.redisForJobQueue.family == null ? 0 : config.redisForJobQueue.family,
|
||||||
|
password: config.redisForJobQueue.pass,
|
||||||
|
db: config.redisForJobQueue.db ?? 0,
|
||||||
},
|
},
|
||||||
prefix: config.redisForJobQueue.prefix ? `${config.redisForJobQueue.prefix}:queue:${queueName}` : `queue:${queueName}`,
|
prefix: config.redisForJobQueue.prefix ? `${config.redisForJobQueue.prefix}:queue:${queueName}` : `queue:${queueName}`,
|
||||||
};
|
};
|
||||||
|
@@ -1,7 +1,7 @@
|
|||||||
import { Inject, Injectable } from '@nestjs/common';
|
import { Inject, Injectable } from '@nestjs/common';
|
||||||
import { IsNull, MoreThan, Not } from 'typeorm';
|
import { IsNull, MoreThan, Not } from 'typeorm';
|
||||||
import { DI } from '@/di-symbols.js';
|
import { DI } from '@/di-symbols.js';
|
||||||
import type { DriveFile, DriveFilesRepository } from '@/models/index.js';
|
import type { DriveFilesRepository } from '@/models/index.js';
|
||||||
import type { Config } from '@/config.js';
|
import type { Config } from '@/config.js';
|
||||||
import type Logger from '@/logger.js';
|
import type Logger from '@/logger.js';
|
||||||
import { DriveService } from '@/core/DriveService.js';
|
import { DriveService } from '@/core/DriveService.js';
|
||||||
@@ -31,7 +31,7 @@ export class CleanRemoteFilesProcessorService {
|
|||||||
this.logger.info('Deleting cached remote files...');
|
this.logger.info('Deleting cached remote files...');
|
||||||
|
|
||||||
let deletedCount = 0;
|
let deletedCount = 0;
|
||||||
let cursor: DriveFile['id'] | null = null;
|
let cursor: any = null;
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
const files = await this.driveFilesRepository.find({
|
const files = await this.driveFilesRepository.find({
|
||||||
@@ -51,7 +51,7 @@ export class CleanRemoteFilesProcessorService {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
cursor = files.at(-1)?.id ?? null;
|
cursor = files[files.length - 1].id;
|
||||||
|
|
||||||
await Promise.all(files.map(file => this.driveService.deleteFileSync(file, true)));
|
await Promise.all(files.map(file => this.driveService.deleteFileSync(file, true)));
|
||||||
|
|
||||||
|
@@ -9,10 +9,10 @@ import type { DriveFile } from '@/models/entities/DriveFile.js';
|
|||||||
import type { Note } from '@/models/entities/Note.js';
|
import type { Note } from '@/models/entities/Note.js';
|
||||||
import { EmailService } from '@/core/EmailService.js';
|
import { EmailService } from '@/core/EmailService.js';
|
||||||
import { bindThis } from '@/decorators.js';
|
import { bindThis } from '@/decorators.js';
|
||||||
import { SearchService } from '@/core/SearchService.js';
|
|
||||||
import { QueueLoggerService } from '../QueueLoggerService.js';
|
import { QueueLoggerService } from '../QueueLoggerService.js';
|
||||||
import type * as Bull from 'bullmq';
|
import type * as Bull from 'bullmq';
|
||||||
import type { DbUserDeleteJobData } from '../types.js';
|
import type { DbUserDeleteJobData } from '../types.js';
|
||||||
|
import { SearchService } from "@/core/SearchService.js";
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class DeleteAccountProcessorService {
|
export class DeleteAccountProcessorService {
|
||||||
@@ -70,7 +70,7 @@ export class DeleteAccountProcessorService {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
cursor = notes.at(-1)?.id ?? null;
|
cursor = notes[notes.length - 1].id;
|
||||||
|
|
||||||
await this.notesRepository.delete(notes.map(note => note.id));
|
await this.notesRepository.delete(notes.map(note => note.id));
|
||||||
|
|
||||||
@@ -101,7 +101,7 @@ export class DeleteAccountProcessorService {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
cursor = files.at(-1)?.id ?? null;
|
cursor = files[files.length - 1].id;
|
||||||
|
|
||||||
for (const file of files) {
|
for (const file of files) {
|
||||||
await this.driveService.deleteFileSync(file);
|
await this.driveService.deleteFileSync(file);
|
||||||
|
@@ -1,7 +1,7 @@
|
|||||||
import { Inject, Injectable } from '@nestjs/common';
|
import { Inject, Injectable } from '@nestjs/common';
|
||||||
import { MoreThan } from 'typeorm';
|
import { MoreThan } from 'typeorm';
|
||||||
import { DI } from '@/di-symbols.js';
|
import { DI } from '@/di-symbols.js';
|
||||||
import type { UsersRepository, DriveFilesRepository, DriveFile } from '@/models/index.js';
|
import type { UsersRepository, DriveFilesRepository } from '@/models/index.js';
|
||||||
import type { Config } from '@/config.js';
|
import type { Config } from '@/config.js';
|
||||||
import type Logger from '@/logger.js';
|
import type Logger from '@/logger.js';
|
||||||
import { DriveService } from '@/core/DriveService.js';
|
import { DriveService } from '@/core/DriveService.js';
|
||||||
@@ -40,7 +40,7 @@ export class DeleteDriveFilesProcessorService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let deletedCount = 0;
|
let deletedCount = 0;
|
||||||
let cursor: DriveFile['id'] | null = null;
|
let cursor: any = null;
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
const files = await this.driveFilesRepository.find({
|
const files = await this.driveFilesRepository.find({
|
||||||
@@ -59,7 +59,7 @@ export class DeleteDriveFilesProcessorService {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
cursor = files.at(-1)?.id ?? null;
|
cursor = files[files.length - 1].id;
|
||||||
|
|
||||||
for (const file of files) {
|
for (const file of files) {
|
||||||
await this.driveService.deleteFileSync(file);
|
await this.driveService.deleteFileSync(file);
|
||||||
|
@@ -3,7 +3,7 @@ import { Inject, Injectable } from '@nestjs/common';
|
|||||||
import { MoreThan } from 'typeorm';
|
import { MoreThan } from 'typeorm';
|
||||||
import { format as dateFormat } from 'date-fns';
|
import { format as dateFormat } from 'date-fns';
|
||||||
import { DI } from '@/di-symbols.js';
|
import { DI } from '@/di-symbols.js';
|
||||||
import type { UsersRepository, BlockingsRepository, Blocking } from '@/models/index.js';
|
import type { UsersRepository, BlockingsRepository } from '@/models/index.js';
|
||||||
import type { Config } from '@/config.js';
|
import type { Config } from '@/config.js';
|
||||||
import type Logger from '@/logger.js';
|
import type Logger from '@/logger.js';
|
||||||
import { DriveService } from '@/core/DriveService.js';
|
import { DriveService } from '@/core/DriveService.js';
|
||||||
@@ -53,7 +53,7 @@ export class ExportBlockingProcessorService {
|
|||||||
const stream = fs.createWriteStream(path, { flags: 'a' });
|
const stream = fs.createWriteStream(path, { flags: 'a' });
|
||||||
|
|
||||||
let exportedCount = 0;
|
let exportedCount = 0;
|
||||||
let cursor: Blocking['id'] | null = null;
|
let cursor: any = null;
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
const blockings = await this.blockingsRepository.find({
|
const blockings = await this.blockingsRepository.find({
|
||||||
@@ -72,7 +72,7 @@ export class ExportBlockingProcessorService {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
cursor = blockings.at(-1)?.id ?? null;
|
cursor = blockings[blockings.length - 1].id;
|
||||||
|
|
||||||
for (const block of blockings) {
|
for (const block of blockings) {
|
||||||
const u = await this.usersRepository.findOneBy({ id: block.blockeeId });
|
const u = await this.usersRepository.findOneBy({ id: block.blockeeId });
|
||||||
|
@@ -94,7 +94,7 @@ export class ExportFavoritesProcessorService {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
cursor = favorites.at(-1)?.id ?? null;
|
cursor = favorites[favorites.length - 1].id;
|
||||||
|
|
||||||
for (const favorite of favorites) {
|
for (const favorite of favorites) {
|
||||||
let poll: Poll | undefined;
|
let poll: Poll | undefined;
|
||||||
|
@@ -79,7 +79,7 @@ export class ExportFollowingProcessorService {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
cursor = followings.at(-1)?.id ?? null;
|
cursor = followings[followings.length - 1].id;
|
||||||
|
|
||||||
for (const following of followings) {
|
for (const following of followings) {
|
||||||
const u = await this.usersRepository.findOneBy({ id: following.followeeId });
|
const u = await this.usersRepository.findOneBy({ id: following.followeeId });
|
||||||
|
@@ -3,7 +3,7 @@ import { Inject, Injectable } from '@nestjs/common';
|
|||||||
import { IsNull, MoreThan } from 'typeorm';
|
import { IsNull, MoreThan } from 'typeorm';
|
||||||
import { format as dateFormat } from 'date-fns';
|
import { format as dateFormat } from 'date-fns';
|
||||||
import { DI } from '@/di-symbols.js';
|
import { DI } from '@/di-symbols.js';
|
||||||
import type { MutingsRepository, UsersRepository, BlockingsRepository, Muting } from '@/models/index.js';
|
import type { MutingsRepository, UsersRepository, BlockingsRepository } from '@/models/index.js';
|
||||||
import type { Config } from '@/config.js';
|
import type { Config } from '@/config.js';
|
||||||
import type Logger from '@/logger.js';
|
import type Logger from '@/logger.js';
|
||||||
import { DriveService } from '@/core/DriveService.js';
|
import { DriveService } from '@/core/DriveService.js';
|
||||||
@@ -56,7 +56,7 @@ export class ExportMutingProcessorService {
|
|||||||
const stream = fs.createWriteStream(path, { flags: 'a' });
|
const stream = fs.createWriteStream(path, { flags: 'a' });
|
||||||
|
|
||||||
let exportedCount = 0;
|
let exportedCount = 0;
|
||||||
let cursor: Muting['id'] | null = null;
|
let cursor: any = null;
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
const mutes = await this.mutingsRepository.find({
|
const mutes = await this.mutingsRepository.find({
|
||||||
@@ -76,7 +76,7 @@ export class ExportMutingProcessorService {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
cursor = mutes.at(-1)?.id ?? null;
|
cursor = mutes[mutes.length - 1].id;
|
||||||
|
|
||||||
for (const mute of mutes) {
|
for (const mute of mutes) {
|
||||||
const u = await this.usersRepository.findOneBy({ id: mute.muteeId });
|
const u = await this.usersRepository.findOneBy({ id: mute.muteeId });
|
||||||
|
@@ -11,8 +11,6 @@ import { createTemp } from '@/misc/create-temp.js';
|
|||||||
import type { Poll } from '@/models/entities/Poll.js';
|
import type { Poll } from '@/models/entities/Poll.js';
|
||||||
import type { Note } from '@/models/entities/Note.js';
|
import type { Note } from '@/models/entities/Note.js';
|
||||||
import { bindThis } from '@/decorators.js';
|
import { bindThis } from '@/decorators.js';
|
||||||
import { DriveFileEntityService } from '@/core/entities/DriveFileEntityService.js';
|
|
||||||
import { Packed } from '@/misc/json-schema.js';
|
|
||||||
import { QueueLoggerService } from '../QueueLoggerService.js';
|
import { QueueLoggerService } from '../QueueLoggerService.js';
|
||||||
import type * as Bull from 'bullmq';
|
import type * as Bull from 'bullmq';
|
||||||
import type { DbJobDataWithUser } from '../types.js';
|
import type { DbJobDataWithUser } from '../types.js';
|
||||||
@@ -36,8 +34,6 @@ export class ExportNotesProcessorService {
|
|||||||
|
|
||||||
private driveService: DriveService,
|
private driveService: DriveService,
|
||||||
private queueLoggerService: QueueLoggerService,
|
private queueLoggerService: QueueLoggerService,
|
||||||
|
|
||||||
private driveFileEntityService: DriveFileEntityService,
|
|
||||||
) {
|
) {
|
||||||
this.logger = this.queueLoggerService.logger.createSubLogger('export-notes');
|
this.logger = this.queueLoggerService.logger.createSubLogger('export-notes');
|
||||||
}
|
}
|
||||||
@@ -94,15 +90,14 @@ export class ExportNotesProcessorService {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
cursor = notes.at(-1)?.id ?? null;
|
cursor = notes[notes.length - 1].id;
|
||||||
|
|
||||||
for (const note of notes) {
|
for (const note of notes) {
|
||||||
let poll: Poll | undefined;
|
let poll: Poll | undefined;
|
||||||
if (note.hasPoll) {
|
if (note.hasPoll) {
|
||||||
poll = await this.pollsRepository.findOneByOrFail({ noteId: note.id });
|
poll = await this.pollsRepository.findOneByOrFail({ noteId: note.id });
|
||||||
}
|
}
|
||||||
const files = await this.driveFileEntityService.packManyByIds(note.fileIds);
|
const content = JSON.stringify(serialize(note, poll));
|
||||||
const content = JSON.stringify(serialize(note, poll, files));
|
|
||||||
const isFirst = exportedNotesCount === 0;
|
const isFirst = exportedNotesCount === 0;
|
||||||
await write(isFirst ? content : ',\n' + content);
|
await write(isFirst ? content : ',\n' + content);
|
||||||
exportedNotesCount++;
|
exportedNotesCount++;
|
||||||
@@ -130,13 +125,12 @@ export class ExportNotesProcessorService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function serialize(note: Note, poll: Poll | null = null, files: Packed<'DriveFile'>[]): Record<string, unknown> {
|
function serialize(note: Note, poll: Poll | null = null): Record<string, unknown> {
|
||||||
return {
|
return {
|
||||||
id: note.id,
|
id: note.id,
|
||||||
text: note.text,
|
text: note.text,
|
||||||
createdAt: note.createdAt,
|
createdAt: note.createdAt,
|
||||||
fileIds: note.fileIds,
|
fileIds: note.fileIds,
|
||||||
files: files,
|
|
||||||
replyId: note.replyId,
|
replyId: note.replyId,
|
||||||
renoteId: note.renoteId,
|
renoteId: note.renoteId,
|
||||||
poll: poll,
|
poll: poll,
|
||||||
|
@@ -1,7 +1,7 @@
|
|||||||
import * as fs from 'node:fs';
|
import * as fs from 'node:fs';
|
||||||
import { Inject, Injectable } from '@nestjs/common';
|
import { Inject, Injectable } from '@nestjs/common';
|
||||||
import { ZipReader } from 'slacc';
|
|
||||||
import { DataSource } from 'typeorm';
|
import { DataSource } from 'typeorm';
|
||||||
|
import unzipper from 'unzipper';
|
||||||
import { DI } from '@/di-symbols.js';
|
import { DI } from '@/di-symbols.js';
|
||||||
import type { EmojisRepository, DriveFilesRepository, UsersRepository } from '@/models/index.js';
|
import type { EmojisRepository, DriveFilesRepository, UsersRepository } from '@/models/index.js';
|
||||||
import type { Config } from '@/config.js';
|
import type { Config } from '@/config.js';
|
||||||
@@ -72,9 +72,9 @@ export class ImportCustomEmojisProcessorService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const outputPath = path + '/emojis';
|
const outputPath = path + '/emojis';
|
||||||
try {
|
const unzipStream = fs.createReadStream(destPath);
|
||||||
this.logger.succ(`Unzipping to ${outputPath}`);
|
const extractor = unzipper.Extract({ path: outputPath });
|
||||||
ZipReader.withDestinationPath(outputPath).viaBuffer(await fs.promises.readFile(destPath));
|
extractor.on('close', async () => {
|
||||||
const metaRaw = fs.readFileSync(outputPath + '/meta.json', 'utf-8');
|
const metaRaw = fs.readFileSync(outputPath + '/meta.json', 'utf-8');
|
||||||
const meta = JSON.parse(metaRaw);
|
const meta = JSON.parse(metaRaw);
|
||||||
|
|
||||||
@@ -115,12 +115,8 @@ export class ImportCustomEmojisProcessorService {
|
|||||||
cleanup();
|
cleanup();
|
||||||
|
|
||||||
this.logger.succ('Imported');
|
this.logger.succ('Imported');
|
||||||
} catch (e) {
|
});
|
||||||
if (e instanceof Error || typeof e === 'string') {
|
unzipStream.pipe(extractor);
|
||||||
this.logger.error(e);
|
this.logger.succ(`Unzipping to ${outputPath}`);
|
||||||
}
|
|
||||||
cleanup();
|
|
||||||
throw e;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,16 +1,16 @@
|
|||||||
import { Inject, Injectable } from '@nestjs/common';
|
import { Inject, Injectable } from '@nestjs/common';
|
||||||
|
import type * as Bull from 'bullmq';
|
||||||
|
|
||||||
import { UserFollowingService } from '@/core/UserFollowingService.js';
|
import { UserFollowingService } from '@/core/UserFollowingService.js';
|
||||||
import { UserBlockingService } from '@/core/UserBlockingService.js';
|
import { UserBlockingService } from '@/core/UserBlockingService.js';
|
||||||
import { bindThis } from '@/decorators.js';
|
import { bindThis } from '@/decorators.js';
|
||||||
import type Logger from '@/logger.js';
|
import type Logger from '@/logger.js';
|
||||||
|
|
||||||
|
import { QueueLoggerService } from '../QueueLoggerService.js';
|
||||||
|
import { RelationshipJobData } from '../types.js';
|
||||||
import type { UsersRepository } from '@/models/index.js';
|
import type { UsersRepository } from '@/models/index.js';
|
||||||
import { DI } from '@/di-symbols.js';
|
import { DI } from '@/di-symbols.js';
|
||||||
import { LocalUser, RemoteUser } from '@/models/entities/User.js';
|
import { LocalUser, RemoteUser } from '@/models/entities/User.js';
|
||||||
import { RelationshipJobData } from '../types.js';
|
|
||||||
import { QueueLoggerService } from '../QueueLoggerService.js';
|
|
||||||
import type * as Bull from 'bullmq';
|
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class RelationshipProcessorService {
|
export class RelationshipProcessorService {
|
||||||
|
@@ -181,7 +181,7 @@ export class ActivityPubServerService {
|
|||||||
undefined,
|
undefined,
|
||||||
inStock ? `${partOf}?${url.query({
|
inStock ? `${partOf}?${url.query({
|
||||||
page: 'true',
|
page: 'true',
|
||||||
cursor: followings.at(-1)!.id,
|
cursor: followings[followings.length - 1].id,
|
||||||
})}` : undefined,
|
})}` : undefined,
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -189,11 +189,7 @@ export class ActivityPubServerService {
|
|||||||
return (this.apRendererService.addContext(rendered));
|
return (this.apRendererService.addContext(rendered));
|
||||||
} else {
|
} else {
|
||||||
// index page
|
// index page
|
||||||
const rendered = this.apRendererService.renderOrderedCollection(
|
const rendered = this.apRendererService.renderOrderedCollection(partOf, user.followersCount, `${partOf}?page=true`);
|
||||||
partOf,
|
|
||||||
user.followersCount,
|
|
||||||
`${partOf}?page=true`,
|
|
||||||
);
|
|
||||||
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(rendered));
|
return (this.apRendererService.addContext(rendered));
|
||||||
@@ -273,7 +269,7 @@ export class ActivityPubServerService {
|
|||||||
undefined,
|
undefined,
|
||||||
inStock ? `${partOf}?${url.query({
|
inStock ? `${partOf}?${url.query({
|
||||||
page: 'true',
|
page: 'true',
|
||||||
cursor: followings.at(-1)!.id,
|
cursor: followings[followings.length - 1].id,
|
||||||
})}` : undefined,
|
})}` : undefined,
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -281,11 +277,7 @@ export class ActivityPubServerService {
|
|||||||
return (this.apRendererService.addContext(rendered));
|
return (this.apRendererService.addContext(rendered));
|
||||||
} else {
|
} else {
|
||||||
// index page
|
// index page
|
||||||
const rendered = this.apRendererService.renderOrderedCollection(
|
const rendered = this.apRendererService.renderOrderedCollection(partOf, user.followingCount, `${partOf}?page=true`);
|
||||||
partOf,
|
|
||||||
user.followingCount,
|
|
||||||
`${partOf}?page=true`,
|
|
||||||
);
|
|
||||||
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(rendered));
|
return (this.apRendererService.addContext(rendered));
|
||||||
@@ -318,10 +310,7 @@ export class ActivityPubServerService {
|
|||||||
|
|
||||||
const rendered = this.apRendererService.renderOrderedCollection(
|
const rendered = this.apRendererService.renderOrderedCollection(
|
||||||
`${this.config.url}/users/${userId}/collections/featured`,
|
`${this.config.url}/users/${userId}/collections/featured`,
|
||||||
renderedNotes.length,
|
renderedNotes.length, undefined, undefined, renderedNotes,
|
||||||
undefined,
|
|
||||||
undefined,
|
|
||||||
renderedNotes,
|
|
||||||
);
|
);
|
||||||
|
|
||||||
reply.header('Cache-Control', 'public, max-age=180');
|
reply.header('Cache-Control', 'public, max-age=180');
|
||||||
@@ -398,7 +387,7 @@ export class ActivityPubServerService {
|
|||||||
})}` : undefined,
|
})}` : undefined,
|
||||||
notes.length ? `${partOf}?${url.query({
|
notes.length ? `${partOf}?${url.query({
|
||||||
page: 'true',
|
page: 'true',
|
||||||
until_id: notes.at(-1)!.id,
|
until_id: notes[notes.length - 1].id,
|
||||||
})}` : undefined,
|
})}` : undefined,
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -406,9 +395,7 @@ export class ActivityPubServerService {
|
|||||||
return (this.apRendererService.addContext(rendered));
|
return (this.apRendererService.addContext(rendered));
|
||||||
} else {
|
} else {
|
||||||
// index page
|
// index page
|
||||||
const rendered = this.apRendererService.renderOrderedCollection(
|
const rendered = this.apRendererService.renderOrderedCollection(partOf, user.notesCount,
|
||||||
partOf,
|
|
||||||
user.notesCount,
|
|
||||||
`${partOf}?page=true`,
|
`${partOf}?page=true`,
|
||||||
`${partOf}?page=true&since_id=000000000000000000000000`,
|
`${partOf}?page=true&since_id=000000000000000000000000`,
|
||||||
);
|
);
|
||||||
|
@@ -3,8 +3,6 @@ import { fileURLToPath } from 'node:url';
|
|||||||
import { dirname } from 'node:path';
|
import { dirname } from 'node:path';
|
||||||
import { Inject, Injectable } from '@nestjs/common';
|
import { Inject, Injectable } from '@nestjs/common';
|
||||||
import rename from 'rename';
|
import rename from 'rename';
|
||||||
import sharp from 'sharp';
|
|
||||||
import { sharpBmp } from 'sharp-read-bmp';
|
|
||||||
import type { Config } from '@/config.js';
|
import type { Config } from '@/config.js';
|
||||||
import type { DriveFile, DriveFilesRepository } from '@/models/index.js';
|
import type { DriveFile, DriveFilesRepository } from '@/models/index.js';
|
||||||
import { DI } from '@/di-symbols.js';
|
import { DI } from '@/di-symbols.js';
|
||||||
@@ -20,9 +18,11 @@ import { contentDisposition } from '@/misc/content-disposition.js';
|
|||||||
import { FileInfoService } from '@/core/FileInfoService.js';
|
import { FileInfoService } from '@/core/FileInfoService.js';
|
||||||
import { LoggerService } from '@/core/LoggerService.js';
|
import { LoggerService } from '@/core/LoggerService.js';
|
||||||
import { bindThis } from '@/decorators.js';
|
import { bindThis } from '@/decorators.js';
|
||||||
import { isMimeImage } from '@/misc/is-mime-image.js';
|
|
||||||
import { correctFilename } from '@/misc/correct-filename.js';
|
|
||||||
import type { FastifyInstance, FastifyRequest, FastifyReply, FastifyPluginOptions } from 'fastify';
|
import type { FastifyInstance, FastifyRequest, FastifyReply, FastifyPluginOptions } from 'fastify';
|
||||||
|
import { isMimeImage } from '@/misc/is-mime-image.js';
|
||||||
|
import sharp from 'sharp';
|
||||||
|
import { sharpBmp } from 'sharp-read-bmp';
|
||||||
|
import { correctFilename } from '@/misc/correct-filename.js';
|
||||||
|
|
||||||
const _filename = fileURLToPath(import.meta.url);
|
const _filename = fileURLToPath(import.meta.url);
|
||||||
const _dirname = dirname(_filename);
|
const _dirname = dirname(_filename);
|
||||||
@@ -180,8 +180,8 @@ export class FileServerService {
|
|||||||
reply.header('Content-Disposition',
|
reply.header('Content-Disposition',
|
||||||
contentDisposition(
|
contentDisposition(
|
||||||
'inline',
|
'inline',
|
||||||
correctFilename(file.filename, image.ext),
|
correctFilename(file.filename, image.ext)
|
||||||
),
|
)
|
||||||
);
|
);
|
||||||
return image.data;
|
return image.data;
|
||||||
}
|
}
|
||||||
@@ -278,11 +278,11 @@ export class FileServerService {
|
|||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
const data = (await sharpBmp(file.path, file.mime, { animated: !('static' in request.query) }))
|
const data = (await sharpBmp(file.path, file.mime, { animated: !('static' in request.query) }))
|
||||||
.resize({
|
.resize({
|
||||||
height: 'emoji' in request.query ? 128 : 320,
|
height: 'emoji' in request.query ? 128 : 320,
|
||||||
withoutEnlargement: true,
|
withoutEnlargement: true,
|
||||||
})
|
})
|
||||||
.webp(webpDefault);
|
.webp(webpDefault);
|
||||||
|
|
||||||
image = {
|
image = {
|
||||||
data,
|
data,
|
||||||
@@ -355,8 +355,8 @@ export class FileServerService {
|
|||||||
reply.header('Content-Disposition',
|
reply.header('Content-Disposition',
|
||||||
contentDisposition(
|
contentDisposition(
|
||||||
'inline',
|
'inline',
|
||||||
correctFilename(file.filename, image.ext),
|
correctFilename(file.filename, image.ext)
|
||||||
),
|
)
|
||||||
);
|
);
|
||||||
return image.data;
|
return image.data;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
@@ -224,18 +224,7 @@ export class ServerService implements OnApplicationShutdown {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
if (this.config.socket) {
|
fastify.listen({ port: this.config.port, host: '0.0.0.0' });
|
||||||
if (fs.existsSync(this.config.socket)) {
|
|
||||||
fs.unlinkSync(this.config.socket);
|
|
||||||
}
|
|
||||||
fastify.listen({ path: this.config.socket }, (err, address) => {
|
|
||||||
if (this.config.chmodSocket) {
|
|
||||||
fs.chmodSync(this.config.socket!, this.config.chmodSocket);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
fastify.listen({ port: this.config.port, host: '0.0.0.0' });
|
|
||||||
}
|
|
||||||
|
|
||||||
await fastify.ready();
|
await fastify.ready();
|
||||||
}
|
}
|
||||||
|
@@ -1,18 +1,18 @@
|
|||||||
import { Inject, Injectable } from '@nestjs/common';
|
import { Inject, Injectable } from '@nestjs/common';
|
||||||
import { IsNull } from 'typeorm';
|
import { IsNull } from 'typeorm';
|
||||||
import vary from 'vary';
|
import vary from 'vary';
|
||||||
import fastifyAccepts from '@fastify/accepts';
|
|
||||||
import { DI } from '@/di-symbols.js';
|
import { DI } from '@/di-symbols.js';
|
||||||
import type { UsersRepository } from '@/models/index.js';
|
import type { UsersRepository } from '@/models/index.js';
|
||||||
import type { Config } from '@/config.js';
|
import type { Config } from '@/config.js';
|
||||||
import { escapeAttribute, escapeValue } from '@/misc/prelude/xml.js';
|
import { escapeAttribute, escapeValue } from '@/misc/prelude/xml.js';
|
||||||
import type { User } from '@/models/entities/User.js';
|
import type { User } from '@/models/entities/User.js';
|
||||||
import * as Acct from '@/misc/acct.js';
|
import * as Acct from '@/misc/acct.js';
|
||||||
import { UserEntityService } from '@/core/entities/UserEntityService.js';
|
|
||||||
import { bindThis } from '@/decorators.js';
|
|
||||||
import { NodeinfoServerService } from './NodeinfoServerService.js';
|
import { NodeinfoServerService } from './NodeinfoServerService.js';
|
||||||
|
import { UserEntityService } from '@/core/entities/UserEntityService.js';
|
||||||
import type { FindOptionsWhere } from 'typeorm';
|
import type { FindOptionsWhere } from 'typeorm';
|
||||||
|
import { bindThis } from '@/decorators.js';
|
||||||
import type { FastifyInstance, FastifyPluginOptions } from 'fastify';
|
import type { FastifyInstance, FastifyPluginOptions } from 'fastify';
|
||||||
|
import fastifyAccepts from '@fastify/accepts';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class WellKnownServerService {
|
export class WellKnownServerService {
|
||||||
|
@@ -1,8 +1,8 @@
|
|||||||
import { randomUUID } from 'node:crypto';
|
|
||||||
import { pipeline } from 'node:stream';
|
import { pipeline } from 'node:stream';
|
||||||
import * as fs from 'node:fs';
|
import * as fs from 'node:fs';
|
||||||
import { promisify } from 'node:util';
|
import { promisify } from 'node:util';
|
||||||
import { Inject, Injectable } from '@nestjs/common';
|
import { Inject, Injectable } from '@nestjs/common';
|
||||||
|
import { v4 as uuid } from 'uuid';
|
||||||
import { DI } from '@/di-symbols.js';
|
import { DI } from '@/di-symbols.js';
|
||||||
import { getIpHash } from '@/misc/get-ip-hash.js';
|
import { getIpHash } from '@/misc/get-ip-hash.js';
|
||||||
import type { LocalUser, User } from '@/models/entities/User.js';
|
import type { LocalUser, User } from '@/models/entities/User.js';
|
||||||
@@ -362,7 +362,7 @@ export class ApiCallService implements OnApplicationShutdown {
|
|||||||
if (err instanceof ApiError || err instanceof AuthenticationError) {
|
if (err instanceof ApiError || err instanceof AuthenticationError) {
|
||||||
throw err;
|
throw err;
|
||||||
} else {
|
} else {
|
||||||
const errId = randomUUID();
|
const errId = uuid();
|
||||||
this.logger.error(`Internal error occurred in ${ep.name}: ${err.message}`, {
|
this.logger.error(`Internal error occurred in ${ep.name}: ${err.message}`, {
|
||||||
ep: ep.name,
|
ep: ep.name,
|
||||||
ps: data,
|
ps: data,
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user