Merge pull request #77 from kokonect-link/develop

Release: 13.14.2-cp-4.2.0
This commit is contained in:
NoriDev 2023-07-29 19:55:05 +09:00 committed by GitHub
commit 0e281f5c8a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
638 changed files with 16876 additions and 8665 deletions

View file

@ -30,6 +30,10 @@ url: https://example.tld/
# The port that your CherryPick server should listen on.
port: 3000
# You can also use UNIX domain socket.
# socket: /path/to/misskey.sock
# chmodSocket: '777'
# ┌──────────────────────────┐
#───┘ PostgreSQL configuration └────────────────────────────────
@ -78,6 +82,8 @@ redis:
#pass: example-pass
#prefix: example-prefix
#db: 1
# You can specify more ioredis options...
#username: example-username
#redisForPubsub:
# host: localhost
@ -86,6 +92,8 @@ redis:
# #pass: example-pass
# #prefix: example-prefix
# #db: 1
# # You can specify more ioredis options...
# #username: example-username
#redisForJobQueue:
# host: localhost
@ -94,6 +102,8 @@ redis:
# #pass: example-pass
# #prefix: example-prefix
# #db: 1
# # You can specify more ioredis options...
# #username: example-username
# ┌───────────────────────────┐
#───┘ MeiliSearch configuration └─────────────────────────────
@ -104,6 +114,7 @@ redis:
# apiKey: ''
# ssl: true
# index: ''
# scope: local
# ┌───────────────┐
#───┘ ID generation └───────────────────────────────────────────

View file

@ -1,12 +1,12 @@
{
"name": "Misskey",
"name": "CherryPick",
"dockerComposeFile": "docker-compose.yml",
"service": "app",
"workspaceFolder": "/workspace",
"features": {
"ghcr.io/devcontainers-contrib/features/pnpm:2": {},
"ghcr.io/devcontainers/features/node:1": {
"version": "18.16.0"
"version": "20.3.1"
}
},
"forwardPorts": [3000],

View file

@ -6,6 +6,10 @@ indent_size = 2
charset = utf-8
insert_final_newline = true
end_of_line = lf
trim_trailing_whitespace = true
[*.md]
trim_trailing_whitespace = false
[*.{yml,yaml}]
indent_style = space

View file

@ -54,7 +54,7 @@ Please include errors from the developer console and/or server log files if you
* Installation Method or Hosting Service: <!-- Example: docker compose, k8s/docker, systemd, "CherryPick install shell script", development environment -->
* CherryPick: 13.x.x-cp-4.x.x
* Node: 18.x.x
* Node: 20.x.x
* PostgreSQL: 15.x.x
* Redis: 7.x.x
* OS and Architecture: <!-- Example: Ubuntu 22.04.2 LTS aarch64 -->

View file

@ -37,7 +37,7 @@ jobs:
with:
version: 8
run_install: false
- name: Use Node.js 18.x
- name: Use Node.js 20.x
uses: actions/setup-node@v3.6.0
with:
node-version-file: '.node-version'

View file

@ -13,7 +13,7 @@ jobs:
strategy:
matrix:
node-version: [18.x]
node-version: [20.x]
services:
postgres:

View file

@ -16,7 +16,7 @@ jobs:
strategy:
matrix:
node-version: [18.x]
node-version: [20.x]
# See supported Node.js release schedule at https://nodejs.org/en/about/releases/
steps:

View file

@ -13,7 +13,7 @@ jobs:
strategy:
matrix:
node-version: [18.x]
node-version: [20.x]
steps:
- uses: actions/checkout@v3.3.0
@ -51,7 +51,7 @@ jobs:
strategy:
fail-fast: false
matrix:
node-version: [18.x]
node-version: [20.x]
browser: [chrome]
services:

View file

@ -16,7 +16,7 @@ jobs:
strategy:
matrix:
node-version: [18.x]
node-version: [20.x]
steps:
- uses: actions/checkout@v3.3.0

3
.gitignore vendored
View file

@ -65,4 +65,5 @@ temp
*.blend4
*.blend5
.pnpm-store/
# VSCode addon
.favorites.json

View file

@ -1 +1 @@
18.16.0
20.3.1

View file

@ -0,0 +1,52 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="cleanup &amp; rebuild &amp; migrate" type="js.build_tools.npm">
<package-json value="$PROJECT_DIR$/package.json" />
<command value="run" />
<scripts>
<script value="start" />
</scripts>
<node-interpreter value="project" />
<envs>
<env name="NODE_ENV" value="development" />
</envs>
<method v="2">
<option name="NpmBeforeRunTask" enabled="true">
<package-json value="$PROJECT_DIR$/package.json" />
<command value="run" />
<scripts>
<script value="cleanall" />
</scripts>
<node-interpreter value="project" />
<envs />
</option>
<option name="NpmBeforeRunTask" enabled="true">
<package-json value="$PROJECT_DIR$/package.json" />
<command value="install" />
<node-interpreter value="project" />
<envs>
<env name="NODE_ENV" value="development" />
</envs>
</option>
<option name="NpmBeforeRunTask" enabled="true">
<package-json value="$PROJECT_DIR$/package.json" />
<command value="run" />
<scripts>
<script value="build" />
</scripts>
<node-interpreter value="project" />
<envs>
<env name="NODE_ENV" value="development" />
</envs>
</option>
<option name="NpmBeforeRunTask" enabled="true">
<package-json value="$PROJECT_DIR$/package.json" />
<command value="run" />
<scripts>
<script value="migrate" />
</scripts>
<node-interpreter value="project" />
<envs />
</option>
</method>
</configuration>
</component>

View file

@ -3,7 +3,7 @@
<package-json value="$PROJECT_DIR$/package.json" />
<command value="run" />
<scripts>
<script value="start" />
<script value="build" />
</scripts>
<node-interpreter value="project" />
<envs>
@ -27,26 +27,6 @@
<env name="NODE_ENV" value="development" />
</envs>
</option>
<option name="NpmBeforeRunTask" enabled="true">
<package-json value="$PROJECT_DIR$/package.json" />
<command value="run" />
<scripts>
<script value="build" />
</scripts>
<node-interpreter value="project" />
<envs>
<env name="NODE_ENV" value="development" />
</envs>
</option>
<option name="NpmBeforeRunTask" enabled="true">
<package-json value="$PROJECT_DIR$/package.json" />
<command value="run" />
<scripts>
<script value="migrate" />
</scripts>
<node-interpreter value="project" />
<envs />
</option>
</method>
</configuration>
</component>

View file

@ -12,10 +12,83 @@
-->
## 13.x.x (unreleased)
## 13.14.2
### Client
- リストTLで、ユーザーが追加・削除されてもTLを初期化しないように
- URL取得変数を関数に変更 CURRENT_URL -> Mk:url()
- Fix: モバイル表示のときページ下部がナビゲーションバーに隠れる問題を修正
- Fix: 一部モーダルダイアログでスクロールできない問題を修正
- Fix: Selecting all emojis in Custom emoji is impossible
- Fix: PhotoSwipeによるメモリリークの修正
### Server
- Fix: APIのオフセットが壊れていたせいで「もっと見る」でもっと見れない問題を修正
- Fix: 外部サーバーの投稿がタイムラインに表示されないことがある問題を修正
## 13.14.1
### General
- 招待機能を改善しました
* 過去に発行した招待コードを確認できるようになりました
* ロールごとに招待コードの発行数制限と制限対象期間、有効期限を設定できるようになりました
* 招待コードを作成したユーザーと使用したユーザーを確認できるようになりました
- ユーザーにロールが期限付きでアサインされている場合、その期限をユーザーのモデレーションページで確認できるようになりました
- identicon生成を無効にしてパフォーマンスを向上させることができるようになりました
- サーバーのマシン情報の公開を無効にしてパフォーマンスを向上させることができるようになりました
### Client
- deck UIのカラムのメニューからアンテナとリストの編集画面を開けるように
- ドライブファイルのメニューで画像をクロップできるように
- 画像を動画と同様に簡単に隠せるように
- Enhance: ノートの埋め込みが複数画像と動画を表示されるように
- オリジナル画像を保持せずにアップロードする場合webpでアップロードされるように(Safari以外)
- 見たことのあるRenoteを省略して表示をオンのときに自分のnoteのrenoteを省略するように
- フォルダーやファイルに対しても開発者モード使用時、IDをコピーできるように
- 引用対象を「もっと見る」で展開した場合、「閉じる」で畳めるように
- プロフィールURLをコピーできるボタンを追加 #11190
- `CURRENT_URL`で現在表示中のURLを取得できるように(AiScript)
- ユーザーのContextMenuに「アンテナに追加」ボタンを追加
- フォローやお気に入り登録をしていないチャンネルを開く時は概要ページを開くように
- 画面ビューワをタップした場合、マウスクリックと同様に画像ビューワを閉じるように
- オフライン時の画面にリロードボタンを追加
- Renote時に公開範囲のデフォルト設定が適用されるように
- Deckで非ルートページにアクセスした際に簡易UIで表示しない設定を追加
- ロール設定画面でロールIDを確認できるように
- コンテキストメニュー表示時のパフォーマンスを改善
- フォロー/フォロワー非公開時の表示を改善
- 本文にMFMが含まれている場合に自動でたたまれる機能が、返信先や引用RNにも適用されるように
- position は対象外になりました
- AiScriptを0.15.0に更新
- Fix: サーバーメトリクスが90度傾いている
- Fix: 非ログイン時にクレデンシャルが必要なページに行くとエラーが出る問題を修正
- Fix: sparkle内にリンクを入れるとクリック不能になる問題の修正
- Fix: ZenUIでポップアップの表示位置がおかしい問題を修正
- Fix: ページ遷移でスクロール位置が保持されない問題を修正
- Fix: フォルダーのページネーションが機能しない #11180
- Fix: 長い文章を投稿する際、プレビューが画面からはみ出る問題を修正
- Fix: システムフォント設定が正しく反映されない問題を修正
- Fix: アンケート終了時のプッシュ通知が正しく表示されない問題を修正
- Fix: MasterVolumeが0の時だけでなく各通知音の音量設定が0のときも、HTMLAudioElement.playが実行されないように変更
### Server
- JSON.parse の回数を削減することで、ストリーミングのパフォーマンスを向上しました
- nsfwjs のモデルロードを排他することで、重複ロードによってメモリ使用量が増加しないように
- 連合の配送ジョブのパフォーマンスを向上ロック機構の見直し、Redisキャッシュの活用
- featuredートのsignedGet回数を減らしました
- ActivityPubの署名用鍵長を2048bitに変更しパフォーマンスを向上(新規アカウントのみ)
- リモートサーバーのセンシティブなファイルのキャッシュだけを無効化できるオプションを追加
- 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

View file

@ -19,16 +19,70 @@
-->
# 릴리즈 노트
이 문서는 CherryPick의 변경 사항만 포함합니다.
## 13.14.2-cp-4.2.0
출시일: 2023/07/29<br>
전체 변경 사항을 확인하려면, [CHANGELOG.md#13142](CHANGELOG.md#13142) 문서를 참고하십시오.
### General
- 리액션 수신의 기본값을 전체로 설정
- 제어판 메인 화면에 서버 통계 추가
- 노트의 시간을 일자로 표시하는 기능
- 고양이 타임라인 추가
- 미디어 타임라인 개선
- 타임라인 편집 기능 추가
- 모바일 환경에서 타임라인의 헤더 디자인을 변경할 수 있음
- 「제어판 - 유저」에서 최근 온라인 유저를 정렬해서 볼 수 있음
- 「이미 본 리노트를 간략화하기」 옵션의 기본값을 켜짐으로 변경 (revert 94bd0fa9)
- 서브 노트에 액션 버튼을 표시하는 기능
- 「발견하기」의 인기 태그 기본값을 펼침으로 설정
- 초대 코드 해지 기능을 새 버전에 맞게 개선
- 리모트 캐시 파일을 별도의 Object Storage에 저장하도록 설정 ([libnare/mk-castella@0d93433](https://github.com/libnare/mk-castella/commit/0d93433b0836238f518658b5719ce335060963b0))
- Byeolvit 테마 추가 ([Luminon/Byeolvit-Theme](https://github.com/Luminon/Byeolvit-Theme), [libnare/mk-castella@3c95399](https://github.com/libnare/mk-castella/commit/3c95399d0989015bb92836e48d010df07619038b))
- buttersc.one 테마 추가 ([libnare/mk-castella@6f15fa1](https://github.com/libnare/mk-castella/commit/6f15fa10b8022d0830254b8f615153d11c441480))
- stella.place 테마 추가 ([libnare/mk-castella@f6f77db](https://github.com/libnare/mk-castella/commit/f6f77dbd7f94b87edd3550ecf59e2bbd1fb3c708))
- 이모지를 한 번에 두 개 이상 업로드할 수 있는 옵션 추가
### Client
- (Friendly) 데스크톱 모드에서 타임라인 옆에 위젯 영역을 배치하도록
- (Friendly) 위젯 영역과 알림 영역의 현재 상태에 따라서 아이콘을 다르게 설정
- 리노트 전 확인 팝업을 띄움
- 유저 팝업 디자인 개선
- 절대 시간으로 표시할 때 툴팁에서는 상대 시간을 표기
- 환영 메시지를 MFM으로 렌더링
- 노트 내용이 없으면 번역 버튼을 활성화하지 않음
- 노트 작성 폼 개선
- 내용이 너무 길면 스크롤 가능하도록
- 브라우저의 최대 높이를 초과하지 않도록
- MkDialog 버튼이 3개 이상이면 정렬을 변경하도록
- 리노트 유저 팝업의 디자인 일부 개선
- 네비게이션 바의 블러 처리 추가
- 헤더의 블러 설정 추가
- 「이미 팔로우한 경우 알림 필드에 팔로우 버튼을 표시하지 않음」설정 사용 시, 팔로우 했다는 문구를 표시하도록
- 흐림 효과를 비활성화 하면 알림을 불투명하게 표시하도록
- 설정 - 일반에 있는 일부 기능의 위치를 CherryPick 으로 이동
- 리노트할 때 확인 팝업 표시 유무를 선택할 수 있음
- Fix: 그룹 초대 알림 아이콘이 잘못 표시되는 문제
- Fix: 노트 디자인이 올바르지 않게 표시되는 문제
- Fix: 프로필 아이콘이 투명일 때 노트 답글선이 비치는 문제
- Fix: 서브 노트의 내용 숨김 버튼의 디자인이 잘못 표시되는 문제
- Fix: 「좋아요만 받기」로 설정된 노트에서 리액션 버튼이 여러 개 표시되는 문제
- Fix: 「좋아요만 받기」로 설정된 노트에서 좋아요를 취소하려고 할 때 아이콘이 잘못 표시되는 문제
### Server
- 미디어 타임라인 개선
- 오류 페이지 재구성
---
## 13.13.2-cp-4.1.0
출시일: 2023/06/20<br>
전체 변경 사항을 확인하려면, [CHANGELOG.md#13132](CHANGELOG.md#13132) 문서를 참고하십시오.
### General
- 타임라인에 노트의 답글을 표시하는 옵션의 기본값을 켜짐으로 설정
- 네비게이션 바의 배치를 수정
- 네비게이션 메뉴의 배치를 수정
- 프로필 아이콘의 기본값을 사각형으로 설정
- 미디어 타임라인 추가 ([kiyo4act/misskey.designc01be0d](https://github.com/kiyo4act/misskey.design/commit/c01be0dc7674cdf0bcac6081c63baab52c4c9abe))
- ruby 표기 지원 ([yuriha-chan/misskey@0a109d4](https://github.com/yuriha-chan/misskey/commit/0a109d4f7442f8eedc48693b09ad2fd0b61e67a5), [yuriha-chan/misskey@446f0c2](https://github.com/yuriha-chan/misskey/commit/446f0c2ea5cc9a9f7f48a75935bce550bd0b3095), [yuriha-chan/misskey@4cfd28a](https://github.com/yuriha-chan/misskey/commit/4cfd28a452be0cdcc1328d77ab0db6dca627ca23), [yuriha-chan/misskey@dc6a6dc](https://github.com/yuriha-chan/misskey/commit/dc6a6dcdc3c2ac5b836570defb14ef4d441725e8))
@ -38,7 +92,7 @@
- 네비게이션 메뉴에 배너 표시 옵션 추가
- 노트에서 프로필 아이콘을 숨기는 옵션 추가
- 닉네임 기능 ([shrimpia/misskey@126f145](https://github.com/shrimpia/misskey/commit/126f145560caa0cc34fe8d2c9ee22f3be922ea10), [shrimpia/misskey@58f70be](https://github.com/shrimpia/misskey/commit/58f70beb9aff2287a64d903b43583184340294aa))
- 유저 페이지에서 사용자의 이름을 클릭 또는 탭하여 원하는 이름으로 변경할 수 있습니다.
- 유저 페이지에서 사용자의 이름을 클릭 또는 탭하여 원하는 이름으로 변경할 수 있습니다.
- 「노트 액션 버튼을 마우스를 올렸을 때에만 표시」 옵션을 켰을 때, 자세히 버튼을 표시하도록 변경 ([shrimpia/misskey@4802191](https://github.com/shrimpia/misskey/commit/48021913bb9b6b2a314e8d88e3816f6f66a52888))
- 「이미 팔로우한 경우 알림 필드에 팔로우 버튼을 표시하지 않음」을 선택 사항으로 설정 ([shrimpia/misskey@9345149](https://github.com/shrimpia/misskey/commit/9345149f5d0447058a6ed1524708925a84744bd7))
- 노트 작성 폼에서 본문 미리보기 상태 기억 ([shrimpia/misskey](https://github.com/shrimpia/misskey))
@ -52,7 +106,7 @@
### Client
- (Friendly) 일부 페이지를 제외하고 플로팅 버튼을 표시하지 않음
- 모바일에서 UI 흐림 효과를 비활성화 했을 때 가독성 향상
- 토스트 알림의 배경이 불투명하게 표시되도록
- 토스트 알림의 배경이 불투명하게 표시되도록
- 헤더의 배경이 불투명하게 표시되도록
- MFM 도움말에 검색 섹션 추가
- 노트 디자인 개선

View file

@ -214,30 +214,13 @@ CherryPick uses [Storybook](https://storybook.js.org/) for UI development.
### Setup & Run
#### Universal
##### Setup
```bash
pnpm --filter cherrypick-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
#### Setup
```bash
pnpm --filter cherrypick-js build
```
##### Run
#### Run
```bash
pnpm --filter frontend storybook-dev
@ -294,11 +277,12 @@ You can override the component meta by creating a meta story file (`MyComponent.
```ts
export const argTypes = {
scale: {
control: {
type: 'range',
min: 1,
max: 4,
},
control: {
type: 'range',
min: 1,
max: 4,
},
},
};
```
@ -435,7 +419,7 @@ export const paramDef = {
```
### コネクションには`markRaw`せよ
**Vueのコンポーネントのdataオプションとして**cherrypick.jsのコネクションを設定するとき、必ず`markRaw`でラップしてください。インスタンスが不必要にリアクティブ化されることで、misskey.js内の処理で不具合が発生するとともに、パフォーマンス上の問題にも繋がる。なお、Composition APIを使う場合はこの限りではない(リアクティブ化はマニュアルなため)。
**Vueのコンポーネントのdataオプションとして**cherrypick.jsのコネクションを設定するとき、必ず`markRaw`でラップしてください。インスタンスが不必要にリアクティブ化されることで、cherrypick.js内の処理で不具合が発生するとともに、パフォーマンス上の問題にも繋がる。なお、Composition APIを使う場合はこの限りではない(リアクティブ化はマニュアルなため)。
### JSONのimportに気を付けよう
TypeScriptでjsonをimportすると、tscでコンパイルするときにそのjsonファイルも一緒にdistディレクトリに吐き出されてしまう。この挙動により、意図せずファイルの書き換えが発生することがあるので、jsonをimportするときは書き換えられても良いものかどうか確認すること。書き換えされて欲しくない場合は、importで読み込むのではなく、`fs.readFileSync`などの関数を使って読み込むようにすればよい。

View file

@ -1,6 +1,6 @@
# syntax = docker/dockerfile:1.4
ARG NODE_VERSION=18.16.0-bullseye
ARG NODE_VERSION=20.3.1-bullseye
# build assets & compile TypeScript

View file

@ -54,6 +54,7 @@ describe('After setup instance', () => {
cy.get('[data-cy-signup]').click();
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-modal-dialog-ok]').click();
cy.get('[data-cy-signup-rules-continue]').should('not.be.disabled');
cy.get('[data-cy-signup-rules-continue]').click();
@ -78,6 +79,7 @@ describe('After setup instance', () => {
cy.get('[data-cy-signup]').click();
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-modal-dialog-ok]').click();
cy.get('[data-cy-signup-rules-continue]').should('not.be.disabled');
cy.get('[data-cy-signup-rules-continue]').click();

View file

@ -2,14 +2,14 @@
* Gulp tasks
*/
const fs = require('fs');
const gulp = require('gulp');
const replace = require('gulp-replace');
const terser = require('gulp-terser');
const cssnano = require('gulp-cssnano');
import * as fs from 'node:fs';
import gulp from 'gulp';
import replace from 'gulp-replace';
import terser from 'gulp-terser';
import cssnano from 'gulp-cssnano';
const locales = require('./locales');
const meta = require('./package.json');
import locales from './locales/index.js';
import meta from './package.json' assert { type: "json" };
gulp.task('copy:backend:views', () =>
gulp.src('./packages/backend/src/server/web/views/**/*').pipe(gulp.dest('./packages/backend/built/server/web/views'))

View file

@ -41,17 +41,23 @@ unfavorite: "إزالة من المفضلة"
favorited: "أُضيف إلى المفضلة."
alreadyFavorited: "تمت إضافته بالفعل إلى المفضلة."
cantFavorite: "تعذرت الإضافة إلى المفضلة."
pin: "دبّسها على الصفحة الشخصية"
unpin: "ألغ تدبيسها من ملفك الشخصي"
pin: "ثبتها على الصفحة الشخصية"
unpin: "فكها من ملفك الشخصي"
copyContent: "انسخ المحتوى"
copyLink: "انسخ الرابط"
delete: "حذف"
deleteAndEdit: "إزالة وإعادة الصياغة"
deleteAndEditConfirm: "أمتأكد من حذف الملاحظة؟ ستفقد كل مشاركاتها، والتفاعلات، والردود عليها."
addToList: "أضفه إلى قائمة"
addToAntenna: "أضف إلى هوائي"
sendMessage: "أرسل رسالة"
copyRSS: "انسخ رابط RSS"
copyUsername: "انسخ اسم المستخدم"
copyUserId: "انسخ معرف المستخدم"
copyNoteId: "انسخ معرف الملاحظة"
copyFileId: "انسخ معرّف الملف"
copyFolderId: "انسخ معرّف المجلد"
copyProfileUrl: "انسخ رابط الملف الشخصي"
searchUser: "ابحث عن مستخدمين"
reply: "رد"
loadMore: "عرض المزيد"
@ -106,8 +112,8 @@ cantReRenote: "لا يمكنك إعادة نشر ملاحظة معاد نشره
quote: "اقتبس"
inChannelRenote: "إعادة نشر في قناة"
inChannelQuote: "اقتباس في قناة"
pinnedNote: "ملاحظة مدبسة"
pinned: "دبّسها على الصفحة الشخصية"
pinnedNote: "ملاحظة مثبتة"
pinned: "ثبتها على الصفحة الشخصية"
you: "أنت"
clickToShow: "اضغط للعرض"
sensitive: "محتوى حساس"
@ -134,8 +140,10 @@ unblockConfirm: "أمتأكد من إلغاء حجب هذا الحساب؟"
suspendConfirm: "أمتأكد من تعليق الحساب؟"
unsuspendConfirm: "أمتأكد من إلغاء تعليق؟"
selectList: "اختر قائمة"
editList: "عدّل القائمة"
selectChannel: "اختر قناة"
selectAntenna: "اختر هوائيًا"
editAntenna: "عدّل الهوائي"
selectWidget: "اختر ودجة"
editWidgets: "عدّل الودجات"
editWidgetsExit: "تم"
@ -206,7 +214,7 @@ blockedUsers: "الحسابات المحجوبة"
noUsers: "ليس هناك مستخدمون"
editProfile: "تعديل الملف التعريفي"
noteDeleteConfirm: "هل تريد حذف هذه الملاحظة؟"
pinLimitExceeded: "لا يمكنك تدبيس الملاحظات بعد الآن."
pinLimitExceeded: "لا يمكنك تثبيت الملاحظات بعد الآن."
intro: "لقد انتهت عملية تنصيب CherryPick. الرجاء إنشاء حساب إداري."
done: "تمّ"
processing: "المعالجة جارية"
@ -305,7 +313,7 @@ copyUrl: "انسخ الرابط"
rename: "إعادة التسمية"
avatar: "الصورة الرمزية"
banner: "الصورة الرأسية"
nsfw: "محتوى حساس"
displayOfSensitiveMedia: "عرض المحتوى الحساس"
whenServerDisconnected: "عند فقدان الاتصال بالخادم"
disconnectedFromServer: "قُطِع الإتصال بالخادم"
reload: "انعش"
@ -344,12 +352,12 @@ iconUrl: "رابط الأيقونة"
bannerUrl: "رابط صورة اللافتة"
backgroundImageUrl: "رابط صورة الخلفية"
basicInfo: "المعلومات الأساسية "
pinnedUsers: "المستخدمون المدبسون"
pinnedUsersDescription: "قائمة المستخدمين المدبسين في لسان \"استكشف\" ، اجعل كل اسم مستخدم في سطر لوحده."
pinnedPages: "الصفحات المدبسة"
pinnedPagesDescription: "أدخل مسار الصفحات التي تريد تدبيسها في أعلى هذا الموقع، اجعل كل مسار في سطر لوحده."
pinnedClipId: "معرّف المشبك المدبس"
pinnedNotes: "ملاحظة مدبسة"
pinnedUsers: "المستخدمون المثبتون"
pinnedUsersDescription: "قائمة المستخدمين المثبتين في لسان \"استكشف\" ، اجعل كل اسم مستخدم في سطر لوحده."
pinnedPages: "الصفحات المثبتة"
pinnedPagesDescription: "أدخل مسار الصفحات التي تريد تثبيتها في أعلى هذا الموقع، اجعل كل مسار في سطر لوحده."
pinnedClipId: "معرّف المشبك المثبت"
pinnedNotes: "ملاحظة مثبتة"
hcaptcha: "hCaptcha"
enableHcaptcha: "فعّل hCaptcha"
hcaptchaSiteKey: "مفتاح الموقع"
@ -398,6 +406,7 @@ totp: "تطبيق استيثاق"
moderator: "مشرِف"
moderation: "الإشراف"
nUsersMentioned: "{n} مستخدمين أُشير إليهم"
securityKeyAndPasskey: "الأمن ومفاتيح الأمان"
securityKey: "مفتاح الأمان"
lastUsed: "آخر استخدام"
lastUsedAt: "آخر استخدام: {t}"
@ -462,6 +471,7 @@ uiLanguage: "لغة واجهة المستخدم"
groupInvited: "دُعيت إلى فريقٍ"
aboutX: "عن {x}"
emojiStyle: "نمط الوجوه التعبيرية"
showNoteActionsOnlyHover: "أظهر الإجراءات عند التمرير فوق الملاحظة"
youHaveNoGroups: "لا تمتلك أية فِرَق"
joinOrCreateGroup: "احصل على دعوة لفريق أو أنشئ واحدًا."
noHistory: "السجل فارغ"
@ -496,10 +506,12 @@ objectStoragePrefix: "البادئة"
objectStoragePrefixDesc: "ستُحفظ الملفات في مجلدات تحوي اسماءها هذه البادئة."
objectStorageEndpoint: "نقطة النهاية"
objectStorageRegion: "المنطقة"
objectStorageRegionDesc: "حدد منطقة مثل \"xx-east-1\". إذا كانت خدمتك لا تميز بين المناطق استخدم \"us-east-1\" أو اتركها فارغة إذا كنت تستخدم متغيرات البيئة أو ملفات ضبط AWS."
objectStorageUseSSL: "استخدم SSL"
objectStorageUseSSLDesc: "عطل هذا الخيار إذا لم ترد استخدام API عبر HTTPS"
objectStorageUseProxy: "اتصل عبر وكيل"
objectStorageUseProxyDesc: "عطل هذا الخيار إذا لم ترد استخدام API عبر وكيل"
objectStorageSetPublicRead: "عينها ك\"علنية\" عند الرفع"
serverLogs: "سجلات الخادم"
deleteAll: "حذف الكل"
showFixedPostForm: "أظهر نموذج الكتابة في أعلى الصفحة"
@ -543,6 +555,7 @@ accountDeletedDescription: "حُذف هذا الحساب."
menu: "القائمة"
divider: "فاصل"
addItem: "إضافة عنصر"
rearrange: "أعد الترتيب"
relays: "المُرَحلات"
addRelay: "إضافة مُرحّل"
inboxUrl: "رابط صندوق الوارد"
@ -566,6 +579,7 @@ leaveConfirm: "لديك تغييرات غير محفوظة. أتريد المت
manage: "إدارة "
plugins: "الإضافات"
preferencesBackups: "النُسخ الاحتياطية للإعدادات"
useBlurEffectForModal: "استخدم تأثير الطمس في المشروط"
useFullReactionPicker: "استخدم الحجم الكامل لمنتقي التفاعلات"
width: "العرض"
height: "الإرتفاع"
@ -641,6 +655,7 @@ clip: "مِشبك"
createNew: "أنشِئ جديد"
optional: "اختياري"
createNewClip: "أنشئ مِشبكَا جديدًا"
confirmToUnclipAlreadyClippedNote: "هذه الملاحظة تنتمي للمشبك {name} سلفًا، أتريد حذفها منه⸮"
public: "علني"
i18nInfo: "يترجم متطوعون ميسكي إلى عدة لغات، يمكنك المساعدة عبر {link}"
manageAccessTokens: "إدارة رموز الوصول"
@ -662,6 +677,7 @@ driveFilesCount: "عدد الملفات في قرص التخزين"
driveUsage: "المستغل من قرص التخزين"
noCrawle: "ارفض فهرسة زاحف الويب"
noCrawleDescription: "يطلب من محركات البحث ألّا يُفهرسوا ملفك الشخصي وملاحظات وصفحاتك وما شابه."
lockedAccountInfo: "ستكون هذه الملاحظة مرئية للجميع مالم تحدد مرئتيها إلى \"للمتابعين فقط\""
alwaysMarkSensitive: "علّم افتراضيًا جميع ملاحظاتي كذات محتوى حساس"
loadRawImages: "حمّل الصور الأصلية بدلًا من المصغرات"
disableShowingAnimatedImages: "لا تشغّل الصور المتحركة"
@ -680,6 +696,8 @@ developer: "المطور"
makeExplorable: "أظهر الحساب في صفحة \"استكشاف\""
makeExplorableDescription: "بتعطيل هذا الخيار لن يظهر حسابك في صفحة \"استكشاف\""
showGapBetweenNotesInTimeline: "أظهر فجوات بين المشاركات في الخيط الزمني"
left: "يسار"
center: "وسط"
wide: "عريض"
narrow: "رفيع"
reloadToApplySetting: "سيُطبق هذا الإعداد بعد إعادة تحميل الصفحة، أتريد إعادة تحميلها الآن؟"
@ -717,6 +735,7 @@ editCode: "حرر الشفرة"
apply: "تطبيق"
receiveAnnouncementFromInstance: "استلم إشعارات من هذا المثيل"
emailNotification: "إشعارات البريد الكتروني"
publish: "علني"
inChannelSearch: "ابحث عن قناة"
useReactionPickerForContextMenu: "افتح منتقي التفاعلات عند النقر بالزر الأيمن"
typingUsers: "{users} يكتب(ون)..."
@ -729,7 +748,7 @@ unlikeConfirm: "أتريد إلغاء إعجابك؟"
fullView: "ملء الشاشة"
quitFullView: "اخرج من وضع ملء للشاشة"
addDescription: "أضف وصفًا"
userPagePinTip: "لعرض ملاحظة هنا اختر \"دبسها على الصفحة الشخصية\" من قائمة تلك الملاحظة."
userPagePinTip: "لعرض ملاحظة هنا اختر \"ثبتها على الصفحة الشخصية\" من قائمة تلك الملاحظة."
notSpecifiedMentionWarning: "في الملاحظة ذكر لمستخدمين لن يستلموها."
info: "عن"
userInfo: "معلومات المستخدم"
@ -756,6 +775,7 @@ noMaintainerInformationWarning: "لم تُضبط معلومات المدير"
noBotProtectionWarning: "لم تضبط الحماية من الحسابات الآلية"
configure: "اضبط"
postToGallery: "انشر في المعرض"
postToHashtag: "انشر بهذا الوسم"
gallery: "المعرض"
recentPosts: "المشاركات الحديثة"
popularPosts: "المشاركات المتداولة"
@ -788,6 +808,7 @@ translate: "ترجم"
translatedFrom: "تُرجم من {x}"
accountDeletionInProgress: "حذف الحساب جارٍ"
usernameInfo: "الاسم الذي يميزك عن بافي مستخدمي هذا الخادم، يمكنك استخدام الحروف اللاتينية (a~z, A~Z) والأرقام (0~9) والشرطة السفلية (_). لا يمكنك تغييره بعد تسجيله."
devMode: "وضع المُطوّر"
keepCw: "أبقِ على تحذيرات المحتوى"
lastCommunication: "آخر تواصل"
resolved: "عولج"
@ -796,6 +817,7 @@ breakFollow: "إلغاء الاشتراك"
breakFollowConfirm: "أمتأكد من إزالة المتابِع ؟"
itsOn: "مفعّل"
itsOff: "معطّل"
on: "مفعل"
emailRequiredForSignup: "عنوان البريد الإلكتروني إلزامي للتسجيل"
unread: "غير مقروءة"
filter: "رشّح"
@ -834,6 +856,9 @@ oneDay: "يوم"
oneWeek: "أسبوع"
oneMonth: "شهر"
failedToFetchAccountInformation: "تعذر جلب معلومات الحساب"
cropImage: "اقتصاص الصورة"
cropImageAsk: "أتريد اقتصاص هذه الصورة"
cropYes: "اقتص"
cropNo: "استخدمها كما هي"
file: "الملفات"
recentNHours: "آخر {n} ساعة"
@ -844,16 +869,19 @@ recommended: "مقترح"
driveCapOverrideLabel: "غيّر حجم قرص التخزين لهذا المستخدم"
driveCapOverrideCaption: "أعد الحجم إلى القيمة الافتراضية بإدخال 0 أو أقل."
requireAdminForView: "لاستعراض هذه الصفحة وجب عليك الولوج كمدير."
isSystemAccount: "حساب أنشأه النظام ويُدار من قِبله."
typeToConfirm: "أدخل {x} للتأكيد"
deleteAccount: "احذف الحساب"
document: "التوثيق"
numberOfPageCache: "عدد الصفحات المخزنة مؤقتًا"
numberOfPageCacheDescription: "رفع الرقم سيسحن تجربة المستخدم لكن سيرفع استهلاك الذاكرة."
logoutConfirm: "أتريد الخروج؟"
lastActiveDate: "آخر استخدام"
statusbar: "شريط الحالة"
pleaseSelect: "حدد خيارًا"
reverse: "اقلب"
colored: "ملوّن"
refreshInterval: "مهلة التحديث"
label: "التسمية"
type: "نوع"
speed: "سرعة"
@ -866,6 +894,9 @@ cannotUploadBecauseInappropriate: "تعذر رفع الملف لوجود محت
cannotUploadBecauseNoFreeSpace: "تعذر رفع الملف لنقص مساحة التخزين."
cannotUploadBecauseExceedsFileSizeLimit: "تعذر رفع الملف بسبب تجاوز حجمه للحد المسموح"
beta: "بيتا"
enableAutoSensitive: "تعيين تلقائي كمحتوى حساس NSFW"
enableAutoSensitiveDescription: "عند الاستطاعة يسمح باكتشاف المحتوى حساس NSFW تلقائيًا في الوسائط باستخدام تعلم الآلة ووسمها تبعًا لذلك. قد يكون هذا الخيار مفعلا من جهة الخادم وسيعمل حتى وان عُطل."
activeEmailValidationDescription: "يتحقق من صحة عنوان البريد الإلكتروني بشكل أكثر حزمًا وذلك عبر تحديد ما إذا كان عنوان بريد إلكتروني مؤقت وإمكانية التواصل معه. إذا لم يحدد هذا الخيار فسيتحقق من نسق عنوان البريد الإلكتروني."
navbar: "شريط التنقل"
shuffle: "خلط"
account: "الحسابات"
@ -877,22 +908,32 @@ pushNotificationAlreadySubscribed: "إرسال الإشعارات مفعل سل
pushNotificationNotSupported: "متصفحك لا يدعم إرسال الإشعارات أو المثيل لا يدعمها."
sendPushNotificationReadMessage: "احذف الإشعارات فور قراءتها"
sendPushNotificationReadMessageCaption: "هذا قد يزيد من معدل استهلاك الطاقة لجهازك."
windowRestore: "استرجاع"
caption: "التعليق التوضيحي"
loggedInAsBot: "والج كآلي"
tools: "أدوات"
cannotLoad: "تعذر التحميل"
numberOfProfileView: "مشاهدات الملف الشخصي"
like: "أعجبني"
unlike: "ألغِ الإعجاب"
numberOfLikes: "الإعجابات"
show: "المظهر"
neverShow: "لا تظهره مجددًا"
remindMeLater: "ربما لاحقا"
didYouLikeMisskey: "هل أعجبك ميسكي؟"
pleaseDonate: "يستخدم {host} البرمجية الحرة ميسكي. نتمنى أن تتبرعوا للمشروع مما سيسمح لنا متابعة تطويره!"
roles: "الأدوار"
role: "الدور"
noRole: "لم يُعثر على دور"
normalUser: "مستخدم عادي"
undefined: "غير معرّف"
assign: "أسند"
unassign: "ألغ الإسناد"
color: "اللون"
manageCustomEmojis: "إدارة الإيموجي المخصصة"
youCannotCreateAnymore: "وصلت لسقف الإنشاء."
cannotPerformTemporary: "غير متاح مؤقتاً"
invalidParamError: "معاملات غير صالحة"
permissionDeniedError: "رُفضة العملية"
preset: "إعدادات مسبقة"
selectFromPresets: "اختر من الإعدادات المسبقة"
@ -914,6 +955,8 @@ cannotBeChangedLater: "لا يمكن تغييره لاحقًا."
reactionAcceptance: "قبول التفاعلات"
rolesAssignedToMe: "الأدوار المسندة إلي"
resetPasswordConfirm: "هل تريد إعادة تعيين كلمة السر؟"
license: "الرخصة"
unfavoriteConfirm: "أتريد إزالتها من المفضلة؟"
noteIdOrUrl: "معرف الملاحظة أو رابطها"
video: "فيديو"
videos: "فيديوهات"
@ -922,6 +965,11 @@ accountMoved: "نقل هذا المستخدم حسابه:"
accountMovedShort: "رُحل هذا الحساب."
operationForbidden: "عملية ممنوعة"
forceShowAds: "أظهر الإعلانات التجارية دائما"
leftTop: "أعلى اليسار"
rightTop: "أعلى اليمين"
leftBottom: "أسفل اليسار"
rightBottom: "أسفل اليمين"
stackAxis: "اتجاه التكديس"
vertical: "عمودي"
horizontal: "جانبي"
position: "الموضع"
@ -931,9 +979,105 @@ pleaseAgreeAllToContinue: "للمتابعة وافق على الحقول أعل
continue: "متابعة"
preservedUsernames: "أسماء المستخدمين المحجوزة"
preservedUsernamesDescription: "قائمة بأسماء المستخدمين المحجوزة كلٌ في سطر. لن يُقبل التسجيل بهذه الأسماء وستبقى محصورة على التسجيل اليدوي بواسطة المديرين. لن يتأثر المستخدمون الذين يملكون هذه الأسماء سلفًا."
createNoteFromTheFile: "أنشئ ملاحظة من هذا الملف"
archive: "الأرشيف"
channelArchiveConfirmTitle: "أتريد أرشفت {name}؟"
channelArchiveConfirmDescription: "لن يمكنك نشر ملاحظات في القناة المأرشفة ولن تظهر في قائمة القنوات ولا في نتائج البحث."
thisChannelArchived: "أُرشفت هذه القناة."
displayOfNote: "عرض الملاحظة"
initialAccountSetting: "إعداد الملف الشخصي"
youFollowing: "متابَع"
options: "خيارات"
specifyUser: "مستخدم محدد"
failedToPreviewUrl: "تتعذر المعاينة"
update: "حدِّث"
rolesThatCanBeUsedThisEmojiAsReaction: "الأدوار التي يُسمح لأصحابها استخدام هذا اإيموجي في اللتفاعل"
rolesThatCanBeUsedThisEmojiAsReactionEmptyDescription: "إذا لم تحدد دورًا يمكن للجميع استخدام هذا الإيموجي في التفاعل."
rolesThatCanBeUsedThisEmojiAsReactionPublicRoleWarn: "يجب أن تكون الأدوار علنية."
cancelReactionConfirm: "أتريد حذف تفاعلك؟"
changeReactionConfirm: "أتريد تعديل تفاعلك؟"
later: "لاحقاً"
goToMisskey: "لميسكي"
additionalEmojiDictionary: "قواميس إيموجي إضافية"
installed: "مُثبت"
_initialAccountSetting:
accountCreated: "نجح إنشاء حسابك!"
letsStartAccountSetup: "إذا كنت جديدًا لنعدّ حسابك الشخصي."
letsFillYourProfile: "أولًا لنعد ملفك الشخصي."
profileSetting: "إعدادات الملف الشخصي"
privacySetting: "إعدادات الخصوصية"
theseSettingsCanEditLater: "يمكنك تغيير هذه الإعدادات لاحقًا."
skipAreYouSure: "أتريد تخطي إعداد الملف الشخصي؟"
laterAreYouSure: "أتريد إعداد الملف الشخصي لاحقًا؟"
_serverRules:
description: "مجموعة من القواعد لعرضها عند التسجيل، من المستحسن كتابة ملخصٍ للشروط الخدمة."
_accountMigration:
moveFrom: "انقل حسابًا آخر لهذا الحساب"
moveFromLabel: "الحساب الأصلي #{n}"
moveTo: "انقل هذا الحساب لحساب آخر"
moveToLabel: "الحساب الوجهة:"
moveCannotBeUndone: "لا يمكن التراجع عن نقل الحساب."
movedTo: "الحساب الوجهة:"
_achievements:
_types:
_notes1:
description: "انشر ملاحظتك الأولى"
flavor: "تمتع باستخدام ميسكي!"
_notes10:
title: "بعض الملاحظات"
description: "انشر 10 ملاحظات"
_notes100:
title: "كثير من الملاحظات"
description: "انشر 100 ملاحظة"
_notes500:
description: "انشر 500 ملاحظة"
_notes1000:
title: "جبل ملاحظات"
description: "انشر 1000 ملاحظة"
_notes5000:
description: "انشر 5000 ملاحظة"
_notes10000:
description: "انشر 10000 ملاحظة"
_notes20000:
title: "أريد...ملاحظات...أكثر"
description: "انشر 20000 ملاحظة"
_notes30000:
title: "ملاحظات وملاحظات وملاحظات"
description: "انشر 30000 ملاحظة"
_notes40000:
title: "مصنع ملاحظات"
description: "انشر 40000 ملاحظة"
_notes50000:
title: "كوكب ملاحظات"
description: "انشر 50000 ملاحظة"
_notes60000:
title: "نجم ملاحظات"
description: "انشر 60000 ملاحظة"
_notes70000:
title: "ثقب أسود للملاحظات"
description: "انشر 70000 ملاحظة"
_notes80000:
title: "مجرة ملاحظات"
description: "انشر 80000 ملاحظة"
_notes90000:
title: "كوْن ملاحظات"
description: "انشر 90000 ملاحظة"
_notes100000:
title: "كل ملاحظاتك لنا"
description: "انشر 100000 ملاحظة"
flavor: "حقًا لديك الكثير من القصص"
_login3:
title: "مبتدأ I"
_noteFavorited1:
description: "فضًِل ملاحظتك الأولى"
_myNoteFavorited1:
title: "ساعٍ للنجوم"
description: "أعجب شخص آخر بإحدى ملاحظاتك"
_profileFilled:
title: "مستعد"
description: "أعدّ حسابك"
_markedAsCat:
title: "أنا قط"
_role:
new: "دور جديد"
edit: "حرر الأدوار"
@ -950,6 +1094,7 @@ _role:
high: "عالية"
_options:
canManageCustomEmojis: "إدارة الإيموجي المخصصة"
pinMax: "حد عدد الملاحظات المثبتة"
_condition:
isLocal: "مستخدم محلي"
isRemote: "مستخدم بعيد"
@ -1010,10 +1155,6 @@ _aboutMisskey:
donate: "تبرع لميسكي"
morePatrons: "نحن نقدر الدعم الذي قدمه العديد من الأشخاص الذين لم نذكرهم. شكرًا لكم 🥰"
patrons: "الداعمون"
_nsfw:
respect: "اخف الوسائط ذات المحتوى الحساس"
ignore: "اعرض الوسائط ذات المحتوى الحساس"
force: "اخف كل الوسائط"
_instanceTicker:
none: "لا تظهره بتاتًا"
remote: "أظهر للمستخدمين البِعاد"
@ -1353,7 +1494,7 @@ _pages:
url: "رابط الصفحة"
summary: "ملخص الصفحة"
alignCenter: "توسيط العناصر"
hideTitleWhenPinned: "اخف عنوان الصفحة عند تدبيسها في ملف الشخصي"
hideTitleWhenPinned: "اخف عنوان الصفحة عند تثبيتها في ملف الشخصي"
font: "الخط"
fontSerif: "Serif"
fontSansSerif: "Sans Serif"

View file

@ -294,7 +294,6 @@ copyUrl: "URL কপি করুন"
rename: "পুনঃনামকরণ"
avatar: "প্রোফাইল ছবি"
banner: "ব্যানার"
nsfw: "সংবেদনশীল বিষয়বস্তু"
whenServerDisconnected: "সার্ভারের সাথে সংযোগ বিচ্ছিন্ন হয়ে গেলে"
disconnectedFromServer: "সার্ভার থেকে সংযোগ বিচ্ছিন্ন হয়েছে"
reload: "আবার লোড করুন"
@ -916,10 +915,6 @@ _aboutMisskey:
donate: "Misskey তে দান করুন"
morePatrons: "আরও অনেকে আমাদের সাহায্য করছেন। তাদের সবাইকে ধন্যবাদ 🥰"
patrons: "সমর্থনকারী"
_nsfw:
respect: "স্পর্শকাতর মিডিয়া লুকান"
ignore: "স্পর্শকাতর মিডিয়া লুকাবেন না"
force: "সকল মিডিয়া লুকান"
_mfm:
cheatSheet: "MFM চিটশিট"
intro: "MFM একটি মার্কআপ ভাষা যা CherryPick-এর মধ্যে বিভিন্ন জায়গায় ব্যবহার করা যেতে পারে। এখানে আপনি MFM-এর সিনট্যাক্সগুলির একটি তালিকা দেখতে পারবেন।"

View file

@ -263,7 +263,6 @@ emptyFolder: "La carpeta està buida"
unableToDelete: "No es pot eliminar"
copyUrl: "Copia l'URL"
rename: "Canvia el nom"
nsfw: "NSFW"
reload: "Actualitza"
doNothing: "Ignora"
accept: "Accepta"

View file

@ -2,6 +2,7 @@
_lang_: "Čeština"
headlineMisskey: "Síť propojená poznámkami"
introMisskey: "Vítejte! CherryPick 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>CherryPick<b> (nazývaná \"CherryPick instance\")."
monthAndDay: "{day}. {month}."
search: "Vyhledávání"
notifications: "Oznámení"
@ -48,8 +49,15 @@ delete: "Smazat"
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."
addToList: "Přidat do seznamu"
addToAntenna: "Přidat do antény"
sendMessage: "Odeslat zprávu"
copyRSS: "Kopírovat RSS"
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"
reply: "Odpovědět"
loadMore: "Zobrazit více"
@ -60,6 +68,7 @@ receiveFollowRequest: "Žádost o sledování přijata"
followRequestAccepted: "Žádost o sledování přijata"
mention: "Zmínění"
mentions: "Zmínění"
directNotes: "Přímé poznámky"
importAndExport: "Import a export"
import: "Importovat"
export: "Exportovat"
@ -82,6 +91,7 @@ error: "Chyba"
somethingHappened: "Jejda. Něco se nepovedlo."
retry: "Opakovat"
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."
youShouldUpgradeClient: "Pro zobrazení této stránky obnovte stránku pro aktualizaci klienta."
enterListName: "Jméno seznamu"
@ -100,6 +110,8 @@ renoted: "Přeposláno"
cantRenote: "Tento příspěvek nelze přeposlat."
cantReRenote: "Odpověď nemůže být odstraněna."
quote: "Citovat"
inChannelRenote: "Přeposlání v kanálu"
inChannelQuote: "Citace v kanálu"
pinnedNote: "Připnutá poznámka"
pinned: "Připnout"
you: "Vy"
@ -108,6 +120,7 @@ sensitive: "NSFW"
add: "Přidat"
reaction: "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í"
rememberNoteVisibility: "Zapamatovat nastavení zobrazení poznámky"
attachCancel: "Odstranit přílohu"
@ -116,6 +129,8 @@ unmarkAsSensitive: "Odznačit jako NSFW"
enterFileName: "Zadejte název souboru"
mute: "Ztlumit"
unmute: "Odmlčet"
renoteMute: "Ztlumit poznámky"
renoteUnmute: "Zrušit ztlumení poznámek"
block: "Zablokovat"
unblock: "Odblokovat"
suspend: "Zmrazit"
@ -125,7 +140,10 @@ unblockConfirm: "Jste si jistí že chcete odblokovat tento účet?"
suspendConfirm: "Jste si jistí že chcete suspendovat tenhle účet?"
unsuspendConfirm: "Jste si jistí že chcete obnovit tenhle účet?"
selectList: "Vybrat seznam"
editList: "Upravit seznam"
selectChannel: "Vybrat kanál"
selectAntenna: "Vyberte Anténu"
editAntenna: "Upravit anténu"
selectWidget: "Zvolte widget"
editWidgets: "Upravit widget"
editWidgetsExit: "Hotovo"
@ -138,6 +156,8 @@ addEmoji: "Přidat emoji"
settingGuide: "Doporučené nastavení"
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."
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"
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í CherryPick systém aby se choval k tomuhle účtu jako bot."
flagAsCat: "Tenhle účet je kočka"
@ -146,6 +166,7 @@ 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."
autoAcceptFollowed: "Automaticky akceptovat následování od účtů které sledujete"
addAccount: "Přidat účet"
reloadAccountsList: "Obnovit list účtů"
loginFailed: "Přihlášení se nezdařilo."
showOnRemote: "Více na původním profilu"
general: "Obecně"
@ -186,17 +207,26 @@ instanceInfo: "Informace o instanci"
statistics: "Statistiky"
clearQueue: "Vyčistit frontu"
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ěť"
clearCachedFilesConfirm: "Jste jistí že chcete smazat všechny vzdálené soubory v mezipaměti?"
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é"
editProfile: "Upravit můj profil"
noteDeleteConfirm: "Jste si jistí že chcete smazat tuhle poznámku?"
pinLimitExceeded: "Nemůžete připnout další poznámky."
intro: "Instalace CherryPick byla dokončena! Prosím vytvořte admina."
done: "Hotovo"
processing: "Zpracovávám"
preview: "Náhled"
default: "Výchozí"
defaultValueIs: "Základní hodnota: {value}"
noCustomEmojis: "Bez Emoji"
federating: "Sdružování"
blocked: "Blokováno"
suspended: "Suspendováno"
all: "Vše"
@ -217,6 +247,7 @@ more: "Více!"
featured: "Oblíbené poznámky"
usernameOrUserId: "Uživatelské jméno nebo uživatelské id"
noSuchUser: "Uživatel nebyl nalezen"
lookup: "Vyhledat"
announcements: "Oznámení"
imageUrl: "URL obrázku"
remove: "Smazat"
@ -227,10 +258,13 @@ resetAreYouSure: "Opravdu resetovat?"
saved: "Uloženo"
messaging: "Zprávy"
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"
fromUrl: "Z URL"
uploadFromUrl: "Nahrát z URL adresy"
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í."
explore: "Objevovat"
messageRead: "Přečtené"
@ -238,6 +272,10 @@ noMoreHistory: "To je vše"
startMessaging: "Zahájit chat"
nUsersRead: "přečteno {n} uživateli"
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"
home: "Domů"
remoteUserCaution: "Tyto informace nemusí být aktuální jelikož uživatel je ze vzdálené instance."
@ -268,18 +306,24 @@ createFolder: "Vytvořit složku"
renameFolder: "Přejmenovat složku"
deleteFolder: "Odstranit složku"
addFile: "Přidat soubor"
emptyDrive: "Váš disk je prázdný"
emptyFolder: "Tato složka je prázdná"
unableToDelete: "Nelze smazat"
inputNewFileName: "Zadejte nový název"
inputNewDescription: "Zadejte nový popisek"
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"
rename: "Přejmenovat"
avatar: "Avatar"
banner: "Baner"
nsfw: "NSFW"
displayOfSensitiveMedia: "Zobrazit citlivé média"
whenServerDisconnected: "Když ztratíte spojení se serverem"
disconnectedFromServer: "Spojení bylo přerušeno"
reload: "Aktualizovat"
doNothing: "Ignorovat"
reloadConfirm: "Chcete obnovit časovou osu?"
watch: "Sledovat"
unwatch: "Přestat sledovat"
accept: "Souhlasím"
@ -302,15 +346,22 @@ connectService: "Připojit"
disconnectService: "Odpojit"
enableLocalTimeline: "Povolit loká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"
enableRegistration: "Povolit registraci novým uživatelům"
invite: "Pozvat"
driveCapacityPerLocalAccount: "Kapacita disku na lokálního uživatele"
driveCapacityPerRemoteAccount: "Kapacita disku na vzdáleného uživatele"
inMb: "V megabajtech"
iconUrl: "Favicon URL"
bannerUrl: "Baner URL"
backgroundImageUrl: "Adresa URL obrázku pozadí"
basicInfo: "Základní informace"
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"
hcaptcha: "hCaptcha"
enableHcaptcha: "Aktivovat hCaptchu"
@ -320,30 +371,56 @@ recaptcha: "reCAPTCHA"
enableRecaptcha: "Zapnout ReCAPTCHu"
recaptchaSiteKey: "Klíč stránky"
recaptchaSecretKey: "Tajný Klíč (Secret Key)"
turnstile: "Turnstile"
enableTurnstile: "Povolit Turnstile"
turnstileSiteKey: "Klíč stránky"
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"
manageAntennas: "Spravovat Antény"
name: "Jméno"
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"
antennaUsersDescription: "Vypsat jednoho uživatele na řádek"
caseSensitive: "Rozlišuje malá a velká písmena"
withReplies: "Zahrnout odpovědi"
connectedTo: "Následující účty jsou připojeny"
notesAndReplies: "Poznámky a odpovědi"
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é"
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"
userList: "Seznamy"
about: "Informace"
aboutMisskey: "O CherryPick"
administrator: "Administrátor"
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"
moderation: "Moderování"
nUsersMentioned: "{n} uživatelů zmínilo"
securityKeyAndPasskey: "Bezpečnostní klíče a tokeny"
securityKey: "Bezpečnostní klíč"
lastUsed: "Naposledy použito"
lastUsedAt: "Naposledy použito: {t}"
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"
newPasswordIs: "Nové heslo je \"{password}\""
reduceUiAnimation: "Snížit UI animace"
@ -392,14 +469,25 @@ or: "Nebo"
language: "Jazyk"
uiLanguage: "Jazyk uživatelského rozhraní"
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"
signinHistory: "Historie přihlášení"
enableAdvancedMfm: "Zapnout pokročilé MFM"
enableAnimatedMfm: "Zapnout animované MFM"
doing: "Procesuju..."
category: "Kategorie"
tags: "Štítky"
docSource: "Zdroj tohoto dokumentu"
createAccount: "Vytvořit účet"
existingAccount: "Existující účet"
regenerate: "Obnovit"
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"
dashboard: "Přehled"
local: "Lokální"
@ -413,15 +501,35 @@ accountSettings: "Nastavení účtu"
promotion: "Propagace"
promote: "Propagovat"
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"
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"
objectStorageBucketDesc: "Prosím upřesněte název bucketu používaný poskytovatelem."
objectStoragePrefix: "Předpona"
objectStoragePrefixDesc: "Soubory budou ukládány pod složkama s tímhle prefixem."
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"
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"
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"
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"
none: "Žádný"
showInPage: "Zobrazit na stránce"
popout: "Pop-out"
volume: "Hlasitost"
@ -434,29 +542,61 @@ install: "Nainstalovat"
uninstall: "Odinstalovat"
installedApps: "Autorizované aplikace"
nothing: "Nic nebylo nalezeno"
installedDate: "Datum autorizace"
lastUsedDate: "Poslední použití"
state: "Stav"
sort: "Seřadit"
ascendingOrder: "Vzestupně"
descendingOrder: "Sestupně"
scratchpad: "Zápisník"
scratchpadDescription: "Scratchpad poskytuje rozhraní pro AiScript experimenty. Můžete psát, spustit či zkontrolovat výsledky jeho interakce s CherryPick."
output: "Výstup"
script: "Skript"
disablePagesScript: "Vypnout AiScript na stránkách"
updateRemoteUser: "Aktualizovat informace o vzdáleném účtu"
deleteAllFiles: "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."
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"
divider: "Dělící čára"
addItem: "Přidat položku"
rearrange: "Přeřadit"
relays: "Relay"
addRelay: "Přidat Relay"
inboxUrl: "Inbox URL"
addedRelays: "Přidané přenosy"
serviceworkerInfo: "Musí být zapnut pro push notifikace."
deletedNote: "Odstraněné 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"
describeFile: "Přidat popisek"
enterFileDescription: "Vložit popisek"
author: "Autor"
leaveConfirm: "Máte neuložené změny. Opravdu je chcete zahodit?"
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"
height: "Výška"
large: "Velké"
@ -466,10 +606,13 @@ generateAccessToken: "Vygenerovat přístupový token"
permission: "Oprávnění"
enableAll: "Povolit 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í"
edit: "Upravit"
emailServer: "Mailový server"
enableEmail: "Zapnout email dystribuci"
emailConfigInfo: "Používá se na ověření emailové adresy během registrace nebo při zapomenutí hesla."
email: "Email"
emailAddress: "Emailová adresa"
smtpConfig: "Konfigurace SMTP serveru"
@ -477,8 +620,15 @@ smtpHost: "Hostitel"
smtpPort: "Port"
smtpUser: "Uživatelské jméno"
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"
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"
display: "Zobrazit"
copy: "Kopírovat"
@ -490,21 +640,66 @@ database: "Databáze"
channel: "Kanály"
create: "Vytvořit"
notificationSetting: "Nastavení oznámení"
notificationSettingDesc: "Vyberte typy oznámení k zobrazení."
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í"
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"
behavior: "Chování"
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"
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ě"
system: "Systém"
switchUi: "Přepnout UI"
desktop: "Plocha"
clip: "Oříznout"
createNew: "Vytvořit nový"
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: "CherryPick 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"
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"
emailVerified: "Váš e-mail byl ověřen"
contact: "Kontakt"

View file

@ -49,11 +49,15 @@ delete: "Löschen"
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."
addToList: "Zu Liste hinzufügen"
addToAntenna: "Zu Antenne hinzufügen"
sendMessage: "Nachricht senden"
copyRSS: "RSS kopieren"
copyUsername: "Benutzernamen kopieren"
copyUserId: "Benutzer-ID kopieren"
copyNoteId: "Notiz-ID kopieren"
copyFileId: "Datei-ID kopieren"
copyFolderId: "Ordner-ID kopieren"
copyProfileUrl: "Profil-URL kopieren"
searchUser: "Nach einem Benutzer suchen"
reply: "Antworten"
loadMore: "Mehr laden"
@ -112,7 +116,7 @@ pinnedNote: "Angeheftete Notiz"
pinned: "Angeheftet"
you: "Du"
clickToShow: "Zum Anzeigen anklicken"
sensitive: "NSFW"
sensitive: "Sensibel"
add: "Hinzufügen"
reaction: "Reaktionen"
reactions: "Reaktionen"
@ -120,8 +124,8 @@ reactionSetting: "In der Reaktionsauswahl anzuzeigende Reaktionen"
reactionSettingDescription2: "Ziehe um Anzuordnen, klicke um zu löschen, drücke „+“ um hinzuzufügen"
rememberNoteVisibility: "Notizsichtbarkeit merken"
attachCancel: "Anhang entfernen"
markAsSensitive: "Als NSFW markieren"
unmarkAsSensitive: "Als nicht NSFW markieren"
markAsSensitive: "Als sensibel markieren"
unmarkAsSensitive: "Als nicht sensibel markieren"
enterFileName: "Dateinamen eingeben"
mute: "Stummschalten"
unmute: "Stummschaltung aufheben"
@ -136,8 +140,10 @@ unblockConfirm: "Möchtest du diese Blockierung wirklich aufheben?"
suspendConfirm: "Möchtest du diesen Benutzer wirklich sperren?"
unsuspendConfirm: "Möchtest du diesen Benutzer wirklich entsperren?"
selectList: "Liste auswählen"
editList: "Liste bearbeiten"
selectChannel: "Kanal auswählen"
selectAntenna: "Antenne auswählen"
editAntenna: "Antenne bearbeiten"
selectWidget: "Widget auswählen"
editWidgets: "Widgets bearbeiten"
editWidgetsExit: "Fertig"
@ -150,6 +156,8 @@ addEmoji: "Emoji hinzufügen"
settingGuide: "Empfohlene Einstellung"
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."
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"
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 CherryPicks interne Systeme dieses Benutzerkonto als Bot behandeln."
flagAsCat: "Als Katze markieren"
@ -311,7 +319,7 @@ copyUrl: "URL kopieren"
rename: "Umbenennen"
avatar: "Profilbild"
banner: "Banner"
nsfw: "NSFW"
displayOfSensitiveMedia: "Anzeige von sensiblen Medien"
whenServerDisconnected: "Bei Verbindungsverlust zum Server"
disconnectedFromServer: "Die Verbindung zum Server wurde getrennt"
reload: "Aktualisieren"
@ -705,7 +713,7 @@ driveUsage: "Drive-Auslastung"
noCrawle: "Crawler-Indexierung ablehnen"
noCrawleDescription: "Suchmaschinen bitten, die eigene Profilseite, Notizen, Seiten usw. nicht zu indexieren."
lockedAccountInfo: "Auch wenn du Follow-Anfragen auf manuelle Bestätigung setzt, wird jede deiner Notizen öffentlich sichtbar sein, sofern du ihre Notizsichtbarkeit nicht auf \"Nur Follower\" setzt."
alwaysMarkSensitive: "Medien standardmäßig als NSFW markieren"
alwaysMarkSensitive: "Medien standardmäßig als sensibel markieren"
loadRawImages: "Anstatt Vorschaubilder immer Originalbilder anzeigen"
disableShowingAnimatedImages: "Animierte Bilder nicht abspielen"
verificationEmailSent: "Eine Bestätigungsmail wurde an deine Email-Adresse versendet. Besuche den dort enthaltenen Link, um die Verifizierung abzuschließen."
@ -926,16 +934,16 @@ type: "Art"
speed: "Geschwindigkeit"
slow: "Langsam"
fast: "Schnell"
sensitiveMediaDetection: "Erkennung von NSFW-Medien"
sensitiveMediaDetection: "Erkennung von sensiblen Medien"
localOnly: "Nur Lokal"
remoteOnly: "Nur für fremde Instanzen"
failedToUpload: "Hochladen fehlgeschlagen"
cannotUploadBecauseInappropriate: "Diese Datei kann nicht hochgeladen werden, da Anteile der Datei als möglicherweise NSFW festgestellt wurden."
cannotUploadBecauseInappropriate: "Diese Datei kann nicht hochgeladen werden, da Anteile der Datei als möglicherweise unangebracht festgestellt wurden."
cannotUploadBecauseNoFreeSpace: "Die Datei konnte nicht hochgeladen werden, da dein Drive-Speicherplatz aufgebraucht ist."
cannotUploadBecauseExceedsFileSizeLimit: "Diese Datei kann wegen Überschreitung der Maximalgröße nicht hochgeladen werden."
beta: "Beta"
enableAutoSensitive: "NSFW-Automarkierung"
enableAutoSensitiveDescription: "Setzt soweit möglich durch Verwendung von Machine Learning automatisch NSFW-Markierungen für Medien, die NSFW-Anteile beinhalten. Auch wenn du diese Option deaktiviert hast, ist sie möglicherweise auf Instanzebene aktiviert."
enableAutoSensitive: "Automarkierung sensibler Medien"
enableAutoSensitiveDescription: "Setzt soweit möglich durch Verwendung von Machine Learning automatisch Markierungen für sensible Medien. Auch wenn du diese Option deaktiviert hast, ist sie möglicherweise auf Instanzebene aktiviert."
activeEmailValidationDescription: "Aktivert strengere Überprüfung von E-Mail-Adressen, d.h. Testen auf Wegwerfadressen und darauf, ob mit der Adresse tatsächlich kommuniziert werden kann. Ist dies deaktiviert, so wird nur das Format der E-Mail überprüft."
navbar: "Navigationsleiste"
shuffle: "Mischen"
@ -1077,6 +1085,29 @@ goToMisskey: "Zu CherryPick"
additionalEmojiDictionary: "Zusätzliche Emoji-Wörterbücher"
installed: "Installiert"
branding: "Branding"
enableServerMachineStats: "Hardwareinformationen des Servers veröffentlichen"
enableIdenticonGeneration: "Generierung von Benutzer-Identicons aktivieren"
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:
accountCreated: "Dein Konto wurde erfolgreich erstellt!"
letsStartAccountSetup: "Lass uns nun dein Konto einrichten."
@ -1387,6 +1418,9 @@ _role:
ltlAvailable: "Kann auf die lokale Chronik zugreifen"
canPublicNote: "Kann öffentliche Notizen erstellen"
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"
driveCapacity: "Drive-Kapazität"
alwaysMarkNsfw: "Dateien immer als NSFW markieren"
@ -1417,10 +1451,10 @@ _role:
or: "ODER-Bedingung"
not: "NICHT-Bedingung"
_sensitiveMediaDetection:
description: "Ermöglicht eine Erleichterung der Servermoderation durch die automatische Erkennungen von NSFW-Medien unter Verwendung von Machine Learning. Hierdurch wird die Serverlast etwas erhöht."
description: "Ermöglicht eine Erleichterung der Servermoderation durch die automatische Erkennungen von sensiblen Medien unter Verwendung von Machine Learning. Hierdurch wird die Serverlast etwas erhöht."
sensitivity: "Erkennungssensitivität"
sensitivityDescription: "Durch das Senken der Sensitivität kann die Anzahl an Fehlerkennungen (sog. false positives) reduziert werden. Durch ein Erhöhen dieser kann die Anzahl an verpassten Erkennungen (sog. false negatives) reduziert werden."
setSensitiveFlagAutomatically: "Als NSFW markieren"
setSensitiveFlagAutomatically: "Als sensibel markieren"
setSensitiveFlagAutomaticallyDescription: "Die Resultate der internen Erkennung werden beibehalten, auch wenn diese Option deaktiviert ist."
analyzeVideos: "Videoanalyse aktivieren"
analyzeVideosDescription: "Analysiert zusätzlich zu Bildern auch Videos. Die Last des Servers wird hierdurch etwas erhöht."
@ -1449,6 +1483,7 @@ _ad:
back: "Zurück"
reduceFrequencyOfThisAd: "Diese Werbung weniger anzeigen"
hide: "Ausblenden"
timezoneinfo: "Der Wochentag wird durch die Serverzeitzone bestimmt."
_forgotPassword:
enterEmail: "Gib die Email-Adresse ein, mit der du dich registriert hast. An diese wird ein Link gesendet, mit dem du dein Passwort zurücksetzen kannst."
ifNoEmail: "Solltest du bei der Registrierung keine Email-Adresse angegeben haben, wende dich bitte an den Administrator."
@ -1500,9 +1535,9 @@ _aboutMisskey:
donate: "An Misskey spenden"
morePatrons: "Wir schätzen ebenso die Unterstützung vieler anderer hier nicht gelisteter Personen sehr. Danke! 🥰"
patrons: "UnterstützerInnen"
_nsfw:
respect: "Als NSFW markierte Bilder verbergen"
ignore: "Als NSFW markierte Bilder nicht verbergen"
_displayOfSensitiveMedia:
respect: "Sensible Medien verbergen"
ignore: "Sensible Medien anzeigen"
force: "Alle Medien verbergen"
_mfm:
cheatSheet: "MFM Spickzettel"
@ -2050,6 +2085,7 @@ _deck:
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."
widgetsIntroduction: "Drücke bitte \"Widgets bearbeiten\" im Spaltenmenü und füge ein Widget hinzu."
useSimpleUiForNonRootPages: "Simple Benutzeroberfläche für navigierte Seiten verwenden"
_columns:
main: "Hauptspalte"
widgets: "Widgets"

View file

@ -1,5 +1,16 @@
---
_lang_: "English"
addSingle: "Add just one"
addMultiple: "Add multiple"
showRenoteConfirmPopup: "Show confirmation popup when renote"
showSubNoteFooterButton: "Show action buttons in subnotes"
showSubNoteFooterButtonDescription: "Enabling this setting will show an action button on the parent note of the replied-to note."
alreadyFollowed: "You've been followed!"
enableMarkByDate: "Show note times as dates"
renoteConfirm: "Do you want to renote?"
inviteRevoke: "Revoke All Invitation Codes"
inviteRevokeConfirm: "Are you sure that you want to revoke all invitation codes?"
enableAbsoluteTime: "Enable Absolute Time"
posted: "Note are now published."
translateNote: "Translate Note"
showTranslateButtonInNote: "Display translate button in note body"
@ -9,7 +20,8 @@ displayBanner: "Display Banner Image"
requireRefresh: "When the page needs to refresh"
performanceWarning: "High resource usage can result in higher device temperatures and faster battery consumption"
photosensitiveSeizuresWarning: "Can cause photosensitive seizures"
friendlyEnableNotification: "Enable/Disable the notification area"
friendlyEnableNotifications: "Enable/Disable the notifications area"
friendlyEnableWidgets: "Enable/Disable the widgets area"
useBoldFont: "Bold Text"
newNoteReceivedNotification: "When receive a new note notification"
disableRightClick: "Prohibit right click"
@ -73,11 +85,15 @@ deleteAndEditConfirm: "Are you sure you want to delete this note and edit it? Yo
copyAndEdit: "Copy and edit"
copyAndEditConfirm: "Are you sure you want to copy this note and edit it? The media included in the notes are also copied."
addToList: "Add to list"
addToAntenna: "Add to antenna"
sendMessage: "Send a message"
copyRSS: "Copy RSS"
copyUsername: "Copy username"
copyUserId: "Copy user ID"
copyNoteId: "Copy note ID"
copyFileId: "Copy file ID"
copyFolderId: "Copy folder ID"
copyProfileUrl: "Copy profile URL"
searchUser: "Search for a user"
reply: "Reply"
loadMore: "Load more"
@ -136,7 +152,7 @@ pinnedNote: "Pinned note"
pinned: "Pin to profile"
you: "You"
clickToShow: "Click to show"
sensitive: "NSFW"
sensitive: "Sensitive"
add: "Add"
reaction: "Reactions"
reactions: "Reactions"
@ -144,8 +160,8 @@ reactionSetting: "Reactions to show in the reaction picker"
reactionSettingDescription2: "Drag to reorder, click to delete, press \"+\" to add."
rememberNoteVisibility: "Remember note visibility settings"
attachCancel: "Remove attachment"
markAsSensitive: "Mark as NSFW"
unmarkAsSensitive: "Unmark as NSFW"
markAsSensitive: "Mark as sensitive"
unmarkAsSensitive: "Unmark as sensitive"
enterFileName: "Enter filename"
mute: "Mute"
unmute: "Unmute"
@ -160,8 +176,10 @@ unblockConfirm: "Are you sure that you want to unblock this account?"
suspendConfirm: "Are you sure that you want to suspend this account?"
unsuspendConfirm: "Are you sure that you want to unsuspend this account?"
selectList: "Select a list"
editList: "Edit list"
selectChannel: "Select a channel"
selectAntenna: "Select an antenna"
editAntenna: "Edit antenna"
selectWidget: "Select a widget"
editWidgets: "Edit widgets"
editWidgetsExit: "Done"
@ -174,6 +192,8 @@ addEmoji: "Add an emoji"
settingGuide: "Recommended settings"
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."
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"
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 CherryPick's internal systems to treat this account as a bot."
flagAsCat: "Mark this account as a cat"
@ -335,7 +355,7 @@ copyUrl: "Copy URL"
rename: "Rename"
avatar: "Avatar"
banner: "Banner"
nsfw: "NSFW"
displayOfSensitiveMedia: "Display of sensitive media"
whenServerDisconnected: "When losing connection to the server"
disconnectedFromServer: "Connection to server has been lost"
reload: "Refresh"
@ -731,7 +751,7 @@ driveUsage: "Drive space usage"
noCrawle: "Reject crawler indexing"
noCrawleDescription: "Ask search engines to not index your profile page, notes, Pages, etc."
lockedAccountInfo: "Unless you set your note visiblity to \"Followers only\", your notes will be visible to anyone, even if you require followers to be manually approved."
alwaysMarkSensitive: "Mark as NSFW by default"
alwaysMarkSensitive: "Mark as sensitive by default"
loadRawImages: "Load original images instead of showing thumbnails"
disableShowingAnimatedImages: "Don't play animated images"
disableShowingAnimatedImagesDescription: "When disabled, the animated images will play. Be careful as it may cause photosensitive seizures."
@ -955,16 +975,16 @@ type: "Type"
speed: "Speed"
slow: "Slow"
fast: "Fast"
sensitiveMediaDetection: "Detection of NSFW media"
sensitiveMediaDetection: "Detection of sensitive media"
localOnly: "Local only"
remoteOnly: "Remote only"
failedToUpload: "Upload failed"
cannotUploadBecauseInappropriate: "This file could not be uploaded because parts of it have been detected as potentially NSFW."
cannotUploadBecauseInappropriate: "This file could not be uploaded because parts of it have been detected as potentially inappropriate."
cannotUploadBecauseNoFreeSpace: "Upload failed due to lack of Drive capacity."
cannotUploadBecauseExceedsFileSizeLimit: "This file cannot be uploaded as it exceeds the file size limit."
beta: "Beta"
enableAutoSensitive: "Automatic NSFW-Marking"
enableAutoSensitiveDescription: "Allows automatic detection and marking of NSFW media through Machine Learning where possible. Even if this option is disabled, it may be enabled instance-wide."
enableAutoSensitive: "Automatic marking as sensitive"
enableAutoSensitiveDescription: "Allows automatic detection and marking of sensitive media through Machine Learning where possible. Even if this option is disabled, it may be enabled instance-wide."
activeEmailValidationDescription: "Enables stricter validation of email addresses, which includes checking for disposable addresses and by whether it can actually be communicated with. When unchecked, only the format of the email is validated."
navbar: "Navigation bar"
shuffle: "Shuffle"
@ -1081,7 +1101,7 @@ vertical: "Vertical"
horizontal: "Horizontal"
position: "Position"
serverRules: "Server rules"
pleaseConfirmBelowBeforeSignup: "Please confirm the below before signing up."
pleaseConfirmBelowBeforeSignup: "To register on this server, you must review and agree to the following:"
pleaseAgreeAllToContinue: "You must agree to all above fields to continue."
continue: "Continue"
preservedUsernames: "Reserved usernames"
@ -1110,13 +1130,33 @@ goToMisskey: "To CherryPick"
additionalEmojiDictionary: "Additional emoji dictionaries"
installed: "Installed"
branding: "Branding"
enableServerMachineStats: "Publish server hardware stats"
enableIdenticonGeneration: "Enable user identicon generation"
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."
additionalPermissionsForFlash: "Allow to add permission to Play"
thisFlashRequiresTheFollowingPermissions: "This Play requires the following permissions"
doYouWantToAllowThisPlayToAccessYourAccount: "Do you want to allow this Play to access your account?"
translateProfile: "Translate profile"
enableAbsoluteTime: "Enable Absolute Time"
inviteRevoke: "Revoke All Invitation Codes"
inviteRevokeConfirm: "Are you sure that you want to revoke all invitation codes?"
_group:
leader: "Group owner"
banish: "Banish"
@ -1133,6 +1173,7 @@ _cherrypick:
rememberPostFormToggleState: "Remember to turn preview on/off in the note post form"
reactableRemoteReaction: "Allow remote custom emoji reactions to react if there is an emoji with the same name on this server."
showFollowingMessageInsteadOfButton: "Do not show the follow button in the notification field if you are already following someone"
mobileTimelineHeaderChange: "Timeline header design change in mobile environment"
_bannerDisplay:
all: "All"
topBottom: "Top and Bottom"
@ -1482,8 +1523,13 @@ _role:
_options:
gtlAvailable: "Can view the global timeline"
ltlAvailable: "Can view the local timeline"
mtlAvailable: "Can view the media timeline"
ctlAvailable: "Can view the cat timeline"
canPublicNote: "Can send public notes"
canInvite: "Can create instance invite codes"
inviteLimit: "Invite limit"
inviteLimitCycle: "Invite limit cooldown"
inviteExpirationTime: "Invite expiration interval"
canManageCustomEmojis: "Can manage custom emojis"
driveCapacity: "Drive capacity"
alwaysMarkNsfw: "Always mark files as NSFW"
@ -1518,10 +1564,10 @@ _newNoteReceivedNotificationBehavior:
count: "Show number of notes"
none: "None"
_sensitiveMediaDetection:
description: "Reduces the effort of server moderation through automatically recognizing NSFW media via Machine Learning. This will slightly increase the load on the server."
description: "Reduces the effort of server moderation through automatically recognizing sensitive media via Machine Learning. This will slightly increase the load on the server."
sensitivity: "Detection sensitivity"
sensitivityDescription: "Reducing the sensitivity will lead to fewer misdetections (false positives) whereas increasing it will lead to fewer missed detections (false negatives)."
setSensitiveFlagAutomatically: "Mark as NSFW"
setSensitiveFlagAutomatically: "Mark as sensitive"
setSensitiveFlagAutomaticallyDescription: "The results of the internal detection will be retained even if this option is turned off."
analyzeVideos: "Enable analysis of videos"
analyzeVideosDescription: "Analyzes videos in addition to images. This will slightly increase the load on the server."
@ -1550,6 +1596,7 @@ _ad:
back: "Back"
reduceFrequencyOfThisAd: "Show this ad less"
hide: "Hide"
timezoneinfo: "The day of the week is determined from the server's timezone."
_forgotPassword:
enterEmail: "Enter the email address you used to register. A link with which you can reset your password will then be sent to it."
ifNoEmail: "If you did not use an email during registration, please contact the instance administrator instead."
@ -1610,9 +1657,9 @@ _aboutMisskey:
donate: "Donate to CherryPick"
relayServer: "Relay Server"
community: "Community"
_nsfw:
respect: "Hide NSFW media"
ignore: "Don't hide NSFW media"
_displayOfSensitiveMedia:
respect: "Hide media marked as sensitive"
ignore: "Display media marked as sensitive"
force: "Hide all media"
_mfm:
cheatSheet: "MFM Cheatsheet"
@ -2051,6 +2098,7 @@ _timelines:
local: "Local"
media: "Media"
social: "Social"
cat: "Cat"
global: "Global"
_play:
new: "Create Play"
@ -2171,6 +2219,7 @@ _deck:
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."
widgetsIntroduction: "Please select \"Edit widgets\" in the column menu and add a widget."
useSimpleUiForNonRootPages: "Use simplified UI to navigated pages"
_columns:
main: "Main"
widgets: "Widgets"

View file

@ -49,9 +49,15 @@ delete: "Borrar"
deleteAndEdit: "Borrar y editar"
deleteAndEditConfirm: "¿Estás seguro de que quieres borrar esta nota y editarla? Perderás todas las reacciones, renotas y respuestas."
addToList: "Agregar a lista"
addToAntenna: "Añadir a la antena"
sendMessage: "Enviar un mensaje"
copyRSS: "Copiar RSS"
copyUsername: "Copiar nombre de usuario"
copyUserId: "Copiar ID del usuario"
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"
reply: "Responder"
loadMore: "Ver más"
@ -134,8 +140,10 @@ unblockConfirm: "¿Quiere dejar de bloquear esta cuenta?"
suspendConfirm: "¿Quiere suspender esta cuenta?"
unsuspendConfirm: "¿Quiere dejar de suspender esta cuenta?"
selectList: "Seleccione una lista"
editList: "Editar lista"
selectChannel: "Seleccionar canal"
selectAntenna: "Seleccionar antena"
editAntenna: "Editar antena"
selectWidget: "Seleccionar widget"
editWidgets: "Editar widgets"
editWidgetsExit: "Terminar edición"
@ -148,6 +156,8 @@ addEmoji: "Agregar emoji"
settingGuide: "Configuración sugerida"
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."
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"
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 CherryPick para que trate a esta cuenta como un bot."
flagAsCat: "Esta cuenta es un gato"
@ -229,10 +239,10 @@ instanceFollowers: "Seguidores de la instancia"
instanceUsers: "Usuarios de la instancia"
changePassword: "Cambiar contraseña"
security: "Seguridad"
retypedNotMatch: "No hay coincidencia"
retypedNotMatch: "La información no coincide."
currentPassword: "Contraseña actual"
newPassword: "Contraseña nueva"
newPasswordRetype: "Contraseña nueva (repetir)"
newPasswordRetype: "Reescribe contraseña nueva"
attachFile: "Añadir archivo"
more: "¡Más!"
featured: "Destacados"
@ -309,7 +319,7 @@ copyUrl: "Copiar URL"
rename: "Renombrar"
avatar: "Avatar"
banner: "Banner"
nsfw: "Marcado como sensible"
displayOfSensitiveMedia: "Mostrar contenido sensible"
whenServerDisconnected: "Cuando se pierda la conexión con el servidor"
disconnectedFromServer: "Desconectado del servidor"
reload: "Recargar"
@ -441,7 +451,7 @@ title: "Título"
text: "Texto"
enable: "Activar"
next: "Siguiente"
retype: "Intentar de nuevo"
retype: "Ingrese de nuevo"
noteOf: "Notas de {user}"
inviteToGroup: "Invitar al grupo"
quoteAttached: "Cita añadida"
@ -462,7 +472,7 @@ weakPassword: "Contraseña débil"
normalPassword: "Buena contraseña"
strongPassword: "Muy buena contraseña"
passwordMatched: "Correcto"
passwordNotMatched: "Las contraseñas no son las mismas"
passwordNotMatched: "Las contraseñas no coinciden"
signinWith: "Inicie sesión con {x}"
signinFailed: "Autenticación fallida. Asegúrate de haber usado el nombre de usuario y contraseña correctos."
or: "O"
@ -802,8 +812,9 @@ noMaintainerInformationWarning: "No se ha establecido la información del admini
noBotProtectionWarning: "La protección contra los bots no está configurada"
configure: "Configurar"
postToGallery: "Crear una nueva publicación en la galería"
postToHashtag: "Publicar a este hashtag"
gallery: "Galería"
recentPosts: "Posts recientes"
recentPosts: "Publicaciones recientes"
popularPosts: "Más vistos"
shareWithNote: "Compartir con una nota"
ads: "Anuncios"
@ -835,6 +846,7 @@ translatedFrom: "Traducido de {x}"
accountDeletionInProgress: "La eliminación de la cuenta está en curso"
usernameInfo: "Un nombre que identifique su cuenta de otras en este servidor. Puede utilizar el alfabeto (a~z, A~Z), dígitos (0~9) o guiones bajos (_). Los nombres de usuario no se pueden cambiar posteriormente."
aiChanMode: "Modo Ai"
devMode: "Modo de desarrollador"
keepCw: "Mantener la advertencia de contenido"
pubSub: "Cuentas Pub/Sub"
lastCommunication: "Última comunicación"
@ -844,15 +856,17 @@ breakFollow: "Dejar de seguir"
breakFollowConfirm: "¿Quieres dejar de seguir?"
itsOn: "¡Está encendido!"
itsOff: "¡Está apagado!"
emailRequiredForSignup: "Se requere una dirección de correo electrónico para el registro de la cuenta"
on: "Activado"
off: "Desactivado"
emailRequiredForSignup: "Se requiere una dirección de correo electrónico para el registro de la cuenta"
unread: "No leído"
filter: "Filtro"
filter: "Filtrar"
controlPanel: "Panel de control"
manageAccounts: "Administrar cuenta"
makeReactionsPublic: "Hacer el historial de reacciones público"
makeReactionsPublicDescription: "Todas las reacciones que hayas hecho serán públicamente visibles."
classic: "Clásico"
muteThread: "Ocultar hilo"
muteThread: "Silenciar hilo"
unmuteThread: "Mostrar hilo"
ffVisibility: "Visibilidad de seguidores y seguidos"
ffVisibilityDescription: "Puedes configurar quien puede ver a quienes sigues y quienes te siguen"
@ -926,6 +940,7 @@ remoteOnly: "Sólo remoto"
failedToUpload: "La subida falló"
cannotUploadBecauseInappropriate: "Este archivo no se puede subir debido a que algunas partes han sido detectadas comoNSFW."
cannotUploadBecauseNoFreeSpace: "La subida falló debido a falta de espacio libre en la unidad del usuario."
cannotUploadBecauseExceedsFileSizeLimit: "Este archivo supera el peso máximo y no puede ser subido."
beta: "Beta"
enableAutoSensitive: "Marcar automáticamente contenido NSFW"
enableAutoSensitiveDescription: "Permite la detección y marcado automático de contenido NSFW usando 'Machine Learning' cuando sea posible. Incluso si esta opción está desactivada, puede ser activado para toda la instancia."
@ -956,18 +971,23 @@ show: "Apariencia"
neverShow: "No mostrar de nuevo"
remindMeLater: "Recordar después"
didYouLikeMisskey: "¿Te gusta CherryPick?"
pleaseDonate: "CherryPick es software libre, y es usado por {host} . Por favor, ¡considera donar al proyecto principal para que podamos continuar!"
pleaseDonate: "{host} usa el software gratuito CherryPick. Por favor ¡Considera donar al proyecto principal para que podamos continuar!"
roles: "Roles"
role: "Roles"
role: "Rol"
noRole: "Rol no encontrado"
normalUser: "Usuario normal"
undefined: "Indefinido"
assign: "Asignar"
unassign: "Quitar"
color: "Color"
manageCustomEmojis: "Administrar emojis personalizados"
youCannotCreateAnymore: "Se alcanzó el límite de creación"
cannotPerformTemporary: "Indisponible temporalmente"
youCannotCreateAnymore: "Has llegado al límite de creaciones."
cannotPerformTemporary: "Temporalmente no disponible"
cannotPerformTemporaryDescription: "Esta acción no se puede realizar porque se excedió el límite de ejecución. Espera un poco y prueba de nuevo."
invalidParamError: "Parámetros inválidos"
invalidParamErrorDescription: "Los parámetros de la solicitud son inválidos. Normalmente se trata de un error, pero también puede haberse excedido algún límite o similares."
permissionDeniedError: "Operación denegada"
permissionDeniedErrorDescription: "Esta cuenta no tiene permisos para hacer esa acción."
preset: "Predefinido"
selectFromPresets: "Escoger desde predefinidos"
achievements: "Logros"
@ -983,7 +1003,7 @@ internalServerErrorDescription: "El servidor tuvo un error inesperado."
copyErrorInfo: "Copiar detalles del error"
joinThisServer: "Registrarse en esta instancia"
exploreOtherServers: "Buscar otra instancia"
letsLookAtTimeline: "Mirar la línea de tiempo local"
letsLookAtTimeline: "Mira la línea de tiempo"
disableFederationConfirm: "¿Estas seguro que quieres desactivar la federación?"
disableFederationConfirmWarn: "Aunque no exista federación los posts no serán marcados como privados. En la mayoría de los casos, no es necesario hacer los posts no federar."
disableFederationOk: "Desactivar."
@ -994,10 +1014,13 @@ cannotBeChangedLater: "Esto no podrá ser cambiado después."
reactionAcceptance: "Aceptación de reacciones"
likeOnly: "Sólo 'me gusta'"
likeOnlyForRemote: "Sólo reacciones de instancias remotas"
nonSensitiveOnly: "Solo no sensible"
nonSensitiveOnlyForLocalLikeOnlyForRemote: "Sólo no contenido sensible (sólo me gusta en remote)"
rolesAssignedToMe: "Roles asignados a mí"
resetPasswordConfirm: "¿Realmente quieres cambiar la contraseña?"
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"
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"
license: "Licencia"
unfavoriteConfirm: "¿Desea quitar de favoritos?"
@ -1011,22 +1034,111 @@ enableChartsForFederatedInstances: "Generar gráficos de servidores remotos"
showClipButtonInNoteFooter: "Añadir \"Clip\" al menú de notas"
largeNoteReactions: "Agrandar las reacciones de las notas"
noteIdOrUrl: "ID o URL de la nota"
video: "Video"
videos: "Video"
dataSaver: "Ahorro de datos"
accountMigration: "Migración de cuenta"
accountMoved: "Este usuario se ha mudado a una nueva cuenta:"
accountMoved: "Este usuario se movió a una nueva cuenta:"
accountMovedShort: "Esta cuenta ha sido migrada."
operationForbidden: "Operación prohibida"
forceShowAds: "Siempre mostrar anuncios"
addMemo: "Añadir nota"
editMemo: "Editar nota"
reactionsList: "Lista de reacciones"
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"
vertical: "Vertical"
horizontal: "Horizontal"
position: "Posición"
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"
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"
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"
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"
specifyUser: "Especificar usuario"
failedToPreviewUrl: "No se pudo generar la vista previa"
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 CherryPick"
additionalEmojiDictionary: "Diccionario adicional de Emoji"
installed: "Instalado"
branding: "Marca"
enableServerMachineStats: "Publicar estadísticas de hardware del servidor"
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:
accountCreated: "¡La cuenta ha sido creada!"
letsStartAccountSetup: "Para empezar, creemos tu perfil."
letsFillYourProfile: "Primero, creemos tu perfil."
profileSetting: "Configuración del perfil"
privacySetting: "Configuración de privacidad"
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."
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} (CherryPick), 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:
moveFrom: "Trasladar de otra cuenta a ésta"
moveFromSub: "Crear un alias para otra cuenta."
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"
moveTo: "Mover esta cuenta a una nueva"
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"
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."
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:"
_achievements:
earnedAt: "Desbloqueado el"
@ -1201,6 +1313,7 @@ _achievements:
description: "30 minutos dedicados a CherryPick"
_client60min:
title: "Viendo mucho CherryPick."
description: "Dejar abierto CherryPick por al menos 60 minutos"
_noteDeletedWithin1min:
title: "Ah... Mejor no..."
description: "Borrar una nota antes que de pase 1 minuto"
@ -1289,6 +1402,8 @@ _role:
iconUrl: "URL del ícono"
asBadge: "Mostrar como emblema"
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"
descriptionOfDisplayOrder: "Entre más alto el número, mayor es la posición en la interfaz."
canEditMembersByModerator: "Permitir a los moderadores editar los miembros"
@ -1303,8 +1418,12 @@ _role:
ltlAvailable: "Explorar la línea de tiempo local"
canPublicNote: "Permitir la publicació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"
driveCapacity: "Capacidad de almacenamiento"
driveCapacity: "Capacidad del drive"
alwaysMarkNsfw: "Siempre marcar archivos como NSFW"
pinMax: "Máximo de notas fijadas"
antennaMax: "Máximo de antenas"
wordMuteMax: "Máximo de caracteres en palabras silenciadas"
@ -1364,6 +1483,7 @@ _ad:
back: "Deseleccionar"
reduceFrequencyOfThisAd: "Mostrar menos este anuncio."
hide: "No mostrar"
timezoneinfo: "El día de la semana está determidado por la zona horaria del servidor."
_forgotPassword:
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."
@ -1415,10 +1535,10 @@ _aboutMisskey:
donate: "Donar a Misskey"
morePatrons: "Muchas más personas nos apoyan. Muchas gracias🥰"
patrons: "Patrocinadores"
_nsfw:
respect: "Ocultar medios NSFW"
ignore: "No esconder medios NSFW "
force: "Ocultar todos los medios"
_displayOfSensitiveMedia:
respect: "Esconder medios marcados como sensibles"
ignore: "Mostrar medios marcados como sensibles"
force: "Esconder todala multimedia"
_mfm:
cheatSheet: "Hoja de referencia de MFM"
intro: "MFM es un lenguaje de marcado dedicado que se puede usar en varios lugares dentro de Misskey. Aquí puede ver una lista de sintaxis disponibles en MFM."
@ -1503,6 +1623,8 @@ _channel:
following: "Siguiendo"
usersCount: "{n} participantes"
notesCount: "{n} notas"
nameAndDescription: "Nombre y descripción"
nameOnly: "Sólo nombre"
_menuDisplay:
sideFull: "Horizontal"
sideIcon: "Horizontal (ícono)"
@ -1606,7 +1728,7 @@ _sfx:
channel: "Notificaciones del canal"
_ago:
future: "Futuro"
justNow: "Recién ahora"
justNow: "Justo ahora"
secondsAgo: "Hace {n} segundos"
minutesAgo: "Hace {n} minutos"
hoursAgo: "Hace {n} horas"
@ -1620,6 +1742,16 @@ _time:
minute: "Minutos"
hour: "Horas"
day: "Días"
_timelineTutorial:
title: "Cómo usar CherryPick"
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_2: "Para añadir una reacción selecciona el botón \"+\" en la nota y escoge el emoji que quieras para reaccionar."
_2fa:
alreadyRegistered: "Ya has completado la configuración."
registerTOTP: "Registrar aplicación autenticadora"
@ -1766,14 +1898,14 @@ _visibility:
homeDescription: "Visible sólo en la linea de tiempo de inicio"
followers: "Seguidores"
followersDescription: "Visible sólo para tus seguidores"
specified: "Mensaje directo"
specified: "Nota directa"
specifiedDescription: "Visible sólo para los usuarios elegidos"
disableFederation: "No federado"
disableFederationDescription: "No enviar a otras instancias"
_postForm:
replyPlaceholder: "Responder a esta nota"
quotePlaceholder: "Citar esta nota"
channelPlaceholder: "Postear en el canal"
channelPlaceholder: "Publicar en el canal"
_placeholders:
a: "¿Qué haces?"
b: "¿Te pasó algo?"
@ -1953,6 +2085,7 @@ _deck:
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."
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:
main: "Principal"
widgets: "Widgets"
@ -1962,7 +2095,8 @@ _deck:
list: "Listas"
channel: "Canal"
mentions: "Menciones"
direct: "Mensaje directo"
direct: "Notas directas"
roleTimeline: "Linea de tiempo del rol"
_dialog:
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}."
@ -1970,8 +2104,8 @@ _disabledTimeline:
title: "Línea de tiempo deshabilitada"
description: "No puedes usar esta línea de tiempo con tus roles actuales."
_drivecleaner:
orderBySizeDesc: "Más grandes"
orderByCreatedAtAsc: "Más antiguos"
orderBySizeDesc: "Tamaño descendiente"
orderByCreatedAtAsc: "Fecha ascendente"
_webhookSettings:
createWebhook: "Crear Webhook"
name: "Nombre"

View file

@ -49,13 +49,19 @@ delete: "Supprimer"
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."
addToList: "Ajouter à une liste"
addToAntenna: "Ajouter à lantenne"
sendMessage: "Envoyer un message"
copyRSS: "Copier le RSS"
copyUsername: "Copier le nom dutilisateur·rice"
searchUser: "Chercher un·e 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 utilisateur"
reply: "Répondre"
loadMore: "Afficher plus …"
showMore: "Afficher plus …"
showMore: "Voir plus"
showLess: "Fermer"
youGotNewFollower: "Vous suit"
receiveFollowRequest: "Demande dabonnement reçue"
@ -68,16 +74,16 @@ import: "Importer"
export: "Exporter"
files: "Fichiers"
download: "Télécharger"
driveFileDeleteConfirm: "Êtes-vous sûr·e de vouloir supprimer le fichier \"{name}\" ? Les notes liées à ce fichier seront aussi supprimées."
driveFileDeleteConfirm: "Êtes-vous sûr de vouloir supprimer le fichier \"{name}\" ? Les notes liées à ce fichier seront aussi supprimées."
unfollowConfirm: "Désirez-vous vous désabonner de {name} ?"
exportRequested: "Vous avez demandé une exportation. Lopération pourrait prendre un peu de temps. Une terminée, le fichier résultant sera ajouté au Drive."
importRequested: "Vous avez initié un import. Cela pourrait prendre un peu de temps."
lists: "Listes"
noLists: "Vous navez aucune liste"
note: "Notes"
note: "Note"
notes: "Notes"
following: "Abonnements"
followers: "Abonné·e·s"
followers: "Abonnés"
followsYou: "Vous suit"
createList: "Créer une liste"
manageLists: "Gérer les listes"
@ -116,7 +122,7 @@ reaction: "Réactions"
reactions: "Réactions"
reactionSetting: "Réactions à afficher dans le sélecteur de réactions"
reactionSettingDescription2: "Déplacer pour réorganiser, cliquer pour effacer, utiliser « + » pour ajouter."
rememberNoteVisibility: "Activer l'option \" se souvenir de la visibilité des notes \" vous permet de réutiliser automatiquement la visibilité utilisée lors de la publication de votre note précédente."
rememberNoteVisibility: "Se souvenir de la visibilité des notes"
attachCancel: "Supprimer le fichier attaché"
markAsSensitive: "Marquer comme sensible"
unmarkAsSensitive: "Supprimer le marquage comme sensible"
@ -134,6 +140,7 @@ unsuspendConfirm: "Êtes-vous sûr·e de vouloir annuler la suspension de ce com
selectList: "Sélectionner une liste"
selectChannel: "Sélectionner un canal"
selectAntenna: "Sélectionner une antenne"
editAntenna: "Modifier l'antenne"
selectWidget: "Sélectionner un widget"
editWidgets: "Modifier les widgets"
editWidgetsExit: "Valider les modifications"
@ -146,6 +153,8 @@ addEmoji: "Ajouter un émoji"
settingGuide: "Configuration proposée"
cacheRemoteFiles: "Mise en cache des fichiers distants"
cacheRemoteFilesDescription: "Lorsque cette option est désactivée, les fichiers distants sont chargés directement depuis linstance distante. La désactiver diminuera certes lutilisation de lespace 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"
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 CherryPick pour traiter ce compte comme un robot."
flagAsCat: "Ce compte est un chat"
@ -154,6 +163,7 @@ 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."
autoAcceptFollowed: "Accepter automatiquement les demandes dabonnement venant dutilisateur·rice·s que vous suivez"
addAccount: "Ajouter un compte"
reloadAccountsList: "Rafraichir la liste des comptes"
loginFailed: "Échec de la connexion"
showOnRemote: "Voir sur linstance distante"
general: "Général"
@ -260,6 +270,8 @@ noMoreHistory: "Il ny a plus dhistorique"
startMessaging: "Commencer à discuter"
nUsersRead: "Lu par {n} personnes"
agreeTo: "Jaccepte {0}"
agree: "Accepter"
termsOfService: "Conditions d'utilisation"
start: "Commencer"
home: "Principal"
remoteUserCaution: "Les informations de ce compte risqueraient dêtre incomplètes du fait que lutilisateur·rice provient dune instance distante."
@ -302,7 +314,7 @@ copyUrl: "Copier lURL"
rename: "Renommer"
avatar: "Avatar"
banner: "Bannière"
nsfw: "Contenu sensible"
displayOfSensitiveMedia: "Afficher les médias sensibles"
whenServerDisconnected: "Lorsque la connexion au serveur est perdue"
disconnectedFromServer: "Déconnecté·e du serveur"
reload: "Rafraîchir"
@ -392,11 +404,15 @@ about: "Informations"
aboutMisskey: "À propos de CherryPick"
administrator: "Administrateur"
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"
moderation: "Modérations"
nUsersMentioned: "{n} utilisateur·rice·s mentionné·e·s"
securityKey: "Clé de sécurité"
lastUsed: "Dernier utilisé"
lastUsedAt: "Dernière utilisation : {t}"
unregister: "Se désinscrire"
passwordLessLogin: "Se connecter sans mot de passe"
resetPassword: "Réinitialiser le mot de passe"
@ -546,9 +562,14 @@ userSuspended: "Cet·te utilisateur·rice a été suspendu·e."
userSilenced: "Cette utilisateur·trice a été mis·e en sourdine."
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."
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"
divider: "Séparateur"
addItem: "Ajouter un élément"
rearrange: "Trier par"
relays: "Relais"
addRelay: "Ajouter un relais"
inboxUrl: "Inbox URL"
@ -690,6 +711,8 @@ contact: "Contact"
useSystemFont: "Utiliser la police par défaut du système"
clips: "Clips"
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"
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\"."
@ -774,6 +797,7 @@ noMaintainerInformationWarning: "Informations administrateur non configurées."
noBotProtectionWarning: "La protection contre les bots n'est pas configurée."
configure: "Configurer"
postToGallery: "Publier dans la galerie"
postToHashtag: "Publier avec ce hashtag"
gallery: "Galerie"
recentPosts: "Les plus récentes"
popularPosts: "Les plus consultées"
@ -812,6 +836,7 @@ lastCommunication: "Dernière communication"
resolved: "Résolu"
unresolved: "En attente"
breakFollow: "Ne plus suivre"
breakFollowConfirm: "Êtes-vous sûr de vouloir vous désabonner?"
itsOn: "Activé"
itsOff: "Désactivé"
emailRequiredForSignup: "Une adresse e-mail est nécessaire pour créer un compte"
@ -1099,10 +1124,6 @@ _aboutMisskey:
donate: "Soutenir Misskey"
morePatrons: "Nous apprécions vraiment le soutien de nombreuses autres personnes non mentionnées ici. Merci à toutes et à tous ! 🥰"
patrons: "Contributeurs"
_nsfw:
respect: "Cacher les médias marqués comme contenu sensible"
ignore: "Afficher les médias sensibles"
force: "Cacher tous les médias"
_mfm:
cheatSheet: "Antisèche MFM"
intro: "MFM est un langage Markdown spécifique utilisable ici et là dans Misskey. Vous pouvez vérifier ici les structures utilisables avec MFM."

View file

@ -1,6 +1,6 @@
const fs = require('fs');
const yaml = require('js-yaml');
const ts = require('typescript');
import * as fs from 'node:fs';
import * as yaml from 'js-yaml';
import * as ts from 'typescript';
function createMembers(record) {
return Object.entries(record)
@ -14,7 +14,7 @@ function createMembers(record) {
));
}
module.exports = function generateDTS() {
export default function generateDTS() {
const locale = yaml.load(fs.readFileSync(`${__dirname}/ja-JP.yml`, 'utf-8'));
const members = createMembers(locale);
const elements = [
@ -51,11 +51,7 @@ module.exports = function generateDTS() {
ts.NodeFlags.Const | ts.NodeFlags.Ambient | ts.NodeFlags.ContextFlags,
),
),
ts.factory.createExportAssignment(
undefined,
true,
ts.factory.createIdentifier('locales'),
),
ts.factory.createExportDefault(ts.factory.createIdentifier('locales')),
];
const printed = ts.createPrinter({
newLine: ts.NewLineKind.LineFeed,

103
locales/hu-HU.yml Normal file
View file

@ -0,0 +1,103 @@
---
_lang_: "Japán"
monthAndDay: "{month}.{day}."
search: "Keresés"
notifications: "Értesítések"
username: "Felhasználónév"
password: "Jelszó"
forgotPassword: "Elfelejtett jelszó"
ok: "OK"
gotIt: "Rendben"
cancel: "Mégse"
noThankYou: "Nem, köszönöm"
enterUsername: "Felhasználónév megadása"
renotedBy: "{user} Renotolta"
noNotes: "Nincs Note"
noNotifications: "Nincs értesítés"
instance: "Szerver"
settings: "Beállítások"
notificationSettings: "Értesítés beállításai"
basicSettings: "Alapbeállítás"
otherSettings: "Egyéb beállítások"
openInWindow: "Megnyitás ablakban"
profile: "Saját profil"
timeline: "Idővonal"
noAccountDescription: "Nincs leírás"
login: "Bejelentkezés"
loggingIn: "Belépés"
logout: "Kijelentkezés"
signup: "Regisztráció"
uploading: "Feltöltés"
save: "Mentés"
users: "Felhasználók"
addUser: "Felhasználó hozzáadása"
favorite: "Kedvencek"
favorites: "Kedvencek"
unfavorite: "Törlés a kedvencek közül."
favorited: "Kedvencek közé rakva."
alreadyFavorited: "Már a kedvencek között van."
cantFavorite: "Nem sikerült a kedvencek közé rakni."
pin: "Rögzítés"
unpin: "Rögzítés feloldása"
copyContent: "Tartalom másolása"
copyLink: "Hivatkozás Másolása"
delete: "Törlés"
deleteAndEdit: "Törlés és szerkesztés"
deleteAndEditConfirm: "Biztosan törlöd ezt a jegyzetet és újrafogalmazza? Így eveszíted az összes reakciót, renote-ot és választ."
addToList: "Hozzáadás a listákhoz"
privacy: "Adatvédelem"
makeFollowManuallyApprove: "Csak jóváhagyással követhetnek"
defaultNoteVisibility: "Alapértelmezett láthatóság"
follow: "Követés"
followRequest: "Követés kérése"
followRequests: "Követési kérések"
unfollow: "Követés visszavonása"
followRequestPending: "Függőben levő követési kérés"
enterEmoji: "Írj egy emoji-t"
renote: "Renote"
unrenote: "Renote visszavonása"
renoted: "Renotolva"
cantRenote: "Nem lehet Renotolni"
cantReRenote: "A Renote nem renotálható"
quote: "Idézet"
inChannelRenote: "Csak csatornán bellüli Renote"
inChannelQuote: "Csak csatornán bellüli idézet"
pinnedNote: "Csatolt jegyzet"
pinned: "Rögzítés"
you: "Te"
clickToShow: "Kattints ide"
sensitive: "Érzékeny"
add: "Hozzáad"
reaction: "Reakciók"
reactions: "Reakciók"
instances: "Szerver"
remove: "Törlés"
pinnedNotes: "Csatolt jegyzet"
smtpUser: "Felhasználónév"
smtpPass: "Jelszó"
user: "Felhasználók"
searchByGoogle: "Keresés"
_theme:
keys:
renote: "Renote"
_sfx:
notification: "Értesítések"
_2fa:
renewTOTPCancel: "Nem, köszönöm"
_widgets:
profile: "Saját profil"
notifications: "Értesítések"
timeline: "Idővonal"
_profile:
username: "Felhasználónév"
_notification:
_types:
renote: "Renote"
quote: "Idézet"
reaction: "Reakciók"
_actions:
renote: "Renote"
_deck:
_columns:
notifications: "Értesítések"
tl: "Idővonal"

View file

@ -5,7 +5,7 @@ introMisskey: "Selamat datang! CherryPick adalah perangkat mikroblog tercatu ber
poweredByMisskeyDescription: "{name} adalah sebuah layanan (instance) yang menggunakan platform sumber terbuka <b>CherryPick</b>."
monthAndDay: "{day} {month}"
search: "Penelusuran"
notifications: "Pemberitahuan"
notifications: "Notifikasi"
username: "Nama Pengguna"
password: "Kata sandi"
forgotPassword: "Lupa Kata Sandi"
@ -17,7 +17,7 @@ noThankYou: "Tidak sekarang."
enterUsername: "Masukkan nama pengguna"
renotedBy: "direnote oleh {user}"
noNotes: "Tidak ada catatan"
noNotifications: "Tidak ada pemberitahuan"
noNotifications: "Tidak ada notifikasi"
instance: "Instansi"
settings: "Pengaturan"
notificationSettings: "Atur Notifikasi"
@ -25,7 +25,7 @@ basicSettings: "Pengaturan umum"
otherSettings: "Pengaturan lainnya"
openInWindow: "Buka di jendela"
profile: "Profil"
timeline: "Linimasa"
timeline: "Lini masa"
noAccountDescription: "Pengguna ini belum menulis bio"
login: "Masuk"
loggingIn: "Sedang masuk"
@ -49,9 +49,15 @@ delete: "Hapus"
deleteAndEdit: "Hapus dan sunting"
deleteAndEditConfirm: "Apakah kamu yakin ingin menghapus note ini dan menyuntingnya? Kamu akan kehilangan semua reaksi, renote dan balasan di note ini."
addToList: "Tambahkan ke daftar"
addToAntenna: "Tambahkan ke Antena"
sendMessage: "Kirim pesan"
copyRSS: "Salin RSS"
copyUsername: "Salin nama pengguna"
copyUserId: "Salin ID pengguna"
copyNoteId: "Salin ID catatan"
copyFileId: "Salin Berkas"
copyFolderId: "Salin Folder"
copyProfileUrl: "Salin Alamat Web Profil"
searchUser: "Cari pengguna"
reply: "Balas"
loadMore: "Selebihnya"
@ -90,7 +96,7 @@ serverIsDead: "Tidak ada respon dari peladen. Mohon tunggu dan coba beberapa saa
youShouldUpgradeClient: "Untuk melihat halaman ini, mohon muat ulang untuk memutakhirkan klienmu."
enterListName: "Masukkan nama daftar"
privacy: "Privasi"
makeFollowManuallyApprove: "Permintaan mengikuti membutuhkan persetujuan"
makeFollowManuallyApprove: "Permintaan mengikuti butuh persetujuan"
defaultNoteVisibility: "Privasi bawaan catatan"
follow: "Ikuti"
followRequest: "Permintaan mengikuti"
@ -115,7 +121,7 @@ add: "Tambahkan"
reaction: "Reaksi"
reactions: "Reaksi"
reactionSetting: "Reaksi untuk dimunculkan di bilah reaksi"
reactionSettingDescription2: "Geser untuk memindah urutkan, klik untuk menghapus, tekan \"+\" untuk menambahkan"
reactionSettingDescription2: "Geser untuk memindah urutan emoji, klik untuk menghapus, tekan \"+\" untuk menambahkan"
rememberNoteVisibility: "Ingat pengaturan visibilitas catatan"
attachCancel: "Hapus lampiran"
markAsSensitive: "Tandai sebagai konten sensitif"
@ -134,8 +140,10 @@ unblockConfirm: "Apakah kamu yakin ingin membuka blokir akun ini?"
suspendConfirm: "Apakah kamu yakin ingin membekukan akun ini?"
unsuspendConfirm: "Apakah kamu yakin ingin membuka pembekuan akun ini?"
selectList: "Pilih daftar"
editList: "Sunting daftar"
selectChannel: "Pilih kanal"
selectAntenna: "Pilih Antena"
editAntenna: "Sunting antena"
selectWidget: "Pilih gawit"
editWidgets: "Sunting gawit"
editWidgetsExit: "Selesai"
@ -146,16 +154,17 @@ emojiName: "Nama emoji"
emojiUrl: "URL Emoji"
addEmoji: "Tambahkan emoji"
settingGuide: "Pengaturan rekomendasi"
cacheRemoteFiles: "Tembolokkan berkas remote"
cacheRemoteFilesDescription: "Ketika pengaturan ini dinonaktifkan, berkas luar akan dimuat langsung dari instansi luar. Menonaktifkan ini akan mengurangi penggunaan penyimpanan, namun dapat menyebabkan meningkatkan lalu lintas bandwidth, karena thumbnail tidak dihasilkan."
cacheRemoteFiles: "Tembolokkan berkas dari instansi luar"
cacheRemoteFilesDescription: "Ketika pengaturan ini dinonaktifkan, berkas dari instansi luar akan dimuat langsung. Menonaktifkan ini akan mengurangi penggunaan penyimpanan peladen, namun dapat menyebabkan peningkatan lalu lintas bandwidth, karena keluku tidak dihasilkan."
flagAsBot: "Atur akun ini sebagai Bot"
flagAsBotDescription: "Jika akun ini dikendalikan oleh program, tetapkanlah opsi ini. Jika diaktifkan, ini akan berfungsi sebagai tanda bagi pengembang lain untuk mencegah interaksi berantai dengan bot lain dan menyesuaikan sistem internal CherryPick untuk memperlakukan akun ini sebagai bot."
flagAsCat: "Atur akun ini sebagai kucing"
flagAsCatDescription: "Nyalakan tanda ini untuk menandai akun ini sebagai kucing."
flagShowTimelineReplies: "Tampilkan balasan di linimasa"
flagShowTimelineRepliesDescription: "Menampilkan balasan pengguna dari note pengguna lain di linimasa apabila dinyalakan."
flagShowTimelineReplies: "Tampilkan balasan di lini masa"
flagShowTimelineRepliesDescription: "Menampilkan balasan pengguna dari catatan pengguna lain di lini masa apabila dinyalakan."
autoAcceptFollowed: "Setujui otomatis permintaan mengikuti dari pengguna yang kamu ikuti"
addAccount: "Tambahkan akun"
reloadAccountsList: "Muat ulang daftar akun"
loginFailed: "Gagal untuk masuk"
showOnRemote: "Lihat profil asli"
general: "Umum"
@ -166,7 +175,7 @@ searchWith: "Cari: {q}"
youHaveNoLists: "Kamu tidak memiliki daftar apapun"
followConfirm: "Apakah kamu yakin ingin mengikuti {name}?"
proxyAccount: "Akun proksi"
proxyAccountDescription: "Akun proksi merupakan sebuah akun yang bertindak sebagai pengikut luar untuk pengguna dalam kondisi tertentu. Sebagai contoh, ketika pengguna menambahkan seorang pengguna luar ke dalam daftar, aktivitas dari pengguna luar tidak akan disampaikan ke instansi apabila tidak ada pengguna lokal yang mengikuti pengguna tersebut, dengan begitu akun proksilah yang akan mengikutinya."
proxyAccountDescription: "Akun proksi merupakan sebuah akun yang bertindak sebagai pengikut instansi luar untuk pengguna dalam kondisi tertentu. Sebagai contoh, ketika pengguna menambahkan seorang pengguna instansi luar ke dalam daftar, aktivitas dari pengguna instansi luar tidak akan disampaikan ke instansi apabila tidak ada pengguna lokal yang mengikuti pengguna tersebut, dengan begitu akun proksilah yang akan mengikutinya."
host: "Host"
selectUser: "Pilih pengguna"
recipient: "Penerima"
@ -198,7 +207,7 @@ clearQueue: "Bersihkan antrian"
clearQueueConfirmTitle: "Apakah kamu yakin ingin membersihkan antrian?"
clearQueueConfirmText: "Seluruh sisa catatan yang tidak tersampaikan di dalam antrian tidak akan difederasi. Biasanya operasi ini TIDAK dibutuhkan."
clearCachedFiles: "Hapus tembolok"
clearCachedFilesConfirm: "Apakah kamu yakin ingin menghapus seluruh tembolok berkas remote?"
clearCachedFilesConfirm: "Apakah kamu yakin ingin menghapus seluruh tembolok berkas instansi luar?"
blockedInstances: "Instansi terblokir"
blockedInstancesDescription: "Daftar nama host dari instansi yang diperlukan untuk diblokir. Instansi yang didaftarkan tidak akan dapat berkomunikasi dengan instansi ini."
muteAndBlock: "Bisukan / Blokir"
@ -223,9 +232,9 @@ all: "Semua"
subscribing: "Berlangganan"
publishing: "Sedang menyiarkan langsung"
notResponding: "Tidak ada respon"
instanceFollowing: "Mengikuti instance"
instanceFollowers: "Pengikut instance"
instanceUsers: "Pengguna pada instance ini"
instanceFollowing: "Mengikuti instansi"
instanceFollowers: "Pengikut instansi"
instanceUsers: "Pengguna pada instansi ini"
changePassword: "Ubah kata sandi"
security: "Keamanan"
retypedNotMatch: "Input tidak sama"
@ -233,11 +242,11 @@ currentPassword: "Kata sandi saat ini"
newPassword: "Kata sandi baru"
newPasswordRetype: "Ulangi kata sandi baru"
attachFile: "Lampirkan berkas"
more: "Lagi !"
more: "Lainnya"
featured: "Sorotan"
usernameOrUserId: "Nama pengguna atau User ID"
noSuchUser: "Pengguna tidak ditemukan"
lookup: "Mencari"
lookup: "Cari"
announcements: "Pengumuman"
imageUrl: "URL Gambar"
remove: "Hapus"
@ -268,7 +277,7 @@ basicNotesBeforeCreateAccount: "Catatan penting"
termsOfService: "Syarat dan ketentuan"
start: "Mulai"
home: "Beranda"
remoteUserCaution: "Informasi ini mungkin tidak mutakhir, karena pengguna ini berasal dari instansi luar."
remoteUserCaution: "Informasi ini mungkin tidak mutakhir, karena pengguna ini berasal dari peladen instansi luar."
activity: "Aktivitas"
images: "Gambar"
image: "Gambar"
@ -308,19 +317,19 @@ copyUrl: "Salin tautan"
rename: "Ubah nama"
avatar: "Avatar"
banner: "Banner"
nsfw: "Konten sensitif"
displayOfSensitiveMedia: "Tampilkan media NSFW"
whenServerDisconnected: "Ketika kehilangan koneksi dengan peladen"
disconnectedFromServer: "Terputus koneksi dari peladen"
reload: "Muat ulang"
doNothing: "Abaikan"
reloadConfirm: "Apakah kamu ingin memuat ulang linimasa?"
reloadConfirm: "Apakah kamu ingin memuat ulang lini masa?"
watch: "Tonton"
unwatch: "Batal tonton"
accept: "Terima"
reject: "Tolak"
normal: "Normal"
instanceName: "Nama instance"
instanceDescription: "Tentang instance"
instanceName: "Nama instansi"
instanceDescription: "Tentang instansi"
maintainerName: "Pengelola"
maintainerEmail: "Surel pengelola"
tosUrl: "URL Syarat dan Ketentuan"
@ -334,9 +343,9 @@ pages: "Halaman"
integration: "Integrasi"
connectService: "Sambungkan"
disconnectService: "Putuskan"
enableLocalTimeline: "Nyalakan linimasa lokal"
enableGlobalTimeline: "Nyalakan linimasa global"
disablingTimelinesInfo: "Admin dan Moderator akan selalu memiliki akses ke semua linimasa meskipun linimasa tersebut tidak diaktifkan."
enableLocalTimeline: "Nyalakan lini masa lokal"
enableGlobalTimeline: "Nyalakan lini masa global"
disablingTimelinesInfo: "Admin dan Moderator akan selalu memiliki akses ke semua lini masa meskipun lini masa tersebut tidak diaktifkan."
registration: "Pendaftaran"
enableRegistration: "Nyalakan pendaftaran pengguna baru"
invite: "Undang"
@ -379,7 +388,7 @@ enableServiceworker: "Aktifkan ServiceWorker"
antennaUsersDescription: "Tuliskan satu nama pengguna per baris"
caseSensitive: "Peka huruf besar dan huruf kecil"
withReplies: "Termasuk balasan"
connectedTo: "Akun yang mengikuti telah terhubung"
connectedTo: "Akun berikut terhubung"
notesAndReplies: "Catatan dan balasan"
withFiles: "Media"
silence: "Bungkam"
@ -398,6 +407,7 @@ about: "Informasi"
aboutMisskey: "Tentang CherryPick"
administrator: "Admin"
token: "Token"
2fa: "Autentikasi 2-faktor"
totp: "Aplikasi autentikator"
totpDescription: "Gunakan aplikasi autentikator untuk mendapatkan kata sandi sekali pakai"
moderator: "Moderator"
@ -409,6 +419,7 @@ lastUsed: "Terakhir digunakan"
lastUsedAt: "Penggunaan terakhir: {t}"
unregister: "Batalkan pendaftaran"
passwordLessLogin: "Setel login tanpa kata sandi"
passwordLessLoginDescription: "Bolehkan masuk tanpa kata sandi dengan menggunakan hanya security-key atau passkey"
resetPassword: "Atur ulang kata sandi"
newPasswordIs: "Kata sandi baru adalah \"{password}\""
reduceUiAnimation: "Kurangi animasi antarmuka"
@ -417,7 +428,7 @@ notFound: "Tidak dapat ditemukan"
notFoundDescription: "Tidak ada halaman sesuai dengan URL yang ditentukan."
uploadFolder: "Lokasi unggah folder bawaan"
cacheClear: "Bersihkan tembolok"
markAsReadAllNotifications: "Tandai semua pemberitahuan telah dibaca"
markAsReadAllNotifications: "Tandai semua notifikasi telah dibaca"
markAsReadAllUnreadNotes: "Tandai semua catatan telah dibaca"
markAsReadAllTalkMessages: "Tandai semua pesan telah dibaca"
help: "Bantuan"
@ -470,6 +481,7 @@ aboutX: "Tentang {x}"
emojiStyle: "Gaya emoji"
native: "Native"
disableDrawer: "Jangan gunakan menu bergaya laci"
showNoteActionsOnlyHover: "Hanya tampilkan aksi catatan saat ditunjuk"
youHaveNoGroups: "Kamu tidak memiliki grup"
joinOrCreateGroup: "Bergabunglah dengan grup atau kamu dapat membuat grupmu sendiri."
noHistory: "Tidak ada riwayat"
@ -484,6 +496,8 @@ createAccount: "Buat akun"
existingAccount: "Akun yang ada"
regenerate: "Buat ulang"
fontSize: "Ukuran huruf"
mediaListWithOneImageAppearance: "Tinggi daftar media dengan satu gambar saja"
limitTo: "Batasi pada {x}"
noFollowRequests: "Kamu tidak memiliki permintaan mengikuti yang menunggu"
openImageInNewTab: "Buka gambar di tab baru"
dashboard: "Dasbor"
@ -499,7 +513,7 @@ promotion: "Promosi"
promote: "Promosikan"
numberOfDays: "Jumlah hari"
hideThisNote: "Sembunyikan catatan ini"
showFeaturedNotesInTimeline: "Tampilkan catatan yang diunggulkan di linimasa"
showFeaturedNotesInTimeline: "Tampilkan catatan yang diunggulkan di lini masa"
objectStorage: "Object Storage"
useObjectStorage: "Gunakan object storage"
objectStorageBaseUrl: "Base URL"
@ -517,9 +531,11 @@ objectStorageUseSSLDesc: "Matikan ini jika kamu tidak akan menggunakan HTTPS unt
objectStorageUseProxy: "Hubungkan melalui Proxy"
objectStorageUseProxyDesc: "Matikan ini jika kamu tidak akan menggunakan Proxy untuk koneksi ObjectStorage"
objectStorageSetPublicRead: "Setel \"public-read\" disaat mengunggah"
s3ForcePathStyleDesc: "Jika s3ForcePathStyle dinyalakan, nama bucket harus dimasukkan dalam path URL dan bukan URL nama host tersebut. Kamu perlu menyalakan pengaturan ini jika menggunakan layanan seperti instansi Minio yang self-hosted."
serverLogs: "Log Peladen"
deleteAll: "Hapus semua"
showFixedPostForm: "Tampilkan form posting di atas linimasa."
showFixedPostForm: "Tampilkan form posting di atas lini masa."
showFixedPostFormInChannel: "Tampilkan form posting di atas lini masa (Kanal)"
newNoteRecived: "Kamu mendapat catatan baru"
sounds: "Bunyi"
sound: "Bunyi"
@ -548,23 +564,28 @@ scratchpadDescription: "Scratchpad menyediakan lingkungan eksperimen untuk AiScr
output: "Keluaran"
script: "Script"
disablePagesScript: "Nonaktifkan script pada halaman"
updateRemoteUser: "Perbaharui informasi pengguna luar"
updateRemoteUser: "Perbaharui informasi pengguna instansi luar"
deleteAllFiles: "Hapus semua berkas"
deleteAllFilesConfirm: "Apakah kamu yakin ingin menghapus semua berkas?"
removeAllFollowing: "Tahan semua mengikuti"
removeAllFollowing: "Batalkan mengikuti semua pengguna"
removeAllFollowingDescription: "Batal mengikuti semua akun dari {host}. Mohon jalankan ini ketika instansi sudah tidak ada lagi."
userSuspended: "Pengguna ini telah dibekukan."
userSilenced: "Pengguna ini telah dibungkam."
yourAccountSuspendedTitle: "Akun ini dibekukan"
yourAccountSuspendedDescription: "Akun ini dibekukan karena melanggar ketentuan penggunaan layanan peladen atau semacamnya. Hubungi admin apabila ingin tahu alasan lebih lanjut. Mohon untuk tidak membuat akun baru."
tokenRevoked: "Token tidak valid"
tokenRevokedDescription: "Token ini telah kedaluwarsa. Mohon masuk lagi."
accountDeleted: "Akun telah dihapus"
accountDeletedDescription: "Akun ini telah dihapus."
menu: "Menu"
divider: "Pembagi"
addItem: "Tambahkan item"
rearrange: "Tata ulang"
relays: "Relay"
addRelay: "Tambahkan relay"
inboxUrl: "URL Kotak masuk"
addedRelays: "Relay yang ditambahkan"
serviceworkerInfo: "Harus diaktifkan untuk pemberitahuan push."
serviceworkerInfo: "Harus diaktifkan untuk notifikasi dorong."
deletedNote: "Catatan yang dihapus"
invisibleNote: "Catatan yang disembunyikan"
enableInfiniteScroll: "Aktifkan gulir tak terbatas"
@ -592,13 +613,13 @@ height: "Tinggi"
large: "Besar"
medium: "Sedang"
small: "Kecil"
generateAccessToken: "Buat access token"
generateAccessToken: "Buat token akses"
permission: "Izin"
enableAll: "Aktifkan semua"
disableAll: "Nonaktifkan semua"
tokenRequested: "Berikan ijin akses ke akun"
pluginTokenRequestedDescription: "Plugin ini dapat menggunakan setelan ijin disini."
notificationType: "Jenis pemberitahuan"
notificationType: "Jenis notifikasi"
edit: "Sunting"
emailServer: "Peladen surel"
enableEmail: "Nyalakan distribusi surel"
@ -629,10 +650,10 @@ delayed: "Terlambat"
database: "Basis data"
channel: "Kanal"
create: "Buat"
notificationSetting: "Pengaturan Pemberitahuan"
notificationSettingDesc: "Pilih tipe pemberitahuan untuk ditampilkan"
notificationSetting: "Pengaturan Notifikasi"
notificationSettingDesc: "Pilih tipe notifikasi untuk ditampilkan"
useGlobalSetting: "Gunakan setelan global"
useGlobalSettingDesc: "Jika dinyalakan, setelan pemberitahuan akun kamu akan digunakan. Jika dimatikan, konfigurasi secara individu dapat dibuat."
useGlobalSettingDesc: "Jika dinyalakan, setelan notifikasi akun kamu akan digunakan. Jika dimatikan, pengaturan secara individu dapat dibuat."
other: "Lainnya"
regenerateLoginToken: "Perbarui token login"
regenerateLoginTokenDescription: "Perbarui token yang digunakan secara internal saat login. Normalnya aksi ini tidak diperlukan. Jika diperbarui, semua perangkat akan dilogout."
@ -669,8 +690,8 @@ createNewClip: "Buat klip baru"
unclip: "Batalkan klip"
confirmToUnclipAlreadyClippedNote: "Catatan ini sudah disertakan di klip \"{name}\". Yakin ingin membatalkan catatan dari klip ini?"
public: "Publik"
i18nInfo: "CherryPick diterjemahkan ke dalam banyak bahasa oleh sukarelawan. Kamu dapat ikut membantu di {link}."
manageAccessTokens: "Kelola access token"
i18nInfo: "CherryPick diterjemahkan ke dalam banyak bahasa oleh sukarelawan. Kamu juga dapat ikut membantu menerjemahkannya di {link}."
manageAccessTokens: "Kelola token akses"
accountInfo: "Informasi akun"
notesCount: "Jumlah catatan"
repliesCount: "Jumlah balasan terkirim"
@ -687,7 +708,7 @@ yes: "Iya"
no: "Tidak"
driveFilesCount: "Jumlah berkas drive"
driveUsage: "Penggunaan ruang penyimpanan drive"
noCrawle: "Tolak pengindeksan crawler"
noCrawle: "Tolak pengindeksan perayap web"
noCrawleDescription: "Meminta mesin pencari untuk tidak mengindeks halaman profil kamu, catatan, Halaman, dll."
lockedAccountInfo: "Kecuali kamu menyetel visibilitas catatan milikmu ke \"Hanya pengikut\", catatan milikmu akan dapat dilihat oleh siapa saja, bahkan jika kamu memerlukan pengikut untuk disetujui secara manual."
alwaysMarkSensitive: "Tandai media dalam catatan sebagai media sensitif"
@ -703,10 +724,12 @@ contact: "Kontak"
useSystemFont: "Gunakan font bawaan sistem operasi"
clips: "Klip"
experimentalFeatures: "Fitur eksperimental"
experimental: "Eksperimental"
thisIsExperimentalFeature: "Fitur ini eksperimental. Fungsionalitas dari fitur ini dapat berubah sewaktu-waktu dan mungkin tidak bekerja sesuai semestinya."
developer: "Pengembang"
makeExplorable: "Buat akun tampil di \"Jelajahi\""
makeExplorableDescription: "Jika kamu mematikan ini, akun kamu tidak akan muncul di bagian \"Jelajahi:"
showGapBetweenNotesInTimeline: "Tampilkan jarak diantara catatan pada linimasa"
makeExplorableDescription: "Jika kamu mematikan ini, akun kamu tidak akan muncul di menu \"Jelajahi\""
showGapBetweenNotesInTimeline: "Tampilkan jarak diantara catatan pada lini masa"
duplicate: "Duplikat"
left: "Kiri"
center: "Tengah"
@ -745,14 +768,14 @@ capacity: "Kapasitas"
inUse: "Digunakan"
editCode: "Sunting kode"
apply: "Terapkan"
receiveAnnouncementFromInstance: "Terima pemberitahuan surel dari instansi ini"
emailNotification: "Pemberitahuan surel"
receiveAnnouncementFromInstance: "Terima pengumuman dari instansi ini"
emailNotification: "Notifikasi surel"
publish: "Terbitkan"
inChannelSearch: "Cari di kanal"
useReactionPickerForContextMenu: "Buka pemilih reaksi dengan klik-kanan"
typingUsers: "{users} sedang mengetik..."
jumpToSpecifiedDate: "Loncat ke tanggal spesifik"
showingPastTimeline: "Sedang menampilkan linimasa lama"
showingPastTimeline: "Sedang menampilkan lini masa lama"
clear: "Bersihkan"
markAllAsRead: "Tandai semua telah dibaca"
goBack: "Kembali"
@ -767,7 +790,7 @@ userInfo: "Informasi pengguna"
unknown: "Tidak diketahui"
onlineStatus: "Status daring"
hideOnlineStatus: "Sembunyikan status daring"
hideOnlineStatusDescription: "Menyembunyikan status daring kamu umengurangi kenyamanan untuk beberapa fungsi seperti contohnya pencarian."
hideOnlineStatusDescription: "Menyembunyikan status daring kamu akan mengurangi kenyamanan untuk beberapa fungsi, seperti contohnya pencarian."
online: "Daring"
active: "Aktif"
offline: "Luring"
@ -787,12 +810,14 @@ noMaintainerInformationWarning: "Informasi pengelola belum disetel."
noBotProtectionWarning: "Proteksi bot belum disetel."
configure: "Setel"
postToGallery: "Posting ke galeri"
postToHashtag: "Catat ke tagar ini"
gallery: "Galeri"
recentPosts: "Postingan terbaru"
popularPosts: "Postingan populer"
shareWithNote: "Bagikan dengan catatan"
ads: "Iklan"
expiration: "Batas akhir"
startingperiod: "Mulai"
memo: "Memo"
priority: "Prioritas"
high: "Tinggi"
@ -819,14 +844,18 @@ translatedFrom: "Terjemahkan dari {x}"
accountDeletionInProgress: "Penghapusan akun sedang dalam proses"
usernameInfo: "Nama yang mengidentifikasikan akun kamu dari yang lain pada peladen ini. Kamu dapat menggunakan alfabet (a~z, A~Z), digit (0~9) atau garis bawah (_). Username tidak dapat diubah setelahnya."
aiChanMode: "Mode Ai"
keepCw: "Biarkan Peringatan Konten"
devMode: "Mode pengembang"
keepCw: "Biarkan peringatan konten"
pubSub: "Akun Pub/Sub"
lastCommunication: "Komunikasi terakhir"
resolved: "Selesai"
unresolved: "Belum selesai"
breakFollow: "Batalkan mengikuti"
breakFollow: "Hapus pengikut"
breakFollowConfirm: "Yakin untuk menghapus pengikut ini?"
itsOn: "Aktif"
itsOff: "Nonaktif"
on: "Nyala"
off: "Mati"
emailRequiredForSignup: "Membutuhkan alamat surel untuk mendaftar"
unread: "Belum dibaca"
filter: "Saring"
@ -905,25 +934,26 @@ slow: "Lambat"
fast: "Cepat"
sensitiveMediaDetection: "Deteksi media NSFW"
localOnly: "Hanya lokal"
remoteOnly: "Hanya remot"
remoteOnly: "Hanya luar instansi"
failedToUpload: "Gagal mengunggah"
cannotUploadBecauseInappropriate: "Berkas ini tidak dapat diunggah karena sebagian dari berkas terdeteksi berpotensi NSFW."
cannotUploadBecauseNoFreeSpace: "Gagal mengunggah karena kekurangan kapasitas Drive."
cannotUploadBecauseExceedsFileSizeLimit: "Berkas ini tidak dapat diunggah karena melebihi batas ukuran berkas."
beta: "Beta"
enableAutoSensitive: "Penandaan NSFW otomatis"
enableAutoSensitiveDescription: "Mendeteksi otomatis dan menandai media NSFW menggunakan Machine Learning jika memungkinkan. Meskipun opsi ini dimatikan, ada kemungkinan dinyalakan secara menyeluruh pada instansi peladen."
enableAutoSensitiveDescription: "Mendeteksi otomatis dan menandai media NSFW menggunakan Pembelajaran Mesin jika memungkinkan. Meskipun opsi ini dimatikan, ada kemungkinan dinyalakan secara menyeluruh pada instansi peladen."
activeEmailValidationDescription: "Membolehkan validasi alamat surel ketat dengan mengecek apakah alamat surel tersebut temporer dan bisa berkomunikasi dengan surel tersebut. Ketidak tidak dicentang, hanya format surel yang divalidasi."
navbar: "Bilah navigasi"
shuffle: "Acak"
account: "Akun"
move: "Pindah"
pushNotification: "Pemberitahuan push"
subscribePushNotification: "Nyalakan pemberitahuan push"
unsubscribePushNotification: "Matikan pemberitahuan push"
pushNotificationAlreadySubscribed: "Pemberitahuan push telah dinyalakan"
pushNotificationNotSupported: "Browser atau instansi kamu tidak mendukung pemberitahuan push"
sendPushNotificationReadMessage: "Hapus pemberitahuan push ketika pemberitahuan relevan atau pesan telah dibaca"
sendPushNotificationReadMessageCaption: "Pemberitahuan berisi teks「{emptyPushNotificationMessage}」akan ditampilkan dalam waktu pendek. Ini mungkin dapat menambah pemakaian baterai pada perangkat kamu."
pushNotification: "Notifikasi dorong"
subscribePushNotification: "Nyalakan notifikasi dorong"
unsubscribePushNotification: "Matikan notifikasi dorong"
pushNotificationAlreadySubscribed: "Notifikasi dorong telah dinyalakan"
pushNotificationNotSupported: "Browser atau instansi kamu tidak mendukung notifikasi dorong"
sendPushNotificationReadMessage: "Hapus notifikasi dorong ketika notifikasi relevan atau pesan telah dibaca"
sendPushNotificationReadMessageCaption: "Notifikasi berisi teks「{emptyPushNotificationMessage}」akan ditampilkan dalam waktu pendek. Ini mungkin dapat menambah pemakaian baterai pada perangkat kamu."
windowMaximize: "Maksimalkan"
windowMinimize: "Minimalkan"
windowRestore: "Kembalikan"
@ -942,6 +972,7 @@ didYouLikeMisskey: "Apakah kamu mulai menyukai CherryPick?"
pleaseDonate: "{host} menggunakan perangkat lunak bebas yaitu CherryPick. Kami sangat mengapresiasi sekali donasi dari kamu agar pengembangan CherryPick tetap dapat berlanjut!"
roles: "Peran"
role: "Peran"
noRole: "Peran tidak temukan"
normalUser: "Pengguna umum"
undefined: "Tak terdefinisi"
assign: "Tetapkan\n"
@ -951,28 +982,146 @@ manageCustomEmojis: "Kelola Emoji Kustom"
youCannotCreateAnymore: "Kamu melewati batas pembuatan."
cannotPerformTemporary: "Sementara Tidak Tersedia"
cannotPerformTemporaryDescription: "Aksi ini tidak dapat dilakukan sementara karena melewati batas eksekusi. Mohon tunggu sejenak dan coba lagi."
invalidParamError: "Parameter tidak valid"
invalidParamErrorDescription: "Parameter permintaan tidak valid. Hal ini biasanya disebabkan oleh bug, namun juga dapat terjadi karena input melebihi batas ukuran atau semacamnya."
permissionDeniedError: "Operasi ditolak"
permissionDeniedErrorDescription: "Akun ini tidak memiliki izin untuk melakukan aksi ini."
preset: "Prasetel"
selectFromPresets: "Pilih dari prasetel"
achievements: "Pencapaian"
gotInvalidResponseError: "Respon peladen tidak valid"
gotInvalidResponseErrorDescription: "Peladen tidak dapat dijangkau atau sedang dalam perawatan. Mohon coba lagi nanti."
thisPostMayBeAnnoying: "Catatan ini mungkin dapat mengganggu orang lain."
thisPostMayBeAnnoyingHome: "Catat ke linimasa beranda"
thisPostMayBeAnnoyingHome: "Catat ke lini masa beranda"
thisPostMayBeAnnoyingCancel: "Batalkan"
thisPostMayBeAnnoyingIgnore: "Tetap catat"
collapseRenotes: "Tutup renote yang sudah kamu lihat"
internalServerError: "Kesalahan internal peladen"
internalServerErrorDescription: "Peladen sedang mengalami galat tak terduga"
copyErrorInfo: "Salin detil galat"
joinThisServer: "Gabung server ini"
exploreOtherServers: "Cari server lain"
joinThisServer: "Gabung peladen ini"
exploreOtherServers: "Cari peladen lain"
letsLookAtTimeline: "LIhat timeline"
disableFederationConfirm: "Matikan federasi?"
disableFederationConfirmWarn: "Mematikan federasi tidak membuat kiriman menjadi privat. Umumnya, mematikan federasi tidak diperlukan."
disableFederationOk: "Matikan federasi"
invitationRequiredToRegister: "Instansi ini dalam mode undangan-saja. Kamu harus memasukkan kode undangan yang valid untuk mendaftar."
emailNotSupported: "Instansi ini tidak mendukung mengirim surel"
postToTheChannel: "Catat ke kanal"
cannotBeChangedLater: "Hal ini nantinya tidak dapat diubah lagi."
reactionAcceptance: "Penerimaan reaksi"
likeOnly: "Hanya suka"
likeOnlyForRemote: "Semua (Hanya suka dari instansi luar)"
nonSensitiveOnly: "Hanya non-sensitif"
nonSensitiveOnlyForLocalLikeOnlyForRemote: "Hanya non-sensitif (Hanya suka dari instansi luar)"
rolesAssignedToMe: "Peran yang ditugaskan ke saya"
resetPasswordConfirm: "Yakin untuk mereset kata sandimu?"
sensitiveWords: "Kata sensitif"
sensitiveWordsDescription: "Visibilitas dari semua catatan mengandung kata yang telah diatur akan dijadikan \"Beranda\" secara otomatis. Kamu dapat mendaftarkan kata tersebut lebih dari satu dengan menuliskannya di baris baru."
sensitiveWordsDescription2: "Menggunakan spasi akan membuat ekspresi AND dan kata kunci disekitarnya dengan garis miring akan mengubahnya menjadi ekspresi reguler."
notesSearchNotAvailable: "Pencarian catatan tidak tersedia."
license: "Lisensi"
unfavoriteConfirm: "Yakin ingin menghapusnya dari favorit?"
myClips: "Klip saya"
drivecleaner: "Pembersih Drive"
retryAllQueuesNow: "Coba jalankan lagi semua antrian"
retryAllQueuesConfirmTitle: "Yakin ingin mencoba lagi semuanya?"
retryAllQueuesConfirmText: "Hal ini akan meningkatkan beban sementara ke peladen."
enableChartsForRemoteUser: "Buat bagan data pengguna instansi luar"
enableChartsForFederatedInstances: "Buat bagan data peladen instansi luar"
showClipButtonInNoteFooter: "Tambahkan \"Klip\" ke menu aksi catatan"
largeNoteReactions: "Besarkan reaksi yang ditampilkan"
noteIdOrUrl: "ID catatan atau URL"
video: "Video"
videos: "Video"
dataSaver: "Penghemat data"
accountMigration: "Pemindahan akun"
accountMoved: "Pengguna ini telah berpindah ke akun baru:"
accountMovedShort: "Akun ini telah dipindahkan."
operationForbidden: "Operasi dilarang"
forceShowAds: "Selalu tampilkan iklan"
addMemo: "Tambahkan memo"
editMemo: "Sunting memo"
reactionsList: "Reaksi"
renotesList: "Renote"
notificationDisplay: "Notifikasi"
leftTop: "Kiri atas"
rightTop: "Kanan atas"
leftBottom: "Kiri bawah"
rightBottom: "Kanan bawah"
stackAxis: "Arah tumpukan"
vertical: "Vertikal"
horizontal: "Horisontal"
position: "Posisi"
serverRules: "Aturan peladen"
pleaseConfirmBelowBeforeSignup: "Mohon konfirmasi di bawah ini sebelum mendaftar."
pleaseAgreeAllToContinue: "Kamu harus menyetujui semua kolom di atas untuk melanjutkan."
continue: "Lanjutkan"
preservedUsernames: "Nama pengguna tercadangkan"
preservedUsernamesDescription: "Daftar nama pengguna yang dicadangkan dipisah dengan baris baru. Nama pengguna berikut akan tidak dapat dipakai pada pembuatan akun normal, namun dapat digunakan oleh admin untuk membuat akun baru. Akun yang sudah ada dengan menggunakan nama pengguna ini tidak akan terpengaruh."
createNoteFromTheFile: "Buat catatan dari berkas ini"
archive: "Arsipkan"
channelArchiveConfirmTitle: "Yakin untuk mengarsipkan {name}?"
channelArchiveConfirmDescription: "Kanal yang diarsipkan tidak akan muncul pada daftar kanal atau hasil pencarian. Postingan baru juga tidak dapat ditambahkan lagi."
thisChannelArchived: "Kanal ini telah diarsipkan."
displayOfNote: "Tampilan catatan"
initialAccountSetting: "Atur profil"
youFollowing: "Mengikuti"
preventAiLearning: "Tolak penggunaan Pembelajaran Mesin (AI Generatif)"
preventAiLearningDescription: "Minta perayap web untuk tidak menggunakan materi teks atau gambar yang telah diposting ke dalam set data Pembelajaran Mesin (Prediktif / Generatif). Hal ini dicapai dengan menambahkan flag HTML-Response \"noai\" ke masing-masing konten. Pencegahan penuh mungkin tidak dapat dicapai dengan flag ini, karena juga dapat diabaikan begitu saja."
options: "Opsi peran"
specifyUser: "Pengguna spesifik"
failedToPreviewUrl: "Tidak dapat dipratinjau"
update: "Perbarui"
rolesThatCanBeUsedThisEmojiAsReaction: "Peran yang dapat menggunakan emoji ini sebagai reaksi"
rolesThatCanBeUsedThisEmojiAsReactionEmptyDescription: "Jika peran tidak ditentukan, semua pengguna dapat menggunakan emoji ini sebagai reaksi."
rolesThatCanBeUsedThisEmojiAsReactionPublicRoleWarn: "Peran ini harus publik."
cancelReactionConfirm: "Yakin untuk menghapus reaksimu?"
changeReactionConfirm: "Yakin untuk mengganti reaksimu?"
later: "Nanti saja"
goToMisskey: "Ke CherryPick"
additionalEmojiDictionary: "Kamus emoji tambahan"
installed: "Terpasang"
branding: "Merek"
enableServerMachineStats: "Tampilkan informasi mesin peladen menjadi publik"
enableIdenticonGeneration: "Nyalakan pembuatan Identicon per pengguna"
turnOffToImprovePerformance: "Matikan untuk tingkatkan performa."
createInviteCode: "Buat kode undangan"
inviteCodeCreated: "Kode undangan dibuat"
inviteLimitExceeded: "Kamu telah mencapai jumlah maksimum kode undangan yang dapat dibuat."
expirationDate: "Tanggal kedaluwarsa"
_initialAccountSetting:
accountCreated: "Akun kamu telah sukses dibuat!"
letsStartAccountSetup: "Untuk pemula, ayo atur profilmu dulu."
letsFillYourProfile: "Pertama, ayo atur profilmu dulu."
profileSetting: "Pengaturan profil"
privacySetting: "Pengaturan privasi"
theseSettingsCanEditLater: "Kamu selalu bisa mengganti pengaturan ini lain kali."
youCanEditMoreSettingsInSettingsPageLater: "Ada banyak pengaturan yang dapat kamu atur dari halaman \"Pengaturan\". Pastikan untuk mengunjungi halaman tersebut nanti."
followUsers: "Coba ikuti beberapa pengguna yang menarik bagimu untuk membangun lini masa akunmu."
pushNotificationDescription: "Menyalakan notifikasi dorong akan membuatmu menerima notifikasi dari {name} secara langsung ke perangkatmu."
initialAccountSettingCompleted: "Pengaturan profil selesai!"
haveFun: "Selamat menikmati, {name}!"
ifYouNeedLearnMore: "Kalau kamu ingin mempelajari lebih lanjut bagaimana cara menggunakan {name} (CherryPick), silahkan kunjungi {link}."
skipAreYouSure: "Yakin melewati atur profil?"
laterAreYouSure: "Yakin banget untuk atur profil nanti?"
_serverRules:
description: "Daftar peraturan akan ditampilkan sebelum pendaftaran. Mengatur ringkasan dari Syarat dan Ketentuan sangat direkomendasikan."
_accountMigration:
moveFrom: "Pindahkan akun lain ke akun ini"
moveFromSub: "Buat alias ke akun lain"
moveFromLabel: "Akun asli #{n}"
moveFromDescription: "Kamu harus membuat alias untuk akun asal kamu berpindah ke akun ini\nMasukkan alias akun asal kamu berpindah ke dalam format berikut: @namapengguna@nama.server.com\nUntuk menghapus alias, kosongkan kolom ini (tidak direkomendasikan)."
moveTo: "Pindahkan akun ini ke akun lain"
moveToLabel: "Akun tujuan pindah:"
moveCannotBeUndone: "Pemindahan akun tidak dapat diurungkan."
moveAccountDescription: "Hal ini akan memindahkan akun kamu ke akun lain.\n ・Pengikut dari akun ini akan secara otomatis dipindahkan ke akun baru\n ・Akun ini akan berhenti mengikuti dari semua pengguna yang sedang kamu ikuti\n ・Kamu akan tidak dapat membuat catatan baru dan lain-lain pada akun ini\n\nMeskipun pemindahan pengikut dilakukan secara otomatis, kamu harus mempersiapkan beberapa langkah secara manual untuk memindahkan daftar pengguna yang sedang kamu ikuti. Untuk melakukan tersebut, lakukan ekspor daftar ikuti yang nantinya dapat kamu impor pada menu pengaturan di akun baru kamu. Prosedur yang sama juga dapat diterapkan pada daftar seperti pengguna yang kamu bisukan atau blokir.\n\n(Penjelasan ini hanya berlaku pada CherryPick versi 13.12.0 dan setelahnya. Perangkat lunak ActivityPub lainnya seperti Mastodon berkemungkinan befungsi berbeda.)"
moveAccountHowTo: "Untuk pindah, pertama buat alias untuk akun ini pada akun tujuan kamu berpindah.\nSetelah kamu membuat alias, masukkan akun tujuan kamu berpindah ke dalam format berikut:\n@namapengguna@nama.server.com"
startMigration: "Pindahkan"
migrationConfirm: "Yakin untuk memindahkan akun ini ke {account}? Sekali dimulai, proses ini tidak dapat dihentikan atau ditarik kembali, dan kamu tidak dapat menggunakan akun ini lagi dalam keadaan asli semula."
movedAndCannotBeUndone: "\nAkun ini telah dipindahkan.\nPemindahan tidak dapat diurungkan."
postMigrationNote: "24 jam setelah pemindahan akun selesai, akun ini akan berhenti mengikuti semua akun yang sedang diikuti. Angka mengikut dan pengikut akan menjadi nol. Untuk menghindari pengikut kamu tidak dapat melihat postingan hanya pengikut saja dalam postingan ini, mereka akan tetap mengikuti akun ini."
movedTo: "Akun baru tujuan pindah:"
_achievements:
earnedAt: "Terbuka pada"
_types:
@ -1144,6 +1293,9 @@ _achievements:
_client30min:
title: "Istirahat pendek"
description: "Habiskan waktu 30 menit di CherryPick"
_client60min:
title: "Tidak ada \"Miss\" dalam CherryPick"
description: "Biarkan CherryPick tetap terbuka setidaknya selama 60 menit"
_noteDeletedWithin1min:
title: "Eh, salah coy!"
description: "Hapus catatan kurang dari semenit kamu catat"
@ -1159,8 +1311,8 @@ _achievements:
title: "Rujukan mandiri"
description: "Kutip catatanmu sendiri"
_htl20npm:
title: "Linimasa mengalir"
description: "Memiliki linimasa beranda dengan kecepatan melebihi 20 cpm (catatan per menit)"
title: "Lini masa mengalir"
description: "Memiliki lini masa beranda dengan kecepatan melebihi 20 cpm (catatan per menit)"
_viewInstanceChart:
title: "Analis"
description: "Lihat bagan instansimu"
@ -1232,6 +1384,10 @@ _role:
iconUrl: "URL ikon"
asBadge: "Tampilkan sebagai lencana"
descriptionOfAsBadge: "Ikon peran ini akan ditampilkan bersebelahan dengan username pengguna yang memiliki peran ini jika dinyalakan."
isExplorable: "Buat peran dapat terjelajahi"
descriptionOfIsExplorable: "Lini masa peran ini dan daftar pengguna dengan peran ini akan dibuat publik apabila dinyalakan."
displayOrder: "Urutan"
descriptionOfDisplayOrder: "Semakin tinggi angka, semakin tinggi posisi antarmukanya."
canEditMembersByModerator: "Perbolehkan moderator untuk menyunting daftar anggota untuk peran ini"
descriptionOfCanEditMembersByModerator: "Ketika dinyalakan, moderator beserta administrator dapat menugaskan ataupun mencabut pengguna ke peran ini. Ketika dimatikan, hanya administrator saja yang dapat menugaskan pengguna ke peran ini."
priority: "Prioritas"
@ -1240,12 +1396,13 @@ _role:
middle: "Sedang"
high: "Tinggi"
_options:
gtlAvailable: "Dapat melihat linimasa global"
ltlAvailable: "Dapat melihat linimasa lokal"
gtlAvailable: "Dapat melihat lini masa global"
ltlAvailable: "Dapat melihat lini masa lokal"
canPublicNote: "Dapat mengirim catatan publik"
canInvite: "Dapat membuat kode undangan instansi"
canManageCustomEmojis: "Dapat mengelola Emoji kustom"
driveCapacity: "Kapasitas Drive"
alwaysMarkNsfw: "Selalu tandai berkas sebagai NSFW"
pinMax: "Jumlah maksimal catatan yang disematkan"
antennaMax: "Jumlah maksimum antena"
wordMuteMax: "Jumlah maksimum karakter yang diperbolehkan dalam membisukan kata"
@ -1257,6 +1414,7 @@ _role:
rateLimitFactor: "Batas kecepatan"
descriptionOfRateLimitFactor: "Batas kecepatan yang rendah tidak begitu membatasi, batas kecepatan tinggi lebih membatasi. "
canHideAds: "Dapat menyembunyikan iklan"
canSearchNotes: "Penggunaan pencarian catatan"
_condition:
isLocal: "Pengguna lokal"
isRemote: "Pengguna remote"
@ -1266,11 +1424,13 @@ _role:
followersMoreThanOrEq: "Memiliki pengikut X atau lebih dari tersebut"
followingLessThanOrEq: "Mengikuti X pengguna atau kurang dari itu"
followingMoreThanOrEq: "Mengikuti X pengguna atau lebih dari itu"
notesLessThanOrEq: "Jumlah postingan kurang dari sama dengan"
notesMoreThanOrEq: "Jumlah postingan lebih dari sama dengan"
and: "Kondisi-AND"
or: "Kondisi-OR"
not: "Kondisi-NOT"
_sensitiveMediaDetection:
description: "Mengurangi usaha moderasi server dengan mengenali media NSFW srcara otomatis menggunakan Machine Learning. Fungsi ini akan sedikit menaikkan beban peladen."
description: "Mengurangi usaha moderasi peladen dengan mengenali media NSFW secara otomatis menggunakan Pembelajaran Mesin. Fungsi ini akan sedikit menaikkan beban peladen."
sensitivity: "Sensitivitas deteksi"
sensitivityDescription: "Mengurangi sensitivitas akan mengurangi misdeteksi (false positive) sedangkan meningkatkannya akan menambah misdeteksi (false positive)."
setSensitiveFlagAutomatically: "Tandai sebagai NSFW"
@ -1353,10 +1513,6 @@ _aboutMisskey:
donate: "Donasi ke Misskey"
morePatrons: "Kami sangat mengapresiasi dukungan dari banyak penolong lain yang tidak tercantum disini. Terima kasih! 🥰"
patrons: "Pendukung"
_nsfw:
respect: "Sembunyikan media NSFW"
ignore: "Jangan sembunyikan media NSFW"
force: "Sembunyikan semua media"
_mfm:
cheatSheet: "Contekan MFM"
intro: "MFM adalah Misskey-exclusive Markup Language yang dapat digunakan di banyak tempat. Berikut kamu bisa melihat daftar dari syntax MFM yang ada."
@ -1423,15 +1579,15 @@ _mfm:
rotateDescription: "Putar konten sesuai sudut yang ditentukan."
_instanceTicker:
none: "Jangan tampilkan"
remote: "Tampilkan untuk pengguna luar"
remote: "Tampilkan untuk pengguna instansi luar"
always: "Selalu tampilkan"
_serverDisconnectedBehavior:
reload: "Muat ulang otomatis"
dialog: "Tampilkan dialog peringatan"
quiet: "Tampilkan peringatan tidak mengganggu"
_channel:
create: "Buat saluran"
edit: "Sunting saluran"
create: "Buat Kanal"
edit: "Sunting Kanal"
setBanner: "Setel banner"
removeBanner: "Hapus banner"
featured: "Tren"
@ -1439,6 +1595,8 @@ _channel:
following: "Mengikuti"
usersCount: "{n} Partisipan"
notesCount: "terdapat {n} catatan"
nameAndDescription: "Nama dan deskripsi"
nameOnly: "Hanya nama"
_menuDisplay:
sideFull: "Horisontal"
sideIcon: "Horisontal (Ikon)"
@ -1447,9 +1605,9 @@ _menuDisplay:
_wordMute:
muteWords: "Kata yang dibisukan"
muteWordsDescription: "Pisahkan dengan spasi untuk kondisi AND. Pisahkan dengan baris baru untuk kondisi OR."
muteWordsDescription2: "Kurung kata kunci dengan garis miring untuk menggunakan regular expressions."
softDescription: "Sembunyikan catatan yang memenuhi aturan kondisi dari linimasa."
hardDescription: "Cegah catatan memenuhi aturan kondisi dari ditambahkan ke linimasa. Dengan tambahan, catatan berikut tidak akan ditambahkan ke linimasa meskipun jika kondisi tersebut diubah."
muteWordsDescription2: "Kurung kata kunci dengan garis miring untuk menggunakan ekspresi reguler."
softDescription: "Sembunyikan catatan yang memenuhi aturan kondisi dari lini masa."
hardDescription: "Cegah catatan memenuhi aturan kondisi dari ditambahkan ke lini masa. Dengan tambahan, catatan berikut tidak akan ditambahkan ke lini masa meskipun jika kondisi tersebut diubah."
soft: "Lembut"
hard: "Keras"
mutedNotes: "Catatan yang dibisukan"
@ -1519,8 +1677,8 @@ _theme:
cwBg: "Latar belakang tombol Sembunyikan Konten"
cwFg: "Teks tombol Sembunyikan Konten"
cwHoverBg: "Latar belakang tombol Sembunyikan Konten (Mengambang)"
toastBg: "Latar belakang pemberitahuan"
toastFg: "Teks pemberitahuan"
toastBg: "Latar belakang notifikasi"
toastFg: "Teks notifikasi"
buttonBg: "Latar belakang tombol"
buttonHoverBg: "Latar belakang tombol (Mengambang)"
inputBorder: "Batas bidang masukan"
@ -1535,11 +1693,11 @@ _theme:
_sfx:
note: "Catatan"
noteMy: "Catatan (Saya)"
notification: "Pemberitahuan"
notification: "Notifikasi"
chat: "Pesan"
chatBg: "Obrolan (Latar Belakang)"
antenna: "Penerimaan Antenna"
channel: "Pemberitahuan saluran"
channel: "Notifikasi Kanal"
_ago:
future: "Masa depan"
justNow: "Baru saja"
@ -1556,15 +1714,40 @@ _time:
minute: "menit"
hour: "jam"
day: "hari"
_timelineTutorial:
title: "Bagaimana cara menggunakan CherryPick"
step1_1: "Ini adalah \"lini masa\". Semua \"catatan\" yang dikirimkan oleh {name} akan dimunculkan secara kronologis di sini."
step1_2: "Ada beberapa lini masa yang berbeda. Seperti contoh, \"Lini masa Beranda\" berisi catatan dari pengguna yang kamu ikuti, dan \"Lini masa lokal\" berisi catatan dari semua pengguna dari {name}."
step2_1: "Selanjutnya, mari kita coba memposting sebuah catatan. Kamu dapat melakukanya dengan menekan tombol dengan ikon pensil."
step2_2: "Bagaimana dengan menuliskan sedikit perkenalan diri, atau hanya \"Hello {name}\" kalau kamu lagi ngga feeling?"
step3_1: "Udah selesai memposting catatan pertamamu?"
step3_2: "Catatan pertamamu seharusnya sekarang sudah tampil di lini masa kamu."
step4_1: "Kamu dapat menyisipkan \"Reaksi\" ke dalam catatan."
step4_2: "Untuk menyisipkan reaksi, tekan tanda \"+\" dalam catatan dan pilih emoji yang kamu suka untuk mereaksi catatan tersebut."
_2fa:
alreadyRegistered: "Kamu telah mendaftarkan perangkat otentikasi dua faktor."
registerTOTP: "Daftarkan aplikasi autentikator"
passwordToTOTP: "Masukkan kata sandimu"
step1: "Pertama, pasang aplikasi otentikasi (seperti {a} atau {b}) di perangkat kamu."
step2: "Lalu, pindai kode QR yang ada di layar."
step2Click: "Mengeklik kode QR ini akan membolehkanmu untuk mendaftarkan 2FA ke security-key atau aplikasi autentikator ponsel."
step2Url: "Di aplikasi desktop, masukkan URL berikut:"
step3Title: "Masukkan kode autentikasi"
step3: "Masukkan token yang telah disediakan oleh aplikasimu untuk menyelesaikan pemasangan."
step4: "Mulai sekarang, upaya login apapun akan meminta token login dari aplikasi otentikasi kamu."
securityKeyNotSupported: "Peramban kamu tidak mendukung security key."
registerTOTPBeforeKey: "Mohon atur aplikasi autentikator untuk mendaftarkan security key atau passkey."
securityKeyInfo: "Kamu dapat memasang otentikasi WebAuthN untuk mengamankan proses login lebih lanjut dengan tidak hanya perangkat keras kunci keamanan yang mendukung FIDO2, namun juga sidik jari atau otentikasi PIN pada perangkatmu."
chromePasskeyNotSupported: "Passkey Chrome saat ini tidak didukung."
registerSecurityKey: "Daftarkan security key atau passkey."
securityKeyName: "Masukkan nama key."
tapSecurityKey: "Mohon ikuti peramban kamu untuk mendaftarkan security key atau passkey"
removeKey: "Hapus security key"
removeKeyConfirm: "Hapus cadangan {name}?"
whyTOTPOnlyRenew: "Aplikasi autentikator tidak dapat dihapus selama security key masih terdaftar."
renewTOTP: "Atur ulang aplikasi autentikator"
renewTOTPConfirm: "Hal ini akan menyebabkan kode verifikasi dari aplikasi autentikator sebelumnya berhenti bekerja"
renewTOTPOk: "Atur ulang"
renewTOTPCancel: "Tidak sekarang."
_permissions:
"read:account": "Lihat informasi akun"
@ -1582,8 +1765,8 @@ _permissions:
"read:mutes": "Lihat daftar orang yang dibisukan"
"write:mutes": "Sunting daftar orang yang dibisukan"
"write:notes": "Buat atau hapus catatan"
"read:notifications": "Lihat pemberitahuan"
"write:notifications": "Sunting pemberitahuan"
"read:notifications": "Lihat notifikasi"
"write:notifications": "Sunting notifikasi"
"read:reactions": "Lihat reaksi"
"write:reactions": "Sunting reaksi"
"write:votes": "Beri suara"
@ -1593,8 +1776,8 @@ _permissions:
"write:page-likes": "Sunting suka pada Halaman"
"read:user-groups": "Lihat grup pengguna"
"write:user-groups": "Sunting atau hapus grup pengguna"
"read:channels": "Lihat saluran"
"write:channels": "Sunting saluran"
"read:channels": "Lihat Kanal"
"write:channels": "Sunting Kanal"
"read:gallery": "Lihat galeri"
"write:gallery": "Sunting galeri"
"read:gallery-likes": "Lihat daftar postingan galeri yang disukai"
@ -1627,8 +1810,8 @@ _widgets:
profile: "Profil"
instanceInfo: "Informasi Instansi"
memo: "Catatan memo"
notifications: "Pemberitahuan"
timeline: "Linimasa"
notifications: "Notifikasi"
timeline: "Lini masa"
calendar: "Kalender"
trends: "Tren"
clock: "Jam"
@ -1682,13 +1865,15 @@ _poll:
remainingSeconds: "Berakhir dalam {s} detik"
_visibility:
public: "Publik"
publicDescription: "Catat ke linimasa global"
publicDescription: "Catat ke lini masa global"
home: "Beranda"
homeDescription: "Catat ke linimasa beranda saja"
homeDescription: "Catat ke lini masa beranda saja"
followers: "Pengikut"
followersDescription: "Catat ke pengikut saja"
specified: "Langsung"
specifiedDescription: "Catat ke pengguna yang ditentukan saja"
disableFederation: "Matikan federasi"
disableFederationDescription: "Jangan kirimkan ke instansi lain"
_postForm:
replyPlaceholder: "Balas ke catatan ini..."
quotePlaceholder: "Kutip catatan ini..."
@ -1729,7 +1914,7 @@ _charts:
activeUsers: "Pengguna aktif"
notesIncDec: "Perbedaan # dalam catatan"
localNotesIncDec: "Perbedaan # dalam catatan lokal"
remoteNotesIncDec: "Perbedaan # dalam catatan luar"
remoteNotesIncDec: "Perbedaan # dalam catatan instansi luar"
notesTotal: "Total # catatan"
filesIncDec: "Perbedaan # dalam berkas"
filesTotal: "Jumlah # berkas"
@ -1848,8 +2033,9 @@ _notification:
pollEnded: "Jajak pendapat berakhir"
receiveFollowRequest: "Permintaan mengikuti diterima"
followRequestAccepted: "Permintaan mengikuti disetujui"
achievementEarned: "Pencapaian didapatkan"
groupInvited: "Diundang ke grup"
app: "Pemberitahuan dari aplikasi"
app: "Notifikasi dari aplikasi tertaut"
_actions:
followBack: "Ikuti Kembali"
reply: "Balas"
@ -1874,13 +2060,34 @@ _deck:
_columns:
main: "Utama"
widgets: "Widget"
notifications: "Pemberitahuan"
tl: "Linimasa"
notifications: "Notifikasi"
tl: "Lini masa"
antenna: "Antena"
list: "Daftar"
channel: "Kanal"
mentions: "Sebutan"
direct: "Langsung"
roleTimeline: "Lini masa peran"
_dialog:
charactersExceeded: "Kamu telah melebihi batas karakter maksimum! Saat ini pada {current} dari {max}."
charactersBelow: "Kamu berada di bawah batas minimum karakter! Saat ini pada {current} dari {min}."
_disabledTimeline:
title: "Lini masa dinonaktifkan"
description: "Saat ini kamu tidak dapat menggunakan lini masa ini karena peran kamu saat ini."
_drivecleaner:
orderBySizeDesc: "Ukuran berkas (Turun)"
orderByCreatedAtAsc: "Tanggal (Naik)"
_webhookSettings:
createWebhook: "Buat Webhook"
name: "Nama"
secret: "Secret"
events: "Webhook Events"
active: "Aktif"
_events:
follow: "Ketika mengikuti pengguna"
followed: "Ketika diikuti pengguna"
note: "Ketika memposting catatan"
reply: "Ketika menerima balasan"
renote: "Ketika direnote"
reaction: "Ketika menerima reaksi"
mention: "Ketika sedang disebut"

63
locales/index.d.ts vendored
View file

@ -3,6 +3,17 @@
// Do not edit this file directly.
export interface Locale {
"_lang_": string;
"addSingle": string;
"addMultiple": string;
"showRenoteConfirmPopup": string;
"showSubNoteFooterButton": string;
"showSubNoteFooterButtonDescription": string;
"alreadyFollowed": string;
"enableMarkByDate": string;
"renoteConfirm": string;
"inviteRevoke": string;
"inviteRevokeConfirm": string;
"enableAbsoluteTime": string;
"posted": string;
"translateNote": string;
"showTranslateButtonInNote": string;
@ -12,7 +23,8 @@ export interface Locale {
"requireRefresh": string;
"performanceWarning": string;
"photosensitiveSeizuresWarning": string;
"friendlyEnableNotification": string;
"friendlyEnableNotifications": string;
"friendlyEnableWidgets": string;
"useBoldFont": string;
"newNoteReceivedNotification": string;
"disableRightClick": string;
@ -76,11 +88,15 @@ export interface Locale {
"copyAndEdit": string;
"copyAndEditConfirm": string;
"addToList": string;
"addToAntenna": string;
"sendMessage": string;
"copyRSS": string;
"copyUsername": string;
"copyUserId": string;
"copyNoteId": string;
"copyFileId": string;
"copyFolderId": string;
"copyProfileUrl": string;
"searchUser": string;
"reply": string;
"loadMore": string;
@ -163,8 +179,10 @@ export interface Locale {
"suspendConfirm": string;
"unsuspendConfirm": string;
"selectList": string;
"editList": string;
"selectChannel": string;
"selectAntenna": string;
"editAntenna": string;
"selectWidget": string;
"editWidgets": string;
"editWidgetsExit": string;
@ -177,6 +195,8 @@ export interface Locale {
"settingGuide": string;
"cacheRemoteFiles": string;
"cacheRemoteFilesDescription": string;
"cacheRemoteSensitiveFiles": string;
"cacheRemoteSensitiveFilesDescription": string;
"flagAsBot": string;
"flagAsBotDescription": string;
"flagAsCat": string;
@ -338,7 +358,7 @@ export interface Locale {
"rename": string;
"avatar": string;
"banner": string;
"nsfw": string;
"displayOfSensitiveMedia": string;
"whenServerDisconnected": string;
"disconnectedFromServer": string;
"reload": string;
@ -1113,13 +1133,33 @@ export interface Locale {
"additionalEmojiDictionary": string;
"installed": string;
"branding": string;
"enableServerMachineStats": string;
"enableIdenticonGeneration": 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;
"additionalPermissionsForFlash": string;
"thisFlashRequiresTheFollowingPermissions": string;
"doYouWantToAllowThisPlayToAccessYourAccount": string;
"translateProfile": string;
"enableAbsoluteTime": string;
"inviteRevoke": string;
"inviteRevokeConfirm": string;
"_group": {
"leader": string;
"banish": string;
@ -1137,6 +1177,7 @@ export interface Locale {
"rememberPostFormToggleState": string;
"reactableRemoteReaction": string;
"showFollowingMessageInsteadOfButton": string;
"mobileTimelineHeaderChange": string;
};
"_bannerDisplay": {
"all": string;
@ -1570,8 +1611,13 @@ export interface Locale {
"_options": {
"gtlAvailable": string;
"ltlAvailable": string;
"mtlAvailable": string;
"ctlAvailable": string;
"canPublicNote": string;
"canInvite": string;
"inviteLimit": string;
"inviteLimitCycle": string;
"inviteExpirationTime": string;
"canManageCustomEmojis": string;
"driveCapacity": string;
"alwaysMarkNsfw": string;
@ -1647,6 +1693,7 @@ export interface Locale {
"back": string;
"reduceFrequencyOfThisAd": string;
"hide": string;
"timezoneinfo": string;
};
"_forgotPassword": {
"enterEmail": string;
@ -1719,7 +1766,7 @@ export interface Locale {
"community": string;
};
};
"_nsfw": {
"_displayOfSensitiveMedia": {
"respect": string;
"ignore": string;
"force": string;
@ -2190,6 +2237,7 @@ export interface Locale {
"local": string;
"media": string;
"social": string;
"cat": string;
"global": string;
};
"_play": {
@ -2319,6 +2367,7 @@ export interface Locale {
"introduction": string;
"introduction2": string;
"widgetsIntroduction": string;
"useSimpleUiForNonRootPages": string;
"_columns": {
"main": string;
"widgets": string;
@ -2364,4 +2413,4 @@ export interface Locale {
declare const locales: {
[lang: string]: Locale;
};
export = locales;
export default locales;

View file

@ -2,8 +2,8 @@
* Languages Loader
*/
const fs = require('fs');
const yaml = require('js-yaml');
import * as fs from 'node:fs';
import * as yaml from 'js-yaml';
const merge = (...args) => args.reduce((a, c) => ({
...a,
@ -52,9 +52,9 @@ const primaries = {
// 何故か文字列にバックスペース文字が混入することがあり、YAMLが壊れるので取り除く
const clean = (text) => text.replace(new RegExp(String.fromCodePoint(0x08), 'g'), '');
const locales = languages.reduce((a, c) => (a[c] = yaml.load(clean(fs.readFileSync(`${__dirname}/${c}.yml`, 'utf-8'))) || {}, a), {});
const locales = languages.reduce((a, c) => (a[c] = yaml.load(clean(fs.readFileSync(new URL(`${c}.yml`, import.meta.url), 'utf-8'))) || {}, a), {});
module.exports = Object.entries(locales)
export default Object.entries(locales)
.reduce((a, [k ,v]) => (a[k] = (() => {
const [lang] = k.split('-');
switch (k) {

View file

@ -26,15 +26,15 @@ otherSettings: "Altre impostazioni"
openInWindow: "Apri in una finestra"
profile: "Profilo"
timeline: "Timeline"
noAccountDescription: "L'utente non ha ancora scritto niente nella biografia di profilo."
noAccountDescription: "La persona non ha ancora scritto alcuna autobiografia."
login: "Accedi"
loggingIn: "Accesso in corso..."
logout: "Uscita"
signup: "Iscriviti"
uploading: "Caricamento..."
save: "Salva"
users: "Utente"
addUser: "Aggiungi utente"
users: "Profili"
addUser: "Aggiungi profilo"
favorite: "Preferiti"
favorites: "Preferiti"
unfavorite: "Rimuovi nota dai preferiti"
@ -49,10 +49,16 @@ delete: "Elimina"
deleteAndEdit: "Elimina e modifica"
deleteAndEditConfirm: "Vuoi davvero cancellare questa nota e scriverla di nuovo? Verranno eliminate anche tutte le reazioni, rinote e risposte collegate."
addToList: "Aggiungi alla lista"
addToAntenna: "Aggiungi all'antenna"
sendMessage: "Invia messaggio"
copyRSS: "Copia RSS"
copyUsername: "Copia nome utente"
searchUser: "Cerca utente"
copyUserId: "Copia ID del profilo"
copyNoteId: "Copia ID della Nota"
copyFileId: "Copia ID del file"
copyFolderId: "Copia ID della cartella"
copyProfileUrl: "Copia URL del profilo"
searchUser: "Cerca profilo"
reply: "Rispondi"
loadMore: "Mostra di più"
showMore: "Espandi"
@ -134,8 +140,10 @@ unblockConfirm: "Vuoi davvero sbloccare il profilo?"
suspendConfirm: "Vuoi sospendere questo profilo?"
unsuspendConfirm: "Vuoi revocare la sospensione si questo profilo?"
selectList: "Seleziona una lista"
editList: "Modifica Lista"
selectChannel: "Seleziona canale"
selectAntenna: "Scegli un'antenna"
editAntenna: "Modifica Antenna"
selectWidget: "Seleziona il riquadro"
editWidgets: "Modifica i riquadri"
editWidgetsExit: "Conferma le modifiche"
@ -148,12 +156,14 @@ addEmoji: "Aggiungi un emoji"
settingGuide: "Configurazione suggerita"
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."
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"
flagAsBotDescription: "Attiva questo campo se il profilo esegue principalmente operazioni automatiche. L'attivazione segnala agli altri sviluppatori come comportarsi per evitare catene dinterazione infinite con altri bot. I sistemi interni di CherryPick si adegueranno al fine di trattare questo profilo come bot."
flagAsCat: "Sono un gatto"
flagAsCatDescription: "La modalità \"sono un gatto\" aggiunge le orecchie al tuo profilo"
flagShowTimelineReplies: "Mostra le risposte alle note sulla timeline."
flagShowTimelineRepliesDescription: "Se è attiva, la timeline mostra le risposte alle altre note dell'utente oltre a quelle dell'utente stesso."
flagShowTimelineRepliesDescription: "Attivando, la timeline mostra le Note del profilo ed anche le risposte ad altre Note"
autoAcceptFollowed: "Accetta automaticamente le richieste di follow da utenti che già segui"
addAccount: "Aggiungi profilo"
reloadAccountsList: "Ricarica l'elenco dei profili"
@ -205,7 +215,7 @@ blockedInstancesDescription: "Elenca le istanze che vuoi bloccare, una per riga.
muteAndBlock: "Silenziati / Bloccati"
mutedUsers: "Profili silenziati"
blockedUsers: "Profili bloccati"
noUsers: "Nessun utente trovato"
noUsers: "Non ci sono profili"
editProfile: "Modifica profilo"
noteDeleteConfirm: "Vuoi davvero eliminare questa Nota?"
pinLimitExceeded: "Non puoi fissare altre note "
@ -236,8 +246,8 @@ newPasswordRetype: "Conferma password"
attachFile: "Allega file"
more: "Di più!"
featured: "Tendenze"
usernameOrUserId: "Nome utente o ID utente"
noSuchUser: "Nessun utente trovato"
usernameOrUserId: "Nome utente o ID"
noSuchUser: "Profilo non trovato"
lookup: "Ricerca remota"
announcements: "Annunci"
imageUrl: "URL dell'immagine"
@ -269,7 +279,7 @@ basicNotesBeforeCreateAccount: "Note importanti"
termsOfService: "Informativa Privacy"
start: "Inizia!"
home: "Home"
remoteUserCaution: "Può darsi che le informazioni siano incomplete perché questo è un utente remoto."
remoteUserCaution: "Le informazioni potrebbero essere incomplete poiché questo profilo remoto potrebbe non essere completamente federato."
activity: "Attività"
images: "Immagini"
image: "Immagini"
@ -309,7 +319,7 @@ copyUrl: "Copia URL"
rename: "Modifica nome"
avatar: "Foto del profilo"
banner: "Intestazione"
nsfw: "Contenuti sensibili"
displayOfSensitiveMedia: "Visibilità dei media sensibili"
whenServerDisconnected: "Quando la connessione col server è persa"
disconnectedFromServer: "Il server si è disconnesso"
reload: "Ricarica"
@ -453,7 +463,7 @@ signinRequired: "Occorre avere un profilo registrato su questa istanza"
invitations: "Invita"
invitationCode: "Codice di invito"
checking: "Confermando"
available: "Consigliati"
available: "Disponibile"
unavailable: "Il nome utente è già in uso"
usernameInvalidFormat: "Il nome utente può contenere solo lettere, numeri e '_'"
tooShort: "Troppo breve"
@ -572,6 +582,7 @@ accountDeletedDescription: "Questo profilo è stato eliminato."
menu: "Menù"
divider: "Linea di separazione"
addItem: "Aggiungi elemento"
rearrange: "Riordina"
relays: "Ripetitori"
addRelay: "Aggiungi ripetitore"
inboxUrl: "Inbox URL"
@ -622,10 +633,10 @@ smtpHost: "Server remoto"
smtpPort: "Porta"
smtpUser: "Nome utente"
smtpPass: "Password"
emptyToDisableSmtpAuth: "Lasciare il nome utente e la password vuoti per disabilitare la verifica SMTP"
smtpSecure: "Usare la porta SSL/TLS implicito per le connessioni SMTP"
emptyToDisableSmtpAuth: "Lasciare i campi vuoti se non c'è autenticazione SMTP"
smtpSecure: "Usare SSL/TLS implicito per le connessioni SMTP"
smtpSecureInfo: "Disabilitare quando è attivo STARTTLS."
testEmail: "Testa la consegna di posta elettronica"
testEmail: "Verifica il funzionamento"
wordMute: "Filtri parole"
regexpError: "errore regex"
regexpErrorDescription: "Si è verificato un errore nell'espressione regolare alla riga {line} della parola muta {tab}:"
@ -672,7 +683,7 @@ instanceTicker: "Informazioni sull'istanza da cui vengono le note"
waitingFor: "Aspettando {x}"
random: "Casuale"
system: "Sistema"
switchUi: "Cambiare interfaccia"
switchUi: "Cambia interfaccia grafica"
desktop: "Desktop"
clip: "Clip"
createNew: "Crea"
@ -715,6 +726,8 @@ contact: "Contatti"
useSystemFont: "Usa il carattere predefinito del sistema"
clips: "Clip"
experimentalFeatures: "Funzioni sperimentali"
experimental: "Sperimentale"
thisIsExperimentalFeature: "Questa è una funzionalità sperimentale. Potrebbe essere malfunzionante o cambiare in futuro."
developer: "Sviluppatore"
makeExplorable: "Profilo visibile pubblicamente nella pagina \"Esplora\""
makeExplorableDescription: "Disabilitando questa opzione, il tuo profilo non verrà elencato nella pagina \"Esplora\"."
@ -778,10 +791,10 @@ info: "Informazioni"
userInfo: "Informazioni utente"
unknown: "Sconosciuto"
onlineStatus: "Stato di connessione"
hideOnlineStatus: "Stato invisibile"
hideOnlineStatusDescription: "Abilitare l'opzione di stato invisibile può guastare la praticità di singole funzioni, come la ricerca."
hideOnlineStatus: "Modalità invisibile"
hideOnlineStatusDescription: "Attivando questa opzione potresti ridurre l'usabilità di alcune funzioni, come la ricerca."
online: "Online"
active: "Attiv@"
active: "Attività"
offline: "Offline"
notRecommended: "Sconsigliato"
botProtection: "Protezione contro i bot"
@ -791,7 +804,7 @@ switchAccount: "Cambia profilo"
enabled: "Attivo"
disabled: "Inattivo"
quickAction: "Azioni rapide"
user: "Utente"
user: "Profilo"
administration: "Gestione"
accounts: "Profilo"
switch: "Cambia"
@ -799,6 +812,7 @@ noMaintainerInformationWarning: "Le informazioni amministratore non sono imposta
noBotProtectionWarning: "Nessuna protezione impostata contro i bot."
configure: "Imposta"
postToGallery: "Pubblicare nella galleria"
postToHashtag: "Pubblica a questo hashtag"
gallery: "Galleria"
recentPosts: "Le più recenti"
popularPosts: "Le più visualizzate"
@ -823,7 +837,7 @@ received: "Ricevuto"
searchResult: "Risultati della Ricerca"
hashtags: "Hashtag"
troubleshooting: "Risoluzione problemi"
useBlurEffect: "Utilizza effetto sfocatura nell'interfaccia"
useBlurEffect: "Utilizza effetto sfocatura"
learnMore: "Più dettagli"
misskeyUpdated: "CherryPick è stato aggiornato!"
whatIsNew: "Visualizza le informazioni sull'aggiornamento"
@ -832,6 +846,7 @@ translatedFrom: "Tradotto da {x}"
accountDeletionInProgress: "È in corso l'eliminazione del profilo"
usernameInfo: "Un nome per identificare univocamente il tuo profilo sull'istanza. Puoi utilizzare caratteri alfanumerici maiuscoli, minuscoli e il trattino basso (_). Non potrai cambiare nome utente in seguito."
aiChanMode: "Modalità Ai"
devMode: "Modalità sviluppatori"
keepCw: "Mantieni il Content Warning"
pubSub: "Publish/Subscribe del profilo"
lastCommunication: "La comunicazione più recente"
@ -841,6 +856,8 @@ breakFollow: "Non seguire"
breakFollowConfirm: "Vuoi davvero togliere follower?"
itsOn: "Abilitato"
itsOff: "Disabilitato"
on: "Acceso"
off: "Spento"
emailRequiredForSignup: "L'ndirizzo e-mail è obbligatorio per registrarsi"
unread: "Non lette"
filter: "Filtri"
@ -851,8 +868,8 @@ makeReactionsPublicDescription: "La lista delle reazioni che avete fatto è a di
classic: "Classico"
muteThread: "Silenzia la conversazione"
unmuteThread: "Riattiva la conversazione"
ffVisibility: "Ambito pubblico del collegamento"
ffVisibilityDescription: "È possibile impostare la portata pubblica delle informazioni sui propri follower/seguaci."
ffVisibility: "Visibilità delle connessioni"
ffVisibilityDescription: "Puoi scegliere a chi mostrare le tue relazioni con altri profili nel fediverso."
continueThread: "Altri thread."
deleteAccountConfirm: "Così verrà eliminato il profilo. Vuoi procedere?"
incorrectPassword: "La password è errata."
@ -862,7 +879,7 @@ leaveGroup: "Esci dal gruppo"
leaveGroupConfirm: "Uscire da「{name}」?"
useDrawerReactionPickerForMobile: "Mostra sul drawer da dispositivo mobile"
welcomeBackWithName: "Ciao, {name}! Eccoti di nuovo!"
clickToFinishEmailVerification: "Fai click su [{ok}] per completare la verifica dell'indirizzo email."
clickToFinishEmailVerification: "Premi il bottone \"{ok}\" per completare la verifica dell'indirizzo email."
overridedDeviceKind: "Tipo di dispositivo"
smartphone: "Smartphone"
tablet: "Tablet"
@ -923,6 +940,7 @@ remoteOnly: "Solo remoto"
failedToUpload: "errore di caricamento"
cannotUploadBecauseInappropriate: "Non è possibile caricarlo perché è stato stabilito che potrebbe contenere contenuti inappropriati."
cannotUploadBecauseNoFreeSpace: "Impossibile caricare a causa della mancanza di spazio libero sul drive."
cannotUploadBecauseExceedsFileSizeLimit: "Il file non può essere caricato perché eccede le dimensioni consentite."
beta: "Versione beta"
enableAutoSensitive: "Determinazione automatica del NSFW"
enableAutoSensitiveDescription: "Se disponibile, il flag NSFW viene impostato automaticamente sui media utilizzando l'apprendimento automatico. Anche se questa funzione è disattivata, in alcuni casi può essere impostata automaticamente."
@ -956,6 +974,7 @@ didYouLikeMisskey: "Ti piace CherryPick?"
pleaseDonate: "CherryPick è il software libero utilizzato su {host}. Offrendo una donazione è più facile continuare a svilupparlo!"
roles: "Ruoli"
role: "Ruolo"
noRole: "Ruolo non trovato"
normalUser: "Profilo standard"
undefined: "Indefinito"
assign: "Assegna"
@ -995,10 +1014,13 @@ cannotBeChangedLater: "Non sarà più modificabile"
reactionAcceptance: "Reazioni consentite"
likeOnly: "Solo i Like"
likeOnlyForRemote: "Solo Like remoti"
nonSensitiveOnly: "Solamente non sensibili"
nonSensitiveOnlyForLocalLikeOnlyForRemote: "Solamente non sensibili (solo Mi piace remoti)"
rolesAssignedToMe: "I miei ruoli"
resetPasswordConfirm: "Vuoi davvero ripristinare la password?"
sensitiveWords: "Parole sensibili"
sensitiveWordsDescription: "Imposta automaticamente \"Home\" alla visibilità delle Note che contengono una qualsiasi parola tra queste configurate. Puoi separarle per riga."
sensitiveWordsDescription2: "Gli spazi creano la relazione \"E\" tra parole (questo E quello). Racchiudere una parola nelle slash \"/\" la trasforma in Espressione Regolare."
notesSearchNotAvailable: "Non è possibile cercare tra le Note."
license: "Licenza"
unfavoriteConfirm: "Vuoi davvero rimuovere la preferenza?"
@ -1017,9 +1039,13 @@ videos: "Video"
dataSaver: "Risparmia dati"
accountMigration: "Migrazione del profilo"
accountMoved: "Questo profilo ha migrato altrove:"
accountMovedShort: "Questo profilo è stato migrato"
operationForbidden: "Operazione non consentita"
forceShowAds: "Mostra sempre i banner"
addMemo: "Aggiungi Memo"
editMemo: "Modifica Memo"
reactionsList: "Elenco delle reazioni"
renotesList: "Elenco di Rinota"
notificationDisplay: "Stile delle notifiche"
leftTop: "In alto a sinistra"
rightTop: "In alto a destra"
@ -1033,18 +1059,86 @@ serverRules: "Regolamento"
pleaseConfirmBelowBeforeSignup: "Ai sensi del regolamento EU 679/2016 GDPR, autorizzo il trattamento dati personali come descritto nella informativa Privacy."
pleaseAgreeAllToContinue: "Per continuare, occorre selezionare ed essere d'accordo su tutto."
continue: "Continua"
preservedUsernames: "Nomi utente riservati"
preservedUsernamesDescription: "Elenca, uno per linea, i nomi utente che non possono essere registrati durante la creazione del profilo. La restrizione non si applica agli amministratori. Inoltre, i profili già registrati sono esenti."
createNoteFromTheFile: "Crea Nota da questo file"
archive: "Archivio"
channelArchiveConfirmTitle: "Vuoi davvero archiviare {name}?"
channelArchiveConfirmDescription: "Un canale archiviato non compare nell'elenco canali, nemmeno nei risultati di ricerca. Non può ricevere nemmeno nuove Note."
thisChannelArchived: "Questo canale è stato archiviato."
displayOfNote: "Visualizzazione delle Note"
initialAccountSetting: "Impostazioni iniziali del profilo"
youFollowing: "Seguiti"
preventAiLearning: "Impedisci l'apprendimento della IA"
preventAiLearningDescription: "Aggiungendo il campo \"noai\" alla risposta HTML, si indica ai Robot esterni di non usare testi e allegati per addestrare sistemi di Machine Learning (IA predittiva/generativa). Anche se è impossibile sapere se la richiesta venga onorata o semplicemente ignorata."
options: "Opzioni del ruolo"
specifyUser: "Profilo specifico"
failedToPreviewUrl: "Anteprima non disponibile"
update: "Aggiorna"
rolesThatCanBeUsedThisEmojiAsReaction: "Ruoli che possono usare questa emoji come reazione"
rolesThatCanBeUsedThisEmojiAsReactionEmptyDescription: "Se non viene specificato alcun ruolo, chiunque può reagire con questa emoji."
rolesThatCanBeUsedThisEmojiAsReactionPublicRoleWarn: "Questi ruoli devono essere pubblici"
cancelReactionConfirm: "Vuoi annullare la tua reazione?"
changeReactionConfirm: "Vuoi cambiare la tua reazione?"
later: "Non ora"
goToMisskey: "Vai a CherryPick"
additionalEmojiDictionary: "Dizionario aggiuntivo emoji"
installed: "Installazione avvenuta"
branding: "Branding"
enableServerMachineStats: "Pubblicare le informazioni sul server"
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"
doYouAgree: "Sei d'accordo?"
beSureToReadThisAsItIsImportant: "Si prega di leggere attentamente perché è importante."
iHaveReadXCarefullyAndAgree: "Ho letto accuratamente \"{x}\" e sono d'accordo."
_initialAccountSetting:
accountCreated: "Il tuo profilo è stato creato!"
letsStartAccountSetup: "Per iniziare, impostiamo il tuo profilo."
letsFillYourProfile: "Innanzitutto, compila il tuo profilo."
profileSetting: "Impostazioni del profilo"
privacySetting: "Impostazioni sulla privacy"
theseSettingsCanEditLater: "In seguito, potrai cambiare la tua scelta."
youCanEditMoreSettingsInSettingsPageLater: "Nella pagina \"Impostazioni\", è possibile personalizzare di più il tuo profilo. Dacci un'occhiata dopo!"
followUsers: "Per comporre la tua Timeline Home (personale) segui i profili delle persone che ti interessano."
pushNotificationDescription: "Attivare le notifiche push ti permettera di ricevere informazioni sulla attività di {name} direttamente sul tuo dispositivo."
initialAccountSettingCompleted: "Hai completato la configurazione iniziale!"
haveFun: "Divertiti con {name}!"
ifYouNeedLearnMore: "Per saperne di più su come usare {name} (CherryPick), visita la pagina {link}"
skipAreYouSure: "Vuoi davvero saltare la configurazione iniziale?"
laterAreYouSure: "Vuoi davvero rimandare la configurazione iniziale?"
_serverRules:
description: "In Europa è necessario mostrare l'informativa sul trattamento dei dati personali, prima della registrazione al servizio."
_accountMigration:
moveFrom: "Migra un altro profilo dentro a questo"
moveFromSub: "Crea un alias verso un altro profilo remoto"
moveFromLabel: "Profilo da cui migrare:"
moveFromDescription: "Se desideri spostare i profili follower da un altro profilo a questo, devi prima creare un alias qui. Assicurati averlo creato PRIMA di eseguire l'attività! Inserisci l'indirizzo del profilo mittente in questo modo: @persona@istanza.it"
moveTo: "Migrare questo profilo verso un un altro"
moveToLabel: "Profilo verso cui migrare"
moveCannotBeUndone: "La migrazione è irreversibile, non può essere interrotta o annullata."
moveAccountDescription: "Questa attività è irreversibile! Innanzitutto, assicurati di aver creato, nella istanza di destinazione, un alias con l'indirizzo di questo profilo. Successivamente, indica qui il profilo di destinazione in questo modo: @persona@istanza.it"
moveAccountHowTo: "Per migrare su un profilo remoto, crea prima un alias di questo profilo, sulla istanza di destinazione.\nDopo aver creato l'alias, inserisci l'indirizzo di destinazione, indicando ad esempio: @profilo@altra.istanza"
startMigration: "Avvia la migrazione"
migrationConfirm: "Vuoi davvero migrare questo profilo su {account}? L'azione è irreversibile e non potrai più utilizzare questo profilo nel suo stato originale.\nInoltre, assicurati di aver già creato un alias sull'account a cui ti stai trasferendo."
movedAndCannotBeUndone: "Il tuo profilo è stato migrato.\nLa migrazione non può essere annullata."
postMigrationNote: "Questo profilo smetterà di seguire gli altri profili remoti a 24 ore dal termine della migrazione.\nSia i Follow che i Follower scenderanno a zero. I tuoi follower saranno comunque in grado di vedere le Note per soli follower, poiché non smetteranno di seguirti."
movedTo: "Profilo verso cui migrare"
_achievements:
earnedAt: "Data di conseguimento"
@ -1324,8 +1418,12 @@ _role:
ltlAvailable: "Disponibilità della Timeline Locale"
canPublicNote: "Può scrivere Note con Visibilità Pubblica"
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"
driveCapacity: "Capienza del Drive"
alwaysMarkNsfw: "Imposta sempre come NSFW"
pinMax: "Quantità massima di Note in primo piano"
antennaMax: "Quantità massima di Antenne"
wordMuteMax: "Lunghezza massima del filtro parole"
@ -1363,7 +1461,7 @@ _sensitiveMediaDetection:
_emailUnavailable:
used: "Email già in uso"
format: "Formato email non valido"
disposable: "Email non riutilizzabile"
disposable: "Indirizzo email non utilizzabile"
mx: "Server email non corretto"
smtp: "Il server email non risponde"
_ffVisibility:
@ -1385,6 +1483,7 @@ _ad:
back: "Indietro"
reduceFrequencyOfThisAd: "Visualizza questa pubblicità meno spesso"
hide: "Nascondi"
timezoneinfo: "Il giorno della settimana è determinato in base al fuso orario del server."
_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."
ifNoEmail: "Se il tuo indirizzo email non risulta registrato, contatta l'amministrazione dell'istanza."
@ -1436,10 +1535,10 @@ _aboutMisskey:
donate: "Sostieni Misskey"
morePatrons: "Apprezziamo sinceramente il supporto di tante altre persone. Grazie mille! 🥰"
patrons: "Sostenitori"
_nsfw:
respect: "Nascondere i media segnati come sensibli"
ignore: "Visualizzare i media segnati come sensibili"
force: "Nascondere tutti i media"
_displayOfSensitiveMedia:
respect: "Nascondere i media sensibili"
ignore: "Non nascondere i media sensibili"
force: "Nascondi tutti i media"
_mfm:
cheatSheet: "Bigliettino MFM"
intro: "MFM è un linguaggio Markdown particolare che si può usare in diverse parti di Misskey. Qui puoi visualizzare a colpo d'occhio tutta la sintassi MFM utile."
@ -1643,6 +1742,16 @@ _time:
minute: "min"
hour: "ore"
day: "giorni"
_timelineTutorial:
title: "Come usare CherryPick"
step1_1: "Questa è la \"Timeline\". tutte le \"Note\" pubblicate su {name} vengono elencate in ordine cronologico."
step1_2: "Le Timeline sono diverse, ad esempio, la \"Home\" elenca le Note dei profili che segui. Quella \"Locale\" elenca quelle di tutti i profili attivi su {name}."
step2_1: "Prova a pubblicare una Nota. Semplicemente premendo il bottone con l'icona di una matita."
step2_2: "Potresti scrivere la tua presentazione, oppure semplicemente \"Ciao da {name}!\""
step3_1: "Hai pubblicato qualcosa?"
step3_2: "In tal caso, dovrebbe comparire subito nella tua \"Home\""
step4_1: "Puoi reagire con un emoji alle Note."
step4_2: "To attach a reaction, press the \"+\" mark on a note and choose an emoji you'd like to react with.\nPer reagire con una emoji, premi il bottone \"+\" (più) visibile vicino ad ogni Nota e scegli dall'elenco la emoji che rappresenta la tua reazione."
_2fa:
alreadyRegistered: "La configurazione è stata già completata."
registerTOTP: "Registra un'app di autenticazione"
@ -1791,7 +1900,7 @@ _visibility:
followersDescription: "Visibile solo ai tuoi follower"
specified: "Nota diretta"
specifiedDescription: "Visibile solo ai profili menzionati"
disableFederation: "Federazione disabilitata"
disableFederation: "Non federare"
disableFederationDescription: "Non spedire attività alle altre istanze remote"
_postForm:
replyPlaceholder: "Rispondi a questa nota..."
@ -1976,6 +2085,7 @@ _deck:
introduction: "Combinate le colonne per creare la vostra interfaccia!"
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à"
useSimpleUiForNonRootPages: "Visualizza sotto pagine con interfaccia web semplice"
_columns:
main: "Principale"
widgets: "Riquadri"

View file

@ -1,5 +1,16 @@
_lang_: "日本語"
addSingle: "一つだけ追加"
addMultiple: "複数追加"
showRenoteConfirmPopup: "Renoteするときに確認ポップアップを表示"
showSubNoteFooterButton: "サブノートにアクションボタンを表示"
showSubNoteFooterButtonDescription: "この設定を有効にすると、返信があるノートの親ノートにアクションボタンを表示します。"
alreadyFollowed: "フォローしました!"
enableMarkByDate: "ノート時刻を日付で表示"
renoteConfirm: "Renoteしますか"
inviteRevoke: "全ての招待コードを失効する"
inviteRevokeConfirm: "本当に全ての招待コードを失効させますか?"
enableAbsoluteTime: "絶対時刻表記を使用する"
posted: "ノートを公開しました。"
translateNote: "ノートを翻訳する"
showTranslateButtonInNote: "ノート本文に翻訳ボタンを表示"
@ -9,7 +20,8 @@ displayBanner: "バナー画像の表示"
requireRefresh: "ページの更新が必要なとき"
performanceWarning: "リソースを多く使用するため、デバイスの温度が高くなり、バッテリーの消耗が速くなる可能性があります"
photosensitiveSeizuresWarning: "光敏感性発作を起こす可能性があります"
friendlyEnableNotification: "通知領域を有効化/無効化"
friendlyEnableNotifications: "通知領域を有効化/無効化"
friendlyEnableWidgets: "ウィジェット領域を有効化/無効化"
useBoldFont: "文字を太くする"
newNoteReceivedNotification: "新しいノート通知を表示するとき"
disableRightClick: "右クリックを禁止"
@ -73,11 +85,15 @@ deleteAndEditConfirm: "このノートを削除してもう一度編集します
copyAndEdit: "コピーして編集"
copyAndEditConfirm: "このノートをコピーして編集しましょうか?ノートに含まれているメディアも一緒にコピーされます。"
addToList: "リストに追加"
addToAntenna: "アンテナに追加"
sendMessage: "メッセージを送信"
copyRSS: "RSSをコピー"
copyUsername: "ユーザー名をコピー"
copyUserId: "ユーザーIDをコピー"
copyNoteId: "ートIDをコピー"
copyFileId: "ファイルIDをコピー"
copyFolderId: "フォルダーIDをコピー"
copyProfileUrl: "プロフィールURLをコピー"
searchUser: "ユーザーを検索"
reply: "返信"
loadMore: "もっと見る"
@ -136,7 +152,7 @@ pinnedNote: "ピン留めされたノート"
pinned: "ピン留め"
you: "あなた"
clickToShow: "クリックして表示"
sensitive: "閲覧注意"
sensitive: "センシティブ"
add: "追加"
reaction: "リアクション"
reactions: "リアクション"
@ -144,8 +160,8 @@ reactionSetting: "ピッカーに表示するリアクション"
reactionSettingDescription2: "ドラッグして並び替え、クリックして削除、+を押して追加します。"
rememberNoteVisibility: "公開範囲を記憶する"
attachCancel: "添付取り消し"
markAsSensitive: "閲覧注意にする"
unmarkAsSensitive: "閲覧注意を解除する"
markAsSensitive: "センシティブとして設定"
unmarkAsSensitive: "センシティブを解除する"
enterFileName: "ファイル名を入力"
mute: "ミュート"
unmute: "ミュート解除"
@ -160,8 +176,10 @@ unblockConfirm: "ブロック解除しますか?"
suspendConfirm: "凍結しますか?"
unsuspendConfirm: "解凍しますか?"
selectList: "リストを選択"
editList: "リストを編集"
selectChannel: "チャンネルを選択"
selectAntenna: "アンテナを選択"
editAntenna: "アンテナを編集"
selectWidget: "ウィジェットを選択"
editWidgets: "ウィジェットを編集"
editWidgetsExit: "編集を終了"
@ -174,6 +192,8 @@ addEmoji: "絵文字を追加"
settingGuide: "おすすめ設定"
cacheRemoteFiles: "リモートのファイルをキャッシュする"
cacheRemoteFilesDescription: "この設定を無効にすると、リモートファイルをキャッシュせず直リンクするようになります。サーバーのストレージを節約できますが、サムネイルが生成されないので通信量が増加します。"
cacheRemoteSensitiveFiles: "リモートのセンシティブなファイルをキャッシュする"
cacheRemoteSensitiveFilesDescription: "この設定を無効にすると、リモートのセンシティブなファイルはキャッシュせず直リンクするようになります。"
flagAsBot: "Botとして設定"
flagAsBotDescription: "このアカウントがプログラムによって運用される場合は、このフラグをオンにします。オンにすると、反応の連鎖を防ぐためのフラグとして他の開発者に役立ったり、CherryPickのシステム上での扱いがBotに合ったものになります。"
flagAsCat: "にゃああああああああああああああ!!!!!!!!!!!!"
@ -335,7 +355,7 @@ copyUrl: "URLをコピー"
rename: "名前を変更"
avatar: "アイコン"
banner: "バナー"
nsfw: "閲覧注意"
displayOfSensitiveMedia: "センシティブなメディアの表示"
whenServerDisconnected: "サーバーとの接続が失われたとき"
disconnectedFromServer: "サーバーから切断されました"
reload: "リロード"
@ -731,7 +751,7 @@ driveUsage: "ドライブ使用量"
noCrawle: "クローラーによるインデックスを拒否"
noCrawleDescription: "外部の検索エンジンにあなたのユーザーページ、ート、Pagesなどのコンテンツを登録(インデックス)しないよう要求します。"
lockedAccountInfo: "フォローを承認制にしても、ノートの公開範囲を「フォロワー」にしない限り、誰でもあなたのノートを見ることができます。"
alwaysMarkSensitive: "デフォルトでメディアを閲覧注意にする"
alwaysMarkSensitive: "デフォルトでメディアをセンシティブ設定にする"
loadRawImages: "添付画像のサムネイルをオリジナル画質にする"
disableShowingAnimatedImages: "アニメーション画像を再生しない"
disableShowingAnimatedImagesDescription: "無効にすると、動く画像が再生されます。光敏感性発作を起こすことがありますので、ご注意ください。"
@ -963,8 +983,8 @@ cannotUploadBecauseInappropriate: "不適切な内容を含む可能性がある
cannotUploadBecauseNoFreeSpace: "ドライブの空き容量が無いためアップロードできません。"
cannotUploadBecauseExceedsFileSizeLimit: "ファイルサイズの制限を超えているためアップロードできません。"
beta: "ベータ"
enableAutoSensitive: "自動NSFW判定"
enableAutoSensitiveDescription: "利用可能な場合は、機械学習を利用して自動でメディアにNSFWフラグを設定します。この機能をオフにしても、サーバーによっては自動で設定されることがあります。"
enableAutoSensitive: "自動センシティブ判定"
enableAutoSensitiveDescription: "利用可能な場合は、機械学習を利用して自動でメディアにセンシティブフラグを設定します。この機能をオフにしても、サーバーによっては自動で設定されることがあります。"
activeEmailValidationDescription: "ユーザーのメールアドレスのバリデーションを、捨てアドかどうかや実際に通信可能かどうかなどを判定しより積極的に行います。オフにすると単に文字列として正しいかどうかのみチェックされます。"
navbar: "ナビゲーションバー"
shuffle: "シャッフル"
@ -1081,7 +1101,7 @@ vertical: "縦"
horizontal: "横"
position: "位置"
serverRules: "サーバールール"
pleaseConfirmBelowBeforeSignup: "このサーバーに登録する前に、以下を確認してください。"
pleaseConfirmBelowBeforeSignup: "このサーバーに登録するには、以下の内容を確認し同意する必要があります。"
pleaseAgreeAllToContinue: "続けるには、全ての「同意する」にチェックが入っている必要があります。"
continue: "続ける"
preservedUsernames: "予約ユーザー名"
@ -1110,13 +1130,33 @@ goToMisskey: "CherryPickへ"
additionalEmojiDictionary: "絵文字の追加辞書"
installed: "インストール済み"
branding: "ブランディング"
enableServerMachineStats: "サーバーのマシン情報を公開する"
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}」の内容をよく読み、同意します。"
additionalPermissionsForFlash: "Playへの追加許可"
thisFlashRequiresTheFollowingPermissions: "このPlayは以下の権限を要求しています"
doYouWantToAllowThisPlayToAccessYourAccount: "このPlayによるアカウントへのアクセスを許可しますか"
translateProfile: "プロフィールを翻訳する"
enableAbsoluteTime: "絶対時刻表記を使用する"
inviteRevoke: "全ての招待コードを失効する"
inviteRevokeConfirm: "本当に全ての招待コードを失効させますか?"
_group:
leader: "グループオーナー"
@ -1135,6 +1175,7 @@ _cherrypick:
rememberPostFormToggleState: "投稿フォームにて、プレビューのオン・オフを記憶する"
reactableRemoteReaction: "リモートのカスタム絵文字リアクションでも、このサーバーに同じ名前の絵文字があればリアクションできるようにする"
showFollowingMessageInsteadOfButton: "既にフォローしている場合、通知欄にフォローボタンを表示しない"
mobileTimelineHeaderChange: "モバイル環境でタイムラインのヘッダーデザインを変更"
_bannerDisplay:
all: "全て"
@ -1492,8 +1533,13 @@ _role:
_options:
gtlAvailable: "グローバルタイムラインの閲覧"
ltlAvailable: "ローカルタイムラインの閲覧"
mtlAvailable: "メディアタイムラインの閲覧"
ctlAvailable: "キャットタイムラインの閲覧"
canPublicNote: "パブリック投稿の許可"
canInvite: "サーバー招待コードの発行"
inviteLimit: "招待コードの作成可能数"
inviteLimitCycle: "招待コードの発行間隔"
inviteExpirationTime: "招待コードの有効期限"
canManageCustomEmojis: "カスタム絵文字の管理"
driveCapacity: "ドライブ容量"
alwaysMarkNsfw: "ファイルにNSFWを常に付与"
@ -1533,7 +1579,7 @@ _sensitiveMediaDetection:
description: "機械学習を使って自動でセンシティブなメディアを検出し、モデレーションに役立てることができます。サーバーの負荷が少し増えます。"
sensitivity: "検出感度"
sensitivityDescription: "感度を低くすると、誤検知(偽陽性)が減ります。感度を高くすると、検知漏れ(偽陰性)が減ります。"
setSensitiveFlagAutomatically: "NSFWフラグを設定する"
setSensitiveFlagAutomatically: "センシティブフラグを設定する"
setSensitiveFlagAutomaticallyDescription: "この設定をオフにしても内部的に判定結果は保持されます。"
analyzeVideos: "動画の解析を有効化"
analyzeVideosDescription: "静止画に加えて動画も解析するようにします。サーバーの負荷が少し増えます。"
@ -1567,6 +1613,7 @@ _ad:
back: "戻る"
reduceFrequencyOfThisAd: "この広告の表示頻度を下げる"
hide: "表示しない"
timezoneinfo: "曜日はサーバーのタイムゾーンを元に指定されます。"
_forgotPassword:
enterEmail: "アカウントに登録したメールアドレスを入力してください。そのアドレス宛てに、パスワードリセット用のリンクが送信されます。"
@ -1635,9 +1682,9 @@ _aboutMisskey:
relayServer: "リレーサーバー"
community: "コミュニティー"
_nsfw:
respect: "閲覧注意のメディアは隠す"
ignore: "閲覧注意のメディアを隠さない"
_displayOfSensitiveMedia:
respect: "センシティブ設定されたメディアを隠す"
ignore: "センシティブ設定されたメディアを隠さない"
force: "常にメディアを隠す"
_mfm:
@ -2104,6 +2151,7 @@ _timelines:
local: "ローカル"
media: "メディア"
social: "ソーシャル"
cat: "キャット"
global: "グローバル"
_play:
@ -2232,6 +2280,7 @@ _deck:
introduction: "カラムを組み合わせて自分だけのインターフェイスを作りましょう!"
introduction2: "画面の右にある + を押して、いつでもカラムを追加できます。"
widgetsIntroduction: "カラムのメニューから、「ウィジェットの編集」を選択してウィジェットを追加してください"
useSimpleUiForNonRootPages: "非ルートページは簡易UIで表示"
_columns:
main: "メイン"

View file

@ -1,7 +1,7 @@
---
_lang_: "日本語 (関西弁)"
headlineMisskey: "ノートでつながるネットワーク"
introMisskey: "ようお越しCherryPickは、オープンソースの分散型マイクロブログサービスやねん。\n「ート」を作って、いま起こっとることを共有したり、あんたについて皆に発信しよう📡\n「ツッコミ」機能で、皆のートに素早く反応を追加したりもできるで✌\nほな新しい世界を探検しよか🚀"
introMisskey: "ようお越しCherryPickは、オープンソースの分散型マイクロブログサービスやねん。\n「ート」を作って、いま起こっとることを共有したり、あんたについて皆に発信しよう📡\n「ツッコミ」機能で、皆のートに素早く反応を追加したりもできるで✌\nほな新しい世界を探検しよか🚀"
poweredByMisskeyDescription: "{name}は、オープンソースのプラットフォーム<b>CherryPick</b>のサーバーのひとつなんやで。"
monthAndDay: "{month}月 {day}日"
search: "探す"
@ -49,11 +49,15 @@ delete: "ほかす"
deleteAndEdit: "ほかして直す"
deleteAndEditConfirm: "このートをほかしてもっかい直すこのートへのツッコミ、Renote、返信も全部消えるんやけどそれでもええん"
addToList: "リストに入れたる"
addToAntenna: "アンテナに追加"
sendMessage: "メッセージを送る"
copyRSS: "RSSをコピー"
copyUsername: "ユーザー名をコピー"
copyUserId: "ユーザーIDをコピー"
copyNoteId: "ートIDをコピー"
copyFileId: "ファイルIDをコピー"
copyFolderId: "フォルダーIDをコピー"
copyProfileUrl: "プロフィールURLをコピー"
searchUser: "ユーザーを検索"
reply: "返事"
loadMore: "まだまだあるで!"
@ -136,8 +140,10 @@ unblockConfirm: "ブロックやめたるってほんまか?"
suspendConfirm: "凍結してしもうてええか?"
unsuspendConfirm: "解凍するけどええか?"
selectList: "リストを選ぶ"
editList: "リスト直すで"
selectChannel: "チャンネルを選ぶ"
selectAntenna: "アンテナを選ぶ"
editAntenna: "アンテナを編集"
selectWidget: "ウィジェットを選ぶ"
editWidgets: "ウィジェットをいじる"
editWidgetsExit: "編集終ったで"
@ -150,6 +156,8 @@ addEmoji: "絵文字を追加"
settingGuide: "ええ感じの設定"
cacheRemoteFiles: "リモートのファイルをキャッシュする"
cacheRemoteFilesDescription: "この設定を切っとったら、リモートファイルをキャッシュせんと直リンクするようになるで。サーバーの容量は節約できるけど、サムネイルを作らんなるから通信量が増えるで。"
cacheRemoteSensitiveFiles: "リモートのセンシティブなファイルをキャッシュする"
cacheRemoteSensitiveFilesDescription: "この設定を無効にすると、リモートのセンシティブなファイルはキャッシュせず直リンクするようになるで。"
flagAsBot: "Botにするで"
flagAsBotDescription: "もしこのアカウントをプログラム使うて運用するんやったら、このフラグをオンにしてや。オンにすれば、反応がバーッて連鎖せんように開発者が使うたり、CherryPickのシステム上での扱いがBotに合ったもんになるからな。"
flagAsCat: "Catやで"
@ -311,7 +319,7 @@ copyUrl: "URLをコピー"
rename: "名前を変えるで"
avatar: "アイコン"
banner: "バナー"
nsfw: "見るんは気いつけてな"
displayOfSensitiveMedia: "センシティブなメディアの表示"
whenServerDisconnected: "サーバーとの接続が失くなってしもうたとき"
disconnectedFromServer: "サーバーが機嫌悪いねん"
reload: "リロード"
@ -1076,6 +1084,30 @@ later: "あとで"
goToMisskey: "CherryPickへ"
additionalEmojiDictionary: "絵文字の追加辞書"
installed: "インストール済み"
branding: "あ"
enableServerMachineStats: "サーバーのマシン情報見せびらかすで"
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:
accountCreated: "アカウント作り終わったで。"
letsStartAccountSetup: "アカウントの初期設定をしよか。"
@ -1386,6 +1418,9 @@ _role:
ltlAvailable: "ローカルタイムラインの閲覧"
canPublicNote: "パブリック投稿の許可"
canInvite: "サーバー招待コードの発行"
inviteLimit: "招待コードの作成可能数"
inviteLimitCycle: "招待コードの発行間隔"
inviteExpirationTime: "招待コードの有効期限"
canManageCustomEmojis: "カスタム絵文字の管理"
driveCapacity: "ドライブ容量"
alwaysMarkNsfw: "勝手にファイルにNSFWをくっつける"
@ -1448,6 +1483,7 @@ _ad:
back: "戻る"
reduceFrequencyOfThisAd: "この広告の表示頻度を下げるで"
hide: "表示せん"
timezoneinfo: "曜日はサーバーのタイムゾーンを元に指定されるで。"
_forgotPassword:
enterEmail: "アカウントに登録したメールアドレスをここに入力してや。そのアドレス宛に、パスワードリセット用のリンクが送られるから待っててな~。"
ifNoEmail: "メールアドレスを登録してへんのやったら、管理者まで教えてな~。"
@ -1499,9 +1535,9 @@ _aboutMisskey:
donate: "Misskeyに寄付"
morePatrons: "他にもぎょうさんの人からサポートしてもろてんねん。ほんまおおきに🥰"
patrons: "支援者"
_nsfw:
respect: "閲覧注意のメディアは隠すで"
ignore: "閲覧注意のメディアは隠さへんで"
_displayOfSensitiveMedia:
respect: "きわどいのは見とうない"
ignore: "きわどいのも見たい"
force: "常にメディアを隠すで"
_mfm:
cheatSheet: "MFMチートシート"
@ -1715,7 +1751,7 @@ _timelineTutorial:
step3_1: "投稿できた?"
step3_2: "あんたのノートがタイムラインに出てきたら成功や。"
step4_1: "ノートには、「ツッコミ」を付けれるで。"
step4_2: "ツッコむんやったら、ノートの「+」マークを押して、好きな絵文字を選ぶで。"
step4_2: "ツッコむんやったら、ノートの「+」マークを押して、好きな絵文字を選ぶんやで。"
_2fa:
alreadyRegistered: "もう設定終わっとるわ。"
registerTOTP: "認証アプリの設定はじめる"
@ -2049,6 +2085,7 @@ _deck:
introduction: "カラムを組み合わせて自分だけのインターフェイスを作りましょ!"
introduction2: "画面の右にある + を押して、いつでもカラムを追加できるで。"
widgetsIntroduction: "カラムのメニューから、「ウィジェットの編集」を選んでウィジェットを追加してなー"
useSimpleUiForNonRootPages: "非ルートページは簡易UIで表示"
_columns:
main: "メイン"
widgets: "ウィジェット"

View file

@ -1,5 +1,16 @@
---
_lang_: "한국어"
addSingle: "하나만 추가"
addMultiple: "여러 개 추가"
showRenoteConfirmPopup: "리노트할 때 확인 팝업 표시"
showSubNoteFooterButton: "서브 노트에 액션 버튼 표시"
showSubNoteFooterButtonDescription: "이 설정을 활성화하면 답글이 달린 노트의 상위 노트에 액션 버튼을 표시해요."
alreadyFollowed: "팔로우 했어요!"
enableMarkByDate: "노트 시간을 일자로 표시"
renoteConfirm: "리노트 할까요?"
inviteRevoke: "모든 초대 코드 제거"
inviteRevokeConfirm: "정말로 모든 초대 코드를 제거할까요?"
enableAbsoluteTime: "절대 시간 표기 사용"
posted: "노트를 게시했어요!"
translateNote: "노트 번역하기"
showTranslateButtonInNote: "노트 본문에 번역 버튼 표시"
@ -9,14 +20,15 @@ displayBanner: "배너 이미지 표시"
requireRefresh: "페이지 새로 고침이 필요할 때"
performanceWarning: "리소스를 많이 사용하므로, 디바이스의 온도가 높아지고 배터리의 소모가 빨라질 수 있어요"
photosensitiveSeizuresWarning: "광과민성 발작을 일으킬 수 있어요"
friendlyEnableNotification: "알림 영역 활성화/비활성화"
friendlyEnableNotifications: "알림 영역 활성화/비활성화"
friendlyEnableWidgets: "위젯 영역 활성화/비활성화"
useBoldFont: "볼드체 텍스트"
newNoteReceivedNotification: "새 노트 알림을 표시할 때"
disableRightClick: "우클릭 방지"
useEnterToSend: "Enter 키를 눌러 보내기"
useEnterToSendDescription: "옵션을 활성화하면 줄 바꿈은 Shift + Enter 키로 할 수 있어요."
postFormVisibilityHotkey: "단축키로 공개 범위 전환하기"
postFormVisibilityHotkeyDescription: "노트를 작성할 때, Ctrl(control) + Shift 키를 누르면 공개 범위를 전환할 수 있어요. 로컬에만 보이게 하는 단축키는 Ctrl(command 또는 control) + Alt(option) 키요."
postFormVisibilityHotkeyDescription: "노트를 작성할 때, Ctrl(control) + Shift 키를 누르면 공개 범위를 전환할 수 있어요. 로컬에만 보이게 하는 단축키는 Ctrl(command 또는 control) + Alt(option) 키요."
cherrypickUpdatedCacheClearTitle: "캐시를 지울까요?"
cherrypickUpdatedCacheClear: "테마 및 색상, 로케일 등의 변경 사항이 제대로 반영되지 않을 수 있기 때문에, 클라이언트가 업데이트되면 <b>캐시를 지울 것을 권장</b>해요.\n계정 로그인 상태는 그대로 유지돼요!"
cherrypickUpdatedCacheClearLater: "나중에 캐시를 지우려면 <b>설정</b> - <b>캐시 지우기</b>에서 할 수 있어요!"
@ -73,11 +85,15 @@ deleteAndEditConfirm: "이 노트를 삭제한 뒤 다시 편집할까요? 이
copyAndEdit: "복사 후 편집"
copyAndEditConfirm: "이 노트를 복사하고 편집할까요? 노트에 포함된 미디어도 같이 복사돼요!"
addToList: "리스트에 추가"
addToAntenna: "안테나에 추가"
sendMessage: "메시지 보내기"
copyRSS: "RSS 복사"
copyUsername: "유저명 복사"
copyUserId: "유저 ID 복사"
copyNoteId: "노트 ID 복사"
copyFileId: "파일 ID 복사"
copyFolderId: "폴더 ID 복사"
copyProfileUrl: "프로필 URL 복사"
searchUser: "사용자 검색"
reply: "답글"
loadMore: "더 보기"
@ -127,8 +143,8 @@ enterEmoji: "이모지 입력"
renote: "리노트"
unrenote: "리노트 취소"
renoted: "리노트 했어요!"
cantRenote: "이 게시물은 리노트 할 수 없어요."
cantReRenote: "리노트된 노트는 리노트 할 수 없어요."
cantRenote: "이 게시물은 리노트할 수 없어요."
cantReRenote: "리노트된 노트는 리노트할 수 없어요."
quote: "인용"
inChannelRenote: "채널 내 리노트"
inChannelQuote: "채널 내 인용"
@ -160,8 +176,10 @@ unblockConfirm: "이 계정의 차단을 해제할까요? 상대방이 나를
suspendConfirm: "이 계정을 정지할까요?"
unsuspendConfirm: "이 계정의 정지를 해제할까요?"
selectList: "리스트 선택"
editList: "리스트 편집"
selectChannel: "채널 선택"
selectAntenna: "안테나 선택"
editAntenna: "안테나 편집"
selectWidget: "위젯 선택"
editWidgets: "위젯 편집"
editWidgetsExit: "편집 종료"
@ -174,10 +192,12 @@ addEmoji: "이모지 추가"
settingGuide: "추천 설정"
cacheRemoteFiles: "리모트 파일을 캐시"
cacheRemoteFilesDescription: "이 설정을 해지하면 리모트 파일을 캐시하지 않고 해당 파일을 직접 링크해요. 그에 따라 서버의 저장 공간을 절약할 수 있지만, 썸네일이 생성되지 않기 때문에 통신량이 증가하게 돼요."
cacheRemoteSensitiveFiles: "리모트의 민감한 파일을 캐시"
cacheRemoteSensitiveFilesDescription: "이 설정을 비활성화하면 리모트의 민감한 파일은 캐시하지 않고 리모트에서 직접 가져오도록 설정해요."
flagAsBot: "삐릭, 삐리리릭? 저는 봇입니다."
flagAsBotDescription: "이 계정을 자동화된 수단으로 운용할 경우에 활성화해 주세요. 이 플래그를 활성화하면, 다른 봇이 이를 참고하여 봇 끼리의 무한 연쇄 반응을 회피하거나, 이 계정의 시스템 상에서의 취급이 봇 운영에 최적화되는 등의 변화가 생겨요"
flagAsCat: "나는 고양이다냥"
flagAsCatDescription: "이 계정이 고양이라면 활성화 해달라냥"
flagAsCatDescription: "이 계정이 고양이라면 활성화 달라냥"
flagShowTimelineReplies: "타임라인에 노트의 답글을 표시하기"
flagShowTimelineRepliesDescription: "이 설정을 활성화하면 타임라인에 다른 유저 간의 답글을 표시해요."
autoAcceptFollowed: "팔로우 중인 유저로부터의 팔로우 요청을 자동 수락"
@ -335,7 +355,7 @@ copyUrl: "URL 복사"
rename: "이름 변경"
avatar: "아바타"
banner: "배너"
nsfw: "열람 주의"
displayOfSensitiveMedia: "민감한 미디어 표시"
whenServerDisconnected: "서버와의 접속이 끊겼을 때"
disconnectedFromServer: "접속이 끊어졌어요!"
reload: "새로고침"
@ -1037,8 +1057,8 @@ cannotBeChangedLater: "나중에 변경할 수 없어요."
reactionAcceptance: "리액션 수신"
likeOnly: "좋아요만 받기"
likeOnlyForRemote: "리모트에서는 좋아요만 받기"
nonSensitiveOnly: "열람 주의로 설정되지 않았을 때만 받기"
nonSensitiveOnlyForLocalLikeOnlyForRemote: "열람 주의로 설정되지 않았을 때만 받기 (리모트에서는 좋아요만 받기)"
nonSensitiveOnly: "민감한 이모지를 제외하고 받기"
nonSensitiveOnlyForLocalLikeOnlyForRemote: "민감한 이모지를 제외하고 받기 (리모트에서는 좋아요만 받기)"
rolesAssignedToMe: "나에게 할당된 역할"
resetPasswordConfirm: "비밀번호를 재설정할까요?"
sensitiveWords: "민감한 단어"
@ -1110,13 +1130,31 @@ later: "나중에"
goToMisskey: "CherryPick으로"
additionalEmojiDictionary: "이모지 추가 사전"
installed: "설치됨"
branding: "브랜딩"
enableServerMachineStats: "서버의 머신 사양을 공개하기"
enableIdenticonGeneration: "유저마다 Identicon 생성 유효화"
turnOffToImprovePerformance: "이 기능을 끄면 성능이 향상될 수 있어요."
createInviteCode: "초대 코드 생성"
createWithOptions: "옵션을 지정하여 생성"
createCount: "초대 수"
inviteCodeCreated: "초대 코드 생성됨"
inviteLimitExceeded: "초대 코드의 생성 한도를 초과했어요."
createLimitRemaining: "초대 한도: {limit}회 남음"
inviteLimitResetCycle: " {time}시간 이내에 최대 {limit}개의 초대 코드를 생성할 수 있어요."
expirationDate: "만료 날짜"
noExpirationDate: "만료기간 없음"
inviteCodeUsedAt: "다음에 사용된 초대 코드"
registeredUserUsingInviteCode: "초대 코드 사용 대상"
waitingForMailAuth: "이메일 인증 보류 중"
inviteCodeCreator: "초대 코드 생성자"
usedAt: "사용 시각"
unused: "사용되지 않음"
used: "사용됨"
expired: "만료됨"
additionalPermissionsForFlash: "Play에 대한 추가 권한"
thisFlashRequiresTheFollowingPermissions: "이 Play는 다음 권한을 요구해요"
doYouWantToAllowThisPlayToAccessYourAccount: "이 Play가 계정에 접근하도록 허용할까요?"
translateProfile: "프로필 번역하기"
enableAbsoluteTime: "절대 시간 표기 사용"
inviteRevoke: "모든 초대 코드 무효화"
inviteRevokeConfirm: "정말로 모든 초대 코드를 무효화 할까요?"
_group:
leader: "그룹 주인"
banish: "추방"
@ -1133,6 +1171,7 @@ _cherrypick:
rememberPostFormToggleState: "노트 작성 화면에서 본문 미리보기 활성화 상태 기억"
reactableRemoteReaction: "서버에 리모트 이모지와 이름이 같은 이모지가 있으면 리모트 이모지에도 반응할 수 있음"
showFollowingMessageInsteadOfButton: "이미 팔로우한 경우 알림 필드에 팔로우 버튼을 표시하지 않음"
mobileTimelineHeaderChange: "모바일 환경에서 타임라인의 헤더 디자인을 변경"
_bannerDisplay:
all: "전부"
topBottom: "상단 및 하단"
@ -1482,8 +1521,13 @@ _role:
_options:
gtlAvailable: "글로벌 타임라인 보이기"
ltlAvailable: "로컬 타임라인 보이기"
mtlAvailable: "미디어 타임라인 보이기"
ctlAvailable: "고양이 타임라인 보이기"
canPublicNote: "공개 노트 허용"
canInvite: "서버 초대 코드 발행"
inviteLimit: "초대 한도"
inviteLimitCycle: "초대 발급 간격"
inviteExpirationTime: "초대 만료 기간"
canManageCustomEmojis: "커스텀 이모지 관리"
driveCapacity: "드라이브 용량"
alwaysMarkNsfw: "파일을 항상 NSFW로 지정"
@ -1550,6 +1594,7 @@ _ad:
back: "뒤로"
reduceFrequencyOfThisAd: "이 광고의 표시 빈도 낮추기"
hide: "보이지 않음"
timezoneinfo: "요일은 서버의 표준 시간대에 따라 결정됩니다."
_forgotPassword:
enterEmail: "여기에 계정에 등록한 메일 주소를 입력해 주세요. 입력한 메일 주소로 비밀번호를 재설정할 수 있는 링크를 보내드릴 거예요."
ifNoEmail: "만약 메일 주소를 등록하지 않았다면 관리자에게 문의해 주세요."
@ -1610,9 +1655,9 @@ _aboutMisskey:
donate: "CherryPick에 기부하기"
relayServer: "릴레이 서버"
community: "커뮤니티"
_nsfw:
respect: "열람 주의로 설정된 미디어 숨기기"
ignore: "열람 주의 미디어 항상 표시"
_displayOfSensitiveMedia:
respect: "민감한 콘텐츠로 표시된 미디어 숨기기"
ignore: "민감한 콘텐츠로 표시된 미디어 보이기"
force: "미디어 항상 숨기기"
_mfm:
cheatSheet: "MFM 도움말"
@ -1637,9 +1682,9 @@ _mfm:
blockCode: "코드(블록)"
blockCodeDescription: "여러 행의 코드를 문법 강조를 적용하여 블록으로 표시해요."
inlineMath: "수식(인라인)"
inlineMathDescription: "수식(KaTeX) 인라인으로 보이게 해요."
inlineMathDescription: "수식(KaTeX) 인라인으로 보이게 해요."
blockMath: "수식(블록)"
blockMathDescription: "여러 줄의 수식(KaTeX) 블록으로 보이게 해요."
blockMathDescription: "여러 줄의 수식(KaTeX) 블록으로 보이게 해요."
quote: "인용"
quoteDescription: "내용을 인용문으로 표시해요."
emoji: "커스텀 이모지"
@ -2051,6 +2096,7 @@ _timelines:
local: "로컬"
media: "미디어"
social: "소셜"
cat: "고양이"
global: "글로벌"
_play:
new: "Play 만들기"
@ -2171,6 +2217,7 @@ _deck:
introduction: "칼럼을 조합해서 나만의 인터페이스를 구성해 보세요!"
introduction2: "언제든지 화면 우측의 + 버튼을 눌러 새 칼럼을 추가할 수 있어요."
widgetsIntroduction: "칼럼 메뉴의 \"위젯 편집\"에서 위젯을 추가해 주세요"
useSimpleUiForNonRootPages: "루트 이외의 페이지로 접속한 경우 UI 간략화하기"
_columns:
main: "메인"
widgets: "위젯"

View file

@ -20,6 +20,7 @@ noNotes: "ບໍ່ມີຫມາຍເຫດ"
noNotifications: "ບໍ່ມີການແຈ້ງເຕືອນ"
instance: "ອີນສະແຕນ"
settings: "ກຳນົດຄ່າ"
notificationSettings: "ຕັ້ງຄ່າການແຈ້ງເຕືອນ"
basicSettings: "ການຕັ້ງຄ່າພື້ນຖານ"
otherSettings: "ການຕັ້ງຄ່າອື່ນໆ"
openInWindow: "ເປີດຢູ່ໃນປ່ອງຢ້ຽມ"
@ -48,9 +49,15 @@ delete: "ລຶບ"
deleteAndEdit: "ລົບ​ແລະ​ແກ້​ໄຂ​"
deleteAndEditConfirm: "ເຈົ້າ​ແນ່​ໃຈ​ບໍ່? ທີ່ທ່ານຕ້ອງການທີ່ຈະລຶບບັນທຶກນີ້ແລະແກ້ໄຂມັນ ທ່ານອາດຈະສູນເສຍການໂຕ້ຕອບ, ບັນທຶກ, ແລະການຕອບກັບທັງໝົດ"
addToList: "ເພີ່ມໃສ່ລາຍຊື່"
addToAntenna: "ເພີ່ມໃສ່ເສົາອາກາດ"
sendMessage: "ສົ່ງຂໍ້ຄວາມ"
copyRSS: "ສຳເນົາ RSS"
copyUsername: "ສຳເນົາຊື່ຜູ້ໃຊ້"
copyUserId: "ສຳເນົາ ID ຜູ້ໃຊ້"
copyNoteId: "ສຳເນົາ ID ບັນທຶກ"
copyFileId: "ສຳເນົາ ID ໄຟລ໌"
copyFolderId: "ສຳເນົາ ID ໂຟນເດີ"
copyProfileUrl: "ສຳເນົາ URL ໂປຣໄຟລ໌"
searchUser: "ຄົ້ນຫາຜູ້ໃຊ້"
reply: "ຕອບ​ໄປ​ທີ"
loadMore: "ໂຫຼດເພີ່ມເຕີມ"
@ -109,6 +116,7 @@ sensitive: "NSFW"
add: "ເພີ່ມ"
reaction: "ປະຕິກິລິຍາ"
reactions: "ປະຕິກິລິຍາ"
attachCancel: "ເອົາໄຟລ໌ແນບ"
mute: "ປີດສຽງ"
unmute: "ເປີດສຽງ"
block: "ບ໋ອກ"
@ -116,6 +124,10 @@ unblock: "ຍົກເລີກກາຮົບລັອກ"
suspend: "ລະງັບ"
unsuspend: "ເຊົາ​ລະ​ງັບ"
selectList: "ເລືອກບັນຊີລາຍການ"
editList: "ແກ້ໄຂລາຍຊື່"
selectChannel: "ເລືອກຊ່ອງ"
selectAntenna: "ເລືອກເສົາອາກາດ"
editAntenna: "ແກ້ໄຂເສົາອາກາດ"
selectWidget: "ເລືອກວິກເຈັດ"
editWidgets: "ແກ້ໄຂ Widget"
editWidgetsExit: "ສຳເລັດແລ້ວ"
@ -125,6 +137,7 @@ emojis: "ອີໂມຈິ"
emojiName: "ຊື່ Emoji"
emojiUrl: "URL ອີໂມຈິ"
addEmoji: "ຕື່ມອີໂມຈິ"
settingGuide: "ການຕັ້ງຄ່າທີ່ແນະນໍາ"
flagAsBot: "ໝາຍບັນຊີນີ້ເປັນບັອດ"
flagAsCat: "ໝາຍບັນຊີນີ້ເປັນແມວ"
flagAsCatDescription: "ເປີດໃຊ້ຕົວເລືອກນີ້ເພື່ອໝາຍບັນຊີນີ້ເປັນແມວ"
@ -133,10 +146,13 @@ flagShowTimelineRepliesDescription: "ສະແດງການຕອບກັບ
autoAcceptFollowed: "ອະນຸມັດອັດຕະໂນມັດຕາມຄຳຮ້ອງຂໍຈາກຜູ້ໃຊ້ທີ່ທ່ານກຳລັງຕິດຕາມຢູ່"
addAccount: "ເພີ່ມບັນຊີ"
loginFailed: "ການເຂົ້າສູ່ລະບົບບໍ່ສຳເລັດ"
showOnRemote: "ເບິ່ງຢູ່ໃນຕົວຢ່າງໄລຍະໄກ"
general: "ທົ່ວໄປ"
wallpaper: "ພາບພື້ນຫລັງ"
setWallpaper: "ຕັ້ງເປັນພາບພື້ນຫຼັງ"
removeWallpaper: "ລຶບຮູບວໍເປເປີອອກ"
searchWith: "ຊອກຫາ: {q}"
youHaveNoLists: "ທ່ານ​ບໍ່​ມີ​ລາຍ​ການ​ໃດໆ​"
proxyAccount: "ບັນຊີພຣັອກຊີ"
host: "ໂຮດສ"
selectUser: "ເລືອກຜູ້ໃຊ້"
@ -155,7 +171,9 @@ operations: "ການດຳເນີນງານ"
software: "ຊອບແວ"
version: "ສະບັບ"
metadata: "Metadata"
withNFiles: "{n} ໄຟລ໌(s)"
monitor: "ຈໍພາບ"
jobQueue: "ຄິວວຽກ"
cpuAndMemory: "CPU ແລະ ຫນ່ວຍຄວາມຈໍາ"
network: "ເຄືອຂ່າຍ"
disk: "ດິສກ໌"
@ -248,7 +266,6 @@ inputNewDescription: "ໃສ່ຄຳບັນຍາຍໃໝ່"
inputNewFolderName: "ໃສ່ຊື່ໂຟນເດີໃໝ່"
circularReferenceFolder: "ໂຟນເດີປາຍທາງແມ່ນໂຟນເດີຍ່ອຍຂອງໂຟນເດີທີ່ທ່ານຕ້ອງການຍ້າຍ"
rename: "ປ່ຽນຊື່"
nsfw: "NSFW"
watch: "ເບິ່ງ"
unwatch: "ຢຸດເບິ່ງ"
accept: "ອະນຸຍາດ"
@ -344,6 +361,7 @@ _widgets:
timeline: "​ເສັ້ນກຳ​ນົດ​ເວ​ລາ​"
activity: "ກິດຈະກຳ"
federation: "ສະຫະພັນ"
jobQueue: "ຄິວວຽກ"
_userList:
chooseList: "ເລືອກບັນຊີລາຍການ"
_cw:

View file

@ -20,6 +20,7 @@ noNotes: "Geen notities"
noNotifications: "Geen meldingen"
instance: "Server"
settings: "Instellingen"
notificationSettings: "Notificatie instellingen"
basicSettings: "Basisinstellingen"
otherSettings: "Overige instellingen"
openInWindow: "In een venster openen"
@ -48,8 +49,15 @@ delete: "Verwijderen"
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."
addToList: "Aan lijst toevoegen"
addToAntenna: "Voeg toe aan antenne"
sendMessage: "Verstuur bericht"
copyRSS: "Kopieer RSS"
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"
reply: "Antwoord"
loadMore: "Laad meer"
@ -296,7 +304,6 @@ copyUrl: "URL kopiëren"
rename: "Hernoemen"
avatar: "Avatar"
banner: "Banner"
nsfw: "NSFW"
whenServerDisconnected: "Wanneer de verbinding met de server wordt onderbroken"
disconnectedFromServer: "Verbinding met de server onderbroken."
reload: "Verversen"

3
locales/package.json Normal file
View file

@ -0,0 +1,3 @@
{
"type": "module"
}

View file

@ -299,7 +299,6 @@ copyUrl: "Skopiuj adres URL"
rename: "Zmień nazwę"
avatar: "Awatar"
banner: "Baner"
nsfw: "NSFW"
whenServerDisconnected: "Po utracie połączenia z serwerem"
disconnectedFromServer: "Utracono połączenie z serwerem."
reload: "Odśwież"
@ -969,10 +968,6 @@ _aboutMisskey:
donate: "Przekaż darowiznę na Misskey"
morePatrons: "Naprawdę doceniam wsparcie ze strony wielu niewymienionych tu osób. Dziękuję! 🥰"
patrons: "Wspierający"
_nsfw:
respect: "Ukrywaj media NSFW"
ignore: "Nie ukrywaj mediów NSFW"
force: "Ukrywaj wszystkie media"
_mfm:
cheatSheet: "Ściąga MFM"
intro: "MFM to język składniowy wyjątkowy dla Misskey, który może być użyty w wielu miejscach. Tu znajdziesz listę wszystkich możliwych elementów składni MFM."

File diff suppressed because it is too large Load diff

View file

@ -294,7 +294,6 @@ copyUrl: "Copiază URL"
rename: "Redenumește"
avatar: "Avatar"
banner: "Banner"
nsfw: "NSFW"
whenServerDisconnected: "Când pierzi conexiunea cu serverul"
disconnectedFromServer: "Conecțiunea cu serverul a fost pierdută"
reload: "Reîncarcă"

View file

@ -49,9 +49,15 @@ delete: "Удалить"
deleteAndEdit: "Удалить и отредактировать"
deleteAndEditConfirm: "Удалить эту заметку и создать отредактированную? Все реакции, ссылки и ответы на существующую будут будут потеряны."
addToList: "Добавить в список"
addToAntenna: "Добавить к антенне"
sendMessage: "Отправить сообщение"
copyRSS: "Скопировать RSS"
copyUsername: "Скопировать имя пользователя"
copyUserId: "Скопировать ID пользователя"
copyNoteId: "Скопировать ID заметки"
copyFileId: "Скопировать ID файла"
copyFolderId: "Скопировать ID папки"
copyProfileUrl: "Скопировать URL профиля "
searchUser: "Поиск людей"
reply: "Ответить"
loadMore: "Показать еще"
@ -134,8 +140,10 @@ unblockConfirm: "Разблокировать этот аккаунт?"
suspendConfirm: "Заморозить этот аккаунт?"
unsuspendConfirm: "Разморозить этот аккаунт?"
selectList: "Выберите список"
editList: "Редактировать список"
selectChannel: "Выберите канал"
selectAntenna: "Выберите антенну"
editAntenna: "Редактировать антенну"
selectWidget: "Выберите виджет"
editWidgets: "Редактировать виджеты"
editWidgetsExit: "Готово"
@ -148,6 +156,8 @@ addEmoji: "Добавить эмодзи"
settingGuide: "Рекомендуемые настройки"
cacheRemoteFiles: "Кешировать внешние файлы"
cacheRemoteFilesDescription: "Когда эта настройка отключена, файлы с других сайтов будут загружаться прямо оттуда. Это сэкономит место на сервере, но увеличит трафик, так как не будут создаваться эскизы."
cacheRemoteSensitiveFiles: "Кешировать внешние файлы"
cacheRemoteSensitiveFilesDescription: "Описание удаленных внешних файлов в кэше"
flagAsBot: "Аккаунт бота"
flagAsBotDescription: "Включите, если этот аккаунт управляется программой. Это позволит системе CherryPick учитывать это, а также поможет разработчикам других ботов предотвратить бесконечные циклы взаимодействия."
flagAsCat: "Аккаунт кота"
@ -309,7 +319,7 @@ copyUrl: "Копировать ссылку"
rename: "Переименовать"
avatar: "Аватар"
banner: "Шапка"
nsfw: "Содержимое не для всех"
displayOfSensitiveMedia: "Определение деликатного контента"
whenServerDisconnected: "Когда соединение с сервером потеряно"
disconnectedFromServer: "Разорвано соединение с сервером"
reload: "Перезагрузить"
@ -802,6 +812,7 @@ noMaintainerInformationWarning: "Не заполнены сведения об
noBotProtectionWarning: "Ботозащита не настроена"
configure: "Настроить"
postToGallery: "Опубликовать в галерею"
postToHashtag: "Опубликовать пост с этим хештегом"
gallery: "Галерея"
recentPosts: "Недавние публикации"
popularPosts: "Популярные публикации"
@ -845,6 +856,8 @@ breakFollow: "Отписка"
breakFollowConfirm: "Удалить из подписок пользователя ?"
itsOn: "Включено"
itsOff: "Выключено"
on: "Вкл"
off: "Выкл"
emailRequiredForSignup: "Для регистрации учётной записи нужен адрес электронной почты"
unread: "Непрочитанное"
filter: "Фильтры"
@ -1001,6 +1014,7 @@ cannotBeChangedLater: "Это нельзя изменить позже"
reactionAcceptance: "Принятие реакций"
likeOnly: "Только лайки"
likeOnlyForRemote: "Только лайки с удалённых серверов"
nonSensitiveOnly: "Безопасный серфинг"
rolesAssignedToMe: "Мои роли"
resetPasswordConfirm: "Сбросить пароль?"
sensitiveWords: "Чувствительные слова"
@ -1021,7 +1035,15 @@ noteIdOrUrl: "ID или ссылка на заметку"
video: "Видео"
videos: "Видео"
dataSaver: "Экономия трафика"
accountMigration: "Перенести учётную запись"
accountMoved: "Учетная запись перенесена"
operationForbidden: "Эта операция невозможна."
addMemo: "Добавить заметку"
editMemo: "Редактировать заметку"
reactionsList: "Реакции"
renotesList: "Репосты"
notificationDisplay: "Отображение уведомления"
leftTop: "Верхний левый угол"
horizontal: "Сбоку"
youFollowing: "Подписки"
options: "Настройки ролей"
@ -1409,10 +1431,6 @@ _aboutMisskey:
donate: "Пожертвование на Misskey"
morePatrons: "Большое спасибо и многим другим, кто принял участие в этом проекте! 🥰"
patrons: "Материальная поддержка"
_nsfw:
respect: "Скрывать содержимое не для всех"
ignore: "Показывать содержимое не для всех"
force: "Скрывать вообще все файлы"
_mfm:
cheatSheet: "Подсказка по разметке MFM"
intro: "MFM — язык оформления текста, который придуман специально для Misskey и готов для применения во многих местах. На этой странице собраны и кратко изложены способы его использовать."

View file

@ -303,7 +303,6 @@ copyUrl: "Kopírovať URL"
rename: "Premenovať"
avatar: "Avatar"
banner: "BAnner"
nsfw: "NSFW"
whenServerDisconnected: "Keď sa stratí spojenie so serverom"
disconnectedFromServer: "Spojenie so serverom bolo prerušené"
reload: "Obnoviť"
@ -1023,10 +1022,6 @@ _aboutMisskey:
donate: "Podporiť Misskey"
morePatrons: "Takisto oceňujeme podporu mnoých ďalších, ktorí tu nie sú uvedení. Ďakujeme! 🥰"
patrons: "Prispievatelia"
_nsfw:
respect: "Skryť NSFW médiá"
ignore: "Neskrývať NSFW médiá"
force: "Skryť všetky médiá"
_mfm:
cheatSheet: "MFM Cheatsheet"
intro: "MFM je Misskey exkluzívny značkovací jazyk, ktorý sa dá používať na viacerých miestach. Tu môžete vidieť zoznam všetkej dostupnej MFM syntaxe."

View file

@ -20,6 +20,7 @@ noNotes: "Inga noteringar"
noNotifications: "Inga notifikationer"
instance: "Instanser"
settings: "Inställningar"
notificationSettings: "Notifieringsinställningar"
basicSettings: "Basinställningar"
otherSettings: "Andra inställningar"
openInWindow: "Öppna i ett fönster"
@ -51,6 +52,10 @@ addToList: "Lägg till i lista"
sendMessage: "Skicka ett meddelande"
copyRSS: "Kopiera RSS"
copyUsername: "Kopiera användarnamn"
copyUserId: "Kopiera användar-ID"
copyNoteId: "Kopiera noter-ID"
copyFileId: "Kopiera Fil-ID"
copyFolderId: "Kopiera mapp-ID"
searchUser: "Sök användare"
reply: "Svara"
loadMore: "Ladda mer"
@ -103,6 +108,8 @@ renoted: "Omnoterad."
cantRenote: "Inlägget kunde inte bli omnoterat."
cantReRenote: "En omnotering kan inte bli omnoterad."
quote: "Citat"
inChannelRenote: "Omnotera inom kanalen"
inChannelQuote: "I kanal citat"
pinnedNote: "Fästad not"
pinned: "Fäst till profil"
you: "Du"
@ -129,7 +136,10 @@ unblockConfirm: "Är du säkert att du vill avblockera kontot?"
suspendConfirm: "Är du säker att du vill suspendera detta konto?"
unsuspendConfirm: "Är du säker att du vill avsuspendera detta konto?"
selectList: "Välj lista"
editList: "Redigera lista"
selectChannel: "Välj en kanal"
selectAntenna: "Välj en antenn"
editAntenna: "Redigera en antenn"
selectWidget: "Välj en widget"
editWidgets: "Redigera widgets"
editWidgetsExit: "Avsluta redigering"
@ -256,6 +266,9 @@ noMoreHistory: "Det finns ingen mer historik"
startMessaging: "Starta en chatt"
nUsersRead: "läst av {n}"
agreeTo: "Jag accepterar {0}"
agree: "Överens"
termsOfService: "Användarvillkor"
start: "Kom igång"
home: "Hem"
remoteUserCaution: "Då denna användaren kommer från en fjärrinstans, kan informationen visad vara ofullständig."
activity: "Aktivitet"
@ -297,10 +310,10 @@ copyUrl: "Kopiera URL"
rename: "Byt namn"
avatar: "Profilbild"
banner: "Banner"
nsfw: "Känsligt innehåll"
reload: "Ladda om"
doNothing: "Ignorera"
reloadConfirm: "Vill du ladda om tidslinjen?"
watch: "Titta"
accept: "Tillåt"
reject: "Neka"
normal: "Normal"
@ -320,16 +333,31 @@ connectService: "Anslut"
disconnectService: "Koppla från"
enableLocalTimeline: "Aktivera lokal tidslinje"
enableGlobalTimeline: "Aktivera global tidslinje"
registration: "Registrera"
enableRegistration: "Aktivera registrering av nya användare"
invite: "Inbjudan"
inMb: "I megabyte"
iconUrl: "URL till profilbilden"
bannerUrl: "URL till banner-bilden"
basicInfo: "Grundläggande info"
pinnedUsers: "Fästa användare"
pinnedPages: "Fästa sidor"
pinnedNotes: "Fästad not"
hcaptcha: "hCaptcha"
enableHcaptcha: "Aktivera hCaptcha"
hcaptchaSiteKey: "Webbplatsnyckel"
hcaptchaSecretKey: "Hemlig nyckel"
recaptcha: "reCAPTCHA"
enableRecaptcha: "Aktivera reCAPTCHA"
recaptchaSiteKey: "Webbplatsnyckel"
recaptchaSecretKey: "Hemlig nyckel"
turnstile: "Turnstile"
enableTurnstile: "Aktivera Turnstile"
turnstileSiteKey: "Webbplatsnyckel"
turnstileSecretKey: "Hemlig nyckel"
antennas: "Antenner"
manageAntennas: "Hantera Antenner"
name: "Namn"
antennaSource: "Antennkälla"
antennaKeywords: "Nyckelord att lyssna efter"
antennaExcludeKeywords: "Nyckelord att exkludera"
@ -338,39 +366,112 @@ notifyAntenna: "Notifiera om nya noter"
withFileAntenna: "Endast noter med filer"
enableServiceworker: "Aktivera pushnotiser i denna webbläsaren"
antennaUsersDescription: "Ange ett användarnamn per linje"
withReplies: "Med svar"
notesAndReplies: "Inlägg och svar"
silence: "Tystnad"
recentlyUpdatedUsers: "Nyligen aktiva användare"
recentlyRegisteredUsers: "Nyligen registrerade användare"
exploreFediverse: "Utforska Fediverse"
popularTags: "Populära taggar"
userList: "Listor"
about: "Om"
aboutMisskey: "Om CherryPick"
administrator: "Administratör"
2fa: "Tvåfaktorsautentisering"
totp: "Autentiseringsapp"
moderator: "Moderator"
passwordLessLogin: "Lösenordsfri inloggning"
passwordLessLoginDescription: "Tillåter lösenordsfri inloggning med endast en säkerhetsnyckel eller en passkey."
resetPassword: "Återställ Lösenord"
newPasswordIs: "Det nya lösenordet är \"{password}\""
share: "Dela"
help: "Hjälp"
close: "Stäng"
invites: "Inbjudan"
members: "Medlemmar"
transfer: "Överför"
text: "Text"
enable: "Aktivera"
next: "Nästa"
invitations: "Inbjudan"
invitationCode: "Inbjudningskod"
available: "Tillgängligt"
weakPassword: "Svagt Lösenord"
normalPassword: "Medel Lösenord"
strongPassword: "Starkt Lösenord"
signinFailed: "Kan inte logga in. Det angivna användarnamnet eller lösenordet är felaktigt."
or: "eller"
language: "Språk"
aboutX: "Om {x}"
category: "Kategori"
tags: "Taggar"
createAccount: "Skapa ett konto"
existingAccount: "Existerande konto"
regenerate: "Regenerera"
fontSize: "Textstorlek"
openImageInNewTab: "Öppna bild i ny flik"
clientSettings: "Klientinställningar"
accountSettings: "Kontoinställningar"
numberOfDays: "Antal dagar"
deleteAll: "Radera alla"
sounds: "Ljud"
sound: "Ljud"
listen: "Lyssna"
none: "Ingen"
volume: "Volym"
chooseEmoji: "Välj en emoji"
recentUsed: "Senast använd"
install: "Installera"
uninstall: "Avinstallera"
menu: "Meny"
serviceworkerInfo: "Måste vara aktiverad för pushnotiser."
enableInfiniteScroll: "Ladda mer automatiskt"
enablePlayer: "Öppna videospelare"
permission: "Behörigheter"
enableAll: "Aktivera alla"
edit: "Ändra"
enableEmail: "Aktivera epost-utskick"
email: "E-post"
smtpHost: "Värd"
smtpUser: "Användarnamn"
smtpPass: "Lösenord"
emptyToDisableSmtpAuth: "Lämna användarnamn och lösenord tomt för att avaktivera SMTP verifiering"
logs: "Logg"
channel: "kanal"
create: "Skapa"
other: "Mer"
send: "Skicka"
openInNewTab: "Öppna i ny flik"
createNew: "Skapa ny"
i18nInfo: "CherryPick översätts till många olika språk av volontärer. Du kan hjälpa till med översättningen på {link}."
accountInfo: "Kontoinformation"
clips: "Klipp"
duplicate: "Duplicera"
reloadToApplySetting: "Inställningen tillämpas efter sidan laddas om. Vill du göra det nu?"
clearCache: "Rensa cache"
onlineUsersCount: "{n} användare är online"
nNotes: "{n} Noter"
backgroundColor: "Bakgrundsbild"
textColor: "Text"
youAreRunningUpToDateClient: "Klienten du använder är uppdaterat."
newVersionOfClientAvailable: "Ny version av klienten är tillgänglig."
publish: "Publicera"
typingUsers: "{users} skriver"
info: "Om"
enabled: "Aktiverad"
user: "Användare"
customCssWarn: "Den här inställningen borde bara ändrats av en som har rätta kunskaper. Om du ställer in det här fel så kan klienten sluta fungera rätt."
global: "Global"
squareAvatars: "Visa fyrkantiga profilbilder"
sent: "Skicka"
misskeyUpdated: "CherryPick har uppdaterats!"
incorrectPassword: "Fel lösenord."
welcomeBackWithName: "Välkommen tillbaka, {name}"
clickToFinishEmailVerification: "Tryck på [{ok}] för att slutföra bekräftelsen på e-postadressen."
searchByGoogle: "Sök"
file: "Filer"
cannotUploadBecauseNoFreeSpace: "Kan inte ladda upp filen för att det finns inget lagringsutrymme kvar."
cannotUploadBecauseExceedsFileSizeLimit: "Kan inte ladda upp filen för att den är större än filstorleksgränsen."
enableAutoSensitive: "Automatisk NSFW markering"
enableAutoSensitiveDescription: "Tillåter automatiskt detektering och marketing av NSFW media genom Maskininlärning när möjligt. Även om denna inställningen är avaktiverad, kan det vara aktiverat på hela instansen."
pushNotification: "Pushnotiser"
@ -381,12 +482,16 @@ pushNotificationNotSupported: "Din webbläsare eller instans har inte stöd för
windowMaximize: "Maximera"
windowMinimize: "Minimera"
windowRestore: "Återställ"
pleaseDonate: "CherryPick ä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?"
dataSaver: "Databesparing"
_achievements:
_types:
_open3windows:
title: "Flera Fönster"
description: "Ha minst 3 fönster öppna samtidigt"
_ffVisibility:
public: "Publicera"
_email:
_follow:
title: "följde dig"
@ -426,6 +531,7 @@ _visibility:
home: "Hem"
followers: "Följare"
_profile:
name: "Namn"
username: "Användarnamn"
changeAvatar: "Ändra profilbild"
changeBanner: "Ändra banner"
@ -461,6 +567,8 @@ _deck:
tl: "Tidslinje"
antenna: "Antenner"
list: "Listor"
channel: "kanal"
mentions: "Omnämningar"
_webhookSettings:
name: "Namn"
active: "Aktiverad"

View file

@ -1,9 +1,9 @@
---
_lang_: "ภาษาไทย"
headlineMisskey: "เชื่อมต่อเครือข่ายโดยโน้ต"
introMisskey: "ยินดีต้อนรับจ้าาา! CherryPick เป็นบริการไมโครบล็อกโอเพ่นซอร์ส แบบการกระจายอำนาจ\nสร้าง \"โน้ต\" เพื่อแบ่งปันความคิดของคุณกับทุกคนรอบตัวคุณกันเถอะ 📡\nด้วยการ \"รีแอคชั่นผู้คน\" คุณยังสามารถแสดงความรู้สึกของคุณเกี่ยวกับบันทึกของทุกคนได้อย่างรวดเร็ว 👍\n\nแล้วมาท่องสำรวจโลกใบใหม่กันเถอะ! 🚀"
headlineMisskey: "เชื่อมต่อระบบ Network ด้วย Note"
introMisskey: "ยินดีต้อนรับทุกคนจ้า! CherryPick คือ บริการไมโครบล็อกกิ้ง (MicroBlogging) แบบกระจายศูนย์อำนาจ (Decentralized) \n\nเขียน \"โน้ต (Note)\" เพื่อส่งต่อเรื่องราวของคุณให้ทั้งโลกได้รับรู้📡\nและอย่าลืมที่จะ \"React\" กับเรื่องราวของคนอื่น ๆ ด้วย! 👍\n\nมุ่งสู่โลกใบใหม่กันเถอะ🚀"
poweredByMisskeyDescription: "{name} เป็นส่วนหนึ่งในบริการที่ถูกขับเคลื่อนโดยแพลตฟอร์มโอเพ่นซอร์ส <b>CherryPick</b> (เรียกว่า \"อินสแตนซ์ CherryPick\")"
monthAndDay: "{เดือน}/{วัน}"
monthAndDay: "{month}/{day}"
search: "ค้นหา"
notifications: "การเเจ้งเตือน"
username: "ชื่อผู้ใช้"
@ -15,7 +15,7 @@ gotIt: "เข้าใจแล้ว !"
cancel: "ยกเลิก"
noThankYou: "ไม่เป็นไร"
enterUsername: "ใส่ชื่อผู้ใช้"
renotedBy: "รีโน้ตโดย {ผู้ใช้}"
renotedBy: "รีโน้ตโดย {user}"
noNotes: "ไม่มีโน้ต"
noNotifications: "ไม่มีการแจ้งเตือน"
instance: "อินสแตนซ์"
@ -49,9 +49,15 @@ delete: "ลบ"
deleteAndEdit: "ลบและแก้ไข"
deleteAndEditConfirm: "นายแน่ใจแล้วเหรอ? ว่าต้องการลบโน้ตนี้และแก้ไข คุณอาจจะสูญเสียการโต้ตอบ, โน้ต, และการตอบกลับทั้งหมดได้นะ"
addToList: "เพิ่มในลิสต์"
addToAntenna: "เพิ่มไปยังเสาอากาศ"
sendMessage: "ส่งข้อความ"
copyRSS: "คัดลอก RSS"
copyUsername: "คัดลอกชื่อผู้ใช้"
copyUserId: "คัดลอก ID ผู้ใช้"
copyNoteId: "คัดลอก ID โน้ต "
copyFileId: "คัดลอกไฟล์ ID"
copyFolderId: "คัดลอกโฟลเดอร์ ID"
copyProfileUrl: "คัดลอกโปรไฟล์ URL"
searchUser: "ค้นหาผู้ใช้งาน"
reply: "ตอบกลับ"
loadMore: "โหลดเพิ่มเติม"
@ -73,8 +79,8 @@ unfollowConfirm: "นายแน่ใจแล้วหรอว่าต้
exportRequested: "เมื่อคุณได้ร้องขอการส่งออก อาจจะต้องใช้เวลาสักครู่ และจะถูกเพิ่มในไดรฟ์ของคุณเมื่อเสร็จสิ้นแล้ว"
importRequested: "เมื่อคุณได้ร้องขอการนำเข้า อาจจะต้องใช้เวลาสักครู่นะ"
lists: "รายการ"
noLists: "คุณไม่มีลิสต์ใดนะ"
note: "ตัวโน้ต"
noLists: "คุณไม่มีลิสต์ใด ๆ"
note: " โน้ต"
notes: "ตัวโน้ต"
following: "กำลังติดตาม"
followers: "ผู้ติดตาม"
@ -92,7 +98,7 @@ enterListName: "ใส่ชื่อสำหรับรายการลิ
privacy: "ความเป็นส่วนตัว"
makeFollowManuallyApprove: "ติดตามคำขอที่ต้องได้รับการอนุมัติ"
defaultNoteVisibility: "การมองเห็นที่เป็นค่าเริ่มต้น"
follow: "กำลังติดตาม"
follow: "ติดตาม"
followRequest: "ส่งคำขอติดตาม"
followRequests: "ส่งคำขอติดตาม"
unfollow: "เลิกติดตาม"
@ -100,7 +106,7 @@ followRequestPending: "กำลังรอดำเนินการร้อ
enterEmoji: "ใส่อีโมจิ"
renote: "รีโน้ต"
unrenote: "เลิกรีโน้ต"
renoted: "รีโน้ตแล้วนะ"
renoted: "รีโน้ตแล้ว"
cantRenote: "โพสต์นี้ไม่สามารถรีโน้ตไว้ใหม่ได้นะ"
cantReRenote: "ไม่สามารถรีโน้ตเอาไว้ใหม่ได้นะ"
quote: "อ้างคำพูด"
@ -108,7 +114,7 @@ inChannelRenote: "รีโน้ตช่องแชลแนลเท่า
inChannelQuote: "อ้างช่องเท่านั้น"
pinnedNote: "โน้ตที่ปักหมุดเอาไว้"
pinned: "ปักหมุดไปยังโปรไฟล์"
you: "ตัวเอง"
you: "คุณ"
clickToShow: "คลิกเพื่อแสดง"
sensitive: "เนื้อหาที่ละเอียดอ่อน NSFW"
add: "เพิ่ม"
@ -134,8 +140,10 @@ unblockConfirm: "คุณแน่ใจแล้วเหรอ? ว่าต
suspendConfirm: "นายแน่ใจแล้วเหรอว่าต้องการระงับบัญชีนี้อ่ะ?"
unsuspendConfirm: "นายแน่ใจแล้วหรอ? ว่าต้องการยกเลิกการระงับบัญชีนี้"
selectList: "เลือกรายการ"
editList: "แก้ไขรายการ"
selectChannel: "เลือกแชนแนล"
selectAntenna: "เลือกเสาอากาศ"
editAntenna: "แก้ไขเสาอากาศ"
selectWidget: "เลือกวิดเจ็ต"
editWidgets: "แก้ไขวิดเจ็ต"
editWidgetsExit: "เรียบร้อย"
@ -148,6 +156,8 @@ addEmoji: "แทรกอีโมจิ"
settingGuide: "การตั้งค่าที่แนะนำ"
cacheRemoteFiles: "แคชไฟล์ระยะไกล"
cacheRemoteFilesDescription: "เมื่อปิดใช้งานการตั้งค่านี้ ไฟล์ระยะไกลนั้นจะถูกโหลดโดยตรงจากอินสแตนซ์ระยะไกล แต่กรณีการปิดใช้งานนี้จะช่วยลดปริมาณการใช้พื้นที่จัดเก็บข้อมูล แต่เพิ่มปริมาณการใช้งาน เพราะเนื่องจากจะไม่มีการสร้างภาพขนาดย่อ"
cacheRemoteSensitiveFiles: "ไฟล์ระยะไกลที่มีความละเอียดอ่อนแคช"
cacheRemoteSensitiveFilesDescription: "เมื่อปิดการใช้งานแล้วการตั้งค่านี้ ไฟล์รีโมตที่มีความละเอียดอ่อนนั้นจะถูกโหลดโดยตรงจากอินสแตนซ์ระยะไกลโดยที่ไม่มีการแคช"
flagAsBot: "ทำเครื่องหมายบอกว่าบัญชีนี้เป็นบอท"
flagAsBotDescription: "การเปิดใช้งานตัวเลือกนี้หากบัญชีนี้ถูกควบคุมโดยนักเขียนโปรแกรม หรือ ถ้าหากเปิดใช้งาน มันจะทำหน้าที่เป็นแฟล็กสำหรับนักพัฒนารายอื่นๆ และเพื่อป้องกันการโต้ตอบแบบไม่มีที่สิ้นสุดกับบอทตัวอื่นๆ และยังสามารถปรับเปลี่ยนระบบภายในของ CherryPick เพื่อปฏิบัติต่อบัญชีนี้เป็นบอท"
flagAsCat: "ทำเครื่องหมายบอกว่าบัญชีนี้เป็นแมว"
@ -164,7 +174,7 @@ wallpaper: "วอลล์เปเปอร์"
setWallpaper: "ตั้งวอลเปเปอร์"
removeWallpaper: "นำวอลเปเปอร์ออก"
searchWith: "ค้นหา: {q}"
youHaveNoLists: "รายการนี้ว่างเปล่า"
youHaveNoLists: "คุณไม่มีลิสต์ใด ๆ "
followConfirm: "คุณแน่ใจแล้วหรอว่าต้องการที่จะติดตาม {name}?"
proxyAccount: "บัญชี พร็อกซี่"
proxyAccountDescription: "บัญชีพร็อกซี่ คือ บัญชีที่จะทำหน้าที่เป็นผู้ติดตามระยะไกลสำหรับผู้ใช้งานที่อยู่ภายใต้ด้วยเงื่อนไขบางอย่าง ยกตัวอย่าง เช่น เมื่อมีผู้ใช้งานนั้นได้เพิ่มผู้ใช้งานจากระยะไกลลงในรายการ แต่กิจกรรมของผู้ใช้ในระยะไกลนั้นจะไม่ถูกส่งไปยังอินสแตนซ์หากไม่มีผู้ใช้งานในพื้นที่ติดตามผู้ใช้รายนั้น ดังนั้นบัญชีพร็อกซีนี้จะติดตามแทน"
@ -173,7 +183,7 @@ selectUser: "เลือกผู้ใช้งาน"
recipient: "ผู้รับ"
annotation: "ความคิดเห็น"
federation: "เฟดิเวิร์ส"
instances: "ตัวอย่าง"
instances: "Server"
registeredAt: "จดทะเบียนที่"
latestRequestReceivedAt: "ได้รับคำขอล่าสุดไปแล้ว"
latestStatus: "สถานะล่าสุด"
@ -186,7 +196,7 @@ blockThisInstance: "บล็อกอินสแตนซ์นี้"
operations: "ดำเนินการ"
software: "ซอฟต์แวร์"
version: "เวอร์ชั่น"
metadata: "ข้อมูลเมตา"
metadata: "Metadata"
withNFiles: "{n} ไฟล์(s)"
monitor: "มอนิเตอร์"
jobQueue: "คิวงาน"
@ -213,7 +223,7 @@ intro: "การติดตั้ง CherryPick เสร็จสิ้นแ
done: "เสร็จสิ้น"
processing: "กำลังประมวลผล..."
preview: "แสดงตัวอย่าง"
default: "ค่าตั้งต้น"
default: "ค่าเริ่มต้น"
defaultValueIs: "ค่าเริ่มต้น: {value}"
noCustomEmojis: "ไม่มีอีโมจิ"
noJobs: "ไม่มีชิ้นงาน"
@ -234,10 +244,10 @@ currentPassword: "รหัสผ่านปัจจุบัน"
newPassword: "รหัสผ่านใหม่"
newPasswordRetype: "ใส่รหัสผ่านใหม่อีกครั้ง"
attachFile: "แนบไฟล์"
more: "เพิ่มเติม!"
more: "เพิ่มเติม"
featured: "ไฮไลท์"
usernameOrUserId: "ชื่อผู้ใช้หรือรหัสผู้ใช้งาน"
noSuchUser: "ไม่มีผู้ใช้นี้อยู่ในระบบ"
noSuchUser: "ไม่พบผู้ใช้"
lookup: "การค้นหา"
announcements: "ประกาศ"
imageUrl: "url รูปภาพ"
@ -282,7 +292,7 @@ themeForLightMode: "ธีมที่จะใช้ในโหมดแสง
themeForDarkMode: "ธีมที่จะใช้ในโหมดมืด"
light: "สว่าง"
dark: "มืด"
lightThemes: "ธีมสีสว่าง"
lightThemes: "ธีมสว่าง"
darkThemes: "ธีมมืด"
syncDeviceDarkMode: "ซิงค์โหมดมืดด้วยการตั้งค่ากับอุปกรณ์"
drive: "ไดรฟ์"
@ -309,7 +319,7 @@ copyUrl: "คัดลอก URL"
rename: "เปลี่ยนชื่อ"
avatar: "ไอคอน"
banner: "แบนเนอร์"
nsfw: "เนื้อหาที่ละเอียดอ่อน NSFW"
displayOfSensitiveMedia: "แสดงผลสื่อละเอียดอ่อน"
whenServerDisconnected: "สูญเสียการเชื่อมต่อกับเซิร์ฟเวอร์"
disconnectedFromServer: "ถูกตัดการเชื่อมต่อออกจากเซิร์ฟเวอร์"
reload: "รีโหลด"
@ -319,7 +329,7 @@ watch: "ดู"
unwatch: "หยุดดู"
accept: "ยอมรับ"
reject: "ปฏิเสธ"
normal: "โหมดปกติ"
normal: "ปกติ"
instanceName: "ชื่อ อินสแตนซ์"
instanceDescription: "คำอธิบายอินสแตนซ์"
maintainerName: "ผู้ดูแล"
@ -328,9 +338,9 @@ tosUrl: "เงื่อนไขการให้บริการ URL"
thisYear: "ปีนี้"
thisMonth: "เดือนนี้"
today: "วันนี้"
dayX: "{วัน}"
monthX: "{เดือน}"
yearX: "{ปี}"
dayX: "{day}"
monthX: "เดือน {month}"
yearX: "{year}"
pages: "หน้า"
integration: "รวบรวม"
connectService: "เชื่อมต่อ"
@ -802,6 +812,7 @@ noMaintainerInformationWarning: "ข้อมูลผู้ดูแลไม
noBotProtectionWarning: "ไม่ได้กำหนดค่าการป้องกันบอทนะ"
configure: "กำหนดค่า"
postToGallery: "สร้างโพสต์แกลเลอรี่ใหม่"
postToHashtag: "โพสต์ไปที่แฮชแท็กนี้"
gallery: "แกลเลอรี่"
recentPosts: "โพสต์ล่าสุด"
popularPosts: "โพสต์ติดอันดับ"
@ -835,6 +846,7 @@ translatedFrom: "แปลมาจาก {x}"
accountDeletionInProgress: "กำลังดำเนินการลบบัญชีอยู่"
usernameInfo: "ชื่อที่ระบุบัญชีของคุณจากผู้อื่นในเซิร์ฟเวอร์นี้ คุณสามารถใช้ตัวอักษร (a~z, A~Z), ตัวเลข (0~9) หรือขีดล่าง (_) ชื่อผู้ใช้ไม่สามารถเปลี่ยนแปลงได้ในภายหลัง"
aiChanMode: "โหมด Ai "
devMode: "โหมดนักพัฒนา"
keepCw: "เก็บคำเตือนเนื้อหา"
pubSub: "บัญชีผับ/ย่อย"
lastCommunication: "การสื่อสารครั้งสุดท้ายล่าสุด"
@ -844,6 +856,8 @@ breakFollow: "ลบผู้ติดตาม"
breakFollowConfirm: "ลบผู้ติดตามนี้ออกจริงหรอ?"
itsOn: "เปิดใช้งาน"
itsOff: "ปิดใช้งาน"
on: "เปิด"
off: "ปิด"
emailRequiredForSignup: "จำเป็นต้องการใช้ที่อยู่อีเมลสำหรับการสมัคร"
unread: "ไม่ได้อ่าน"
filter: "กรอง"
@ -864,7 +878,7 @@ hide: "ซ่อน"
leaveGroup: "ออกจากกลุ่ม"
leaveGroupConfirm: "คุณแน่ใจหรอว่าต้องการออกจาก \"{name}\""
useDrawerReactionPickerForMobile: "แสดงผล ตัวเลือกปฏิกิริยาเป็นลิ้นชักบนมือถือ"
welcomeBackWithName: "ยินดีต้อนรับการกลับมานะคะ, {name}"
welcomeBackWithName: "ยินดีต้อนรับการกลับมานะคะ, {name}"
clickToFinishEmailVerification: "กรุณาคลิก [{ok}] เพื่อดำเนินการยืนยันอีเมลให้เสร็จสมบูรณ์นะ"
overridedDeviceKind: "ประเภทอุปกรณ์"
smartphone: "สมาร์ทโฟน"
@ -969,7 +983,7 @@ color: "สี"
manageCustomEmojis: "จัดการอีโมจิแบบกำหนดเอง"
youCannotCreateAnymore: "คุณถึงขีดจํากัดการสร้างแล้วนะ"
cannotPerformTemporary: "ไม่สามารถใช้การได้ชั่วคราว"
cannotPerformTemporaryDescription: "การดําเนินการนี้ไม่สามารถดําเนินการได้ชั่วคราว เนื่องจากเกินขีดจํากัดการดําเนินการ กรุณารอสักครู่แล้วลองใหม่อีกครั้งนะค่ะ"
cannotPerformTemporaryDescription: "ไม่สามารถดําเนินการได้ชั่วคราว เนื่องจากเกินขีดจํากัดการดําเนินการ กรุณารอสักครู่แล้วลองใหม่อีกครั้ง"
invalidParamError: "ข้อผิดพลาดพารามิเตอร์"
invalidParamErrorDescription: "คำขอพารามิเตอร์ไม่ถูกต้อง สิ่งนี้มักจะเกิดจากข้อผิดพลาด แต่อาจเกิดจากอินพุตเกินขีดจำกัดของขนาดหรือที่คล้ายกัน"
permissionDeniedError: "การดำเนินถูกปฏิเสธ"
@ -991,20 +1005,23 @@ joinThisServer: "ลงชื่อสมัครใช้ในอินสแ
exploreOtherServers: "มองหาอินสแตนซ์อื่น"
letsLookAtTimeline: "ลองดูที่ไทม์ไลน์"
disableFederationConfirm: "ปิดใช้งานสหพันธ์จริงๆหรอแน่ใจแล้วนะ?"
disableFederationConfirmWarn: "แม้ว่าจะถูกยกเลิกเอาไว้โพสต์ดังกล่าวนั้นจะยังคงเป็นสาธารณะต่อไป เว้นแต่ว่า...จะตั้งค่าเป็นอย่างอื่น โดยปกติคุณไม่จำเป็นต้องทำตรงนี้หรอกนะค่ะ"
disableFederationConfirmWarn: "โพสต์จะยังคงเป็นสาธารณะต่อไป เว้นแต่จะตั้งค่าเป็นอย่างอื่น"
disableFederationOk: "ปิดการใช้งาน"
invitationRequiredToRegister: "อินสแตนซ์นี้เป็นแบบรับเชิญเท่านั้น คุณต้องป้อนรหัสเชิญที่ถูกต้องถึงจะลงทะเบียนได้นะค่ะ"
emailNotSupported: "อินสแตนซ์นี้ไม่รองรับการส่งอีเมลนะค่ะ"
invitationRequiredToRegister: "อินสแตนซ์นี้เป็นแบบรับเชิญเท่านั้น คุณต้องป้อนรหัสเชิญ เพื่องลงทะเบียนเข้าใช้งาน"
emailNotSupported: "อินสแตนซ์นี้ไม่รองรับการส่งอีเมล"
postToTheChannel: "โพสต์ลงช่อง"
cannotBeChangedLater: "สิ่งนี้ไม่สามารถเปลี่ยนแปลงได้ในภายหลังนะ"
reactionAcceptance: "การยอมรับรีแอคชั่น"
likeOnly: "ที่ชอบเท่านั้น"
likeOnlyForRemote: "ไลค์สำหรับอินสแตนซ์ระยะไกลเท่านั้น"
nonSensitiveOnly: "ไม่มีความอ่อนไหวเท่านั้น"
nonSensitiveOnlyForLocalLikeOnlyForRemote: "ไม่มีความอ่อนไหวเท่านั้น (เฉพาะไลค์จากระยะไกลเท่านั้น)"
rolesAssignedToMe: "บทบาทที่ได้รับมอบหมายให้ฉัน"
resetPasswordConfirm: "รีเซ็ตรหัสผ่านของคุณจริงๆหรอ?"
sensitiveWords: "คำที่ละเอียดอ่อน"
sensitiveWordsDescription: "การเปิดเผยโน้ตทั้งหมดที่มีคำที่กำหนดค่าไว้จะถูกตั้งค่าเป็น \"หน้าแรก\" โดยอัตโนมัติ คุณยังสามารถแสดงหลายรายการได้โดยแยกรายการโดยใช้ตัวแบ่งบรรทัดได้นะ"
notesSearchNotAvailable: "การค้นหาโน้ตไม่พร้อมใช้งานนะค่ะ"
sensitiveWordsDescription2: "การใช้ช่องว่างนั้นอาจจะสร้างนิพจน์ AND และคำหลักที่มีเครื่องหมายทับล้อมรอบจะเปลี่ยนเป็นนิพจน์ทั่วไปนะ"
notesSearchNotAvailable: "การค้นหาโน้ตไม่พร้อมใช้งาน"
license: "ใบอนุญาต"
unfavoriteConfirm: "ลบออกจากรายการโปรดแน่ใจหรอ?"
myClips: "คลิปของฉัน"
@ -1039,29 +1056,87 @@ vertical: "แนวตั้ง"
horizontal: "ด้านข้าง"
position: "ตำแหน่ง"
serverRules: "กฎของเซิฟเวอร์"
pleaseConfirmBelowBeforeSignup: "โปรดยืนยันด้านล่างก่อนกำลังลงชื่อสมัครนะค่ะ"
pleaseConfirmBelowBeforeSignup: "โปรดยืนยันที่ด้านล่างก่อนสมัครใช้งาน"
pleaseAgreeAllToContinue: "คุณต้องยอมรับทุกช่องตรงด้านบนเพื่อดำเนินการต่อค่ะ"
continue: "ดำเนินการต่อ"
preservedUsernames: "ชื่อผู้ใช้ที่สงวนไว้"
preservedUsernamesDescription: "ลิสต์ชื่อผู้ใช้ที่จะสำรองโดยคั่นด้วยการแบ่งบรรทัดนั้น เพราะสิ่งเหล่านี้จะไม่สามารถทำได้ในระหว่างการสร้างบัญชีตามปกติ บัญชีที่มีอยู่แล้วนั้นโดยใช้ชื่อผู้ใช้เหล่านี้จะไม่ได้รับผลกระทบอะไร"
createNoteFromTheFile: "เรียบเรียงโน้ตจากไฟล์นี้"
archive: "เก็บถาวร"
channelArchiveConfirmTitle: "เก็บถาวรจริงๆ {name} มั้ย?"
channelArchiveConfirmDescription: "ช่องที่ถูกเก็บถาวรแล้วนั้นจะไม่ปรากฏในรายการช่องหรือผลการค้นหานั้นอีกต่อไปไม่สามารถเพิ่มโพสต์ใหม่ได้อีกต่อไปนะ"
thisChannelArchived: "ช่องนี้ถูกเก็บถาวรแล้วนะ"
displayOfNote: "การแสดงโน้ต"
initialAccountSetting: "ตั้งค่าโปรไฟล์"
youFollowing: "ติดตามแล้ว"
preventAiLearning: "ปฏิเสธการใช้งาน ในการเรียนรู้ของเครื่อง (Generative AI)"
preventAiLearningDescription: "การส่งคำร้องขอโปรแกรมรวบรวมข้อมูลไม่ให้ใช้ข้อความที่โพสต์หรือรูปภาพ ฯลฯ ในชุดข้อมูลแมชชีนเลิร์นนิง (Predictive / Generative AI) สิ่งนี้นั้นทำได้โดยการเพิ่มแฟล็กการตอบสนอง \"noai\" HTML ให้กับเนื้อหาที่เกี่ยวข้อง แต่อย่างไรก็ตามแล้ว การป้องกันโดยสมบูรณ์นั้นไม่สามารถทำได้ผ่านแฟล็กนี้เนื่องจากอาจจะทำให้ถูกเพิกเฉยได้"
options: "ตัวเลือกบทบาท"
specifyUser: "ผู้ใช้เฉพาะ"
failedToPreviewUrl: "ไม่สามารถดูตัวอย่างได้"
update: "อัปเดต"
rolesThatCanBeUsedThisEmojiAsReaction: "บทบาทที่สามารถใช้อิโมจินี้เป็นรีแอคชั่นได้"
rolesThatCanBeUsedThisEmojiAsReactionEmptyDescription: "ถ้าหากไม่ได้ระบุบทบาท ทุกคนนั้นก็สามารถใช้อิโมจินี้เป็นการแสดงความรู้สึกได้นะ"
rolesThatCanBeUsedThisEmojiAsReactionPublicRoleWarn: "บทบาทเหล่านี้ต้องเป็นสาธารณะ"
cancelReactionConfirm: "ต้องการลบรีแอคชั่นของคุณจริงๆหรอ?"
changeReactionConfirm: "ต้องการเปลี่ยนรีแอคชั่นของคุณจริงๆหรอ?"
later: "ไว้ทีหลัง"
goToMisskey: "ถึง CherryPick"
additionalEmojiDictionary: "พจนานุกรมอีโมจิเพิ่มเติม"
installed: "ติดตั้งแล้ว"
branding: "แบรนดิ้ง"
enableServerMachineStats: "เผยแพร่สถานะฮาร์ดแวร์ของเซิร์ฟเวอร์"
enableIdenticonGeneration: "เปิดใช้งานผู้ใช้สร้างตัวระบุ"
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:
accountCreated: "คุณได้สร้างบัญชีของคุณสำเร็จเรียบร้อยแล้ว!"
letsStartAccountSetup: "สำหรับผู้เริ่มต้นมาตั้งค่าโปรไฟล์ของคุณกันเถอะ"
letsFillYourProfile: "ก่อนอื่นมาตั้งค่าโปรไฟล์ของคุณ"
profileSetting: "ตั้งค่าโปรไฟล์"
privacySetting: "ตั้งค่าความเป็นส่วนตัว"
theseSettingsCanEditLater: "คุณสามารถเปลี่ยนการตั้งค่าเหล่านี้ได้ในภายหลังได้ตลอดเวลานะ"
youCanEditMoreSettingsInSettingsPageLater: "ยังมีการตั้งค่าอื่นๆ อีกมากมายที่คุณนั้นสามารถกำหนดค่าได้จาก \"การตั้งค่า\" เพื่อให้แน่ใจว่าได้เยี่ยมชมมันได้ภายหลังนะ"
followUsers: "ลองติดตามผู้ใช้บางคนที่คุณอาจจะสนใจเพื่อสร้างไทม์ไลน์ของคุณสิ !"
pushNotificationDescription: "กำลังเปิดใช้งานการแจ้งเตือนแบบพุชจะช่วยให้คุณได้รับการแจ้งเตือนจาก {name} โดยตรงบนอุปกรณ์ของคุณนะ"
initialAccountSettingCompleted: "ตั้งค่าโปรไฟล์เสร็จสมบูรณ์แล้ว!"
haveFun: "สนุกกับ {name}!"
ifYouNeedLearnMore: "ถ้าหากคุณต้องการเรียนรู้เพิ่มเติมเกี่ยวกับวิธีใช้ {ชื่อ} (CherryPick) กรุณาไปที่ {link}"
skipAreYouSure: "ต้องการข้ามการตั้งค่าโปรไฟล์จริงๆแบบนั้นหรอ?"
laterAreYouSure: "ต้องการตั้งค่าโปรไฟล์ในภายหลังจริงๆอย่างงั้นหรอ?"
_serverRules:
description: "ชุดของกฎที่จะแสดงก่อนการลงทะเบียนเราขอแนะนำให้ตั้งค่าสรุปข้อกำหนดในการให้บริการ"
_accountMigration:
moveFrom: "ย้ายข้อมูลบัญชีอื่นไปยังอีกบัญชีนี้หนึ่ง"
moveFromSub: "สร้างนามแฝงไปยังบัญชีอื่น"
moveFromLabel: "บัญชีที่จะย้ายจาก:"
moveFromDescription: "สร้างนามแฝงสำหรับบัญชีที่จะย้ายจากบัญชีนี้ ถ้าหากคุณต้องการโอนผู้ติดตาม สิ่งนี้ต้องทำก่อนโอนก่อนนะค่ะ! หลังจากนั้น ป้อนบัญชีที่จะย้ายไปในรูปแบบต่อไปนี้: @person@instance.com"
moveFromDescription: "ถ้าหากคุณต้องการโอนข้อมูล คุณจำเป็นต้องสร้างบัญชีสำรองสำหรับการย้ายบัญชี หลังจากนั้นป้อนบัญชีที่จะย้ายไปในรูปแบบต่อไปนี้: @person@instance.com"
moveTo: "ย้ายข้อมูลบัญชีนี้ไปยังบัญชีอีกหนึ่ง"
moveToLabel: "บัญชีที่จะย้ายไปที่:"
moveCannotBeUndone: "ไม่สามารถยกเลิกการโอนย้ายบัญชีได้"
moveAccountDescription: "การกระทำนี้ไม่สามารถย้อนกลับได้นะ ขั้นตอนแรก ต้องสร้างนามแฝงสำหรับบัญชีนี้ในบัญชีที่คุณต้องการย้ายไป หลังจากนั้นแล้ว ป้อนบัญชีที่จะย้ายไปในรูปแบบดังต่อไปนี้: @person@instance.com"
moveAccountHowTo: "หากต้องการย้ายข้อมูลก่อนอื่นให้สร้างชื่อแทนสำหรับบัญชีนี้ ในบัญชีที่จะต้องการย้ายไป\nหลังจากที่คุณสร้างนามแฝงนั้นแล้ว ให้ป้อนบัญชีที่ต้องการจะย้ายไปในรูปแบบดังต่อไปนี้: @username@server.example.com"
startMigration: "โอนย้าย"
migrationConfirm: "ย้ายข้อมูลบัญชีนี้ไปที่ {account} จริงๆนะ เมื่อมีการเริ่มต้นแล้ว กระบวนการนี้จะไม่สามารถหยุดหรือนำกลับคืนมาได้ และคุณจะไม่สามารถใช้บัญชีนี้ในสถานะดั้งเดิมได้อีกต่อไป\n\nนอกจากนี้ เพื่อให้แน่ใจยืนยันว่าคุณได้สร้างนามแฝงในบัญชีที่จะย้ายข้อมูลนะค่ะ"
migrationConfirm: "ยืนยันการย้ายข้อมูลบัญชีนี้ไปที่ {account} เมื่อเริ่มแล้วจะไม่สามารถหยุดหรือนำกลับคืนมาได้ และคุณจะไม่สามารถใช้บัญชีนี้ในสถานะดั้งเดิมได้อีกต่อไป\n\nนอกจากนี้ คุณจำเป็นต้องสร้างบัญชีสำรองสำหรับการย้ายบัญชี"
movedAndCannotBeUndone: "\nบัญชีนี้ถูกโอนย้ายไปแล้ว\nไม่สามารถย้อนกลับโอนย้ายข้อมูลได้"
postMigrationNote: "บัญชีนี้จะถูกเลิกติดตามบัญชีทั้งหมดที่กำลังติดตามภายใน 24 ชั่วโมงหลังจากการย้ายข้อมูลนั้นเสร็จสิ้น ทั้งจำนวนผู้ติดตามและผู้ติดตามนั้นจะกลายเป็นศูนย์ เพื่อหลีกเลี่ยงป้องกันไม่ให้ผู้ติดตามของคุณนั้นไม่สามารถเห็นโพสต์เฉพาะผู้ติดตามของบัญชีนี้ได้ แต่อย่างไรก็ตามแล้วพวกเขาจะยังคงติดตามบัญชีนี้ต่อไป"
movedTo: "บัญชีที่จะย้ายไปที่:"
@ -1237,7 +1312,7 @@ _achievements:
title: "พักผ่อนสักหน่อย"
description: "ใช้เวลา 30 นาทีบน CherryPick"
_client60min:
title: "ไม่มี \"Miss\" ใน CherryPick นะค่ะ !"
title: "ไม่พบ \"Miss\" ใน CherryPick "
description: "เปิด CherryPick ค้างไว้แล้วอย่างน้อย 60 นาที"
_noteDeletedWithin1min:
title: "ไม่เป็นไร"
@ -1343,6 +1418,9 @@ _role:
ltlAvailable: "การดูไทม์ไลน์ในท้องถิ่น"
canPublicNote: "สามารถส่งโน้ตสาธารณะ"
canInvite: "สร้างรหัสเชิญอินสแตนซ์"
inviteLimit: "จำกัดการเชิญ"
inviteLimitCycle: "จำกัดการเชิญไว้คูลดาวน์"
inviteExpirationTime: "วันหมดอายุของรหัสการเชิญ"
canManageCustomEmojis: "จัดการอีโมจิแบบกำหนดเอง"
driveCapacity: "ความจุของไดรฟ์"
alwaysMarkNsfw: "ทำเครื่องหมายไฟล์ว่าเป็น NSFW เสมอ"
@ -1405,6 +1483,7 @@ _ad:
back: "ย้อนกลับ"
reduceFrequencyOfThisAd: "แสดงโฆษณานี้ให้น้อยลง"
hide: "ไม่ต้องแสดง"
timezoneinfo: "วันในสัปดาห์นี้จะถูกกำหนดจากโซนเวลาของเซิร์ฟเวอร์"
_forgotPassword:
enterEmail: "ป้อนที่อยู่อีเมลที่คุณเคยใช้ในการลงทะเบียนไว้ ลิงก์ที่คุณสามารถรีเซ็ตรหัสผ่านได้นั้นจะถูกส่งไปนะ"
ifNoEmail: "ถ้าหากคุณไม่ได้ใช้อีเมลระหว่างการลงทะเบียน กรุณาติดต่อผู้ดูแลระบบอินสแตนซ์แทนนะ"
@ -1456,9 +1535,9 @@ _aboutMisskey:
donate: "บริจาคให้กับ Misskey"
morePatrons: "เราขอขอบคุณสำหรับความช่วยเหลือจากผู้ช่วยอื่นๆ ที่ไม่ได้ระบุไว้ที่นี่นะ ขอขอบคุณ! 🥰"
patrons: "สมาชิกพันธมิตร"
_nsfw:
respect: "ซ่อนสื่อ NSFW"
ignore: "อย่าซ่อนสื่อ NSFW"
_displayOfSensitiveMedia:
respect: "ซ่อนสื่อทำเครื่องหมายบอกว่าละเอียดอ่อน"
ignore: "แสดงผลสื่อทำเครื่องหมายบอกว่าละเอียดอ่อน"
force: "ซ่อนสื่อทั้งหมด"
_mfm:
cheatSheet: "โค้ด MFM Cheat Sheet"
@ -1665,9 +1744,13 @@ _time:
day: "วัน"
_timelineTutorial:
title: "วิธีใช้งาน CherryPick"
step1_1: "นี่คือ \"ไทม์ไลน์\" \"โน้ต\" ทั้งหมดที่ส่งใน {name} จะแสดงรายการตามลำดับเวลาที่นี่นะ"
step1_2: "อาจจะมีไทม์ไลน์ที่แตกต่างกันเล็กน้อยยกตัวอย่างเช่น \"ไทม์ไลน์หน้าแรก\" จะมีโน้ตของผู้ใช้ที่คุณติดตามและ \"ไทม์ไลน์ท้องถิ่น\" จะมีโน้ตจากผู้ใช้ทั้งหมดของ {name}"
step2_1: "มาลองโพสต์โน้ตต่อไปกัน คุณสามารถทำได้โดยการกดปุ่มที่มีไอคอนดินสอ"
step2_2: "ยังไงไหนลองเขียนแนะนำตัวเองหรือแค่ \"สวัสดี {name}!\" ถ้าคุณไม่รู้สึกเหมือนมัน?"
step3_1: "เสร็จสิ้นการโพสต์โน้ตย่อแรกของคุณแล้วอย่างงั้นหรอ?"
step3_2: "ไชโย! ตอนนี้โน้ตย่อแรกของคุณได้ปรากฏบนไทม์ไลน์ของคุณแล้วนะ"
step4_1: "คุณยังสามารถแนบ \"ปฏิกิริยา\" ไปกับโน้ตได้อีกด้วยนะค่ะ"
step4_1: "คุณสามารถเพิ่ม \"การตอบสนอง\" ในโน้ตได้"
step4_2: "หากต้องการแนบการแสดงความรู้สึก ให้กดเครื่องหมาย \"+\" บนโน้ตแล้วเลือกอิโมจิที่คุณต้องการแสดงความรู้สึกที่ตนเองชอบได้เลย"
_2fa:
alreadyRegistered: "คุณได้ลงทะเบียนอุปกรณ์ยืนยันตัวตนแบบ 2 ชั้นแล้ว"
@ -2002,6 +2085,7 @@ _deck:
introduction: "สร้างอินเทอร์เฟซที่สมบูรณ์แบบสำหรับคุณโดยจัดเรียงคอลัมน์ได้อย่างอิสระ!"
introduction2: "คลิกที่เครื่องหมาย + ทางขวาของหน้าจอเพื่อเพิ่มคอลัมน์ใหม่ทุกครั้งที่คุณต้องการ"
widgetsIntroduction: "กรุณาเลือก \"แก้ไขวิดเจ็ต\" ในเมนูคอลัมน์และเพิ่มวิดเจ็ต"
useSimpleUiForNonRootPages: "แสดง UI ของ Root Page อย่างง่าย "
_columns:
main: "หลัก"
widgets: "วิดเจ็ต"

View file

@ -1,5 +1,6 @@
---
_lang_: "Türkçe"
headlineMisskey: "Notlarla bağlanmış bir ağ"
introMisskey: "Açık kaynaklı bir dağıtılmış mikroblog hizmeti olan CherryPick'e hoş geldiniz.\nCherryPick, 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>CherryPick</b>Dünya'nın en sunucularında biri。"
monthAndDay: "{month}Ay {day}Gün"
@ -11,7 +12,9 @@ forgotPassword: "şifremi unuttum"
ok: "TAMAM"
gotIt: "Anladım"
cancel: "İptal"
noThankYou: "Hayır, teşekkürler"
enterUsername: "Kullanıcı adınızı giriniz"
renotedBy: "{user} tarafından Renotelandı"
noNotes: "Notlar mevcut değil."
noNotifications: "Bildirim bulunmuyor"
instance: "Sunucu"
@ -45,15 +48,35 @@ delete: "Sil"
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."
addToList: "Listeye ekle"
addToAntenna: "Antene ekle"
sendMessage: "Mesaj Gönder"
copyRSS: "RSSKopyala"
copyUsername: "Kullanıcı Adını Kopyala"
copyUserId: "Kullanıcıyı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"
reply: "yanıt"
loadMore: "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"
noLists: "Liste yok"
note: "not"
@ -64,6 +87,16 @@ followsYou: "seni takip ediyor"
createList: "Liste oluştur"
manageLists: "Yönetici Listeleri"
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"
followRequest: "Takip isteği"
followRequests: "Takip istekleri"
@ -76,9 +109,24 @@ renoted: "yeniden adlandırılmış"
cantRenote: "Ayrılamama"
cantReRenote: "not alabilirmiyim"
quote: "alıntı"
inChannelRenote: "Kanal içi Renote"
inChannelQuote: "Kanal içi Alıntı"
pinnedNote: "Sabitlenen"
pinned: "Sabitlenmiş"
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ç"
renoteMute: "sesi kapat"
renoteUnmute: "sesi açmayı iptal et"
@ -88,46 +136,280 @@ suspend: "askıya al"
unsuspend: "askıya alma"
blockConfirm: "Onayı engelle"
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ç"
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"
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 CherryPick'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"
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: "CherryPick 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"
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"
manageAntennas: "Anten ayarları"
userList: "Listeler"
resetPassword: "Şifre sıfırlama"
noMessagesYet: "Şimdilik mesaj yok"
details: "Detaylar"
deck: "Güverte"
smtpHost: "Sağlayıcı"
smtpUser: "Kullanıcı Adı"
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ı"
global: "Küresel"
squareAvatars: "Kare avatarlar"
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:
color: "Renk"
keys:
mention: "Bahset"
renote: "vazgeçme"
_sfx:
note: "notlar"
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:
profile: "Profil"
instanceInfo: "Sunucu Bilgisi"
notifications: "Bildirim"
timeline: "Zaman çizelgesi"
calendar: "Takvim"
clock: "Saat"
activity: "Etkinlik"
federation: "Federasyon"
jobQueue: "İşlem sırası"
_userList:
chooseList: "Bir liste seç"
_cw:
show: "Devamını yükle"
_poll:
vote: "Oy kullan"
_visibility:
publicDescription: "Herkese açık"
home: "Ana sayfa"
followers: "takipçi"
_profile:
username: "Kullanıcı Adı"
_exportOrImport:
followingList: "takipçi"
muteList: "Gizle"
blockingList: "engelle"
userLists: "Listeler"
_charts:
federation: "Federasyon"
_timelines:
home: "Ana sayfa"
global: "Küresel"
_pages:
blocks:
image: "Görseller"
_notification:
youWereFollowed: "seni takip etti"
unreadAntennaNote: "{name} anteni"
_types:
follow: "takipçi"
mention: "Bahset"
renote: "vazgeçme"
quote: "alıntı"
reaction: "Tepkiler"
receiveFollowRequest: "Takip isteği alındı"
followRequestAccepted: "Takip isteği kabul edildi"
_actions:
reply: "yanıt"
renote: "vazgeçme"
_deck:
configureColumn: "Sütun seçenekleri"
_columns:
notifications: "Bildirim"
tl: "Zaman çizelgesi"
list: "Listeler"
mentions: "Bahsetmeler"

View file

@ -300,7 +300,6 @@ copyUrl: "Копіювати URL"
rename: "Перейменувати"
avatar: "Аватар"
banner: "Банер"
nsfw: "NSFW"
whenServerDisconnected: "Коли зв’язок із сервером втрачено"
disconnectedFromServer: "Зв’язок із сервером було перервано"
reload: "Оновити"
@ -1214,10 +1213,6 @@ _aboutMisskey:
donate: "Пожертвувати Misskey"
morePatrons: "Ми дуже цінуємо підтримку багатьох інших помічників, не перелічених тут. Дякуємо! 🥰"
patrons: "Підтримали"
_nsfw:
respect: "Приховувати NSFW медіа"
ignore: "Не приховувати NSFW медіа"
force: "Приховувати всі медіа файли"
_mfm:
cheatSheet: " Довідка MFM"
intro: "MFM це ексклюзивна мова розмітки тексту в Misskey, яку можна використовувати в багатьох місцях. Тут ви можете переглянути приклади її синтаксису."

736
locales/uz-UZ.yml Normal file
View file

@ -0,0 +1,736 @@
---
_lang_: "O'zbek tili"
headlineMisskey: "Qaydlar tarmog'i"
introMisskey: "Xush kelibsiz! CherryPick 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 bildiring. 👍\nQani, yangi dunyoni kashf qilaylik! 🚀"
poweredByMisskeyDescription: "{name} ochiq manbali <b>CherryPick</b>(\"CherryPick 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: "Xabarlar mavjud emas"
instance: "Server"
settings: "Sozlamalar"
notificationSettings: "Xabarnoma sozlamalari"
basicSettings: "Asosiy sozlamalar"
otherSettings: "Qoshimcha 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: "Sevimlilar"
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: "kontentni 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 va javoblarni yo'qotasiz."
addToList: "Royxatga qoshish"
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: "Koproq korish"
showMore: "Koproq korish"
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? Ushbu fayldan foydalanadigan har qanday kontent ham oʻchiriladi."
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 bolish"
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 muammolarni 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"
defaultNoteVisibility: "Standart ko'rinish"
follow: "Obuna bolish"
followRequest: "Obuna bo'lish uchun ruxsat olish"
followRequests: "Obuna bo'lmoqchilar"
unfollow: "obunani bekor qilish"
followRequestPending: "obuna bo'lishga ruxsat kutilmoqda"
enterEmoji: "Emojini kiriting"
renote: "Qayta qayd etish"
unrenote: "Qayta qayd etishni bekor qilish"
renoted: "Qayta qayd etildi"
cantRenote: "Qayta qayd etish mumkin emas"
cantReRenote: "Repostni qayta joylashtirish mumkin emas."
quote: "Iqtibos keltirish"
inChannelRenote: "Faqat kanalga qayta qayd etish"
inChannelQuote: "Kanaldagi eslatmalar"
pinnedNote: "Qadalgan 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'yxati"
reactionSettingDescription2: "Qayta tartiblash uchun ushlab turib siljiting, oʻchirish uchun bosing, qoʻshish uchun “+” tugmasini bosing."
rememberNoteVisibility: "Qaydning ko'rinish sozlamarini eslab qolish"
attachCancel: "Qo'shimchani olib tashlash"
markAsSensitive: "\"Hamma ko'rishi mumkin emas\" deb belgilash"
unmarkAsSensitive: "\"Hamma ko'rishi mumkin\" deb belgilash"
enterFileName: "Fayl nomini kiriting"
mute: "Ovozni ochirish"
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 toxtatib qoymoqchi 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"
cacheRemoteSensitiveFilesDescription: "Bu sozlama oʻchiq boʻlsa, \"barcha ko'rishi mumkin bo'lmagan\" fayllar keshlashsiz toʻgʻridan-toʻgʻri masofaviy serverdan yuklanadi."
flagAsBot: "Ushbu akkauntni bot sifatida belgilash"
flagAsBotDescription: "Agar bu akkaunt bot tomonidan boshqaralayotgan bo'lsa, bu sozlamani yoqing. Sozlama yoqilganda, boshqa foydalanuvchilar uchun belgi sifatida ishlaydi, va CherryPick ichki tizimlari bu akkauntni bot ekanini biladi."
flagAsCat: "Bu akkauntni mushuk sifatida belgilash"
flagAsCatDescription: "Ushbu akkauntni mushuk sifatida belgilash uchun ushbu sozlamani yoqing."
flagShowTimelineReplies: "Javoblarni xronogoliya bo'yicha ko'rsatish"
flagShowTimelineRepliesDescription: "Bu parametr yoqilganda, lentada foydalanuvchi xabarlariga javob berilgan xabarlar ham ko'rinadi"
autoAcceptFollowed: "Obunachilarni avtomatik ravishda qabul qilish"
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"
proxyAccountDescription: "Proksi-hisob qaydnomasi - bu ma'lum shartlar ostida foydalanuvchi uchun masofaviy kuzatuvchi sifatida ishlaydigan hisob. Misol uchun, foydalanuvchi uzoq foydalanuvchini roʻyxatga qoʻyganda, roʻyxatdagi foydalanuvchini hech kim kuzatib turmasa, faoliyat serverga yetkazilmaydi, shuning uchun biz proksi hisobi ularning oʻrniga ularni kuzatishini xohlaymiz."
host: "Host"
selectUser: "Foydalanuvchini tanlang"
recipient: "Qabul qiluvchi"
annotation: "Izohlar"
federation: "Federatsiya"
instances: "Serverlar"
registeredAt: "Ro'yhatdan o'tgan"
latestRequestReceivedAt: "Oxirgi qabul qilingan so'rov"
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?"
clearQueueConfirmText: "Yetkazib berilmagan xabarlar yetkazilmaydi. Odatda buni qilish shart emas."
clearCachedFiles: "Keshni tozalash"
clearCachedFilesConfirm: "Barcha keshlangan masofaviy fayllar oʻchirilsinmi?"
blockedInstances: "Bloklangan serverlar"
blockedInstancesDescription: "Bloklanmoqchi bo'lgan serverlaringiz hostlarini yangi qatorlar bilan ajrating. Bloklangan server bu server bilan ozaro aloqada bolmaydi. Subdomenlar ham bloklangan."
muteAndBlock: "Ovozsiz va Bloklangan"
mutedUsers: "Ovozsiz foydalanuvchilar"
blockedUsers: "Bloklangan foydalanuvchilar"
noUsers: "Foydalanuvchilar yoq"
editProfile: "Profilni o'zgartirish"
noteDeleteConfirm: "Haqiqatan ham bu qaydni oʻchirib tashlamoqchimisiz?"
pinLimitExceeded: "Siz boshqa qaydlarni mahkamlay olmaysiz"
intro: "CherryPickni 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"
federating: "Ittifoqdosh"
blocked: "Bloklangan"
suspended: "To'xtatilgan"
all: "Barcha"
subscribing: "Obuna bo'lish"
publishing: "Yuborilmoqda"
notResponding: "Javob bermayapti"
instanceFollowing: "server obuna bo'ladi"
instanceFollowers: "server obunachisi"
instanceUsers: "server foydalanuvchisi"
changePassword: "Parolni ozgartirish"
security: "Xavfsizlik"
retypedNotMatch: "Maydonlar mos kelmayapti"
currentPassword: "Joriy parol"
newPassword: "Yangi parol"
newPasswordRetype: "Yangi parolni boshqatdan tering"
attachFile: "Fayl biriktirish"
more: "Ko'proq!"
featured: "ta'kidlash"
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"
fromUrl: "URL dan"
uploadFromUrlDescription: "Yuklamoqchi bo'lgan faylingizga havola"
uploadFromUrlRequested: "yuklab olish so'ralgan"
uploadFromUrlMayTakeTime: "Yuklash tugallanishi uchun biroz vaqt ketishi mumkin."
explore: "Ko'rib chiqish"
messageRead: "Oqildi"
noMoreHistory: "Buning ortida hech qanday hikoya yo'q"
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"
syncDeviceDarkMode: "Qurilmangizning qorongi rejimi bilan sinxronlashtiring"
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 ozgartirish"
deleteFolder: "Papkani ochirish"
addFile: "Fayl qoshish"
emptyDrive: "Diskingiz bo'sh"
emptyFolder: "Ushbu papka bo'sh"
unableToDelete: "O'chirilmadi"
inputNewFileName: "Yangi fayl nomini kiriting"
inputNewDescription: "Iltimos, yangi sarlavha kiriting."
inputNewFolderName: "Yangi papka nomini kiriting"
hasChildFilesOrFolders: "Bu papka boʻsh emas va uni oʻchirib boʻlmaydi."
copyUrl: "Bog'lamadan nusxa olish"
rename: "Qayta nomlash"
avatar: "Avatar"
banner: "Banner"
whenServerDisconnected: "server bilan aloqa uzilganda"
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"
iconUrl: "Ikonkaning URL manzili (masalan: favicon)"
backgroundImageUrl: "Fon rasmi URL manzili"
basicInfo: "Asosiy ma'lumot"
pinnedUsers: "Qadalgan foydalanuvchilar"
pinnedPages: "Qadalgan Sahifalar"
pinnedNotes: "Qadalgan 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"
antennaKeywords: "Kalit so'zni qabul qilish"
notifyAntenna: "Yangi qaydlar haqida menga xabar bering"
connectedTo: "Quyidagi akkountlarga ulangan"
silence: "Sukunat"
popularUsers: "Mashhur foydalanuvchilar."
recentlyRegisteredUsers: "Yaqinda ro'yxatdan o'tgan foydalanuvchilar"
exploreUsersCount: "{count} ta foydalanuvchi bor"
popularTags: "Ommabop teglar"
userList: "Ro'yxatlar"
about: "Haqida"
aboutMisskey: "CherryPick haqida"
administrator: "Administrator"
token: "Tasdiqlash"
2fa: "Ikki faktorli autentifikatsiya"
totp: "Autentifikatsiya ilovasi"
totpDescription: "Bir martalik parollarni kiritish uchun autentifikatsiya ilovasidan foydalaning"
moderator: "Moderator"
nUsersMentioned: "{n} tomonidan chop etilgan"
resetPassword: "Parolni tiklash"
share: "Yuborish"
notFound: "Topilmadi"
uploadFolder: "Jildni yuklash"
cacheClear: "Keshni tozalash"
markAsReadAllTalkMessages: "Barcha suhbatlarni o'qilgan deb belgilang"
help: "Yordam"
inputMessageHere: "Xabar kiriting"
close: "Yopish"
invites: "Taklif qilish"
members: "A'zolar"
transfer: "topshiriq"
title: "Sarlavha"
text: "Matn"
enable: "Yoqish"
next: "Keyingisi"
retype: "Qayta kiriting"
onlyOneFileCanBeAttached: "Faqat bitta faylni biriktirish mumkin"
signinRequired: "Davom etishdan oldin ro'yhatdan o'tishingiz yoki tizimga kirishingiz kerak"
invitations: "Taklif qilish"
invitationCode: "taklif qilish kodi"
checking: "Tekshirilmoqda"
available: "Mavjud"
unavailable: "Mavjud emas"
usernameInvalidFormat: "Siz a~z, A~Z, 0~9, _ dan foydalanishingiz mumkin"
tooShort: "Juda qisqa"
tooLong: "juda uzun"
weakPassword: "Zaif parol"
normalPassword: "Oddiy parol"
strongPassword: "Kuchli parol"
passwordMatched: "Mos keldi"
passwordNotMatched: "mos kelmadi"
signinWith: "{x} bilan tizimga kirish"
signinFailed: "Tizimga kirishda xatolik yuz berdi. Iltimos, foydalanuvchi nomingiz va parolingizni tekshiring."
or: "yoki"
language: "til"
aboutX: "{x} haqida"
showNoteActionsOnlyHover: "Eslatma amallarini faqat sichqonchani olib borganda korsatish"
noHistory: "Tarix yo'q"
signinHistory: "kirish tarixi"
category: "kategoriya"
tags: "teg"
docSource: "Ushbu hujjatning manbasi"
createAccount: "Akkaunt yaratish"
existingAccount: "mavjud akkaunt"
regenerate: "regeneratsiya"
fontSize: "shrift hajmi"
limitTo: "{x} gacha"
noFollowRequests: "obuna uchun so'rov yo'q"
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"
promotion: "rag'batlantirish"
promote: "targ'ib qilish"
numberOfDays: "kunlar soni"
hideThisNote: "bu eslatmani yashiring"
showFeaturedNotesInTimeline: "Tanlangan qaydlarni Timelineda ko'rsatish"
objectStorageBaseUrl: "Asosiy URL"
objectStorageRegion: "Mintaqa"
objectStorageUseSSL: "SSL dan foydalaning"
sounds: "Tovushlar"
sound: "ovoz"
none: "Hechnima"
volume: "Ovoz balandligi"
details: "Batafsil"
output: "Chiqish"
deleteAllFiles: "barcha fayllarni o'chirish"
deleteAllFilesConfirm: "Barcha fayllar oʻchirilsinmi?"
userSuspended: "Bu foydalanuvchi muzlatilgan."
yourAccountSuspendedTitle: "akkaunt muzlatilgan"
yourAccountSuspendedDescription: "Ushbu akkaunt serverning xizmat ko'rsatish shartlarini buzish kabi sabablarga ko'ra to'xtatilgan. Tafsilotlar uchun administratoringizga murojaat qiling. Iltimos, yangi akkaunt yaratmang."
tokenRevoked: "token yaroqsiz"
tokenRevokedDescription: "Kirish tokeningizni muddati tugagan. Iltimos, qaytadan kiring."
accountDeleted: "akkaunt o'chirildi"
accountDeletedDescription: "Bu akkaunt oʻchirildi."
menu: "Menyu"
divider: "Ajratrmoq"
addItem: "Element qo'shish"
serviceworkerInfo: "bildirishnomalar uchun yoqilgan bo'lishi kerak."
deletedNote: "Oʻchirilgan post"
themeEditor: "Rang sxemasi muharriri"
describeFile: "sarlavha qo'shing"
enterFileDescription: "sarlavha kiriting"
author: "muallif"
leaveConfirm: "Sizda saqlanmagan oʻzgarishlar bor. Bekor qilinsinmi?"
useBlurEffectForModal: "Modal uchun xiralashtirish effektidan foydalaning"
width: "kengligi"
height: "balandligi"
large: "Katta"
small: "kichik"
enableAll: "Yoqish"
disableAll: "hammasini o'chirib qo'ying"
edit: "Tahrirlash"
email: "Email"
smtpHost: "Host"
smtpUser: "Foydalanuvchi nomi"
smtpPass: "Parol"
copy: "Nusxa olish"
notificationSetting: "Bildirishnoma sozlamalari"
other: "Qoshimcha"
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 qayd etish"
divider: "Ajratrmoq"
accentDarken: "Urg'u (Qoraytirilgan)"
accentLighten: "Urg'u (Yoritilgan)"
fgHighlighted: "Belgilangan matn"
_sfx:
note: "Qaydlar"
notification: "Xabarnomalar"
chat: "Suhbat"
_ago:
minutesAgo: "{n} daqiqa oldin"
hoursAgo: "{n} soat oldin"
daysAgo: "{n} kun oldin"
_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: "Koproq korish"
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 bolish"
muteList: "Ovozni ochirish"
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 bolish"
mention: "Murojat"
renote: "Qayta qayd etish"
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 ochirib tashlash"
_columns:
main: "Asosiy"
notifications: "Xabarnomalar"
tl: "Xronologiya"
antenna: "Antennalar"
list: "Royxat"
channel: "Kanal"
mentions: "Eslatib o'tish"
direct: "Bevosita qaydlar"
roleTimeline: "Rol xronologiyasi"
_webhookSettings:
name: "Ism"
active: "Yoqilgan"
_events:
renote: "Qayta qayd qilinganda"
mention: "Eslanganda"

View file

@ -303,7 +303,6 @@ copyUrl: "Sao chép URL"
rename: "Đổi tên"
avatar: "Ảnh đại diện"
banner: "Ảnh bìa"
nsfw: "Nhạy cảm"
whenServerDisconnected: "Khi mất kết nối tới máy chủ"
disconnectedFromServer: "Mất kết nối tới máy chủ"
reload: "Tải lại"
@ -1226,10 +1225,6 @@ _aboutMisskey:
donate: "Ủng hộ Misskey"
morePatrons: "Chúng tôi cũng trân trọng sự hỗ trợ của nhiều người đóng góp khác không được liệt kê ở đây. Cảm ơn! 🥰"
patrons: "Người ủng hộ"
_nsfw:
respect: "Ẩn nội dung NSFW"
ignore: "Hiện nội dung NSFW"
force: "Ẩn mọi media"
_mfm:
cheatSheet: "MFM Cheatsheet"
intro: "MFM là ngôn ngữ phát triển độc quyền của Misskey có thể được sử dụng ở nhiều nơi. Tại đây bạn có thể xem danh sách tất cả các cú pháp MFM có sẵn."

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -1,12 +1,12 @@
{
"name": "cherrypick",
"version": "13.13.2-cp-4.1.0",
"version": "13.14.2-cp-4.2.0",
"codename": "nasubi",
"repository": {
"type": "git",
"url": "https://github.com/kokonect-link/cherrypick.git"
},
"packageManager": "pnpm@8.6.0",
"packageManager": "pnpm@8.6.10",
"workspaces": [
"packages/frontend",
"packages/backend",
@ -25,7 +25,7 @@
"migrateandstart": "pnpm migrate && pnpm start",
"gulp": "pnpm exec gulp build",
"watch": "pnpm dev",
"dev": "node ./scripts/dev.js",
"dev": "node ./scripts/dev.mjs",
"lint": "pnpm -r lint",
"cy:open": "pnpm cypress open --browser --e2e --config-file=cypress.config.ts",
"cy:run": "pnpm cypress run",
@ -44,23 +44,23 @@
"lodash": "4.17.21"
},
"dependencies": {
"execa": "5.1.1",
"execa": "7.1.1",
"gulp": "4.0.2",
"gulp-cssnano": "2.1.3",
"gulp-rename": "2.0.0",
"gulp-replace": "1.1.4",
"gulp-terser": "2.1.0",
"js-yaml": "4.1.0",
"typescript": "5.1.3"
"typescript": "5.1.6"
},
"devDependencies": {
"@types/gulp": "4.0.10",
"@types/gulp-rename": "2.0.1",
"@typescript-eslint/eslint-plugin": "5.59.8",
"@typescript-eslint/parser": "5.59.8",
"@typescript-eslint/eslint-plugin": "5.61.0",
"@typescript-eslint/parser": "5.61.0",
"cross-env": "7.0.3",
"cypress": "12.13.0",
"eslint": "8.41.0",
"cypress": "12.17.1",
"eslint": "8.45.0",
"start-server-and-test": "2.0.0"
},
"optionalDependencies": {

View file

@ -17,7 +17,7 @@
"paths": {
"@/*": ["*"]
},
"target": "es2021"
"target": "es2022"
},
"minify": false
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 66 KiB

View file

@ -2,14 +2,7 @@ import Redis from 'ioredis';
import { loadConfig } from './built/config.js';
const config = loadConfig();
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,
});
const redis = new Redis(config.redis);
redis.on('connect', () => redis.disconnect());
redis.on('error', (e) => {

View file

@ -0,0 +1,9 @@
export class ad1677054292210 {
name = 'ad1677054292210';
async up(queryRunner) {
await queryRunner.query(`ALTER TABLE "ad" ADD "dayOfWeek" integer NOT NULL Default 0`);
}
async down(queryRunner) {
await queryRunner.query(`ALTER TABLE "ad" DROP COLUMN "dayOfWeek"`);
}
}

View file

@ -0,0 +1,13 @@
export class AddMetaOptions1688280713783 {
name = 'AddMetaOptions1688280713783'
async up(queryRunner) {
await queryRunner.query(`ALTER TABLE "meta" ADD "enableServerMachineStats" boolean NOT NULL DEFAULT false`);
await queryRunner.query(`ALTER TABLE "meta" ADD "enableIdenticonGeneration" boolean NOT NULL DEFAULT true`);
}
async down(queryRunner) {
await queryRunner.query(`ALTER TABLE "meta" DROP COLUMN "enableIdenticonGeneration"`);
await queryRunner.query(`ALTER TABLE "meta" DROP COLUMN "enableServerMachineStats"`);
}
}

View file

@ -0,0 +1,25 @@
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"`);
}
}

View file

@ -0,0 +1,13 @@
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"`);
}
}

View file

@ -0,0 +1,11 @@
export class NsfwCache1689102832143 {
name = 'NsfwCache1689102832143'
async up(queryRunner) {
await queryRunner.query(`ALTER TABLE "meta" ADD "cacheRemoteSensitiveFiles" boolean NOT NULL DEFAULT true`);
}
async down(queryRunner) {
await queryRunner.query(`ALTER TABLE "meta" DROP COLUMN "cacheRemoteSensitiveFiles"`);
}
}

View file

@ -0,0 +1,36 @@
export class ObjectStorageRemoteSetting1689580926821 {
name = 'ObjectStorageRemoteSetting1689580926821'
async up(queryRunner) {
await queryRunner.query(`ALTER TABLE "meta" ADD "useObjectStorageRemote" boolean NOT NULL DEFAULT false`);
await queryRunner.query(`ALTER TABLE "meta" ADD "objectStorageRemoteBucket" character varying(1024)`);
await queryRunner.query(`ALTER TABLE "meta" ADD "objectStorageRemotePrefix" character varying(1024)`);
await queryRunner.query(`ALTER TABLE "meta" ADD "objectStorageRemoteBaseUrl" character varying(1024)`);
await queryRunner.query(`ALTER TABLE "meta" ADD "objectStorageRemoteEndpoint" character varying(1024)`);
await queryRunner.query(`ALTER TABLE "meta" ADD "objectStorageRemoteRegion" character varying(1024)`);
await queryRunner.query(`ALTER TABLE "meta" ADD "objectStorageRemoteAccessKey" character varying(1024)`);
await queryRunner.query(`ALTER TABLE "meta" ADD "objectStorageRemoteSecretKey" character varying(1024)`);
await queryRunner.query(`ALTER TABLE "meta" ADD "objectStorageRemotePort" integer`);
await queryRunner.query(`ALTER TABLE "meta" ADD "objectStorageRemoteUseSSL" boolean NOT NULL DEFAULT true`);
await queryRunner.query(`ALTER TABLE "meta" ADD "objectStorageRemoteUseProxy" boolean NOT NULL DEFAULT true`, undefined);
await queryRunner.query(`ALTER TABLE "meta" ADD "objectStorageRemoteSetPublicRead" boolean NOT NULL DEFAULT false`);
await queryRunner.query(`ALTER TABLE "meta" ADD "objectStorageRemoteS3ForcePathStyle" boolean NOT NULL DEFAULT true`);
}
async down(queryRunner) {
await queryRunner.query(`ALTER TABLE "meta" DROP COLUMN "objectStorageRemoteS3ForcePathStyle"`);
await queryRunner.query(`ALTER TABLE "meta" DROP COLUMN "objectStorageRemoteSetPublicRead"`);
await queryRunner.query(`ALTER TABLE "meta" DROP COLUMN "objectStorageRemoteUseProxy"`, undefined);
await queryRunner.query(`ALTER TABLE "meta" DROP COLUMN "objectStorageRemoteUseSSL"`);
await queryRunner.query(`ALTER TABLE "meta" DROP COLUMN "objectStorageRemotePort"`);
await queryRunner.query(`ALTER TABLE "meta" DROP COLUMN "objectStorageRemoteSecretKey"`);
await queryRunner.query(`ALTER TABLE "meta" DROP COLUMN "objectStorageRemoteAccessKey"`);
await queryRunner.query(`ALTER TABLE "meta" DROP COLUMN "objectStorageRemoteRegion"`);
await queryRunner.query(`ALTER TABLE "meta" DROP COLUMN "objectStorageRemoteEndpoint"`);
await queryRunner.query(`ALTER TABLE "meta" DROP COLUMN "objectStorageRemoteBaseUrl"`);
await queryRunner.query(`ALTER TABLE "meta" DROP COLUMN "objectStorageRemotePrefix"`);
await queryRunner.query(`ALTER TABLE "meta" DROP COLUMN "objectStorageRemoteBucket"`);
await queryRunner.query(`ALTER TABLE "meta" DROP COLUMN "useObjectStorageRemote"`);
}
}

View file

@ -3,6 +3,9 @@
"main": "./index.js",
"private": true,
"type": "module",
"engines": {
"node": ">=18.16.0"
},
"scripts": {
"start": "node ./built/index.js",
"start:test": "NODE_ENV=test node ./built/index.js",
@ -25,6 +28,7 @@
"@swc/core-android-arm64": "1.3.11",
"@swc/core-darwin-arm64": "1.3.56",
"@swc/core-darwin-x64": "1.3.56",
"@swc/core-freebsd-x64": "1.3.11",
"@swc/core-linux-arm-gnueabihf": "1.3.56",
"@swc/core-linux-arm64-gnu": "1.3.56",
"@swc/core-linux-arm64-musl": "1.3.56",
@ -36,56 +40,57 @@
"@tensorflow/tfjs": "4.4.0",
"@tensorflow/tfjs-node": "4.4.0",
"bufferutil": "^4.0.7",
"slacc-android-arm-eabi": "0.0.9",
"slacc-android-arm64": "0.0.9",
"slacc-darwin-arm64": "0.0.9",
"slacc-darwin-universal": "0.0.9",
"slacc-darwin-x64": "0.0.9",
"slacc-freebsd-x64": "0.0.9",
"slacc-linux-arm-gnueabihf": "0.0.9",
"slacc-linux-arm64-gnu": "0.0.9",
"slacc-linux-arm64-musl": "0.0.9",
"slacc-linux-x64-gnu": "0.0.9",
"slacc-win32-arm64-msvc": "0.0.9",
"slacc-win32-x64-msvc": "0.0.9",
"slacc-android-arm-eabi": "0.0.10",
"slacc-android-arm64": "0.0.10",
"slacc-darwin-arm64": "0.0.10",
"slacc-darwin-universal": "0.0.10",
"slacc-darwin-x64": "0.0.10",
"slacc-freebsd-x64": "0.0.10",
"slacc-linux-arm-gnueabihf": "0.0.10",
"slacc-linux-arm64-gnu": "0.0.10",
"slacc-linux-arm64-musl": "0.0.10",
"slacc-linux-x64-gnu": "0.0.10",
"slacc-linux-x64-musl": "0.0.10",
"slacc-win32-arm64-msvc": "0.0.10",
"slacc-win32-x64-msvc": "0.0.10",
"utf-8-validate": "^6.0.3"
},
"dependencies": {
"@aws-sdk/client-s3": "3.321.1",
"@aws-sdk/lib-storage": "3.321.1",
"@aws-sdk/node-http-handler": "3.321.1",
"@bull-board/api": "5.2.0",
"@bull-board/fastify": "5.2.0",
"@bull-board/ui": "5.2.0",
"@aws-sdk/client-s3": "3.367.0",
"@aws-sdk/lib-storage": "3.367.0",
"@aws-sdk/node-http-handler": "3.360.0",
"@bull-board/api": "5.6.1",
"@bull-board/fastify": "5.6.1",
"@bull-board/ui": "5.6.1",
"@discordapp/twemoji": "14.1.2",
"@fastify/accepts": "4.1.0",
"@fastify/accepts": "4.2.0",
"@fastify/cookie": "8.3.0",
"@fastify/cors": "8.3.0",
"@fastify/http-proxy": "9.1.0",
"@fastify/multipart": "7.6.0",
"@fastify/http-proxy": "9.2.1",
"@fastify/multipart": "7.7.1",
"@fastify/static": "6.10.2",
"@fastify/view": "7.4.1",
"@fastify/view": "8.0.0",
"@google-cloud/logging": "^10.5.0",
"@google-cloud/translate": "^7.2.1",
"@nestjs/common": "9.4.2",
"@nestjs/core": "9.4.2",
"@nestjs/testing": "9.4.2",
"@nestjs/common": "10.1.0",
"@nestjs/core": "10.1.0",
"@nestjs/testing": "10.1.0",
"@peertube/http-signature": "1.7.0",
"@sinonjs/fake-timers": "10.2.0",
"@sinonjs/fake-timers": "10.3.0",
"@swc/cli": "0.1.62",
"@swc/core": "1.3.61",
"@swc/core": "1.3.70",
"@vitalets/google-translate-api": "9.2.0",
"accepts": "1.3.8",
"ajv": "8.12.0",
"archiver": "5.3.1",
"autwh": "0.1.0",
"async-mutex": "^0.4.0",
"bcryptjs": "2.4.3",
"blurhash": "2.0.5",
"bullmq": "3.15.0",
"cacheable-lookup": "6.1.0",
"bullmq": "4.4.0",
"cacheable-lookup": "7.0.0",
"cbor": "9.0.0",
"chalk": "5.2.0",
"chalk-template": "0.4.0",
"chalk": "5.3.0",
"chalk-template": "1.1.0",
"cherrypick-js": "workspace:*",
"cherrypick-mfm-js": "github:kokonect-link/mfm.js",
"chokidar": "3.5.3",
@ -94,24 +99,24 @@
"content-disposition": "0.5.4",
"date-fns": "2.30.0",
"deep-email-validator": "0.1.21",
"escape-regexp": "0.0.1",
"fastify": "4.17.0",
"fastify": "4.20.0",
"feed": "4.2.2",
"file-type": "18.4.0",
"file-type": "18.5.0",
"fluent-ffmpeg": "2.1.2",
"form-data": "4.0.0",
"got": "12.6.0",
"happy-dom": "9.20.3",
"got": "13.0.0",
"happy-dom": "10.0.3",
"hpagent": "1.2.0",
"ioredis": "5.3.2",
"ip-cidr": "3.1.0",
"is-svg": "4.3.2",
"ipaddr.js": "2.1.0",
"is-svg": "5.0.0",
"js-yaml": "4.1.0",
"jsdom": "22.1.0",
"json5": "2.2.3",
"jsonld": "8.2.0",
"jsrsasign": "10.8.6",
"meilisearch": "0.32.5",
"meilisearch": "0.33.0",
"mime-types": "2.1.35",
"ms": "3.0.0-canary.1",
"nested-property": "4.0.0",
@ -120,10 +125,9 @@
"nsfwjs": "2.4.2",
"oauth": "0.10.0",
"os-utils": "0.0.14",
"otpauth": "9.1.2",
"otpauth": "9.1.3",
"parse5": "7.1.2",
"pg": "8.11.0",
"private-ip": "3.0.0",
"pg": "8.11.1",
"probe-image-size": "7.2.3",
"promise-limit": "2.7.0",
"pug": "3.0.2",
@ -132,42 +136,37 @@
"qrcode": "1.5.3",
"random-seed": "0.3.0",
"ratelimiter": "3.4.1",
"re2": "1.19.0",
"re2": "1.19.1",
"redis-lock": "0.1.4",
"reflect-metadata": "0.1.13",
"rename": "1.0.4",
"rndstr": "1.0.0",
"rss-parser": "3.13.0",
"rxjs": "7.8.1",
"s-age": "1.1.2",
"sanitize-html": "2.10.0",
"seedrandom": "3.0.5",
"semver": "7.5.1",
"sharp": "0.32.1",
"sanitize-html": "2.11.0",
"semver": "7.5.4",
"sharp": "0.32.3",
"sharp-read-bmp": "github:misskey-dev/sharp-read-bmp",
"slacc": "0.0.9",
"slacc": "0.0.10",
"strict-event-emitter-types": "2.0.0",
"stringz": "2.1.0",
"strip-ansi": "^7.1.0",
"summaly": "github:misskey-dev/summaly",
"systeminformation": "5.17.16",
"systeminformation": "5.18.7",
"tinycolor2": "1.6.0",
"tmp": "0.2.1",
"tsc-alias": "1.8.6",
"tsc-alias": "1.8.7",
"tsconfig-paths": "4.2.0",
"twemoji-parser": "14.0.0",
"typeorm": "0.3.16",
"typescript": "5.1.3",
"typeorm": "0.3.17",
"typescript": "5.1.6",
"ulid": "2.3.0",
"unzipper": "0.10.14",
"uuid": "9.0.0",
"vary": "1.1.2",
"web-push": "3.6.1",
"web-push": "3.6.3",
"ws": "8.13.0",
"xev": "3.0.2"
},
"devDependencies": {
"@jest/globals": "29.5.0",
"@jest/globals": "29.6.1",
"@swc/jest": "0.2.26",
"@types/accepts": "1.3.5",
"@types/archiver": "5.3.2",
@ -175,25 +174,24 @@
"@types/cbor": "6.0.0",
"@types/color-convert": "2.0.0",
"@types/content-disposition": "0.5.5",
"@types/escape-regexp": "0.0.1",
"@types/fluent-ffmpeg": "2.1.21",
"@types/jest": "29.5.2",
"@types/jest": "29.5.3",
"@types/js-yaml": "4.0.5",
"@types/jsdom": "21.1.1",
"@types/jsonld": "1.5.8",
"@types/jsonld": "1.5.9",
"@types/jsrsasign": "10.5.8",
"@types/mime-types": "2.1.1",
"@types/node": "20.2.5",
"@types/ms": "^0.7.31",
"@types/node": "20.4.2",
"@types/node-fetch": "3.0.3",
"@types/nodemailer": "6.4.8",
"@types/oauth": "0.9.1",
"@types/pg": "8.10.1",
"@types/pg": "8.10.2",
"@types/pug": "2.0.6",
"@types/punycode": "2.1.0",
"@types/qrcode": "1.5.0",
"@types/qrcode": "1.5.1",
"@types/random-seed": "0.3.3",
"@types/ratelimiter": "3.4.4",
"@types/redis": "4.0.11",
"@types/rename": "1.0.4",
"@types/sanitize-html": "2.9.0",
"@types/semver": "7.5.0",
@ -201,20 +199,17 @@
"@types/sinonjs__fake-timers": "8.1.2",
"@types/tinycolor2": "1.4.3",
"@types/tmp": "0.2.3",
"@types/unzipper": "0.10.6",
"@types/uuid": "9.0.1",
"@types/vary": "1.1.0",
"@types/web-push": "3.3.2",
"@types/websocket": "1.0.5",
"@types/ws": "8.5.4",
"@typescript-eslint/eslint-plugin": "5.59.8",
"@typescript-eslint/parser": "5.59.8",
"aws-sdk-client-mock": "2.1.1",
"@types/ws": "8.5.5",
"@typescript-eslint/eslint-plugin": "5.61.0",
"@typescript-eslint/parser": "5.61.0",
"aws-sdk-client-mock": "3.0.0",
"cross-env": "7.0.3",
"eslint": "8.41.0",
"eslint": "8.45.0",
"eslint-plugin-import": "2.27.5",
"execa": "6.1.0",
"jest": "29.5.0",
"jest-mock": "29.5.0"
"execa": "7.1.1",
"jest": "29.6.1",
"jest-mock": "29.6.1"
}
}

View file

@ -41,14 +41,7 @@ const $meilisearch: Provider = {
const $redis: Provider = {
provide: DI.redis,
useFactory: (config: Config) => {
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,
});
return new Redis.Redis(config.redis);
},
inject: [DI.config],
};
@ -56,14 +49,7 @@ const $redis: Provider = {
const $redisForPub: Provider = {
provide: DI.redisForPub,
useFactory: (config: Config) => {
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,
});
const redis = new Redis.Redis(config.redisForPubsub);
return redis;
},
inject: [DI.config],
@ -72,14 +58,7 @@ const $redisForPub: Provider = {
const $redisForSub: Provider = {
provide: DI.redisForSub,
useFactory: (config: Config) => {
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,
});
const redis = new Redis.Redis(config.redisForPubsub);
redis.subscribe(config.host);
return redis;
},

View file

@ -80,7 +80,7 @@ export async function masterMain() {
await spawnWorkers(config.clusterLimit);
}
bootLogger.succ(`Now listening on port ${config.port} on ${config.url}`, null, true);
bootLogger.succ(config.socket ? `Now listening on socket ${config.socket} on ${config.url}` : `Now listening on port ${config.port} on ${config.url}`, null, true);
}
function showEnvironment(): void {
@ -98,12 +98,6 @@ function showNodejsVersion(): void {
const nodejsLogger = bootLogger.createSubLogger('nodejs');
nodejsLogger.info(`Version ${process.version} detected.`);
const minVersion = fs.readFileSync(`${_dirname}/../../../../.node-version`, 'utf-8').trim();
if (semver.lt(process.version, minVersion)) {
nodejsLogger.error(`At least Node.js ${minVersion} required!`);
process.exit(1);
}
}
function loadConfigBoot(): Config {

View file

@ -6,6 +6,16 @@ import * as fs from 'node:fs';
import { fileURLToPath } from 'node:url';
import { dirname, resolve } from 'node:path';
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;
};
/**
*
@ -14,7 +24,9 @@ export type Source = {
repository_url?: string;
feedback_url?: string;
url: string;
port: number;
port?: number;
socket?: string;
chmodSocket?: string;
disableHsts?: boolean;
db: {
host: string;
@ -33,36 +45,16 @@ export type Source = {
user: string;
pass: string;
}[];
redis: {
host: string;
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;
};
redis: RedisOptionsSource;
redisForPubsub?: RedisOptionsSource;
redisForJobQueue?: RedisOptionsSource;
meilisearch?: {
host: string;
port: string;
apiKey: string;
ssl?: boolean;
index: string;
scope?: 'local' | 'global' | string[];
};
proxy?: string;
@ -122,8 +114,9 @@ export type Mixin = {
mediaProxy: string;
externalMediaProxyEnabled: boolean;
videoThumbnailGenerator: string | null;
redisForPubsub: NonNullable<Source['redisForPubsub']>;
redisForJobQueue: NonNullable<Source['redisForJobQueue']>;
redis: RedisOptions & RedisOptionsSource;
redisForPubsub: RedisOptions & RedisOptionsSource;
redisForJobQueue: RedisOptions & RedisOptionsSource;
};
export type Config = Source & Mixin;
@ -185,9 +178,9 @@ export function loadConfig() {
config.videoThumbnailGenerator.endsWith('/') ? config.videoThumbnailGenerator.substring(0, config.videoThumbnailGenerator.length - 1) : config.videoThumbnailGenerator
: null;
if (!config.redis.prefix) config.redis.prefix = mixin.host;
if (config.redisForPubsub == null) config.redisForPubsub = config.redis;
if (config.redisForJobQueue == null) config.redisForJobQueue = config.redis;
mixin.redis = convertRedisOptions(config.redis, mixin.host);
mixin.redisForPubsub = config.redisForPubsub ? convertRedisOptions(config.redisForPubsub, mixin.host) : mixin.redis;
mixin.redisForJobQueue = config.redisForJobQueue ? convertRedisOptions(config.redisForJobQueue, mixin.host) : mixin.redis;
return Object.assign(config, mixin);
}
@ -199,3 +192,14 @@ function tryCreateUrl(url: string) {
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,
};
}

View file

@ -4,10 +4,9 @@ import { IsNull, In, MoreThan, Not } from 'typeorm';
import { bindThis } from '@/decorators.js';
import { DI } from '@/di-symbols.js';
import type { Config } from '@/config.js';
import type { LocalUser, RemoteUser } from '@/models/entities/User.js';
import type { LocalUser, RemoteUser, User } from '@/models/entities/User.js';
import type { BlockingsRepository, FollowingsRepository, InstancesRepository, Muting, MutingsRepository, UserListJoiningsRepository, UsersRepository } from '@/models/index.js';
import type { RelationshipJobData, ThinUser } from '@/queue/types.js';
import type { User } from '@/models/entities/User.js';
import { IdService } from '@/core/IdService.js';
import { GlobalEventService } from '@/core/GlobalEventService.js';

View file

@ -4,6 +4,7 @@ import { dirname } from 'node:path';
import { Inject, Injectable } from '@nestjs/common';
import * as nsfw from 'nsfwjs';
import si from 'systeminformation';
import { Mutex } from 'async-mutex';
import type { Config } from '@/config.js';
import { DI } from '@/di-symbols.js';
import { bindThis } from '@/decorators.js';
@ -17,6 +18,7 @@ let isSupportedCpu: undefined | boolean = undefined;
@Injectable()
export class AiService {
private model: nsfw.NSFWJS;
private modelLoadMutex: Mutex = new Mutex();
constructor(
@Inject(DI.config)
@ -39,7 +41,13 @@ export class AiService {
const tf = await import('@tensorflow/tfjs-node');
if (this.model == null) this.model = await nsfw.load(`file://${_dirname}/../../nsfw-model/`, { size: 299 });
if (this.model == null) {
await this.modelLoadMutex.runExclusive(async () => {
if (this.model == null) {
this.model = await nsfw.load(`file://${_dirname}/../../nsfw-model/`, { size: 299 });
}
});
}
const buffer = await fs.promises.readFile(path);
const image = await tf.node.decodeImage(buffer, 3) as any;

View file

@ -32,11 +32,6 @@ export class AppLockService {
return this.lock(`ap-object:${uri}`, timeout);
}
@bindThis
public getFetchInstanceMetadataLock(host: string, timeout = 30 * 1000): Promise<() => void> {
return this.lock(`instance:${host}`, timeout);
}
@bindThis
public getChartInsertLock(lockKey: string, timeout = 30 * 1000): Promise<() => void> {
return this.lock(`chart-insert:${lockKey}`, timeout);

View file

@ -12,10 +12,10 @@ import type { OnApplicationShutdown } from '@nestjs/common';
@Injectable()
export class CacheService implements OnApplicationShutdown {
public userByIdCache: MemoryKVCache<User>;
public localUserByNativeTokenCache: MemoryKVCache<LocalUser | null>;
public userByIdCache: MemoryKVCache<User, User | string>;
public localUserByNativeTokenCache: MemoryKVCache<LocalUser | null, string | null>;
public localUserByIdCache: MemoryKVCache<LocalUser>;
public uriPersonCache: MemoryKVCache<User | null>;
public uriPersonCache: MemoryKVCache<User | null, string | null>;
public userProfileCache: RedisKVCache<UserProfile>;
public flashAccessTokensCache: RedisKVCache<FlashToken | null>;
public userMutingsCache: RedisKVCache<Set<string>>;
@ -57,10 +57,41 @@ export class CacheService implements OnApplicationShutdown {
) {
//this.onMessage = this.onMessage.bind(this);
this.userByIdCache = new MemoryKVCache<User>(Infinity);
this.localUserByNativeTokenCache = new MemoryKVCache<LocalUser | null>(Infinity);
this.localUserByIdCache = new MemoryKVCache<LocalUser>(Infinity);
this.uriPersonCache = new MemoryKVCache<User | null>(Infinity);
const localUserByIdCache = new MemoryKVCache<LocalUser>(1000 * 60 * 60 * 6 /* 6h */);
this.localUserByIdCache = localUserByIdCache;
// ローカルユーザーならlocalUserByIdCacheにデータを追加し、こちらにはid(文字列)だけを追加する
const userByIdCache = new MemoryKVCache<User, User | string>(1000 * 60 * 60 * 6 /* 6h */, {
toMapConverter: user => {
if (user.host === null) {
localUserByIdCache.set(user.id, user as LocalUser);
return user.id;
}
return user;
},
fromMapConverter: userOrId => typeof userOrId === 'string' ? localUserByIdCache.get(userOrId) : userOrId,
});
this.userByIdCache = userByIdCache;
this.localUserByNativeTokenCache = new MemoryKVCache<LocalUser | null, string | null>(Infinity, {
toMapConverter: user => {
if (user === null) return null;
localUserByIdCache.set(user.id, user);
return user.id;
},
fromMapConverter: id => id === null ? null : localUserByIdCache.get(id),
});
this.uriPersonCache = new MemoryKVCache<User | null, string | null>(Infinity, {
toMapConverter: user => {
if (user === null) return null;
userByIdCache.set(user.id, user);
return user.id;
},
fromMapConverter: id => id === null ? null : userByIdCache.get(id),
});
this.userProfileCache = new RedisKVCache<UserProfile>(this.redisClient, 'userProfile', {
lifetime: 1000 * 60 * 30, // 30m
@ -140,7 +171,7 @@ export class CacheService implements OnApplicationShutdown {
const user = await this.usersRepository.findOneByOrFail({ id: body.id });
this.userByIdCache.set(user.id, user);
for (const [k, v] of this.uriPersonCache.cache.entries()) {
if (v.value?.id === user.id) {
if (v.value === user.id) {
this.uriPersonCache.set(k, user);
}
}

View file

@ -82,6 +82,7 @@ import { GalleryLikeEntityService } from './entities/GalleryLikeEntityService.js
import { GalleryPostEntityService } from './entities/GalleryPostEntityService.js';
import { HashtagEntityService } from './entities/HashtagEntityService.js';
import { InstanceEntityService } from './entities/InstanceEntityService.js';
import { InviteCodeEntityService } from './entities/InviteCodeEntityService.js';
import { MessagingMessageEntityService } from './entities/MessagingMessageEntityService.js';
import { ModerationLogEntityService } from './entities/ModerationLogEntityService.js';
import { MutingEntityService } from './entities/MutingEntityService.js';
@ -211,6 +212,7 @@ const $GalleryLikeEntityService: Provider = { provide: 'GalleryLikeEntityService
const $GalleryPostEntityService: Provider = { provide: 'GalleryPostEntityService', useExisting: GalleryPostEntityService };
const $HashtagEntityService: Provider = { provide: 'HashtagEntityService', useExisting: HashtagEntityService };
const $InstanceEntityService: Provider = { provide: 'InstanceEntityService', useExisting: InstanceEntityService };
const $InviteCodeEntityService: Provider = { provide: 'InviteCodeEntityService', useExisting: InviteCodeEntityService };
const $MessagingMessageEntityService: Provider = { provide: 'MessagingMessageEntityService', useExisting: MessagingMessageEntityService };
const $ModerationLogEntityService: Provider = { provide: 'ModerationLogEntityService', useExisting: ModerationLogEntityService };
const $MutingEntityService: Provider = { provide: 'MutingEntityService', useExisting: MutingEntityService };
@ -340,6 +342,7 @@ const $ApEventService: Provider = { provide: 'ApEventService', useExisting: ApEv
GalleryPostEntityService,
HashtagEntityService,
InstanceEntityService,
InviteCodeEntityService,
MessagingMessageEntityService,
ModerationLogEntityService,
MutingEntityService,
@ -464,6 +467,7 @@ const $ApEventService: Provider = { provide: 'ApEventService', useExisting: ApEv
$GalleryPostEntityService,
$HashtagEntityService,
$InstanceEntityService,
$InviteCodeEntityService,
$MessagingMessageEntityService,
$ModerationLogEntityService,
$MutingEntityService,
@ -588,6 +592,7 @@ const $ApEventService: Provider = { provide: 'ApEventService', useExisting: ApEv
GalleryPostEntityService,
HashtagEntityService,
InstanceEntityService,
InviteCodeEntityService,
MessagingMessageEntityService,
ModerationLogEntityService,
MutingEntityService,
@ -711,6 +716,7 @@ const $ApEventService: Provider = { provide: 'ApEventService', useExisting: ApEv
$GalleryPostEntityService,
$HashtagEntityService,
$InstanceEntityService,
$InviteCodeEntityService,
$MessagingMessageEntityService,
$ModerationLogEntityService,
$MutingEntityService,

View file

@ -1,6 +1,6 @@
import { randomUUID } from 'node:crypto';
import { Inject, Injectable } from '@nestjs/common';
import bcrypt from 'bcryptjs';
import { v4 as uuid } from 'uuid';
import { IsNull, DataSource } from 'typeorm';
import { genRsaKeyPair } from '@/misc/gen-key-pair.js';
import { User } from '@/models/entities/User.js';
@ -24,7 +24,7 @@ export class CreateSystemUserService {
@bindThis
public async createSystemUser(username: string): Promise<User> {
const password = uuid();
const password = randomUUID();
// Generate hash of password
const salt = await bcrypt.genSalt(8);
@ -33,7 +33,7 @@ export class CreateSystemUserService {
// Generate secret
const secret = generateNativeUserToken();
const keyPair = await genRsaKeyPair(4096);
const keyPair = await genRsaKeyPair();
let account!: User;

View file

@ -1,9 +1,7 @@
import * as fs from 'node:fs';
import * as stream from 'node:stream';
import * as util from 'node:util';
import * as stream from 'node:stream/promises';
import { Inject, Injectable } from '@nestjs/common';
import IPCIDR from 'ip-cidr';
import PrivateIp from 'private-ip';
import ipaddr from 'ipaddr.js';
import chalk from 'chalk';
import got, * as Got from 'got';
import { parse } from 'content-disposition';
@ -15,7 +13,6 @@ import { StatusError } from '@/misc/status-error.js';
import { LoggerService } from '@/core/LoggerService.js';
import type Logger from '@/logger.js';
const pipeline = util.promisify(stream.pipeline);
import { bindThis } from '@/decorators.js';
@Injectable()
@ -103,7 +100,7 @@ export class DownloadService {
});
try {
await pipeline(req, fs.createWriteStream(path));
await stream.pipeline(req, fs.createWriteStream(path));
} catch (e) {
if (e instanceof Got.HTTPError) {
throw new StatusError(`${e.response.statusCode} ${e.response.statusMessage}`, e.response.statusCode, e.response.statusMessage);
@ -130,7 +127,7 @@ export class DownloadService {
// write content at URL to temp file
await this.downloadUrl(url, path);
const text = await util.promisify(fs.readFile)(path, 'utf8');
const text = await fs.promises.readFile(path, 'utf8');
return text;
} finally {
@ -140,13 +137,14 @@ export class DownloadService {
@bindThis
private isPrivateIp(ip: string): boolean {
const parsedIp = ipaddr.parse(ip);
for (const net of this.config.allowedPrivateNetworks ?? []) {
const cidr = new IPCIDR(net);
if (cidr.contains(ip)) {
if (parsedIp.match(ipaddr.parseCIDR(net))) {
return false;
}
}
return PrivateIp(ip) ?? false;
return parsedIp.range() !== 'unicast';
}
}

View file

@ -1,6 +1,6 @@
import { randomUUID } from 'node:crypto';
import * as fs from 'node:fs';
import { Inject, Injectable } from '@nestjs/common';
import { v4 as uuid } from 'uuid';
import sharp from 'sharp';
import { sharpBmp } from 'sharp-read-bmp';
import { IsNull } from 'typeorm';
@ -131,9 +131,10 @@ export class DriveService {
* @param type Content-Type for original
* @param hash Hash for original
* @param size Size for original
* @param isRemote If true, file is remote file
*/
@bindThis
private async save(file: DriveFile, path: string, name: string, type: string, hash: string, size: number): Promise<DriveFile> {
private async save(file: DriveFile, path: string, name: string, type: string, hash: string, size: number, isRemote: boolean): Promise<DriveFile> {
// thunbnail, webpublic を必要なら生成
const alts = await this.generateAlts(path, type, !file.uri);
@ -158,11 +159,19 @@ export class DriveService {
ext = '';
}
const baseUrl = meta.objectStorageBaseUrl
?? `${ meta.objectStorageUseSSL ? 'https' : 'http' }://${ meta.objectStorageEndpoint }${ meta.objectStoragePort ? `:${meta.objectStoragePort}` : '' }/${ meta.objectStorageBucket }`;
const useObjectStorageRemote = isRemote && meta.useObjectStorageRemote;
const objectStorageBaseUrl = useObjectStorageRemote ? meta.objectStorageRemoteBaseUrl : meta.objectStorageBaseUrl;
const objectStorageUseSSL = useObjectStorageRemote ? meta.objectStorageRemoteUseSSL : meta.objectStorageUseSSL;
const objectStorageEndpoint = useObjectStorageRemote ? meta.objectStorageRemoteEndpoint : meta.objectStorageEndpoint;
const objectStoragePort = useObjectStorageRemote ? meta.objectStorageRemotePort : meta.objectStoragePort;
const objectStorageBucket = useObjectStorageRemote ? meta.objectStorageRemoteBucket : meta.objectStorageBucket;
const objectStoragePrefix = useObjectStorageRemote ? meta.objectStorageRemotePrefix : meta.objectStoragePrefix;
const baseUrl = objectStorageBaseUrl
?? `${ objectStorageUseSSL ? 'https' : 'http' }://${ objectStorageEndpoint }${ objectStoragePort ? `:${objectStoragePort}` : '' }/${ objectStorageBucket }`;
// for original
const key = `${meta.objectStoragePrefix}/${uuid()}${ext}`;
const key = `${objectStoragePrefix}/${randomUUID()}${ext}`;
const url = `${ baseUrl }/${ key }`;
// for alts
@ -175,23 +184,23 @@ export class DriveService {
//#region Uploads
this.registerLogger.info(`uploading original: ${key}`);
const uploads = [
this.upload(key, fs.createReadStream(path), type, null, name),
this.upload(key, fs.createReadStream(path), type, isRemote, null, name),
];
if (alts.webpublic) {
webpublicKey = `${meta.objectStoragePrefix}/webpublic-${uuid()}.${alts.webpublic.ext}`;
webpublicKey = `${objectStoragePrefix}/webpublic-${randomUUID()}.${alts.webpublic.ext}`;
webpublicUrl = `${ baseUrl }/${ webpublicKey }`;
this.registerLogger.info(`uploading webpublic: ${webpublicKey}`);
uploads.push(this.upload(webpublicKey, alts.webpublic.data, alts.webpublic.type, alts.webpublic.ext, name));
uploads.push(this.upload(webpublicKey, alts.webpublic.data, alts.webpublic.type, isRemote, alts.webpublic.ext, name));
}
if (alts.thumbnail) {
thumbnailKey = `${meta.objectStoragePrefix}/thumbnail-${uuid()}.${alts.thumbnail.ext}`;
thumbnailKey = `${objectStoragePrefix}/thumbnail-${randomUUID()}.${alts.thumbnail.ext}`;
thumbnailUrl = `${ baseUrl }/${ thumbnailKey }`;
this.registerLogger.info(`uploading thumbnail: ${thumbnailKey}`);
uploads.push(this.upload(thumbnailKey, alts.thumbnail.data, alts.thumbnail.type, alts.thumbnail.ext, `${name}.thumbnail`));
uploads.push(this.upload(thumbnailKey, alts.thumbnail.data, alts.thumbnail.type, isRemote, alts.thumbnail.ext, `${name}.thumbnail`));
}
await Promise.all(uploads);
@ -212,9 +221,9 @@ export class DriveService {
return await this.driveFilesRepository.insert(file).then(x => this.driveFilesRepository.findOneByOrFail(x.identifiers[0]));
} else { // use internal storage
const accessKey = uuid();
const thumbnailAccessKey = 'thumbnail-' + uuid();
const webpublicAccessKey = 'webpublic-' + uuid();
const accessKey = randomUUID();
const thumbnailAccessKey = 'thumbnail-' + randomUUID();
const webpublicAccessKey = 'webpublic-' + randomUUID();
const url = this.internalStorageService.saveFromPath(accessKey, path);
@ -360,14 +369,18 @@ export class DriveService {
* Upload to ObjectStorage
*/
@bindThis
private async upload(key: string, stream: fs.ReadStream | Buffer, type: string, ext?: string | null, filename?: string) {
private async upload(key: string, stream: fs.ReadStream | Buffer, type: string, isRemote: boolean, ext?: string | null, filename?: string) {
if (type === 'image/apng') type = 'image/png';
if (!FILE_TYPE_BROWSERSAFE.includes(type)) type = 'application/octet-stream';
const meta = await this.metaService.fetch();
const useObjectStorageRemote = isRemote && meta.useObjectStorageRemote;
const objectStorageBucket = useObjectStorageRemote ? meta.objectStorageRemoteBucket : meta.objectStorageBucket;
const objectStorageSetPublicRead = useObjectStorageRemote ? meta.objectStorageRemoteSetPublicRead : meta.objectStorageSetPublicRead;
const params = {
Bucket: meta.objectStorageBucket,
Bucket: objectStorageBucket,
Key: key,
Body: stream,
ContentType: type,
@ -380,9 +393,9 @@ export class DriveService {
// 許可されているファイル形式でしか拡張子をつけない
ext ? correctFilename(filename, ext) : filename,
);
if (meta.objectStorageSetPublicRead) params.ACL = 'public-read';
if (objectStorageSetPublicRead) params.ACL = 'public-read';
await this.s3Service.upload(meta, params)
await this.s3Service.upload(meta, params, isRemote)
.then(
result => {
if ('Bucket' in result) { // CompleteMultipartUploadCommandOutput
@ -584,9 +597,9 @@ export class DriveService {
if (isLink) {
file.url = url;
// ローカルプロキシ用
file.accessKey = uuid();
file.thumbnailAccessKey = 'thumbnail-' + uuid();
file.webpublicAccessKey = 'webpublic-' + uuid();
file.accessKey = randomUUID();
file.thumbnailAccessKey = 'thumbnail-' + randomUUID();
file.webpublicAccessKey = 'webpublic-' + randomUUID();
}
}
@ -618,7 +631,8 @@ export class DriveService {
}
}
} else {
file = await (this.save(file, path, detectedName, info.type.mime, info.md5, info.size));
const isRemote = user ? this.userEntityService.isRemoteUser(user) : false;
file = await (this.save(file, path, detectedName, info.type.mime, info.md5, info.size, isRemote));
}
this.registerLogger.succ(`drive file has been created ${file.id}`);
@ -672,7 +686,7 @@ export class DriveService {
}
@bindThis
public async deleteFileSync(file: DriveFile, isExpired = false) {
public async deleteFileSync(file: DriveFile, isExpired = false, isRemote: boolean) {
if (file.storedInternal) {
this.internalStorageService.del(file.accessKey!);
@ -686,14 +700,14 @@ export class DriveService {
} else if (!file.isLink) {
const promises = [];
promises.push(this.deleteObjectStorageFile(file.accessKey!));
promises.push(this.deleteObjectStorageFile(file.accessKey!, isRemote));
if (file.thumbnailUrl) {
promises.push(this.deleteObjectStorageFile(file.thumbnailAccessKey!));
promises.push(this.deleteObjectStorageFile(file.thumbnailAccessKey!, isRemote));
}
if (file.webpublicUrl) {
promises.push(this.deleteObjectStorageFile(file.webpublicAccessKey!));
promises.push(this.deleteObjectStorageFile(file.webpublicAccessKey!, isRemote));
}
await Promise.all(promises);
@ -713,9 +727,9 @@ export class DriveService {
webpublicUrl: null,
storedInternal: false,
// ローカルプロキシ用
accessKey: uuid(),
thumbnailAccessKey: 'thumbnail-' + uuid(),
webpublicAccessKey: 'webpublic-' + uuid(),
accessKey: randomUUID(),
thumbnailAccessKey: 'thumbnail-' + randomUUID(),
webpublicAccessKey: 'webpublic-' + randomUUID(),
});
} else {
this.driveFilesRepository.delete(file.id);
@ -733,15 +747,17 @@ export class DriveService {
}
@bindThis
public async deleteObjectStorageFile(key: string) {
public async deleteObjectStorageFile(key: string, isRemote: boolean) {
const meta = await this.metaService.fetch();
const useObjectStorageRemote = isRemote && meta.useObjectStorageRemote;
const objectStorageBucket = useObjectStorageRemote ? meta.objectStorageRemoteBucket : meta.objectStorageBucket;
try {
const param = {
Bucket: meta.objectStorageBucket,
Bucket: objectStorageBucket,
Key: key,
} as DeleteObjectCommandInput;
await this.s3Service.delete(meta, param);
await this.s3Service.delete(meta, param, isRemote);
} catch (err: any) {
if (err.name === 'NoSuchKey') {
this.deleteLogger.warn(`The object storage had no such key to delete: ${key}. Skipping this.`, err as Error);

View file

@ -2,9 +2,8 @@ import { URL } from 'node:url';
import { Inject, Injectable } from '@nestjs/common';
import { JSDOM } from 'jsdom';
import tinycolor from 'tinycolor2';
import * as Redis from 'ioredis';
import type { Instance } from '@/models/entities/Instance.js';
import type { InstancesRepository } from '@/models/index.js';
import { AppLockService } from '@/core/AppLockService.js';
import type Logger from '@/logger.js';
import { DI } from '@/di-symbols.js';
import { LoggerService } from '@/core/LoggerService.js';
@ -37,33 +36,43 @@ export class FetchInstanceMetadataService {
private logger: Logger;
constructor(
@Inject(DI.instancesRepository)
private instancesRepository: InstancesRepository,
private appLockService: AppLockService,
private httpRequestService: HttpRequestService,
private loggerService: LoggerService,
private federatedInstanceService: FederatedInstanceService,
@Inject(DI.redis)
private redisClient: Redis.Redis,
) {
this.logger = this.loggerService.getLogger('metadata', 'cyan');
}
@bindThis
public async tryLock(host: string): Promise<boolean> {
const mutex = await this.redisClient.set(`fetchInstanceMetadata:mutex:${host}`, '1', 'GET');
return mutex !== '1';
}
@bindThis
public unlock(host: string): Promise<'OK'> {
return this.redisClient.set(`fetchInstanceMetadata:mutex:${host}`, '0');
}
@bindThis
public async fetchInstanceMetadata(instance: Instance, force = false): Promise<void> {
const unlock = await this.appLockService.getFetchInstanceMetadataLock(instance.host);
if (!force) {
const _instance = await this.instancesRepository.findOneBy({ host: instance.host });
const now = Date.now();
if (_instance && _instance.infoUpdatedAt && (now - _instance.infoUpdatedAt.getTime() < 1000 * 60 * 60 * 24)) {
unlock();
return;
}
}
this.logger.info(`Fetching metadata of ${instance.host} ...`);
const host = instance.host;
// Acquire mutex to ensure no parallel runs
if (!await this.tryLock(host)) return;
try {
if (!force) {
const _instance = await this.federatedInstanceService.fetch(host);
const now = Date.now();
if (_instance && _instance.infoUpdatedAt && (now - _instance.infoUpdatedAt.getTime() < 1000 * 60 * 60 * 24)) {
// unlock at the finally caluse
return;
}
}
this.logger.info(`Fetching metadata of ${instance.host} ...`);
const [info, dom, manifest] = await Promise.all([
this.fetchNodeinfo(instance).catch(() => null),
this.fetchDom(instance).catch(() => null),
@ -94,7 +103,7 @@ export class FetchInstanceMetadataService {
if (name) updates.name = name;
if (description) updates.description = description;
if (icon || favicon) updates.iconUrl = icon ?? favicon;
if (icon || favicon) updates.iconUrl = (icon && !icon.includes('data:image/png;base64')) ? icon : favicon;
if (favicon) updates.faviconUrl = favicon;
if (themeColor) updates.themeColor = themeColor;
@ -104,7 +113,7 @@ export class FetchInstanceMetadataService {
} catch (e) {
this.logger.error(`Failed to update metadata of ${instance.host}: ${e}`);
} finally {
unlock();
await this.unlock(host);
}
}

View file

@ -1,8 +1,7 @@
import * as fs from 'node:fs';
import * as crypto from 'node:crypto';
import { join } from 'node:path';
import * as stream from 'node:stream';
import * as util from 'node:util';
import * as stream from 'node:stream/promises';
import { Injectable } from '@nestjs/common';
import { FSWatcher } from 'chokidar';
import * as fileType from 'file-type';
@ -16,8 +15,6 @@ import { createTempDir } from '@/misc/create-temp.js';
import { AiService } from '@/core/AiService.js';
import { bindThis } from '@/decorators.js';
const pipeline = util.promisify(stream.pipeline);
export type FileInfo = {
size: number;
md5: string;
@ -304,11 +301,11 @@ export class FileInfoService {
@bindThis
public fixMime(mime: string | fileType.MimeType): string {
// see https://github.com/misskey-dev/misskey/pull/10686
if (mime === "audio/x-flac") {
return "audio/flac";
if (mime === 'audio/x-flac') {
return 'audio/flac';
}
if (mime === "audio/vnd.wave") {
return "audio/wav";
if (mime === 'audio/vnd.wave') {
return 'audio/wav';
}
return mime;
@ -355,11 +352,12 @@ export class FileInfoService {
* Check the file is SVG or not
*/
@bindThis
public async checkSvg(path: string) {
public async checkSvg(path: string): Promise<boolean> {
try {
const size = await this.getFileSize(path);
if (size > 1 * 1024 * 1024) return false;
return isSvg(fs.readFileSync(path));
const buffer = await fs.promises.readFile(path);
return isSvg(buffer.toString());
} catch {
return false;
}
@ -370,8 +368,7 @@ export class FileInfoService {
*/
@bindThis
public async getFileSize(path: string): Promise<number> {
const getStat = util.promisify(fs.stat);
return (await getStat(path)).size;
return (await fs.promises.stat(path)).size;
}
/**
@ -380,7 +377,7 @@ export class FileInfoService {
@bindThis
private async calcHash(path: string): Promise<string> {
const hash = crypto.createHash('md5').setEncoding('hex');
await pipeline(fs.createReadStream(path), hash);
await stream.pipeline(fs.createReadStream(path), hash);
return hash.read();
}

View file

@ -24,7 +24,7 @@ import type { Packed } from '@/misc/json-schema.js';
import { DI } from '@/di-symbols.js';
import type { Config } from '@/config.js';
import { bindThis } from '@/decorators.js';
import { Role } from '@/models';
import { Role } from '@/models/index.js';
@Injectable()
export class GlobalEventService {

View file

@ -1,5 +1,6 @@
import * as http from 'node:http';
import * as https from 'node:https';
import * as net from 'node:net';
import CacheableLookup from 'cacheable-lookup';
import fetch from 'node-fetch';
import { HttpProxyAgent, HttpsProxyAgent } from 'hpagent';
@ -46,14 +47,14 @@ export class HttpRequestService {
this.http = new http.Agent({
keepAlive: true,
keepAliveMsecs: 30 * 1000,
lookup: cache.lookup,
} as http.AgentOptions);
lookup: cache.lookup as unknown as net.LookupFunction,
});
this.https = new https.Agent({
keepAlive: true,
keepAliveMsecs: 30 * 1000,
lookup: cache.lookup,
} as https.AgentOptions);
lookup: cache.lookup as unknown as net.LookupFunction,
});
const maxSockets = Math.max(256, config.deliverJobConcurrency ?? 128);
@ -144,7 +145,7 @@ export class HttpRequestService {
method: args.method ?? 'GET',
headers: {
'User-Agent': this.config.userAgent,
...(args.headers ?? {})
...(args.headers ?? {}),
},
body: args.body,
size: args.size ?? 10 * 1024 * 1024,

View file

@ -5,7 +5,7 @@ import type { Config } from '@/config.js';
import { genAid, parseAid } from '@/misc/id/aid.js';
import { genMeid, parseMeid } from '@/misc/id/meid.js';
import { genMeidg, parseMeidg } from '@/misc/id/meidg.js';
import { genObjectId } from '@/misc/id/object-id.js';
import { genObjectId, parseObjectId } from '@/misc/id/object-id.js';
import { bindThis } from '@/decorators.js';
import { parseUlid } from '@/misc/id/ulid.js';
@ -38,7 +38,7 @@ export class IdService {
public parse(id: string): { date: Date; } {
switch (this.method) {
case 'aid': return parseAid(id);
case 'objectid':
case 'objectid': return parseObjectId(id);
case 'meid': return parseMeid(id);
case 'meidg': return parseMeidg(id);
case 'ulid': return parseUlid(id);

View file

@ -3,7 +3,7 @@ import { DI } from '@/di-symbols.js';
import type { Config } from '@/config.js';
import Logger from '@/logger.js';
import { bindThis } from '@/decorators.js';
import type { KEYWORD } from 'color-convert/conversions';
import type { KEYWORD } from 'color-convert/conversions.js';
@Injectable()
export class LoggerService {

View file

@ -593,12 +593,14 @@ export class NoteCreateService implements OnApplicationShutdown {
if (data.reply) {
// 通知
if (data.reply.userHost === null) {
const threadMuted = await this.noteThreadMutingsRepository.findOneBy({
userId: data.reply.userId,
threadId: data.reply.threadId ?? data.reply.id,
const isThreadMuted = await this.noteThreadMutingsRepository.exist({
where: {
userId: data.reply.userId,
threadId: data.reply.threadId ?? data.reply.id,
},
});
if (!threadMuted) {
if (!isThreadMuted) {
nm.push(data.reply.userId, 'reply');
this.globalEventService.publishMainStream(data.reply.userId, 'reply', noteObj);
@ -735,12 +737,14 @@ export class NoteCreateService implements OnApplicationShutdown {
@bindThis
private async createMentionedEvents(mentionedUsers: MinimumUser[], note: Note, nm: NotificationManager) {
for (const u of mentionedUsers.filter(u => this.userEntityService.isLocalUser(u))) {
const threadMuted = await this.noteThreadMutingsRepository.findOneBy({
userId: u.id,
threadId: note.threadId ?? note.id,
const isThreadMuted = await this.noteThreadMutingsRepository.exist({
where: {
userId: u.id,
threadId: note.threadId ?? note.id,
},
});
if (threadMuted) {
if (isThreadMuted) {
continue;
}

View file

@ -17,6 +17,7 @@ import { UserEntityService } from '@/core/entities/UserEntityService.js';
import { NoteEntityService } from '@/core/entities/NoteEntityService.js';
import { bindThis } from '@/decorators.js';
import { MetaService } from '@/core/MetaService.js';
import { SearchService } from '@/core/SearchService.js';
@Injectable()
export class NoteDeleteService {
@ -41,6 +42,7 @@ export class NoteDeleteService {
private apRendererService: ApRendererService,
private apDeliverManagerService: ApDeliverManagerService,
private metaService: MetaService,
private searchService: SearchService,
private notesChart: NotesChart,
private perUserNotesChart: PerUserNotesChart,
private instanceChart: InstanceChart,
@ -53,6 +55,7 @@ export class NoteDeleteService {
*/
async delete(user: { id: User['id']; uri: User['uri']; host: User['host']; isBot: User['isBot']; }, note: Note, quiet = false) {
const deletedAt = new Date();
const cascadingNotes = await this.findCascadingNotes(note);
// この投稿を除く指定したユーザーによる指定したノートのリノートが存在しないとき
if (note.renoteId && (await this.noteEntityService.countSameRenotes(user.id, note.renoteId, note.id)) === 0) {
@ -88,8 +91,8 @@ export class NoteDeleteService {
}
// also deliever delete activity to cascaded notes
const cascadingNotes = (await this.findCascadingNotes(note)).filter(note => !note.localOnly); // filter out local-only notes
for (const cascadingNote of cascadingNotes) {
const federatedLocalCascadingNotes = (cascadingNotes).filter(note => !note.localOnly && note.userHost == null); // filter out local-only notes
for (const cascadingNote of federatedLocalCascadingNotes) {
if (!cascadingNote.user) continue;
if (!this.userEntityService.isLocalUser(cascadingNote.user)) continue;
const content = this.apRendererService.addContext(this.apRendererService.renderDelete(this.apRendererService.renderTombstone(`${this.config.url}/notes/${cascadingNote.id}`), cascadingNote.user));
@ -114,6 +117,11 @@ export class NoteDeleteService {
}
}
for (const cascadingNote of cascadingNotes) {
this.searchService.unindexNote(cascadingNote);
}
this.searchService.unindexNote(note);
await this.notesRepository.delete({
id: note.id,
userId: user.id,
@ -121,10 +129,8 @@ export class NoteDeleteService {
}
@bindThis
private async findCascadingNotes(note: Note) {
const cascadingNotes: Note[] = [];
const recursive = async (noteId: string) => {
private async findCascadingNotes(note: Note): Promise<Note[]> {
const recursive = async (noteId: string): Promise<Note[]> => {
const query = this.notesRepository.createQueryBuilder('note')
.where('note.replyId = :noteId', { noteId })
.orWhere(new Brackets(q => {
@ -133,14 +139,16 @@ export class NoteDeleteService {
}))
.leftJoinAndSelect('note.user', 'user');
const replies = await query.getMany();
for (const reply of replies) {
cascadingNotes.push(reply);
await recursive(reply.id);
}
};
await recursive(note.id);
return cascadingNotes.filter(note => note.userHost === null); // filter out non-local users
return [
replies,
...await Promise.all(replies.map(reply => recursive(reply.id))),
].flat();
};
const cascadingNotes: Note[] = await recursive(note.id);
return cascadingNotes;
}
@bindThis

View file

@ -43,11 +43,13 @@ export class NoteReadService implements OnApplicationShutdown {
//#endregion
// スレッドミュート
const threadMute = await this.noteThreadMutingsRepository.findOneBy({
userId: userId,
threadId: note.threadId ?? note.id,
const isThreadMuted = await this.noteThreadMutingsRepository.exist({
where: {
userId: userId,
threadId: note.threadId ?? note.id,
},
});
if (threadMute) return;
if (isThreadMuted) return;
const unread = {
id: this.idService.genId(),
@ -62,9 +64,9 @@ export class NoteReadService implements OnApplicationShutdown {
// 2秒経っても既読にならなかったら「未読の投稿がありますよ」イベントを発行する
setTimeout(2000, 'unread note', { signal: this.#shutdownController.signal }).then(async () => {
const exist = await this.noteUnreadsRepository.findOneBy({ id: unread.id });
const exist = await this.noteUnreadsRepository.exist({ where: { id: unread.id } });
if (exist == null) return;
if (!exist) return;
if (params.isMentioned) {
this.globalEventService.publishMainStream(userId, 'unreadMention', note.id);

View file

@ -3,7 +3,7 @@ import push from 'web-push';
import * as Redis from 'ioredis';
import { DI } from '@/di-symbols.js';
import type { Config } from '@/config.js';
import type { Packed } from '@/misc/json-schema';
import type { Packed } from '@/misc/json-schema.js';
import { getNoteSummary } from '@/misc/get-note-summary.js';
import type { SwSubscription, SwSubscriptionsRepository } from '@/models/index.js';
import { MetaService } from '@/core/MetaService.js';

View file

@ -1,5 +1,5 @@
import { randomUUID } from 'node:crypto';
import { Inject, Injectable } from '@nestjs/common';
import { v4 as uuid } from 'uuid';
import type { IActivity } from '@/core/activitypub/type.js';
import type { DriveFile } from '@/models/entities/DriveFile.js';
import type { Webhook, webhookEventTypes } from '@/models/entities/Webhook.js';
@ -8,7 +8,7 @@ import { DI } from '@/di-symbols.js';
import { bindThis } from '@/decorators.js';
import type { Antenna } from '@/server/api/endpoints/i/import-antennas.js';
import type { DbQueue, DeliverQueue, EndedPollNotificationQueue, InboxQueue, ObjectStorageQueue, RelationshipQueue, SystemQueue, WebhookDeliverQueue } from './QueueModule.js';
import type { DbJobData, RelationshipJobData, ThinUser } from '../queue/types.js';
import type { DbJobData, DeliverJobData, RelationshipJobData, ThinUser } from '../queue/types.js';
import type httpSignature from '@peertube/http-signature';
import type * as Bull from 'bullmq';
@ -69,7 +69,7 @@ export class QueueService {
if (content == null) return null;
if (to == null) return null;
const data = {
const data: DeliverJobData = {
user: {
id: user.id,
},
@ -88,6 +88,40 @@ export class QueueService {
});
}
/**
* ApDeliverManager-DeliverManager.execute()inboxesを突っ込んでaddBulkしたい
* @param user `{ id: string; }` ThinUserに変換しないので前もって変換してください
* @param content IActivity | null
* @param inboxes `Map<string, boolean>` / key: to (inbox url), value: isSharedInbox (whether it is sharedInbox)
* @returns void
*/
@bindThis
public async deliverMany(user: ThinUser, content: IActivity | null, inboxes: Map<string, boolean>) {
if (content == null) return null;
const opts = {
attempts: this.config.deliverJobMaxAttempts ?? 12,
backoff: {
type: 'custom',
},
removeOnComplete: true,
removeOnFail: true,
};
await this.deliverQueue.addBulk(Array.from(inboxes.entries(), d => ({
name: d[0],
data: {
user,
content,
to: d[0],
isSharedInbox: d[1],
} as DeliverJobData,
opts,
})));
return;
}
@bindThis
public inbox(activity: IActivity, signature: httpSignature.IParsedSignature) {
const data = {
@ -382,7 +416,7 @@ export class QueueService {
to: webhook.url,
secret: webhook.secret,
createdAt: Date.now(),
eventId: uuid(),
eventId: randomUUID(),
};
return this.webhookDeliverQueue.add(webhook.id, data, {
@ -400,11 +434,11 @@ export class QueueService {
this.deliverQueue.once('cleaned', (jobs, status) => {
//deliverLogger.succ(`Cleaned ${jobs.length} ${status} jobs`);
});
this.deliverQueue.clean(0, Infinity, 'delayed');
this.deliverQueue.clean(0, 0, 'delayed');
this.inboxQueue.once('cleaned', (jobs, status) => {
//inboxLogger.succ(`Cleaned ${jobs.length} ${status} jobs`);
});
this.inboxQueue.clean(0, Infinity, 'delayed');
this.inboxQueue.clean(0, 0, 'delayed');
}
}

View file

@ -8,8 +8,9 @@ import type { LocalUser, RemoteUser } from '@/models/entities/User.js';
import type { Config } from '@/config.js';
import type Logger from '@/logger.js';
import { UtilityService } from '@/core/UtilityService.js';
import { WebfingerService } from '@/core/WebfingerService.js';
import { ILink, WebfingerService } from '@/core/WebfingerService.js';
import { RemoteLoggerService } from '@/core/RemoteLoggerService.js';
import { ApDbResolverService } from '@/core/activitypub/ApDbResolverService.js';
import { ApPersonService } from '@/core/activitypub/models/ApPersonService.js';
import { bindThis } from '@/decorators.js';
@ -27,6 +28,7 @@ export class RemoteUserResolveService {
private utilityService: UtilityService,
private webfingerService: WebfingerService,
private remoteLoggerService: RemoteLoggerService,
private apDbResolverService: ApDbResolverService,
private apPersonService: ApPersonService,
) {
this.logger = this.remoteLoggerService.logger.createSubLogger('resolve-user');
@ -67,11 +69,27 @@ export class RemoteUserResolveService {
if (user == null) {
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)}`);
return await this.apPersonService.createPerson(self.href);
}
// ユーザー情報が古い場合は、WebFilgerからやりなおして返す
// ユーザー情報が古い場合は、WebFingerからやりなおして返す
if (user.lastFetchedAt == null || Date.now() - user.lastFetchedAt.getTime() > 1000 * 60 * 60 * 24) {
// 繋がらないインスタンスに何回も試行するのを防ぐ, 後続の同様処理の連続試行を防ぐ ため 試行前にも更新する
await this.usersRepository.update(user.id, {
@ -119,7 +137,7 @@ export class RemoteUserResolveService {
}
@bindThis
private async resolveSelf(acctLower: string) {
private async resolveSelf(acctLower: string): Promise<ILink> {
this.logger.info(`WebFinger for ${chalk.yellow(acctLower)}`);
const finger = await this.webfingerService.webfinger(acctLower).catch(err => {
this.logger.error(`Failed to WebFinger for ${chalk.yellow(acctLower)}: ${ err.statusCode ?? err.message }`);

View file

@ -13,14 +13,19 @@ import { UserEntityService } from '@/core/entities/UserEntityService.js';
import { StreamMessages } from '@/server/api/stream/types.js';
import { IdService } from '@/core/IdService.js';
import { GlobalEventService } from '@/core/GlobalEventService.js';
import type { Packed } from '@/misc/json-schema';
import type { Packed } from '@/misc/json-schema.js';
import type { OnApplicationShutdown } from '@nestjs/common';
export type RolePolicies = {
gtlAvailable: boolean;
ltlAvailable: boolean;
mtlAvailable: boolean;
ctlAvailable: boolean;
canPublicNote: boolean;
canInvite: boolean;
inviteLimit: number;
inviteLimitCycle: number;
inviteExpirationTime: number;
canManageCustomEmojis: boolean;
canSearchNotes: boolean;
canHideAds: boolean;
@ -40,8 +45,13 @@ export type RolePolicies = {
export const DEFAULT_POLICIES: RolePolicies = {
gtlAvailable: true,
ltlAvailable: true,
mtlAvailable: true,
ctlAvailable: true,
canPublicNote: true,
canInvite: false,
inviteLimit: 0,
inviteLimitCycle: 60 * 24 * 7,
inviteExpirationTime: 0,
canManageCustomEmojis: false,
canSearchNotes: false,
canHideAds: false,
@ -214,14 +224,19 @@ export class RoleService implements OnApplicationShutdown {
}
@bindThis
public async getUserRoles(userId: User['id']) {
public async getUserAssigns(userId: User['id']) {
const now = Date.now();
let assigns = await this.roleAssignmentByUserIdCache.fetch(userId, () => this.roleAssignmentsRepository.findBy({ userId }));
// 期限切れのロールを除外
assigns = assigns.filter(a => a.expiresAt == null || (a.expiresAt.getTime() > now));
const assignedRoleIds = assigns.map(x => x.roleId);
return assigns;
}
@bindThis
public async getUserRoles(userId: User['id']) {
const roles = await this.rolesCache.fetch(() => this.rolesRepository.findBy({}));
const assignedRoles = roles.filter(r => assignedRoleIds.includes(r.id));
const assigns = await this.getUserAssigns(userId);
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 matchedCondRoles = roles.filter(r => r.target === 'conditional' && this.evalCond(user!, r.condFormula));
return [...assignedRoles, ...matchedCondRoles];
@ -275,8 +290,13 @@ export class RoleService implements OnApplicationShutdown {
return {
gtlAvailable: calc('gtlAvailable', vs => vs.some(v => v === true)),
ltlAvailable: calc('ltlAvailable', vs => vs.some(v => v === true)),
mtlAvailable: calc('mtlAvailable', vs => vs.some(v => v === true)),
ctlAvailable: calc('ctlAvailable', vs => vs.some(v => v === true)),
canPublicNote: calc('canPublicNote', 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)),
canSearchNotes: calc('canSearchNotes', vs => vs.some(v => v === true)),
canHideAds: calc('canHideAds', vs => vs.some(v => v === true)),

View file

@ -23,35 +23,45 @@ export class S3Service {
}
@bindThis
public getS3Client(meta: Meta): S3Client {
const u = meta.objectStorageEndpoint
? `${meta.objectStorageUseSSL ? 'https' : 'http'}://${meta.objectStorageEndpoint}`
: `${meta.objectStorageUseSSL ? 'https' : 'http'}://example.net`; // dummy url to select http(s) agent
public getS3Client(meta: Meta, isRemote: boolean): S3Client {
const useObjectStorageRemote = isRemote && meta.useObjectStorageRemote;
const agent = this.httpRequestService.getAgentByUrl(new URL(u), !meta.objectStorageUseProxy);
const objectStorageEndpoint = useObjectStorageRemote ? meta.objectStorageRemoteEndpoint : meta.objectStorageEndpoint;
const objectStorageUseSSL = useObjectStorageRemote ? meta.objectStorageRemoteUseSSL : meta.objectStorageUseSSL;
const objectStorageUseProxy = useObjectStorageRemote ? meta.objectStorageRemoteUseProxy : meta.objectStorageUseProxy;
const objectStorageAccessKey = useObjectStorageRemote ? meta.objectStorageRemoteAccessKey : meta.objectStorageAccessKey;
const objectStorageSecretKey = useObjectStorageRemote ? meta.objectStorageRemoteSecretKey : meta.objectStorageSecretKey;
const objectStorageRegion = useObjectStorageRemote ? meta.objectStorageRemoteRegion : meta.objectStorageRegion;
const objectStorageS3ForcePathStyle = useObjectStorageRemote ? meta.objectStorageRemoteS3ForcePathStyle : meta.objectStorageS3ForcePathStyle;
const u = objectStorageEndpoint
? `${objectStorageUseSSL ? 'https' : 'http'}://${objectStorageEndpoint}`
: `${objectStorageUseSSL ? 'https' : 'http'}://example.net`; // dummy url to select http(s) agent
const agent = this.httpRequestService.getAgentByUrl(new URL(u), !objectStorageUseProxy);
const handlerOption: NodeHttpHandlerOptions = {};
if (meta.objectStorageUseSSL) {
if (objectStorageUseSSL) {
handlerOption.httpsAgent = agent as https.Agent;
} else {
handlerOption.httpAgent = agent as http.Agent;
}
return new S3Client({
endpoint: meta.objectStorageEndpoint ? u : undefined,
credentials: (meta.objectStorageAccessKey !== null && meta.objectStorageSecretKey !== null) ? {
accessKeyId: meta.objectStorageAccessKey,
secretAccessKey: meta.objectStorageSecretKey,
endpoint: objectStorageEndpoint ? u : undefined,
credentials: (objectStorageAccessKey !== null && objectStorageSecretKey !== null) ? {
accessKeyId: objectStorageAccessKey,
secretAccessKey: objectStorageSecretKey,
} : undefined,
region: meta.objectStorageRegion ? meta.objectStorageRegion : undefined, // 空文字列もundefinedにするため ?? は使わない
tls: meta.objectStorageUseSSL,
forcePathStyle: meta.objectStorageEndpoint ? meta.objectStorageS3ForcePathStyle : false, // AWS with endPoint omitted
region: objectStorageRegion ? objectStorageRegion : undefined, // empty string is converted to undefined
tls: objectStorageUseSSL,
forcePathStyle: objectStorageEndpoint ? objectStorageS3ForcePathStyle : false, // AWS with endPoint omitted
requestHandler: new NodeHttpHandler(handlerOption),
});
}
@bindThis
public async upload(meta: Meta, input: PutObjectCommandInput) {
const client = this.getS3Client(meta);
public async upload(meta: Meta, input: PutObjectCommandInput, isRemote: boolean) {
const client = this.getS3Client(meta, isRemote);
return new Upload({
client,
params: input,
@ -62,8 +72,8 @@ export class S3Service {
}
@bindThis
public delete(meta: Meta, input: DeleteObjectCommandInput) {
const client = this.getS3Client(meta);
public delete(meta: Meta, input: DeleteObjectCommandInput, isRemote: boolean) {
const client = this.getS3Client(meta, isRemote);
return client.send(new DeleteObjectCommand(input));
}
}

View file

@ -52,6 +52,7 @@ function compileQuery(q: Q): string {
@Injectable()
export class SearchService {
private readonly meilisearchIndexScope: 'local' | 'global' | string[] = 'local';
private meilisearchNoteIndex: Index | null = null;
constructor(
@ -92,6 +93,10 @@ export class SearchService {
},
});
}
if (config.meilisearch?.scope) {
this.meilisearchIndexScope = config.meilisearch.scope;
}
}
@bindThis
@ -100,7 +105,22 @@ export class SearchService {
if (!['home', 'public'].includes(note.visibility)) return;
if (this.meilisearch) {
this.meilisearchNoteIndex!.addDocuments([{
switch (this.meilisearchIndexScope) {
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,
createdAt: note.createdAt.getTime(),
userId: note.userId,
@ -115,6 +135,15 @@ export class SearchService {
}
}
@bindThis
public async unindexNote(note: Note): Promise<void> {
if (!['home', 'public'].includes(note.visibility)) return;
if (this.meilisearch) {
this.meilisearchNoteIndex!.deleteDocument(note.id);
}
}
@bindThis
public async searchNote(q: string, me: User | null, opts: {
userId?: Note['userId'] | null;
@ -181,7 +210,7 @@ export class SearchService {
if (me) this.queryService.generateMutedUserQuery(query, me);
if (me) this.queryService.generateBlockedUserQuery(query, me);
return await query.take(pagination.limit).getMany();
return await query.limit(pagination.limit).getMany();
}
}
}

View file

@ -71,12 +71,12 @@ export class SignupService {
const secret = generateUserToken();
// Check username duplication
if (await this.usersRepository.findOneBy({ usernameLower: username.toLowerCase(), host: IsNull() })) {
if (await this.usersRepository.exist({ where: { usernameLower: username.toLowerCase(), host: IsNull() } })) {
throw new Error('DUPLICATED_USERNAME');
}
// Check deleted username duplication
if (await this.usedUsernamesRepository.findOneBy({ username: username.toLowerCase() })) {
if (await this.usedUsernamesRepository.exist({ where: { username: username.toLowerCase() } })) {
throw new Error('USED_USERNAME');
}
@ -92,7 +92,7 @@ export class SignupService {
const keyPair = await new Promise<string[]>((res, rej) =>
generateKeyPair('rsa', {
modulusLength: 4096,
modulusLength: 2048,
publicKeyEncoding: {
type: 'spki',
format: 'pem',

View file

@ -1,5 +1,6 @@
import { Inject, Injectable, OnModuleInit, forwardRef } from '@nestjs/common';
import { ModuleRef } from '@nestjs/core';
import { IsNull } from 'typeorm';
import type { LocalUser, PartialLocalUser, PartialRemoteUser, RemoteUser, User } from '@/models/entities/User.js';
import { IdentifiableError } from '@/misc/identifiable-error.js';
import { QueueService } from '@/core/QueueService.js';
@ -21,9 +22,8 @@ import { UserBlockingService } from '@/core/UserBlockingService.js';
import { MetaService } from '@/core/MetaService.js';
import { CacheService } from '@/core/CacheService.js';
import type { Config } from '@/config.js';
import Logger from '../logger.js';
import { IsNull } from 'typeorm';
import { AccountMoveService } from '@/core/AccountMoveService.js';
import Logger from '../logger.js';
const logger = new Logger('following/create');
@ -122,22 +122,26 @@ export class UserFollowingService implements OnModuleInit {
let autoAccept = false;
// 鍵アカウントであっても、既にフォローされていた場合はスルー
const following = await this.followingsRepository.findOneBy({
followerId: follower.id,
followeeId: followee.id,
const isFollowing = await this.followingsRepository.exist({
where: {
followerId: follower.id,
followeeId: followee.id,
},
});
if (following) {
if (isFollowing) {
autoAccept = true;
}
// フォローしているユーザーは自動承認オプション
if (!autoAccept && (this.userEntityService.isLocalUser(followee) && followeeProfile.autoAcceptFollowed)) {
const followed = await this.followingsRepository.findOneBy({
followerId: followee.id,
followeeId: follower.id,
const isFollowed = await this.followingsRepository.exist({
where: {
followerId: followee.id,
followeeId: follower.id,
},
});
if (followed) autoAccept = true;
if (isFollowed) autoAccept = true;
}
// Automatically accept if the follower is an account who has moved and the locked followee had accepted the old account.
@ -206,12 +210,14 @@ export class UserFollowingService implements OnModuleInit {
this.cacheService.userFollowingsCache.refresh(follower.id);
const req = await this.followRequestsRepository.findOneBy({
followeeId: followee.id,
followerId: follower.id,
const requestExist = await this.followRequestsRepository.exist({
where: {
followeeId: followee.id,
followerId: follower.id,
},
});
if (req) {
if (requestExist) {
await this.followRequestsRepository.delete({
followeeId: followee.id,
followerId: follower.id,
@ -316,7 +322,7 @@ export class UserFollowingService implements OnModuleInit {
where: {
followerId: follower.id,
followeeId: followee.id,
}
},
});
if (following === null || !following.follower || !following.followee) {
@ -406,8 +412,8 @@ export class UserFollowingService implements OnModuleInit {
followerId: user.id,
followee: {
movedToUri: IsNull(),
}
}
},
},
});
const nonMovedFollowers = await this.followingsRepository.count({
relations: {
@ -417,8 +423,8 @@ export class UserFollowingService implements OnModuleInit {
followeeId: user.id,
follower: {
movedToUri: IsNull(),
}
}
},
},
});
await this.usersRepository.update(
{ id: user.id },
@ -505,12 +511,14 @@ export class UserFollowingService implements OnModuleInit {
}
}
const request = await this.followRequestsRepository.findOneBy({
followeeId: followee.id,
followerId: follower.id,
const requestExist = await this.followRequestsRepository.exist({
where: {
followeeId: followee.id,
followerId: follower.id,
},
});
if (request == null) {
if (!requestExist) {
throw new IdentifiableError('17447091-ce07-46dd-b331-c1fd4f15b1e7', 'request not found');
}
@ -638,7 +646,7 @@ export class UserFollowingService implements OnModuleInit {
where: {
followeeId: followee.id,
followerId: follower.id,
}
},
});
if (!following || !following.followee || !following.follower) return;

View file

@ -52,7 +52,7 @@ export class VideoProcessingService {
query({
thumbnail: '1',
url,
})
}),
);
}
}

View file

@ -6,12 +6,12 @@ import { query as urlQuery } from '@/misc/prelude/url.js';
import { HttpRequestService } from '@/core/HttpRequestService.js';
import { bindThis } from '@/decorators.js';
type ILink = {
export type ILink = {
href: string;
rel?: string;
};
type IWebFinger = {
export type IWebFinger = {
links: ILink[];
subject: string;
};

View file

@ -16,6 +16,8 @@ type AudienceInfo = {
visibleUsers: User[],
};
type GroupedAudience = Record<'public' | 'followers' | 'other', string[]>;
@Injectable()
export class ApAudienceService {
constructor(
@ -67,11 +69,11 @@ export class ApAudienceService {
}
@bindThis
private groupingAudience(ids: string[], actor: RemoteUser) {
const groups = {
public: [] as string[],
followers: [] as string[],
other: [] as string[],
private groupingAudience(ids: string[], actor: RemoteUser): GroupedAudience {
const groups: GroupedAudience = {
public: [],
followers: [],
other: [],
};
for (const id of ids) {
@ -90,18 +92,16 @@ export class ApAudienceService {
}
@bindThis
private isPublic(id: string) {
private isPublic(id: string): boolean {
return [
'https://www.w3.org/ns/activitystreams#Public',
'as#Public',
'as:Public',
'Public',
].includes(id);
}
@bindThis
private isFollowers(id: string, actor: RemoteUser) {
return (
id === (actor.followersUri ?? `${actor.uri}/followers`)
);
private isFollowers(id: string, actor: RemoteUser): boolean {
return id === (actor.followersUri ?? `${actor.uri}/followers`);
}
}

View file

@ -1,5 +1,4 @@
import { Inject, Injectable, OnApplicationShutdown } from '@nestjs/common';
import escapeRegexp from 'escape-regexp';
import { DI } from '@/di-symbols.js';
import type { MessagingMessagesRepository, NotesRepository, UserPublickeysRepository, UsersRepository } from '@/models/index.js';
import type { Config } from '@/config.js';
@ -60,25 +59,18 @@ export class ApDbResolverService implements OnApplicationShutdown {
@bindThis
public parseUri(value: string | IObject): UriParseResult {
const uri = getApId(value);
const separator = '/';
// the host part of a URL is case insensitive, so use the 'i' flag.
const localRegex = new RegExp('^' + escapeRegexp(this.config.url) + '/(\\w+)/(\\w+)(?:\/(.+))?', 'i');
const matchLocal = uri.match(localRegex);
const uri = new URL(getApId(value));
if (uri.origin !== this.config.url) return { local: false, uri: uri.href };
if (matchLocal) {
return {
local: true,
type: matchLocal[1],
id: matchLocal[2],
rest: matchLocal[3],
};
} else {
return {
local: false,
uri,
};
}
const [, type, id, ...rest] = uri.pathname.split(separator);
return {
local: true,
type,
id,
rest: rest.length === 0 ? undefined : rest.join(separator),
};
}
/**
@ -128,13 +120,15 @@ export class ApDbResolverService implements OnApplicationShutdown {
if (parsed.local) {
if (parsed.type !== 'users') return null;
return await this.cacheService.userByIdCache.fetchMaybe(parsed.id, () => this.usersRepository.findOneBy({
id: parsed.id,
}).then(x => x ?? undefined)) as LocalUser | undefined ?? null;
return await this.cacheService.userByIdCache.fetchMaybe(
parsed.id,
() => this.usersRepository.findOneBy({ id: parsed.id }).then(x => x ?? undefined),
) as LocalUser | undefined ?? null;
} else {
return await this.cacheService.uriPersonCache.fetch(parsed.uri, () => this.usersRepository.findOneBy({
uri: parsed.uri,
})) as RemoteUser | null;
return await this.cacheService.uriPersonCache.fetch(
parsed.uri,
() => this.usersRepository.findOneBy({ uri: parsed.uri }),
) as RemoteUser | null;
}
}
@ -174,9 +168,11 @@ export class ApDbResolverService implements OnApplicationShutdown {
} | null> {
const user = await this.apPersonService.resolvePerson(uri) as RemoteUser;
if (user == null) return null;
const key = await this.publicKeyByUserIdCache.fetch(user.id, () => this.userPublickeysRepository.findOneBy({ userId: user.id }), v => v != null);
const key = await this.publicKeyByUserIdCache.fetch(
user.id,
() => this.userPublickeysRepository.findOneBy({ userId: user.id }),
v => v != null,
);
return {
user,

View file

@ -7,6 +7,8 @@ import type { LocalUser, RemoteUser, User } from '@/models/entities/User.js';
import { QueueService } from '@/core/QueueService.js';
import { UserEntityService } from '@/core/entities/UserEntityService.js';
import { bindThis } from '@/decorators.js';
import type { IActivity } from '@/core/activitypub/type.js';
import { ThinUser } from '@/queue/types.js';
interface IRecipe {
type: string;
@ -21,12 +23,127 @@ interface IDirectRecipe extends IRecipe {
to: RemoteUser;
}
const isFollowers = (recipe: any): recipe is IFollowersRecipe =>
const isFollowers = (recipe: IRecipe): recipe is IFollowersRecipe =>
recipe.type === 'Followers';
const isDirect = (recipe: any): recipe is IDirectRecipe =>
const isDirect = (recipe: IRecipe): recipe is IDirectRecipe =>
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()
export class ApDeliverManagerService {
constructor(
@ -46,11 +163,11 @@ export class ApDeliverManagerService {
/**
* Deliver activity to followers
* @param actor
* @param activity Activity
* @param from Followee
*/
@bindThis
public async deliverToFollowers(actor: { id: LocalUser['id']; host: null; }, activity: any) {
public async deliverToFollowers(actor: { id: LocalUser['id']; host: null; }, activity: IActivity): Promise<void> {
const manager = new DeliverManager(
this.userEntityService,
this.followingsRepository,
@ -64,11 +181,12 @@ export class ApDeliverManagerService {
/**
* Deliver activity to user
* @param actor
* @param activity Activity
* @param to Target user
*/
@bindThis
public async deliverToUser(actor: { id: LocalUser['id']; host: null; }, activity: any, to: RemoteUser) {
public async deliverToUser(actor: { id: LocalUser['id']; host: null; }, activity: IActivity, to: RemoteUser): Promise<void> {
const manager = new DeliverManager(
this.userEntityService,
this.followingsRepository,
@ -81,7 +199,7 @@ export class ApDeliverManagerService {
}
@bindThis
public createDeliverManager(actor: { id: User['id']; host: null; }, activity: any) {
public createDeliverManager(actor: { id: User['id']; host: null; }, activity: IActivity | null): DeliverManager {
return new DeliverManager(
this.userEntityService,
this.followingsRepository,
@ -92,118 +210,3 @@ export class ApDeliverManagerService {
);
}
}
class DeliverManager {
private actor: { id: User['id']; host: null; };
private activity: any;
private recipes: IRecipe[] = [];
/**
* Constructor
* @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: any,
) {
this.actor = actor;
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() {
if (!this.userEntityService.isLocalUser(this.actor)) return;
// The value flags whether it is shared or not.
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
for (const inbox of inboxes) {
// inbox[0]: inbox, inbox[1]: whether it is sharedInbox
this.queueService.deliver(this.actor, this.activity, inbox[0], inbox[1]);
}
}
}

View file

@ -22,10 +22,10 @@ import { NoteEntityService } from '@/core/entities/NoteEntityService.js';
import { UserEntityService } from '@/core/entities/UserEntityService.js';
import { QueueService } from '@/core/QueueService.js';
import { MessagingService } from '@/core/MessagingService.js';
import type { UsersRepository, NotesRepository, FollowingsRepository, MessagingMessagesRepository, AbuseUserReportsRepository, FollowRequestsRepository, } from '@/models/index.js';
import type { UsersRepository, NotesRepository, FollowingsRepository, MessagingMessagesRepository, AbuseUserReportsRepository, FollowRequestsRepository } from '@/models/index.js';
import { bindThis } from '@/decorators.js';
import type { RemoteUser } from '@/models/entities/User.js';
import { getApHrefNullable, getApId, getApIds, getApType, getOneApHrefNullable, isAccept, isActor, isAdd, isAnnounce, isBlock, isCollection, isCollectionOrOrderedCollection, isCreate, isDelete, isFlag, isFollow, isLike, isMove, isPost, isRead, isReject, isRemove, isTombstone, isUndo, isUpdate, validActor, validPost } from './type.js';
import { getApHrefNullable, getApId, getApIds, getApType, isAccept, isActor, isAdd, isAnnounce, isBlock, isCollection, isCollectionOrOrderedCollection, isCreate, isDelete, isFlag, isFollow, isLike, isMove, isPost, isRead, isReject, isRemove, isTombstone, isUndo, isUpdate, validActor, validPost } from './type.js';
import { ApNoteService } from './models/ApNoteService.js';
import { ApLoggerService } from './ApLoggerService.js';
import { ApDbResolverService } from './ApDbResolverService.js';
@ -91,7 +91,7 @@ export class ApInboxService {
}
@bindThis
public async performActivity(actor: RemoteUser, activity: IObject) {
public async performActivity(actor: RemoteUser, activity: IObject): Promise<void> {
if (isCollectionOrOrderedCollection(activity)) {
const resolver = this.apResolverService.createResolver();
for (const item of toArray(isCollection(activity) ? activity.items : activity.orderedItems)) {
@ -112,7 +112,7 @@ export class ApInboxService {
if (actor.uri) {
if (actor.lastFetchedAt == null || Date.now() - actor.lastFetchedAt.getTime() > 1000 * 60 * 60 * 24) {
setImmediate(() => {
this.apPersonService.updatePerson(actor.uri!);
this.apPersonService.updatePerson(actor.uri);
});
}
}
@ -259,7 +259,7 @@ export class ApInboxService {
@bindThis
private async add(actor: RemoteUser, activity: IAdd): Promise<void> {
if ('actor' in activity && actor.uri !== activity.actor) {
if (actor.uri !== activity.actor) {
throw new Error('invalid actor');
}
@ -303,7 +303,7 @@ export class ApInboxService {
const unlock = await this.appLockService.getApLock(uri);
try {
// 既に同じURIを持つものが登録されていないかチェック
// 既に同じURIを持つものが登録されていないかチェック
const exist = await this.apNoteService.fetchNote(uri);
if (exist) {
return;
@ -322,7 +322,7 @@ export class ApInboxService {
return;
}
this.logger.warn(`Error in announce target ${targetUri} - ${err.statusCode ?? err}`);
this.logger.warn(`Error in announce target ${targetUri} - ${err.statusCode}`);
}
throw err;
}
@ -439,7 +439,7 @@ export class ApInboxService {
@bindThis
private async delete(actor: RemoteUser, activity: IDelete): Promise<string> {
if ('actor' in activity && actor.uri !== activity.actor) {
if (actor.uri !== activity.actor) {
throw new Error('invalid actor');
}
@ -450,7 +450,7 @@ export class ApInboxService {
// typeが不明だけど、どうせ消えてるのでremote resolveしない
formerType = undefined;
} else {
const object = activity.object as IObject;
const object = activity.object;
if (isTombstone(object)) {
formerType = toSingle(object.formerType);
} else {
@ -542,7 +542,10 @@ export class ApInboxService {
// 対象ユーザーは一番最初のユーザー として あとはコメントとして格納する
const uris = getApIds(activity.object);
const userIds = uris.filter(uri => uri.startsWith(this.config.url + '/users/')).map(uri => uri.split('/').pop()!);
const userIds = uris
.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({
id: In(userIds),
});
@ -605,7 +608,7 @@ export class ApInboxService {
@bindThis
private async remove(actor: RemoteUser, activity: IRemove): Promise<void> {
if ('actor' in activity && actor.uri !== activity.actor) {
if (actor.uri !== activity.actor) {
throw new Error('invalid actor');
}
@ -625,7 +628,7 @@ export class ApInboxService {
@bindThis
private async undo(actor: RemoteUser, activity: IUndo): Promise<string> {
if ('actor' in activity && actor.uri !== activity.actor) {
if (actor.uri !== activity.actor) {
throw new Error('invalid actor');
}
@ -657,12 +660,14 @@ export class ApInboxService {
return 'skip: follower not found';
}
const following = await this.followingsRepository.findOneBy({
followerId: follower.id,
followeeId: actor.id,
const isFollowing = await this.followingsRepository.exist({
where: {
followerId: follower.id,
followeeId: actor.id,
},
});
if (following) {
if (isFollowing) {
await this.userFollowingService.unfollow(follower, actor);
return 'ok: unfollowed';
}
@ -712,22 +717,26 @@ export class ApInboxService {
return 'skip: フォロー解除しようとしているユーザーはローカルユーザーではありません';
}
const req = await this.followRequestsRepository.findOneBy({
followerId: actor.id,
followeeId: followee.id,
const requestExist = await this.followRequestsRepository.exist({
where: {
followerId: actor.id,
followeeId: followee.id,
},
});
const following = await this.followingsRepository.findOneBy({
followerId: actor.id,
followeeId: followee.id,
const isFollowing = await this.followingsRepository.exist({
where: {
followerId: actor.id,
followeeId: followee.id,
},
});
if (req) {
if (requestExist) {
await this.userFollowingService.cancelFollowRequest(followee, actor);
return 'ok: follow request canceled';
}
if (following) {
if (isFollowing) {
await this.userFollowingService.unfollow(actor, followee);
return 'ok: unfollowed';
}
@ -752,7 +761,7 @@ export class ApInboxService {
@bindThis
private async update(actor: RemoteUser, activity: IUpdate): Promise<string> {
if ('actor' in activity && actor.uri !== activity.actor) {
if (actor.uri !== activity.actor) {
return 'skip: invalid actor';
}
@ -766,7 +775,7 @@ export class ApInboxService {
});
if (isActor(object)) {
await this.apPersonService.updatePerson(actor.uri!, resolver, object);
await this.apPersonService.updatePerson(actor.uri, resolver, object);
return 'ok: Person updated';
} else if (getApType(object) === 'Question') {
await this.apQuestionService.updateQuestion(object, resolver).catch(err => console.error(err));

View file

@ -4,9 +4,9 @@ import { DI } from '@/di-symbols.js';
import type { Config } from '@/config.js';
import { MfmService } from '@/core/MfmService.js';
import type { Note } from '@/models/entities/Note.js';
import { bindThis } from '@/decorators.js';
import { extractApHashtagObjects } from './models/tag.js';
import type { IObject } from './type.js';
import { bindThis } from '@/decorators.js';
@Injectable()
export class ApMfmService {
@ -19,14 +19,13 @@ export class ApMfmService {
}
@bindThis
public htmlToMfm(html: string, tag?: IObject | IObject[]) {
const hashtagNames = extractApHashtagObjects(tag).map(x => x.name).filter((x): x is string => x != null);
public htmlToMfm(html: string, tag?: IObject | IObject[]): string {
const hashtagNames = extractApHashtagObjects(tag).map(x => x.name);
return this.mfmService.fromHtml(html, hashtagNames);
}
@bindThis
public getNoteHtml(note: Note) {
public getNoteHtml(note: Note): string | null {
if (!note.text) return '';
return this.mfmService.toHtml(mfm.parse(note.text), JSON.parse(note.mentionedRemoteUsers));
}

View file

@ -1,7 +1,6 @@
import { createPublicKey } from 'node:crypto';
import { createPublicKey, randomUUID } from 'node:crypto';
import { Inject, Injectable } from '@nestjs/common';
import { In, IsNull } from 'typeorm';
import { v4 as uuid } from 'uuid';
import { In } from 'typeorm';
import * as mfm from 'cherrypick-mfm-js';
import { DI } from '@/di-symbols.js';
import type { Config } from '@/config.js';
@ -27,7 +26,6 @@ import { isNotNull } from '@/misc/is-not-null.js';
import { LdSignatureService } from './LdSignatureService.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, IRead, IReject, IRemove, ITombstone, IUndo, IUpdate } from './type.js';
import type { IIdentifier } from './models/identifier.js';
@Injectable()
export class ApRendererService {
@ -67,7 +65,7 @@ export class ApRendererService {
}
@bindThis
public renderAccept(object: any, user: { id: User['id']; host: null }): IAccept {
public renderAccept(object: string | IObject, user: { id: User['id']; host: null }): IAccept {
return {
type: 'Accept',
actor: this.userEntityService.genLocalUserUri(user.id),
@ -76,7 +74,7 @@ export class ApRendererService {
}
@bindThis
public renderAdd(user: LocalUser, target: any, object: any): IAdd {
public renderAdd(user: LocalUser, target: string | IObject | undefined, object: string | IObject): IAdd {
return {
type: 'Add',
actor: this.userEntityService.genLocalUserUri(user.id),
@ -86,7 +84,7 @@ export class ApRendererService {
}
@bindThis
public renderAnnounce(object: any, note: Note): IAnnounce {
public renderAnnounce(object: string | IObject, note: Note): IAnnounce {
const attributedTo = this.userEntityService.genLocalUserUri(note.userId);
let to: string[] = [];
@ -137,13 +135,13 @@ export class ApRendererService {
@bindThis
public renderCreate(object: IObject, note: Note): ICreate {
const activity = {
const activity: ICreate = {
id: `${this.config.url}/notes/${note.id}/activity`,
actor: this.userEntityService.genLocalUserUri(note.userId),
type: 'Create',
published: note.createdAt.toISOString(),
object,
} as ICreate;
};
if (object.to) activity.to = object.to;
if (object.cc) activity.cc = object.cc;
@ -213,7 +211,7 @@ export class ApRendererService {
* @param id Follower|Followee ID
*/
@bindThis
public async renderFollowUser(id: User['id']) {
public async renderFollowUser(id: User['id']): Promise<string> {
const user = await this.usersRepository.findOneByOrFail({ id: id }) as PartialLocalUser | PartialRemoteUser;
return this.userEntityService.getUserUri(user);
}
@ -227,8 +225,8 @@ export class ApRendererService {
return {
id: requestId ?? `${this.config.url}/follows/${follower.id}/${followee.id}`,
type: 'Follow',
actor: this.userEntityService.getUserUri(follower)!,
object: this.userEntityService.getUserUri(followee)!,
actor: this.userEntityService.getUserUri(follower),
object: this.userEntityService.getUserUri(followee),
};
}
@ -268,14 +266,14 @@ export class ApRendererService {
public async renderLike(noteReaction: NoteReaction, note: { uri: string | null }): Promise<ILike> {
const reaction = noteReaction.reaction;
const object = {
const object: ILike = {
type: 'Like',
id: `${this.config.url}/likes/${noteReaction.id}`,
actor: `${this.config.url}/users/${noteReaction.userId}`,
object: note.uri ? note.uri : `${this.config.url}/notes/${noteReaction.noteId}`,
content: reaction,
_misskey_reaction: reaction,
} as ILike;
};
if (reaction.startsWith(':')) {
const name = reaction.replaceAll(':', '');
@ -291,7 +289,7 @@ export class ApRendererService {
public renderMention(mention: PartialLocalUser | PartialRemoteUser): IApMention {
return {
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}`,
};
}
@ -301,8 +299,8 @@ export class ApRendererService {
src: PartialLocalUser | PartialRemoteUser,
dst: PartialLocalUser | PartialRemoteUser,
): IMove {
const actor = this.userEntityService.getUserUri(src)!;
const target = this.userEntityService.getUserUri(dst)!;
const actor = this.userEntityService.getUserUri(src);
const target = this.userEntityService.getUserUri(dst);
return {
id: `${this.config.url}/moves/${src.id}/${dst.id}`,
actor,
@ -314,10 +312,10 @@ export class ApRendererService {
@bindThis
public async renderNote(note: Note, dive = true, isTalk = false): Promise<IPost> {
const getPromisedFiles = async (ids: string[]) => {
if (!ids || ids.length === 0) return [];
const getPromisedFiles = async (ids: string[]): Promise<DriveFile[]> => {
if (ids.length === 0) return [];
const items = await this.driveFilesRepository.findBy({ id: In(ids) });
return ids.map(id => items.find(item => item.id === id)).filter(item => item != null) as DriveFile[];
return ids.map(id => items.find(item => item.id === id)).filter((item): item is DriveFile => item != null);
};
let inReplyTo;
@ -327,9 +325,9 @@ export class ApRendererService {
inReplyToNote = await this.notesRepository.findOneBy({ id: note.replyId });
if (inReplyToNote != null) {
const inReplyToUser = await this.usersRepository.findOneBy({ id: inReplyToNote.userId });
const inReplyToUserExist = await this.usersRepository.exist({ where: { id: inReplyToNote.userId } });
if (inReplyToUser != null) {
if (inReplyToUserExist) {
if (inReplyToNote.uri) {
inReplyTo = inReplyToNote.uri;
} else {
@ -379,7 +377,7 @@ export class ApRendererService {
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 files = await getPromisedFiles(note.fileIds);
@ -473,37 +471,26 @@ export class ApRendererService {
@bindThis
public async renderPerson(user: LocalUser) {
const id = this.userEntityService.genLocalUserUri(user.id);
const isSystem = !!user.username.match(/\./);
const isSystem = user.username.includes('.');
const [avatar, banner, profile] = await Promise.all([
user.avatarId ? this.driveFilesRepository.findOneBy({ id: user.avatarId }) : Promise.resolve(undefined),
user.bannerId ? this.driveFilesRepository.findOneBy({ id: user.bannerId }) : Promise.resolve(undefined),
user.avatarId ? this.driveFilesRepository.findOneBy({ id: user.avatarId }) : undefined,
user.bannerId ? this.driveFilesRepository.findOneBy({ id: user.bannerId }) : undefined,
this.userProfilesRepository.findOneByOrFail({ userId: user.id }),
]);
const attachment: {
const attachment = profile.fields.map(field => ({
type: 'PropertyValue',
name: string,
value: string,
identifier?: IIdentifier,
}[] = [];
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,
});
}
}
name: field.name,
value: /^https?:/.test(field.value)
? `<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 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 = [
...apemojis,
@ -512,7 +499,7 @@ export class ApRendererService {
const keypair = await this.userKeypairService.getUserKeypair(user.id);
const person = {
const person: any = {
type: isSystem ? 'Application' : user.isBot ? 'Service' : 'Person',
id,
inbox: `${id}/inbox`,
@ -530,11 +517,11 @@ export class ApRendererService {
image: banner ? this.renderImage(banner) : null,
tag,
manuallyApprovesFollowers: user.isLocked,
discoverable: !!user.isExplorable,
discoverable: user.isExplorable,
publicKey: this.renderKey(user, keypair, '#main-key'),
isCat: user.isCat,
attachment: attachment.length ? attachment : undefined,
} as any;
};
if (user.movedToUri) {
person.movedTo = user.movedToUri;
@ -583,7 +570,7 @@ export class ApRendererService {
}
@bindThis
public renderReject(object: any, user: { id: User['id'] }): IReject {
public renderReject(object: string | IObject, user: { id: User['id'] }): IReject {
return {
type: 'Reject',
actor: this.userEntityService.genLocalUserUri(user.id),
@ -592,7 +579,7 @@ export class ApRendererService {
}
@bindThis
public renderRemove(user: { id: User['id'] }, target: any, object: any): IRemove {
public renderRemove(user: { id: User['id'] }, target: string | IObject | undefined, object: string | IObject): IRemove {
return {
type: 'Remove',
actor: this.userEntityService.genLocalUserUri(user.id),
@ -610,8 +597,8 @@ export class ApRendererService {
}
@bindThis
public renderUndo(object: any, user: { id: User['id'] }): IUndo {
const id = typeof object.id === 'string' && object.id.startsWith(this.config.url) ? `${object.id}/undo` : undefined;
public renderUndo(object: string | IObject, user: { id: User['id'] }): IUndo {
const id = typeof object !== 'string' && typeof object.id === 'string' && object.id.startsWith(this.config.url) ? `${object.id}/undo` : undefined;
return {
type: 'Undo',
@ -623,7 +610,7 @@ export class ApRendererService {
}
@bindThis
public renderUpdate(object: any, user: { id: User['id'] }): IUpdate {
public renderUpdate(object: string | IObject, user: { id: User['id'] }): IUpdate {
return {
id: `${this.config.url}/users/${user.id}#updates/${new Date().getTime()}`,
actor: this.userEntityService.genLocalUserUri(user.id),
@ -656,7 +643,7 @@ export class ApRendererService {
@bindThis
public addContext<T extends IObject>(x: T): T & { '@context': any; id: string; } {
if (typeof x === 'object' && x.id == null) {
x.id = `${this.config.url}/${uuid()}`;
x.id = `${this.config.url}/${randomUUID()}`;
}
return Object.assign({
@ -690,7 +677,7 @@ export class ApRendererService {
vcard: 'http://www.w3.org/2006/vcard/ns#',
},
],
}, x as T & { id: string; });
}, x as T & { id: string });
}
@bindThis
@ -715,13 +702,13 @@ export class ApRendererService {
*/
@bindThis
public renderOrderedCollectionPage(id: string, totalItems: any, orderedItems: any, partOf: string, prev?: string, next?: string) {
const page = {
const page: any = {
id,
partOf,
type: 'OrderedCollectionPage',
totalItems,
orderedItems,
} as any;
};
if (prev) page.prev = prev;
if (next) page.next = next;
@ -738,7 +725,7 @@ export class ApRendererService {
* @param orderedItems attached objects (optional)
*/
@bindThis
public renderOrderedCollection(id: string | null, totalItems: any, first?: string, last?: string, orderedItems?: IObject[]) {
public renderOrderedCollection(id: string, totalItems: number, first?: string, last?: string, orderedItems?: IObject[]) {
const page: any = {
id,
type: 'OrderedCollection',
@ -754,7 +741,7 @@ export class ApRendererService {
@bindThis
private async getEmojis(names: string[]): Promise<Emoji[]> {
if (names == null || names.length === 0) return [];
if (names.length === 0) return [];
const allEmojis = await this.customEmojiService.localEmojisCache.fetch();
const emojis = names.map(name => allEmojis.get(name)).filter(isNotNull);

Some files were not shown because too many files have changed in this diff Show more