diff --git a/.config/LICENSE b/.config/LICENSE new file mode 100644 index 000000000..342509dec --- /dev/null +++ b/.config/LICENSE @@ -0,0 +1,13 @@ +Copyright 2023 Calckey + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/.config/example.yml b/.config/example.yml index ba74df8a5..f73f4f1d7 100644 --- a/.config/example.yml +++ b/.config/example.yml @@ -121,7 +121,7 @@ redis: # ┌─────────────────────┐ #───┘ Other configuration └───────────────────────────────────── -# Maximum length of a post (default 3000, max 8192) +# Maximum length of a post (default 3000, max 100000) #maxNoteLength: 3000 # Maximum length of an image caption (default 1500, max 8192) diff --git a/.gitignore b/.gitignore index 29377540d..6bf2ea1b1 100644 --- a/.gitignore +++ b/.gitignore @@ -25,6 +25,7 @@ coverage !/.config/devenv.yml !/.config/docker_example.env !/.config/helm_values_example.yml +!/.config/LICENSE #docker dev config /dev/docker-compose.yml diff --git a/CALCKEY.md b/CALCKEY.md index 5a8bbd8ff..bb28e5bbf 100644 --- a/CALCKEY.md +++ b/CALCKEY.md @@ -6,19 +6,13 @@ ## Planned - Stucture - - [DragonflyDB](https://dragonflydb.io/) support as a Redis alternative - - Optionally use [ScyllaDB](https://www.scylladb.com/open-source-nosql-database/) for storing notes - Rewrite backend in Rust and [Rocket](https://rocket.rs/) - - Use [Magic RegExP](https://regexp.dev/) for RegEx 🦄 - Function - User "choices" (recommended users) and featured hashtags like Mastodon and Soapbox - Join Reason system like Mastodon/Pleroma - Option to publicize server blocks - More antenna options - Groups -- Form - - Lookup/details for post/file/server - - [Rat mode?](https://stop.voring.me/notes/933fx97bmd) ## Work in progress @@ -30,6 +24,7 @@ - Timeline filters - Events - Fully revamp non-logged-in screen +- Optionally use [ScyllaDB](https://www.scylladb.com/open-source-nosql-database/) for storing notes ## Implemented @@ -122,6 +117,7 @@ - Let moderators see moderation nodes - Non-mangled unicode emojis - Skin tone selection support +- [DragonflyDB](https://dragonflydb.io/) support as a Redis alternative ## Implemented (remote) @@ -137,7 +133,7 @@ - 👍 also triggers generic like/favorite - [Add additional background for acrylic popups if backdrop-filter is unsupported](https://github.com/misskey-dev/misskey/pull/8671) - [Add parameters to MFM rotate](https://github.com/misskey-dev/misskey/pull/8549) -- Many changes from [Foundkey](https://akkoma.dev/FoundKeyGang/Foundkey) +- Many changes from [FoundKey](https://akkoma.dev/FoundKeyGang/FoundKey) - https://akkoma.dev/FoundKeyGang/FoundKey/commit/0ece67b04c3f0365057624c1068808276ccab981: refactor pages/auth.form.vue to composition API - https://akkoma.dev/FoundKeyGang/FoundKey/commit/4bc9610d8bf5af736b5e89e4782395705de45d7d: remove unnecessary joins - https://akkoma.dev/FoundKeyGang/FoundKey/commit/9ee609d70082f7a6dc119a5d83c0e7c5e1208676: enhance privacy of notes diff --git a/CHANGELOG.md b/CHANGELOG.md index 988156a72..b9a998f62 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2704,7 +2704,7 @@ Co-committed-by: naskya Passwords will be automatically re-hashed on sign-in. All new password hashes will be argon2 by default. This uses argon2id and is not configurable. In the very unlikely case someone has more specific needs, a fork is recommended. ChangeLog: Added Co-authored-by: Chloe Kudryavtsev -Breaks Calckey -> Misskey migration, but fixes Foundkey -> Calckey migration +Breaks Calckey -> Misskey migration, but fixes FoundKey -> Calckey migration - Add argon diff --git a/COPYING b/COPYING index fb483b523..387515b06 100644 --- a/COPYING +++ b/COPYING @@ -1,15 +1,24 @@ -Unless otherwise stated this repository is -Copyright © 2014-2022 syuilo and contributers -Copyright © 2022 thatonecalculator and contributers +Unless specified otherwise, the entirety of this repository is subject to the following: +Copyright © 2014-2023 syuilo and contributors +Copyright © 2022-2023 Kainoa Kanter and contributors And is distributed under The GNU Affero General Public License Version 3, you should have received a copy of the license file as LICENSE. +--- -Calckey includes several third-party Open-Source softwares. +These specific configuration directories: -Emoji keywords for Unicode 11 and below by Mu-An Chiou -License: MIT -https://github.com/muan/emojilib/blob/master/LICENSE +- .config/ +- custom/assets/ + +and their contents are +Copyright © 2022-2023 Kainoa Kanter and contributors + +And are distributed under The Apache License, Version 2.0, you should have received a copy of the license file as LICENSE in each specified directory. + +--- + +Calckey includes several third-party open-source softwares and software libraries. RsaSignature2017 implementation by Transmute Industries Inc License: MIT @@ -18,3 +27,7 @@ https://github.com/transmute-industries/RsaSignature2017/blob/master/LICENSE Machine learning model for sensitive images by Infinite Red, Inc. License: MIT https://github.com/infinitered/nsfwjs/blob/master/LICENSE + +Licenses for all softwares and software libraries installed via the Node Package Manager ("npm") can be found by running the following shell command in the root directory of this repository: + +pnpm licenses list diff --git a/README.md b/README.md index 2e6907e30..a2465cc09 100644 --- a/README.md +++ b/README.md @@ -72,6 +72,14 @@ # 🌠 Getting started +Want to just join a Calckey server? View the list here, pick one, and join: + +### https://calckey.org/join + +--- + +Want to make your own? Keep reading! + This guide will work for both **starting from scratch** and **migrating from Misskey**. ## 🔰 Easy installers @@ -208,9 +216,9 @@ Please don't use ElasticSearch unless you already have an ElasticSearch setup an - Edit `.config/default.yml`, making sure to fill out required fields. - Also copy and edit `.config/docker_example.env` to `.config/docker.env` if you're using Docker. -## 🚚 Migrating from Misskey to Calckey +## 🚚 Migrating from Misskey/FoundKey to Calckey -For migrating from Misskey v13, Misskey v12, and Foundkey, read [this document](https://codeberg.org/calckey/calckey/src/branch/develop/docs/migrate.md). +For migrating from Misskey v13, Misskey v12, and FoundKey, read [this document](https://codeberg.org/calckey/calckey/src/branch/develop/docs/migrate.md). ## 🌐 Web proxy diff --git a/custom/assets/LICENSE b/custom/assets/LICENSE new file mode 100644 index 000000000..342509dec --- /dev/null +++ b/custom/assets/LICENSE @@ -0,0 +1,13 @@ +Copyright 2023 Calckey + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/docs/migrate.md b/docs/migrate.md index 7e9653e70..3c43af809 100644 --- a/docs/migrate.md +++ b/docs/migrate.md @@ -1,10 +1,11 @@ -# 🚚 Migrating from Misskey to Calckey +# 🚚 Migrating from Misskey/FoundKey to Calckey -The following procedure may not work depending on your environment and version of Misskey. +All the guides below assume you're starting in the root of the repo directory. -**Make sure you** -- **stopped all master and worker processes of Misskey.** -- **have backups of the database before performing any commands.** +### Before proceeding + +- **Ensure you have stopped all master and worker processes of Misskey.** +- **Ensure you have backups of the database before performing any commands.** ## Misskey v13 and above @@ -77,15 +78,16 @@ NODE_ENV=production pnpm run migrate # build using prefered method ``` -## Foundkey +## FoundKey ```sh cd packages/backend +sed -i '12s/^/\/\//' ./migration/1663399074403-resize-comments-drive-file.js LINE_NUM="$(npx typeorm migration:show -d ormconfig.js | grep -n uniformThemecolor1652859567549 | cut -d ':' -f 1)" -NUM_MIGRATIONS="$(npx typeorm migration:show -d ormconfig.js | tail -n+"$LINE_NUM" | grep '\[X\]' | nl)" +NUM_MIGRATIONS="$(npx typeorm migration:show -d ormconfig.js | tail -n+"$LINE_NUM" | grep '\[X\]' | wc -l)" -for i in $(seq 1 $NUM_MIGRAIONS); do +for i in $(seq 1 $NUM_MIGRATIONS); do npx typeorm migration:revert -d ormconfig.js done @@ -100,4 +102,4 @@ NODE_ENV=production pnpm run migrate ## Reverse -You ***cannot*** migrate back to Misskey from Calckey due to re-hashing passwords on signin with argon2. You can migrate from Calckey to Foundkey, though. +You ***cannot*** migrate back to Misskey from Calckey due to re-hashing passwords on signin with argon2. You can migrate from Calckey to FoundKey, although this is not recommended due to FoundKey being end-of-life. diff --git a/locales/ca-ES.yml b/locales/ca-ES.yml index 6cda10f96..8fb57e879 100644 --- a/locales/ca-ES.yml +++ b/locales/ca-ES.yml @@ -95,7 +95,7 @@ privacy: "Privadesa" makeFollowManuallyApprove: "Les sol·licituds de seguiment requereixen aprovació" defaultNoteVisibility: "Visibilitat per defecte" follow: "Segueix" -followRequest: "Segueix" +followRequest: "Sol·licitud de Seguiment" followRequests: "Sol·licituds de seguiment" unfollow: "Deixa de seguir" followRequestPending: "Sol·licituds de seguiment pendents" @@ -1382,7 +1382,7 @@ adminCustomCssWarn: Aquesta configuració només s'ha d'utilitzar si sabeu què showUpdates: Mostra una finestra emergent quan Calckey s'actualitzi recommendedInstances: Servidors recomanats recommendedInstancesDescription: Servidors recomanats separats per salts de línia - que apareixen a la línia de temps recomanada. NO afegiu `https://`, NOMÉS el domini. + que apareixen a la línia de temps recomanada. caption: Descripció Automàtica splash: Pantalla de Benvinguda swipeOnDesktop: Permet lliscar a l'estil del mòbil a l'escriptori @@ -1603,6 +1603,13 @@ _aboutMisskey: patrons: Mecenes de Calckey patronsList: Llistats cronològicament, no per la quantitat donada. Fes una donació amb l'enllaç de dalt per veure el teu nom aquí! + donateTitle: T'agrada Calckey? + pleaseDonateToCalckey: Penseu en fer una donació a Calckey per donar suport al seu + desenvolupament. + pleaseDonateToHost: Penseu també en fer una donació a la vostre instància, {host}, + per ajudar-lo a suportar els costos de funcionament. + donateHost: Fes una donació a {host} + sponsors: Patrocinadors de Calckey unknown: Desconegut pageLikesCount: Nombre de pàgines amb M'agrada youAreRunningUpToDateClient: Estás fent servir la versió del client més nova. @@ -2144,3 +2151,13 @@ _skinTones: swipeOnMobile: Permet lliscar entre pàgines enableIdenticonGeneration: Habilitar la generació d'Identicon enableServerMachineStats: Habilitar les estadístiques del maquinari del servidor +showPopup: Notificar els usuaris amb una finestra emergent +showWithSparkles: Mostra amb espurnes +youHaveUnreadAnnouncements: Tens anuncis sense llegir +xl: XL +donationLink: Enllaç a la pàgina de donacions +neverShow: No tornis a mostrar +remindMeLater: Potser després +removeMember: Elimina el membre +removeQuote: Elimina la cita +removeRecipient: Elimina el destinatari diff --git a/locales/en-US.yml b/locales/en-US.yml index b7248e033..76bc5c24a 100644 --- a/locales/en-US.yml +++ b/locales/en-US.yml @@ -105,7 +105,7 @@ privacy: "Privacy" makeFollowManuallyApprove: "Follow requests require approval" defaultNoteVisibility: "Default visibility" follow: "Follow" -followRequest: "Follow" +followRequest: "Follow Request" followRequests: "Follow requests" unfollow: "Unfollow" followRequestPending: "Follow request pending" @@ -644,6 +644,7 @@ useBlurEffectForModal: "Use blur effect for modals" useFullReactionPicker: "Use full-size reaction picker" width: "Width" height: "Height" +xl: "XL" large: "Big" medium: "Medium" small: "Small" @@ -1049,7 +1050,7 @@ customSplashIconsDescription: "URLs for custom splash screen icons separated by showUpdates: "Show a popup when Calckey updates" recommendedInstances: "Recommended servers" recommendedInstancesDescription: "Recommended servers separated by line breaks to - appear in the recommended timeline. Do NOT add `https://`, ONLY the domain." + appear in the recommended timeline." caption: "Auto Caption" splash: "Splash Screen" updateAvailable: "There might be an update available!" @@ -1117,6 +1118,12 @@ enableIdenticonGeneration: "Enable Identicon generation" showPopup: "Notify users with popup" showWithSparkles: "Show with sparkles" youHaveUnreadAnnouncements: "You have unread announcements" +donationLink: "Link to donation page" +neverShow: "Don't show again" +remindMeLater: "Maybe later" +removeQuote: "Remove quote" +removeRecipient: "Remove recipient" +removeMember: "Remove member" _sensitiveMediaDetection: description: "Reduces the effort of server moderation through automatically recognizing @@ -1215,8 +1222,13 @@ _aboutMisskey: source: "Source code" translation: "Translate Calckey" donate: "Donate to Calckey" + donateTitle: "Enjoying Calckey?" + pleaseDonateToCalckey: "Please consider donating to Calckey to support its development." + pleaseDonateToHost: "Please also consider donating to your home server, {host}, to help support its operation costs." + donateHost: "Donate to {host}" morePatrons: "We also appreciate the support of many other helpers not listed here. Thank you! 🥰" + sponsors: "Calckey sponsors" patrons: "Calckey patrons" patronsList: "Listed chronologically, not by donation size. Donate with the link above to get your name on here!" _nsfw: diff --git a/locales/es-ES.yml b/locales/es-ES.yml index 0bd874f33..faf9ba282 100644 --- a/locales/es-ES.yml +++ b/locales/es-ES.yml @@ -642,7 +642,7 @@ wordMute: "Silenciar palabras" regexpError: "Error de la expresión regular" regexpErrorDescription: "Ocurrió un error en la expresión regular en la linea {line} de las palabras muteadas {tab}" -instanceMute: "Instancias silenciadas" +instanceMute: "Servidores silenciados" userSaysSomething: "{name} dijo algo" makeActive: "Activar" display: "Apariencia" @@ -671,14 +671,14 @@ sample: "Muestra" abuseReports: "Reportes" reportAbuse: "Reportar" reportAbuseOf: "Reportar a {name}" -fillAbuseReportDescription: "Ingrese los detalles del reporte. Si hay una nota en - particular, ingrese la URL de esta." +fillAbuseReportDescription: "Ingrese los detalles del reporte. Si hay una publicación + en particular, ingrese la URL de esta." abuseReported: "Se ha enviado el reporte. Muchas gracias." reporter: "Reportador" reporteeOrigin: "Reportar a" reporterOrigin: "Origen del reporte" -forwardReport: "Transferir un informe a una instancia remota" -forwardReportIsAnonymous: "No puede ver su información de la instancia remota y aparecerá +forwardReport: "Transferir reporte a un servidor remoto" +forwardReportIsAnonymous: "No puede ver su información del servidor remoto y aparecerá como una cuenta anónima del sistema" send: "Enviar" abuseMarkAsResolved: "Marcar reporte como resuelto" @@ -686,7 +686,7 @@ openInNewTab: "Abrir en una Nueva Pestaña" openInSideView: "Abrir en una vista al costado" defaultNavigationBehaviour: "Navegación por defecto" editTheseSettingsMayBreakAccount: "Editar estas configuraciones puede dañar su cuenta." -instanceTicker: "Información de notas de la instancia" +instanceTicker: "Información de publicaciones de el servidor" waitingFor: "Esperando a {x}" random: "Aleatorio" system: "Sistema" @@ -697,14 +697,14 @@ createNew: "Crear" optional: "Opcional" createNewClip: "Crear clip nuevo" unclip: "Quitar clip" -confirmToUnclipAlreadyClippedNote: "Esta nota ya está incluida en el clip \"{name}\"\ - . ¿Quiere quitar la nota del clip?" +confirmToUnclipAlreadyClippedNote: "Esta publicación ya está incluida en el clip \"\ + {name}\". ¿Quiere quitar la nota del clip?" public: "Público" i18nInfo: "Calckey está siendo traducido a varios idiomas gracias a voluntarios. Se puede colaborar traduciendo en {link}" manageAccessTokens: "Administrar tokens de acceso" accountInfo: "Información de la Cuenta" -notesCount: "Cantidad de notas" +notesCount: "Cantidad de publicaciones" repliesCount: "Cantidad de respuestas hechas" renotesCount: "Cantidad de renotas hechas" repliedCount: "Cantidad de respuestas recibidas" @@ -720,7 +720,7 @@ no: "No" driveFilesCount: "Cantidad de archivos en el drive" driveUsage: "Uso del drive" noCrawle: "Rechazar indexación del crawler" -noCrawleDescription: "Pedir a los motores de búsqueda que no indexen tu perfil, notas, +noCrawleDescription: "Pedir a los motores de búsqueda que no indexen tu perfil, publicaciones, páginas, etc." lockedAccountInfo: "A menos que configures la visibilidad de tus notas como \"Sólo seguidores\", tus notas serán visibles para cualquiera, incluso si requieres que @@ -734,7 +734,7 @@ verificationEmailSent: "Se le ha enviado un correo electrónico de confirmación configuración." notSet: "Sin especificar" emailVerified: "Su dirección de correo electrónico ha sido verificada." -noteFavoritesCount: "Número de notas favoritas" +noteFavoritesCount: "Número de publicaciones favoritas" pageLikesCount: "Número de favoritos en la página" pageLikedCount: "Número de favoritos de su página" contact: "Contacto" @@ -975,7 +975,7 @@ shuffle: "Aleatorio" account: "Cuentas" move: "Mover" _sensitiveMediaDetection: - description: "Reduce el esfuerzo de la moderación el el servidor a través del reconocimiento + description: "Reduce el esfuerzo de la moderación de el servidor a través del reconocimiento automático de contenido NSFW usando 'Machine Learning'. Esto puede incrementar ligeramente la carga en el servidor." sensitivity: "Sensibilidad de detección" @@ -1295,7 +1295,7 @@ _time: _tutorial: title: "Cómo usar Calckey" step1_1: "¡Bienvenido!" - step1_2: "Vamos a configurarte. Estarás listo y funcionando en poco tiempo" + step1_2: "Vamos a configurarte. ¡Estarás listo y funcionando en poco tiempo!" step2_1: "En primer lugar, rellena tu perfil" step2_2: "Proporcionar algo de información sobre quién eres hará que sea más fácil para los demás saber si quieren ver tus notas o seguirte." @@ -1789,7 +1789,7 @@ _pages: splitStrByLine: "Separar texto en lineas" _splitStrByLine: arg1: "Texto" - ref: "Variables" + ref: "Variable" aiScriptVar: "Variable de AiScript" fn: "funciones" _fn: @@ -1800,8 +1800,8 @@ _pages: _for: arg1: "Cantidad de repeticiones" arg2: "Acción" - typeError: "El slot {slot} acepta el tipo {expect} pero fue ingresado el tipo - {actual}" + typeError: "El slot {slot} acepta el tipo \"{expect}\" pero fue ingresado el tipo + \"{actual}\"" thereIsEmptySlot: "El slot {slot} está vacío" types: string: "Texto" diff --git a/locales/fr-FR.yml b/locales/fr-FR.yml index 633b393ff..f81ef4520 100644 --- a/locales/fr-FR.yml +++ b/locales/fr-FR.yml @@ -1952,8 +1952,7 @@ antennaInstancesDescription: Lister un hôte d'instance par ligne userSaysSomethingReason: '{name} a dit {reason}' breakFollowConfirm: Êtes vous sur de vouloir retirer l'abonné ? recommendedInstancesDescription: Instances recommandées séparées par une nouvelle - ligne pour apparaître dans la timeline recommandée. Ne PAS ajouter `https://`, SEULEMENT - le domaine. + ligne pour apparaître dans la timeline recommandée. sendPushNotificationReadMessage: Supprimer les notifications push une fois que les notifications ou messages concernés ont été lus sendPushNotificationReadMessageCaption: Une notification contenant le texte "{emptyPushNotificationMessage}" diff --git a/locales/gl.yml b/locales/gl.yml new file mode 100644 index 000000000..891a81927 --- /dev/null +++ b/locales/gl.yml @@ -0,0 +1,17 @@ +_lang_: Inglés +introMisskey: Benvida! Calckey é unha plataforma de medios sociais de código aberto, + descentralizada e gratuíta para sempre!🚀 +monthAndDay: '{day}/{month}' +notifications: Notificacións +password: Contrasinal +forgotPassword: Esquecín o contrasinal +gotIt: Vale! +cancel: Cancelar +noThankYou: Non, grazas +headlineMisskey: Plataforma de medios sociais de código aberto e descentralizada, + gratuíta para sempre!🚀 +search: Buscar +searchPlaceholder: Buscar en Calckey +username: Identificador +fetchingAsApObject: Descargando desde o Fediverso +ok: OK diff --git a/locales/ja-JP.yml b/locales/ja-JP.yml index 95fb7bcf8..1043e3524 100644 --- a/locales/ja-JP.yml +++ b/locales/ja-JP.yml @@ -946,7 +946,7 @@ customSplashIconsDescription: "ユーザがページをロード/リロードす URL。画像は静的なURLで、できればすべて192x192にリサイズしてください。" showUpdates: "Calckeyの更新時にポップアップを表示する" recommendedInstances: "おすすめサーバー" -recommendedInstancesDescription: "おすすめタイムラインに表示するサーバーを改行区切りで入力してください。`https://`は書かず、ドメインのみを入力してください。" +recommendedInstancesDescription: "おすすめタイムラインに表示するサーバーを改行区切りで入力してください。" caption: "自動キャプション" splash: "スプラッシュスクリーン" updateAvailable: "アップデートがありますよ!" @@ -983,6 +983,8 @@ enableIdenticonGeneration: "ユーザーごとのIdenticon生成を有効にす showPopup: "ポップアップを表示してユーザーに知らせる" showWithSparkles: "タイトルをキラキラさせる" youHaveUnreadAnnouncements: "未読のお知らせがあります" +neverShow: "今後表示しない" +remindMeLater: "また後で" _sensitiveMediaDetection: description: "機械学習を使って自動でセンシティブなメディアを検出し、モデレーションに役立てられます。サーバーの負荷が少し増えます。" @@ -1068,6 +1070,10 @@ _aboutMisskey: morePatrons: "他にも多くの方が支援してくれています。ありがとうございます! 🥰" patrons: "支援者" patronsList: 寄付額ではなく時系列順に並んでいます。上記のリンクから寄付を行ってここにあなたのIDを載せましょう! + pleaseDonateToCalckey: Calckey開発への寄付をご検討ください。 + pleaseDonateToHost: また、このサーバー {host} の運営者への寄付もご検討ください。 + donateHost: '{host} に寄付する' + donateTitle: Calckeyを気に入りましたか? _nsfw: respect: "閲覧注意のメディアは隠す" ignore: "閲覧注意のメディアを隠さない" @@ -1948,3 +1954,8 @@ removeReaction: リアクションを取り消す alt: 代替テキスト swipeOnMobile: ページ間のスワイプを有効にする reactionPickerSkinTone: 優先する絵文字のスキン色 +xl: 特大 +donationLink: 寄付ページへのリンク +removeMember: メンバーを削除 +removeQuote: 引用を削除 +removeRecipient: 宛先を削除 diff --git a/locales/no-NO.yml b/locales/no-NO.yml index 83e189b9c..5f02d5f19 100644 --- a/locales/no-NO.yml +++ b/locales/no-NO.yml @@ -1,2 +1,83 @@ ---- _lang_: "Norsk Bokmål" +search: Søk +monthAndDay: '{day}/{month}' +fetchingAsApObject: Henter fra fediverset +ok: OK +gotIt: Jeg forstår! +profile: Profil +timeline: Tidslinje +save: Lagre +addToList: Legg til liste +searchPlaceholder: Søk Calckey +username: Brukernavn +password: Passord +notifications: Meldinger +forgotPassword: Glemt passord +cancel: Avbryt +noNotes: Ingen poster +instance: Server +settings: Innstillinger +noAccountDescription: Denne brukeren har ikke fylt ut bio'en sin ennå. +login: Logg inn +loggingIn: Logger inn +signup: Oppretter bruker +uploading: Laster opp.. +enterUsername: Skriv inn brukernavn +noNotifications: Ingen meldinger +users: Brukere +addUser: Legg til en bruker +favorite: Legg til i bokmerker +cantFavorite: Kunne ikke legges til i bokmerker. +pin: Fest til profilen +copyContent: Kopier innhold +deleteAndEdit: Slett og rediger +sendMessage: Send en melding +copyUsername: Kopier brukernavn +reply: Svar +loadMore: Last mer +showLess: Lukk +receiveFollowRequest: Følgeforespørsel mottatt +directNotes: Direktemelding +importAndExport: Importer/eksporter data +importRequested: Du har bedt om en importering. Dette vil ta litt tid. +lists: Lister +listsDesc: Lister lar deg lage tidslinjer med utvalgte brukere. De kan hentes frem + fra tidslinje-siden. +deleted: Slettet +editNote: Rediger notat +followsYou: Følger deg +createList: Lag liste +newer: nyere +older: eldre +download: Last ned +unfollowConfirm: Er du sikker på at du ikke lenger vil følge {name}? +noLists: Du har ingen lister +following: Følger +files: Filer +note: Post +notes: Poster +followers: Følgere +otherSettings: Andre innstillinger +addInstance: Legg til en server +alreadyFavorited: Allerede lagt til i bokmerker. +delete: Slett +openInWindow: Åpne i vindu +basicSettings: Grunnleggende innstillinger +headlineMisskey: En desentralisert sosialt media-plattform, basert på åpen kildekode, + som alltid vil være gratis! 🚀 +introMisskey: Velkommen! Calckey er en desentralisert sosialt media-plattform, basert + på åpen kildekode, som alltid vil være gratis! 🚀 +exportRequested: Du har bedt om en eksportering. Dette vil ta litt tid. Den vil bli + lagt til på disken din når den er ferdig. +noThankYou: Nei takk +favorites: Bokmerker +unfavorite: Fjern fra bokmerker +favorited: Lagt til i bokmerker. +copyLink: Kopier lenke +searchUser: Søk etter en bruker +jumpToPrevious: Gå til foregående +showMore: Vis mer +followRequestAccepted: Følgeforespørsel godtatt +import: Importer +export: Eksporter +logout: Logger ut diff --git a/locales/pt_BR.yml b/locales/pt_BR.yml index 2cc22c86a..f991be913 100644 --- a/locales/pt_BR.yml +++ b/locales/pt_BR.yml @@ -85,3 +85,28 @@ noLists: Você não possui nenhuma lista following: Seguindo followers: Seguidores followsYou: Segue você +fetchingAsApObject: Buscando do Fediverse +timeline: Linha do tempo +favorite: Adicionar aos marcadores +favorites: Marcadores +unfavorite: Remover dos marcadores +favorited: Adicionado aos marcadores. +alreadyFavorited: Já foi adicionado aos marcadores. +download: Download +pageLoadError: Ocorreu um erro ao carregar a página. +pageLoadErrorDescription: Isso normalmente é causado por erros de rede ou pelo cache + do navegador. Tente limpar o cache e, depois de esperar um pouquinho, tente novamente. +serverIsDead: Esse servidos não está respondendo. Por favor espere um pouco e tente + novamente. +youShouldUpgradeClient: Para visualizar essa página, favor reiniciar para atualizar + seu cliente. +enterListName: Insira um nome para a lista +privacy: Privacidade +defaultNoteVisibility: Visibilidade padrão +makeFollowManuallyApprove: Pedidos de seguimento precisam de aprovação +follow: Seguir +followRequest: Seguir +followRequests: Pedidos de seguimento +unfollow: Parar de seguir +followRequestPending: Pedido de seguimento pendente +enterEmoji: Insira um emoji diff --git a/locales/ru-RU.yml b/locales/ru-RU.yml index 8b3e05a17..bfef68d10 100644 --- a/locales/ru-RU.yml +++ b/locales/ru-RU.yml @@ -1847,7 +1847,7 @@ customMOTDDescription: Пользовательские сообщения дл разрывами строк, будут отображаться случайным образом каждый раз, когда пользователь загружает / перезагружает страницу. recommendedInstancesDescription: Рекомендуемые инстансы, разделенные разрывами строк, - должны отображаться на рекомендуемой ленте. НЕ добавляйте `https://`, ТОЛЬКО домен. + должны отображаться на рекомендуемой ленте. caption: Автоматическая подпись splash: Заставка updateAvailable: Возможно, доступно обновление! diff --git a/locales/tr-TR.yml b/locales/tr-TR.yml index a0a45f34c..a3021221d 100644 --- a/locales/tr-TR.yml +++ b/locales/tr-TR.yml @@ -1,9 +1,6 @@ _lang_: "Türkçe" -introMisskey: "Açık kaynaklı bir dağıtılmış mikroblog hizmeti olan Calckey'e hoş geldiniz.\n - Misskey, 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.\n - Herkesin notlarına kendi tepkilerinizi hızlıca eklemek için \"Tepkiler\" özelliğini - de kullanabilirsiniz👍.\nYeni bir dünyayı keşfedin🚀." +introMisskey: "Hoş geldin! Calckey, sonsuza kadar ücretsiz olan, açık kaynaklı, merkezi + olmayan bir sosyal medya platformudur! 🚀" monthAndDay: "{month}Ay {day}Gün" search: "Arama" notifications: "Bildirimler" @@ -11,10 +8,10 @@ username: "Kullanıcı Adı" password: "Şifre" forgotPassword: "şifremi unuttum" ok: "TAMAM" -gotIt: "Anladım" +gotIt: "Anladım!" cancel: "İptal" enterUsername: "Kullanıcı adınızı giriniz" -noNotes: "Gönderiler mevcut değil." +noNotes: "Gönderiler mevcut değil" noNotifications: "Bildirim bulunmuyor" settings: "Ayarlar" basicSettings: "Temel Ayarlar" @@ -22,11 +19,11 @@ otherSettings: "Diğer Ayarlar" openInWindow: "Bir pencere ile aç" profile: "Profil" timeline: "Zaman çizelgesi" -noAccountDescription: "Bu kullanıcı henüz biyografisini yazmadı" -login: "Giriş Yap " +noAccountDescription: "Bu kullanıcı henüz hakkındasını yazmadı." +login: "Giriş Yap" logout: "Çıkış Yap" signup: "Kayıt Ol" -uploading: "Yükleniyor" +uploading: "Yükleniyor..." users: "Kullanıcı" addUser: "Kullanıcı Ekle" favorite: "Favoriler" @@ -54,17 +51,175 @@ user: "Kullanıcı" searchByGoogle: "Arama" _mfm: search: "Arama" + play: MFM'i çal + stop: MFM'i durdur + cheatSheet: MFM Kopya Kağıdı + intro: MFM, Misskey, Calckey, Akkoma ve daha pek çok yerde kullanılabilen bir biçimlendirme + dilidir. Burada mevcut tüm MFM sözdiziminin bir listesini görüntüleyebilirsiniz. + link: Link + boldDescription: Harfleri kalınlaştırarak vurgular. + small: Küçük + smallDescription: İçeriği küçük ve ince görüntüler. + warn: MFM, hızla hareket eden veya gösterişli animasyonlar içerebilir + alwaysPlay: Her zaman tüm animasyonlu MFM'yi otomatik oynat + x4Description: İçeriği büyükten de büyükten daha büyük görüntüler. + rainbowDescription: İçeriğin gökkuşağı renklerinde görünmesini sağlar. + bounceDescription: İçeriğe sıçarayan bir animasyon verir. + sparkle: Işıltı + sparkleDescription: İçeriğe ışıltılı bir parçacık efekti verir. + rotateDescription: İçeriği belirli bir açıyla döndürür. + fadeDescription: İçeriği içeri ve dışarı karartır. + fade: Karart + position: Pozisyon + blockCode: Kod (Blok) + crop: Kırp + positionDescription: İçeriği belirli bir miktarda taşıyın. + scale: Ölçek + scaleDescription: İçeriği belirtilen bir miktara göre ölçeklendirin. + foreground: Ön plan rengi + mention: Bahset + mentionDescription: Bir et-sembolü (@) ve bir kullanıcı adı kullanarak bir kullanıcı + belirleyebilirsiniz. + hashtag: Etiket + dummy: Calckey, Fediverse dünyasını genişletiyor + hashtagDescription: Sayı işareti ve metin kullanarak bir etiket belirtebilirsiniz. + url: URL + urlDescription: URL'ler görüntülenebilir. + inlineMath: Matematik (Satır İçi) + blockCodeDescription: Bir blokta çok satırlı (program) kod için sözdizimi vurgulamasını + görüntüler. + inlineMathDescription: Matematik formüllerini (KaTeX) satır içinde görüntüleyin + quote: Alıntı + quoteDescription: İçeriği alıntı olarak görüntüler. + twitch: Animasyon (Seğir) + emoji: Özel Emoji + jelly: Animasyon (Jöle) + blur: Bulanık + blurDescription: İçeriği bulanıklaştırır. Fareyle üzerine gelindiğinde net bir şekilde + görüntülenecektir. + spinDescription: İçeriğe dönen bir animasyon verir. + plainDescription: Bu MFM efektinde bulunan tüm MFM'lerin etkilerini devre dışı bırakır. + background: Arka plan rengi + backgroundDescription: Metnin arka plan rengini değiştirin. + jump: Animasyon (Zıpla) + cropDescription: İçeriği kırpar. + advancedDescription: Devre dışı bırakılırsa, animasyonlu MFM oynatılmadığı sürece + yalnızca temel işaretlemeye izin verir + bold: Kalın + inlineCodeDescription: (Program) kodu için satır içi sözdizimi vurgulamasını görüntüler. + flip: Tersine Çevir + flipDescription: İçeriği yatay veya dikey olarak çevirir. + font: Yazı Tipi + twitchDescription: İçeriğe güçlü bir şekilde seğiren bir animasyon verir. + spin: Animasyon (Dön) + x2Description: İçeriği büyük gösterir. + rotate: Döndür + plain: Düz + linkDescription: Metnin belirli bölümleri bir URL olarak görüntülenebilir. + searchDescription: Önceden girilmiş metin içeren bir arama kutusu görüntüler. + blockMathDescription: Matematik formüllerini (KaTeX) bir blokta görüntüleyin + jumpDescription: İçeriğe zıplama animasyonu verir. + rainbow: Gökkuşağı + x4: İnanılmaz derecede büyük + tadaDescription: İçeriğe "Tada!" benzeri bir animasyon verir. + shake: Animasyon (Salla) + x3: Büyük göster + blockMath: Matematik (Blok) + x2: Büyük + fontDescription: İçeriğin görüntüleneceği yazı tipini ayarlar. + foregroundDescription: Metnin ön plan rengini değiştirin. + centerDescription: İçeriği ortada görüntüler. + inlineCode: Kod (Satır İçi) + advanced: Gelişmiş MFM + center: Ortala + x3Description: İçeriği daha büyük gösterir. + tada: Animasyon (Tada) + emojiDescription: Özel bir emoji adını iki nokta ile çevreleyerek, özel emoji görüntülenebilir. + jellyDescription: İçeriğe jöle benzeri bir animasyon verir. + shakeDescription: İçeriğe sallanan bir animasyon verir. + bounce: Animasyon (Sıçra) _sfx: notification: "Bildirim" + noteMy: Kendi Gönderim + note: Yeni gönderi + antenna: Anten + chat: Sohbet + channel: Kanal bildirimleri + chatBg: Sohbet (Arkaplan) _widgets: notifications: "Bildirim" timeline: "Zaman çizelgesi" + photos: Fotoğraflar + userList: Kullanıcı Listesi + _userList: + chooseList: Liste seç + onlineUsers: Aktif Kullanıcılar + aiscript: AiScript Konsolu + activity: Aktivite + digitalClock: Dijital Saat + unixClock: UNIX Saati + meiliIndexCount: Indexlenmiş gönderiler + calendar: Takvim + trends: Popüler + memo: Yapışkan Notlar + rssTicker: RSS Ticker + federation: Federasyon + instanceCloud: Sunucu Bulutu + postForm: Gönderi Formu + meiliSize: Index boyutu + slideshow: Slayt Gösterisi + button: Düğme + clock: Saat + rss: RSS Okuyucu + serverInfo: Sunucu Bilgisi + meiliStatus: Sunucu Durumu + jobQueue: İş Sırası + serverMetric: Sunucu Bilgileri _profile: username: "Kullanıcı Adı" + changeBanner: Afişini değiştir + locationDescription: Önce şehrinizi girerseniz, yerel saatinizi diğer kullanıcılara + gösterecektir. + youCanIncludeHashtags: Hakkımdan'da etiket kullanabilirsin. + description: Hakkımda + metadataDescription: Bunları kullanarak profilinizde ek bilgi alanları görüntüleyebilirsiniz. + metadata: Ek Bilgi + metadataContent: İçerik + metadataLabel: Etiket + changeAvatar: Avatarını değiştir + name: İsim + metadataEdit: Ek Bilgini Düzenle _deck: _columns: notifications: "Bildirim" tl: "Zaman çizelgesi" + antenna: Anten + list: Liste + widgets: Araçlar + channel: Kanal + direct: Direkt mesajlar + main: Ana + mentions: Bahsetmeler + swapLeft: Sol sütunla değiştir + addColumn: Sütun ekle + configureColumn: Sütun ayarları + swapRight: Sağ sütunla değiştir + swapUp: Üstteki sütunla değiştir + stackLeft: Sol sütunla birleştir + swapDown: Alttaki sütunla değiştir + popRight: Sağdaki sütunu aç + introduction2: İstediğiniz zaman yeni sütunlar eklemek için ekranın sağındaki + + işaretini tıklayın. + alwaysShowMainColumn: Her zaman ana sütunu göster + columnAlign: Sütunları hizala + profile: Çalışma alanı + newProfile: Yeni çalışma alanı + renameProfile: Çalışma alanını yeniden adlandır + deleteProfile: Çalışma alanını sil + nameAlreadyExists: Bu çalışma alanı zaten mevcut. + introduction: Sütunları özgürce düzenleyerek sizin için mükemmel arayüzü oluşturun! + widgetsIntroduction: Lütfen sütun menüsünde "Araç'ları düzenle"yi seçin ve bir widget + ekleyin. searchPlaceholder: Calckey'de Ara reply: Yanıtla jumpToPrevious: Öncekini görüntüle @@ -80,4 +235,1892 @@ headlineMisskey: Sonsuza kadar ücretsiz, açık kaynak kodlu, merkeziyetsiz sos platformu! 🚀 loadMore: Daha fazla yükle instance: Sunucu -fetchingAsApObject: Fedevren'den çekiliyor +fetchingAsApObject: Fediverse'den çekiliyor +removeReaction: Tepkini sil +rememberNoteVisibility: Gönderi görünürlüğü ayarlarını hatırla +attachCancel: Eklentiyi kaldır +suspend: Askıya Al +unsuspend: Askıya Almayı Kaldır +unmute: Susturmayı Kaldır +blockConfirm: Bu hesabı engellemek istediğinize emin misiniz? +unblockConfirm: Bu hesabın engelini kaldırmak istediğinize emin misiniz? +settingGuide: Tavsiye edilen ayarlar +cacheRemoteFilesDescription: Bu ayar devre dışı bırakıldığında, uzak dosyalar doğrudan + uzak sunucudan yüklenir. Bunun devre dışı bırakılması depolama kullanımını azaltacak, + ancak küçük resimler oluşturulmayacağından trafiği artıracaktır. +flagAsCatDescription: Kedi kulaklarına sahip olacak ve bir kedi gibi konuşacaksın! +flagSpeakAsCat: Kedi gibi konuş +setWallpaper: Arkaplan ayarla +removeWallpaper: Arkaplanı sil +operations: Operasyonlar +clearCachedFiles: Ön belleği temizle +clearCachedFilesConfirm: Önbelleğe alınan tüm uzak dosyaları silmek istediğinizden + emin misiniz? +blockedInstancesDescription: Engellemek istediğiniz sunucuların ana bilgisayar adlarını + listeleyin. Listelenen sunucular artık bu sunucularla iletişim kuramayacak. +blockedUsers: Engellenmiş kullanıcılar +editProfile: Profilini düzenle +intro: Calckey'in indirilmesi tamamlandı! Lütfen yönetici hesap oluşturun. +instanceUsers: Sunucunun kullanıcıları +changePassword: Şifreyi değiştir +security: Güvenlik +newPasswordRetype: Yeni şifreyi tekrarla +uploadFromUrlRequested: Yükleme istendi +syncDeviceDarkMode: Karanlık modu cihazının ayarları ile senkronize et +renameFolder: Bu klasörü yeniden adlandır +emptyFolder: Bu klasör boş +unableToDelete: Silinemiyor +inputNewDescription: Yeni başlık gir +hasChildFilesOrFolders: Bu klasör boş olduğundan silinemez. +disconnectedFromServer: Sunucuyla bağlantı kesildi +reload: Yenile +disablingTimelinesInfo: Yöneticiler ve Moderatörler, etkinleştirilmemiş olsalar bile + tüm zaman çizelgelerine her zaman erişebilir. +pinnedUsersDescription: '"Keşfet" sekmesinde sabitlenecek kullanıcı adlarını satır + sonlarıyla ayırarak listeleyin.' +pinnedPages: Sabitlenmiş Sayfalar +pinnedPagesDescription: Bu sunucunun üst sayfasına sabitlemek istediğiniz Sayfaların + yollarını satır sonları ile ayırarak girin. +enableHcaptcha: hCaptcha'yı Aktif Et +notifyAntenna: Yeni gönderileribildir +recentlyUpdatedUsers: En son aktif kullanıcılar +about: Hakkında +twoStepAuthentication: İki-adımlı doğrulama +securityKeyName: Key name +help: Yardım +inputMessageHere: Mesajını buraya gir +ownedGroups: Gruplarım +joinedGroups: Katılınmış gruplar +invites: Davetler +members: Kullanıcılar +transfer: Transfer +messagingWithGroup: Grup sohbeti +next: Sonraki +retype: Tekrar gir +dashboard: Panel +objectStorageBucket: Bucket +objectStorageBucketDesc: Sağlayıcınız tarafından kullanınan bucket ismini yazın. +showFixedPostForm: Gönderim formunu zaman çizelgesinin en üstünde görüntüleyin +newNoteRecived: Yeni gönderiler mevcut +none: Hiçbiri +details: Detaylar +recentUsed: Son kullanılan +installedApps: Yetkilendirilmiş Uygulamalar +removeAllFollowing: Takip edilen herkesi çıkar +yourAccountSuspendedDescription: Bu hesap, sunucunun hizmet şartlarını veya benzerlerini + ihlal ettiği için askıya alındı. Daha ayrıntılı bir neden öğrenmek istiyorsanız + yöneticiyle iletişime geçin. Lütfen yeni bir hesap oluşturmayın. +addedRelays: Eklenen Röleler +serviceworkerInfo: Push bildirimleri için aktif olması gerekiyor. +author: Sahip +tokenRequested: Hesaba erişim ver +useFullReactionPicker: Tam boyutunda tepki seçici kullan +small: Küçük +enableAll: Hepsine izin ver +disableAll: Hepsini kapat +regexpError: Regex hatası +emailConfigInfo: Kayıt sırasında veya şifrenizi unutursanız e-postanızı onaylamak + için kullanılır +smtpSecure: SMTP bağlantıları için SSL/TSL kullan +regexpErrorDescription: '{tab} kelimenizin {line} satırındaki normal ifadede bir hata + oluştu:' +instanceMute: Sunucu Susturmaları +reporter: Rapor eden +userSaysSomethingReason: '{name}, {reason} söyledi' +userSaysSomethingReasonRenote: '{name}, {reason} içeren bir gönderiyi öne çıkardı' +userSaysSomethingReasonQuote: '{name}, {reason} içeren bir gönderiden alıntı yaptı' +notificationSettingDesc: Görünecek bildirimleri seç. +other: Diğer +sample: Örnek +notSet: Ayarlanmadı +emailVerified: Mail doğrulandı +showGapBetweenNotesInTimeline: Zaman tünelinde gönderiler arasındaki boşluğu göster +sendErrorReports: Hata raporları gönder +followingCount: Takip edilen hesap sayısı +no: Hayır +myTheme: Temam +backgroundColor: Arkaplan rengi +accentColor: Vurgu rengi +textColor: Yazı rengi +createdAt: Oluşturuldu +updatedAt: Güncellendi +saveConfirm: Kaydet? +registry: Kayıt +currentVersion: Şuanki Sürüm +accountDeletionInProgress: Hesap silme şu anda devam ediyor +unresolved: Çözülmedi +newVersionOfClientAvailable: Yeni istemci sürümü mevcut. +shareWithNote: Gönderi ile paylaş +whatIsNew: Değişiklikleri göster +translate: Çevir +breakFollow: Takipçiyi sil +breakFollowConfirm: Takipçiyi kaldırmak istediğinizden emin misiniz? +unfollowConfirm: "{name}'i takibi bırakmak istediğinizden emin misiniz?" +importRequested: Bir içe aktarma isteğinde bulundunuz. Bu biraz zaman alabilir. +somethingHappened: Bir hata ile karşılaşıldı +retry: Tekrar Dene +youShouldUpgradeClient: Bu sayfayı görüntülemek için, lütfen istemcinizi güncelleyin. +reactionSetting: Tepki seçicide gösterilecek tepkiler +unmarkAsSensitive: NSFW işaretini kaldır +enterFileName: Dosya adı gir +noJobs: Hiçbir iş yok +instanceFollowing: Sunucuda takip ediliyor +instanceFollowers: Sunucunun takipçileri +currentPassword: Şuanki şifre +newPassword: Yeni şifre +saved: Kaydedildi +uploadFromUrlDescription: Yüklemek istediğiniz dosyanın URL'si +noMoreHistory: Başka geçmiş yok +startMessaging: Yeni sohbet oluştur +manageGroups: Grupları düzenle +nUsersRead: '{n} tarafından okundu' +images: Görseller +birthday: Doğumgünü +light: Aydınlık +dark: Karanlık +lightThemes: Aydınlık temalar +selectFiles: Dosyalar seç +selectFolders: Klasörler seç +renameFile: Dosyayı yeniden adlandır +folderName: Klasör adı +createFolder: Klasör oluştur +copyUrl: URL'yi Kopyala +maintainerName: Sahip +maintainerEmail: Sahibin e-postası +tosUrl: Kullanım Koşulları URL'si +monthX: '{month}' +basicInfo: Basit bilgi +pinnedUsers: Sabitlenmiş kullanıcılar +manageAntennas: Antenleri Düzenle +name: İsim +silence: Sustur +unsilence: Susturmayı geri al +exploreUsersCount: '{count} Kullanıcı var' +exploreFediverse: Fediversi keşfet +popularTags: Popüler etiketler +close: Kapat +group: Grup +text: Yazı +checking: Doğrulanıyor... +tooLong: Çok uzun +weakPassword: Zayıf şifre +normalPassword: Ortalama şifre +disableDrawer: Çekmece tarzı menüler kullanmayın +youHaveNoGroups: Grupların yok +joinOrCreateGroup: Bir gruba davet edil veya kendininkini oluştur. +regenerate: Yeniden Oluştur +fontSize: Yazı boyutu +noFollowRequests: Bekleyen takip isteğiniz yok +openImageInNewTab: Resmi yeni sekmede aç +useObjectStorage: Object Storage kullan +objectStorageUseProxy: Proxy üzerinden bağlan +installedDate: Yetkilendirilme tarihi +scratchpad: Karalama Defteri +deleteAllFiles: Tüm dosyaları isl +useCw: İçeriği gizle +plugins: Eklentiler +manage: Yönetmek +preferencesBackups: Tercih yedekleri +generateAccessToken: Erişim tokeni oluştur +enableEmail: E-posta dağıtımını etkinleştir +regenerateLoginToken: Giriş tokenini yeniden oluştur +regenerateLoginTokenDescription: Oturum açma sırasında dahili olarak kullanılan belirteci + yeniden oluşturur. Normalde bu eylem gerekli değildir. Yeniden oluşturulursa, tüm + cihazların oturumu kapatılacaktır. +followersCount: Takipçi sayısı +yes: Evet +lockedAccountInfo: Gönderi görünürlüğünüzü "Yalnızca takipçiler" olarak ayarlamazsanız, + takipçilerin manuel olarak onaylanmasını isteseniz bile gönderileriniz herkes tarafından + görülebilir. +unlikeConfirm: Beğeniyi kaldırmak istiyor musunuz? +notSpecifiedMentionWarning: Bu gönderi, alıcı olarak dahil edilmeyen kullanıcılardan + bahsetmektedir +hideOnlineStatus: Çevrimiçi bilgisini gizle +hideOnlineStatusDescription: Çevrimiçi durumunuzu gizlemek, arama gibi bazı özelliklerin + rahatlığını azaltır. +botProtection: Bot Koruması +selectAccount: Hesap seç +recentPosts: En son sayfalar +high: Yüksek +middle: Orta +secureModeInfo: Diğer sunuculardan talepte bulunurken kanıtlamadan geri göndermeyiniz. +previewNoteText: Önizlemeyi göster +customCss: Özel CSS +global: Global +makeReactionsPublic: Tepki geçmişini herkese açık olarak ayarla +clickToFinishEmailVerification: Mail doğrulamasını tamamlamak için lütfen [{ok}]'a + tıklayın. +overridedDeviceKind: Cihaz tipi +smartphone: Akıllı telefon +tablet: Tablet +auto: Otomatik +tenMinutes: 10 dakika +recentNDays: Son {n} gün +noEmailServerWarning: Mail sunucusu ayarlanmadı. +thereIsUnresolvedAbuseReportWarning: Çözülmemiş raporlar var. +statusbar: Durum çubuğu +pleaseSelect: Bir seçenek seçin +lastActiveDate: Son kullanılan +reverse: Tersi +logoutConfirm: Gerçekten oturum kapatılsın mı? +type: Tip +speed: Hız +slow: Yavaş +activeEmailValidationDescription: Tek kullanımlık adreslerin kontrol edilmesi ve gerçekten + iletişim kurup kurulamayacağına göre e-posta adreslerinin daha sıkı doğrulanmasını + sağlar. İşaretlenmediğinde, yalnızca e-postanın biçimi doğrulanır. +move: Taşı +defaultReaction: Giden ve gelen gönderiler için varsayılan emoji tepkisi +indexPosts: Dizin Gönderileri +youGotNewFollower: takip etti +receiveFollowRequest: Takip isteği alındı +followRequestAccepted: Takip isteği onaylandı +mention: Bahset +download: İndir +lists: Listeler +noLists: Hiç listen yok +cantRenote: Bu gönderi yükseltilemez. +cantReRenote: Yükseltme yükseltilemez. +mute: Sustur +block: Engelle +editWidgetsExit: Tamamlandı +customEmojis: Özel Tepki +cpuAndMemory: İşlemci ve Bellek +selectInstance: Sunucu seç +instances: Sunucular +silencedInstancesDescription: Susturmak istediğiniz sunucuların ana bilgisayar adlarını + listeleyin. Listelenen sunuculardaki hesaplar "Sessiz" olarak değerlendirilir, yalnızca + takip istekleri yapabilir ve takip edilmediği takdirde yerel hesaplardan bahsedemez. + Bu, engellenen sunucuları etkilemeyecektir. +muteAndBlock: Susturmalar ve Engeller +noteDeleteConfirm: Bu gönderiyi silmek istediğine emin misin? +resetAreYouSure: Gerçekten sıfırla? +remoteUserCaution: Uzak kullanıcılardan gelen bilgiler eksik olabilir. +yearsOld: '{age} yaşında' +removed: Başarıyla silindi +reject: Reddet +unwatch: İzlemeyi bırak +accept: Kabul et +normal: Normal +thisMonth: Ay +enableRecaptcha: reCAPTCHA'yı Aktif Et +antennas: Antenler +recaptchaSiteKey: Site key +withFileAntenna: Sadece dosyalı gönderiler +antennaInstancesDescription: Sunucu başı bir satır kullanın +moderator: Moderatör +moderation: Moderasyon +lastUsed: En son kullanılan +unregister: Kaydı sil +passwordLessLogin: Şifresiz giriş +uploadFolder: Yüklemeler için varsayılan klasör +markAsReadAllUnreadNotes: Tüm gönderileri okundu olarak işaretle +notFound: Bulunamadı +groups: Gruplar +quoteQuestion: Alıntı olarak eklensin mi? +signinRequired: Lütfen devam etmeden önce kayıt olun +noMessagesYet: Şuana kadar mesaj yok +newMessageExists: Yeni mesaj yok +invitations: Davetler +invitationCode: Davet kodu +signinWith: '{x} ile giriş yap' +strongPassword: Güçlü şifre +passwordNotMatched: Uyuşmuyor +signinFailed: Giriş yapılamadı. Şifre ve ya kullanıcı adı yanlış. +tapSecurityKey: Güvenlik anahtarınıza dokunun +or: veya +noHistory: Geçmiş bulunamadı +language: Dil +clientSettings: İstemci Ayarları +accountSettings: Hesap Ayarları +listen: Dinle +chooseEmoji: Emoji seç +promotion: Terfi Edildi +nothing: Burada görüntülenecek bir şey yok +lastUsedDate: Son kullanılma tarihi +updateRemoteUser: Uzak kullanıcı bilgilerini güncelle +width: Genişlik +height: Uzunluk +permission: İzinler +email: Mail +smtpSecureInfo: STARTTLS kullanırken bunu kapatın +alwaysMarkSensitive: Varsayılan olarak NSFW olarak işaretle +noteFavoritesCount: İşaretlenen gönderilerin sayısı +pageLikesCount: Beğenilen Sayfaların sayısı +duplicate: Kopyasını Oluştur +clearCache: Önbelleği Temizle +onlineUsersCount: '{n} kullanıcı aktif' +nUsers: '{n} Kullanıcı' +nNotes: '{n} Gönderi' +useReactionPickerForContextMenu: Sağ tık ile tepki seçiciyi aç +typingUsers: '{users} yazıyor' +jumpToSpecifiedDate: Spesifik tarihe atla +showingPastTimeline: Şuan eski bir zaman çizelgesini görüntülüyorsunuz +clear: Temizle +fullView: Tam görünüm +emailNotConfiguredWarning: Mail adresi seçilmedi. +privateMode: Özel Mod +fast: Hızlı +learnMore: Daha fazla bilgi edin +localOnly: Sadece yerel +delayed: Ertelenmiş +useGlobalSetting: Global ayaralrı kullan +switchAccount: Hesap değiştir +notRecommended: Tavsiye edilmiyor +onlineStatus: Çevrimiçi bilgisi +active: Aktif +instanceBlocking: Federasyon Yönetmek +enabled: Aktif +disabled: Deaktif +quickAction: Hızlı işlemler +configure: Yapılandır +blockedInstances: Engellenmiş Sunucular +silencedInstances: Susturulmuş Sunucular +lookup: Görüntüle +inputNewFolderName: Yeni klasör ismi gir +noteOf: Gönderi {user} tarafından +onlyOneFileCanBeAttached: Bir mesaja sadece 1 dosya ekleyebilirsin +install: İndir +uninstall: kALDIR +send: Gönder +noCrawleDescription: Arama motorlarından profil sayfanızı, gönderilerinizi, Sayfalarınızı + vb. indekslememesini isteyin. +emailNotification: Mail bildirimleri +goBack: Geri +online: Çevrimiçi +translatedFrom: "{x}'den çevrildi" +cropImage: Resmi kırp +deleteAccount: Hesabı Sil +navbar: Gezinti çubuğu +account: Hesap +instanceDefaultThemeDescription: Tema kodunu nesne biçiminde girin. +alt: ALT +mutePeriod: Sessiz süresi +indefinitely: Kalıcı olarak +oneHour: Bir saat +oneWeek: Bir hafta +colored: Renkli +sensitiveMediaDetection: Resim NSFW Belirleme +subscribePushNotification: Push bildirimlerini aktif et +pushNotificationAlreadySubscribed: Push bildirimler zaten açık +sendPushNotificationReadMessage: İlgili bildirimler veya mesajlar okunduktan sonra + push bildirimlerini silin +sendPushNotificationReadMessageCaption: Kısa bir süre için "{emptyPushNotificationMessage}" + metnini içeren bir bildirim görüntülenecektir. Bu, mümkünse cihazınızın pil kullanımını + artırabilir. +enterSendsMessage: Mesaj göndermek için Mesajlaşma'da Geri Dön'e basın (Ctrl + Return) +customMOTDDescription: Bir kullanıcı sayfayı her yüklediğinde/yeniden yüklediğinde + rastgele gösterilecek satır sonlarıyla ayrılmış MOTD (açılış ekranı) için özel mesajlar. +customSplashIconsDescription: Bir kullanıcı sayfayı her yüklediğinde/yeniden yüklediğinde + rastgele gösterilecek satır sonlarıyla ayrılmış özel açılış ekranı simgeleri için + URL'ler. Lütfen resimlerin statik bir URL'de olduğundan ve tercihen tümü 192x192 + olarak yeniden boyutlandırıldığından emin olun. +updateAvailable: Bir güncelleme mevcut olabilir! +splash: Açılış Ekranı +moveTo: Şimdiki hesabını yeni bir hesaba taşı +swipeOnMobile: Sayfalar arasında kaydırmaya izin ver +swipeOnDesktop: Masaüstünde mobil stil kaydırmaya izin ver +migration: Taşıma +moveAccount: Hesabını taşı! +moveFrom: Daha eski bir hesaptan bu hesaba taşıyın +moveFromLabel: 'Taşındığınız hesap:' +importAndExport: İçeri/Dışarı Aktar +manageLists: Listeleri düzenle +error: Hata +pageLoadError: Sayfayı yüklerken bir hata ile karşılaşıldı. +serverIsDead: Sunucu yanıt vermiyor. Biraz bekleyip tekrar deneyin. +defaultNoteVisibility: Varsayılan görünürlük +follow: Takip et +reactionSettingDescription2: Yeniden sıralamak için sürükleyin, silmek için tıklayın, + eklemek için "+"ya basın. +you: Sen +clickToShow: Görmek için tıkla +sensitive: NSFW +add: Ekle +reaction: Tepkiler +markAsSensitive: NSFW olarak işaretle +unblock: Engeli Kaldır +addAccount: Hesap ekle +network: İnternet +disk: Depolama +instanceInfo: Sunucu Bilgisi +statistics: İstatistikler +hiddenTagsDescription: Trendlerden gizlemek ve keşfetmek istediğiniz etiketlerin (# + olmadan)etiketlerini listeleyin. Gizli etiketler başka yollarla keşfedilebilir. +mutedUsers: Susturulmuş kullanıcılar +uploadFromUrlMayTakeTime: Yüklemenin tamamlanması zaman alabilir. +activity: Aktivite +theme: Temalar +themeForLightMode: Aydınlık modda kullanmak için temalar +reloadConfirm: Zaman çizelgesini yenilemek ister misiniz? +instanceName: Sunucu adı +circularReferenceFolder: Hedef klasör, taşımak istediğiniz klasörün bir alt klasörüdür. +instanceDescription: Sunucu açıklaması +driveCapacityPerLocalAccount: Kullanıcı başı Driver kapasitesi +driveCapacityPerRemoteAccount: Uzak kullanıcı başı Driver kapasitesi +inMb: Megabayt cinsinden +pinnedClipId: Sabitlenecek atacın ID'si +withFiles: Dosya içeren +recentlyRegisteredUsers: Yeni katılmış kullanıcılar +recentlyDiscoveredUsers: Yeni keşfedilmiş kullanıcılar +nUsersMentioned: '{n} kullanıcı tarafından bahsedildi' +securityKey: Security key +title: Başlık +total: Toplam +sounds: Sesler +objectStorageRegionDesc: "'xx-east-1' gibi bir bölge belirtin. Hizmetiniz bölgeler + arasında ayrım yapmıyorsa, bunu boş bırakın veya 'us-east-1' girin." +objectStorageUseSSL: SSL Kullan +popout: Açılır Pencere +volume: Ses Kuvveti +showInPage: Sayfada göster +masterVolume: Ana ses +undeck: Desteden çık +useBlurEffectForModal: Modallar için bulanıklık efekti uygula +leaveConfirm: Kaydedilmemiş değişiklikler var. Devam etmek istiyor musunuz? +testEmail: Email dağıtımını test et +wordMute: Kelime susturması +userSaysSomething: '{name} bir şey söyledi' +channel: Kanallar +create: Oluştur +useGlobalSettingDesc: Açıksa, hesap bildirim ayarlarınız kullanılacaktır. Kapatılırsa, + bireysel yapılandırmalar yapılabilir. +setMultipleBySeparatingWithSpace: Birden çok girişi boşluklarla ayırın. +fileIdOrUrl: Dosya ID veya URL'si +behavior: Davranış +abuseReported: Raporunuz gönderildi. Teşekkürler. +reporteeOrigin: Ana Raporcu +reporterOrigin: Ana Rapor Eden +defaultNavigationBehaviour: Varsayılan gezinme davranışı +editTheseSettingsMayBreakAccount: Bunları düzenlemek hesabınıza zarar verebilir. +renotedCount: Alınan yükseltme sayısı +driveFilesCount: Drive dosya sayısı +deleteConfirm: Sil? +invalidValue: Geçersiz değer. +instanceSecurity: Sunucu Güvenliği +searchResult: Arama sonuçları +useBlurEffect: Kullanıcı arayüzünde bulanıklaştırma efektleri kullanın +misskeyUpdated: Calckey güncellendi! +lastCommunication: Son iletişim +itsOn: Etkinleştirilmiş +emailRequiredForSignup: Kayıt olmak için mail gerekiyor +leaveGroup: Gruptan ayrıl +useDrawerReactionPickerForMobile: Reaksiyon seçiciyi mobil cihazda çekmece olarak + göster +leaveGroupConfirm: '"{name}"den ayrılmak istediğinizden emin misiniz?' +instanceDefaultLightTheme: Sunucu genelinde varsayılan aydınlık tema +document: Dökümanlar +numberOfPageCacheDescription: Bu sayının arttırılması, kullanıcılar için kolaylık + sağlayacaktır ancak daha fazla sunucu yükünün yanı sıra daha fazla bellek kullanılmasına + neden olacaktır. +refreshInterval: 'Güncelleme aralığı ' +label: Etiket +replayTutorial: Eğiticiyi tekrar oynat +moveAccountDescription: Bu süreç geri döndürülemez. Taşımadan önce yeni hesabınızda + bu hesap için bir takma ad ayarladığınızdan emin olun. Lütfen @person@server.com + şeklinde biçimlendirilmiş hesabın etiketini girin +emojis: Emoji +flagAsCat: Kedi misin? 😺 +selectChannel: Kanal seç +emojiName: Emoji adı +showOnRemote: Uzak sunucuda görüntüle +flagSpeakAsCatDescription: Gönderileriniz kedi modundayken nyanifiye edilecek +flagShowTimelineReplies: Yanıtları zaman çizelgesinde göster +silenceThisInstance: Bu sunucuyu sustur +proxyAccountDescription: Vekil 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 sunucuya teslim edilmeyecektir, bu nedenle onun yerine vekil hesabı takip + edilecektir. +clearQueueConfirmTitle: Bu sırayı temizlemek istediğine emin misin? +software: Yazılım +version: Sürüm +federating: Federasyon +preview: Ön izleme +retypedNotMatch: Girişler uyuşmuyor. +attachFile: Dosya ekle +noSuchUser: Kullanıcı bulunamadı +removeAreYouSure: '"{x}" kaldırmak istediğinize emin misiniz?' +keepOriginalUploading: Orjinal resmi sakla +messageRead: Oku +deleteAreYouSure: '"{x}" silmek istediğinize emin misiniz?' +messaging: Sohbet +upload: Yükle +fromUrl: URL'den +agreeTo: '{0} kabul ediyorum' +tos: Kullanım Koşulları +drive: Drive +selectFolder: Klasör seç +inputNewFileName: Yeni dosya ismi gir +whenServerDisconnected: Sunucuyla bağlantı kesildiğinde +avatar: Avatar +rename: Yeniden Adlandır +banner: Afiş +nsfw: NSFW +doNothing: Görmezden Gel +watch: İzle +connectService: Bağlan +registration: Kayıt +hcaptcha: hCaptcha +pinnedNotes: Sabitlenmiş gönderiler +hcaptchaSiteKey: Site key +hcaptchaSecretKey: Secret key +antennaSource: Anten kaynağı +antennaKeywords: Dinlenecek anahtar kelimeler +antennaExcludeKeywords: Hariç tutulacak anahtar kelimeler +antennaKeywordsDescription: AND koşulu için boşluklarla veya OR koşulu için satır + sonlarıyla ayırın. +caseSensitive: Büyük harf duyarlı +enableServiceworker: Tarayıcınız için Push-Bildirimleri Etkinleştirin +unsilenceConfirm: Bu kullanıcının susturma işlemini geri almak istediğinizden emin + misiniz? +userList: Listeler +antennaUsersDescription: Kullanıcı başı bir satır kullanın +administrator: Yönetici +token: Token +cacheClear: Önbelleği temizle +createGroup: Grup oluştur +newPasswordIs: Yeni şifren "{password}" +share: Paylaş +enable: Etkinleştir +groupName: Grup adı +available: Mevcut +unavailable: Mevcut değil +weekOverWeekChanges: Geçen haftadan beri değişiklikler +usernameInvalidFormat: Büyük ve küçük harfleri, sayıları ve alt çizgileri kullanabilirsiniz. +tooShort: Çok kısa +passwordMatched: Uyuşuyor +dayOverDayChanges: Dünden beri değişiklikler +appearance: Görünüm +objectStorageBaseUrl: Ana URL +objectStoragePrefix: Prefix +unableToProcess: Operasyon tamamlanamadı +deleteAllFilesConfirm: Tüm dosyaları silmek istediğine emin misin? +disablePagesScript: Sayfalardan AiScript'i deaktive et +expandOnNoteClick: Gönderileri basarak aç +expandOnNoteClickDesc: Kapatılırsa, gönderileri hala menüden veya sağtıklayarak açabilirsin. +removeAllFollowingDescription: Bunu gerçekleştirmek, {host} üzerindeki tüm hesapları + takip etmeyi bırakır. +deck: Deste +pluginTokenRequestedDescription: Bu eklenti, burada ayarlanan izinleri kullanabilecektir. +notificationType: Bildirim tipi +channelFederationWarn: Kanallar başka sunuculara federe edilmiyor +forwardReport: Raporu uzak sunucuya ilet +openInNewTab: Yeni sekmede aç +clip: Ataç +optional: Opsiyonel +manageAccessTokens: Erişim tokenlerini düzenle +clipsDesc: Ataçlar, paylaşılabilen kategorize yer imleri gibidir. Tek tek gönderiler + menüsünden ataçlar oluşturabilirsiniz. +makeExplorable: Hesabını "Keşfet" 'te göster +accountInfo: Hesap Bilgisi +makeExplorableDescription: Bunu kapatırsanız, hesabınız "Keşfet" bölümünde görünmez. +saveAs: Olarak kaydet... +advanced: Gelişmiş +value: Değer +youAreRunningUpToDateClient: En son istemci sürümünü kullanıyorsunuz. +accounts: Hesaplar +switch: Değiştir +popularPosts: Popüler sayfalar +inChannelSearch: Kanalda ara +administration: Yönetim +ads: Reklamlar +low: Düşük +seperateRenoteQuote: Ayrı destek ve fiyat teklifi düğmeleri +sent: Gönderildi +customMOTD: Özel MOTD +showUpdates: Calckey güncellendiğinde bir açılır pencere göster +logoImageUrl: Logo resim URL'si +showAdminUpdates: Yeni bir Calckey sürümünün mevcut olduğunu belirtin (yalnızca yönetici) +newer: asla +older: daha eski +exportRequested: Bir dışarı aktarma talebinde bulundunuz. Bu biraz zaman alabilir. + Tamamlandığında Drive'ınıza eklenecektir. +notes: Gönderiler +following: Takip Ediyor +followers: Takipçiler +followsYou: Seni takip ediyor +pageLoadErrorDescription: Buna normalde ağ hataları veya tarayıcının önbelleği neden + olur. Önbelleği temizlemeyi deneyin ve biraz bekledikten sonra tekrar deneyin. +quote: Alıntıla +pinnedNote: Sabitlenmiş gönderi +renote: Yükselt +unrenote: Yükseltmeyi geri al +emojiUrl: Emoji URL +suspendConfirm: Bu hesabı askıya almak istediğinize emin misiniz? +addEmoji: Ekle +autoAcceptFollowed: Takip ettiğiniz kullanıcıların takip isteklerini otomatik olarak + onaylayın +general: Genel +accountMoved: 'Bu kullanıcı yeni bir hesapa taşındı:' +wallpaper: Arkaplan +searchWith: 'Arat: {q}' +youHaveNoLists: Hiçbir listen yok +followConfirm: '{name} kullanıcısını takip etmek istediğine emin misin?' +metadata: Metadata +monitor: İzlengeç +jobQueue: İş Sırası +noUsers: Kullanıcı bulunamadı +noInstances: Sunucu bulunamadı +pinLimitExceeded: Daha fazla gönderi sabitleyemezsin +defaultValueIs: 'Varsayılan: {value}' +noCustomEmojis: Emoji yok +blocked: Engellenmiş +default: Varsayılan +all: Tümü +subscribing: Abone Olunuyor +publishing: Yayınlanmak +notResponding: Cevap vermiyor +more: Daha fazla! +featured: Önerilen +usernameOrUserId: Kullanıcı adı veya kullanıcı id'si +fromDrive: Drive'dan +uploadFromUrl: URL'den yükle +announcements: Duyurular +explore: Keşfet +imageUrl: Resim URL'si +thisYear: Yıl +deleteFolder: Bu klasörü sil +addFile: Dosya ekle +dayX: '{day}' +enableLocalTimeline: Yerel zaman çizgisini aktif et +disconnectService: Bağlantıyı kes +enableGlobalTimeline: Global zaman çizgisini aktif et +enableRegistration: Yeni kullanıcı kaydını aktif et +invite: Davet et +bannerUrl: Afiş resmi URL +backgroundImageUrl: Arkaplan URL'si +recaptcha: reCAPTCHA +iconUrl: Ikon URL +recaptchaSecretKey: Secret key +avoidMultiCaptchaConfirm: Birden fazla Captcha sistemi kullanmak aralarında etkileşime + neden olabilir. Şu anda etkin olan diğer Captcha sistemlerini devre dışı bırakmak + ister misiniz? Etkin kalmalarını istiyorsanız, iptal düğmesine basın. +aboutMisskey: Calckey Hakkında +popularUsers: Popüler kullanıcılar +notFoundDescription: Bu URL'ye karşılık gelen sayfa bulunamadı. +reduceUiAnimation: Arayüz animasyonlarını azalt +markAsReadAllNotifications: Tüm bildirimleri okundu olarak işaretle +markAsReadAllTalkMessages: Tüm mesajları okundu olarak işaretle +inviteToGroup: Gruba davet et +quoteAttached: Alıntıla +useOsNativeEmojis: Sistem Emojilerini Kullan +signinHistory: Giriş geçmişleri +disableAnimatedMfm: Animasyonlu MFM'yi devre dışı bırak +uiLanguage: Arayüz dili +groupInvited: Bir gruba davet edildin +createAccount: Hesap Oluştur +existingAccount: Var olan hesap +aboutX: '{x} Hakkında' +doing: İşleniyor... +category: Kategori +deleteAll: Hepsini sil +objectStorageEndpoint: Endpoint +output: Çıkış +userSuspended: Bu kullanıcı askıya alındı. +userSilenced: Bu kullanıcı susturuldu. +yourAccountSuspendedTitle: Bu hesap askıya alındı +relays: Röleler +inboxUrl: Gelen URL +menu: Menü +divider: Ayraç +addItem: Öğe Ekle +enableInfiniteScroll: Otomatik olarak daha fazla yükle +enablePlayer: Video oynatıcıyı aç +disablePlayer: Video oynatıcıyı kapat +expandTweet: Tweeti Büyüt +large: Büyük +medium: Orta +smtpConfig: SMTP Sunucusu Ayarları +smtpHost: Adres +emailServer: Mail sunucusu +edit: Düzenle +emailAddress: Mail adresi +smtpPort: Port +emptyToDisableSmtpAuth: SMTP doğrulamasını kapatmak için kullanıcı adı ve şifreyi + boş bırakın +makeActive: Aktif +display: Gösterim +copy: Kopyala +metrics: Metrikler +pollVotesCount: Gönderilen oylama sayısı +loadRawImages: Küçük resimleri göstermek yerine orijinal resimleri yükleyin +switchUi: Düzen +sentReactionsCount: Gönderilen tepki sayısı +receivedReactionsCount: Alınan tepki sayısı +pollVotedCount: Alınan oylama sayısı +pageLikedCount: Beğeni alan Sayfa sayısı +contact: Bağlantı +useSystemFont: Sistemin varsayılan yazı tipini kullan +usageAmount: Kullanım +inUse: Kullanılan +userInfo: Kullanıcı bilgisi +unknown: Bilinmiyor +customCssWarn: Bu ayar yalnızca ne işe yaradığını biliyorsanız kullanılmalıdır. Uygun + olmayan değerlerin girilmesi, istemcinin normal şekilde çalışmamasına neden olabilir. +memo: Not +allowedInstancesDescription: Her biri yeni bir satırla ayrılmış, federasyon için beyaz + listeye eklenecek sunucu ana bilgisayarları (yalnızca özel modda geçerlidir). +expiration: Bitiş +troubleshooting: Sorun giderme +usernameInfo: Hesabınızı bu sunucudaki diğerlerinden ayıran bir ad. Alfabeyi (a~z, + A~Z), rakamları (0~9) veya alt çizgileri (_) kullanabilirsiniz. Kullanıcı adları + daha sonra değiştirilemez. +size: Boyut +numberOfColumn: Sütun Sayısı +driveCapOverrideCaption: 0 veya daha düşük bir değer girerek kapasiteyi varsayılana + sıfırlayın. +requireAdminForView: Bunu görüntülemek için bir yönetici hesabıyla oturum açmalısınız. +userSaysSomethingReasonReply: '{name}, {reason} içeren bir gönderiye cevap verdi' +overview: Genel Bakış +logs: Günlükler +database: Veri Tabanı +reportAbuseOf: '{name} kullanıcısını raporla' +openInSideView: Yan görünümde aç +createNew: Yeni oluştur +createNewClip: Yeni ataç oluştur +unclip: Atacı Kaldır +notesCount: Gönderi sayısı +repliesCount: Gönderilen yanıt sayısı +renotesCount: Göndeirlen yükseltme sayısı +repliedCount: Alınan yanıt sayısı +driveUsage: Drive kullanımı +noCrawle: Tarayıcı dizine eklemeyi reddet +needReloadToApply: Bunun yansıtılması için bir yeniden yükleme gereklidir. +showTitlebar: Başlık çubuğunu göster +latestVersion: En Son Sürüm +capacity: Kapasite +userPagePinTip: Tek tek gönderiler menüsünden "Profile sabitle"yi seçerek gönderileri + burada görüntüleyebilirsiniz. +offline: Çevrimdışı +priority: Öncelik +ratio: Oran +secureMode: Güvenli Mod (Yetkili Getirme) +aiChanMode: Klasik kullanıcı arayüzünde Ai-chan +recommended: Önerilen +received: Alındı +classic: Ortalanmış +muteThread: Konuyu sessize al +deleteAccountConfirm: Bu, hesabınızı geri alınamaz bir şekilde silecektir. İlerle? +hide: Gizle +pubSub: Pub/Sub Hesapları +filter: Filtre +controlPanel: Kontrol Paneli +continueThread: Konuya devam et +incorrectPassword: Yanlış şifre. +voteConfirm: '"{choice}" için oyunuzu onaylıyor musunuz?' +failedToFetchAccountInformation: Hesap bilgileri getirilemedi +rateLimitExceeded: Hız limiti aşıldı +renotedBy: '{user} Yükseltti' +host: Host +objectStorage: Object Storage +objectStorageUseSSLDesc: API bağlantıları için HTTPS kullanmayacaksanız bunu kapatın +objectStorageUseProxyDesc: API bağlantıları için Proxy kullanmayacaksanız bunu kapatın +objectStorageSetPublicRead: Yüklendiğinde "public-read" kullan +serverLogs: Sunucu günlüğü +abuseReports: Raporlar +reportAbuse: Rapor +verificationEmailSent: Bir doğrulama maili gönderildi. Doğrulamayı tamamlamak için + lütfen verilen bağlantıyı takip edin. +hashtags: Etiketler +resolved: Çözüldü +flagShowTimelineRepliesDescription: Açıksa, kullanıcıların zaman çizelgesindeki diğer + kullanıcıların gönderilerine verdiği yanıtları gösterir. +clearQueueConfirmText: Kuyrukta kalan teslim edilmemiş gönderiler birleştirilmeyecektir. + Genellikle bu işleme gerek yoktur. +image: Resim +video: Video +showMore: Daha Fazla +showLess: Kapat +selectAntenna: Anten seç +selectWidget: Araç seç +unsuspendConfirm: Bu hesabın askıya almasını kaldırmak istediğinize emin misiniz? +selectList: Liste seç +editWidgets: Araçları düzenle +showEmojisInReactionNotifications: Tepki bildirimlerinde emojileri göster +renoteMute: Yükseltmeleri sustur +renoteUnmute: Yükseltmeleri susturmayı kaldır +loginFailed: Giriş yapılamadı +proxyAccount: Vekil Hesap +selectUser: Kullanıcı seç +recipient: Alıcı(lar) +annotation: Yorumlar +federation: Federasyon +registeredAt: Kayıtlı +latestRequestSentAt: Gönderilen son istek +latestRequestReceivedAt: Alınan son istek +latestStatus: Son durum +storageUsage: Depolama kullanımı +charts: Grafikler +perHour: Saat Başı +perDay: Gün Başı +stopActivityDelivery: Etkinlik göndermeyi durdur +blockThisInstance: Bu sunucuyu engelle +themeForDarkMode: Karanlık modda kullanmak için temalar +fileName: Dosya adı +selectFile: Dosya seç +emptyDrive: Drive'n boş +promote: Terfi +numberOfDays: Gün sayısı +hideThisNote: Bu gönderiyi gizle +file: Dosya +enableEmojiReactions: Emoji tepkilerini aç +cw: İçerik uyarısı +makeFollowManuallyApprove: Takip istekleri onay gerektirir +today: Bugün +enableRecommendedTimeline: Tavsiye edilen zaman çizgisini aktive et +state: Durum +sort: Sırala +script: Skript +keepCw: İçerik uyarılarını sakla +manageAccounts: Hesapları Düzenle +makeReactionsPublicDescription: Bu, tüm geçmiş tepkilerinizin listesini herkesin görebileceği + bir hale getirecektir. +unmuteThread: İleti dizisinin sesini aç +ffVisibility: Takipler/Takipçiler Görünürlüğü +reflectMayTakeTime: Bunun yansıması biraz zaman alabilir. +cropImageAsk: Bu resmi kırpmak istediğinize emin misiniz? +check: Kontrol Et +driveCapOverrideLabel: Bu kullanıcı için drive kapasitesini değiştirin +numberOfPageCache: Önbelleğe alınan sayfa sayısı +license: Lisans +indexFrom: Post ID'den itibaren dizin +xl: XL +notificationSetting: Bildirim ayarları +fillAbuseReportDescription: Lütfen bu raporla ilgili ayrıntıları doldurun. Belirli + bir gönderiyle ilgiliyse, lütfen URL'sini ekleyin. +forwardReportIsAnonymous: Uzak sunucuda, hesabınız yerine raportör olarak anonim bir + sistem hesabı görüntülenecektir. +abuseMarkAsResolved: Raporu çözüldü olarak işaretle +instanceTicker: Göndeirlerdeki sunucu bilgisi +waitingFor: '{x} bekleniyor' +random: Rastgele +public: Herkese açık +i18nInfo: Calckey, gönüllüler tarafından çeşitli dillere çevriliyor. {link} adresinden + yardımcı olabilirsiniz. +disableShowingAnimatedImages: Animasyonlu görüntüleri oynatma +clips: Ataçlar +experimentalFeatures: Deneysel özellikler +developer: Geliştirici +left: Sol +center: Orta +wide: Geniş +narrow: Dar +reloadToApplySetting: Bu ayar yalnızca bir sayfa yeniden yüklendikten sonra geçerli + olacaktır. Şimdi yeniden yüklensin mi? +editCode: Kodu düzenle +apply: Uygula +receiveAnnouncementFromInstance: Bu sunucudan bildirimleri al +publish: Paylaş +quitFullView: Tam görünümden çık +addDescription: Açıklama ekle +info: Hakkında +noMaintainerInformationWarning: Yönetici bilgileri yapılandırılmadı. +noBotProtectionWarning: Bot koruması yapılandırılmamış. +postToGallery: Yeni galeri gönderisi oluştur +gallery: Galeri +privateModeInfo: Etkinleştirildiğinde, yalnızca beyaz listedeki sunucular sunucunuzla + birleşebilir. Tüm gönderiler halktan gizlenecektir. +itsOff: Etkinsizleştirilmiş +ffVisibilityDescription: Kimleri takip ettiğinizi ve kimlerin sizi takip ettiğini + kimlerin görebileceğini yapılandırmanıza izin verir. +welcomeBackWithName: Tekrar hoş geldin {name} +themeColor: Sunucu Kayan Yazı Rengi +audio: Ses +recentNHours: Son {n} saat +isSystemAccount: Bu hesap sistem tarafından oluşturulur ve otomatik olarak işletilir. + Lütfen bu hesabı denetlemeyin, düzenlemeyin, silmeyin veya başka bir şekilde kurcalamayın, + aksi takdirde sunucunuz bozulabilir. +typeToConfirm: Lütfen onaylamak için {x} girin +remoteOnly: Sadece uzak +failedToUpload: Yükleme başarısız +cannotUploadBecauseInappropriate: Bu dosya, bazı bölümleri potansiyel olarak NSFW + olarak algılandığından yüklenemedi. +cannotUploadBecauseNoFreeSpace: Drive kapasitesi yetersiz olduğundan yükleme başarısız + oldu. +cannotUploadBecauseExceedsFileSizeLimit: Bu dosya, izin verilen maksimum boyutu aştığı + için yüklenemedi. +beta: Beta +enableAutoSensitive: Otomatik NSFW İşaretleme +enableAutoSensitiveDescription: Mümkün olduğunda Makine Öğrenimi yoluyla NSFW ortamının + otomatik olarak algılanmasına ve işaretlenmesine olanak tanır. Bu seçenek devre + dışı bırakılsa bile, sunucu çapında etkinleştirilebilir. +shuffle: Karıştır +pushNotification: Push bildirimleri +unsubscribePushNotification: Push bildirimlerini kapat +pushNotificationNotSupported: Tarayıcınız veya sunucunuz push bildirimleri desteklemiyor +caption: Otomatik Başlık +moveToLabel: 'Taşıyacağın hesap:' +moveFromDescription: Bu, eski hesabınızın bir takma adını belirleyecek ve böylece + o hesaptan bu mevcut hesaba geçebileceksiniz. Bunu eski hesabınızdan taşınmadan + ÖNCE yapın. Lütfen @person@server.com şeklinde biçimlendirilmiş hesabın etiketini + girin +migrationConfirm: "Hesabınızı {account} hesabına taşımak istediğinizden kesinlikle + emin misiniz? Bunu yaptığınızda, geri alamazsınız ve hesabınızı bir daha normal + şekilde kullanamazsınız.\nAyrıca, lütfen bu cari hesabı, taşındığınız hesap olarak + ayarladığınızdan emin olun." +indexFromDescription: Her gönderiyi dizine eklemek için boş bırakın +indexNotice: Şimdi indeksleniyor. Bu muhtemelen biraz zaman alacaktır, lütfen sunucunuzu + en az bir saat yeniden başlatmayın. +customKaTeXMacro: Özel KaTeX makroları +directNotes: Direkt Mesajlar +import: İçeri Aktar +export: Dışarı Aktar +mentions: Bahsetmeler +files: Dosyalar +driveFileDeleteConfirm: '"{name}" dosyasını silmek istediğinizden emin misiniz? Ek + olarak içeren tüm gönderilerden kaldırılacaktır.' +createList: Liste oluştur +listsDesc: Listeler, belirtilen kullanıcılarla zaman çizelgesi oluşturmanıza olanak + tanır. Zaman Çizelgesi sayfasından erişilebilirler. +note: Gönder +enterListName: Liste için isim gir +unfollow: Takipten Çık +privacy: Gizlilik +followRequestPending: Takip isteği bekleniyor +enterEmoji: Bir emoji gir +followRequest: Takip İsteği +followRequests: Takip istekleri +renoted: Yükseldi. +emoji: Emoji +cacheRemoteFiles: Uzak dosyaları önbellekle +flagAsBot: Bu hesabı robot olarak işaretle +flagAsBotDescription: Bu hesap bir program tarafından kontrol ediliyorsa bu seçeneği + etkinleştirin. Etkinleştirilirse, diğer geliştiricilerin diğer botlarla sonsuz etkileşim + zincirlerini önlemesi ve Calckey'nin dahili sistemlerini bu hesabı bir bot olarak + ele alacak şekilde ayarlaması için bir bayrak görevi görür. +clearQueue: Sırayı Temizle +hiddenTags: Gizlenmiş Etiketler +done: Tamamlandı +processing: İşleniyor +silenced: Susturulmuş +darkThemes: Karanlık temalar +suspended: Askıya Alınmış +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. +start: Başla +home: Ev +location: Konum +registeredDate: Katılım tarihi +yearX: '{year}' +pages: Sayfalar +integration: Entegrasyonlar +antennasDesc: "Antenler, belirlediğiniz kriterlere uyan yeni gönderiler görüntüler!\n + Zaman çizelgeleri sayfasından erişilebilirler." +notesAndReplies: Gönderiler ve yanıtlar +withReplies: Yanıtları da içer +connectedTo: Aşağıdaki hesap(lar) bağlı +silenceConfirm: Bu kullanıcıyı susturmak istediğinize emin misiniz? +messagingWithUser: Özel sohbet +resetPassword: Şifreyi sıfırla +registerSecurityKey: Yeni security key tanımla +docSource: Bu dökümanın kaynağı +ascendingOrder: Artan +tags: Etiketler +descendingOrder: Azalan +scratchpadDescription: Karalama defteri, AiScript deneyleri için bir ortam sağlar. + İçinde Calckey ile etkileşime girerek sonuçlarını yazabilir, çalıştırabilir ve kontrol + edebilirsiniz. +local: Yerel +remote: Uzak +addRelay: Röle Ekle +accessibility: Erişilebilirlik +showFeaturedNotesInTimeline: Önerilen gönderileri zaman çizelgesinde göster +objectStorageBaseUrlDesc: "Referans olarak kullanılan URL. İkisinden birini kullanıyorsanız, + CDN veya Proxy'nizin URL'sini belirtin.\nS3 için 'https://.s3.amazonaws.com' + kullanın ve GCS veya eşdeğer hizmetler için 'https://storage.googleapis.com/' + vb. kullanın." +objectStoragePrefixDesc: Dosyalar bu prefix ile dizinler altında saklanacaktır. +objectStorageEndpointDesc: AWS S3 kullanıyorsanız bunu boş bırakın, aksi halde kullandığınız + hizmete bağlı olarak uç noktayı "" veya ":" olarak belirtin. +objectStorageRegion: Region +invisibleNote: Gizli Gönderi +deletedNote: Silinmiş Gönderi +visibility: Görünürlük +poll: Anket +themeEditor: Tema düzenleyicisi +enterFileDescription: Başlık gir +description: Açıklama +describeFile: Başlık ekle +system: Sistem +desktop: Masaüstü +confirmToUnclipAlreadyClippedNote: Bu gönderi zaten "{name}" atacının bir parçası. + Bunun yerine onu bu ataçtan kaldırmak istiyor musunuz? +sendErrorReportsDescription: "Açıldığında, bir sorun oluştuğunda ayrıntılı hata bilgileri + Calckey ile paylaşılarak Calckey kalitesinin artırılmasına yardımcı olur.\nBu, işletim + sisteminizin sürümü, kullandığınız tarayıcı, Calckey'deki etkinliğiniz vb. bilgileri + içerecektir." +closeAccount: Hesabı kapat +markAllAsRead: Okunmuş olarak işaretle +allowedInstances: Beyaz Listedeki Sunucular +squareAvatars: Kare avatarları göster +unread: Okunmaımş +instanceDefaultDarkTheme: Sunucu genelinde varsayılan karanlık tema +oneDay: Bir gün +showAds: Reklamları göster +adminCustomCssWarn: Bu ayar yalnızca ne işe yaradığını biliyorsanız kullanılmalıdır. + Yanlış değerler girilmesi, HERKESİN istemcilerinin normal şekilde çalışmamasına + neden olabilir. Lütfen CSS'nizi kullanıcı ayarlarınızda test ederek düzgün çalıştığından + emin olun. +customSplashIcons: Özel açılış ekranı simgeleri (url'ler) +recommendedInstancesDescription: Önerilen zaman çizelgesinde görünmesi için satır + sonlarıyla ayrılmış önerilen sunucular. +recommendedInstances: Önerilen sunucular +enableServerMachineStats: Sunucu donanımı istatistiklerini etkinleştir +_sensitiveMediaDetection: + sensitivityDescription: Hassasiyetin düşürülmesi daha az yanlış tespite yol açarken, + hassasiyeti artırmak daha az tespitin gözden kaçmasına yol açacaktır. + setSensitiveFlagAutomaticallyDescription: Bu seçenek kapatılsa bile dahili algılamanın + sonuçları korunacaktır. + description: Makine Öğrenimi yoluyla NSFW ortamını otomatik olarak tanıyarak sunucu + denetleme çabasını azaltır. Bu, sunucudaki yükü biraz artıracaktır. + sensitivity: Algılama hassasiyeti + analyzeVideos: Videoların analizini etkinleştir + setSensitiveFlagAutomatically: NSFW olarak işaretle + analyzeVideosDescription: Görüntülere ek olarak videoları da analiz eder. Bu, sunucudaki + yükü biraz artıracaktır. +enableIdenticonGeneration: Kimlik oluşturmayı etkinleştir +reactionPickerSkinTone: Tercih edilen emoji cilt tonu +noteId: Gönderi ID +preventAiLearning: AI bot öğrenmesini önleyin +preventAiLearningDescription: Gönderiler ve resimler gibi yüklediğiniz içeriği incelememek + için üçüncü taraf yapay zeka dil modellerini isteyin. +isAdmin: Yönetici +_emailUnavailable: + disposable: Tek kullanımlık mail adresleri kullanılamaz + smtp: Bu mail sunucusu cevap vermiyor + mx: Bu mail sunucusu hatalı + used: Bu mail zaten kullanılıyor + format: Bu mail adresi yanlış +apps: Uygulamalar +findOtherInstance: Başka bir sunucu bul +showWithSparkles: Parıltılarla göster +showPopup: Kullanıcıları pop-up ile bilgilendirin +silencedWarning: Bu sayfa, bu kullanıcılar yöneticinizin susturduğu sunuculardan olduğu + için gösteriliyor, bu nedenle potansiyel olarak spam olabilirler. +isPatron: Calckey Patronu +youHaveUnreadAnnouncements: Okunmamış duyurularınız var +donationLink: Bağış sayfası linki +neverShow: Birdaha gösterme +remindMeLater: Belki sonra +removeQuote: Alıntıyı sil +removeRecipient: Alıcıyı sil +removeMember: Kullanıcıyı sil +customKaTeXMacroDescription: 'Kolayca matematiksel ifadeler yazmak için makrolar kurun! + Gösterim, LaTeX komut tanımlarına uygundur ve \newcommand{\ name}{content} veya + \newcommand{\name}[argüman sayısı]{content} şeklinde yazılır. Örneğin, \newcommand{\add}[2]{#1 + + #2}, \add{3}{foo} öğesini 3 + foo olarak genişletir. Makro adını çevreleyen süslü + parantezler, yuvarlak veya köşeli parantezler olarak değiştirilebilir. Bu, bağımsız + değişkenler için kullanılan parantezleri etkiler. Satır başına bir (ve yalnızca + bir) makro tanımlanabilir ve satırı tanımın ortasından ayıramazsınız. Geçersiz satırlar + basitçe yoksayılır. Yalnızca basit dizi değiştirme işlevleri desteklenir; koşullu + dallanma gibi gelişmiş söz dizimi burada kullanılamaz.' +enableCustomKaTeXMacro: Özel KaTeX makrolarını aktif et +isLocked: Bu hesabın takip onayları var +isModerator: Moderatör +signupsDisabled: Bu sunucudaki kayıtlar şu anda devre dışı, ancak istediğiniz zaman + başka bir sunucuya kaydolabilirsiniz! Bu sunucu için bir davet kodunuz varsa, lütfen + aşağıya girin. +sendModMail: Moderasyon Bildirimi Gönder +noGraze: Calckey ile çakıştığı için lütfen "Graze for Mastodon" tarayıcı uzantısını + devre dışı bırakın. +isBot: Bu hesap bir bottur +_2fa: + renewTOTPOk: Yeniden Yapılandır + registerTOTP: Doğrulayıcı uygulamasını kaydedin + renewTOTPCancel: İptal Et + renewTOTPConfirm: Bu, önceki uygulamanızdaki doğrulama kodlarının çalışmamasına + neden olur + alreadyRegistered: Zaten bir 2 faktörlü kimlik doğrulama cihazını kaydettiniz. + chromePasskeyNotSupported: Chrome geçiş anahtarları şu anda desteklenmemektedir. + registerSecurityKey: Bir güvenlik veya geçiş anahtarı kaydedin + securityKeyName: Bir anahtar adı girin + removeKey: Güvenlik anahtarını kaldır + removeKeyConfirm: '{name} anahtarı gerçekten silinsin mi?' + renewTOTP: Kimlik doğrulayıcı uygulamasını yeniden yapılandırın + token: 2FA Tokeni + step1: Öncelikle, cihazınıza bir kimlik doğrulama uygulaması ({a} veya {b} gibi) + yükleyin. + step2Click: Bu QR koduna tıklamak, 2FA'yı güvenlik anahtarınıza veya telefon kimlik + doğrulayıcı uygulamanıza kaydetmenize olanak tanır. + step3Title: Bir kimlik doğrulama kodu girin + securityKeyNotSupported: Tarayıcınız güvenlik anahtarlarını desteklemiyor. + step2: Ardından, bu ekranda görüntülenen QR kodunu tarayın. + step2Url: "Bir masaüstü programı kullanıyorsanız bu URL'yi de girebilirsiniz:" + step3: Kurulumu tamamlamak için uygulamanız tarafından sağlanan tokeni girin. + step4: Şu andan itibaren, gelecekteki herhangi bir oturum açma denemesi böyle bir + oturum açma tokeni isteyecektir. + securityKeyInfo: Parmak izi veya PIN kimlik doğrulamasının yanı sıra, hesabınızın + güvenliğini daha da artırmak için FIDO2'yi destekleyen donanım güvenlik anahtarları + aracılığıyla kimlik doğrulama ayarlayabilirsiniz. + tapSecurityKey: Güvenlik veya geçiş anahtarını kaydetmek için lütfen tarayıcınızı + takip edin + registerTOTPBeforeKey: Bir güvenlik veya geçiş anahtarı kaydetmek için lütfen bir + kimlik doğrulama uygulaması kurun. + whyTOTPOnlyRenew: Kimlik doğrulayıcı uygulaması, bir güvenlik anahtarı kaydedildiği + sürece kaldırılamaz. +_poll: + voted: Oylandı + deadlineTime: Zaman + remainingDays: '{d} gün {h} saat kaldı' + remainingHours: '{h} saat {m} dakika kaldı' + remainingSeconds: '{s} saniye kaldı' + remainingMinutes: '{m} dakika {s} saniye kaldı' + noOnlyOneChoice: En az 2 seçenek gerekiyor + noMore: Daha fazla seçenek ekleyemezsin + at: Bitiş... + deadlineDate: Bitiş tarihi + duration: Süre + votesCount: '{n} oy' + expiration: Anketi bitir + totalVotes: toplam {n} oy + closed: Bitti + infinite: Asla + vote: Oyla + showResult: Sonuçları görüntüle + after: "'den sonra bitiş..." + choiceN: Seçenek {n} + canMultipleVote: Birden fazla seçime izin ver +_theme: + code: Tema kodu + description: Açıklama + builtinThemes: Yerleşik temalar + color: Renk + keys: + fgHighlighted: Vurgulanan Metin + infoWarnFg: Uyarı metni + mention: Bahsetme + mentionMe: Bahsetme (Kendim) + buttonBg: Düğme arka planı + buttonHoverBg: Düğme arka planı (Üstüne Gelince) + shadow: Gölge + navBg: Kenar çubuğu arka planı + accent: Vurgu + fg: Yazı + dateLabelFg: Tarih etiketi metni + navActive: Kenar çubuğu metni (Etkin) + wallpaperOverlay: Arkaplan arayüzü + messageBg: Sohbet arkaplanı + focus: Fokus + accentLighten: Vurgu (Aydınlık) + bg: Arkaplan + indicator: Gösterge + hashtag: Etiket + renote: Yükseltme + modalBg: Modal arka plan + divider: Bölücü + scrollbarHandle: Kaydırma çubuğu kolu + scrollbarHandleHover: Kaydırma çubuğu tutacağı (Üzerine Gelince) + infoBg: Bilgi geçmişi + accentDarken: Vurgu (Karanlık) + header: Başlık + navFg: Kenar çubuğu metni + navIndicator: Kenar çubuğu göstergesi + link: Link + infoFg: Bilgi metni + infoWarnBg: Uyarı arka planı + badge: Rozen + panel: Panel + navHoverFg: Kenar çubuğu metni (Üzerine Gelince) + cwBg: CW düğmesi arka planı + cwFg: CW düğmesi meni + cwHoverBg: CW düğmesi arka planı (Üzerine Gelince) + toastFg: Bildirim metni + inputBorder: Giriş alanı sınırı + listItemHoverBg: Liste öğesi arka planı (Üstüne Gelince) + toastBg: Bildirim arka planı + driveFolderBg: Drive klasörü arkaplanı + funcKind: Fonksiyon tipi + argument: Argüman + lighten: Aydınlat + inputConstantName: Bu sabit için bir ad girin + deleteConstantConfirm: '{const} sabitini gerçekten silmek istiyor musunuz?' + explore: Temaları Keşfet + darken: Karart + base: Temel + manage: Temaları düzenle + installedThemes: Yüklenen temalar + invalid: Bu temanın biçimi geçersiz + make: Tema oluştur + key: Anahtar + alpha: Opaklık + install: Tema yükle + installed: '{name} başarıyla yüklendi' + alreadyInstalled: Bu tema zaten yüklendi + importInfo: Buraya tema kodunu girerseniz, onu tema düzenleyiciye aktarabilirsiniz + func: Fonksiyonlar + basedProp: Referenslanan özellik + constant: Sabit + defaultValue: Varsayılan değer + refConst: Bir sabiti referansla + refProp: Bir mülkü referansla + addConstant: Sabit ekle +_menuDisplay: + sideIcon: Yan (Simgeler) + sideFull: Yan + hide: Gizle + top: Üst +_filters: + fromUser: Kullanıcıdan + withFile: Dosya ile + notesBefore: Gönderiden önce + notesAfter: Gönderiden sonra + followingOnly: Sadece takip ettiklerim + fromDomain: Alan adı ile + followersOnly: Sadece takipçiler +_permissions: + "write:blocks": Engelli kullanıcıları düzenle + "read:drive": Drive dosya ve klasörlerine eriş + "read:favorites": Yer imlerini görüntüle + "write:mutes": Susturulmuş kullanıcıları düzenle + "read:notifications": Bildirimleri görüntüle + "write:notifications": Bildirimleri düzenle + "write:page-likes": Sayfalardaki beğenilerini düzenle + "read:user-groups": Kullanıcı gruplarını göster + "write:reactions": Tepkilerini düzenle + "read:pages": Sayfalarını göster + "write:channels": Kanallarını düzenle + "read:gallery": Galerini göster + "read:gallery-likes": Beğenilen galeri gönderilerini göster + "write:gallery-likes": Galeri gönderilerini düzenle + "write:messaging": Sohbet mesajı oluştur veya sil + "write:user-groups": Kullanıcı gruplarını düzenle veya sil + "read:messaging": Sohbetlerini görüntüle + "read:mutes": Susturulmuş kullanıcıları göster + "write:votes": Bir ankete oy ver + "read:page-likes": Beğenilen sayfalarını göster + "read:reactions": Tepkilerini göster + "read:channels": Kanallarını göster + "write:notes": Gönderi oluştur veya sil + "write:drive": Drive dosya ve klasörlerini düzenle + "write:favorites": Yer imlerini düzenle + "read:following": Kimleri takip ettiğini göster + "write:account": Hesap bilgisini düzenle + "read:account": Hesap bilgisini görüntüle + "read:blocks": Engelli kullanıcıları gör + "write:following": Hesapları takip et veya takipten çıkar + "write:pages": Sayfalarını düzenle veya sil + "write:gallery": Galerini düzenle +_auth: + pleaseGoBack: Lütfen uygulamaya geri dönün + callback: Uygulamaya geri dönülüyor + shareAccess: '"{name}" adlı kişinin bu hesaba erişmesine izin vermek ister misiniz?' + permissionAsk: 'Bu uygulama aşağıdaki izinleri ister:' + allPermissions: Tam hesap erişimi + denied: Erişim reddedildi + copyAsk: 'Lütfen aşağıdaki yetkilendirme kodunu uygulamaya yapıştırın:' + shareAccessAsk: Bu uygulamanın hesabınıza erişmesine izin vermek istediğinizden + emin misiniz? +_antennaSources: + users: Belirli kullanıcılardan gönderiler + homeTimeline: Takip edilen kullanıcılardan gönderiler + all: Tüm gönderiler + instances: Bir sunucudaki tüm kullanıcılardan gelen gönderiler + userList: Belirli bir kullanıcı listesinden gönderiler + userGroup: Belirli bir gruptaki kullanıcıların gönderileri +_charts: + usersIncDec: Kullanıcı sayısı farkı + usersTotal: Toplam kullanıcı sayısı + remoteNotesIncDec: Uzak gönderilerin sayısındaki fark + notesTotal: Toplam gönderi sayısı + filesTotal: Toplam dosya sayısı + apRequest: İstekler + storageUsageIncDec: Depolama kullanımındaki fark + localNotesIncDec: Yerel gönderilerin sayısındaki fark + storageUsageTotal: Toplam depolama kullanımı + federation: Federasyon + notesIncDec: Gönderi sayısındaki fark + activeUsers: Aktif kullanıcılar + filesIncDec: Dosya sayısındaki fark +_pages: + fontSerif: Serif + fontSansSerif: Sans Serif + chooseBlock: Bloğu sil + blocks: + _canvas: + id: Tuval ID + height: Yükseklik + width: Genişlik + _button: + _action: + resetRandom: Rastgele çekirdeği sıfırla + _pushEvent: + no-variable: Hiçbiri + event: Etkinlik ismi + message: Aktif olduğunda gösterilecek mesaj + variable: Gönderilecek değişken + callAiScript: AiScript'i çağırın + _callAiScript: + functionName: Fonksiyon ismi + dialog: Dialog göster + _dialog: + content: İçerik + pushEvent: Etkinlik gönder + text: Başlık + action: Düğmeye basıldığında olacaklar + colored: Renkli + text: Yazı + if: Eğer + _if: + variable: Değişken + canvas: Tuval + note: Gömülü yazı + _note: + id: Gönderi ID + idDescription: Alternatif olarak gönderi URL'sini buraya yapıştırabilirsiniz. + detailed: Detaylı görüntüleme + _counter: + text: Başlık + inc: Adım + name: Değer ismi + radioButton: Seçenek + _radioButton: + name: Değişken ismi + values: Seçenekleri satırlarla ayırın + title: Başlık + default: Varsayılan değer + _post: + text: İçerik + attachCanvasImage: Tuval resmi ekle + canvasId: Tuval ID + _textInput: + text: Başlık + name: Değişken ismi + default: Varsayılan değer + _numberInput: + name: Değiken ismi + text: Başlık + default: Varsayılan değer + _textareaInput: + text: Başlık + name: Değişken ismi + default: Varsayılan değer + textarea: Yazı alanı + _switch: + name: Değişken ismi + default: Varsayılan değer + text: Başlık + counter: Sayaç + switch: Değiştir + post: Gönderi formu + image: Resimler + section: Bölüm + textareaInput: Çok satırlı yazı girişi + button: Düğme + textInput: Yazı girişi + numberInput: Sayısal giriş + script: + categories: + text: Yazı işlemleri + flow: Akış kontrolü + random: Rastgele + fn: Fonksiyonlar + convert: Dönüşümler + list: Listeler + logical: Mantıksal işlem + operation: Hesaplama + comparison: Karşılaştırma + value: Değerler + blocks: + and: A ve B + _or: + arg2: B + arg1: A + _lt: + arg1: A + arg2: B + _ltEq: + arg1: A + arg2: B + textList: Yazı listesi + strReverse: Yazıyı çevir + multiply: Çarp + subtract: Çıkar + _mod: + arg1: A + arg2: B + _divide: + arg2: B + arg1: A + round: Ondalık yuvarlama + _round: + arg1: Sayı + _eq: + arg1: A + arg2: B + notEq: A ve B farklıysa + _notEq: + arg1: A + arg2: B + or: A veya B + gt: "> A, B'den çoksa" + ltEq: <= A, B'den az veya eşitse + gtEq: ">= A, B'den çok veya eşitse" + _gtEq: + arg1: A + arg2: B + _not: + arg1: OLUMSUZ + random: Rastgele + randomPick: Listeden rastgele seç + seedRandom: Random (çekirdek ile) + _for: + arg1: Tekrarlama sayısı + arg2: Eylem + _seedRannum: + arg3: Maksimum değer + arg2: Minimum değer + arg1: Çekirdek + _strReplace: + arg3: ile değiştir + arg2: Değiştirilecek yazı + arg1: Yazı + _subtract: + arg2: B + arg1: A + mod: Kalan + _and: + arg1: A + arg2: B + _DRPWPM: + arg1: Yazı listesi + _fn: + slots-info: Her yuvayı bir satır sonu ile ayırın + arg1: Çıkış + slots: Yuvalar + for: dögü + dailyRandomPick: Listeden rastgele seçim yapın (Her kullanıcı için günde bir + kez değişir) + _dailyRannum: + arg1: Minimum değer + arg2: Maksimum değer + _seedRandomPick: + arg2: Liste + arg1: Çekirdek + _pick: + arg2: Pozisyon + arg1: Liste + number: Sayı + _if: + arg3: Yoksa + arg1: Eğer + arg2: Sonra + _rannum: + arg1: Minimum değer + arg2: Maksimum değer + eq: A ve B eşitse + _gt: + arg1: A + arg2: B + rannum: Rastgele sayı + _randomPick: + arg1: Liste + pick: Listeden seç + _listLen: + arg1: Liste + _multiply: + arg2: B + arg1: A + divide: Böl + strPick: Dize ayıklayın + _strPick: + arg1: Yazı + arg2: Dize konunumu + dailyRandom: Rastgele (Her kullanıcı için günde bir kez değişir) + _dailyRandom: + arg1: Olasılık + dailyRannum: Rastgele sayı (Her kullanıcı için günde bir kez değişir) + _stringToNumber: + arg1: Yazı + if: Şube + strReplace: Yedek dize + text: Yazı + _splitStrByLine: + arg1: Yazı + not: OLUMSUZ + _seedRandom: + arg1: Çekirdek + arg2: Olasılık + seedRandomPick: Listeden rastgele seçim yapın (çekirdek ile) + fn: Fonksiyon + multiLineText: Yazı (çok satırlı) + _textList: + info: Her girişi satırlar ile ayırın + _strReverse: + arg1: Yazı + join: Yazıyı birleştirme + _join: + arg1: Listeler + arg2: Ayraç + add: Ekle + _add: + arg1: A + arg2: B + _strLen: + arg1: Yazu + aiScriptVar: AiScript Değişkeni + ref: Değişken + splitStrByLine: Yazıyı satır sonlarına göre bölme + strLen: Yazı uzunluğu + lt: < A, B'den azsa + _random: + arg1: Olasılık + DRPWPM: Ağırlıklı listeden rastgele seçim yapın (Her kullanıcı için günde bir + kez değişir) + listLen: Listenin uzunluğunu al + numberToString: Sayıdan yazıya + _dailyRandomPick: + arg1: Liste + stringToNumber: Yazıdan Sayıya + seedRannum: Rastgele sayı (çekirdek ile) + _numberToString: + arg1: Sayı + types: + number: Sayı + boolean: Etiket + array: Liste + stringArray: Yazı listesi + string: Yazı + emptySlot: Boş yuva + enviromentVariables: Ortam değikenleri + argVariables: Giriş yuvaları + thereIsEmptySlot: Yuva {slot} boş! + typeError: Yuva {slot}, "{expect}" türündeki değerleri kabul eder, ancak sağlanan + değer "{actual}" türündedir! + pageVariables: Sayfa değişkenleri + readPage: Bu sayfanın kaynağını görüntüle + created: Sayfa başarıyla oluşturuldu + eyeCatchingImageRemove: Afişi sil + selectType: Tip seç + pageSetting: Sayfa ayarları + viewSource: Kaynağı görüntüle + variables: Değişkenler + url: Sayfa URL'si + unlike: Beğeniyi kaldır + my: Sayfalarım + content: Sayfa bloğu + deleted: Sayfa başarıyla silindi + newPage: Yeni sayfa oluştur + editPage: Bu sayfayı düzenle + viewPage: Sayfalarını görüntüle + like: Beğen + nameAlreadyExists: Belirtilen Sayfa URL'si zaten var + invalidNameTitle: Belirtilen Sayfa URL'si geçersiz + invalidNameText: Sayfa başlığının boş olmadığından emin olun + editThisPage: Sayfayı düzenle + featured: Popüler + inspector: Denetçi + contents: İçerik + title: Başlık + liked: Beğenilen Sayfalar + font: Yazı Tipi + alignCenter: İçerikleri ortala + eyeCatchingImageSet: Afiş ayarla + enterVariableName: Değişken ismi ekle + hideTitleWhenPinned: Profile sabitlendiğinde Sayfa başlığını gizle + variableNameIsAlreadyUsed: Bu değişken adı zaten kullanımda + contentBlocks: İçerik + inputBlocks: Giriş + specialBlocks: Özel + updated: Sayfa başarıyla düzenlendi + summary: Sayfa özeti +_notification: + _types: + follow: Yeni takipçiler + mention: Bahsetmeler + app: Bağlı uygulamalardan bildirimler + pollEnded: Biten anket + receiveFollowRequest: Takip istekleri alındı + reaction: Tepkiler + all: Hepsi + followRequestAccepted: Takip istekleri kabul edildi + pollVote: Anket oylamaları + renote: Yükseltmeler + reply: Yanıtlar + groupInvited: Grup davetleri + quote: Alıntılar + pollEnded: Anket sonuçları açıklandı + fileUploaded: Dosya başarıyla yüklendi + youRenoted: '{name} tarafından yükseltildin' + _actions: + followBack: Seni geri takip etti + reply: Yanıtla + renote: Yükseltmeler + youGotMention: '{name} senden bahsetti' + youWereFollowed: seni takip etti + youGotMessagingMessageFromGroup: '{name} grubuna bir sohbet mesajı gönderildi' + renoted: gönderini yükseltti + youGotQuote: '{name} seni alıntıladı' + youGotReply: '{name} seni yanıtladı' + reacted: gönderine tepki ekledi + yourFollowRequestAccepted: Takip isteğin kabul edildi + emptyPushNotificationMessage: Push bildirimleri güncellendi + youWereInvitedToGroup: '{userName} seni gruba davet etti' + voted: anketine oy verdi + youReceivedFollowRequest: Bir takip isteği geldi + youGotPoll: '{name} anketinde oylama yaptı' + youGotMessagingMessageFromUser: '{name} sana bir sohbet mesajı gönderdi' +_experiments: + title: Deneyler + postImportsCaption: Kullanıcıların geçmiş Calckey, Misskey, Mastodon, Akkoma ve + Pleroma hesaplarından gönderilerini içe aktarmalarına izin verir. Kuyruğunuz tıkanırsa + yükleme sırasında yavaşlamalara neden olabilir. + enablePostImports: Gönderi içeri aktarmasını aktif et +_dialog: + charactersExceeded: 'Maksimum karakter aşıldı! Geçerli: {current}/Sınır: {max}' + charactersBelow: 'Yeterli karakter yok! Geçerli: {current}/Sınır: {min}' +_signup: + emailSent: Mail adresinize ({email}) bir onay maili gönderildi. Hesap oluşturmayı + tamamlamak için lütfen verilen bağlantıya tıklayın. + almostThere: Neredeyse vardık + emailAddressInfo: Lütfen mail adresinizi giriniz. Herkese açık gözükmeyecektir. +_ad: + back: Geri + reduceFrequencyOfThisAd: Daha az reklam göster +_accountDelete: + accountDelete: Hesabı sil + mayTakeTime: Hesap silme, kaynak yoğun bir işlem olduğundan, ne kadar içerik oluşturduğunuza + ve ne kadar dosya yüklediğinize bağlı olarak tamamlanması biraz zaman alabilir. + sendEmail: Hesap silme işlemi tamamlandıktan sonra, bu hesapta kayıtlı olan mail + adresine bir mail gönderilecektir. + started: Silme işlemi başlatıldı. + requestAccountDelete: Hesap silme talebinde bulun + inProgress: Silme işlemi şu anda devam ediyor +_forgotPassword: + enterEmail: Kaydolmak için kullandığınız mail adresini girin. Parolanızı sıfırlayabileceğiniz + bir bağlantı daha sonra ona gönderilecektir. + contactAdmin: Bu sunucu, mail adreslerinin kullanılmasını desteklemiyor, bunun yerine + şifrenizi sıfırlamak için lütfen sunucu yöneticisiyle iletişime geçin. + ifNoEmail: Kayıt sırasında bir mail kullanmadıysanız, sunucu yöneticisiyle iletişime + geçin. +_gallery: + my: Galerim + liked: Beğenilen Gönderiler + like: Beğen + unlike: Beğeniyi kaldır +_registry: + key: Anahtar + scope: Kapsam + keys: Anahtarlar + createKey: Anahtar oluştur + domain: Alan adı +_email: + _follow: + title: Yeni bir takipçin var + _receiveFollowRequest: + title: Yeni bir takip isteğin var +_preferencesBackups: + apply: Bu cihaza uygula + invalidFile: Geçersiz dosya formatı + applyConfirm: '"{name}" yedeğini bu cihaza gerçekten uygulamak istiyor musunuz? + Bu cihazın mevcut ayarlarının üzerine yazılacak.' + inputName: Lütfen bu yedekleme için bir ad girin + cannotSave: Kaydedilemedi + saveConfirm: Yedekleme {name} olarak kaydedilsin mi? + renameConfirm: '"{old}" olan bu yedeğin adı "{new}" olarak değiştirilsin mi?' + createdAt: 'Oluşturma tarihi: {date} {time}' + save: Değişiklikleri Kaydet + nameAlreadyExists: '"{name}" adlı bir yedek zaten var. Lütfen farklı bir ad girin.' + deleteConfirm: '{name} yedeği silinsin mi?' + noBackups: Yedekleme yok. "Yeni yedekleme oluştur" seçeneğini kullanarak bu sunucudaki + istemci ayarlarınızı yedekleyebilirsiniz. + list: Oluşturulan yedekler + saveNew: Yeni bir yedek oluştur + loadFile: Dosyadan yükle + updatedAt: 'Güncelleme tarihi: {date} {time}' + cannotLoad: Yüklenemedi +_aboutMisskey: + patronsList: Bağış büyüklüğüne göre değil, kronolojik olarak listelenmiştir. Adınızı + buraya almak için yukarıdaki bağlantıyla bağış yapın! + about: Calckey, 2022'den beri geliştirilmekte olan ThatOneCalculator tarafından + yapılan bir Misskey çatalıdır. + allContributors: Tüm katkıda bulunanlar + patrons: Calckey patronları + morePatrons: Burada listelenmeyen diğer birçok yardımcının desteğini de takdir ediyoruz. + Teşekkür ederim! 🥰 + donate: Calckey'e bağışta bulunun + contributors: Ana katkıda bulunanlar + source: Kaynak Kodu + translation: Calckey'i tercüme et + donateTitle: Calckey'den hoşlanıyor musunuz? + pleaseDonateToCalckey: Lütfen gelişimini desteklemek için Calckey'e bağış yapmayı + düşünün. + pleaseDonateToHost: İşletme maliyetlerini desteklemek için lütfen ev sunucunuz {host}'a + bağış yapmayı da düşünün. + donateHost: '{ev sahibi} için bağış yapın' + sponsors: Calckey sponsorları +_weekday: + saturday: Cumartesi + sunday: Pazar + wednesday: Çarşamba + friday: Cuma + thursday: Perşembe + monday: Pazartesi + tuesday: Salı +_serverDisconnectedBehavior: + reload: Otomatik olarak yenile + quiet: Göze çarpmayan uyarı göster + nothing: Hiçbir şey yapma + dialog: Uyarı mesajını göster +_channel: + removeBanner: Afişi sil + owned: Sahip Olunan + nameOnly: Sadece isim + featured: Popüler + setBanner: Afiş ayarla + usersCount: '{n} Katılımcı' + create: Kanal oluştur + following: Takip + notesCount: '{n} Gönderi' + nameAndDescription: İsim ve açıklama + edit: Kanalı düzenle +_messaging: + groups: Gruplar + dms: Özel +_tutorial: + step5_5: Sosyal {icon} zaman çizelgesi, Ev ve Yerel zaman çizelgelerinin bir kombinasyonudur. + step5_6: Önerilen {icon} zaman çizelgesi, yöneticilerin önerdiği sunuculardan gelen + gönderileri görebileceğiniz yerdir. + step6_1: Peki burası neresi? + title: Calckey nasıl kullanılır + step3_2: "Ev ve sosyal zaman çizelgeleriniz, kimi takip ettiğinize bağlıdır, bu + nedenle başlamak için birkaç hesabı takip etmeyi deneyin.\nTakip etmek için bir + profilin sağ üstündeki artı dairesine tıklayın." + step5_3: Ana Sayfa {icon} zaman çizelgesi, takip ettiğiniz hesaplardan gelen gönderileri + görebileceğiniz yerdir. + step5_4: Yerel {icon} zaman çizelgesi, bu sunucudaki diğer herkesin gönderilerini + görebileceğiniz yerdir. + step6_2: Calckey'e öylece katılmadın. Binlerce sunucudan oluşan birbirine bağlı + bir ağ olan Fediverse'e giden bir portala katıldınız. + step6_4: Şimdi gidin, keşfedin ve eğlenin! + step5_7: Global {icon} zaman çizelgesi, bağlı diğer tüm sunuculardan gelen gönderileri + görebileceğiniz yerdir. + step2_1: Öncelikle lütfen profilinizi doldurunuz. + step2_2: Kim olduğunuz hakkında biraz bilgi vermeniz, başkalarının gönderilerinizi + görmek mi yoksa sizi takip etmek mi istediklerini anlamalarını kolaylaştıracaktır. + step3_1: Şimdi birkaç kullanıcı takip etme zamanı! + step1_1: Hoşgeldin! + step1_2: Hadi seni hazırlayalım. Kısa sürede kullanmaya başlayacaksınız! + step5_1: Zaman çizelgeleri, her yerde zaman çizelgeleri! + step6_3: Her sunucu farklı şekillerde çalışır ve tüm sunucular Calckey'i çalıştırmaz. + Ama bu sunucu kullanıyor! Biraz karışık ama kısa sürede anlayacaksın. + step4_1: Seni oradan çıkaralım. + step5_2: Sunucunuzda etkinleştirilmiş {timelines} farklı zaman çizelgesi var. + step4_2: İlk gönderiniz için, bazı insanlar bir {introduction} gönderisi veya basit + bir "Merhaba dünya!" gönderir +_visibility: + public: Herkese açık + publicDescription: Gönderiniz herkese açık tüm zaman çizelgelerinde görünür olacak + specified: Direkt + followersDescription: Yalnızca takipçilerinize ve adı geçen kullanıcılara görünür + kılın + localOnlyDescription: Uzak kullanıcılara gözükmez + home: Listelenmemiş + homeDescription: Yalnızca ev zaman çizelgesine yayınla + followers: Takipçiler + specifiedDescription: Belirli kullanıcılara özel yapın + localOnly: Sadece yerel +_postForm: + quotePlaceholder: Bu gönderiyi alıntıla... + _placeholders: + a: Ne ile meşgulsün? + b: Etrafında neler oluyor? + f: Yazman bekleniyor... + c: Aklınızdan ne geçiyor? + d: Ne demek istiyorsun? + e: Yazmaya başka... + replyPlaceholder: Bu gönderiyi yanıtla... + channelPlaceholder: Bir kanala gönder... +_exportOrImport: + allNotes: Tüm gönderiler + followingList: Takip edilen kullanıcılar + muteList: Susturulmuş kullanıcılar + excludeMutingUsers: Susturulmuş kullanıcıları hariç tut + excludeInactiveUsers: Aktif olmayan kullanıcıları hariç tut + userLists: Kullanıcı listeleri + blockingList: Engellenimş kullanıcılar +_instanceCharts: + notes: Gönderi sayısındaki fark + notesTotal: Toplu gönderi sayısı + files: Dosya sayısındaki fark + filesTotal: Toplu dosya sayısı + requests: İstekler + usersTotal: Toplu kullanıcı sayısı + users: Kullanıcı sayısı farkı + cacheSize: Önbellek boyutundaki fark + ff: 'Takip edilen / Takipçi sayısındaki fark ' + cacheSizeTotal: Toplam önbellek boyutu + ffTotal: Toplu Takip edilen / Takipçi sayısı +_wordMute: + soft: Yumuşak + muteWords: Susturulmuş kelimeler + muteWordsDescription: AND koşulu için boşluklarla veya OR koşulu için satır sonlarıyla + ayırın. + softDescription: Belirlenen koşulları karşılayan gönderileri zaman çizelgesinden + gizleyin. + hardDescription: Belirlenen koşulları sağlayan gönderilerin zaman çizelgesineeklenmesini + engeller. Ayrıca bu gönderiler, koşullar değişse dahi zaman tüneline eklenmeyecektir. + mutedNotes: Susturulmuş gönderiler + hard: Sert + muteWordsDescription2: Normal ifadeleri kullanmak için anahtar kelimeleri eğik çizgilerle + çevreleyin. +_ago: + weeksAgo: '{n}hafta önce' + minutesAgo: '{n}dakika önce' + daysAgo: '{n}gün önce' + future: Gelecek + justNow: Şimdi + secondsAgo: '{n}saniye önce' + hoursAgo: '{n}saat önce' + monthsAgo: '{n}ay önce' + yearsAgo: '{n}yıl önce' +_timelines: + home: Ev + local: Yerel + social: Sosyal + global: Global + recommended: Tavsiye Edilen +_nsfw: + respect: NSFW medyasını gizle + force: Tüm medyayı gizle + ignore: NSFW medyasını gizleme +_cw: + files: '{count} dosya(lar)' + chars: '{count} harf' + hide: Gizle + show: İçeriği göster +_relayStatus: + rejected: Reddedildi + accepted: Kabul edildi + requesting: Bekleniyor +_time: + day: Gün(ler) + hour: Saat(ler) + second: Saniye(ler) + minute: Dakika(lar) +_skinTones: + light: Aydınlık + medium: Orta + mediumLight: Orta Aydınlık + dark: Karanlık + yellow: Sarı + mediumDark: Orta Karanlık +_plugin: + install: Eklenti indir + installWarn: Lütfen güvenli olmayan eklentiler kurmayınız. + manage: Eklentileri yönet +_instanceTicker: + remote: Uzak kullanıcılar için göster + always: Her zaman göster + none: Asla gösterme +_instanceMute: + heading: Sessize alınacak sunucuların listesi + instanceMuteDescription2: Yeni satırlarla ayırın + title: Listelenen sunuculardan gönderileri gizler. + instanceMuteDescription: Bu, sessize alınmış bir sunucudan bir kullanıcıya yanıt + veren kullanıcılarınkiler de dahil olmak üzere, listelenen sunuculardan gelen + tüm gönderileri/yükseltmeleri sessize alacaktır. +_ffVisibility: + followers: Takipçilere açık + private: Gizli + public: Herkese açık diff --git a/locales/uk-UA.yml b/locales/uk-UA.yml index 712c0fd03..78aaf2bbd 100644 --- a/locales/uk-UA.yml +++ b/locales/uk-UA.yml @@ -1,7 +1,9 @@ ---- _lang_: "Українська" headlineMisskey: "Мережа об'єднана записами" -introMisskey: "Ласкаво просимо! Calckey - децентралізована служба мікроблогів з відкритим кодом.\nСтворюйте \"нотатки\", щоб поділитися тим, що відбувається, і розповісти всім про себе 📡\nЗа допомогою \"реакцій\" ви також можете швидко висловити свої почуття щодо нотаток інших 👍\nДосліджуймо новий світ! 🚀" +introMisskey: "Ласкаво просимо! Calckey - децентралізована служба мікроблогів з відкритим + кодом.\nСтворюйте \"нотатки\", щоб поділитися тим, що відбувається, і розповісти + всім про себе 📡\nЗа допомогою \"реакцій\" ви також можете швидко висловити свої + почуття щодо нотаток інших 👍\nДосліджуймо новий світ! 🚀" monthAndDay: "{month}/{day}" search: "Пошук" notifications: "Сповіщення" @@ -14,16 +16,16 @@ gotIt: "Зрозуміло!" cancel: "Скасувати" enterUsername: "Введіть ім'я користувача" renotedBy: "Поширено {user}" -noNotes: "Немає нотаток" +noNotes: "Немає записів" noNotifications: "Немає сповіщень" -instance: "Інстанс" +instance: "Сервер" settings: "Налаштування" basicSettings: "Основні налаштування" otherSettings: "Інші налаштування" openInWindow: "Відкрити у вікні" profile: "Профіль" timeline: "Стрічка" -noAccountDescription: "Цей користувач ще нічого не написав про себе" +noAccountDescription: "Цей користувач ще нічого не написав про себе." login: "Увійти" loggingIn: "Здійснюємо вхід..." logout: "Вийти" @@ -44,7 +46,8 @@ copyContent: "Скопіювати контент" copyLink: "Скопіювати посилання" delete: "Видалити" deleteAndEdit: "Видалити й редагувати" -deleteAndEditConfirm: "Ви впевнені, що хочете видалити цю нотатку та відредагувати її? Ви втратите всі реакції, поширення та відповіді на неї." +deleteAndEditConfirm: "Ви впевнені, що хочете видалити цей запис та відредагувати + його? Ви втратите всі реакції, поширення та відповіді на нього." addToList: "Додати до списку" sendMessage: "Надіслати повідомлення" copyUsername: "Скопіювати ім’я користувача" @@ -64,9 +67,11 @@ import: "Імпорт" export: "Експорт" files: "Файли" download: "Завантажити" -driveFileDeleteConfirm: "Ви впевнені, що хочете видалити файл {name}? Нотатки із цим файлом також буде видалено." +driveFileDeleteConfirm: "Ви впевнені, що хочете видалити файл {name}? Його буде видалено + з усіх записів які містили його." unfollowConfirm: "Ви впевнені, що хочете відписатися від {name}?" -exportRequested: "Експортування розпочато. Це може зайняти деякий час. Після завершення експорту отриманий файл буде додано на диск." +exportRequested: "Експортування розпочато. Це може зайняти деякий час. Після завершення + експорту отриманий файл буде додано на диск." importRequested: "Імпортування розпочато. Це може зайняти деякий час." lists: "Списки" noLists: "Немає списків" @@ -80,10 +85,12 @@ manageLists: "Управління списками" error: "Помилка" somethingHappened: "Щось пішло не так" retry: "Спробувати знову" -pageLoadError: "Помилка при завантаженні сторінки" -pageLoadErrorDescription: "Зазвичай це пов’язано з помилками мережі або кешем браузера. Очистіть кеш або почекайте трохи й спробуйте ще раз." +pageLoadError: "Помилка при завантаженні сторінки." +pageLoadErrorDescription: "Зазвичай це пов’язано з помилками мережі або кешем браузера. + Очистіть кеш або почекайте трохи й спробуйте ще раз." serverIsDead: "Відповіді від сервера немає. Зачекайте деякий час і повторіть спробу." -youShouldUpgradeClient: "Перезавантажте та використовуйте нову версію клієнта, щоб переглянути цю сторінку." +youShouldUpgradeClient: "Перезавантажте та використовуйте нову версію клієнта, щоб + переглянути цю сторінку." enterListName: "Введіть назву списку" privacy: "Конфіденційність" makeFollowManuallyApprove: "Підтверджувати підписників уручну" @@ -95,10 +102,10 @@ unfollow: "Відписатись" followRequestPending: "Очікуючі запити на підписку" enterEmoji: "Введіть емодзі" renote: "Поширити" -unrenote: "Відміна поширення" -renoted: "Поширити запис." -cantRenote: "Неможливо поширити." -cantReRenote: "Поширення не можливо поширити." +unrenote: "скасувати поширення" +renoted: "Поширено." +cantRenote: "Цей запис неможливо поширити." +cantReRenote: "Поширення неможливо поширити." quote: "Цитата" pinnedNote: "Закріплений запис" pinned: "Закріпити" @@ -108,7 +115,8 @@ sensitive: "NSFW" add: "Додати" reaction: "Реакції" reactionSetting: "Налаштування реакцій" -reactionSettingDescription2: "Перемістити щоб змінити порядок, Клацнути мишою щоб видалити, Натиснути \"+\" щоб додати." +reactionSettingDescription2: "Перемістити щоб змінити порядок, Клацнути мишою щоб + видалити, Натиснути \"+\" щоб додати." rememberNoteVisibility: "Пам’ятати параметри видимісті" attachCancel: "Видалити вкладення" markAsSensitive: "Позначити як NSFW" @@ -137,14 +145,21 @@ emojiUrl: "URL емодзі" addEmoji: "Додати емодзі" settingGuide: "Рекомендована конфігурація" cacheRemoteFiles: "Кешувати дані з інших інстансів" -cacheRemoteFilesDescription: "Якщо кешування вимкнено, віддалені файли завантажуються безпосередньо з віддаленого інстансу. Це зменшує використання сховища, але збільшує трафік, оскільки не генеруются ескізи." +cacheRemoteFilesDescription: "Якщо кешування вимкнено, віддалені файли завантажуються + безпосередньо з віддаленого серверу. Це зменшує використання сховища, але збільшує + трафік, оскільки не генеруются ескізи." flagAsBot: "Акаунт бота" -flagAsBotDescription: "Ввімкніть якщо цей обліковий запис використовується ботом. Ця опція позначить обліковий запис як бота. Це потрібно щоб виключити безкінечну інтеракцію між ботами а також відповідного підлаштування Calckey." +flagAsBotDescription: "Ввімкніть якщо цей обліковий запис використовується ботом. + Ця опція позначить обліковий запис як бота. Це потрібно щоб виключити безкінечну + інтеракцію між ботами а також відповідного підлаштування Calckey." flagAsCat: "Акаунт кота" -flagAsCatDescription: "Ввімкніть, щоб позначити, що обліковий запис є котиком." +flagAsCatDescription: "Ввімкніть, щоб позначити, що обліковий запис є котиком, та + отримати котячі вуха!" flagShowTimelineReplies: "Показувати відповіді на нотатки на часовій шкалі" -flagShowTimelineRepliesDescription: "Показує відповіді користувачів на нотатки інших користувачів на часовій шкалі." -autoAcceptFollowed: "Автоматично приймати запити на підписку від користувачів, на яких ви підписані" +flagShowTimelineRepliesDescription: "Показує відповіді користувачів на записи інших + користувачів у стрічці." +autoAcceptFollowed: "Автоматично приймати запити на підписку від користувачів, на + яких ви підписані" addAccount: "Додати акаунт" loginFailed: "Не вдалося увійти" showOnRemote: "Переглянути в оригіналі" @@ -155,14 +170,18 @@ removeWallpaper: "Прибрати шпалери" searchWith: "Пошук: {q}" youHaveNoLists: "У вас немає списків" followConfirm: "Підписатися на {name}?" -proxyAccount: "Проксі-акаунт" -proxyAccountDescription: "Обліковий запис проксі – це обліковий запис, який діє як віддалений підписник для користувачів за певних умов. Наприклад, коли користувач додає віддаленого користувача до списку, активність віддаленого користувача не буде доставлена на сервер, якщо жоден локальний користувач не стежить за цим користувачем, то замість нього буде використовуватися обліковий запис проксі-сервера." +proxyAccount: "Обліковий запис проксі" +proxyAccountDescription: "Обліковий запис проксі – це обліковий запис, який діє як + віддалений підписник для користувачів за певних умов. Наприклад, коли користувач + додає віддаленого користувача до списку, активність віддаленого користувача не буде + доставлена на сервер, якщо жоден локальний користувач не стежить за цим користувачем, + то замість нього буде використовуватися обліковий запис проксі-сервера." host: "Хост" selectUser: "Виберіть користувача" recipient: "Отримувач" annotation: "Коментарі" federation: "Федіверс" -instances: "Інстанс" +instances: "Сервери" registeredAt: "Приєднався(лась)" latestRequestSentAt: "Останній запит надіслано" latestRequestReceivedAt: "Останній запит прийнято" @@ -172,7 +191,7 @@ charts: "Графіки" perHour: "Щогодинно" perDay: "Щоденно" stopActivityDelivery: "Припинити розсилання активності" -blockThisInstance: "Заблокувати цей інстанс" +blockThisInstance: "Заблокувати цей сервер" operations: "Операції" software: "Програмне забезпечення" version: "Версія" @@ -182,22 +201,24 @@ jobQueue: "Черга завдань" cpuAndMemory: "ЦП та пам'ять" network: "Мережа" disk: "Диск" -instanceInfo: "Про цей інстанс" +instanceInfo: "Про цей сервер" statistics: "Статистика" clearQueue: "Очистити чергу" clearQueueConfirmTitle: "Ви впевнені, що хочете очистити чергу?" -clearQueueConfirmText: "Будь-які невідправлені нотатки, що залишилися в черзі, не будуть передані. Зазвичай ця операція НЕ потрібна." +clearQueueConfirmText: "Будь-які невідправлені записи, що залишилися в черзі, не будуть + передані. Зазвичай ця операція НЕ потрібна." clearCachedFiles: "Очистити кеш" clearCachedFilesConfirm: "Ви впевнені, що хочете видалити всі кешовані файли?" -blockedInstances: "Заблоковані інстанси" -blockedInstancesDescription: "Вкажіть інстанси, які потрібно заблокувати. Перелічені інстанси більше не зможуть спілкуватися з цим інстансом." +blockedInstances: "Заблоковані сервери" +blockedInstancesDescription: "Вкажіть сервери, які потрібно заблокувати. Перелічені + сервери більше не зможуть спілкуватися з цим сервером." muteAndBlock: "Заглушення і блокування" mutedUsers: "Заглушені користувачі" blockedUsers: "Заблоковані користувачі" noUsers: "Немає користувачів" editProfile: "Редагувати обліковий запис" noteDeleteConfirm: "Ви дійсно хочете видалити цей запис?" -pinLimitExceeded: "Більше записів не можна закріпити" +pinLimitExceeded: "Ви не можете закріпити більше записів" intro: "Встановлення Calckey завершено! Будь ласка, створіть обліковий запис адміністратора." done: "Готово" processing: "Обробка" @@ -212,9 +233,9 @@ all: "Всі" subscribing: "Підписка" publishing: "Публікація" notResponding: "Не відповідає" -instanceFollowing: "Підписка на інстанс" -instanceFollowers: "Підписники інстансу" -instanceUsers: "Користувачі цього інстансу" +instanceFollowing: "Підписка на сервер" +instanceFollowers: "Підписники серверу" +instanceUsers: "Користувачі цього серверу" changePassword: "Змінити пароль" security: "Безпека" retypedNotMatch: "Введені дані не збігаються." @@ -238,7 +259,8 @@ saved: "Збережено" messaging: "Чати" upload: "Завантажити" keepOriginalUploading: "Зберегти оригінальне зображення" -keepOriginalUploadingDescription: "Зберігає початково завантажене зображення як є. Якщо вимкнено, версія для відображення в Інтернеті буде створена під час завантаження." +keepOriginalUploadingDescription: "Зберігає початково завантажене зображення як є. + Якщо вимкнено, версія для відображення в Інтернеті буде створена під час завантаження." fromDrive: "З диска" fromUrl: "З посилання" uploadFromUrl: "Завантажити з посилання" @@ -288,7 +310,7 @@ inputNewFileName: "Введіть ім'я нового файлу" inputNewDescription: "Введіть новий заголовок" inputNewFolderName: "Введіть ім'я нової теки" circularReferenceFolder: "Ви намагаєтесь перемістити папку в її підпапку." -hasChildFilesOrFolders: "Ця тека не порожня і не може бути видалена" +hasChildFilesOrFolders: "Ця тека не порожня і не може бути видалена." copyUrl: "Копіювати URL" rename: "Перейменувати" avatar: "Аватар" @@ -304,8 +326,8 @@ unwatch: "Не стежити" accept: "Прийняти" reject: "Відхилити" normal: "Нормальний" -instanceName: "Назва інстансу" -instanceDescription: "Описання інстансу" +instanceName: "Назва серверу" +instanceDescription: "Опис серверу" maintainerName: "Ім'я адміністратора" maintainerEmail: "Email адміністратора" tosUrl: "URL умов використання" @@ -316,12 +338,13 @@ dayX: "{day}" monthX: "{month}" yearX: "{year}" pages: "Сторінки" -integration: "Інтеграція" +integration: "Інтеграції" connectService: "Під’єднати" disconnectService: "Відключитися" enableLocalTimeline: "Увімкнути локальну стрічку" enableGlobalTimeline: "Увімкнути глобальну стрічку" -disablingTimelinesInfo: "Адміністратори та модератори завжди мають доступ до всіх стрічок, навіть якщо вони вимкнуті." +disablingTimelinesInfo: "Адміністратори та модератори завжди мають доступ до всіх + стрічок, навіть якщо вони вимкнуті." registration: "Реєстрація" enableRegistration: "Дозволити реєстрацію" invite: "Запросити" @@ -333,11 +356,13 @@ bannerUrl: "URL банера" backgroundImageUrl: "URL-адреса фонового зображення" basicInfo: "Основна інформація" pinnedUsers: "Закріплені користувачі" -pinnedUsersDescription: "Впишіть в список користувачів, яких хочете закріпити на сторінці \"Знайти\", ім'я в стовпчик." +pinnedUsersDescription: "Впишіть в список користувачів, яких хочете закріпити на сторінці + \"Знайти\", ім'я в стовпчик." pinnedPages: "Закріплені сторінки" -pinnedPagesDescription: "Введіть шляхи сторінок, які ви бажаєте закріпити на головній сторінці цього інстанса, розділені новими рядками." -pinnedClipId: "Ідентифікатор закріпленої замітки." -pinnedNotes: "Закріплена нотатка" +pinnedPagesDescription: "Введіть шляхи сторінок, які ви бажаєте закріпити на головній + сторінці цього сервера, розділені новими рядками." +pinnedClipId: "Ідентифікатор закріпленої замітки" +pinnedNotes: "Закріплений запис" hcaptcha: "hCaptcha" enableHcaptcha: "Увімкнути hCaptcha" hcaptchaSiteKey: "Ключ сайту" @@ -346,22 +371,25 @@ recaptcha: "reCAPTCHA" enableRecaptcha: "Увімкнути reCAPTCHA" recaptchaSiteKey: "Ключ сайту" recaptchaSecretKey: "Секретний ключ" -avoidMultiCaptchaConfirm: "Використання кількох систем Captcha може спричинити перешкоди між ними. Бажаєте вимкнути інші активні системи Captcha? Якщо ви хочете, щоб вони залишалися ввімкненими, натисніть «Скасувати»." +avoidMultiCaptchaConfirm: "Використання кількох систем Captcha може спричинити перешкоди + між ними. Бажаєте вимкнути інші активні системи Captcha? Якщо ви хочете, щоб вони + залишалися ввімкненими, натисніть «Скасувати»." antennas: "Антени" manageAntennas: "Налаштування антен" name: "Ім'я" antennaSource: "Джерело антени" antennaKeywords: "Ключові слова антени" antennaExcludeKeywords: "Винятки" -antennaKeywordsDescription: "Розділення ключових слів пробілами для \"І\" або з нової лінійки для \"АБО\"" -notifyAntenna: "Сповіщати про нові нотатки" -withFileAntenna: "Тільки нотатки з вкладеними файлами" +antennaKeywordsDescription: "Відокремте пробілами для умови \"І\" або перенесенням + до нового рядка для умови \"АБО\"." +notifyAntenna: "Сповіщати про нові записи" +withFileAntenna: "Тільки записи з вкладеними файлами" enableServiceworker: "Ввімкнути ServiceWorker" antennaUsersDescription: "Список імя користувачів в стопчик" caseSensitive: "З урахуванням регістру" withReplies: "Включаючи відповіді" connectedTo: "Наступні акаунти під'єднані" -notesAndReplies: "Нотатки та відповіді" +notesAndReplies: "Записи та відповіді" withFiles: "Файли" silence: "Заглушити" silenceConfirm: "Ви впевнені, що хочете заглушити цього користувача?" @@ -397,7 +425,7 @@ notFoundDescription: "Сторінка за вказаною адресою не uploadFolder: "Місце для завантаження за замовчуванням" cacheClear: "Очистити кеш" markAsReadAllNotifications: "Позначити всі сповіщення як прочитані" -markAsReadAllUnreadNotes: "Позначити всі нотатки як прочитані" +markAsReadAllUnreadNotes: "Позначити всі записи як прочитані" markAsReadAllTalkMessages: "Позначити всі повідомлення як прочитані" help: "Допомога" inputMessageHere: "Введіть повідомлення тут" @@ -418,7 +446,7 @@ text: "Текст" enable: "Увімкнути" next: "Далі" retype: "Введіть ще раз" -noteOf: "Нотатка {user}" +noteOf: "Запис {user}" inviteToGroup: "Запрошення до групи" quoteAttached: "Цитата" quoteQuestion: "Ви хочете додати цитату?" @@ -431,7 +459,8 @@ invitationCode: "Код запрошення" checking: "Перевірка…" available: "Доступно" unavailable: "Недоступно" -usernameInvalidFormat: "літери, цифри та _ є прийнятними" +usernameInvalidFormat: "Ви можете використовувати великі та малі літери, цифри та + підкреслення." tooShort: "Занадто короткий" tooLong: "Занадто довгий" weakPassword: "Слабкий пароль" @@ -454,7 +483,7 @@ joinOrCreateGroup: "Отримуйте запрошення до груп або noHistory: "Історія порожня" signinHistory: "Історія входів" disableAnimatedMfm: "Відключити анімації MFM" -doing: "Виконується" +doing: "Виконується..." category: "Категорія" tags: "Теги" docSource: "Джерело цього документа" @@ -476,29 +505,36 @@ accountSettings: "Налаштування акаунта" promotion: "Виділене" promote: "Виділити" numberOfDays: "Кількість днів" -hideThisNote: "Сховати цю нотатку" -showFeaturedNotesInTimeline: "Показувати популярні нотатки у стрічці" -objectStorage: "Object Storage" +hideThisNote: "Сховати цей запис" +showFeaturedNotesInTimeline: "Показувати популярні записи у стрічці" +objectStorage: "Сховище" useObjectStorage: "Використовувати object storage" -objectStorageBaseUrl: "Base URL" -objectStorageBaseUrlDesc: "Це початкова частина адреси, що використовується CDN або проксі, наприклад для S3: https://.s3.amazonaws.com, або GCS: 'https://storage.googleapis.com/'" -objectStorageBucket: "Bucket" +objectStorageBaseUrl: "Базовий URL" +objectStorageBaseUrlDesc: "URL-адреса, що використовується як джерело. Вкажіть URL-адресу + вашого CDN або проксі-сервера, якщо ви їх використовуєте.\nДля S3 використовуйте + 'https://.s3.amazonaws.com', а для GCS або подібних сервісів - 'https://storage.googleapis.com/', + тощо." +objectStorageBucket: "Сховище (Bucket)" objectStorageBucketDesc: "Будь ласка вкажіть назву відра в налаштованому сервісі." objectStoragePrefix: "Prefix" objectStoragePrefixDesc: "Файли будуть зберігатись у розташуванні з цим префіксом." -objectStorageEndpoint: "Endpoint" -objectStorageEndpointDesc: "Залиште пустим при використанні AWS S3. Інакше введіть кінцевий пункт як '' або ':' слідуючи інструкціям сервісу, який використовується." +objectStorageEndpoint: "Кінцевий пункт" +objectStorageEndpointDesc: "Залиште пустим при використанні AWS S3. Інакше введіть + кінцевий пункт як '' або ':' слідуючи інструкціям сервісу, який + використовується." objectStorageRegion: "Region" -objectStorageRegionDesc: "Введіть регіон у формі 'xx-east-1'. Залиште пустим, якщо ваш сервіс не різниться відповідно до регіонів, або введіть 'us-east-1'." +objectStorageRegionDesc: "Введіть регіон у формі 'xx-east-1'. Залиште пустим, якщо + ваш сервіс не різниться відповідно до регіонів, або введіть 'us-east-1'." objectStorageUseSSL: "Використовувати SSL" objectStorageUseSSLDesc: "Вимкніть коли не використовується HTTPS для з'єднання API" objectStorageUseProxy: "Використовувати Proxy" -objectStorageUseProxyDesc: "Вимкніть коли проксі не використовується для з'єднання ObjectStorage" +objectStorageUseProxyDesc: "Вимкніть коли проксі не використовується для з'єднання + ObjectStorage" objectStorageSetPublicRead: "Встановіть 'публічне читання' при завантаженні" serverLogs: "Журнал сервера" deleteAll: "Видалити все" -showFixedPostForm: "Показати форму запису над стрічкою новин." -newNoteRecived: "Є нові нотатки" +showFixedPostForm: "Показати форму запису над стрічкою новин" +newNoteRecived: "Є нові записи" sounds: "Звуки" listen: "Слухати" none: "Відсутній" @@ -521,7 +557,8 @@ sort: "Сортування" ascendingOrder: "За зростанням" descendingOrder: "За спаданням" scratchpad: "Чернетка" -scratchpadDescription: "Scratchpad надає середовище для експериментів з AiScript. Ви можете писати, виконувати його і тестувати взаємодію з Calckey." +scratchpadDescription: "Scratchpad надає середовище для експериментів з AiScript. + Ви можете писати, виконувати його і тестувати взаємодію з Calckey." output: "Вихід" script: "Скрипт" disablePagesScript: "Вимкнути AiScript на Сторінках" @@ -529,11 +566,14 @@ updateRemoteUser: "Оновити інформацію про віддалено deleteAllFiles: "Видалити всі файли" deleteAllFilesConfirm: "Ви дійсно хочете видалити всі файли?" removeAllFollowing: "Скасувати всі підписки" -removeAllFollowingDescription: "Скасувати підписку на всі акаунти з {host}. Будь ласка, робіть це, якщо інстанс більше не існує." +removeAllFollowingDescription: "Скасувати підписку на всі акаунти з {host}. Будь ласка, + робіть це, якщо сервер більше не існує." userSuspended: "Обліковий запис заблокований." userSilenced: "Обліковий запис приглушений." yourAccountSuspendedTitle: "Цей обліковий запис заблоковано" -yourAccountSuspendedDescription: "Цей обліковий запис було заблоковано через порушення умов надання послуг сервера. Зв'яжіться з адміністратором, якщо ви хочете дізнатися докладнішу причину. Будь ласка, не створюйте новий обліковий запис." +yourAccountSuspendedDescription: "Цей обліковий запис було заблоковано через порушення + умов надання послуг сервера. Зв'яжіться з адміністратором, якщо ви хочете дізнатися + докладнішу причину. Будь ласка, не створюйте новий обліковий запис." menu: "Меню" divider: "Розділювач" addItem: "Додати елемент" @@ -542,8 +582,8 @@ addRelay: "Додати ретранслятор" inboxUrl: "Inbox URL" addedRelays: "Додані ретранслятори" serviceworkerInfo: "Повинен бути ввімкнений для push-сповіщень." -deletedNote: "Видалена нотатка" -invisibleNote: "Приховані записи" +deletedNote: "Видалений запис" +invisibleNote: "Прихований запис" enableInfiniteScroll: "Увімкнути нескінченну прокрутку" visibility: "Видимість" poll: "Опитування" @@ -573,12 +613,14 @@ permission: "Права" enableAll: "Увімкнути все" disableAll: "Вимкнути все" tokenRequested: "Надати доступ до акаунту" -pluginTokenRequestedDescription: "Цей плагін зможе використовувати дозволи які тут вказані." +pluginTokenRequestedDescription: "Цей плагін зможе використовувати дозволи які тут + вказані." notificationType: "Тип сповіщення" edit: "Редагувати" emailServer: "Сервер електронної пошти" enableEmail: "Увімкнути функцію доставки пошти" -emailConfigInfo: "Використовується для підтвердження електронної пошти підчас реєстрації, а також для відновлення паролю." +emailConfigInfo: "Використовується для підтвердження електронної пошти під час реєстрації, + а також для відновлення паролю" email: "E-mail" emailAddress: "E-mail адреса" smtpConfig: "Налаштування сервера SMTP" @@ -586,14 +628,16 @@ smtpHost: "Хост" smtpPort: "Порт" smtpUser: "Ім'я користувача" smtpPass: "Пароль" -emptyToDisableSmtpAuth: "Залиште назву користувача і пароль пустими для вимкнення підтвердження SMTP" +emptyToDisableSmtpAuth: "Залиште назву користувача і пароль пустими для вимкнення + підтвердження SMTP" smtpSecure: "Використовувати безумовне шифрування SSL/TLS для з'єднань SMTP" -smtpSecureInfo: "Вимкніть при використанні STARTTLS " +smtpSecureInfo: "Вимкніть при використанні STARTTLS" testEmail: "Тестовий email" wordMute: "Блокування слів" regexpError: "Помилка регулярного виразу" -regexpErrorDescription: "Сталася помилка в регулярному виразі в рядку {line} вашого слова {tab} слова що ігноруються:" -instanceMute: "Приглушення інстансів" +regexpErrorDescription: "Сталася помилка в регулярному виразі в рядку {line} вашого + слова {tab} слова що ігноруються:" +instanceMute: "Приглушення серверів" userSaysSomething: "{name} щось сказав(ла)" makeActive: "Активувати" display: "Відображення" @@ -606,12 +650,15 @@ database: "База даних" channel: "Канали" create: "Створити" notificationSetting: "Параметри сповіщень" -notificationSettingDesc: "Виберіть типи сповіщень для відображення" +notificationSettingDesc: "Оберіть типи сповіщень для відображення." useGlobalSetting: "Застосувати глобальнi параметри" -useGlobalSettingDesc: "Якщо увімкнено, то будуть використовуватись налаштування повідомлень облікового запису, інакше можливо налаштувати індивідуально." +useGlobalSettingDesc: "Якщо увімкнено, то будуть використовуватись налаштування повідомлень + облікового запису, інакше можливо налаштувати індивідуально." other: "Інше" regenerateLoginToken: "Оновити Login Token" -regenerateLoginTokenDescription: "Регенерувати внутрішній ключ використовуваний під час входу. Зазвичай цього не потрібно робити. При регенерації всі пристрої вийдуть з системи." +regenerateLoginTokenDescription: "Регенерувати внутрішній ключ використовуваний під + час входу. Зазвичай цього не потрібно робити. При регенерації всі пристрої вийдуть + з системи." setMultipleBySeparatingWithSpace: "Можна вказати кілька значень, відділивши їх пробілом." fileIdOrUrl: "Ідентифікатор файлу або посилання" behavior: "Поведінка" @@ -619,34 +666,38 @@ sample: "Приклад" abuseReports: "Скарги" reportAbuse: "Поскаржитись" reportAbuseOf: "Поскаржитись на {name}" -fillAbuseReportDescription: "Будь ласка вкажіть подробиці скарги. Якщо скарга стосується запису, вкажіть посилання на нього." -abuseReported: "Дякуємо, вашу скаргу було відправлено. " +fillAbuseReportDescription: "Будь ласка вкажіть подробиці скарги. Якщо скарга стосується + запису, вкажіть посилання на нього." +abuseReported: "Дякуємо. Ваш звіт було відправлено." reporter: "Репортер" reporteeOrigin: "Про кого повідомлено" reporterOrigin: "Хто повідомив" -forwardReport: "Переслати звіт на віддалений інстанс" -forwardReportIsAnonymous: "Замість вашого облікового запису анонімний системний обліковий запис буде відображатися як доповідач на віддаленому інстансі" +forwardReport: "Переслати звіт на віддалений сервер" +forwardReportIsAnonymous: "Замість вашого облікового запису, анонімний системний обліковий + запис буде відображатися як доповідач на віддаленому сервері." send: "Відправити" abuseMarkAsResolved: "Позначити скаргу як вирішену" openInNewTab: "Відкрити в новій вкладці" openInSideView: "Відкрити збоку" defaultNavigationBehaviour: "Поведінка навігації за замовчуванням" -editTheseSettingsMayBreakAccount: "Зміна цих параметрів може призвести до пошкодження вашого акаунта." -instanceTicker: "Мітка з назвою інстанса в нотатках" +editTheseSettingsMayBreakAccount: "Зміна цих параметрів може призвести до пошкодження + вашого акаунта." +instanceTicker: "Інформація про записи на сервері" waitingFor: "Чекаємо на {x}" random: "Випадковий" system: "Система" switchUi: "Інтерфейс" desktop: "Десктоп" -clip: "Добірка" +clip: "Підбірка" createNew: "Створити новий" optional: "Необов'язково" -createNewClip: "Створити нотатку" +createNewClip: "Створити підбірку" public: "Публічний" -i18nInfo: "Calckey перекладається на різні мови волонтерами. Ви можете допомогти: {link}" +i18nInfo: "Calckey перекладається на різні мови волонтерами. Ви можете допомогти за + посиланням: {link}." manageAccessTokens: "Керування токенами доступу" accountInfo: "Інформація про акаунт" -notesCount: "Кількість нотаток" +notesCount: "Кількість записів" repliesCount: "Кількість надісланих відповідей" renotesCount: "Кількість поширень" repliedCount: "Кількість отриманих відповідей" @@ -662,15 +713,19 @@ no: "Ні" driveFilesCount: "Кількість файлів на диску" driveUsage: "Використання місця на диску" noCrawle: "Заборонити індексацію" -noCrawleDescription: "Просити пошукові системи не індексувати ваш профіль, нотатки, сторінки тощо." -lockedAccountInfo: "Якщо видимість вашого запису не встановлена як \"Тільки підписники\", то кожен зможе побачити ваш запис, навіть якщо ви вимагаєте підтвердження підписок вручну." -alwaysMarkSensitive: "Позначати NSFW за замовчуванням" +noCrawleDescription: "Просити пошукові системи не індексувати ваш профіль, записи, + сторінки тощо." +lockedAccountInfo: "Якщо видимість вашого запису не встановлена як \"Тільки підписники\"\ + , то кожен зможе побачити ваш запис, навіть якщо ви вимагаєте підтвердження підписок + вручну." +alwaysMarkSensitive: "Позначати як NSFW за замовчуванням" loadRawImages: "Відображати вкладені зображення повністю замість ескізів" disableShowingAnimatedImages: "Не програвати анімовані зображення" -verificationEmailSent: "Електронний лист з підтвердженням відісланий. Будь ласка перейдіть по посиланню в листі для підтвердження." +verificationEmailSent: "Електронний лист з підтвердженням відісланий. Будь ласка перейдіть + по посиланню в листі для підтвердження." notSet: "Не налаштовано" -emailVerified: "Електронну пошту підтверджено." -noteFavoritesCount: "Кількість улюблених нотаток" +emailVerified: "Електронну пошту підтверджено" +noteFavoritesCount: "Кількість улюблених записів" pageLikesCount: "Кількість отриманих вподобань сторінки" pageLikedCount: "Кількість вподобаних сторінок" contact: "Контакт" @@ -679,7 +734,8 @@ clips: "Добірка" experimentalFeatures: "Експериментальні функції" developer: "Розробник" makeExplorable: "Зробіть обліковий запис видимим у розділі \"Огляд\"" -makeExplorableDescription: "Вимкніть, щоб обліковий запис не показувався у розділі \"Огляд\"." +makeExplorableDescription: "Вимкніть, щоб обліковий запис не показувався у розділі + \"Огляд\"." showGapBetweenNotesInTimeline: "Показувати розрив між записами у стрічці новин" duplicate: "Дублікат" left: "Лівий" @@ -694,7 +750,10 @@ onlineUsersCount: "{n} користувачів онлайн" nUsers: "{n} Користувачів" nNotes: "{n} Записів" sendErrorReports: "Надіслати звіт про помилки" -sendErrorReportsDescription: "При увімкненні детальна інформація про помилки буде надана Calckey у разі виникнення проблем, що дасть можливість покращити Calckey." +sendErrorReportsDescription: "Якщо увімкнено, детальна інформація про помилки буде + передаватися до Calckey, коли виникає проблема, це допоможе покращити якість роботи + Calckey.\nЦе буде включати інформацію таку як: версія вашої ОС, який браузер ви + використовуєте, ваша активність в Calckey тощо." myTheme: "Моя тема" backgroundColor: "Фон" accentColor: "Акцент" @@ -718,7 +777,7 @@ capacity: "Ємність" inUse: "Зайнято" editCode: "Редагувати вихідний текст" apply: "Застосувати" -receiveAnnouncementFromInstance: "Отримувати оповіщення з інстансу" +receiveAnnouncementFromInstance: "Отримувати сповіщення з серверу" emailNotification: "Сповіщення електронною поштою" publish: "Опублікувати" inChannelSearch: "Пошук за каналом" @@ -726,88 +785,110 @@ useReactionPickerForContextMenu: "Відкривати палітру реакц typingUsers: "Стук клавіш. Це {users}…" goBack: "Назад" info: "Інформація" -user: "Користувачі" +user: "Користувач" administration: "Управління" expiration: "Опитування закінчується" middle: "Середній" global: "Глобальна" -sent: "Відправити" +sent: "Відправлене" hashtags: "Хештеґ" hide: "Сховати" searchByGoogle: "Пошук" indefinitely: "Ніколи" file: "Файли" -reverse: "Перевернути" +reverse: "Переворот" colored: "Кольоровий" label: "Назва" localOnly: "Локально" _ffVisibility: public: "Опублікувати" + private: Приватні + followers: Доступно тільки для підписників _ad: back: "Назад" + reduceFrequencyOfThisAd: Менше показувати цю рекламу _gallery: unlike: "Не вподобати" + liked: Вподобані записи + like: Подобається + my: Моя галерея _email: _follow: title: "Новий підписник" + _receiveFollowRequest: + title: Ви отримали запит на підписку _registry: key: "Ключ" keys: "Ключі" domain: "Домен" createKey: "Створити ключ" + scope: Область _aboutMisskey: - about: "Misskey - це програмне забезпечення з відкритим кодом, яке розробляє syuilo з 2014 року." + about: "Misskey - це програмне забезпечення з відкритим кодом, яке розробляє syuilo + з 2014 року." contributors: "Головні помічники" allContributors: "Всі помічники" source: "Вихідний код" translation: "Перекладати Calckey" donate: "Пожертвувати Calckey" - morePatrons: "Ми дуже цінуємо підтримку багатьох інших помічників, не перелічених тут. Дякуємо! 🥰" + morePatrons: "Ми дуже цінуємо підтримку багатьох інших помічників, не перелічених + тут. Дякуємо! 🥰" patrons: "Підтримали" + patronsList: Перераховані в хронологічному порядку, а не за розміром пожертви. Зробіть + внесок за посиланням вище, щоб ваше ім'я було тут! + donateTitle: Сподобався Calckey? + pleaseDonateToCalckey: Будь ласка, підтримайте розробку Calckey. + pleaseDonateToHost: Також не забудьте підтримати ваш домашній сервер {host}, щоб + допомогти з його операційними витратами. + donateHost: Зробити внесок на рахунок {host} + sponsors: Спонсори Calckey _nsfw: respect: "Приховувати NSFW медіа" ignore: "Не приховувати NSFW медіа" force: "Приховувати всі медіа файли" _mfm: - cheatSheet: " Довідка MFM" - intro: "MFM це ексклюзивна мова розмітки тексту в Calckey, яку можна використовувати в багатьох місцях. Тут ви можете переглянути приклади її синтаксису." + cheatSheet: "Довідка MFM" + intro: "MFM це ексклюзивна мова розмітки тексту в Calckey, яку можна використовувати + в багатьох місцях. Тут ви можете переглянути приклади її синтаксису." dummy: "Calckey розширює світ Федіверсу" mention: "Згадка" - mentionDescription: "За допомогою знака \"@\" перед ім'ям можна згадати конкретного користувача." + mentionDescription: "За допомогою знака \"@\" перед ім'ям можна згадати конкретного + користувача." hashtag: "Хештеґ" hashtagDescription: "За допомогою знака \"решітка\" перед словом задається хештег." url: "URL" urlDescription: "Відображаються URL-адреси." link: "Посилання" - linkDescription: "Окремі частини тексту можуть містити посилання" + linkDescription: "Окремі частини тексту можуть містити посилання." bold: "Жирний шрифт" - boldDescription: "Виділяє літери, роблячи їх товще" + boldDescription: "Виділяє літери, роблячи їх товщими." small: "Дрібний шрифт" - smallDescription: "Робить текст маленьким і тонким" + smallDescription: "Робить текст маленьким і тонким." center: "По центру" - centerDescription: "Показує вміст у центрі" + centerDescription: "Показує вміст у центрі." inlineCode: "Код (у рядку)" - inlineCodeDescription: "Показує фрагмент тексту у рядку як програмний код" + inlineCodeDescription: "Відображає підсвічування синтаксису для коду (програми)." blockCode: "Код (блок)" - blockCodeDescription: "Показує кілька рядків тексту як блок програмного кода" + blockCodeDescription: "Відображає підсвічування синтаксису для багаторядкового (програмного) + коду в блоці." inlineMath: "Формула (у рядку)" inlineMathDescription: "Відображення математичних формул (KaTeX) у рядку" blockMath: "Формули (блок)" - blockMathDescription: "Відображати багаторядкові формули (KaTeX) блоками" + blockMathDescription: "Відображати математичні формули (KaTeX) блоками" quote: "Цитата" quoteDescription: "Відображає зміст як цитату." emoji: "Кастомні емоджі" emojiDescription: "Щоб показати нетиповий емоджі, потрібно ввести його назву в двокрапках." search: "Пошук" - searchDescription: "Відображає вікно пошуку з попередньо введеним текстом" + searchDescription: "Відображає вікно пошуку з попередньо введеним текстом." flip: "Перевернути" - flipDescription: "Віддзеркалює вміст по горизонталі або вертикалі" + flipDescription: "Віддзеркалює вміст по горизонталі або вертикалі." jelly: "Анімація (желе)" - jellyDescription: "Створює желеподібну анімацію" + jellyDescription: "Створює желеподібну анімацію." tada: "Анімація (Тада!)" - tadaDescription: "Створює анімацію з відчуттям \"Тада!\"" + tadaDescription: "Створює анімацію з відчуттям \"Тада!\"." jump: "Анімація (стрибки)" - jumpDescription: "Показує стрибаючу анімацію" + jumpDescription: "Надає вмісту стрибучу анімацію." bounce: "Анімація (пружина)" shake: "Анімація (Shake)" twitch: "Анімація (Twitch)" @@ -819,10 +900,41 @@ _mfm: x4: "Надзвичайно великий" x4Description: "Показує контент надзвичайно великим." blur: "Розмиття" - blurDescription: "Цей ефект зробить контент розмитим. Контент можна зробити чітким, якщо навести на нього вказівник миші." + blurDescription: "Цей ефект зробить контент розмитим. Контент можна зробити чітким, + якщо навести на нього вказівник миші." font: "Шрифт" fontDescription: "Встановлює шрифт для контенту." rotate: "Обертати" + play: Відтворити MFM + alwaysPlay: Завжди автозапускати всі анімовані MFM + twitchDescription: Надає контенту анімацію, що сильно сіпається. + spinDescription: Надає контенту анімацію обертання. + sparkle: Блиск + sparkleDescription: Надає вмісту ефект мерехтливого блиску. + fade: Згасання + fadeDescription: Зменшує та збільшує видимість контенту. + crop: Обрізати + cropDescription: Обрізати вміст. + scale: Масштабувати + positionDescription: Перемістити вміст на вказане значення. + scaleDescription: Масштабувати вміст на вказану величину. + background: Фоновий колір + foreground: Колір переднього плану + foregroundDescription: Змінити колір тексту на передньому плані. + bounceDescription: Надає контенту пружної анімації. + shakeDescription: Надає контенту тремтливої анімації. + rainbowDescription: Робить вміст веселковим. + rotateDescription: Повертає вміст на вказаний кут. + advancedDescription: Якщо вимкнено, дозволяє лише базову розмітку, якщо не відтворюється + анімований MFM + plainDescription: Вимикає ефекти всіх MFM, що містяться в цьому MFM-ефекті. + stop: Зупинити MFM + plain: Звичайний текст + advanced: Розширені MFM + warn: MFM може містити швидко-рухому або яскраву анімацію + position: Розташування + rainbow: Веселка + backgroundDescription: Змінити колір фону тексту. _instanceTicker: none: "Не відображати" remote: "Відображати для віддалених користувачів" @@ -831,6 +943,7 @@ _serverDisconnectedBehavior: reload: "Автоматично перезавантажити" dialog: "Показати діалогове вікно" quiet: "Показати ненав’язливе попередження" + nothing: Нічого не робити _channel: create: "Створити канал" edit: "Редагувати канал" @@ -839,18 +952,27 @@ _channel: featured: "Тренди" following: "Підписки" usersCount: "{n} учасників" - notesCount: "{n} дописів" + notesCount: "{n} записів" + nameOnly: Тільки назва + nameAndDescription: Назва та опис + owned: Власні _menuDisplay: hide: "Сховати" + sideFull: Збоку + sideIcon: Збоку (тільки іконки) + top: Верх _wordMute: muteWords: "Заглушені слова" - muteWordsDescription: "Розділення ключових слів пробілами для \"І\" або з нової лінійки для \"АБО\"" - muteWordsDescription2: "Для використання RegEx, ключові слова потрібно вписати поміж слешів \"/\"." - softDescription: "Приховати записи які відповідають критеріям зі стрічки подій." - hardDescription: "Приховати записи які відповідають критеріям зі стрічки подій. Також приховані записи не будуть додані до стрічки подій навіть якщо критерії буде змінено." + muteWordsDescription: "Відокремліть ключові слова пробілами для умови \"І\" або + з нового рядку для умови \"АБО\"." + muteWordsDescription2: "Для використання RegEx, ключові слова потрібно вписати поміж + слешів \"/\"." + softDescription: "Приховати записи які відповідають критеріям зі стрічки." + hardDescription: "Приховати записи які відповідають критеріям зі стрічки подій. + Також приховані записи не будуть додані до стрічки навіть якщо критерії буде змінено." soft: "М'яко" hard: "Жорстко" - mutedNotes: "Заблоковані нотатки" + mutedNotes: "Ігноровані записи" _theme: explore: "Оглянути теми" install: "Встановити тему" @@ -914,9 +1036,20 @@ _theme: accentDarken: "Акцент (Затемлений)" accentLighten: "Акцент (Освітлений)" fgHighlighted: "Виділений текст" + color: Колір + refProp: Посилання на властивість + alpha: Прозорість + constant: Стала + refConst: Посилання на сталу + key: Ключ + funcKind: Тип функції + darken: Затемнення + argument: Аргумент + basedProp: Початкова властивість + addConstant: Додати сталу _sfx: - note: "Нотатки" - noteMy: "Мої нотатки" + note: "Новий запис" + noteMy: "Мої записи" notification: "Сповіщення" chat: "Чати" chatBg: "Чати (фон)" @@ -926,7 +1059,7 @@ _ago: future: "Майбутнє" justNow: "Щойно" secondsAgo: "{n}с тому" - minutesAgo: "{n}х тому" + minutesAgo: "{n}хв тому" hoursAgo: "{n}г тому" daysAgo: "{n}д тому" weeksAgo: "{n} тиж. тому" @@ -941,25 +1074,66 @@ _tutorial: title: "Як використовувати Calckey" step1_1: "Ласкаво просимо!" step1_2: "Давайте налаштуємо вас. Ви будете працювати в найкоротші терміни!" - step2_1: "Спочатку, будь ласка, заповніть свій профіль" - step2_2: "Надавши деяку інформацію про себе, іншим людям буде легше зрозуміти, чи хочуть вони бачити ваші записи або стежити за вами." - step3_1: "Тепер настав час стежити за деякими людьми!" - step3_2: "Ваша домашня і соціальна стрічки ґрунтуються на тому, за ким ви стежите, тому для початку спробуйте стежити за кількома акаунтами.\nНатисніть на гурток із плюсом у правому верхньому кутку профілю, щоб стежити за ним." - step4_1: "Давайте вийдемо на вас" - step4_2: "Для свого першого повідомлення деякі люди люблять робити {introduction} повідомлення або просте \"Hello world!\"" - step5_1: "Тимчасові рамки, скрізь тимчасові рамки!" - step5_2: "У вашому екземплярі включені {timelines} різних часових ліній." - step5_3: "Головна {icon} часова шкала - це шкала, де ви можете бачити повідомлення ваших підписників." - step5_4: "Місцева {icon} тимчасова шкала - це шкала, де ви можете бачити повідомлення всіх інших користувачів даного екземпляра" - step5_5: "Тимчасова шкала Рекомендовані {icon} - це шкала, де ви можете бачити повідомлення від інстанцій, рекомендованих адміністраторами." - step5_6: "На часовій шкалі Social {icon} відображаються повідомлення від друзів ваших підписників" - step5_7: "Глобальна {icon} часова шкала - це місце, де ви можете бачити повідомлення від усіх інших підключених екземплярів" + step2_1: "Спочатку, будь ласка, заповніть свій профіль." + step2_2: "Після надання інформації про себе, іншим людям буде легше зрозуміти, чи + хочуть вони бачити ваші записи або стежити за вами." + step3_1: "Тепер настав час на когось підписатися!" + step3_2: "Ваша домашня і соціальна стрічки ґрунтуються на тому, за ким ви стежите, + тому для початку спробуйте стежити за кількома акаунтами.\nНатисніть на гурток + із плюсом у правому верхньому кутку профілю, щоб стежити за ним." + step4_1: "Давайте вийдемо на вас." + step4_2: "Для свого першого повідомлення деякі люди люблять робити {introduction} + повідомлення або просте \"Hello world!\"" + step5_1: "Стрічки, скрізь одні стрічки!" + step5_2: "У вашому сервері включені {timelines} різні стрічки." + step5_3: "Головна {icon} стрічка - це стрічка, де ви можете бачити записи тих, на + кого ви підписалися." + step5_4: "Місцева {icon} стрічка - це стрічка, де ви можете бачити записи всіх інших + користувачів даного серверу." + step5_5: "Стрічка рекомендованих {icon} - це комбінація домашньої та місцевої стрічок." + step5_6: "На стрічці Рекомендованих {icon} ви можете бачити записи з серверів, які + рекомендують адміністратори." + step5_7: "Глобальна {icon} стрічка - це місце, де ви можете бачити записи від усіх + інших приєднаних серверів." step6_1: "Отже, що це за місце?" - step6_2: "Ну, ви не просто приєдналися до Кальки. Ви приєдналися до порталу в Fediverse, взаємопов'язаної мережі з тисяч серверів, званих \"інстансами\"." - step6_3: "Кожен сервер працює по-своєму, і не на всіх серверах працює Calckey. Але цей працює! Це трохи складно, але ви швидко розберетеся" + step6_2: "Ну, ви не просто приєдналися до Calckey. Ви увійшли в Fediverse, взаємопов'язану + мережу з тисяч серверів." + step6_3: "Кожен сервер працює по-своєму, і не на всіх серверах працює Calckey. Але + цей працює! Це трохи складно, але ви швидко розберетеся." step6_4: "Тепер ідіть, вивчайте і розважайтеся!" _2fa: registerSecurityKey: "Зареєструвати новий ключ безпеки" + registerTOTP: Зареєструйте новий пристрій + tapSecurityKey: Будь ласка, дотримуйтесь інструкцій вашого браузера, щоб зареєструвати + апаратний ключ безпеки або ключ-пароль + securityKeyName: Введіть назву ключа + chromePasskeyNotSupported: Паролі Chrome наразі не підтримуються. + renewTOTPOk: Переналаштувати + removeKey: Видалити ключ безпеки + alreadyRegistered: 2FA вже налаштовано. + step2Click: Натиснувши на цей QR-код, ви зможете зареєструвати 2FA у вашому ключі + безпеки або додатку-автентифікаторі для телефону. + step3Title: Введіть код автентифікації + step1: По-перше, встановіть програму 2FA (наприклад, {a} або {b}) на свій пристрій. + securityKeyNotSupported: Ваш браузер не підтримує ключі безпеки. + step4: Відтепер при наступних спробах входу в систему буде запитуватися такий токен. + securityKeyInfo: Окрім автентифікації за відбитком пальця або PIN-кодом, ви також + можете налаштувати автентифікацію за допомогою апаратних ключів безпеки, які підтримують + FIDO2, щоб додатково захистити свій обліковий запис. + removeKeyConfirm: Дійсно видалити ключ {name}? + whyTOTPOnlyRenew: Додаток автентифікатора не можна видалити, доки зареєстровано + ключ безпеки. + renewTOTP: Переналаштувати додаток-автентифікатор + renewTOTPCancel: Скасувати + renewTOTPConfirm: Це призведе до того, що коди підтвердження з попереднього додатку + перестануть працювати + token: 2FA Токен + registerTOTPBeforeKey: Будь ласка, налаштуйте додаток-автентифікатор, щоб зареєструвати + ключ безпеки або пароль. + step2Url: 'Також, ви можете ввести цю URL-адресу, якщо використовуєте десктопну + програму:' + step3: Введіть токен, наданий вашим додатком, щоб завершити налаштування. + step2: Потім відскануйте QR-код, що відображається на цьому екрані. _permissions: "read:account": "Переглядати дані профілю" "write:account": "Змінити дані акаунту" @@ -975,7 +1149,7 @@ _permissions: "write:messaging": "Створювати та видаляти повідомлення" "read:mutes": "Переглядати список ігнорованих" "write:mutes": "Змінювати список ігнорованих" - "write:notes": "Писати і видаляти нотатки" + "write:notes": "Створення та видалення записів" "read:notifications": "Переглядати сповіщення" "read:reactions": "Переглядати реакції" "write:reactions": "Змінювати реакції" @@ -988,13 +1162,27 @@ _permissions: "write:user-groups": "Змінювати групи користувача" "read:channels": "Переглядати канали" "write:channels": "Змінювати канали" + "read:gallery": Переглянути галерею + "write:gallery": Редагування галереї + "read:gallery-likes": Переглянути список вподобаних записів галереї + "write:notifications": Керування сповіщеннями + "write:gallery-likes": Редагувати список вподобаних записів галереї _auth: shareAccess: "Ви хочете надати \"{name}\" доступ до цього акаунту?" shareAccessAsk: "Ви впевнені, що хочете надати цій програмі доступ до вашого акаунту?" denied: "У доступі відмовлено" + allPermissions: Повний доступ до облікового запису + permissionAsk: 'Цей додаток запитує наступні дозволи:' + copyAsk: 'Будь ласка, вставте наступний код авторизації в додаток:' + pleaseGoBack: Будь ласка, поверніться до додатку + callback: Повернення до додатку _antennaSources: - all: "Всі нотатки" - homeTimeline: "Нотатки тих, на кого ви підписані" + all: "Усі записи" + homeTimeline: "Записи тих, на кого ви підписані" + instances: Записи від усіх користувачів на сервері + userGroup: Записи від користувачів у вказаній групі + users: Записи обраних користувачів + userList: Дописи користувачів із вказаного списку _weekday: sunday: "Неділя" monday: "Понеділок" @@ -1015,20 +1203,30 @@ _widgets: photos: "Фото" digitalClock: "Цифровий годинник" federation: "Федіверс" - postForm: "Створення нотатки" + postForm: "Створення запису" slideshow: "Слайд-шоу" button: "Кнопка" onlineUsers: "Користувачі онлайн" jobQueue: "Черга завдань" - serverMetric: "Показники сервера " + serverMetric: "Показники сервера" aiscript: "Консоль AiScript" + _userList: + chooseList: Оберіть список + meiliStatus: Стан сервера + meiliSize: Розмір індексу + rssTicker: RSS-тікер + instanceCloud: Хмара серверів + unixClock: Годинник UNIX + userList: Список користувачів + serverInfo: Інформація про сервер + meiliIndexCount: Індексовані записи _cw: hide: "Сховати" show: "Показати більше" chars: "{count} символів" files: "{count} файлів" _poll: - noOnlyOneChoice: "Потрібні принаймні два варіанти." + noOnlyOneChoice: "Потрібні принаймні два варіанти" choiceN: "Варіант {n}" noMore: "Більше варіантів додати не можна" canMultipleVote: "Можна вибрати кілька варіантів" @@ -1051,19 +1249,19 @@ _poll: remainingSeconds: "Залишилось {s} секунд" _visibility: public: "Публічний" - publicDescription: "Для всіх користувачів" - home: "Домівка" + publicDescription: "Ваш запис буде видно в усіх публічних стрічках" + home: "Скритий" homeDescription: "Лише на домашній стрічці" followers: "Підписники" - followersDescription: "Тільки для підписників" + followersDescription: "Зробити видимим тільки для ваших підписників і згаданих користувачів" specified: "Особисто" specifiedDescription: "Лише для певних користувачів" localOnly: "Локально" localOnlyDescription: "Приховано для віддалених користувачів" _postForm: - replyPlaceholder: "Відповідь на цю нотатку..." - quotePlaceholder: "Прокоментуйте цю нотатку..." - channelPlaceholder: "Опублікувати в каналі" + replyPlaceholder: "Відповідь на цей запис..." + quotePlaceholder: "Прокоментуйте цей запис..." + channelPlaceholder: "Опублікувати в каналі..." _placeholders: a: "Чим займаєтесь?" b: "Що відбувається навколо вас?" @@ -1078,51 +1276,65 @@ _profile: youCanIncludeHashtags: "Ви також можете включити хештеги у свій опис." metadata: "Додаткова інформація" metadataEdit: "Редагувати додаткову інформацію" - metadataDescription: "Ви можете вказати до чотирьох пунктів додаткової інформації у своєму профілі." + metadataDescription: "Ви можете вказати до чотирьох пунктів додаткової інформації + у своєму профілі." metadataLabel: "Назва" metadataContent: "Вміст" changeAvatar: "Змінити аватар" changeBanner: "Змінити банер" + locationDescription: Якщо ви спочатку введете своє місто, іншим користувачам буде + показано ваш місцевий час. _exportOrImport: - allNotes: "Всі нотатки" + allNotes: "Всі записи" followingList: "Підписки" muteList: "Ігнорувати" blockingList: "Заблокувати" userLists: "Списки" + excludeInactiveUsers: Вилучити неактивних користувачів + excludeMutingUsers: Вилучити заглушених користувачів _charts: federation: "Федіверс" apRequest: "Запити" usersTotal: "Загальна кількість користувачів" activeUsers: "Активні користувачі" - notesTotal: "Загальна кількість нотаток" + notesTotal: "Загальна кількість записів" filesIncDec: "Зміни кількості файлів" filesTotal: "Загальна кількість файлів" + storageUsageIncDec: Різниця в використанні ємності диску + remoteNotesIncDec: Різниця в кількості віддалених записів + notesIncDec: Різниця в кількості записів + localNotesIncDec: Різниця в кількості локальних записів + storageUsageTotal: Загальне використання пам'яті + usersIncDec: Різниця в кількості користувачів _instanceCharts: requests: "Запити" usersTotal: "Сумарна кількість користувачів" - notes: "Різниця кількості зроблених записів" - notesTotal: "Сумарна кількість нотаток" - ff: "Різниця кількості підписників" + notes: "Різниця в кількості зроблених записів" + notesTotal: "Сумарна кількість записів" + ff: "Різниця кількості підписників " ffTotal: "Кількість підписників" cacheSizeTotal: "Сумарний розмір кешу" files: "Різниця в кількості файлів" filesTotal: "Сумарна кількість файлів" + users: Різниця в кількості користувачів + cacheSize: Різниця в розмірі кешу _timelines: home: "Домівка" local: "Локальна" social: "Соціальна" global: "Глобальна" + recommended: Рекомендована _pages: newPage: "Створити сторінку" editPage: "Редагувати сторінку" readPage: "Перегляд вихідного коду" - created: "Сторінка успішно створена." - updated: "Сторінка успішно оновлена." + created: "Сторінка успішно створена" + updated: "Сторінка успішно оновлена" deleted: "Сторінку видалено" pageSetting: "Налаштування сторінки" - nameAlreadyExists: "Вказана адреса сторінки вже існує." - invalidNameTitle: "Вказана адреса сторінки неприпустима." - invalidNameText: "Переконайтеся, що не залишили порожнім." + nameAlreadyExists: "Вказана адреса сторінки вже існує" + invalidNameTitle: "Вказана адреса сторінки неприпустима" + invalidNameText: "Переконайтеся, що поле заголовка сторінки не порожнє" editThisPage: "Редагувати цю сторінку" viewSource: "Переглянути вихідний код" viewPage: "Переглянути свої сторінки" @@ -1165,6 +1377,7 @@ _pages: _post: text: "Вміст" canvasId: "Ідентифікатор полотна" + attachCanvasImage: Прикріпити зображення полотна textInput: "Введення тексту" _textInput: name: "Ім'я змінної" @@ -1185,10 +1398,10 @@ _pages: id: "Ідентифікатор полотна" width: "Ширина" height: "Висота" - note: "Вбудована нотатка" + note: "Вбудований запис" _note: - id: "Ідентифікатор нотатки" - idDescription: "Також можна вказати посилання на нотатку" + id: "Ідентифікатор запису" + idDescription: "Також можна вказати посилання на запис." detailed: "Детальний вигляд" switch: "Перемикач" _switch: @@ -1379,7 +1592,7 @@ _pages: arg1: "Текст" ref: "Змінні" aiScriptVar: "Змінна AiScript" - fn: "Функції" + fn: "Функція" _fn: slots: "Паз" slots-info: "Використовувати нову лінію як роздільник пазів" @@ -1388,7 +1601,8 @@ _pages: _for: arg1: "Кількість повторень" arg2: "Дія" - typeError: "Паз {slot} приймає \"{expect}\" тип, але надана змінна має тип \"{actual}\"!" + typeError: "Паз {slot} приймає \"{expect}\" тип, але надана змінна має тип \"\ + {actual}\"!" thereIsEmptySlot: "Паз {slot} пустий!" types: string: "Текст" @@ -1430,9 +1644,16 @@ _notification: followRequestAccepted: "Прийняті підписки" groupInvited: "Запрошення до груп" app: "Сповіщення від додатків" + pollEnded: Опитування закінчено _actions: reply: "Відповісти" - renote: "Поширити" + renote: "Поширення" + followBack: також підписався на вас + emptyPushNotificationMessage: Push-сповіщення були оновлені + voted: проголосував на вашому опитуванні + renoted: поширив ваш запис + reacted: відреагував на ваш запис + pollEnded: Стали доступні результати опитування _deck: alwaysShowMainColumn: "Завжди показувати головну колонку" columnAlign: "Вирівняти стовпці" @@ -1443,13 +1664,470 @@ _deck: swapDown: "Пересунути вниз" stackLeft: "У стовпчик вліво" popRight: "Витягнути вправо" - profile: "Обліковий запис" + profile: "Простір" _columns: main: "Головна" widgets: "Віджети" notifications: "Сповіщення" tl: "Стрічка" - antenna: "Антени" + antenna: "Антена" list: "Списки" mentions: "Згадки" - direct: "Особисте" + direct: "Особисті повідомлення" + channel: Канал + newProfile: Новий простір + introduction2: Натисніть на + у правій частині екрана, щоб додавати нові стовпці + по бажанню. + configureColumn: Налаштування стовпців + introduction: Створіть ідеальний інтерфейс для себе, вільно розташовуючи стовпці! + widgetsIntroduction: Будь ласка, виберіть "Редагувати віджети" в меню колонки і + додайте віджет. + renameProfile: Перейменувати простір + deleteProfile: Видалити простір + nameAlreadyExists: Простір із такою назвою вже існує. +removeReaction: Видалити вашу реакцію +renoteMute: Ігнорувати поширення +renoteUnmute: Показувати поширення +flagSpeakAsCat: Говорити як кішка +accessibility: Доступність +priority: Пріорітет +high: Високий +customCss: Користувацькі CSS +itsOn: Увімкнено +showingPastTimeline: Наразі відображається стара стрічка +enabled: Увімкнено +noMaintainerInformationWarning: Інформація про супровідника не налаштована. +recommended: Рекомендоване +resolved: Вирішено +itsOff: Вимкнено +emailRequiredForSignup: Вимагати адресу електронної пошти для реєстрації +moderation: Модерація +selectInstance: Оберіть сервер +instanceSecurity: Безпека сервера +searchPlaceholder: Шукати в Calckey +editNote: Відредагувати запис +enableEmojiReactions: Ввімкнути реакції емодзі +low: Низький +emailNotConfiguredWarning: Адрес електронної пошти не встановлено. +unresolved: Не вирішено +offline: Не в мережі +disabled: Вимкнено +configure: Налаштувати +popularPosts: Популярні сторінки +silenced: Ігнорується +manageGroups: Керування групами +active: Активний +whatIsNew: Показати зміни +deleted: Видалено +selectChannel: Виберіть канал +flagSpeakAsCatDescription: Ваші записи будуть няніфіковані у режимі кота +userSaysSomethingReason: '{name} сказав(ла) {reason}' +clear: Очистити +userInfo: Інформація про користувача +selectAccount: Оберіть обліковий запис +switchAccount: Змінити обліковий запис +accounts: Облікові записи +switch: Змінити +noBotProtectionWarning: Захист від ботів не налаштовано. +gallery: Галерея +recentPosts: Недавні сторінки +privateModeInfo: Якщо увімкнено, лише сервери з білого списку можуть федеруватися + з вашим сервером. Всі повідомлення будуть приховані від публіки. +troubleshooting: Вирішення проблем +customCssWarn: Цей параметр слід використовувати лише тоді, коли ви знаєте, що він + робить. Введення неправильних значень може призвести до того, що клієнт перестане + нормально функціонувати. +newer: новіші +older: старіші +addDescription: Додати опис +notSpecifiedMentionWarning: У цьому записі згадуються користувачі, яких не було включено + до списку одержувачів +markAllAsRead: Позначити все як прочитане +userPagePinTip: Ви можете відображати записи тут, вибравши "Прикріпити до профілю" + в меню окремих записів. +unknown: Невідомо +onlineStatus: Онлайн-статус +hideOnlineStatus: Приховати онлайн-статус +online: В мережі +breakFollow: Видалити підписника +translate: Перекласти +translatedFrom: Перекладено з {x} +userSaysSomethingReasonQuote: '{name} цитував запис з {reason}' +userSaysSomethingReasonRenote: '{name} поширив запис з {reason}' +notRecommended: Не рекомендується +botProtection: Захист від ботів +instanceBlocking: Керування Федерацією +privateMode: Приватний режим +allowedInstances: Сервери у білому списку +previewNoteText: Показати прев'ю +antennaInstancesDescription: Введіть по одному хосту сервера на рядок +breakFollowConfirm: Ви дійсно бажаєте видалити підписника? +ads: Реклама +cw: Попередження про вміст +hiddenTags: Приховані хештеги +noInstances: Немає серверів +misskeyUpdated: Calckey оновлено! +received: Отримане +xl: Надвеликий +searchResult: Результати пошуку +useBlurEffect: Використовувати ефекти розмиття в інтерфейсі +learnMore: Дізнатися більше +usernameInfo: Ім'я, яке ідентифікує ваш обліковий запис серед інших на цьому сервері. Ви + можете використовувати алфавіт (a~z, A~Z), цифри (0~9) або знаки підкреслення (_). + Ім'я користувача не може бути змінено пізніше. +noThankYou: Ні, дякую +keepCw: Зберігати попередження про вміст +showEmojisInReactionNotifications: Показувати емодзі у сповіщеннях про реакції +accountMoved: 'Користувач переїхав до нового облікового запису:' +expandOnNoteClickDesc: Якщо цю опцію вимкнено, ви все одно зможете відкривати дописи + в меню, клацнувши правою кнопкою миші або натиснувши на мітку часу. +deleteAccountConfirm: Це призведе до незворотного видалення вашого облікового запису. + Приступити? +unread: Непрочитане +filter: Фільтри +useDrawerReactionPickerForMobile: Відображати вибирач реакцій як шухляду на мобільному + телефоні +leaveGroupConfirm: Ви впевнені, що хочете залишити "{name}"? +clickToFinishEmailVerification: Будь ласка, натисніть [{ok}], щоб завершити перевірку + електронної пошти. +welcomeBackWithName: Ласкаво просимо назад, {name} +overridedDeviceKind: Тип пристрою +themeColor: Колір теми серверу +oneDay: Один день +instanceDefaultLightTheme: Світла тема за замовчуванням для сервера +oneWeek: Одна неділя +instanceDefaultDarkTheme: Темна тема за замовчуванням для сервера +video: Відео +audio: Аудіо +rateLimitExceeded: Перевищено ліміт +numberOfPageCacheDescription: Збільшення цієї величини покращить зручність для користувачів, + але призведе до збільшення навантаження на сервер та використання більшої кількості + пам'яті. +lastActiveDate: Останній раз використовувався у +statusbar: Панель статусу +speed: Швидкість +sensitiveMediaDetection: Виявлення NSFW медіа +cannotUploadBecauseNoFreeSpace: Завантаження не вдалося через брак місця на Диску. +cannotUploadBecauseExceedsFileSizeLimit: Цей файл не може бути завантажений, оскільки + він перевищує максимально дозволений розмір. +account: Обліковий запис +move: Перемістити +pushNotification: Push-сповіщення +subscribePushNotification: Увімкнути push-сповіщення +unsubscribePushNotification: Вимкнути push-сповіщення +pushNotificationAlreadySubscribed: Push-сповіщення вже увімкнено +enterSendsMessage: Натисніть Enter у повідомленнях, щоб надіслати повідомлення (якщо + вимкнено, то Ctrl + Enter) +showAds: Показувати рекламу +customMOTD: Користувацькі MOTD (повідомлення на заставці) +customSplashIcons: Користувацькі іконки заставки (URL) +splash: Заставка +adminCustomCssWarn: Цей параметр слід використовувати, тільки якщо ви знаєте, що він + робить. Введення неправильних значень може призвести до того, що ВСІ клієнти перестануть + нормально працювати. Будь ласка, переконайтеся, що ваш CSS працює належним чином, + протестувавши його в налаштуваннях користувача. +_filters: + followersOnly: Тільки підписники + fromUser: Від користувача + notesBefore: Записи до + withFile: З файлом + fromDomain: З домену + notesAfter: Записи після + followingOnly: Тільки підписки +sendModMail: Надіслати повідомлення про модерацію +enableServerMachineStats: Увімкнути статистику серверного обладнання +enableIdenticonGeneration: Увімкнути генерацію Identicon +_sensitiveMediaDetection: + analyzeVideosDescription: Аналізує відео так само як і зображення. Це трохи збільшить + навантаження на сервер. + description: Зменшує навантаження на серверну модерацію завдяки автоматичному розпізнаванню + NSFW медіа за допомогою машинного навчання. Це трохи збільшить навантаження на + сервер. + sensitivity: Чутливість виявлення + sensitivityDescription: Зменшення чутливості призведе до зменшення кількості хибних + спрацьовувань, тоді як збільшення чутливості призведе до зменшення кількості пропущених + спрацьовувань. + setSensitiveFlagAutomatically: Позначити як NSFW + setSensitiveFlagAutomaticallyDescription: Результати внутрішнього виявлення будуть + збережені, навіть якщо цю опцію вимкнено. + analyzeVideos: Ввімкнути аналіз відео +_emailUnavailable: + used: Ця електронна пошта вже використовується + format: Формат цієї адреси електронної пошти є неправильним + mx: Цей сервер електронної пошти є недійсним + disposable: Використовувати одноразові адреси електронної пошти заборонено + smtp: Цей поштовий сервер не відповідає +_messaging: + dms: Приватні + groups: Групи +_instanceMute: + instanceMuteDescription: Це приховає всі записи/поширення із вказаних серверів, + включно з відповідями користувачам заглушеного серверу. + title: Приховує записи з перелічених серверів. + instanceMuteDescription2: Розділити новими рядками + heading: Список серверів для заглушення +_experiments: + enablePostImports: Ввімкнути імпорт записів + title: Експерименти + postImportsCaption: Дозволяє користувачам імпортувати свої публікації з минулих + облікових записів Calckey, Misskey, Mastodon, Akkoma і Pleroma. Це може спричинити + зниження швидкості під час завантаження, якщо ваша черга перевантажена. +_dialog: + charactersExceeded: 'Перевищено максимальну кількість символів! Обмеження: {current}/{max}' + charactersBelow: 'Недостатньо символів! Обмеження: {current}/{min}' +jumpToSpecifiedDate: Перейти до конкретної дати +quitFullView: Закрити повний вигляд +ffVisibility: Видимість підписок/підписників +numberOfColumn: Кількість стовпців +failedToFetchAccountInformation: Не вдалося отримати інформацію про обліковий запис +reflectMayTakeTime: Може пройти деякий час, перш ніж зміни набудуть чинності. +recentNHours: Останні {n} годин +logoutConfirm: Ви впевнені, що хочете вийти? +enableRecommendedTimeline: Увімкнути рекомендовану стрічку +_accountDelete: + requestAccountDelete: Запросити видалення облікового запису + accountDelete: Видалити обліковий запис + mayTakeTime: Оскільки видалення облікового запису є ресурсоємним процесом, він може + зайняти деякий час, залежно від того, скільки контенту ви створили та скільки + файлів завантажили. + sendEmail: Коли ваш обліковий запис буде видалено, ми повідомимо на вказану вами + електронну пошту. + started: Процес видалення розпочався. + inProgress: Наразі триває видалення +_preferencesBackups: + deleteConfirm: Видалити резервну копію {name}? + applyConfirm: Ви дійсно хочете застосувати резервну копію "{name}" до цього пристрою? + Існуючі налаштування цього пристрою буде замінено. + saveConfirm: Зберегти резервну копію як {name}? + saveNew: Зберегти нову резервну копію + save: Зберегти зміни + inputName: Будь ласка, введіть назву для цієї резервної копії + loadFile: Завантажити з файлу + updatedAt: 'Оновлено: {date} {time}' + invalidFile: Неправильний формат файлу + apply: Застосувати до цього пристрою + list: Створені резервні копії + cannotSave: Збереження невдале + nameAlreadyExists: Резервна копія з назвою "{name}" вже існує. Будь ласка, введіть + іншу назву. + renameConfirm: Перейменувати цю резервну копію з "{old}" на "{new}"? + noBackups: Резервних копій немає. Ви можете створити резервну копію налаштувань + клієнта на цьому сервері за допомогою "Створити нову резервну копію". + createdAt: 'Створено: {date} {time}' + cannotLoad: Не вдалося завантажити +beta: Бета +customMOTDDescription: Користувацькі повідомлення для MOTD (заставки), розділені новими + рядками, які будуть показуватися випадковим чином щоразу, коли користувач завантажує/перезавантажує + сторінку. +replayTutorial: Перезапустити туторіал +_forgotPassword: + ifNoEmail: Якщо ви не використовували електронну пошту під час реєстрації, зверніться + до адміністратора серверу. + enterEmail: Введіть адресу електронної пошти, яку ви використовували для реєстрації. + На неї буде надіслано посилання, за яким ви зможете скинути пароль. + contactAdmin: Цей сервер не підтримує використання адрес електронної пошти, будь + ласка, зверніться до адміністратора сервера, щоб скинути пароль. +reactionPickerSkinTone: Бажаний колір шкіри емодзі +addInstance: Додати сервер +jumpToPrevious: Перейти до попереднього +listsDesc: Списки дозволяють створювати стрічки із вказаними користувачами. Доступ + до них можна отримати на сторінці стрічок. +channelFederationWarn: Канали наразі федеруються з іншими серверами +lastCommunication: Останнє повідомлення +edited: Відредаговано {date} о {time} +confirmToUnclipAlreadyClippedNote: Цей запис уже в підбірці "{name}". Чи бажаєте ви + натомість видалити пост із підбірки? +quickAction: Швидкі дії +remoteOnly: Тільки віддалені +failedToUpload: Помилка завантаження +moveFrom: Мігрувати на цей обліковий запис зі старого облікового запису +preventAiLearning: Захист від скрепінгу ШІ-ботів +moveAccountDescription: Цей процес є незворотнім. Переконайтеся, що ви створили псевдонім + для цього акаунта в новому акаунті перед переїздом. Будь ласка, введіть тег акаунта + у форматі @person@server.com +_signup: + almostThere: Майже готово + emailAddressInfo: Будь ласка, введіть свою адресу електронної пошти. Вона не буде + опублікована. + emailSent: На вашу електронну адресу ({email}) було надіслано лист із підтвердженням. + Будь ласка, перейдіть за посиланням, щоб завершити створення облікового запису. +defaultValueIs: 'За замовчуванням: {value}' +shareWithNote: Поділитися з записом +classic: Відцентрований +size: Розмір +slow: Повільно +alt: ALT +auto: Автоматично +oneHour: Одна година +instanceDefaultThemeDescription: Введіть код теми в об'єктному форматі. +cropImageAsk: Чи бажаєте ви обрізати це зображення? +noEmailServerWarning: Поштовий сервер не налаштовано. +thereIsUnresolvedAbuseReportWarning: Є не розглянуті звіти. +image: Зображення +check: Перевірити +isSystemAccount: Цей акаунт створений і автоматично управляється системою. Будь ласка, + не модеруйте, не редагуйте, не видаляйте та не втручайтеся в цей акаунт будь-яким + іншим чином, інакше це може призвести до поломки вашого серверу. +document: Документація +driveCapOverrideCaption: Ви можете скинути ємність до значення за замовчуванням, ввівши + значення 0 або менше. +numberOfPageCache: Кількість кешованих сторінок +pleaseSelect: Оберіть варіант +refreshInterval: 'Інтервал оновлення ' +enableAutoSensitive: Автоматичне маркування NSFW +cannotUploadBecauseInappropriate: Цей файл не може бути завантажений тому що його + частини були виявлені як потенційне NSFW. +sendPushNotificationReadMessageCaption: На короткий час буде показано сповіщення з + текстом "{emptyPushNotificationMessage}". Це може призвести до збільшення споживання + заряду акумулятора вашого пристрою, якщо це можливо. +pushNotificationNotSupported: Ваш браузер або сервер не підтримує push-сповіщення +showUpdates: Показувати спливаюче вікно при оновленні Calckey +updateAvailable: Можливо, є доступне оновлення! +recommendedInstancesDescription: Рекомендовані сервери відокремлюються переведенням + рядка, щоб з'явитися на стрічці рекомендацій. +caption: Автоматичний підпис +showAdminUpdates: Вказати, що доступна нова версія Calckey (тільки для адміністратора) +defaultReaction: Емодзі реакція за замовчуванням для вихідних і вхідних записів +license: Ліцензія +indexPosts: Індексувати пости +indexFrom: Індексувати записи з ID +indexFromDescription: Залиште порожнім, щоб індексувати кожен запис +indexNotice: Зараз відбувається індексація. Це, ймовірно, займе деякий час, будь ласка, + не перезавантажуйте сервер принаймні годину. +signupsDisabled: Реєстрація на цьому сервері наразі відключена, але ви завжди можете + зареєструватися на іншому сервері! Якщо у вас є код запрошення на цей сервер, будь + ласка, введіть його нижче. +findOtherInstance: Знайти інший сервер +customKaTeXMacro: Користувацькі макроси KaTeX +enableCustomKaTeXMacro: Увімкнути користувацькі макроси KaTeX +apps: Додатки +isModerator: Модератор +isAdmin: Адміністратор +isPatron: Патрон Calckey +swipeOnMobile: Дозволити гортання між сторінками +migration: Міграція +swipeOnDesktop: Дозволити свайп у мобільному стилі на десктопі +logoImageUrl: URL-адреса зображення логотипу +moveTo: Перенести поточний обліковий запис на новий +moveFromDescription: Це встановить псевдонім вашого старого облікового запису, щоб + ви могли перейти зі старого облікового запису до цього поточного. Зробіть це ДО + переходу зі старого акаунта. Будь ласка, введіть тег акаунта у форматі @person@server.com +moveToLabel: 'Обліковий запис, на який ви мігруєте:' +moveAccount: Перемістити обліковий запис! +moveFromLabel: 'Обліковий запис, з якого ви мігруєте:' +_plugin: + install: Встановлення плагінів + manage: Керування плагінами + installWarn: Будь ласка, не встановлюйте ненадійні плагіни. +_skinTones: + yellow: Жовтий + mediumLight: Помірно-світлий + medium: Помірний + mediumDark: Помірно-темний + dark: Темний + light: Світлий +tenMinutes: 10 хвилин +expandOnNoteClick: Відкрити запис кліком +preferencesBackups: Резервне копіювання +unlikeConfirm: Дійсно видалити вподобайку? +fullView: Повний вигляд +postToGallery: Опублікувати в галереї +memo: Нотатки +allowedInstancesDescription: Хости серверів, які будуть допущені до федерації, кожен + з яких відокремлюється новим рядком (стосується лише приватного режиму). +squareAvatars: Квадратні аватарки +aiChanMode: Режим ШІ +controlPanel: Панель керування +manageAccounts: Керування обліковими записами +incorrectPassword: Неправильний пароль. +voteConfirm: Підтвердити свій голос за "{choice}"? +leaveGroup: Залишити групу +smartphone: Смартфон +mutePeriod: Тривалість глушіння +requireAdminForView: Ви маєте увійти з облікового запису адміністратора, щоб переглянути + це. +fast: Швидко +isBot: Цей обліковий запис є ботом +isLocked: Цей обліковий запис має схвалення запитів на підписку +silenceThisInstance: Ігнорувати цей сервер +hideOnlineStatusDescription: Приховування вашого онлайн-статусу знижує зручність деяких + функцій, таких як пошук. +accountDeletionInProgress: Наразі триває видалення облікового запису +makeReactionsPublic: Зробити історію реакцій публічною +continueThread: Показати наступні відповіді +unmuteThread: Скасувати глушіння гілки +ffVisibilityDescription: Дозволяє налаштувати, хто може бачити, на кого ви підписані + і хто підписаний на вас. +tablet: Планшет +cropImage: Обрізати зображення +recentNDays: Останні {n} днів +navbar: Панель навігації +noGraze: Будь ласка, вимкніть розширення браузера "Graze для Mastodon", оскільки воно + заважає роботі Calckey. +preventAiLearningDescription: Попросити сторонні мовні моделі ШІ не вивчати вміст, + який ви завантажуєте, наприклад, записи та зображення. +userSaysSomethingReasonReply: '{name} відповів на пост з {reason}' +secureMode: Безпечний режим (Authorized Fetch) +seperateRenoteQuote: Розділити кнопки поширення та цитати +makeReactionsPublicDescription: Це зробить список усіх ваших минулих реакцій публічно + видимим. +muteThread: Заглушити гілку +sendPushNotificationReadMessage: Видаляти push-сповіщення після того, як відповідні + сповіщення або повідомлення будуть прочитані +unclip: Видалити з підбірки +silencedInstances: Ігноровані сервери +typeToConfirm: Введіть {x} щоб підтвердити +silencedWarning: Ця сторінка відображається тому, що ці користувачі з серверів, які + ваш адміністратор заглушив, тому вони потенційно можуть бути спамом. +shuffle: Перетасувати +ratio: Співвідношення +secureModeInfo: У разі запитів з інших серверів не надсилати непідтверджену відповідь. +pubSub: Облікові записи Pub/Sub +driveCapOverrideLabel: Змінити ємність диску для цього користувача +deleteAccount: Видалити обліковий запис +type: Тип +enableAutoSensitiveDescription: Дозволяє автоматично виявляти та позначати медіафайли + NSFW за допомогою машинного навчання, де це можливо. Навіть якщо цю опцію вимкнено, + вона може бути увімкнена на всьому сервері. +recommendedInstances: Рекомендовані сервери +noteId: Ідентифікатор запису +showPopup: Сповіщати користувачів спливаючим вікном +showWithSparkles: Показати з блиском +youHaveUnreadAnnouncements: У вас є непрочитані оголошення +donationLink: Посилання на сторінку для внесків +neverShow: Не показувати знову +remindMeLater: Можливо пізніше +removeQuote: Видалити цитату +removeRecipient: Видалити одержувача +removeMember: Видалити члена +silencedInstancesDescription: Вкажіть імена хостів серверів, які ви хочете ігнорувати. + Облікові записи на перелічених серверах вважаються "Ігнорованими", можуть робити + лише запити на підписку і не можуть згадувати локальні облікові записи, якщо на + них не підписалися. Це не вплине на заблоковані сервери. +hiddenTagsDescription: 'Перелічіть хештеги (без #), які ви хочете приховати з трендів + і дослідження. Приховані хештеги все одно можна знайти іншими способами.' +antennasDesc: "Антени показують нові дописи, що відповідають встановленим вами критеріям!\n + Доступ до них можна отримати зі сторінки стрічок." +clipsDesc: Підбірки схожі на категоризовані закладки, до яких можна надавати спільний + доступ. Ви можете створювати підбірки з меню окремих записів. +migrationConfirm: "Ви точно впевнені, що хочете перенести свій обліковий запис на + {account}? Якщо ви це зробите, ви не зможете скасувати цю операцію і не зможете + користуватися своїм обліковим записом як раніше.\nТакож, будь ласка, переконайтеся, + що ви вибрали цей поточний обліковий запис як обліковий запис, з якого ви переходите." +customKaTeXMacroDescription: 'Налаштуйте макроси, щоб легко писати математичні вирази! + Позначення відповідає визначенню команд LaTeX і записується у вигляді \newcommand{\ + name}{content} або \newcommand{\name}[number of arguments]{content}. Наприклад, + \newcommand{\add}[2]{#1 + #2} розширить \add{3}{foo} to 3 + foo. Фігурні дужки навколо + назви макросу можна змінити на круглі або квадратні. Це вплине на дужки, що використовуються + для аргументів. В одному рядку можна визначити один (і тільки один) макрос, і жоден + рядок не можна розривати посередині визначення. Неправильні рядки просто ігноруються. + Підтримуються лише прості функції заміни рядків; розширений синтаксис, такий як + умовне розгалуження, не може бути використаний тут.' +activeEmailValidationDescription: Вмикає більш сувору перевірку адрес електронної + пошти, яка включає перевірку на наявність одноразових адрес і перевірку того, чи + дійсно з нею можна зв'язатися. Якщо цей прапорець знято, перевіряється лише формат + електронної пошти. +customSplashIconsDescription: URL-адреси іконок для заставки, розділені новими рядками, + які будуть показуватися випадковим чином щоразу, коли користувач завантажує/перезавантажує + сторінку. Будь ласка, переконайтеся, що зображення знаходяться на статичній URL-адресі, + бажано, щоб вони були змінені до розміру 192x192. diff --git a/locales/zh-TW.yml b/locales/zh-TW.yml index 2803d7846..d1bad4ad1 100644 --- a/locales/zh-TW.yml +++ b/locales/zh-TW.yml @@ -1839,7 +1839,7 @@ pushNotification: 推送通知 subscribePushNotification: 啟用推送通知 unsubscribePushNotification: 禁用推送通知 pushNotificationAlreadySubscribed: 推送通知已經啟用 -recommendedInstancesDescription: 以每行分隔的推薦伺服器出現在推薦的時間線中。 不要添加 `https://`,只添加域名。 +recommendedInstancesDescription: 以每行分隔的推薦伺服器出現在推薦的時間線中。 searchPlaceholder: 在聯邦網路上搜尋 cw: 內容警告 selectChannel: 選擇一個頻道 diff --git a/package.json b/package.json index ec899739f..d4460c878 100644 --- a/package.json +++ b/package.json @@ -1,16 +1,16 @@ { "name": "calckey", - "version": "14.0.0-rc3", + "version": "14.0.0-dev79", "codename": "aqua", "repository": { "type": "git", "url": "https://codeberg.org/calckey/calckey.git" }, - "packageManager": "pnpm@8.6.6", + "packageManager": "pnpm@8.6.7", "private": true, "scripts": { - "rebuild": "pnpm run clean && pnpm node ./scripts/build-greet.js && pnpm -r run build && pnpm run gulp", - "build": "pnpm node ./scripts/build-greet.js && pnpm -r run build && pnpm run gulp", + "rebuild": "pnpm run clean && pnpm node ./scripts/build-greet.js && pnpm -r --parallel run build && pnpm run gulp", + "build": "pnpm node ./scripts/build-greet.js && pnpm -r --parallel run build && pnpm run gulp", "start": "pnpm --filter backend run start", "start:test": "pnpm --filter backend run start:test", "init": "pnpm run migrate", @@ -21,13 +21,13 @@ "watch": "pnpm run dev", "dev": "pnpm node ./scripts/dev.js", "dev:staging": "NODE_OPTIONS=--max_old_space_size=3072 NODE_ENV=development pnpm run build && pnpm run start", - "lint": "pnpm -r run lint", + "lint": "pnpm -r --parallel run lint", "cy:open": "cypress open --browser --e2e --config-file=cypress.config.ts", "cy:run": "cypress run", "e2e": "start-server-and-test start:test http://localhost:61812 cy:run", "mocha": "pnpm --filter backend run mocha", "test": "pnpm run mocha", - "format": "pnpm -r run format", + "format": "pnpm -r --parallel run format", "clean": "pnpm node ./scripts/clean.js", "clean-all": "pnpm node ./scripts/clean-all.js", "cleanall": "pnpm run clean-all" @@ -36,17 +36,17 @@ "chokidar": "^3.3.1" }, "dependencies": { - "@bull-board/api": "5.2.0", - "@bull-board/ui": "5.2.0", + "@bull-board/api": "5.6.0", + "@bull-board/ui": "5.6.0", "@napi-rs/cli": "^2.16.1", "@tensorflow/tfjs": "^3.21.0", "js-yaml": "4.1.0", "seedrandom": "^3.0.5" }, "devDependencies": { - "@types/node": "18.11.18", - "@types/gulp": "4.0.10", - "@types/gulp-rename": "2.0.1", + "@types/gulp": "4.0.13", + "@types/gulp-rename": "2.0.2", + "@types/node": "20.4.1", "chalk": "4.1.2", "cross-env": "7.0.3", "cypress": "10.11.0", @@ -57,8 +57,8 @@ "gulp-replace": "1.1.4", "gulp-terser": "2.1.0", "install-peers": "^1.0.4", - "rome": "^12.1.3", + "rome": "^v12.1.3-nightly.f65b0d9", "start-server-and-test": "1.15.2", - "typescript": "4.9.4" + "typescript": "5.1.6" } } diff --git a/packages/backend/migration/1678426061773-tweak-varchar-length.js b/packages/backend/migration/1678426061773-tweak-varchar-length.js new file mode 100644 index 000000000..00ddcaebe --- /dev/null +++ b/packages/backend/migration/1678426061773-tweak-varchar-length.js @@ -0,0 +1,16 @@ +export class tweakVarcharLength1678426061773 { + name = "tweakVarcharLength1678426061773"; + + async up(queryRunner) { + await queryRunner.query( + `ALTER TABLE "meta" ALTER COLUMN "smtpUser" TYPE character varying(1024)`, + undefined, + ); + await queryRunner.query( + `ALTER TABLE "meta" ALTER COLUMN "smtpPass" TYPE character varying(1024)`, + undefined, + ); + } + + async down(queryRunner) {} +} diff --git a/packages/backend/migration/1689136347561-donation-link.js b/packages/backend/migration/1689136347561-donation-link.js new file mode 100644 index 000000000..dbe0ed7c8 --- /dev/null +++ b/packages/backend/migration/1689136347561-donation-link.js @@ -0,0 +1,15 @@ +export class DonationLink1689136347561 { + name = "DonationLink1689136347561"; + + async up(queryRunner) { + await queryRunner.query( + `ALTER TABLE "meta" ADD "donationLink" character varying(256)`, + ); + } + + async down(queryRunner) { + await queryRunner.query( + `ALTER TABLE "meta" DROP COLUMN "DonationLink1689136347561"`, + ); + } +} diff --git a/packages/backend/native-utils/package.json b/packages/backend/native-utils/package.json index 385330d77..962b4bc4c 100644 --- a/packages/backend/native-utils/package.json +++ b/packages/backend/native-utils/package.json @@ -43,6 +43,7 @@ "universal": "napi universal", "version": "napi version", "format": "cargo fmt --all", + "lint": "cargo clippy --fix", "cargo:test": "pnpm run cargo:unit && pnpm run cargo:integration", "cargo:unit": "cargo test unit_test && cargo test -F napi unit_test", "cargo:integration": "cargo test -F noarray int_test -- --test-threads=1" diff --git a/packages/backend/native-utils/src/model/repository/antenna.rs b/packages/backend/native-utils/src/model/repository/antenna.rs index 36c641cb0..80f34fed1 100644 --- a/packages/backend/native-utils/src/model/repository/antenna.rs +++ b/packages/backend/native-utils/src/model/repository/antenna.rs @@ -40,7 +40,7 @@ impl Repository for antenna::Model { src: self.src.try_into()?, user_list_id: self.user_list_id, user_group_id, - users: self.users.into(), + users: self.users, instances: self.instances.into(), case_sensitive: self.case_sensitive, notify: self.notify, diff --git a/packages/backend/native-utils/src/model/schema/antenna.rs b/packages/backend/native-utils/src/model/schema/antenna.rs index 4ec1e0794..da2c3061b 100644 --- a/packages/backend/native-utils/src/model/schema/antenna.rs +++ b/packages/backend/native-utils/src/model/schema/antenna.rs @@ -58,7 +58,7 @@ impl TryFrom for super::AntennaSrc { // ---- TODO: could be macro impl Schema for super::Antenna {} -pub static VALIDATOR: Lazy = Lazy::new(|| super::Antenna::validator()); +pub static VALIDATOR: Lazy = Lazy::new(super::Antenna::validator); // ---- cfg_if! { diff --git a/packages/backend/native-utils/src/model/schema/app.rs b/packages/backend/native-utils/src/model/schema/app.rs index d13e9ef36..5f859ecb3 100644 --- a/packages/backend/native-utils/src/model/schema/app.rs +++ b/packages/backend/native-utils/src/model/schema/app.rs @@ -91,7 +91,7 @@ pub enum AppPermission { impl Schema for App {} -pub static VALIDATOR: Lazy = Lazy::new(|| App::validator()); +pub static VALIDATOR: Lazy = Lazy::new(App::validator); #[cfg(test)] mod unit_test { diff --git a/packages/backend/native-utils/tests/common.rs b/packages/backend/native-utils/tests/common.rs index 31c6ef053..674297606 100644 --- a/packages/backend/native-utils/tests/common.rs +++ b/packages/backend/native-utils/tests/common.rs @@ -148,8 +148,8 @@ async fn setup_model(db: &DbConn) { let user_model = entity::user::Model { id: user_id.to_owned(), created_at: Utc::now().into(), - username: name.to_lowercase().to_string(), - username_lower: name.to_lowercase().to_string(), + username: name.to_lowercase(), + username_lower: name.to_lowercase(), name: Some(name.to_string()), token: Some(gen_string(16)), is_admin: true, diff --git a/packages/backend/native-utils/tests/model/repository/antenna.rs b/packages/backend/native-utils/tests/model/repository/antenna.rs index 02ef8f5be..9b03d3652 100644 --- a/packages/backend/native-utils/tests/model/repository/antenna.rs +++ b/packages/backend/native-utils/tests/model/repository/antenna.rs @@ -43,18 +43,16 @@ mod int_test { keywords: vec![ vec!["foo".to_string(), "bar".to_string()], vec!["foobar".to_string()], - ] - .into(), + ], exclude_keywords: vec![ vec!["abc".to_string()], vec!["def".to_string(), "ghi".to_string()], - ] - .into(), + ], src: schema::AntennaSrc::All, user_list_id: None, user_group_id: None, - users: vec![].into(), - instances: vec![].into(), + users: vec![], + instances: vec![], case_sensitive: true, notify: true, with_replies: false, diff --git a/packages/backend/package.json b/packages/backend/package.json index ec6451f61..8564ca832 100644 --- a/packages/backend/package.json +++ b/packages/backend/package.json @@ -25,16 +25,16 @@ "@tensorflow/tfjs-node": "3.21.1" }, "dependencies": { - "@bull-board/api": "5.2.0", - "@bull-board/koa": "5.2.0", - "@bull-board/ui": "5.2.0", + "@bull-board/api": "5.6.0", + "@bull-board/koa": "5.6.0", + "@bull-board/ui": "5.6.0", "@discordapp/twemoji": "14.1.2", "@elastic/elasticsearch": "7.17.0", "@koa/cors": "3.4.3", "@koa/multer": "3.0.2", "@koa/router": "9.0.1", "@peertube/http-signature": "1.7.0", - "@redocly/openapi-core": "1.0.0-beta.120", + "@redocly/openapi-core": "1.0.0-beta.131", "@sinonjs/fake-timers": "9.1.2", "@syuilo/aiscript": "0.11.1", "@tensorflow/tfjs": "^4.2.0", @@ -42,20 +42,19 @@ "ajv": "8.12.0", "archiver": "5.3.1", "argon2": "^0.30.3", - "autobind-decorator": "2.4.0", "autolinker": "4.0.0", "autwh": "0.1.0", - "aws-sdk": "2.1277.0", + "aws-sdk": "2.1413.0", "axios": "^1.4.0", "bcryptjs": "2.4.3", - "blurhash": "1.1.5", + "blurhash": "2.0.5", "bull": "4.10.4", "cacheable-lookup": "7.0.0", "calckey-js": "workspace:*", "cbor": "8.1.0", - "chalk": "5.2.0", + "chalk": "5.3.0", "chalk-template": "0.4.0", - "chokidar": "3.5.3", + "chokidar": "^3.5.3", "cli-highlight": "2.1.11", "color-convert": "2.0.1", "content-disposition": "0.5.4", @@ -68,15 +67,16 @@ "got": "12.5.3", "hpagent": "0.1.2", "ioredis": "5.3.2", - "ip-cidr": "3.0.11", + "ip-cidr": "3.1.0", "is-svg": "4.3.2", "js-yaml": "4.1.0", "jsdom": "20.0.3", + "json5": "2.2.3", "jsonld": "8.2.0", - "jsrsasign": "10.6.1", - "koa": "2.13.4", + "jsrsasign": "10.8.6", + "koa": "2.14.2", "koa-body": "^6.0.1", - "koa-bodyparser": "4.3.0", + "koa-bodyparser": "4.4.1", "koa-favicon": "2.1.0", "koa-json-body": "5.3.0", "koa-logger": "3.2.1", @@ -98,9 +98,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", + "pg": "8.11.1", "private-ip": "2.3.4", "probe-image-size": "7.2.3", "promise-limit": "2.7.0", @@ -110,7 +110,7 @@ "qs": "6.11.2", "random-seed": "0.3.0", "ratelimiter": "3.4.1", - "re2": "1.19.0", + "re2": "1.19.1", "redis-lock": "0.1.4", "redis-semaphore": "5.3.1", "reflect-metadata": "0.1.13", @@ -119,7 +119,7 @@ "rss-parser": "3.13.0", "sanitize-html": "2.10.0", "seedrandom": "^3.0.5", - "semver": "7.5.1", + "semver": "7.5.4", "sharp": "0.32.1", "sonic-channel": "^1.3.1", "stringz": "2.1.0", @@ -130,27 +130,26 @@ "tinycolor2": "1.5.2", "tmp": "0.2.1", "twemoji-parser": "14.0.0", - "typeorm": "0.3.11", + "typeorm": "0.3.17", "ulid": "2.3.0", "uuid": "9.0.0", - "web-push": "3.6.1", + "web-push": "3.6.3", "websocket": "1.0.34", "xev": "3.0.2" }, "devDependencies": { "@swc/cli": "^0.1.62", - "@swc/core": "^1.3.62", + "@swc/core": "^1.3.68", "@types/adm-zip": "^0.5.0", "@types/bcryptjs": "2.4.2", - "@types/bull": "3.15.9", "@types/cbor": "6.0.0", "@types/escape-regexp": "0.0.1", - "@types/fluent-ffmpeg": "2.1.20", + "@types/fluent-ffmpeg": "2.1.21", "@types/js-yaml": "4.0.5", - "@types/jsdom": "20.0.1", - "@types/jsonld": "1.5.8", - "@types/jsrsasign": "10.5.4", - "@types/koa": "2.13.5", + "@types/jsdom": "21.1.1", + "@types/jsonld": "1.5.9", + "@types/jsrsasign": "10.5.8", + "@types/koa": "2.13.6", "@types/koa-bodyparser": "4.3.10", "@types/koa-cors": "0.0.2", "@types/koa-favicon": "2.0.21", @@ -169,7 +168,7 @@ "@types/probe-image-size": "^7.2.0", "@types/pug": "2.0.6", "@types/punycode": "2.1.0", - "@types/qrcode": "1.5.0", + "@types/qrcode": "1.5.1", "@types/qs": "6.9.7", "@types/random-seed": "0.3.3", "@types/ratelimiter": "3.4.4", @@ -177,29 +176,26 @@ "@types/rename": "1.0.4", "@types/sanitize-html": "2.9.0", "@types/semver": "7.5.0", - "@types/sharp": "0.31.1", "@types/sinonjs__fake-timers": "8.1.2", "@types/tinycolor2": "1.4.3", "@types/tmp": "0.2.3", - "@types/uuid": "8.3.4", + "@types/uuid": "9.0.2", "@types/web-push": "3.3.2", "@types/websocket": "1.0.5", - "@types/ws": "8.5.4", - "autobind-decorator": "2.4.0", + "@types/ws": "8.5.5", "cross-env": "7.0.3", - "eslint": "^8.42.0", + "eslint": "^8.44.0", "execa": "6.1.0", - "json5": "2.2.3", "json5-loader": "4.0.1", "mocha": "10.2.0", "pug": "3.0.2", "strict-event-emitter-types": "2.0.0", "swc-loader": "^0.2.3", - "ts-loader": "9.4.3", + "ts-loader": "9.4.4", "ts-node": "10.9.1", "tsconfig-paths": "4.2.0", - "typescript": "5.1.3", - "webpack": "^5.85.1", + "typescript": "5.1.6", + "webpack": "^5.88.1", "ws": "8.13.0" } } diff --git a/packages/backend/src/const.ts b/packages/backend/src/const.ts index 7e8f96444..2a955ee52 100644 --- a/packages/backend/src/const.ts +++ b/packages/backend/src/const.ts @@ -1,8 +1,13 @@ import config from "@/config/index.js"; -import { DB_MAX_IMAGE_COMMENT_LENGTH } from "@/misc/hard-limits.js"; +import { + DB_MAX_NOTE_TEXT_LENGTH, + DB_MAX_IMAGE_COMMENT_LENGTH, +} from "@/misc/hard-limits.js"; -export const MAX_NOTE_TEXT_LENGTH = - config.maxNoteLength != null ? config.maxNoteLength : 3000; // <- should we increase this? +export const MAX_NOTE_TEXT_LENGTH = Math.min( + config.maxNoteLength ?? 3000, + DB_MAX_NOTE_TEXT_LENGTH, +); export const MAX_CAPTION_TEXT_LENGTH = Math.min( config.maxCaptionLength ?? 1500, DB_MAX_IMAGE_COMMENT_LENGTH, diff --git a/packages/backend/src/misc/acct.ts b/packages/backend/src/misc/acct.ts index 5b7767a10..cb6808b4b 100644 --- a/packages/backend/src/misc/acct.ts +++ b/packages/backend/src/misc/acct.ts @@ -4,7 +4,7 @@ export type Acct = { }; export function parse(acct: string): Acct { - if (acct.startsWith("@")) acct = acct.substr(1); + if (acct.startsWith("@")) acct = acct.slice(1); const split = acct.split("@", 2); return { username: split[0], host: split[1] || null }; } diff --git a/packages/backend/src/misc/download-url.ts b/packages/backend/src/misc/download-url.ts index 7fafb635b..e9975f348 100644 --- a/packages/backend/src/misc/download-url.ts +++ b/packages/backend/src/misc/download-url.ts @@ -24,6 +24,7 @@ export async function downloadUrl(url: string, path: string): Promise { .stream(url, { headers: { "User-Agent": config.userAgent, + Host: new URL(url).hostname, }, timeout: { lookup: timeout, diff --git a/packages/backend/src/misc/hard-limits.ts b/packages/backend/src/misc/hard-limits.ts index 51d2c0f5d..5ce3e0ac9 100644 --- a/packages/backend/src/misc/hard-limits.ts +++ b/packages/backend/src/misc/hard-limits.ts @@ -3,8 +3,13 @@ /** * Maximum note text length that can be stored in DB. * Surrogate pairs count as one + * + * NOTE: this can hypothetically be pushed further + * (up to 250000000), but will likely cause truncations + * and incompatibilities with other servers, + * as well as potential performance issues. */ -export const DB_MAX_NOTE_TEXT_LENGTH = 8192; +export const DB_MAX_NOTE_TEXT_LENGTH = 100000; /** * Maximum image description length that can be stored in DB. diff --git a/packages/backend/src/misc/nyaize.ts b/packages/backend/src/misc/nyaize.ts index dd0c5bbdf..13a112ce5 100644 --- a/packages/backend/src/misc/nyaize.ts +++ b/packages/backend/src/misc/nyaize.ts @@ -20,5 +20,9 @@ export function nyaize(text: string): string { ) .replace(/(다$)|(다(?=\.))|(다(?= ))|(다(?=!))|(다(?=\?))/gm, "다냥") .replace(/(야(?=\?))|(야$)|(야(?= ))/gm, "냥") + // el-GR + .replaceAll("να", "νια") + .replaceAll("ΝΑ", "ΝΙΑ") + .replaceAll("Να", "Νια") ); } diff --git a/packages/backend/src/models/entities/meta.ts b/packages/backend/src/models/entities/meta.ts index 200ef5055..e90a5269a 100644 --- a/packages/backend/src/models/entities/meta.ts +++ b/packages/backend/src/models/entities/meta.ts @@ -326,13 +326,13 @@ export class Meta { public smtpPort: number | null; @Column("varchar", { - length: 128, + length: 1024, nullable: true, }) public smtpUser: string | null; @Column("varchar", { - length: 128, + length: 1024, nullable: true, }) public smtpPass: string | null; @@ -556,4 +556,10 @@ export class Meta { default: true, }) public enableIdenticonGeneration: boolean; + + @Column("varchar", { + length: 256, + nullable: true, + }) + public donationLink: string | null; } diff --git a/packages/backend/src/models/repositories/user.ts b/packages/backend/src/models/repositories/user.ts index 1f9cd80fb..e7c4b6f00 100644 --- a/packages/backend/src/models/repositories/user.ts +++ b/packages/backend/src/models/repositories/user.ts @@ -453,6 +453,7 @@ export const UserRepository = db.getRepository(User).extend({ isAdmin: user.isAdmin || falsy, isModerator: user.isModerator || falsy, isBot: user.isBot || falsy, + isLocked: user.isLocked, isCat: user.isCat || falsy, speakAsCat: user.speakAsCat || falsy, instance: user.host @@ -497,7 +498,6 @@ export const UserRepository = db.getRepository(User).extend({ : null, bannerBlurhash: user.banner?.blurhash || null, bannerColor: null, // 後方互換性のため - isLocked: user.isLocked, isSilenced: user.isSilenced || falsy, isSuspended: user.isSuspended || falsy, description: profile!.description, diff --git a/packages/backend/src/queue/processors/background/index-all-notes.ts b/packages/backend/src/queue/processors/background/index-all-notes.ts index 1dce4406a..c0275b420 100644 --- a/packages/backend/src/queue/processors/background/index-all-notes.ts +++ b/packages/backend/src/queue/processors/background/index-all-notes.ts @@ -1,4 +1,5 @@ import type Bull from "bull"; +import type { DoneCallback } from "bull"; import { queueLogger } from "../../logger.js"; import { Notes } from "@/models/index.js"; @@ -11,7 +12,7 @@ const logger = queueLogger.createSubLogger("index-all-notes"); export default async function indexAllNotes( job: Bull.Job>, - done: () => void, + done: DoneCallback, ): Promise { logger.info("Indexing all notes..."); @@ -20,7 +21,7 @@ export default async function indexAllNotes( let total: number = (job.data.total as number) ?? 0; let running = true; - const take = 100000; + const take = 10000; const batch = 100; while (running) { logger.info( @@ -41,13 +42,14 @@ export default async function indexAllNotes( }, relations: ["user"], }); - } catch (e) { + } catch (e: any) { logger.error(`Failed to query notes ${e}`); - continue; + done(e); + break; } if (notes.length === 0) { - job.progress(100); + await job.progress(100); running = false; break; } @@ -55,7 +57,7 @@ export default async function indexAllNotes( try { const count = await Notes.count(); total = count; - job.update({ indexedCount, cursor, total }); + await job.update({ indexedCount, cursor, total }); } catch (e) {} for (let i = 0; i < notes.length; i += batch) { @@ -69,12 +71,12 @@ export default async function indexAllNotes( indexedCount += chunk.length; const pct = (indexedCount / total) * 100; - job.update({ indexedCount, cursor, total }); - job.progress(+pct.toFixed(1)); + await job.update({ indexedCount, cursor, total }); + await job.progress(+pct.toFixed(1)); logger.info(`Indexed notes ${indexedCount}/${total ? total : "?"}`); } cursor = notes[notes.length - 1].id; - job.update({ indexedCount, cursor, total }); + await job.update({ indexedCount, cursor, total }); if (notes.length < take) { running = false; diff --git a/packages/backend/src/queue/processors/db/export-notes.ts b/packages/backend/src/queue/processors/db/export-notes.ts index de8fac05b..bf53f8360 100644 --- a/packages/backend/src/queue/processors/db/export-notes.ts +++ b/packages/backend/src/queue/processors/db/export-notes.ts @@ -4,7 +4,7 @@ import * as fs from "node:fs"; import { queueLogger } from "../../logger.js"; import { addFile } from "@/services/drive/add-file.js"; import { format as dateFormat } from "date-fns"; -import { Users, Notes, Polls } from "@/models/index.js"; +import { Users, Notes, Polls, DriveFiles } from "@/models/index.js"; import { MoreThan } from "typeorm"; import type { Note } from "@/models/entities/note.js"; import type { Poll } from "@/models/entities/poll.js"; @@ -75,7 +75,7 @@ export async function exportNotes( if (note.hasPoll) { poll = await Polls.findOneByOrFail({ noteId: note.id }); } - const content = JSON.stringify(serialize(note, poll)); + const content = JSON.stringify(await serialize(note, poll)); const isFirst = exportedNotesCount === 0; await write(isFirst ? content : ",\n" + content); exportedNotesCount++; @@ -112,15 +112,16 @@ export async function exportNotes( done(); } -function serialize( +async function serialize( note: Note, poll: Poll | null = null, -): Record { +): Promise> { return { id: note.id, text: note.text, createdAt: note.createdAt, fileIds: note.fileIds, + files: await DriveFiles.packMany(note.fileIds), replyId: note.replyId, renoteId: note.renoteId, poll: poll, diff --git a/packages/backend/src/queue/processors/db/import-calckey-post.ts b/packages/backend/src/queue/processors/db/import-calckey-post.ts index 28e794aa0..945c50d63 100644 --- a/packages/backend/src/queue/processors/db/import-calckey-post.ts +++ b/packages/backend/src/queue/processors/db/import-calckey-post.ts @@ -3,6 +3,8 @@ import create from "@/services/note/create.js"; import { Users } from "@/models/index.js"; import type { DbUserImportMastoPostJobData } from "@/queue/types.js"; import { queueLogger } from "../../logger.js"; +import { uploadFromUrl } from "@/services/drive/upload-from-url.js"; +import type { DriveFile } from "@/models/entities/drive-file.js"; import type Bull from "bull"; const logger = queueLogger.createSubLogger("import-calckey-post"); @@ -29,10 +31,25 @@ export async function importCkPost( done(); return; } + const urls = (post.files || []) + .map((x: any) => x.url) + .filter((x: String) => x.startsWith("http")); + const files: DriveFile[] = []; + for (const url of urls) { + try { + const file = await uploadFromUrl({ + url: url, + user: user, + }); + files.push(file); + } catch (e) { + logger.error(`Skipped adding file to drive: ${url}`); + } + } const { text, cw, localOnly, createdAt } = Post.parse(post); const note = await create(user, { createdAt: createdAt, - files: undefined, + files: files.length == 0 ? undefined : files, poll: undefined, text: text || undefined, reply: null, diff --git a/packages/backend/src/queue/processors/db/import-masto-post.ts b/packages/backend/src/queue/processors/db/import-masto-post.ts index 317ba7b1b..05166b085 100644 --- a/packages/backend/src/queue/processors/db/import-masto-post.ts +++ b/packages/backend/src/queue/processors/db/import-masto-post.ts @@ -6,6 +6,8 @@ import type Bull from "bull"; import { htmlToMfm } from "@/remote/activitypub/misc/html-to-mfm.js"; import { resolveNote } from "@/remote/activitypub/models/note.js"; import { Note } from "@/models/entities/note.js"; +import { uploadFromUrl } from "@/services/drive/upload-from-url.js"; +import type { DriveFile } from "@/models/entities/drive-file.js"; const logger = queueLogger.createSubLogger("import-masto-post"); @@ -43,14 +45,30 @@ export async function importMastoPost( throw e; } job.progress(80); + const urls = post.object.attachment + .map((x: any) => x.url) + .filter((x: String) => x.startsWith("http")); + const files: DriveFile[] = []; + for (const url of urls) { + try { + const file = await uploadFromUrl({ + url: url, + user: user, + }); + files.push(file); + } catch (e) { + logger.error(`Skipped adding file to drive: ${url}`); + } + } + const note = await create(user, { createdAt: new Date(post.object.published), - files: undefined, + files: files.length == 0 ? undefined : files, poll: undefined, text: text || undefined, reply, renote: null, - cw: post.sensitive, + cw: post.object.sensitive ? post.object.summary : undefined, localOnly: false, visibility: "hidden", visibleUsers: [], diff --git a/packages/backend/src/remote/activitypub/models/person.ts b/packages/backend/src/remote/activitypub/models/person.ts index c5519ba03..14abf3b1d 100644 --- a/packages/backend/src/remote/activitypub/models/person.ts +++ b/packages/backend/src/remote/activitypub/models/person.ts @@ -147,11 +147,11 @@ export async function fetchPerson( } //#region Returns if already registered with this server - const exist = await Users.findOneBy({ uri }); + const user = await Users.findOneBy({ uri }); - if (exist) { - await uriPersonCache.set(uri, exist); - return exist; + if (user != null) { + await uriPersonCache.set(uri, user); + return user; } //#endregion @@ -396,9 +396,9 @@ export async function updatePerson( } //#region Already registered on this server? - const exist = (await Users.findOneBy({ uri })) as IRemoteUser; + const user = (await Users.findOneBy({ uri })) as IRemoteUser; - if (exist == null) { + if (user == null) { return; } //#endregion @@ -416,17 +416,15 @@ export async function updatePerson( [person.icon, person.image].map((img) => img == null ? Promise.resolve(null) - : resolveImage(exist, img).catch(() => null), + : resolveImage(user, img).catch(() => null), ), ); // Custom pictogram acquisition - const emojis = await extractEmojis(person.tag || [], exist.host).catch( - (e) => { - logger.info(`extractEmojis: ${e}`); - return [] as Emoji[]; - }, - ); + const emojis = await extractEmojis(person.tag || [], user.host).catch((e) => { + logger.info(`extractEmojis: ${e}`); + return [] as Emoji[]; + }); const emojiNames = emojis.map((emoji) => emoji.name); @@ -518,11 +516,11 @@ export async function updatePerson( } // Update user - await Users.update(exist.id, updates); + await Users.update(user.id, updates); if (person.publicKey) { await UserPublickeys.update( - { userId: exist.id }, + { userId: user.id }, { keyId: person.publicKey.id, keyPem: person.publicKey.publicKeyPem, @@ -531,7 +529,7 @@ export async function updatePerson( } await UserProfiles.update( - { userId: exist.id }, + { userId: user.id }, { url: url, fields, @@ -543,15 +541,15 @@ export async function updatePerson( }, ); - publishInternalEvent("remoteUserUpdated", { id: exist.id }); + publishInternalEvent("remoteUserUpdated", { id: user.id }); // Hashtag Update - updateUsertags(exist, tags); + updateUsertags(user, tags); // If the user in question is a follower, followers will also be updated. await Followings.update( { - followerId: exist.id, + followerId: user.id, }, { followerSharedInbox: @@ -560,7 +558,7 @@ export async function updatePerson( }, ); - await updateFeatured(exist.id, resolver).catch((err) => logger.error(err)); + await updateFeatured(user.id, resolver).catch((err) => logger.error(err)); } /** @@ -576,10 +574,10 @@ export async function resolvePerson( if (typeof uri !== "string") throw new Error("uri is not string"); //#region If already registered on this server, return it. - const exist = await fetchPerson(uri); + const user = await fetchPerson(uri); - if (exist) { - return exist; + if (user != null) { + return user; } //#endregion diff --git a/packages/backend/src/server/api/endpoints/admin/meta.ts b/packages/backend/src/server/api/endpoints/admin/meta.ts index 50317d4a8..9abb57b1b 100644 --- a/packages/backend/src/server/api/endpoints/admin/meta.ts +++ b/packages/backend/src/server/api/endpoints/admin/meta.ts @@ -491,6 +491,11 @@ export const meta = { optional: false, nullable: false, }, + donationLink: { + type: "string", + optional: true, + nullable: true, + }, }, }, } as const; @@ -604,5 +609,6 @@ export default define(meta, paramDef, async (ps, me) => { experimentalFeatures: instance.experimentalFeatures, enableServerMachineStats: instance.enableServerMachineStats, enableIdenticonGeneration: instance.enableIdenticonGeneration, + donationLink: instance.donationLink, }; }); diff --git a/packages/backend/src/server/api/endpoints/admin/promo/create.ts b/packages/backend/src/server/api/endpoints/admin/promo/create.ts index a6d1f3519..00244a777 100644 --- a/packages/backend/src/server/api/endpoints/admin/promo/create.ts +++ b/packages/backend/src/server/api/endpoints/admin/promo/create.ts @@ -40,9 +40,9 @@ export default define(meta, paramDef, async (ps, user) => { throw err; }); - const exist = await PromoNotes.findOneBy({ noteId: note.id }); + const exist = await PromoNotes.exist({ where: { noteId: note.id } }); - if (exist != null) { + if (exist) { throw new ApiError(meta.errors.alreadyPromoted); } diff --git a/packages/backend/src/server/api/endpoints/admin/update-meta.ts b/packages/backend/src/server/api/endpoints/admin/update-meta.ts index cf22c6c48..2142c7df7 100644 --- a/packages/backend/src/server/api/endpoints/admin/update-meta.ts +++ b/packages/backend/src/server/api/endpoints/admin/update-meta.ts @@ -1,6 +1,5 @@ import { Meta } from "@/models/entities/meta.js"; import { insertModerationLog } from "@/services/insert-moderation-log.js"; -import { DB_MAX_NOTE_TEXT_LENGTH } from "@/misc/hard-limits.js"; import { db } from "@/db/postgre.js"; import define from "../../define.js"; @@ -177,6 +176,9 @@ export const paramDef = { postImports: { type: "boolean" }, }, }, + enableServerMachineStats: { type: "boolean" }, + enableIdenticonGeneration: { type: "boolean" }, + donationLink: { type: "string", nullable: true }, }, required: [], } as const; @@ -218,6 +220,15 @@ export default define(meta, paramDef, async (ps, me) => { if (Array.isArray(ps.recommendedInstances)) { set.recommendedInstances = ps.recommendedInstances.filter(Boolean); + if (set.recommendedInstances?.length > 0) { + set.recommendedInstances.forEach((instance, index) => { + if (/^https?:\/\//i.test(instance)) { + set.recommendedInstances![index] = instance + .replace(/^https?:\/\//i, "") + .replace(/\/$/, ""); + } + }); + } } if (Array.isArray(ps.hiddenTags)) { @@ -568,6 +579,21 @@ export default define(meta, paramDef, async (ps, me) => { set.experimentalFeatures = ps.experimentalFeatures || undefined; } + if (ps.enableServerMachineStats !== undefined) { + set.enableServerMachineStats = ps.enableServerMachineStats; + } + + if (ps.enableIdenticonGeneration !== undefined) { + set.enableIdenticonGeneration = ps.enableIdenticonGeneration; + } + + if (ps.donationLink !== undefined) { + set.donationLink = ps.donationLink; + if (set.donationLink && !/^https?:\/\//i.test(set.donationLink)) { + set.donationLink = `https://${set.donationLink}`; + } + } + await db.transaction(async (transactionalEntityManager) => { const metas = await transactionalEntityManager.find(Meta, { order: { diff --git a/packages/backend/src/server/api/endpoints/auth/accept.ts b/packages/backend/src/server/api/endpoints/auth/accept.ts index 35565e256..8e6ad6527 100644 --- a/packages/backend/src/server/api/endpoints/auth/accept.ts +++ b/packages/backend/src/server/api/endpoints/auth/accept.ts @@ -41,12 +41,14 @@ export default define(meta, paramDef, async (ps, user) => { const accessToken = secureRndstr(32, true); // Fetch exist access token - const exist = await AccessTokens.findOneBy({ - appId: session.appId, - userId: user.id, + const exist = await AccessTokens.exist({ + where: { + appId: session.appId, + userId: user.id, + }, }); - if (exist == null) { + if (!exist) { // Lookup app const app = await Apps.findOneByOrFail({ id: session.appId }); diff --git a/packages/backend/src/server/api/endpoints/blocking/create.ts b/packages/backend/src/server/api/endpoints/blocking/create.ts index 4bd58d5ef..f00a2923d 100644 --- a/packages/backend/src/server/api/endpoints/blocking/create.ts +++ b/packages/backend/src/server/api/endpoints/blocking/create.ts @@ -69,12 +69,14 @@ export default define(meta, paramDef, async (ps, user) => { }); // Check if already blocking - const exist = await Blockings.findOneBy({ - blockerId: blocker.id, - blockeeId: blockee.id, + const exist = await Blockings.exist({ + where: { + blockerId: blocker.id, + blockeeId: blockee.id, + }, }); - if (exist != null) { + if (exist) { throw new ApiError(meta.errors.alreadyBlocking); } diff --git a/packages/backend/src/server/api/endpoints/blocking/delete.ts b/packages/backend/src/server/api/endpoints/blocking/delete.ts index 6c4ca2775..037d5af22 100644 --- a/packages/backend/src/server/api/endpoints/blocking/delete.ts +++ b/packages/backend/src/server/api/endpoints/blocking/delete.ts @@ -69,12 +69,14 @@ export default define(meta, paramDef, async (ps, user) => { }); // Check not blocking - const exist = await Blockings.findOneBy({ - blockerId: blocker.id, - blockeeId: blockee.id, + const exist = await Blockings.exist({ + where: { + blockerId: blocker.id, + blockeeId: blockee.id, + }, }); - if (exist == null) { + if (!exist) { throw new ApiError(meta.errors.notBlocking); } diff --git a/packages/backend/src/server/api/endpoints/clips/add-note.ts b/packages/backend/src/server/api/endpoints/clips/add-note.ts index b9d6b54c9..416af6faa 100644 --- a/packages/backend/src/server/api/endpoints/clips/add-note.ts +++ b/packages/backend/src/server/api/endpoints/clips/add-note.ts @@ -57,12 +57,14 @@ export default define(meta, paramDef, async (ps, user) => { throw err; }); - const exist = await ClipNotes.findOneBy({ - noteId: note.id, - clipId: clip.id, + const exist = await ClipNotes.exist({ + where: { + noteId: note.id, + clipId: clip.id, + }, }); - if (exist != null) { + if (exist) { throw new ApiError(meta.errors.alreadyClipped); } diff --git a/packages/backend/src/server/api/endpoints/drive/files/check-existence.ts b/packages/backend/src/server/api/endpoints/drive/files/check-existence.ts index df8968520..e26da30eb 100644 --- a/packages/backend/src/server/api/endpoints/drive/files/check-existence.ts +++ b/packages/backend/src/server/api/endpoints/drive/files/check-existence.ts @@ -26,10 +26,12 @@ export const paramDef = { } as const; export default define(meta, paramDef, async (ps, user) => { - const file = await DriveFiles.findOneBy({ - md5: ps.md5, - userId: user.id, + const exist = await DriveFiles.exist({ + where: { + md5: ps.md5, + userId: user.id, + }, }); - return file != null; + return exist; }); diff --git a/packages/backend/src/server/api/endpoints/following/create.ts b/packages/backend/src/server/api/endpoints/following/create.ts index e617c1ffb..48ae6ae7a 100644 --- a/packages/backend/src/server/api/endpoints/following/create.ts +++ b/packages/backend/src/server/api/endpoints/following/create.ts @@ -82,12 +82,14 @@ export default define(meta, paramDef, async (ps, user) => { }); // Check if already following - const exist = await Followings.findOneBy({ - followerId: follower.id, - followeeId: followee.id, + const exist = await Followings.exist({ + where: { + followerId: follower.id, + followeeId: followee.id, + }, }); - if (exist != null) { + if (exist) { throw new ApiError(meta.errors.alreadyFollowing); } diff --git a/packages/backend/src/server/api/endpoints/following/delete.ts b/packages/backend/src/server/api/endpoints/following/delete.ts index 2eebe8a90..cbc6097f4 100644 --- a/packages/backend/src/server/api/endpoints/following/delete.ts +++ b/packages/backend/src/server/api/endpoints/following/delete.ts @@ -69,12 +69,14 @@ export default define(meta, paramDef, async (ps, user) => { }); // Check not following - const exist = await Followings.findOneBy({ - followerId: follower.id, - followeeId: followee.id, + const exist = await Followings.exist({ + where: { + followerId: follower.id, + followeeId: followee.id, + }, }); - if (exist == null) { + if (!exist) { throw new ApiError(meta.errors.notFollowing); } diff --git a/packages/backend/src/server/api/endpoints/following/invalidate.ts b/packages/backend/src/server/api/endpoints/following/invalidate.ts index 979d298f7..01ccc2761 100644 --- a/packages/backend/src/server/api/endpoints/following/invalidate.ts +++ b/packages/backend/src/server/api/endpoints/following/invalidate.ts @@ -69,12 +69,14 @@ export default define(meta, paramDef, async (ps, user) => { }); // Check not following - const exist = await Followings.findOneBy({ - followerId: follower.id, - followeeId: followee.id, + const exist = await Followings.exist({ + where: { + followerId: follower.id, + followeeId: followee.id, + }, }); - if (exist == null) { + if (!exist) { throw new ApiError(meta.errors.notFollowing); } diff --git a/packages/backend/src/server/api/endpoints/gallery/posts/like.ts b/packages/backend/src/server/api/endpoints/gallery/posts/like.ts index fd46406bd..2506e40aa 100644 --- a/packages/backend/src/server/api/endpoints/gallery/posts/like.ts +++ b/packages/backend/src/server/api/endpoints/gallery/posts/like.ts @@ -40,12 +40,14 @@ export default define(meta, paramDef, async (ps, user) => { } // if already liked - const exist = await GalleryLikes.findOneBy({ - postId: post.id, - userId: user.id, + const exist = await GalleryLikes.exist({ + where: { + postId: post.id, + userId: user.id, + }, }); - if (exist != null) { + if (exist) { throw new ApiError(meta.errors.alreadyLiked); } diff --git a/packages/backend/src/server/api/endpoints/gallery/posts/unlike.ts b/packages/backend/src/server/api/endpoints/gallery/posts/unlike.ts index 772dc9202..03bc299b9 100644 --- a/packages/backend/src/server/api/endpoints/gallery/posts/unlike.ts +++ b/packages/backend/src/server/api/endpoints/gallery/posts/unlike.ts @@ -38,17 +38,17 @@ export default define(meta, paramDef, async (ps, user) => { throw new ApiError(meta.errors.noSuchPost); } - const exist = await GalleryLikes.findOneBy({ + const like = await GalleryLikes.findOneBy({ postId: post.id, userId: user.id, }); - if (exist == null) { + if (like == null) { throw new ApiError(meta.errors.notLiked); } // Delete like - await GalleryLikes.delete(exist.id); + await GalleryLikes.delete(like.id); GalleryPosts.decrement({ id: post.id }, "likedCount", 1); }); diff --git a/packages/backend/src/server/api/endpoints/i/read-announcement.ts b/packages/backend/src/server/api/endpoints/i/read-announcement.ts index 5218dba87..d0dfa6657 100644 --- a/packages/backend/src/server/api/endpoints/i/read-announcement.ts +++ b/packages/backend/src/server/api/endpoints/i/read-announcement.ts @@ -30,19 +30,23 @@ export const paramDef = { export default define(meta, paramDef, async (ps, user) => { // Check if announcement exists - const announcement = await Announcements.findOneBy({ id: ps.announcementId }); + const exist = await Announcements.exist({ + where: { id: ps.announcementId }, + }); - if (announcement == null) { + if (!exist) { throw new ApiError(meta.errors.noSuchAnnouncement); } // Check if already read - const read = await AnnouncementReads.findOneBy({ - announcementId: ps.announcementId, - userId: user.id, + const read = await AnnouncementReads.exist({ + where: { + announcementId: ps.announcementId, + userId: user.id, + }, }); - if (read != null) { + if (read) { return; } diff --git a/packages/backend/src/server/api/endpoints/i/revoke-token.ts b/packages/backend/src/server/api/endpoints/i/revoke-token.ts index 308442bf7..3a410fa0e 100644 --- a/packages/backend/src/server/api/endpoints/i/revoke-token.ts +++ b/packages/backend/src/server/api/endpoints/i/revoke-token.ts @@ -17,9 +17,9 @@ export const paramDef = { } as const; export default define(meta, paramDef, async (ps, user) => { - const token = await AccessTokens.findOneBy({ id: ps.tokenId }); + const exist = await AccessTokens.exist({ where: { id: ps.tokenId } }); - if (token) { + if (exist) { await AccessTokens.delete({ id: ps.tokenId, userId: user.id, diff --git a/packages/backend/src/server/api/endpoints/meta.ts b/packages/backend/src/server/api/endpoints/meta.ts index 673a0266c..03b0da401 100644 --- a/packages/backend/src/server/api/endpoints/meta.ts +++ b/packages/backend/src/server/api/endpoints/meta.ts @@ -389,6 +389,11 @@ export const meta = { nullable: false, default: "⭐", }, + donationLink: { + type: "string", + optional: "true", + nullable: true, + }, }, }, } as const; @@ -491,6 +496,7 @@ export default define(meta, paramDef, async (ps, me) => { translatorAvailable: instance.deeplAuthKey != null || instance.libreTranslateApiUrl != null, defaultReaction: instance.defaultReaction, + donationLink: instance.donationLink, ...(ps.detail ? { diff --git a/packages/backend/src/server/api/endpoints/mute/create.ts b/packages/backend/src/server/api/endpoints/mute/create.ts index bacab9b45..7b2f10905 100644 --- a/packages/backend/src/server/api/endpoints/mute/create.ts +++ b/packages/backend/src/server/api/endpoints/mute/create.ts @@ -64,12 +64,14 @@ export default define(meta, paramDef, async (ps, user) => { }); // Check if already muting - const exist = await Mutings.findOneBy({ - muterId: muter.id, - muteeId: mutee.id, + const exist = await Mutings.exist({ + where: { + muterId: muter.id, + muteeId: mutee.id, + }, }); - if (exist != null) { + if (exist) { throw new ApiError(meta.errors.alreadyMuting); } diff --git a/packages/backend/src/server/api/endpoints/mute/delete.ts b/packages/backend/src/server/api/endpoints/mute/delete.ts index cc67a44c2..cd00c1a8a 100644 --- a/packages/backend/src/server/api/endpoints/mute/delete.ts +++ b/packages/backend/src/server/api/endpoints/mute/delete.ts @@ -56,18 +56,18 @@ export default define(meta, paramDef, async (ps, user) => { }); // Check not muting - const exist = await Mutings.findOneBy({ + const muting = await Mutings.findOneBy({ muterId: muter.id, muteeId: mutee.id, }); - if (exist == null) { + if (muting == null) { throw new ApiError(meta.errors.notMuting); } // Delete mute await Mutings.delete({ - id: exist.id, + id: muting.id, }); publishUserEvent(user.id, "unmute", mutee); diff --git a/packages/backend/src/server/api/endpoints/notes/children.ts b/packages/backend/src/server/api/endpoints/notes/children.ts index 9047fcce1..a35b17a02 100644 --- a/packages/backend/src/server/api/endpoints/notes/children.ts +++ b/packages/backend/src/server/api/endpoints/notes/children.ts @@ -1,4 +1,3 @@ -import { Brackets } from "typeorm"; import { Notes } from "@/models/index.js"; import define from "../../define.js"; import { makePaginationQuery } from "../../common/make-pagination-query.js"; @@ -11,6 +10,7 @@ export const meta = { requireCredential: false, requireCredentialPrivateMode: true, + description: "Get threaded/chained replies to a note", res: { type: "array", @@ -23,13 +23,14 @@ export const meta = { ref: "Note", }, }, -}; +} as const; export const paramDef = { type: "object", properties: { noteId: { type: "string", format: "misskey:id" }, limit: { type: "integer", minimum: 1, maximum: 100, default: 10 }, + depth: { type: "integer", minimum: 1, maximum: 100, default: 12 }, sinceId: { type: "string", format: "misskey:id" }, untilId: { type: "string", format: "misskey:id" }, }, diff --git a/packages/backend/src/server/api/endpoints/notes/conversation.ts b/packages/backend/src/server/api/endpoints/notes/conversation.ts index 2e8f5ef73..c74da2ec7 100644 --- a/packages/backend/src/server/api/endpoints/notes/conversation.ts +++ b/packages/backend/src/server/api/endpoints/notes/conversation.ts @@ -9,6 +9,7 @@ export const meta = { requireCredential: false, requireCredentialPrivateMode: true, + description: "Get conversation of a note thread/chain by a reply", res: { type: "array", @@ -34,7 +35,11 @@ export const meta = { export const paramDef = { type: "object", properties: { - noteId: { type: "string", format: "misskey:id" }, + noteId: { + type: "string", + format: "misskey:id", + description: "Should be a reply", + }, limit: { type: "integer", minimum: 1, maximum: 100, default: 10 }, offset: { type: "integer", default: 0 }, }, @@ -51,7 +56,7 @@ export default define(meta, paramDef, async (ps, user) => { const conversation: Note[] = []; let i = 0; - async function get(id: any) { + async function get(id: string) { i++; const p = await getNote(id, user).catch((e) => { if (e.id === "9725d0ce-ba28-4dde-95a7-2cbb2c15de24") return null; @@ -60,7 +65,7 @@ export default define(meta, paramDef, async (ps, user) => { if (p == null) return; - if (i > ps.offset!) { + if (i > ps.offset) { conversation.push(p); } diff --git a/packages/backend/src/server/api/endpoints/notes/create.ts b/packages/backend/src/server/api/endpoints/notes/create.ts index 41b8ab979..e15221046 100644 --- a/packages/backend/src/server/api/endpoints/notes/create.ts +++ b/packages/backend/src/server/api/endpoints/notes/create.ts @@ -224,11 +224,13 @@ export default define(meta, paramDef, async (ps, user) => { // Check blocking if (renote.userId !== user.id) { - const block = await Blockings.findOneBy({ - blockerId: renote.userId, - blockeeId: user.id, + const isBlocked = await Blockings.exist({ + where: { + blockerId: renote.userId, + blockeeId: user.id, + }, }); - if (block) { + if (isBlocked) { throw new ApiError(meta.errors.youHaveBeenBlocked); } } @@ -249,11 +251,13 @@ export default define(meta, paramDef, async (ps, user) => { // Check blocking if (reply.userId !== user.id) { - const block = await Blockings.findOneBy({ - blockerId: reply.userId, - blockeeId: user.id, + const isBlocked = await Blockings.exist({ + where: { + blockerId: reply.userId, + blockeeId: user.id, + }, }); - if (block) { + if (isBlocked) { throw new ApiError(meta.errors.youHaveBeenBlocked); } } diff --git a/packages/backend/src/server/api/endpoints/notes/favorites/create.ts b/packages/backend/src/server/api/endpoints/notes/favorites/create.ts index 835594f03..64862a373 100644 --- a/packages/backend/src/server/api/endpoints/notes/favorites/create.ts +++ b/packages/backend/src/server/api/endpoints/notes/favorites/create.ts @@ -43,12 +43,14 @@ export default define(meta, paramDef, async (ps, user) => { }); // if already favorited - const exist = await NoteFavorites.findOneBy({ - noteId: note.id, - userId: user.id, + const exist = await NoteFavorites.exist({ + where: { + noteId: note.id, + userId: user.id, + }, }); - if (exist != null) { + if (exist) { throw new ApiError(meta.errors.alreadyFavorited); } diff --git a/packages/backend/src/server/api/endpoints/notes/favorites/delete.ts b/packages/backend/src/server/api/endpoints/notes/favorites/delete.ts index 9a0976748..e05d04a96 100644 --- a/packages/backend/src/server/api/endpoints/notes/favorites/delete.ts +++ b/packages/backend/src/server/api/endpoints/notes/favorites/delete.ts @@ -42,15 +42,15 @@ export default define(meta, paramDef, async (ps, user) => { }); // if already favorited - const exist = await NoteFavorites.findOneBy({ + const favorite = await NoteFavorites.findOneBy({ noteId: note.id, userId: user.id, }); - if (exist == null) { + if (favorite == null) { throw new ApiError(meta.errors.notFavorited); } // Delete favorite - await NoteFavorites.delete(exist.id); + await NoteFavorites.delete(favorite.id); }); diff --git a/packages/backend/src/server/api/endpoints/notes/show.ts b/packages/backend/src/server/api/endpoints/notes/show.ts index 39d128134..8c5f91c5c 100644 --- a/packages/backend/src/server/api/endpoints/notes/show.ts +++ b/packages/backend/src/server/api/endpoints/notes/show.ts @@ -21,6 +21,7 @@ export const meta = { message: "No such note.", code: "NO_SUCH_NOTE", id: "24fcbfc6-2e37-42b6-8388-c29b3861a08d", + httpStatusCode: 404, }, }, } as const; diff --git a/packages/backend/src/server/api/endpoints/pages/like.ts b/packages/backend/src/server/api/endpoints/pages/like.ts index f14ed39eb..03482c961 100644 --- a/packages/backend/src/server/api/endpoints/pages/like.ts +++ b/packages/backend/src/server/api/endpoints/pages/like.ts @@ -40,12 +40,14 @@ export default define(meta, paramDef, async (ps, user) => { } // if already liked - const exist = await PageLikes.findOneBy({ - pageId: page.id, - userId: user.id, + const exist = await PageLikes.exist({ + where: { + pageId: page.id, + userId: user.id, + }, }); - if (exist != null) { + if (exist) { throw new ApiError(meta.errors.alreadyLiked); } diff --git a/packages/backend/src/server/api/endpoints/pages/unlike.ts b/packages/backend/src/server/api/endpoints/pages/unlike.ts index 07bf3fbf4..e607d7a54 100644 --- a/packages/backend/src/server/api/endpoints/pages/unlike.ts +++ b/packages/backend/src/server/api/endpoints/pages/unlike.ts @@ -38,17 +38,17 @@ export default define(meta, paramDef, async (ps, user) => { throw new ApiError(meta.errors.noSuchPage); } - const exist = await PageLikes.findOneBy({ + const like = await PageLikes.findOneBy({ pageId: page.id, userId: user.id, }); - if (exist == null) { + if (like == null) { throw new ApiError(meta.errors.notLiked); } // Delete like - await PageLikes.delete(exist.id); + await PageLikes.delete(like.id); Pages.decrement({ id: page.id }, "likedCount", 1); }); diff --git a/packages/backend/src/server/api/endpoints/patrons.ts b/packages/backend/src/server/api/endpoints/patrons.ts index 696d0e338..8ca1f8902 100644 --- a/packages/backend/src/server/api/endpoints/patrons.ts +++ b/packages/backend/src/server/api/endpoints/patrons.ts @@ -9,7 +9,7 @@ const _dirname = dirname(_filename); export const meta = { tags: ["meta"], - description: "Get list of Calckey patrons from Codeberg", + description: "Get Calckey patrons", requireCredential: false, requireCredentialPrivateMode: false, @@ -51,6 +51,8 @@ export default define(meta, paramDef, async (ps) => { }); await redisClient.set("patrons", JSON.stringify(patrons), "EX", 3600); } - - return patrons["patrons"]; + return { + patrons: patrons["patrons"], + sponsors: patrons["sponsors"], + }; }); diff --git a/packages/backend/src/server/api/endpoints/promo/read.ts b/packages/backend/src/server/api/endpoints/promo/read.ts index 09c8cb6fa..5310382a4 100644 --- a/packages/backend/src/server/api/endpoints/promo/read.ts +++ b/packages/backend/src/server/api/endpoints/promo/read.ts @@ -33,12 +33,14 @@ export default define(meta, paramDef, async (ps, user) => { throw err; }); - const exist = await PromoReads.findOneBy({ - noteId: note.id, - userId: user.id, + const exist = await PromoReads.exist({ + where: { + noteId: note.id, + userId: user.id, + }, }); - if (exist != null) { + if (exist) { return; } diff --git a/packages/backend/src/server/api/endpoints/renote-mute/create.ts b/packages/backend/src/server/api/endpoints/renote-mute/create.ts index 857cbd975..f09f197c0 100644 --- a/packages/backend/src/server/api/endpoints/renote-mute/create.ts +++ b/packages/backend/src/server/api/endpoints/renote-mute/create.ts @@ -47,12 +47,14 @@ export default define(meta, paramDef, async (ps, user) => { }); // Check if already muting - const exist = await RenoteMutings.findOneBy({ - muterId: muter.id, - muteeId: mutee.id, + const exist = await RenoteMutings.exist({ + where: { + muterId: muter.id, + muteeId: mutee.id, + }, }); - if (exist != null) { + if (exist) { throw new ApiError(meta.errors.alreadyMuting); } diff --git a/packages/backend/src/server/api/endpoints/renote-mute/delete.ts b/packages/backend/src/server/api/endpoints/renote-mute/delete.ts index fb4c972af..7a898141c 100644 --- a/packages/backend/src/server/api/endpoints/renote-mute/delete.ts +++ b/packages/backend/src/server/api/endpoints/renote-mute/delete.ts @@ -45,18 +45,18 @@ export default define(meta, paramDef, async (ps, user) => { }); // Check not muting - const exist = await RenoteMutings.findOneBy({ + const muting = await RenoteMutings.findOneBy({ muterId: muter.id, muteeId: mutee.id, }); - if (exist == null) { + if (muting == null) { throw new ApiError(meta.errors.notMuting); } // Delete mute await RenoteMutings.delete({ - id: exist.id, + id: muting.id, }); // publishUserEvent(user.id, "unmute", mutee); diff --git a/packages/backend/src/server/api/endpoints/sw/register.ts b/packages/backend/src/server/api/endpoints/sw/register.ts index 41be4bf74..6268ae26d 100644 --- a/packages/backend/src/server/api/endpoints/sw/register.ts +++ b/packages/backend/src/server/api/endpoints/sw/register.ts @@ -57,8 +57,7 @@ export const paramDef = { } as const; export default define(meta, paramDef, async (ps, me) => { - // if already subscribed - const exist = await SwSubscriptions.findOneBy({ + const subscription = await SwSubscriptions.findOneBy({ userId: me.id, endpoint: ps.endpoint, auth: ps.auth, @@ -67,13 +66,14 @@ export default define(meta, paramDef, async (ps, me) => { const instance = await fetchMeta(true); - if (exist != null) { + // if already subscribed + if (subscription != null) { return { state: "already-subscribed" as const, key: instance.swPublicKey, userId: me.id, - endpoint: exist.endpoint, - sendReadMessage: exist.sendReadMessage, + endpoint: subscription.endpoint, + sendReadMessage: subscription.sendReadMessage, }; } diff --git a/packages/backend/src/server/api/endpoints/sw/show-registration.ts b/packages/backend/src/server/api/endpoints/sw/show-registration.ts index c7a9609cf..3ccb7de94 100644 --- a/packages/backend/src/server/api/endpoints/sw/show-registration.ts +++ b/packages/backend/src/server/api/endpoints/sw/show-registration.ts @@ -42,16 +42,16 @@ export const paramDef = { // eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, me) => { - const exist = await SwSubscriptions.findOneBy({ + const subscription = await SwSubscriptions.findOneBy({ userId: me.id, endpoint: ps.endpoint, }); - if (exist != null) { + if (subscription != null) { return { - userId: exist.userId, - endpoint: exist.endpoint, - sendReadMessage: exist.sendReadMessage, + userId: subscription.userId, + endpoint: subscription.endpoint, + sendReadMessage: subscription.sendReadMessage, }; } diff --git a/packages/backend/src/server/api/endpoints/users/followers.ts b/packages/backend/src/server/api/endpoints/users/followers.ts index 855ab3573..31719bad3 100644 --- a/packages/backend/src/server/api/endpoints/users/followers.ts +++ b/packages/backend/src/server/api/endpoints/users/followers.ts @@ -98,11 +98,13 @@ export default define(meta, paramDef, async (ps, me) => { if (me == null) { throw new ApiError(meta.errors.forbidden); } else if (me.id !== user.id) { - const following = await Followings.findOneBy({ - followeeId: user.id, - followerId: me.id, + const isFollowed = await Followings.exist({ + where: { + followeeId: user.id, + followerId: me.id, + }, }); - if (following == null) { + if (!isFollowed) { throw new ApiError(meta.errors.nullFollowers); } } diff --git a/packages/backend/src/server/api/endpoints/users/following.ts b/packages/backend/src/server/api/endpoints/users/following.ts index 37d69b048..1c1da0e11 100644 --- a/packages/backend/src/server/api/endpoints/users/following.ts +++ b/packages/backend/src/server/api/endpoints/users/following.ts @@ -97,11 +97,13 @@ export default define(meta, paramDef, async (ps, me) => { if (me == null) { throw new ApiError(meta.errors.forbidden); } else if (me.id !== user.id) { - const following = await Followings.findOneBy({ - followeeId: user.id, - followerId: me.id, + const isFollowing = await Followings.exist({ + where: { + followeeId: user.id, + followerId: me.id, + }, }); - if (following == null) { + if (!isFollowing) { throw new ApiError(meta.errors.cannot_find); } } diff --git a/packages/backend/src/server/api/endpoints/users/lists/push.ts b/packages/backend/src/server/api/endpoints/users/lists/push.ts index a14195bbc..6f3e09fcb 100644 --- a/packages/backend/src/server/api/endpoints/users/lists/push.ts +++ b/packages/backend/src/server/api/endpoints/users/lists/push.ts @@ -52,12 +52,14 @@ export const paramDef = { export default define(meta, paramDef, async (ps, me) => { // Fetch the list - const userList = await UserLists.findOneBy({ - id: ps.listId, - userId: me.id, + const listExists = await UserLists.exist({ + where: { + id: ps.listId, + userId: me.id, + }, }); - if (userList == null) { + if (!listExists) { throw new ApiError(meta.errors.noSuchList); } @@ -70,18 +72,22 @@ export default define(meta, paramDef, async (ps, me) => { // Check blocking if (user.id !== me.id) { - const block = await Blockings.findOneBy({ - blockerId: user.id, - blockeeId: me.id, + const isBlocked = await Blockings.exist({ + where: { + blockerId: user.id, + blockeeId: me.id, + }, }); - if (block) { + if (isBlocked) { throw new ApiError(meta.errors.youHaveBeenBlocked); } } - const exist = await UserListJoinings.findOneBy({ - userListId: userList.id, - userId: user.id, + const exist = await UserListJoinings.exist({ + where: { + userListId: userList.id, + userId: user.id, + }, }); if (exist) { diff --git a/packages/backend/src/server/api/endpoints/users/lists/show.ts b/packages/backend/src/server/api/endpoints/users/lists/show.ts index 716fd405d..8479a4e03 100644 --- a/packages/backend/src/server/api/endpoints/users/lists/show.ts +++ b/packages/backend/src/server/api/endpoints/users/lists/show.ts @@ -37,12 +37,14 @@ export const paramDef = { export default define(meta, paramDef, async (ps, me) => { // Fetch the list - const userList = await UserLists.findOneBy({ - id: ps.listId, - userId: me.id, + const exist = await UserLists.exist({ + where: { + id: ps.listId, + userId: me.id, + }, }); - if (userList == null) { + if (!exist) { throw new ApiError(meta.errors.noSuchList); } diff --git a/packages/backend/src/server/api/endpoints/users/reactions.ts b/packages/backend/src/server/api/endpoints/users/reactions.ts index 17b7a04a0..6b6d32e8a 100644 --- a/packages/backend/src/server/api/endpoints/users/reactions.ts +++ b/packages/backend/src/server/api/endpoints/users/reactions.ts @@ -49,7 +49,7 @@ export const paramDef = { export default define(meta, paramDef, async (ps, me) => { const profile = await UserProfiles.findOneByOrFail({ userId: ps.userId }); - if (me == null || (me.id !== ps.userId && !profile.publicReactions)) { + if (me.id !== ps.userId && !profile.publicReactions) { throw new ApiError(meta.errors.reactionsNotPublic); } diff --git a/packages/backend/src/server/api/mastodon/endpoints/meta.ts b/packages/backend/src/server/api/mastodon/endpoints/meta.ts index 2df4af82a..042071f0e 100644 --- a/packages/backend/src/server/api/mastodon/endpoints/meta.ts +++ b/packages/backend/src/server/api/mastodon/endpoints/meta.ts @@ -1,4 +1,5 @@ import { Entity } from "megalodon"; +import config from "@/config/index.js"; import { fetchMeta } from "@/misc/fetch-meta.js"; import { Users, Notes } from "@/models/index.js"; import { IsNull, MoreThan } from "typeorm"; @@ -17,7 +18,7 @@ export async function getInstance(response: Entity.Instance) { response.description || "This is a vanilla Calckey Instance. It doesnt seem to have a description. BTW you are using the Mastodon api to access this server :)", email: response.email || "", - version: "3.0.0 compatible (3.5+ Calckey)", //I hope this version string is correct, we will need to test it. + version: `3.0.0 (compatible; Calckey ${config.version})`, urls: response.urls, stats: { user_count: await totalUsers, diff --git a/packages/backend/src/server/api/mastodon/endpoints/status.ts b/packages/backend/src/server/api/mastodon/endpoints/status.ts index 76057ef0a..caa9d1d68 100644 --- a/packages/backend/src/server/api/mastodon/endpoints/status.ts +++ b/packages/backend/src/server/api/mastodon/endpoints/status.ts @@ -67,6 +67,25 @@ export function apiStatusMastodon(router: Router): void { const { sensitive } = body; body.sensitive = typeof sensitive === "string" ? sensitive === "true" : sensitive; + + if (body.poll) { + if ( + body.poll.expires_in != null && + typeof body.poll.expires_in === "string" + ) + body.poll.expires_in = parseInt(body.poll.expires_in); + if ( + body.poll.multiple != null && + typeof body.poll.multiple === "string" + ) + body.poll.multiple = body.poll.multiple == "true"; + if ( + body.poll.hide_totals != null && + typeof body.poll.hide_totals === "string" + ) + body.poll.hide_totals = body.poll.hide_totals == "true"; + } + const data = await client.postStatus(text, body); ctx.body = convertStatus(data.data); } catch (e: any) { @@ -86,7 +105,7 @@ export function apiStatusMastodon(router: Router): void { ctx.body = convertStatus(data.data); } catch (e: any) { console.error(e); - ctx.status = 401; + ctx.status = ctx.status == 404 ? 404 : 401; ctx.body = e.response.data; } }); diff --git a/packages/backend/src/server/api/service/discord.ts b/packages/backend/src/server/api/service/discord.ts index 9906d2f7c..848a70d4a 100644 --- a/packages/backend/src/server/api/service/discord.ts +++ b/packages/backend/src/server/api/service/discord.ts @@ -18,7 +18,7 @@ function getUserToken(ctx: Koa.BaseContext): string | null { function compareOrigin(ctx: Koa.BaseContext): boolean { function normalizeUrl(url?: string): string { - return url ? (url.endsWith("/") ? url.substr(0, url.length - 1) : url) : ""; + return url ? (url.endsWith("/") ? url.slice(0, url.length - 1) : url) : ""; } const referer = ctx.headers["referer"]; diff --git a/packages/backend/src/server/api/service/github.ts b/packages/backend/src/server/api/service/github.ts index f77c5f795..fd015fb8a 100644 --- a/packages/backend/src/server/api/service/github.ts +++ b/packages/backend/src/server/api/service/github.ts @@ -18,7 +18,7 @@ function getUserToken(ctx: Koa.BaseContext): string | null { function compareOrigin(ctx: Koa.BaseContext): boolean { function normalizeUrl(url?: string): string { - return url ? (url.endsWith("/") ? url.substr(0, url.length - 1) : url) : ""; + return url ? (url.endsWith("/") ? url.slice(0, url.length - 1) : url) : ""; } const referer = ctx.headers["referer"]; diff --git a/packages/backend/src/server/api/stream/channels/user-list.ts b/packages/backend/src/server/api/stream/channels/user-list.ts index 0b52f6912..d14031950 100644 --- a/packages/backend/src/server/api/stream/channels/user-list.ts +++ b/packages/backend/src/server/api/stream/channels/user-list.ts @@ -22,11 +22,13 @@ export default class extends Channel { this.listId = params.listId as string; // Check existence and owner - const list = await UserLists.findOneBy({ - id: this.listId, - userId: this.user!.id, + const exist = await UserLists.exist({ + where: { + id: this.listId, + userId: this.user!.id, + }, }); - if (!list) return; + if (!exist) return; // Subscribe stream this.subscriber.on(`userListStream:${this.listId}`, this.send); diff --git a/packages/backend/src/server/api/stream/index.ts b/packages/backend/src/server/api/stream/index.ts index e778c4946..72dce1951 100644 --- a/packages/backend/src/server/api/stream/index.ts +++ b/packages/backend/src/server/api/stream/index.ts @@ -247,7 +247,7 @@ export default class Connection { for (const obj of objs) { const { type, body } = obj; - console.log(type, body); + // console.log(type, body); switch (type) { case "readNotification": this.onReadNotification(body); diff --git a/packages/backend/src/server/proxy/proxy-media.ts b/packages/backend/src/server/proxy/proxy-media.ts index a9c257bfe..b3bb03124 100644 --- a/packages/backend/src/server/proxy/proxy-media.ts +++ b/packages/backend/src/server/proxy/proxy-media.ts @@ -1,4 +1,6 @@ import * as fs from "node:fs"; +import net from "node:net"; +import { promises } from "node:dns"; import type Koa from "koa"; import sharp from "sharp"; import type { IImage } from "@/services/drive/image-processor.js"; @@ -19,6 +21,40 @@ export async function proxyMedia(ctx: Koa.Context) { return; } + const { hostname } = new URL(url); + let resolvedIps; + try { + resolvedIps = await promises.resolve(hostname); + } catch (error) { + ctx.status = 400; + ctx.body = { message: "Invalid URL" }; + return; + } + + const isSSRF = resolvedIps.some((ip) => { + if (net.isIPv4(ip)) { + const parts = ip.split(".").map(Number); + return ( + parts[0] === 10 || + (parts[0] === 172 && parts[1] >= 16 && parts[1] < 32) || + (parts[0] === 192 && parts[1] === 168) || + parts[0] === 127 || + parts[0] === 0 + ); + } else if (net.isIPv6(ip)) { + return ( + ip.startsWith("::") || ip.startsWith("fc00:") || ip.startsWith("fe80:") + ); + } + return false; + }); + + if (isSSRF) { + ctx.status = 400; + ctx.body = { message: "Access to this URL is not allowed" }; + return; + } + // Create temp file const [path, cleanup] = await createTemp(); diff --git a/packages/backend/src/server/web/boot.js b/packages/backend/src/server/web/boot.js index d3b7c3b82..9c966036f 100644 --- a/packages/backend/src/server/web/boot.js +++ b/packages/backend/src/server/web/boot.js @@ -102,7 +102,11 @@ localStorage.setItem("fontSize", null); fontSize = localStorage.getItem("fontSize"); } - document.documentElement.style.fontSize = fontSize + "px"; + document.documentElement.style.fontSize = `${fontSize}px`; + } + + if (["ja-JP", "ja-KS", "ko-KR", "zh-CN", "zh-TW"].includes(lang)) { + document.documentElement.classList.add("useCJKFont"); } const useSystemFont = localStorage.getItem("useSystemFont"); @@ -123,7 +127,7 @@ } async function addStyle(styleText) { - let css = document.createElement("style"); + const css = document.createElement("style"); css.appendChild(document.createTextNode(styleText)); document.head.appendChild(css); } diff --git a/packages/backend/src/services/note/reaction/delete.ts b/packages/backend/src/services/note/reaction/delete.ts index 82648249e..15c6d1cf6 100644 --- a/packages/backend/src/services/note/reaction/delete.ts +++ b/packages/backend/src/services/note/reaction/delete.ts @@ -13,13 +13,13 @@ export default async ( user: { id: User["id"]; host: User["host"] }, note: Note, ) => { - // if already unreacted - const exist = await NoteReactions.findOneBy({ + const reaction = await NoteReactions.findOneBy({ noteId: note.id, userId: user.id, }); - if (exist == null) { + // if already unreacted + if (reaction == null) { throw new IdentifiableError( "60527ec9-b4cb-4a88-a6bd-32d3ad26817d", "not reacted", @@ -27,7 +27,7 @@ export default async ( } // Delete reaction - const result = await NoteReactions.delete(exist.id); + const result = await NoteReactions.delete(reaction.id); if (result.affected !== 1) { throw new IdentifiableError( @@ -37,7 +37,7 @@ export default async ( } // Decrement reactions count - const sql = `jsonb_set("reactions", '{${exist.reaction}}', (COALESCE("reactions"->>'${exist.reaction}', '0')::int - 1)::text::jsonb)`; + const sql = `jsonb_set("reactions", '{${reaction.reaction}}', (COALESCE("reactions"->>'${reaction.reaction}', '0')::int - 1)::text::jsonb)`; await Notes.createQueryBuilder() .update() .set({ @@ -49,14 +49,14 @@ export default async ( Notes.decrement({ id: note.id }, "score", 1); publishNoteStream(note.id, "unreacted", { - reaction: decodeReaction(exist.reaction).reaction, + reaction: decodeReaction(reaction.reaction).reaction, userId: user.id, }); //#region 配信 if (Users.isLocalUser(user) && !note.localOnly) { const content = renderActivity( - renderUndo(await renderLike(exist, note), user), + renderUndo(await renderLike(reaction, note), user), ); const dm = new DeliverManager(user, content); if (note.userHost !== null) { diff --git a/packages/backend/src/services/note/unread.ts b/packages/backend/src/services/note/unread.ts index 275b230d4..cb87abe0e 100644 --- a/packages/backend/src/services/note/unread.ts +++ b/packages/backend/src/services/note/unread.ts @@ -42,9 +42,9 @@ export async function insertNoteUnread( // 2秒経っても既読にならなかったら「未読の投稿がありますよ」イベントを発行する setTimeout(async () => { - const exist = await NoteUnreads.findOneBy({ id: unread.id }); + const exist = await NoteUnreads.exist({ where: { id: unread.id } }); - if (exist == null) return; + if (!exist) return; if (params.isMentioned) { publishMainStream(userId, "unreadMention", note.id); diff --git a/packages/calckey-js/src/acct.ts b/packages/calckey-js/src/acct.ts index 5b7767a10..cb6808b4b 100644 --- a/packages/calckey-js/src/acct.ts +++ b/packages/calckey-js/src/acct.ts @@ -4,7 +4,7 @@ export type Acct = { }; export function parse(acct: string): Acct { - if (acct.startsWith("@")) acct = acct.substr(1); + if (acct.startsWith("@")) acct = acct.slice(1); const split = acct.split("@", 2); return { username: split[0], host: split[1] || null }; } diff --git a/packages/client/.eslintrc.json b/packages/client/.eslintrc.json new file mode 100644 index 000000000..fd4718003 --- /dev/null +++ b/packages/client/.eslintrc.json @@ -0,0 +1,7 @@ +{ + "extends": ["@eslint-sets/vue3", "@eslint-sets/vue3-ts"], + "plugins": ["file-progress", "prettier"], + "rules": { + "file-progress/activate": 1 + } +} diff --git a/packages/client/package.json b/packages/client/package.json index e34773ffe..3fe101b81 100644 --- a/packages/client/package.json +++ b/packages/client/package.json @@ -4,11 +4,14 @@ "scripts": { "watch": "pnpm vite build --watch --mode development", "build": "pnpm vite build", - "lint": "pnpm rome check \"src/**/*.{ts,vue}\"", - "format": "pnpm rome format * --write && pnpm prettier --write '**/*.{scss,vue}'" + "lint": "pnpm rome check **/*.ts --apply && pnpm run lint:vue", + "lint:vue": "pnpm paralint --ext .vue --fix '**/*.vue' --cache", + "format": "pnpm rome format * --write && pnpm prettier --write '**/*.{scss,vue}' --cache --cache-strategy metadata" }, "devDependencies": { "@discordapp/twemoji": "14.1.2", + "@eslint-sets/eslint-config-vue3": "^5.6.1", + "@eslint-sets/eslint-config-vue3-ts": "^3.3.0", "@phosphor-icons/web": "^2.0.3", "@rollup/plugin-alias": "3.1.9", "@rollup/plugin-json": "4.1.0", @@ -16,7 +19,7 @@ "@syuilo/aiscript": "0.11.1", "@types/escape-regexp": "0.0.1", "@types/glob": "8.1.0", - "@types/gulp": "4.0.11", + "@types/gulp": "4.0.13", "@types/gulp-rename": "2.0.2", "@types/katex": "0.16.0", "@types/matter-js": "0.18.2", @@ -29,8 +32,8 @@ "@vue/compiler-sfc": "3.3.4", "autobind-decorator": "2.4.0", "autosize": "5.0.2", - "blurhash": "1.1.5", - "broadcast-channel": "4.19.1", + "blurhash": "2.0.5", + "broadcast-channel": "5.1.0", "browser-image-resizer": "github:misskey-dev/browser-image-resizer", "calckey-js": "workspace:*", "chart.js": "4.3.0", @@ -39,56 +42,60 @@ "chartjs-plugin-gradient": "0.6.1", "chartjs-plugin-zoom": "2.0.1", "city-timezones": "^1.2.1", - "compare-versions": "5.0.3", + "compare-versions": "6.0.0", "cropperjs": "2.0.0-beta.2", "cross-env": "7.0.3", "cypress": "10.11.0", "date-fns": "2.30.0", "emojilib": "github:thatonecalculator/emojilib", "escape-regexp": "0.0.1", - "eventemitter3": "4.0.7", - "focus-trap": "^7.4.3", + "eslint-config-prettier": "^8.6.0", + "eslint-plugin-file-progress": "^1.3.0", + "eventemitter3": "5.0.1", + "fast-blurhash": "^1.1.2", + "focus-trap": "^7.5.2", "focus-trap-vue": "^4.0.2", - "gsap": "^3.11.5", + "gsap": "^3.12.2", "idb-keyval": "6.2.1", "insert-text-at-cursor": "0.3.0", "json5": "2.2.3", - "katex": "0.16.7", + "katex": "0.16.8", "matter-js": "0.18.0", "mfm-js": "0.23.3", - "photoswipe": "5.3.7", + "paralint": "^1.2.1", + "photoswipe": "5.3.8", "prettier": "3.0.0", "prettier-plugin-vue": "1.1.6", "prismjs": "1.29.0", - "punycode": "2.1.1", + "punycode": "2.3.0", "querystring": "0.2.1", "rndstr": "1.0.0", - "rollup": "3.23.1", + "rollup": "3.26.2", "s-age": "1.1.2", - "sass": "1.62.1", + "sass": "1.63.6", "seedrandom": "3.0.5", "start-server-and-test": "1.15.2", "strict-event-emitter-types": "2.0.0", "stringz": "2.1.0", - "swiper": "9.3.2", + "swiper": "10.0.4", "syuilo-password-strength": "0.0.1", "textarea-caret": "3.1.0", "three": "0.146.0", "throttle-debounce": "5.0.0", - "tinycolor2": "1.5.2", - "tsc-alias": "1.8.6", + "tinycolor2": "1.6.0", + "tsc-alias": "1.8.7", "tsconfig-paths": "4.2.0", "twemoji-parser": "14.0.0", - "typescript": "5.1.3", + "typescript": "5.1.6", "unicode-emoji-json": "^0.4.0", "uuid": "9.0.0", "vanilla-tilt": "1.8.0", - "vite": "4.3.9", + "vite": "4.4.2", "vite-plugin-compression": "^0.5.1", "vue": "3.3.4", + "vue-draggable-plus": "^0.2.2", "vue-isyourpasswordsafe": "^2.0.0", "vue-plyr": "^7.0.0", - "vue-prism-editor": "2.0.0-alpha.2", - "vuedraggable": "4.1.0" + "vue-prism-editor": "2.0.0-alpha.2" } } diff --git a/packages/client/src/components/MkAbuseReport.vue b/packages/client/src/components/MkAbuseReport.vue index ccb85d722..f92d10ba7 100644 --- a/packages/client/src/components/MkAbuseReport.vue +++ b/packages/client/src/components/MkAbuseReport.vue @@ -80,11 +80,11 @@ const emit = defineEmits<{ (ev: "resolved", reportId: string): void; }>(); -let forward = $ref(props.report.forwarded); +const forward = $ref(props.report.forwarded); function resolve() { os.apiWithDialog("admin/resolve-abuse-user-report", { - forward: forward, + forward, reportId: props.report.id, }).then(() => { emit("resolved", props.report.id); diff --git a/packages/client/src/components/MkAbuseReportWindow.vue b/packages/client/src/components/MkAbuseReportWindow.vue index 6fdf3b9e0..fc80cd66f 100644 --- a/packages/client/src/components/MkAbuseReportWindow.vue +++ b/packages/client/src/components/MkAbuseReportWindow.vue @@ -41,7 +41,7 @@ + + + + diff --git a/packages/client/src/components/MkEmojiPicker.vue b/packages/client/src/components/MkEmojiPicker.vue index 09d61518d..2a797f56a 100644 --- a/packages/client/src/components/MkEmojiPicker.vue +++ b/packages/client/src/components/MkEmojiPicker.vue @@ -195,7 +195,7 @@ const props = withDefaults( ); const emit = defineEmits<{ - (ev: "chosen", v: string): void; + (ev: "chosen", v: string, ev: MouseEvent): void; }>(); const search = ref(); @@ -436,7 +436,7 @@ function chosen(emoji: any, ev?: MouseEvent) { } const key = getKey(emoji); - emit("chosen", key); + emit("chosen", key, ev); // 最近使った絵文字更新 if (!pinned.value.includes(key)) { diff --git a/packages/client/src/components/MkEmojiPickerDialog.vue b/packages/client/src/components/MkEmojiPickerDialog.vue index fcd2f26a3..c3212cd40 100644 --- a/packages/client/src/components/MkEmojiPickerDialog.vue +++ b/packages/client/src/components/MkEmojiPickerDialog.vue @@ -12,7 +12,7 @@ :transparent-bg="true" :manual-showing="manualShowing" :src="src" - @click="modal?.close()" + @click="checkForShift" @opening="opening" @close="emit('close')" @closed="emit('closed')" @@ -31,7 +31,7 @@ diff --git a/packages/client/src/components/MkUserPreview.vue b/packages/client/src/components/MkUserPreview.vue index 6c3838fd2..e78c36c65 100644 --- a/packages/client/src/components/MkUserPreview.vue +++ b/packages/client/src/components/MkUserPreview.vue @@ -19,96 +19,7 @@ } " > -
- - -
- -

-
-
- -
- -
-
-
- -
-
- -
-
-
-
-
-

{{ i18n.ts.notes }}

- {{ user.notesCount }} -
-
-

{{ i18n.ts.following }}

- {{ user.followingCount }} -
-
-

{{ i18n.ts.followers }}

- {{ user.followersCount }} -
-
- -
+
@@ -118,14 +29,10 @@ diff --git a/packages/client/src/pages/admin/settings.vue b/packages/client/src/pages/admin/settings.vue index b03a98ae5..a33335089 100644 --- a/packages/client/src/pages/admin/settings.vue +++ b/packages/client/src/pages/admin/settings.vue @@ -53,6 +53,18 @@ i18n.ts.maintainerEmail }} + + + + + @@ -435,6 +447,7 @@ let description: string | null = $ref(null); let tosUrl: string | null = $ref(null); let maintainerName: string | null = $ref(null); let maintainerEmail: string | null = $ref(null); +let donationLink: string | null = $ref(null); let iconUrl: string | null = $ref(null); let bannerUrl: string | null = $ref(null); let logoImageUrl: string | null = $ref(null); @@ -481,6 +494,7 @@ async function init() { defaultDarkTheme = meta.defaultDarkTheme; maintainerName = meta.maintainerName; maintainerEmail = meta.maintainerEmail; + donationLink = meta.donationLink; enableLocalTimeline = !meta.disableLocalTimeline; enableGlobalTimeline = !meta.disableGlobalTimeline; enableRecommendedTimeline = !meta.disableRecommendedTimeline; @@ -527,6 +541,7 @@ function save() { defaultDarkTheme: defaultDarkTheme === "" ? null : defaultDarkTheme, maintainerName, maintainerEmail, + donationLink, disableLocalTimeline: !enableLocalTimeline, disableGlobalTimeline: !enableGlobalTimeline, disableRecommendedTimeline: !enableRecommendedTimeline, diff --git a/packages/client/src/pages/announcements.vue b/packages/client/src/pages/announcements.vue index 8e9975020..cc62ce0f5 100644 --- a/packages/client/src/pages/announcements.vue +++ b/packages/client/src/pages/announcements.vue @@ -15,8 +15,13 @@ class="_card announcement" >
- 🆕 {{ announcement.title }} + 🆕 +

{{ announcement.title }}

+ +
+ {{ i18n.ts.updatedAt }}: + +
@@ -76,6 +81,10 @@ definePageMetadata({ margin-bottom: var(--margin); } + > ._title { + padding: 14px 32px !important; + } + > ._content { > img { display: block; diff --git a/packages/client/src/pages/channels.vue b/packages/client/src/pages/channels.vue index 75e922440..65f4dbf0c 100644 --- a/packages/client/src/pages/channels.vue +++ b/packages/client/src/pages/channels.vue @@ -112,7 +112,7 @@ diff --git a/packages/client/src/pages/settings/reaction.vue b/packages/client/src/pages/settings/reaction.vue index 992900486..29f14fd48 100644 --- a/packages/client/src/pages/settings/reaction.vue +++ b/packages/client/src/pages/settings/reaction.vue @@ -10,32 +10,30 @@ i18n.ts.reactionSettingDescription }}
- - - - +
+ +
+ +