diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index fbf959d449..713c2e5fdd 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -5,7 +5,7 @@ "workspaceFolder": "/workspace", "features": { "ghcr.io/devcontainers/features/node:1": { - "version": "20.16.0" + "version": "22.11.0" }, "ghcr.io/devcontainers-contrib/features/corepack:1": {} }, diff --git a/.github/workflows/get-api-diff.yml b/.github/workflows/get-api-diff.yml index 1bcaa0d9c4..972619ec60 100644 --- a/.github/workflows/get-api-diff.yml +++ b/.github/workflows/get-api-diff.yml @@ -17,7 +17,7 @@ jobs: strategy: matrix: - node-version: [20.16.0] + node-version: [22.11.0] api-json-name: [api-base.json, api-head.json] include: - api-json-name: api-base.json diff --git a/.github/workflows/on-release-created.yml b/.github/workflows/on-release-created.yml index ffaf7bc038..6258fa693a 100644 --- a/.github/workflows/on-release-created.yml +++ b/.github/workflows/on-release-created.yml @@ -17,7 +17,7 @@ jobs: strategy: matrix: - node-version: [20.16.0] + node-version: [22.11.0] steps: - uses: actions/checkout@v4.1.1 diff --git a/.github/workflows/test-backend.yml b/.github/workflows/test-backend.yml index d95d6676f9..fc614dcf85 100644 --- a/.github/workflows/test-backend.yml +++ b/.github/workflows/test-backend.yml @@ -22,7 +22,7 @@ jobs: strategy: matrix: - node-version: [20.16.0] + node-version: [22.11.0] services: postgres: @@ -61,7 +61,7 @@ jobs: - name: Test run: pnpm --filter backend test-and-coverage - name: Upload to Codecov - uses: codecov/codecov-action@v4 + uses: codecov/codecov-action@v5 with: token: ${{ secrets.CODECOV_TOKEN }} files: ./packages/backend/coverage/coverage-final.json @@ -71,7 +71,7 @@ jobs: strategy: matrix: - node-version: [20.16.0] + node-version: [22.11.0] services: postgres: @@ -108,7 +108,7 @@ jobs: - name: Test run: pnpm --filter backend test-and-coverage:e2e - name: Upload to Codecov - uses: codecov/codecov-action@v4 + uses: codecov/codecov-action@v5 with: token: ${{ secrets.CODECOV_TOKEN }} files: ./packages/backend/coverage/coverage-final.json diff --git a/.github/workflows/test-federation.yml b/.github/workflows/test-federation.yml index 183ddb6f34..e89cdcb091 100644 --- a/.github/workflows/test-federation.yml +++ b/.github/workflows/test-federation.yml @@ -20,7 +20,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - node-version: [20.16.0] + node-version: [22.11.0] steps: - uses: actions/checkout@v4 with: diff --git a/.github/workflows/test-frontend.yml b/.github/workflows/test-frontend.yml index c68e1a8ef1..6128abb502 100644 --- a/.github/workflows/test-frontend.yml +++ b/.github/workflows/test-frontend.yml @@ -26,7 +26,7 @@ jobs: strategy: matrix: - node-version: [20.16.0] + node-version: [22.11.0] steps: - uses: actions/checkout@v4.1.1 @@ -50,7 +50,7 @@ jobs: - name: Test run: pnpm --filter frontend test-and-coverage - name: Upload Coverage - uses: codecov/codecov-action@v4 + uses: codecov/codecov-action@v5 with: token: ${{ secrets.CODECOV_TOKEN }} files: ./packages/frontend/coverage/coverage-final.json @@ -61,7 +61,7 @@ jobs: strategy: fail-fast: false matrix: - node-version: [20.16.0] + node-version: [22.11.0] browser: [chrome] services: diff --git a/.github/workflows/test-misskey-js.yml b/.github/workflows/test-misskey-js.yml index 63e81f8c92..c7bb0753a8 100644 --- a/.github/workflows/test-misskey-js.yml +++ b/.github/workflows/test-misskey-js.yml @@ -21,7 +21,7 @@ jobs: strategy: matrix: - node-version: [20.16.0] + node-version: [22.11.0] # See supported Node.js release schedule at https://nodejs.org/en/about/releases/ steps: @@ -51,7 +51,7 @@ jobs: CI: true - name: Upload Coverage - uses: codecov/codecov-action@v4 + uses: codecov/codecov-action@v5 with: token: ${{ secrets.CODECOV_TOKEN }} files: ./packages/misskey-js/coverage/coverage-final.json diff --git a/.github/workflows/test-production.yml b/.github/workflows/test-production.yml index 0abc09c5a6..11a95ca82f 100644 --- a/.github/workflows/test-production.yml +++ b/.github/workflows/test-production.yml @@ -16,7 +16,7 @@ jobs: strategy: matrix: - node-version: [20.16.0] + node-version: [22.11.0] steps: - uses: actions/checkout@v4.1.1 diff --git a/.github/workflows/validate-api-json.yml b/.github/workflows/validate-api-json.yml index f809af1063..835b2a9a24 100644 --- a/.github/workflows/validate-api-json.yml +++ b/.github/workflows/validate-api-json.yml @@ -18,7 +18,7 @@ jobs: strategy: matrix: - node-version: [20.16.0] + node-version: [22.11.0] steps: - uses: actions/checkout@v4.1.1 diff --git a/.gitignore b/.gitignore index 5b8a798ba6..ac7502f384 100644 --- a/.gitignore +++ b/.gitignore @@ -68,6 +68,8 @@ misskey-assets # Vite temporary files vite.config.js.timestamp-* vite.config.ts.timestamp-* +vite.config.local-dev.js.timestamp-* +vite.config.local-dev.ts.timestamp-* # blender backups *.blend1 diff --git a/.node-version b/.node-version index 8ce7030825..7af24b7ddb 100644 --- a/.node-version +++ b/.node-version @@ -1 +1 @@ -20.16.0 +22.11.0 diff --git a/CHANGELOG.md b/CHANGELOG.md index 121ddbb255..0791a9f301 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,10 @@ ## 2024.11.0 +### Note +- Node.js 20.xは非推奨になりました。Node.js 22.x (LTS)の利用を推奨します。 + - なお、Node.js 23.xは対応していません。 +- DockerのNode.jsが22.11.0に更新されました + ### General - Feat: コンテンツの表示にログインを必須にできるように - Feat: 過去のノートを非公開化/フォロワーのみ表示可能にできるように @@ -21,6 +26,9 @@ - Enhance: Self-XSS防止用の警告を追加 - Enhance: カタルーニャ語 (ca-ES) に対応 - Enhance: 個別お知らせページではMetaタグを出力するように +- Enhance: ノート詳細画面にロールのバッジを表示 +- Enhance: 過去に送信したフォローリクエストを確認できるように + (Based on https://activitypub.software/TransFem-org/Sharkey/-/merge_requests/663) - Fix: 通知の範囲指定の設定項目が必要ない通知設定でも範囲指定の設定がでている問題を修正 - Fix: Turnstileが失敗・期限切れした際にも成功扱いとなってしまう問題を修正 (Cherry-picked from https://github.com/MisskeyIO/misskey/pull/768) @@ -30,12 +38,17 @@ = Fix: ノート投稿ボタンにホバー時のスタイルが適用されていないのを修正 (Cherry-picked from https://github.com/taiyme/misskey/pull/305) - Fix: メールアドレス登録有効化時の「完了」ダイアログボックスの表示条件を修正 +- Fix: 画面幅が狭い環境でデザインが崩れる問題を修正 + (Cherry-picked from https://github.com/MisskeyIO/misskey/pull/815) ### Server +- Enhance: DockerのNode.jsを22.11.0に更新 - Enhance: 起動前の疎通チェックで、DBとメイン以外のRedisの疎通確認も行うように (Based on https://activitypub.software/TransFem-org/Sharkey/-/merge_requests/588) (Cherry-picked from https://activitypub.software/TransFem-org/Sharkey/-/merge_requests/715) - Enhance: リモートユーザーの照会をオリジナルにリダイレクトするように +- Fix: sharedInboxが無いActorに紐づくリモートユーザーを照会できない +- Fix: Aproving request from GtS appears with some delay - Fix: フォロワーへのメッセージの絵文字をemojisに含めるように - Fix: Nested proxy requestsを検出した際にブロックするように [ghsa-gq5q-c77c-v236](https://github.com/misskey-dev/misskey/security/advisories/ghsa-gq5q-c77c-v236) @@ -47,6 +60,7 @@ (Cherry-picked from https://activitypub.software/TransFem-org/Sharkey/-/merge_requests/712) - Fix: FTT無効時にユーザーリストタイムラインが使用できない問題を修正 (Cherry-picked from https://activitypub.software/TransFem-org/Sharkey/-/merge_requests/709) +- Fix: User Webhookテスト機能のMock Payloadを修正 ### Misskey.js - Fix: Stream初期化時、別途WebSocketを指定する場合の型定義を修正 diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index f8af6b3df0..1c777259d2 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -101,6 +101,22 @@ Be willing to comment on the good points and not just the things you want fixed - Are there any omissions or gaps? - Does it check for anomalies? +## Security Advisory +### For reporter +Thank you for your reporting! + +If you can also create a patch to fix the vulnerability, please create a PR on the private fork. + +> [!note] +> There is a GitHub bug that prevents merging if a PR not following the develop branch of upstream, so please keep follow the develop branch. + +### For misskey-dev member +修正PRがdevelopに追従されていないとマージできないので、マージできなかったら + +> Could you merge or rebase onto upstream develop branch? + +などと伝える。 + ## Deploy The `/deploy` command by issue comment can be used to deploy the contents of a PR to the preview environment. ``` diff --git a/Dockerfile b/Dockerfile index e21b2a31fc..ee765abe7c 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,6 +1,6 @@ # syntax = docker/dockerfile:1.4 -ARG NODE_VERSION=20.16.0-bullseye +ARG NODE_VERSION=22.11.0-bullseye # build assets & compile TypeScript diff --git a/SECURITY.md b/SECURITY.md index fc5dec5de4..04567baf07 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -6,3 +6,10 @@ This will allow us to assess the risk, and make a fix available before we add a bug report to the GitHub repository. Thanks for helping make Misskey safe for everyone. + +## When create a patch + +If you can also create a patch to fix the vulnerability, please create a PR on the private fork. + +> [!note] +> There is a GitHub bug that prevents merging if a PR not following the develop branch of upstream, so please keep follow the develop branch. diff --git a/locales/ca-ES.yml b/locales/ca-ES.yml index 748f6f03c0..048abfd781 100644 --- a/locales/ca-ES.yml +++ b/locales/ca-ES.yml @@ -8,37 +8,37 @@ search: "Cercar" notifications: "Notificacions" username: "Nom d'usuari" password: "Contrasenya" -initialPasswordForSetup: "Contrasenya inicial per la configuració inicial" +initialPasswordForSetup: "Contrasenya inicial per fer la primera configuració " initialPasswordIsIncorrect: "La contrasenya no és correcta." initialPasswordForSetupDescription: "Fes servir la contrasenya que has fet servir al fitxer de configuració, si tu mateix has instal·lat Misskey.\nSi fas servir una empresa d'allotjament de Misskey, fes servir la contrasenya que t'han donat.\nSi no has posat cap contrasenya deixar l'espai en blanc." -forgotPassword: "Contrasenya oblidada" -fetchingAsApObject: "Cercant en el Fediverse..." +forgotPassword: "Restableix la contrasenya " +fetchingAsApObject: "Cercant al Fediverse..." ok: "OK" -gotIt: "Ho he entès!" +gotIt: "D'acord " cancel: "Cancel·lar" noThankYou: "No, gràcies" enterUsername: "Introdueix el teu nom d'usuari" renotedBy: "Impulsat per {user}" noNotes: "Cap nota" noNotifications: "Cap notificació" -instance: "Servidor" +instance: "Instància " settings: "Preferències" -notificationSettings: "Paràmetres de notificacions" +notificationSettings: "Configurar les notificacions" basicSettings: "Configuració bàsica" -otherSettings: "Configuració avançada" -openInWindow: "Obrir en una nova finestra" +otherSettings: "Altres configuracions" +openInWindow: "Obrir en una finestra nova" profile: "Perfil" timeline: "Línia de temps" noAccountDescription: "Aquest usuari encara no ha escrit la seva biografia." login: "Iniciar sessió" -loggingIn: "Identificant-se" +loggingIn: "Iniciar la sessió " logout: "Tancar la sessió" signup: "Registrar-se" uploading: "Pujant..." save: "Desa" users: "Usuaris" addUser: "Afegir un usuari" -favorite: "Afegir a preferits" +favorite: "Afegeix als preferits" favorites: "Favorits" unfavorite: "Eliminar dels preferits" favorited: "Afegit als preferits." @@ -50,26 +50,26 @@ copyContent: "Copiar el contingut" copyLink: "Copiar l'enllaç" copyLinkRenote: "Copiar l'enllaç de la renota" delete: "Elimina" -deleteAndEdit: "Elimina i edita" +deleteAndEdit: "Eliminar i editar" deleteAndEditConfirm: "Segur que vols eliminar aquesta publicació i editar-la? Perdràs totes les reaccions, impulsos i respostes." addToList: "Afegir a una llista" -addToAntenna: "Afegir a l'antena" +addToAntenna: "Afegir a una antena" sendMessage: "Enviar un missatge" copyRSS: "Copiar RSS" copyUsername: "Copiar nom d'usuari" copyUserId: "Copiar ID d'usuari" -copyNoteId: "Copiar ID de nota" -copyFileId: "Copiar ID d'arxiu" -copyFolderId: "Copiar ID de carpeta" -copyProfileUrl: "Copiar URL del perfil" +copyNoteId: "Copiar ID de la nota" +copyFileId: "Copiar ID de l'arxiu" +copyFolderId: "Copiar ID de la carpeta" +copyProfileUrl: "Copiar adreça URL del perfil" searchUser: "Cercar un usuari" -searchThisUsersNotes: "Cerca les publicacions de l'usuari" -reply: "Respondre" +searchThisUsersNotes: "Cercar les publicacions de l'usuari" +reply: "Respon" loadMore: "Carregar més" showMore: "Veure més" -showLess: "Mostra menys" +showLess: "Mostrar menys" youGotNewFollower: "t'ha seguit" -receiveFollowRequest: "Sol·licitud de seguiment rebuda" +receiveFollowRequest: "Has rebut una sol·licitud de seguiment" followRequestAccepted: "Sol·licitud de seguiment acceptada" mention: "Menció" mentions: "Mencions" @@ -78,25 +78,25 @@ importAndExport: "Importar / Exportar" import: "Importar" export: "Exporta" files: "Fitxers" -download: "Baixar" -driveFileDeleteConfirm: "Estàs segur que vols suprimir el fitxer \"{name}\"? Les notes associades a aquest fitxer adjunt també se suprimiran." -unfollowConfirm: "Estàs segur que vols deixar de seguir {name}?" -exportRequested: "Has sol·licitat una exportació. Això pot trigar una estona. S'afegirà a la teva unitat un cop completat." -importRequested: "Has sol·licitat una importació. Això pot trigar una estona." +download: "Descarregar" +driveFileDeleteConfirm: "Estàs segur que vols suprimir el fitxer \"{name}\"? Les notes associades a aquest fitxer també seran esborrades." +unfollowConfirm: "Segur que vols deixar de seguir a {name}?" +exportRequested: "Has sol·licitat una exportació de dades. Això pot trigar una estona. S'afegirà a la teva unitat de disc un cop estigui completada." +importRequested: "Has sol·licitat una importació de dades. Això pot trigar una estona." lists: "Llistes" noLists: "No tens cap llista" note: "Nota" notes: "Notes" -following: "Seguint" +following: "Segueixes " followers: "Seguidors" followsYou: "Et segueix" createList: "Crear llista" manageLists: "Gestionar les llistes" error: "Error" somethingHappened: "S'ha produït un error" -retry: "Torna-ho a intentar" +retry: "Torna-ho a provar" pageLoadError: "S'ha produït un error en carregar la pàgina" -pageLoadErrorDescription: "Això normalment es deu a errors de xarxa o a la memòria cau del navegador. Prova d'esborrar la memòria cau i torna-ho a provar després d'esperar una estona." +pageLoadErrorDescription: "Això normalment és a causa d'errors a la xarxa o a la memòria cau del navegador. Prova d'esborrar la memòria cau i torna-ho a provar després d'esperar un temps." serverIsDead: "Aquest servidor no respon. Espera una estona i torna-ho a provar." youShouldUpgradeClient: "Per veure aquesta pàgina, actualitzeu-la per actualitzar el vostre client." enterListName: "Introdueix un nom per a la llista" @@ -104,52 +104,52 @@ privacy: "Privadesa" makeFollowManuallyApprove: "Les sol·licituds de seguiment requereixen aprovació" defaultNoteVisibility: "Visibilitat per defecte" follow: "Seguint" -followRequest: "Enviar la sol·licitud de seguiment" +followRequest: "Enviar sol·licitud de seguiment" followRequests: "Sol·licituds de seguiment" unfollow: "Deixar de seguir" followRequestPending: "Sol·licituds de seguiment pendents" enterEmoji: "Introduir un emoji" -renote: "Impulsa" +renote: "Impulsar " unrenote: "Anul·la l'impuls" renoted: "S'ha impulsat" renotedToX: "Impulsat per {name}." cantRenote: "No es pot impulsar aquesta publicació" -cantReRenote: "No es pot impulsar l'impuls." +cantReRenote: "No es pot impulsar un impuls." quote: "Cita" -inChannelRenote: "Renotar només al Canal" -inChannelQuote: "Citar només al Canal" -renoteToChannel: "Impulsa a un canal" -renoteToOtherChannel: "Impulsa a un altre canal" +inChannelRenote: "Impulsar només a un canal" +inChannelQuote: "Citar només a un canal" +renoteToChannel: "Impulsar a un canal" +renoteToOtherChannel: "Impulsar a un altre canal" pinnedNote: "Nota fixada" pinned: "Fixar al perfil" you: "Tu" clickToShow: "Fes clic per mostrar" -sensitive: "NSFW" +sensitive: "Sensible" add: "Afegir" -reaction: "Reaccions" +reaction: "Reacció " reactions: "Reaccions" -emojiPicker: "Selecció d'emojis" -pinnedEmojisForReactionSettingDescription: "Selecciona l'emoji amb el qual reaccionar" -pinnedEmojisSettingDescription: "Selecciona l'emoji amb el qual reaccionar" -emojiPickerDisplay: "Visualitza el selector d'emojis" +emojiPicker: "Selector d'emojis" +pinnedEmojisForReactionSettingDescription: "Selecciona l'emoji amb qui vols reaccionar" +pinnedEmojisSettingDescription: "Selecciona quins emojis vols deixar fixats i es mostrin en obrir el selector d'emojis" +emojiPickerDisplay: "Mostrar el selector d'emojis" overwriteFromPinnedEmojisForReaction: "Reemplaça els emojis de la reacció" -overwriteFromPinnedEmojis: "Sobreescriu des dels emojis fixats" +overwriteFromPinnedEmojis: "Sobreescriu els emojis fixats al panel de reaccions" reactionSettingDescription2: "Arrossega per reordenar, fes clic per suprimir, prem \"+\" per afegir." rememberNoteVisibility: "Recorda la configuració de visibilitat de les notes" attachCancel: "Eliminar el fitxer adjunt" deleteFile: "Esborrar l'arxiu " -markAsSensitive: "Marcar com a NSFW" +markAsSensitive: "Marcar com a sensible" unmarkAsSensitive: "Deixar de marcar com a sensible" enterFileName: "Defineix nom del fitxer" mute: "Silencia" unmute: "Deixa de silenciar" -renoteMute: "Silenciar Renotes" -renoteUnmute: "Treure el silenci de les renotes" +renoteMute: "Silenciar impulsos" +renoteUnmute: "Treure el silenci dels impulsos" block: "Bloqueja" unblock: "Desbloqueja" suspend: "Suspèn" unsuspend: "Deixa de suspendre" -blockConfirm: "Vols bloquejar?" +blockConfirm: "Vols bloquejar-lo?" unblockConfirm: "Vols desbloquejar-lo?" suspendConfirm: "Estàs segur que vols suspendre aquest compte?" unsuspendConfirm: "Estàs segur que vols treure la suspensió d'aquest compte?" @@ -175,11 +175,11 @@ youCanCleanRemoteFilesCache: "Pots netejar la memòria cau fent clic al botó de cacheRemoteSensitiveFiles: "Posar a la memòria cau arxius remots sensibles" cacheRemoteSensitiveFilesDescription: "Quan aquesta opció és desactiva, els arxius remots sensibles es carregant directament del servidor d'origen sense que es guardin a la memòria cau." flagAsBot: "Marca aquest compte com a bot" -flagAsBotDescription: "Marca aquest compte com a bot" +flagAsBotDescription: "Activa aquesta opció si el compte el controla un programa. Si s'activa, actuarà com un senyal per altres desenvolupadors per prevenir cadenes d'interacció sense fi i ajustar els paràmetres interns de Misskey pe tractar el compte com un bot." flagAsCat: "Marca aquest compte com a gat" flagAsCatDescription: "Activeu aquesta opció per marcar aquest compte com a gat." flagShowTimelineReplies: "Mostra les respostes a la línia de temps" -flagShowTimelineRepliesDescription: "Mostra les respostes a la línia de temps" +flagShowTimelineRepliesDescription: "Mostra les respostes dels usuaris a les notes d'altres usuaris a la línia de temps." autoAcceptFollowed: "Aprova automàticament les sol·licituds de seguiment dels usuaris que segueixes" addAccount: "Afegeix un compte" reloadAccountsList: "Recarregar la llista de contactes" @@ -204,7 +204,7 @@ selectUser: "Selecciona usuari/a" recipient: "Destinatari" annotation: "Comentaris" federation: "Federació" -instances: "Servidors" +instances: "Instàncies " registeredAt: "Registrat a" latestRequestReceivedAt: "Última petició rebuda" latestStatus: "Últim estat" @@ -213,7 +213,7 @@ charts: "Gràfics" perHour: "Per hora" perDay: "Per dia" stopActivityDelivery: "Deixa d'enviar activitats" -blockThisInstance: "Deixa d'enviar activitats" +blockThisInstance: "Bloca aquesta instància " silenceThisInstance: "Silencia aquesta instància " mediaSilenceThisInstance: "Silenciar els arxius d'aquesta instància " operations: "Accions" @@ -228,7 +228,7 @@ network: "Xarxa" disk: "Disc" instanceInfo: "Informació del fitxer d'instal·lació" statistics: "Estadístiques" -clearQueue: "Esborrar la cua" +clearQueue: "Esborra la cua de feina" clearQueueConfirmTitle: "Esteu segur que voleu esborrar la cua?" clearQueueConfirmText: "Les notes no lliurades que quedin a la cua no es federaran. Normalment aquesta operació no és necessària." clearCachedFiles: "Esborra la memòria cau" @@ -254,7 +254,7 @@ processing: "S'està processant..." preview: "Vista prèvia" default: "Per defecte" defaultValueIs: "Per defecte: {value}" -noCustomEmojis: "Cap emoji personalitzat" +noCustomEmojis: "No hi ha emojis personalitzats" noJobs: "No hi ha feines" federating: "Federant" blocked: "Bloquejat" @@ -268,11 +268,11 @@ instanceFollowers: "Seguidors del servidor" instanceUsers: "Usuaris del servidor" changePassword: "Canvia la contrasenya" security: "Seguretat" -retypedNotMatch: "L'entrada no coincideix" +retypedNotMatch: "Les entrades no coincideix" currentPassword: "Contrasenya actual" newPassword: "Contrasenya nova" -newPasswordRetype: "Contrasenya nou (repeteix-la)" -attachFile: "Adjunta fitxers" +newPasswordRetype: "Contrasenya nova (repeteix-la)" +attachFile: "Afegeix un arxiu" more: "Més" featured: "Destacat" usernameOrUserId: "Nom o ID d'usuari" @@ -282,25 +282,25 @@ announcements: "Anuncis" imageUrl: "URL de la imatge" remove: "Eliminar" removed: "Eliminat" -removeAreYouSure: "Segur que voleu retirar «{x}»?" -deleteAreYouSure: "Segur que voleu retirar «{x}»?" -resetAreYouSure: "Segur que voleu restablir-ho?" -areYouSure: "Està segur?" +removeAreYouSure: "Segur que vols esborrar «{x}»?" +deleteAreYouSure: "Segur que vols esborrar «{x}»?" +resetAreYouSure: "Segur que vols restablir-ho?" +areYouSure: "Estàs segur?" saved: "S'ha desat" messaging: "Xat" upload: "Puja" keepOriginalUploading: "Guarda la imatge original" -keepOriginalUploadingDescription: "Guarda la imatge pujada com hi és. Si està apagat, una versió per a la visualització a la xarxa serà generada quan sigui pujada." -fromDrive: "Des de la unitat" +keepOriginalUploadingDescription: "Guarda la imatge pujada sense modificar. Si està desactivat, es generarà una versió per visualitzar a la web en pujar la imatge." +fromDrive: "Des del Disc" fromUrl: "Des d'un enllaç" uploadFromUrl: "Carrega des d'un enllaç" uploadFromUrlDescription: "Enllaç del fitxer que vols carregar" uploadFromUrlRequested: "Càrrega sol·licitada" -uploadFromUrlMayTakeTime: "La càrrega des de l'enllaç pot prendre un temps" +uploadFromUrlMayTakeTime: "La càrrega des de l'enllaç pot trigar un temps" explore: "Explora" messageRead: "Vist" -noMoreHistory: "No hi resta més per veure" -startMessaging: "Començar a xatejar" +noMoreHistory: "No hi ha res més per veure" +startMessaging: "Comença a xatejar" nUsersRead: "Vist per {n}" agreeTo: "Accepto que {0}" agree: "Hi estic d'acord" @@ -312,7 +312,7 @@ home: "Inici" remoteUserCaution: "Ja que aquest usuari resideix a una instància remota, la informació mostrada es podria trobar incompleta." activity: "Activitat" images: "Imatges" -image: "Imatges" +image: "Imatge" birthday: "Aniversari" yearsOld: "{age} anys" registeredDate: "Data de registre" @@ -327,10 +327,10 @@ darkThemes: "Temes foscos" syncDeviceDarkMode: "Sincronitza el mode fosc amb la configuració del dispositiu" drive: "Unitat" fileName: "Nom del Fitxer" -selectFile: "Selecciona fitxers" +selectFile: "Selecciona un fitxer" selectFiles: "Selecciona fitxers" selectFolder: "Selecció de carpeta" -selectFolders: "Selecció de carpeta" +selectFolders: "Selecció de carpetes" fileNotSelected: "Cap fitxer seleccionat" renameFile: "Canvia el nom del fitxer" folderName: "Nom de la carpeta" @@ -359,9 +359,9 @@ reload: "Actualitza" doNothing: "Ignora" reloadConfirm: "Vols recarregar?" watch: "Veure" -unwatch: "Deixar de veure" +unwatch: "Deixa de veure" accept: "Acceptar" -reject: "Denegar" +reject: "Denega" normal: "Normal" instanceName: "Nom del servidor" instanceDescription: "Descripció del servidor" @@ -382,7 +382,7 @@ enableLocalTimeline: "Activa la línia de temps local" enableGlobalTimeline: "Activa la línia de temps global" disablingTimelinesInfo: "Fins i tot si aquestes línies de temps són desactivades, els administradors i els moderadors poden continuar visualitzant per conveniència." registration: "Registre" -enableRegistration: "Permet els registres d'usuaris" +enableRegistration: "Permet el registre de nous usuaris" invite: "Convida" driveCapacityPerLocalAccount: "Capacitat del disc per usuaris locals" driveCapacityPerRemoteAccount: "Capacitat del disc per usuaris remots" @@ -393,20 +393,20 @@ basicInfo: "Informació bàsica" pinnedUsers: "Usuaris fixats" pinnedUsersDescription: "Llista d'usuaris, separats per salts de línia, que seran fixats a la pestanya \"Explorar\"." pinnedPages: "Pàgines fixades" -pinnedPagesDescription: "Escriu els camins de les pàgines que vols fixar a la pàgina d'inici d'aquesta instància. Separades per salts de línia." +pinnedPagesDescription: "Escriu les adreces de les pàgines que vols fixar a la pàgina d'inici d'aquesta instància. Separades per salts de línia." pinnedClipId: "ID del retall fixat" pinnedNotes: "Nota fixada" hcaptcha: "hCaptcha" -enableHcaptcha: "Activar hCaptcha" +enableHcaptcha: "Activa hCaptcha" hcaptchaSiteKey: "Clau del lloc" hcaptchaSecretKey: "Clau secreta" mcaptcha: "mCaptcha" -enableMcaptcha: "Activar mCaptcha" +enableMcaptcha: "Activa mCaptcha" mcaptchaSiteKey: "Clau del lloc" mcaptchaSecretKey: "Clau secreta" mcaptchaInstanceUrl: "Adreça URL del servidor mCaptcha" recaptcha: "reCAPTCHA" -enableRecaptcha: "Activar reCAPTCHA" +enableRecaptcha: "Activa reCAPTCHA" recaptchaSiteKey: "Clau del lloc" recaptchaSecretKey: "Clau secreta" turnstile: "Turnstile" @@ -448,14 +448,14 @@ aboutMisskey: "Quant a Misskey" administrator: "Administrador/a" token: "Codi de verificació" 2fa: "Autenticació de doble factor" -setupOf2fa: "Configurar l'autenticació de doble factor" +setupOf2fa: "Configura l'autenticació de doble factor" totp: "Aplicació d'autenticació" totpDescription: "Escriu una contrasenya d'un sol us fent servir l'aplicació d'autenticació" moderator: "Moderador/a" moderation: "Moderació" moderationNote: "Nota de moderació " moderationNoteDescription: "Pots escriure notes que es compartiran entre els moderadors." -addModerationNote: "Afegir una nota de moderació " +addModerationNote: "Afegeix una nota de moderació " moderationLogs: "Registre de moderació " nUsersMentioned: "{n} usuaris mencionats" securityKeyAndPasskey: "Clau de seguretat / Clau de pas" @@ -471,13 +471,13 @@ reduceUiAnimation: "Redueix les animacions de la interfície" share: "Comparteix" notFound: "No s'ha trobat" notFoundDescription: "No es troba cap pàgina que correspongui a aquesta adreça" -uploadFolder: "Carpeta per defecte per pujades" +uploadFolder: "Carpeta per defecte on desar els arxius pujats" markAsReadAllNotifications: "Marca totes les notificacions com a llegides" markAsReadAllUnreadNotes: "Marca-ho tot com a llegit" markAsReadAllTalkMessages: "Marcar tots els missatges com llegits" help: "Ajuda" inputMessageHere: "Escriu aquí el teu missatge " -close: "Tancar" +close: "Tanca" invites: "Convida" members: "Membres" transfer: "Transferir" @@ -508,7 +508,7 @@ normalPassword: "Bona contrasenya" strongPassword: "Contrasenya segura" passwordMatched: "Correcte!" passwordNotMatched: "No coincideix" -signinWith: "Inicia sessió amb amb {x}" +signinWith: "Inicia sessió amb {x}" signinFailed: "Autenticació sense èxit. Intenta-ho un altre cop utilitzant la contrasenya i el nom correctes." or: "O" language: "Idioma" @@ -591,7 +591,7 @@ chooseEmoji: "Tria un emoji" unableToProcess: "L'operació no pot ser completada " recentUsed: "Utilitzat recentment" install: "Instal·lació " -uninstall: "Desinstal·lar " +uninstall: "Desinstal·la" installedApps: "Aplicacions autoritzades " nothing: "No hi ha res per veure aquí " installedDate: "Data d'instal·lació" @@ -608,13 +608,13 @@ output: "Sortida" script: "Script" disablePagesScript: "Desactivar AiScript a les pàgines " updateRemoteUser: "Actualitzar la informació de l'usuari remot" -unsetUserAvatar: "Desactivar l'avatar " +unsetUserAvatar: "Desactiva l'avatar " unsetUserAvatarConfirm: "Segur que vols desactivar l'avatar?" -unsetUserBanner: "Desactivar el bàner " +unsetUserBanner: "Desactiva el bàner " unsetUserBannerConfirm: "Segur que vols desactivar el bàner?" -deleteAllFiles: "Esborrar tots els arxius" +deleteAllFiles: "Esborra tots els arxius" deleteAllFilesConfirm: "Segur que vols esborrar tots els arxius?" -removeAllFollowing: "Deixar de seguir tots els usuaris seguits" +removeAllFollowing: "Deixa de seguir tots els usuaris seguits" removeAllFollowingDescription: "El fet d'executar això, et farà deixar de seguir a tots els usuaris de {host}. Si us plau, executa això si l'amfitrió, per exemple, ja no existeix." userSuspended: "Aquest usuari ha sigut suspès" userSilenced: "Aquest usuari està sent silenciat" @@ -1183,8 +1183,8 @@ currentAnnouncements: "Informes actuals" pastAnnouncements: "Informes passats" youHaveUnreadAnnouncements: "Tens informes per llegir." useSecurityKey: "Segueix les instruccions del teu navegador O dispositiu per fer servir el teu passkey." -replies: "Respondre" -renotes: "Impulsa" +replies: "Respon" +renotes: "Impulsar " loadReplies: "Mostrar les respostes" loadConversation: "Mostrar la conversació " pinnedList: "Llista fixada" @@ -1299,6 +1299,7 @@ yourNameContainsProhibitedWordsDescription: "Si de veritat vols fer servir aques thisContentsAreMarkedAsSigninRequiredByAuthor: "L'autor requereix l'inici de sessió per poder veure" lockdown: "Bloquejat" pleaseSelectAccount: "Seleccionar un compte" +availableRoles: "Roles disponibles " _accountSettings: requireSigninToViewContents: "És obligatori l'inici de sessió per poder veure el contingut" requireSigninToViewContentsDescription1: "Es requereix l'inici de sessió per poder veure totes les notes i el contingut que has creat. Amb això esperem evitar que els rastrejadors recopilin informació." diff --git a/locales/de-DE.yml b/locales/de-DE.yml index 4e2bd06934..1aacbabbba 100644 --- a/locales/de-DE.yml +++ b/locales/de-DE.yml @@ -8,6 +8,8 @@ search: "Suchen" notifications: "Benachrichtigungen" username: "Benutzername" password: "Passwort" +initialPasswordForSetup: "Initiales Passwort für die Einrichtung" +initialPasswordIsIncorrect: "Das initiale Passwort für die Einrichtung ist falsch" forgotPassword: "Passwort vergessen" fetchingAsApObject: "Wird aus dem Fediverse angefragt …" ok: "OK" @@ -60,6 +62,7 @@ copyFileId: "Datei-ID kopieren" copyFolderId: "Ordner-ID kopieren" copyProfileUrl: "Profil-URL kopieren" searchUser: "Nach einem Benutzer suchen" +searchThisUsersNotes: "Notizen dieses Benutzers suchen" reply: "Antworten" loadMore: "Mehr laden" showMore: "Mehr anzeigen" @@ -150,6 +153,7 @@ editList: "Liste bearbeiten" selectChannel: "Kanal auswählen" selectAntenna: "Antenne auswählen" editAntenna: "Antenne bearbeiten" +createAntenna: "Erstelle eine Antenne" selectWidget: "Widget auswählen" editWidgets: "Widgets bearbeiten" editWidgetsExit: "Fertig" @@ -186,6 +190,7 @@ followConfirm: "Möchtest du {name} wirklich folgen?" proxyAccount: "Proxy-Benutzerkonto" proxyAccountDescription: "Ein Proxy-Konto ist ein Benutzerkonto, das unter bestimmten Bedingungen als Follower für Benutzer fremder Instanzen fungiert. Wenn zum Beispiel ein Benutzer einen Benutzer einer fremden Instanz zu einer Liste hinzufügt, werden die Aktivitäten des entfernten Benutzers nicht an die Instanz übermittelt, wenn kein lokaler Benutzer diesem Benutzer folgt; stattdessen folgt das Proxy-Konto." host: "Hostname" +selectSelf: "Mich auswählen" selectUser: "Benutzer auswählen" recipient: "Empfänger" annotation: "Anmerkung" @@ -312,6 +317,7 @@ selectFile: "Datei auswählen" selectFiles: "Dateien auswählen" selectFolder: "Ordner auswählen" selectFolders: "Ordner auswählen" +fileNotSelected: "Keine Datei ausgewählt" renameFile: "Datei umbenennen" folderName: "Ordnername" createFolder: "Ordner erstellen" @@ -399,6 +405,7 @@ name: "Name" antennaSource: "Antennenquelle" antennaKeywords: "Zu beobachtende Schlüsselwörter" antennaExcludeKeywords: "Zu ignorierende Schlüsselwörter" +antennaExcludeBots: "Bot-Accounts ausschließen" antennaKeywordsDescription: "Zum Nutzen einer \"UND\"-Verknüpfung Einträge mit Leerzeichen trennen, zum Nutzen einer \"ODER\"-Verknüpfung Einträge mit einem Zeilenumbruch trennen" notifyAntenna: "Über neue Notizen benachrichtigen" withFileAntenna: "Nur Notizen mit Dateien" @@ -885,6 +892,7 @@ unmuteThread: "Threadstummschaltung aufheben" continueThread: "Weiteren Threadverlauf anzeigen" deleteAccountConfirm: "Dein Benutzerkonto wird unwiderruflich gelöscht. Trotzdem fortfahren?" incorrectPassword: "Falsches Passwort." +incorrectTotp: "Das Einmalpasswort ist falsch oder abgelaufen." voteConfirm: "Wirklich für „{choice}“ abstimmen?" hide: "Inhalt verbergen" useDrawerReactionPickerForMobile: "Auf mobilen Geräten ausfahrbare Reaktionsauswahl anzeigen" @@ -909,6 +917,9 @@ oneHour: "Eine Stunde" oneDay: "Einen Tag" oneWeek: "Eine Woche" oneMonth: "1 Monat" +threeMonths: "3 Monate" +oneYear: "1 Jahr" +threeDays: "3 Tage" reflectMayTakeTime: "Es kann etwas dauern, bis sich dies widerspiegelt." failedToFetchAccountInformation: "Benutzerkontoinformationen konnten nicht abgefragt werden" rateLimitExceeded: "Versuchsanzahl überschritten" @@ -982,6 +993,7 @@ neverShow: "Nicht wieder anzeigen" remindMeLater: "Vielleicht später" didYouLikeMisskey: "Gefällt dir Misskey?" pleaseDonate: "Misskey ist die kostenlose Software, die von {host} verwendet wird. Wir würden uns über Spenden freuen, damit dessen Entwicklung weitergeführt werden kann!" +correspondingSourceIsAvailable: "Der entsprechende Quellcode ist verfügbar unter {anchor}" roles: "Rollen" role: "Rolle" noRole: "Rolle nicht gefunden" @@ -1032,6 +1044,7 @@ resetPasswordConfirm: "Wirklich Passwort zurücksetzen?" sensitiveWords: "Sensible Wörter" sensitiveWordsDescription: "Die Notizsichtbarkeit aller Notizen, die diese Wörter enthalten, wird automatisch auf \"Startseite\" gesetzt. Durch Zeilenumbrüche können mehrere konfiguriert werden." sensitiveWordsDescription2: "Durch die Verwendung von Leerzeichen können AND-Verknüpfungen angegeben werden und durch das Umgeben von Schrägstrichen können reguläre Ausdrücke verwendet werden." +prohibitedWords: "Verbotene Wörter" prohibitedWordsDescription2: "Durch die Verwendung von Leerzeichen können AND-Verknüpfungen angegeben werden und durch das Umgeben von Schrägstrichen können reguläre Ausdrücke verwendet werden." hiddenTags: "Ausgeblendete Hashtags" hiddenTagsDescription: "Die hier eingestellten Tags werden nicht mehr in den Trends angezeigt. Mit der Umschalttaste können mehrere ausgewählt werden." @@ -1078,6 +1091,8 @@ preservedUsernames: "Reservierte Benutzernamen" preservedUsernamesDescription: "Gib zu reservierende Benutzernamen durch Zeilenumbrüche getrennt an. Diese werden für die Registrierung gesperrt, können aber von Administratoren zur manuellen Erstellung von Konten verwendet werden. Existierende Konten, die diese Namen bereits verwenden, werden nicht beeinträchtigt." createNoteFromTheFile: "Notiz für diese Datei schreiben" archive: "Archivieren" +archived: "Archiviert" +unarchive: "Dearchivieren" channelArchiveConfirmTitle: "{name} wirklich archivieren?" channelArchiveConfirmDescription: "Ein archivierter Kanal taucht nicht mehr in der Kanalliste oder in Suchergebnissen auf. Zudem können ihm keine Beiträge mehr hinzugefügt werden." thisChannelArchived: "Dieser Kanal wurde archiviert." @@ -1176,15 +1191,35 @@ signupPendingError: "Beim Überprüfen der Mailadresse ist etwas schiefgelaufen. cwNotationRequired: "Ist \"Inhaltswarnung verwenden\" aktiviert, muss eine Beschreibung gegeben werden." doReaction: "Reagieren" code: "Code" +remainingN: "Verbleibend: {n}" decorate: "Dekorieren" addMfmFunction: "MFM hinzufügen" sfx: "Soundeffekte" +showReplay: "Wiederholung anzeigen" lastNDays: "Letzten {n} Tage" surrender: "Abbrechen" +keepOriginalFilename: "Ursprünglichen Dateinamen beibehalten" +tryAgain: "Bitte später erneut versuchen" +confirmWhenRevealingSensitiveMedia: "Das Anzeigen von sensiblen Medien bestätigen" +createdLists: "Erstellte Listen" +createdAntennas: "Erstellte Antennen" +genEmbedCode: "Einbettungscode generieren" +noteOfThisUser: "Notizen dieses Benutzers" +clipNoteLimitExceeded: "Zu diesem Clip können keine weiteren Notizen hinzugefügt werden." +discard: "Verwerfen" +signinWithPasskey: "Mit Passkey anmelden" +passkeyVerificationFailed: "Die Passkey-Verifizierung ist fehlgeschlagen." +passkeyVerificationSucceededButPasswordlessLoginDisabled: "Die Verifizierung des Passkeys war erfolgreich, aber die passwortlose Anmeldung ist deaktiviert." +pleaseSelectAccount: "Bitte Konto auswählen" +availableRoles: "Verfügbare Rollen" +_abuseUserReport: + forward: "Weiterleiten" _delivery: stop: "Gesperrt" _type: none: "Wird veröffentlicht" +_bubbleGame: + howToPlay: "Wie man spielt" _announcement: forExistingUsers: "Nur für existierende Nutzer" forExistingUsersDescription: "Ist diese Option aktiviert, wird diese Ankündigung nur Nutzern angezeigt, die zum Zeitpunkt der Ankündigung bereits registriert sind. Ist sie deaktiviert, wird sie auch Nutzern, die sich nach dessen Veröffentlichung registrieren, angezeigt." @@ -1515,6 +1550,10 @@ _achievements: description: "Betätige den Benachrichtigungstest mehrfach innerhalb einer extrem kurzen Zeitspanne" _tutorialCompleted: description: "Tutorial abgeschlossen" + _bubbleGameExplodingHead: + title: "🤯" + _bubbleGameDoubleExplodingHead: + title: "Doppel🤯" _role: new: "Rolle erstellen" edit: "Rolle bearbeiten" @@ -2115,6 +2154,7 @@ _notification: pollEnded: "Umfrageergebnisse sind verfügbar" newNote: "Neue Notiz" unreadAntennaNote: "Antenne {name}" + roleAssigned: "Rolle zugewiesen" emptyPushNotificationMessage: "Push-Benachrichtigungen wurden aktualisiert" achievementEarned: "Errungenschaft freigeschaltet" testNotification: "Testbenachrichtigung" diff --git a/locales/en-US.yml b/locales/en-US.yml index 8570addfa2..6703d1cf3a 100644 --- a/locales/en-US.yml +++ b/locales/en-US.yml @@ -331,6 +331,7 @@ selectFile: "Select a file" selectFiles: "Select files" selectFolder: "Select a folder" selectFolders: "Select folders" +fileNotSelected: "No file selected" renameFile: "Rename file" folderName: "Folder name" createFolder: "Create a folder" @@ -1298,6 +1299,7 @@ yourNameContainsProhibitedWordsDescription: "If you wish to use this name, pleas thisContentsAreMarkedAsSigninRequiredByAuthor: "Set by the author to require login to view" lockdown: "Lockdown" pleaseSelectAccount: "Select an account" +availableRoles: "Available roles" _accountSettings: requireSigninToViewContents: "Require sign-in to view contents" requireSigninToViewContentsDescription1: "Require login to view all notes and other content you have created. This will have the effect of preventing crawlers from collecting your information." @@ -2223,7 +2225,7 @@ _widgets: _userList: chooseList: "Select a list" clicker: "Clicker" - birthdayFollowings: "Users who celebrate their birthday today" + birthdayFollowings: "Today's Birthdays" _cw: hide: "Hide" show: "Show content" @@ -2730,3 +2732,9 @@ _embedCodeGen: generateCode: "Generate embed code" codeGenerated: "The code has been generated" codeGeneratedDescription: "Paste the generated code into your website to embed the content." +_selfXssPrevention: + warning: "WARNING" + title: "\"Paste something on this screen\" is all a scam." + description1: "If you paste something here, a malicious user could hijack your account or steal your personal information." + description2: "If you do not understand exactly what you are trying to paste, %cstop working right now and close this window." + description3: "For more information, please refer to this. {link}" diff --git a/locales/index.d.ts b/locales/index.d.ts index 81613651b6..637d32e9c6 100644 --- a/locales/index.d.ts +++ b/locales/index.d.ts @@ -1546,10 +1546,6 @@ export interface Locale extends ILocale { * 登録 */ "registration": string; - /** - * 誰でも新規登録できるようにする - */ - "enableRegistration": string; /** * 招待 */ @@ -5218,6 +5214,10 @@ export interface Locale extends ILocale { * 利用可能なロール */ "availableRoles": string; + /** + * 注意事項を理解した上でオンにします。 + */ + "acknowledgeNotesAndEnable": string; /** * デフォルトでフォローするユーザー (ID) */ @@ -5826,6 +5826,14 @@ export interface Locale extends ILocale { * サーバー運営者へのお問い合わせフォームのURLや、運営者の連絡先等が記載されたWebページのURLを指定します。 */ "inquiryUrlDescription": string; + /** + * アカウントの作成をオープンにする + */ + "openRegistration": string; + /** + * 登録を開放することはリスクが伴います。サーバーを常に監視し、トラブルが発生した際にすぐに対応できる体制がある場合のみオンにすることを推奨します。 + */ + "openRegistrationWarning": string; /** * 一定期間モデレーターのアクティビティが検出されなかった場合、スパム防止のためこの設定は自動でオフになります。 */ @@ -10611,6 +10619,16 @@ export interface Locale extends ILocale { */ "description3": ParameterizedString<"link">; }; + "_followRequest": { + /** + * 受け取った申請 + */ + "recieved": string; + /** + * 送った申請 + */ + "sent": string; + }; } declare const locales: { [lang: string]: Locale; diff --git a/locales/ja-JP.yml b/locales/ja-JP.yml index 61c2cf050a..4e3f9835f6 100644 --- a/locales/ja-JP.yml +++ b/locales/ja-JP.yml @@ -382,7 +382,6 @@ enableLocalTimeline: "ローカルタイムラインを有効にする" enableGlobalTimeline: "グローバルタイムラインを有効にする" disablingTimelinesInfo: "これらのタイムラインを無効化しても、利便性のため管理者およびモデレーターは引き続き利用することができます。" registration: "登録" -enableRegistration: "誰でも新規登録できるようにする" invite: "招待" driveCapacityPerLocalAccount: "ローカルユーザーひとりあたりのドライブ容量" driveCapacityPerRemoteAccount: "リモートユーザーひとりあたりのドライブ容量" @@ -1300,6 +1299,7 @@ thisContentsAreMarkedAsSigninRequiredByAuthor: "投稿者により、表示に lockdown: "ロックダウン" pleaseSelectAccount: "アカウントを選択してください" availableRoles: "利用可能なロール" +acknowledgeNotesAndEnable: "注意事項を理解した上でオンにします。" defaultFollowedUsers: "デフォルトでフォローするユーザー (ID)" defaultFollowedUsersDescription: "今後アカウントが作成された際に自動でフォローされるユーザー(解除可能)のユーザーIDを改行区切りで指定します。" forciblyFollowedUsers: "交流を断てないユーザー (ID)" @@ -1474,6 +1474,8 @@ _serverSettings: reactionsBufferingDescription: "有効にすると、リアクション作成時のパフォーマンスが大幅に向上し、データベースへの負荷を軽減することが可能です。ただし、Redisのメモリ使用量は増加します。" inquiryUrl: "問い合わせ先URL" inquiryUrlDescription: "サーバー運営者へのお問い合わせフォームのURLや、運営者の連絡先等が記載されたWebページのURLを指定します。" + openRegistration: "アカウントの作成をオープンにする" + openRegistrationWarning: "登録を開放することはリスクが伴います。サーバーを常に監視し、トラブルが発生した際にすぐに対応できる体制がある場合のみオンにすることを推奨します。" thisSettingWillAutomaticallyOffWhenModeratorsInactive: "一定期間モデレーターのアクティビティが検出されなかった場合、スパム防止のためこの設定は自動でオフになります。" _accountMigration: @@ -2827,3 +2829,7 @@ _selfXssPrevention: description1: "ここに何かを貼り付けると、悪意のあるユーザーにアカウントを乗っ取られたり、個人情報を盗まれたりする可能性があります。" description2: "貼り付けようとしているものが何なのかを正確に理解していない場合は、%c今すぐ作業を中止してこのウィンドウを閉じてください。" description3: "詳しくはこちらをご確認ください。 {link}" + +_followRequest: + recieved: "受け取った申請" + sent: "送った申請" diff --git a/locales/ko-KR.yml b/locales/ko-KR.yml index 414202adab..5d07ebe244 100644 --- a/locales/ko-KR.yml +++ b/locales/ko-KR.yml @@ -42,7 +42,7 @@ favorite: "즐겨찾기" favorites: "즐겨찾기" unfavorite: "즐겨찾기에서 제거" favorited: "즐겨찾기에 등록했습니다." -alreadyFavorited: "이미 즐겨찾기에 등록했습니다." +alreadyFavorited: "이미 즐겨찾기에 등록되어 있습니다." cantFavorite: "즐겨찾기에 등록하지 못했습니다." pin: "프로필에 고정" unpin: "프로필에서 고정 해제" @@ -947,6 +947,9 @@ oneHour: "1시간" oneDay: "1일" oneWeek: "일주일" oneMonth: "1개월" +threeMonths: "3개월" +oneYear: "1년" +threeDays: "3일" reflectMayTakeTime: "반영되기까지 시간이 걸릴 수 있습니다." failedToFetchAccountInformation: "계정 정보를 가져오지 못했습니다" rateLimitExceeded: "요청 제한 횟수를 초과하였습니다" @@ -1286,13 +1289,29 @@ signinWithPasskey: "패스키로 로그인" unknownWebAuthnKey: "등록되지 않은 패스키입니다." passkeyVerificationFailed: "패스키 검증을 실패했습니다." passkeyVerificationSucceededButPasswordlessLoginDisabled: "패스키를 검증했으나, 비밀번호 없이 로그인하기가 꺼져 있습니다." -messageToFollower: "팔로워에 보낼 메시지" +messageToFollower: "팔로워에게 보낼 메시지" target: "대상" testCaptchaWarning: "CAPTCHA를 테스트하기 위한 기능입니다. 실제 환경에서는 사용하지 마세요." prohibitedWordsForNameOfUser: "금지 단어 (사용자 이름)" prohibitedWordsForNameOfUserDescription: "이 목록에 포함되는 키워드가 사용자 이름에 있는 경우, 일반 사용자는 이름을 바꿀 수 없습니다. 모더레이터 권한을 가진 사용자는 제한 대상에서 제외됩니다." yourNameContainsProhibitedWords: "바꾸려는 이름에 금지된 키워드가 포함되어 있습니다." yourNameContainsProhibitedWordsDescription: "이름에 금지된 키워드가 있습니다. 이름을 사용해야 하는 경우, 서버 관리자에 문의하세요." +thisContentsAreMarkedAsSigninRequiredByAuthor: "게시자에 의해 로그인해야 볼 수 있도록 설정되어 있습니다." +lockdown: "잠금" +pleaseSelectAccount: "계정을 선택해주세요." +availableRoles: "사용 가능한 역할" +_accountSettings: + requireSigninToViewContents: "콘텐츠 열람을 위해 로그인으 필수로 설정하기" + requireSigninToViewContentsDescription1: "자신이 작성한 모든 노트 등의 콘텐츠를 보기 위해 로그인을 필수로 설정합니다. 크롤러가 정보 수집하는 것을 방지하는 효과를 기대할 수 있습니다." + requireSigninToViewContentsDescription2: "URL 미리보기(OGP), 웹페이지에 삽입, 노트 인용을 지원하지 않는 서버에서 볼 수 없게 됩니다." + requireSigninToViewContentsDescription3: "원격 서버에 연합된 콘텐츠에는 이러한 제한이 적용되지 않을 수 있습니다." + makeNotesFollowersOnlyBefore: "과거 노트는 팔로워만 볼 수 있도록 설정하기" + makeNotesFollowersOnlyBeforeDescription: "이 기능이 활성화되어 있는 동안, 설정된 날짜 및 시간보다 과거 또는 설정된 시간이 지난 노트는 팔로워만 볼 수 있게 됩니다.비활성화하면 노트의 공개 상태도 원래대로 돌아갑니다." + makeNotesHiddenBefore: "과거 노트 비공개로 전환하기" + makeNotesHiddenBeforeDescription: "이 기능이 활성화되어 있는 동안 설정한 날짜 및 시간보다 과거 또는 설정한 시간이 지난 노트는 본인만 볼 수 있게(비공개로 전환) 됩니다. 비활성화하면 노트의 공개 상태도 원래대로 돌아갑니다." + mayNotEffectForFederatedNotes: "원격 서버에 연합된 노트에는 효과가 없을 수도 있습니다." + notesHavePassedSpecifiedPeriod: "지정한 시간이 경과된 노트" + notesOlderThanSpecifiedDateAndTime: "지정된 날짜 및 시간 이전의 노트" _abuseUserReport: forward: "전달" forwardDescription: "익명 시스템 계정을 사용하여 리모트 서버에 신고 내용을 전달할 수 있습니다." @@ -2157,8 +2176,11 @@ _auth: permissionAsk: "이 앱은 다음의 권한을 요청합니다" pleaseGoBack: "앱으로 돌아가서 시도해 주세요" callback: "앱으로 돌아갑니다" + accepted: "접근 권한이 부여되었습니다." denied: "접근이 거부되었습니다" + scopeUser: "다음 사용자로 활동하고 있습니다." pleaseLogin: "어플리케이션의 접근을 허가하려면 로그인하십시오." + byClickingYouWillBeRedirectedToThisUrl: "접근을 허용하면 자동으로 다음 URL로 이동합니다." _antennaSources: all: "모든 노트" homeTimeline: "팔로우중인 유저의 노트" @@ -2710,3 +2732,9 @@ _embedCodeGen: generateCode: "임베디드 코드를 만들기" codeGenerated: "코드를 만들었습니다." codeGeneratedDescription: "만들어진 코드를 웹 사이트에 붙여서 사용하세요." +_selfXssPrevention: + warning: "경고" + title: "“이 화면에 뭔가를 붙여넣어라\"는 것은 모두 사기입니다." + description1: "여기에 무언가를 붙여넣으면 악의적인 사용자에게 계정을 탈취당하거나 개인정보를 도용당할 수 있습니다." + description2: "붙여 넣으려는 항목이 무엇인지 정확히 이해하지 못하는 경우, %c지금 바로 작업을 중단하고 이 창을 닫으십시오." + description3: "자세한 내용은 여기를 확인해 주세요. {link}" diff --git a/locales/sv-SE.yml b/locales/sv-SE.yml index 5a0de660e8..4945e0f677 100644 --- a/locales/sv-SE.yml +++ b/locales/sv-SE.yml @@ -385,6 +385,7 @@ passwordLessLoginDescription: "Tillåter lösenordsfri inloggning med endast en resetPassword: "Återställ Lösenord" newPasswordIs: "Det nya lösenordet är \"{password}\"" share: "Dela" +markAsReadAllTalkMessages: "Markera alla meddelanden som lästa" help: "Hjälp" close: "Stäng" invites: "Inbjudan" @@ -393,12 +394,15 @@ transfer: "Överför" text: "Text" enable: "Aktivera" next: "Nästa" +retype: "Ange igen" +noMessagesYet: "Inga meddelanden än" invitations: "Inbjudan" invitationCode: "Inbjudningskod" available: "Tillgängligt" weakPassword: "Svagt Lösenord" normalPassword: "Medel Lösenord" strongPassword: "Starkt Lösenord" +signinWith: "Logga in med {x}" signinFailed: "Kan inte logga in. Det angivna användarnamnet eller lösenordet är felaktigt." or: "eller" language: "Språk" @@ -410,70 +414,122 @@ existingAccount: "Existerande konto" regenerate: "Regenerera" fontSize: "Textstorlek" openImageInNewTab: "Öppna bild i ny flik" +appearance: "Utseende" clientSettings: "Klientinställningar" accountSettings: "Kontoinställningar" numberOfDays: "Antal dagar" +objectStorageUseSSL: "Använd SSL" +serverLogs: "Serverloggar" deleteAll: "Radera alla" sounds: "Ljud" sound: "Ljud" listen: "Lyssna" none: "Ingen" volume: "Volym" +notUseSound: "Inaktivera ljud" chooseEmoji: "Välj en emoji" recentUsed: "Senast använd" install: "Installera" uninstall: "Avinstallera" +deleteAllFiles: "Radera alla filer" +deleteAllFilesConfirm: "Är du säker på att du vill radera alla filer?" menu: "Meny" +addItem: "Lägg till objekt" serviceworkerInfo: "Måste vara aktiverad för pushnotiser." enableInfiniteScroll: "Ladda mer automatiskt" enablePlayer: "Öppna videospelare" +description: "Beskrivning" permission: "Behörigheter" enableAll: "Aktivera alla" +disableAll: "Inaktivera alla" edit: "Ändra" enableEmail: "Aktivera epost-utskick" email: "E-post" +emailAddress: "E-postadress" smtpHost: "Värd" smtpUser: "Användarnamn" smtpPass: "Lösenord" emptyToDisableSmtpAuth: "Lämna användarnamn och lösenord tomt för att avaktivera SMTP verifiering" +makeActive: "Aktivera" +copy: "Kopiera" +overview: "Översikt" logs: "Logg" +database: "Databas" channel: "kanal" create: "Skapa" other: "Mer" +abuseReports: "Rapporter" +reportAbuse: "Rapporter" +reportAbuseOf: "Rapportera {name}" +abuseReported: "Din rapport har skickats. Tack så mycket." send: "Skicka" openInNewTab: "Öppna i ny flik" createNew: "Skapa ny" +private: "Privat" i18nInfo: "Misskey översätts till många olika språk av volontärer. Du kan hjälpa till med översättningen på {link}." accountInfo: "Kontoinformation" +followersCount: "Antal följare" +yes: "Ja" +no: "Nej" clips: "Klipp" duplicate: "Duplicera" reloadToApplySetting: "Inställningen tillämpas efter sidan laddas om. Vill du göra det nu?" clearCache: "Rensa cache" onlineUsersCount: "{n} användare är online" +nUsers: "{n} användare" nNotes: "{n} Noter" backgroundColor: "Bakgrundsbild" textColor: "Text" +saveAs: "Spara som..." youAreRunningUpToDateClient: "Klienten du använder är uppdaterat." newVersionOfClientAvailable: "Ny version av klienten är tillgänglig." +editCode: "Redigera kod" publish: "Publicera" typingUsers: "{users} skriver" +goBack: "Tillbaka" +addDescription: "Lägg till beskrivning" info: "Om" +online: "Online" +active: "Aktiv" +offline: "Offline" enabled: "Aktiverad" +quickAction: "Snabbåtgärder" user: "Användare" +gallery: "Galleri" +popularPosts: "Populära inlägg" customCssWarn: "Den här inställningen borde bara ändrats av en som har rätta kunskaper. Om du ställer in det här fel så kan klienten sluta fungera rätt." global: "Global" squareAvatars: "Visa fyrkantiga profilbilder" sent: "Skicka" +searchResult: "Sökresultat" +learnMore: "Läs mer" misskeyUpdated: "Misskey har uppdaterats!" +translate: "Översätt" +controlPanel: "Kontrollpanel" +manageAccounts: "Hantera konton" incorrectPassword: "Fel lösenord." +hide: "Dölj" welcomeBackWithName: "Välkommen tillbaka, {name}" clickToFinishEmailVerification: "Tryck på [{ok}] för att slutföra bekräftelsen på e-postadressen." +size: "Storlek" searchByGoogle: "Sök" +indefinitely: "Aldrig" +tenMinutes: "10 minuter" +oneHour: "En timme" +oneDay: "En dag" +oneWeek: "En vecka" +oneMonth: "En månad" +threeMonths: "3 månader" +oneYear: "1 år" +threeDays: "3 dagar" file: "Filer" +label: "Etikett" cannotUploadBecauseNoFreeSpace: "Kan inte ladda upp filen för att det finns inget lagringsutrymme kvar." cannotUploadBecauseExceedsFileSizeLimit: "Kan inte ladda upp filen för att den är större än filstorleksgränsen." +beta: "Beta" enableAutoSensitive: "Automatisk NSFW markering" enableAutoSensitiveDescription: "Tillåter automatiskt detektering och marketing av NSFW media genom Maskininlärning när möjligt. Även om denna inställningen är avaktiverad, kan det vara aktiverat på hela instansen." +move: "Flytta" pushNotification: "Pushnotiser" subscribePushNotification: "Aktivera pushnotiser" unsubscribePushNotification: "Avaktivera pushnotiser" @@ -482,16 +538,38 @@ pushNotificationNotSupported: "Din webbläsare eller instans har inte stöd för windowMaximize: "Maximera" windowMinimize: "Minimera" windowRestore: "Återställ" +tools: "Verktyg" +like: "Gilla" pleaseDonate: "Misskey är en gratis programvara som används på {host}. Donera gärna för att göra utvecklingen ständigt, tack!" +roles: "Roll" +role: "Roll" +color: "Färg" resetPasswordConfirm: "Återställ verkligen ditt lösenord?" dataSaver: "Databesparing" icon: "Profilbild" +forYou: "För dig" replies: "Svara" renotes: "Omnotera" +loadReplies: "Visa svar" +loadConversation: "Visa konversation" +authentication: "Autentisering" +sourceCode: "Källkod" +doReaction: "Lägg till reaktion" +code: "Kod" +gameRetry: "Försök igen" +inquiry: "Kontakt" +tryAgain: "Försök igen senare" +signinWithPasskey: "Logga in med nyckel" +unknownWebAuthnKey: "Okänd nyckel" _delivery: stop: "Suspenderad" _type: none: "Publiceras" +_initialAccountSetting: + profileSetting: "Profilinställningar" +_initialTutorial: + _reaction: + title: "Vad är reaktioner?" _achievements: _types: _open3windows: @@ -499,13 +577,25 @@ _achievements: description: "Ha minst 3 fönster öppna samtidigt" _ffVisibility: public: "Publicera" + private: "Privat" +_ad: + back: "Tillbaka" +_gallery: + like: "Gilla" _email: _follow: title: "följde dig" +_aboutMisskey: + source: "Källkod" _channel: setBanner: "Välj banner" removeBanner: "Ta bort banner" + nameAndDescription: "Namn och beskrivning" +_menuDisplay: + hide: "Dölj" _theme: + description: "Beskrivning" + color: "Färg" keys: mention: "Nämn" renote: "Omnotera" @@ -530,13 +620,19 @@ _widgets: _userList: chooseList: "Välj lista" _cw: + hide: "Dölj" show: "Ladda mer" + chars: "{count} tecken" + files: "{count} fil(er)" +_poll: + infinite: "Aldrig" _visibility: home: "Hem" followers: "Följare" _profile: name: "Namn" username: "Användarnamn" + metadataLabel: "Etikett" changeAvatar: "Ändra profilbild" changeBanner: "Ändra banner" _exportOrImport: @@ -547,9 +643,12 @@ _exportOrImport: userLists: "Listor" _charts: federation: "Federation" + activeUsers: "Aktiva användare" _timelines: home: "Hem" global: "Global" +_play: + summary: "Beskrivning" _pages: blocks: image: "Bilder" @@ -584,3 +683,10 @@ _abuseReport: _moderationLogTypes: suspend: "Suspendera" resetPassword: "Återställ Lösenord" +_reversi: + blackOrWhite: "Svart/Vit" + rules: "Regler" + black: "Svart" + white: "Vit" +_selfXssPrevention: + warning: "VARNING" diff --git a/locales/vi-VN.yml b/locales/vi-VN.yml index 235497d844..fb8e898bf1 100644 --- a/locales/vi-VN.yml +++ b/locales/vi-VN.yml @@ -8,6 +8,9 @@ search: "Tìm kiếm" notifications: "Thông báo" username: "Tên người dùng" password: "Mật khẩu" +initialPasswordForSetup: "Mật khẩu ban đầu để thiết lập" +initialPasswordIsIncorrect: "Mật khẩu ban đầu đã nhập sai" +initialPasswordForSetupDescription: "Nếu bạn tự cài đặt Misskey, hãy sử dụng mật khẩu ban đầu của bạn đã nhập trong tệp cấu hình.\nNếu bạn đang sử dụng dịch vụ nào đó giống như dịch vụ lưu trữ của Misskey, hãy sử dụng mật khẩu ban đầu được cung cấp.\nNếu bạn chưa đặt mật khẩu ban đầu, vui lòng để trống và tiếp tục." forgotPassword: "Quên mật khẩu" fetchingAsApObject: "Đang nạp dữ liệu từ Fediverse..." ok: "Đồng ý" diff --git a/locales/zh-CN.yml b/locales/zh-CN.yml index 93804608c2..7a11f247ca 100644 --- a/locales/zh-CN.yml +++ b/locales/zh-CN.yml @@ -107,7 +107,7 @@ follow: "关注" followRequest: "关注申请" followRequests: "关注申请" unfollow: "取消关注" -followRequestPending: "关注请求批准中" +followRequestPending: "关注请求待批准" enterEmoji: "输入表情符号" renote: "转发" unrenote: "取消转发" @@ -136,7 +136,7 @@ overwriteFromPinnedEmojisForReaction: "从「置顶(回应)」设置覆盖" overwriteFromPinnedEmojis: "从全局设置覆盖" reactionSettingDescription2: "拖动重新排序,单击删除,点击 + 添加。" rememberNoteVisibility: "保存上次设置的可见性" -attachCancel: "删除附件" +attachCancel: "取消添加附件" deleteFile: "删除文件" markAsSensitive: "标记为敏感内容" unmarkAsSensitive: "取消标记为敏感内容" @@ -603,7 +603,7 @@ descendingOrder: "降序" scratchpad: "AiScript 控制台" scratchpadDescription: "AiScript 控制台为 AiScript 提供了实验环境。您可以编写代码与 Misskey 交互,运行并查看结果。" uiInspector: "UI 检查器" -uiInspectorDescription: "查看所有内存中由 UI 组件生成出的实例。UI 组件由 UI:C 系列函数所生成。" +uiInspectorDescription: "查看内存中所有由 UI 组件生成出的实例。UI 组件由 UI:C 系列函数所生成。" output: "输出" script: "脚本" disablePagesScript: "禁用页面脚本" @@ -856,9 +856,9 @@ user: "用户" administration: "管理" accounts: "账户" switch: "切换" -noMaintainerInformationWarning: "管理人员信息未设置。" +noMaintainerInformationWarning: "尚未设置管理员信息。" noInquiryUrlWarning: "尚未设置联络地址。" -noBotProtectionWarning: "Bot 防御未设置。" +noBotProtectionWarning: "尚未设置 Bot 防御。" configure: "设置" postToGallery: "发送到图库" postToHashtag: "投稿到这个标签" @@ -874,11 +874,11 @@ priority: "优先级" high: "高" middle: "中" low: "低" -emailNotConfiguredWarning: "电子邮件地址未设置。" +emailNotConfiguredWarning: "尚未设置电子邮件地址。" ratio: "比率" previewNoteText: "预览文本" customCss: "自定义 CSS" -customCssWarn: "这些设置必须有相关的基础知识,不当的配置可能导致客户端无法正常使用!" +customCssWarn: "这些设置必须有相关的基础知识,不当的配置可能导致客户端无法正常使用。" global: "全局" squareAvatars: "显示方形头像图标" sent: "发送" @@ -1057,7 +1057,7 @@ internalServerErrorDescription: "内部服务器发生了预期外的错误" copyErrorInfo: "复制错误信息" joinThisServer: "在本服务器上注册" exploreOtherServers: "探索其他服务器" -letsLookAtTimeline: "时间线" +letsLookAtTimeline: "看看时间线" disableFederationConfirm: "确定要禁用联合?" disableFederationConfirmWarn: "禁用联合不会将帖子设为私有。在大多数情况下,不需要禁用联合。" disableFederationOk: "联合禁用" @@ -1076,7 +1076,7 @@ sensitiveWords: "敏感词" sensitiveWordsDescription: "包含这些词的帖子将只在首页可见。可用换行来设定多个词。" sensitiveWordsDescription2: "AND 条件用空格分隔,正则表达式用斜线包裹。" prohibitedWords: "禁用词" -prohibitedWordsDescription: "发布包含设定词汇的帖子时将出错。可用换行设定多个关键字" +prohibitedWordsDescription: "发布包含设定词汇的帖子时将出错。可用换行设定多个关键字。" prohibitedWordsDescription2: "AND 条件用空格分隔,正则表达式用斜线包裹。" hiddenTags: "隐藏标签" hiddenTagsDescription: "设定的标签将不会在时间线上显示。可使用换行来设置多个标签。" @@ -1119,7 +1119,7 @@ vertical: "纵向" horizontal: "横向" position: "位置" serverRules: "服务器规则" -pleaseConfirmBelowBeforeSignup: "在这个服务器上注册账号前,请确认以下信息。" +pleaseConfirmBelowBeforeSignup: "如果要在此服务器上注册,需要确认并同意以下内容。" pleaseAgreeAllToContinue: "必须全部勾选「同意」才能够继续。" continue: "继续" preservedUsernames: "保留的用户名" @@ -1159,10 +1159,10 @@ turnOffToImprovePerformance: "关闭该选项可以提高性能。" createInviteCode: "生成邀请码" createWithOptions: "使用选项来创建" createCount: "发行数" -inviteCodeCreated: "已创建邀请码" -inviteLimitExceeded: "可供发行的邀请码已达上限。" -createLimitRemaining: "可供发行的邀请码:剩余{limit}个" -inviteLimitResetCycle: "可以在{time}内发行最多{limit}个邀请码。" +inviteCodeCreated: "已生成邀请码" +inviteLimitExceeded: "可供生成的邀请码已达上限。" +createLimitRemaining: "可供生成的邀请码:剩余 {limit} 个" +inviteLimitResetCycle: "可以在 {time} 内生成最多 {limit} 个邀请码。" expirationDate: "有效日期" noExpirationDate: "不设置有效日期" inviteCodeUsedAt: "邀请码被使用的日期和时间" @@ -1299,6 +1299,7 @@ yourNameContainsProhibitedWordsDescription: "用户名内含有违禁词。若 thisContentsAreMarkedAsSigninRequiredByAuthor: "根据发帖者的设定,需要登录才能显示" lockdown: "锁定" pleaseSelectAccount: "请选择帐户" +availableRoles: "可用角色" _accountSettings: requireSigninToViewContents: "需要登录才能显示内容" requireSigninToViewContentsDescription1: "您发布的所有帖子将变成需要登入后才会显示。有望防止爬虫收集各种信息。" @@ -1426,8 +1427,8 @@ _initialTutorial: description: "对于服务器方针所要求要求的,又或者不适合直接展示的附件,请添加「敏感」标记。\n" tryThisFile: "试试看,将附加到此窗口的图像标注为敏感!" _exampleNote: - note: "拆纳豆包装时出错了…" - method: "要标注附件为敏感内容,请单击该文件以打开菜单,然后单击“标记为敏感内容”。" + note: "拆纳豆包装时失手了…" + method: "要标注附件为敏感内容,请单击该文件以打开菜单,然后单击「标记为敏感内容」。" sensitiveSucceeded: "附加文件时,请遵循服务器的条款来设置正确敏感设定。\n" doItToContinue: "将图像标记为敏感后才能够继续" _done: diff --git a/locales/zh-TW.yml b/locales/zh-TW.yml index 16afeed0f8..b7c9def26f 100644 --- a/locales/zh-TW.yml +++ b/locales/zh-TW.yml @@ -8,8 +8,8 @@ search: "搜尋" notifications: "通知" username: "使用者名稱" password: "密碼" -initialPasswordForSetup: "初始設定用的密碼" -initialPasswordIsIncorrect: "初始設定用的密碼錯誤。" +initialPasswordForSetup: "啟動初始設定的密碼" +initialPasswordIsIncorrect: "啟動初始設定的密碼錯誤。" initialPasswordForSetupDescription: "如果您自己安裝了 Misskey,請使用您在設定檔中輸入的密碼。\n如果您使用 Misskey 的託管服務之類的服務,請使用提供的密碼。\n如果您尚未設定密碼,請將其留空並繼續。" forgotPassword: "忘記密碼" fetchingAsApObject: "從聯邦宇宙取得中..." @@ -1299,6 +1299,7 @@ yourNameContainsProhibitedWordsDescription: "名稱中包含禁止使用的字 thisContentsAreMarkedAsSigninRequiredByAuthor: "作者將其設定為需要登入才能顯示。" lockdown: "鎖定" pleaseSelectAccount: "請選擇帳戶" +availableRoles: "可用角色" _accountSettings: requireSigninToViewContents: "須登入以顯示內容" requireSigninToViewContentsDescription1: "必須登入才會顯示您建立的貼文等內容。可望有效防止資訊被爬蟲蒐集。" diff --git a/package.json b/package.json index 6a44eb04f3..63043d62e0 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "misskey", - "version": "2024.11.0-alpha.0", + "version": "2024.11.0-alpha.1", "codename": "nasubi", "repository": { "type": "git", @@ -56,22 +56,22 @@ "fast-glob": "3.3.2", "ignore-walk": "6.0.5", "js-yaml": "4.1.0", - "postcss": "8.4.47", + "postcss": "8.4.49", "tar": "6.2.1", - "terser": "5.33.0", - "typescript": "5.6.2", - "esbuild": "0.23.1", + "terser": "5.36.0", + "typescript": "5.6.3", + "esbuild": "0.24.0", "glob": "11.0.0" }, "devDependencies": { "@misskey-dev/eslint-plugin": "2.0.3", - "@types/node": "20.14.12", + "@types/node": "22.9.0", "@typescript-eslint/eslint-plugin": "7.17.0", "@typescript-eslint/parser": "7.17.0", "cross-env": "7.0.3", - "cypress": "13.14.2", - "eslint": "9.8.0", - "globals": "15.9.0", + "cypress": "13.15.2", + "eslint": "9.14.0", + "globals": "15.12.0", "ncp": "2.0.0", "start-server-and-test": "2.0.8" }, diff --git a/packages/backend/package.json b/packages/backend/package.json index 0dd738a1e6..f56a737eea 100644 --- a/packages/backend/package.json +++ b/packages/backend/package.json @@ -69,32 +69,32 @@ "dependencies": { "@aws-sdk/client-s3": "3.620.0", "@aws-sdk/lib-storage": "3.620.0", - "@bull-board/api": "6.0.0", - "@bull-board/fastify": "6.0.0", - "@bull-board/ui": "6.0.0", + "@bull-board/api": "6.5.0", + "@bull-board/fastify": "6.5.0", + "@bull-board/ui": "6.5.0", "@discordapp/twemoji": "15.1.0", "@fastify/accepts": "5.0.1", - "@fastify/cookie": "10.0.1", + "@fastify/cookie": "11.0.1", "@fastify/cors": "10.0.1", "@fastify/express": "4.0.1", - "@fastify/http-proxy": "10.0.0", + "@fastify/http-proxy": "10.0.1", "@fastify/multipart": "9.0.1", - "@fastify/static": "8.0.1", + "@fastify/static": "8.0.2", "@fastify/view": "10.0.1", "@misskey-dev/sharp-read-bmp": "1.2.0", "@misskey-dev/summaly": "5.1.0", "@napi-rs/canvas": "0.1.56", - "@nestjs/common": "10.4.4", - "@nestjs/core": "10.4.4", - "@nestjs/testing": "10.4.4", + "@nestjs/common": "10.4.7", + "@nestjs/core": "10.4.7", + "@nestjs/testing": "10.4.7", "@peertube/http-signature": "1.7.0", - "@sentry/node": "8.20.0", - "@sentry/profiling-node": "8.20.0", + "@sentry/node": "8.38.0", + "@sentry/profiling-node": "8.38.0", "@simplewebauthn/server": "10.0.1", "@sinonjs/fake-timers": "11.2.2", "@smithy/node-http-handler": "2.5.0", "@swc/cli": "0.3.12", - "@swc/core": "1.6.6", + "@swc/core": "1.9.2", "@twemoji/parser": "15.1.1", "accepts": "1.3.8", "ajv": "8.17.1", @@ -103,7 +103,7 @@ "bcryptjs": "2.4.3", "blurhash": "2.0.5", "body-parser": "1.20.3", - "bullmq": "5.15.0", + "bullmq": "5.26.1", "cacheable-lookup": "7.0.0", "cbor": "9.0.2", "chalk": "5.3.0", @@ -117,11 +117,11 @@ "fastify": "5.0.0", "fastify-raw-body": "5.0.0", "feed": "4.2.2", - "file-type": "19.5.0", + "file-type": "19.6.0", "fluent-ffmpeg": "2.1.3", - "form-data": "4.0.0", - "got": "14.4.2", - "happy-dom": "15.7.4", + "form-data": "4.0.1", + "got": "14.4.4", + "happy-dom": "15.11.4", "hpagent": "1.2.0", "htmlescape": "1.1.1", "http-link-header": "1.1.3", @@ -134,7 +134,7 @@ "json5": "2.2.3", "jsonld": "8.3.2", "jsrsasign": "11.1.0", - "meilisearch": "0.42.0", + "meilisearch": "0.45.0", "juice": "11.0.0", "mfm-js": "0.24.0", "microformats-parser": "2.0.2", @@ -142,18 +142,18 @@ "misskey-js": "workspace:*", "misskey-reversi": "workspace:*", "ms": "3.0.0-canary.1", - "nanoid": "5.0.7", + "nanoid": "5.0.8", "nested-property": "4.0.0", "node-fetch": "3.3.2", - "nodemailer": "6.9.15", + "nodemailer": "6.9.16", "nsfwjs": "2.4.2", "oauth": "0.10.0", "oauth2orize": "1.12.0", "oauth2orize-pkce": "0.1.2", "os-utils": "0.0.14", "otpauth": "9.3.4", - "parse5": "7.1.2", - "pg": "8.13.0", + "parse5": "7.2.1", + "pg": "8.13.1", "pkce-challenge": "4.1.0", "probe-image-size": "7.2.3", "promise-limit": "2.7.0", @@ -180,7 +180,7 @@ "tsc-alias": "1.8.10", "tsconfig-paths": "4.2.0", "typeorm": "0.3.20", - "typescript": "5.6.2", + "typescript": "5.6.3", "ulid": "2.3.0", "vary": "1.1.2", "web-push": "3.6.7", @@ -189,28 +189,28 @@ }, "devDependencies": { "@jest/globals": "29.7.0", - "@nestjs/platform-express": "10.4.4", + "@nestjs/platform-express": "10.4.7", "@simplewebauthn/types": "10.0.0", - "@swc/jest": "0.2.36", + "@swc/jest": "0.2.37", "@types/accepts": "1.3.7", - "@types/archiver": "6.0.2", + "@types/archiver": "6.0.3", "@types/bcryptjs": "2.4.6", "@types/body-parser": "1.19.5", "@types/color-convert": "2.0.4", "@types/content-disposition": "0.5.8", - "@types/fluent-ffmpeg": "2.1.26", + "@types/fluent-ffmpeg": "2.1.27", "@types/htmlescape": "1.1.3", "@types/http-link-header": "1.0.7", - "@types/jest": "29.5.13", + "@types/jest": "29.5.14", "@types/js-yaml": "4.0.9", "@types/jsdom": "21.1.7", "@types/jsonld": "1.5.15", "@types/jsrsasign": "10.5.14", "@types/mime-types": "2.1.4", "@types/ms": "0.7.34", - "@types/node": "20.14.12", + "@types/node": "22.9.0", "@types/nodemailer": "6.4.16", - "@types/oauth": "0.9.5", + "@types/oauth": "0.9.6", "@types/oauth2orize": "1.11.5", "@types/oauth2orize-pkce": "0.1.2", "@types/pg": "8.11.10", @@ -227,14 +227,14 @@ "@types/tinycolor2": "1.4.6", "@types/tmp": "0.2.6", "@types/vary": "1.1.3", - "@types/web-push": "3.6.3", - "@types/ws": "8.5.12", + "@types/web-push": "3.6.4", + "@types/ws": "8.5.13", "@typescript-eslint/eslint-plugin": "7.17.0", "@typescript-eslint/parser": "7.17.0", "aws-sdk-client-mock": "4.0.1", "cross-env": "7.0.3", "eslint-plugin-import": "2.30.0", - "execa": "9.4.0", + "execa": "8.0.1", "fkill": "9.0.0", "jest": "29.7.0", "jest-mock": "29.7.0", diff --git a/packages/backend/src/core/QueueService.ts b/packages/backend/src/core/QueueService.ts index 37028026cc..50f08da241 100644 --- a/packages/backend/src/core/QueueService.ts +++ b/packages/backend/src/core/QueueService.ts @@ -7,7 +7,7 @@ import { randomUUID } from 'node:crypto'; import { Inject, Injectable } from '@nestjs/common'; import type { IActivity } from '@/core/activitypub/type.js'; import type { MiDriveFile } from '@/models/DriveFile.js'; -import type { MiWebhook, webhookEventTypes } from '@/models/Webhook.js'; +import type { MiWebhook, WebhookEventTypes, webhookEventTypes } from '@/models/Webhook.js'; import type { MiSystemWebhook, SystemWebhookEventType } from '@/models/SystemWebhook.js'; import type { Config } from '@/config.js'; import { DI } from '@/di-symbols.js'; @@ -35,6 +35,7 @@ import type { } from './QueueModule.js'; import type httpSignature from '@peertube/http-signature'; import type * as Bull from 'bullmq'; +import { type UserWebhookPayload } from './UserWebhookService.js'; @Injectable() export class QueueService { @@ -468,10 +469,10 @@ export class QueueService { * @see UserWebhookDeliverProcessorService */ @bindThis - public userWebhookDeliver( + public userWebhookDeliver( webhook: MiWebhook, - type: typeof webhookEventTypes[number], - content: unknown, + type: T, + content: UserWebhookPayload, opts?: { attempts?: number }, ) { const data: UserWebhookDeliverJobData = { diff --git a/packages/backend/src/core/UserWebhookService.ts b/packages/backend/src/core/UserWebhookService.ts index 8a40a53688..7117a3d7fa 100644 --- a/packages/backend/src/core/UserWebhookService.ts +++ b/packages/backend/src/core/UserWebhookService.ts @@ -6,11 +6,23 @@ import { Inject, Injectable } from '@nestjs/common'; import * as Redis from 'ioredis'; import { type WebhooksRepository } from '@/models/_.js'; -import { MiWebhook } from '@/models/Webhook.js'; +import { MiWebhook, WebhookEventTypes } from '@/models/Webhook.js'; import { DI } from '@/di-symbols.js'; import { bindThis } from '@/decorators.js'; import { GlobalEvents } from '@/core/GlobalEventService.js'; import type { OnApplicationShutdown } from '@nestjs/common'; +import type { Packed } from '@/misc/json-schema.js'; + +export type UserWebhookPayload = + T extends 'note' | 'reply' | 'renote' |'mention' ? { + note: Packed<'Note'>, + } : + T extends 'follow' | 'unfollow' ? { + user: Packed<'UserDetailedNotMe'>, + } : + T extends 'followed' ? { + user: Packed<'UserLite'>, + } : never; @Injectable() export class UserWebhookService implements OnApplicationShutdown { diff --git a/packages/backend/src/core/WebhookTestService.ts b/packages/backend/src/core/WebhookTestService.ts index c826a28963..b1ea7974fb 100644 --- a/packages/backend/src/core/WebhookTestService.ts +++ b/packages/backend/src/core/WebhookTestService.ts @@ -10,7 +10,7 @@ import { MiSystemWebhook, type SystemWebhookEventType } from '@/models/SystemWeb import { SystemWebhookService } from '@/core/SystemWebhookService.js'; import { Packed } from '@/misc/json-schema.js'; import { type WebhookEventTypes } from '@/models/Webhook.js'; -import { UserWebhookService } from '@/core/UserWebhookService.js'; +import { type UserWebhookPayload, UserWebhookService } from '@/core/UserWebhookService.js'; import { QueueService } from '@/core/QueueService.js'; import { ModeratorInactivityRemainingTime } from '@/queue/processors/CheckModeratorsActivityProcessorService.js'; @@ -306,10 +306,10 @@ export class WebhookTestService { * - 送信対象イベント(on)に関する設定 */ @bindThis - public async testUserWebhook( + public async testUserWebhook( params: { webhookId: MiWebhook['id'], - type: WebhookEventTypes, + type: T, override?: Partial>, }, sender: MiUser | null, @@ -321,7 +321,7 @@ export class WebhookTestService { } const webhook = webhooks[0]; - const send = (contents: unknown) => { + const send = (type: U, contents: UserWebhookPayload) => { const merged = { ...webhook, ...params.override, @@ -329,7 +329,7 @@ export class WebhookTestService { // テスト目的なのでUserWebhookServiceの機能を経由せず直接キューに追加する(チェック処理などをスキップする意図). // また、Jobの試行回数も1回だけ. - this.queueService.userWebhookDeliver(merged, params.type, contents, { attempts: 1 }); + this.queueService.userWebhookDeliver(merged, type, contents, { attempts: 1 }); }; const dummyNote1 = generateDummyNote({ @@ -361,33 +361,40 @@ export class WebhookTestService { switch (params.type) { case 'note': { - send(toPackedNote(dummyNote1)); + send('note', { note: toPackedNote(dummyNote1) }); break; } case 'reply': { - send(toPackedNote(dummyReply1)); + send('reply', { note: toPackedNote(dummyReply1) }); break; } case 'renote': { - send(toPackedNote(dummyRenote1)); + send('renote', { note: toPackedNote(dummyRenote1) }); break; } case 'mention': { - send(toPackedNote(dummyMention1)); + send('mention', { note: toPackedNote(dummyMention1) }); break; } case 'follow': { - send(toPackedUserDetailedNotMe(dummyUser1)); + send('follow', { user: toPackedUserDetailedNotMe(dummyUser1) }); break; } case 'followed': { - send(toPackedUserLite(dummyUser2)); + send('followed', { user: toPackedUserLite(dummyUser2) }); break; } case 'unfollow': { - send(toPackedUserDetailedNotMe(dummyUser3)); + send('unfollow', { user: toPackedUserDetailedNotMe(dummyUser3) }); break; } + // まだ実装されていない (#9485) + case 'reaction': return; + default: { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + const _exhaustiveAssertion: never = params.type; + return; + } } } diff --git a/packages/backend/src/core/activitypub/models/ApPersonService.ts b/packages/backend/src/core/activitypub/models/ApPersonService.ts index c9de67b3a0..8c4e40c561 100644 --- a/packages/backend/src/core/activitypub/models/ApPersonService.ts +++ b/packages/backend/src/core/activitypub/models/ApPersonService.ts @@ -355,7 +355,7 @@ export class ApPersonService implements OnModuleInit { usernameLower: person.preferredUsername?.toLowerCase(), host, inbox: person.inbox, - sharedInbox: person.sharedInbox ?? person.endpoints?.sharedInbox, + sharedInbox: person.sharedInbox ?? person.endpoints?.sharedInbox ?? null, followersUri: person.followers ? getApId(person.followers) : undefined, featured: person.featured ? getApId(person.featured) : undefined, uri: person.id, @@ -521,7 +521,7 @@ export class ApPersonService implements OnModuleInit { const updates = { lastFetchedAt: new Date(), inbox: person.inbox, - sharedInbox: person.sharedInbox ?? person.endpoints?.sharedInbox, + sharedInbox: person.sharedInbox ?? person.endpoints?.sharedInbox ?? null, followersUri: person.followers ? getApId(person.followers) : undefined, featured: person.featured, emojis: emojiNames, @@ -593,7 +593,7 @@ export class ApPersonService implements OnModuleInit { // 該当ユーザーが既にフォロワーになっていた場合はFollowingもアップデートする await this.followingsRepository.update( { followerId: exist.id }, - { followerSharedInbox: person.sharedInbox ?? person.endpoints?.sharedInbox }, + { followerSharedInbox: person.sharedInbox ?? person.endpoints?.sharedInbox ?? null }, ); await this.updateFeatured(exist.id, resolver).catch(err => this.logger.error(err)); diff --git a/packages/backend/src/server/api/EndpointsModule.ts b/packages/backend/src/server/api/EndpointsModule.ts index 3557fa40a5..5bb194313d 100644 --- a/packages/backend/src/server/api/EndpointsModule.ts +++ b/packages/backend/src/server/api/EndpointsModule.ts @@ -187,6 +187,7 @@ import * as ep___following_invalidate from './endpoints/following/invalidate.js' import * as ep___following_requests_accept from './endpoints/following/requests/accept.js'; import * as ep___following_requests_cancel from './endpoints/following/requests/cancel.js'; import * as ep___following_requests_list from './endpoints/following/requests/list.js'; +import * as ep___following_requests_sent from './endpoints/following/requests/sent.js'; import * as ep___following_requests_reject from './endpoints/following/requests/reject.js'; import * as ep___gallery_featured from './endpoints/gallery/featured.js'; import * as ep___gallery_popular from './endpoints/gallery/popular.js'; @@ -574,6 +575,7 @@ const $following_invalidate: Provider = { provide: 'ep:following/invalidate', us const $following_requests_accept: Provider = { provide: 'ep:following/requests/accept', useClass: ep___following_requests_accept.default }; const $following_requests_cancel: Provider = { provide: 'ep:following/requests/cancel', useClass: ep___following_requests_cancel.default }; const $following_requests_list: Provider = { provide: 'ep:following/requests/list', useClass: ep___following_requests_list.default }; +const $following_requests_sent: Provider = { provide: 'ep:following/requests/sent', useClass: ep___following_requests_sent.default }; const $following_requests_reject: Provider = { provide: 'ep:following/requests/reject', useClass: ep___following_requests_reject.default }; const $gallery_featured: Provider = { provide: 'ep:gallery/featured', useClass: ep___gallery_featured.default }; const $gallery_popular: Provider = { provide: 'ep:gallery/popular', useClass: ep___gallery_popular.default }; @@ -965,6 +967,7 @@ const $reversi_verify: Provider = { provide: 'ep:reversi/verify', useClass: ep__ $following_requests_accept, $following_requests_cancel, $following_requests_list, + $following_requests_sent, $following_requests_reject, $gallery_featured, $gallery_popular, diff --git a/packages/backend/src/server/api/endpoints.ts b/packages/backend/src/server/api/endpoints.ts index 49b07d6ced..15809b2678 100644 --- a/packages/backend/src/server/api/endpoints.ts +++ b/packages/backend/src/server/api/endpoints.ts @@ -193,6 +193,7 @@ import * as ep___following_invalidate from './endpoints/following/invalidate.js' import * as ep___following_requests_accept from './endpoints/following/requests/accept.js'; import * as ep___following_requests_cancel from './endpoints/following/requests/cancel.js'; import * as ep___following_requests_list from './endpoints/following/requests/list.js'; +import * as ep___following_requests_sent from './endpoints/following/requests/sent.js'; import * as ep___following_requests_reject from './endpoints/following/requests/reject.js'; import * as ep___gallery_featured from './endpoints/gallery/featured.js'; import * as ep___gallery_popular from './endpoints/gallery/popular.js'; @@ -578,6 +579,7 @@ const eps = [ ['following/requests/accept', ep___following_requests_accept], ['following/requests/cancel', ep___following_requests_cancel], ['following/requests/list', ep___following_requests_list], + ['following/requests/sent', ep___following_requests_sent], ['following/requests/reject', ep___following_requests_reject], ['gallery/featured', ep___gallery_featured], ['gallery/popular', ep___gallery_popular], diff --git a/packages/backend/src/server/api/endpoints/following/requests/sent.ts b/packages/backend/src/server/api/endpoints/following/requests/sent.ts new file mode 100644 index 0000000000..6325f01bb8 --- /dev/null +++ b/packages/backend/src/server/api/endpoints/following/requests/sent.ts @@ -0,0 +1,77 @@ +/* + * SPDX-FileCopyrightText: syuilo and misskey-project + * SPDX-License-Identifier: AGPL-3.0-only + */ + +import { Inject, Injectable } from '@nestjs/common'; +import { Endpoint } from '@/server/api/endpoint-base.js'; +import { QueryService } from '@/core/QueryService.js'; +import type { FollowRequestsRepository } from '@/models/_.js'; +import { FollowRequestEntityService } from '@/core/entities/FollowRequestEntityService.js'; +import { DI } from '@/di-symbols.js'; + +export const meta = { + tags: ['following', 'account'], + + requireCredential: true, + + kind: 'read:following', + + res: { + type: 'array', + optional: false, nullable: false, + items: { + type: 'object', + optional: false, nullable: false, + properties: { + id: { + type: 'string', + optional: false, nullable: false, + format: 'id', + }, + follower: { + type: 'object', + optional: false, nullable: false, + ref: 'UserLite', + }, + followee: { + type: 'object', + optional: false, nullable: false, + ref: 'UserLite', + }, + }, + }, + }, +} as const; + +export const paramDef = { + type: 'object', + properties: { + sinceId: { type: 'string', format: 'misskey:id' }, + untilId: { type: 'string', format: 'misskey:id' }, + limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 }, + }, + required: [], +} as const; + +@Injectable() +export default class extends Endpoint { // eslint-disable-line import/no-default-export + constructor( + @Inject(DI.followRequestsRepository) + private followRequestsRepository: FollowRequestsRepository, + + private followRequestEntityService: FollowRequestEntityService, + private queryService: QueryService, + ) { + super(meta, paramDef, async (ps, me) => { + const query = this.queryService.makePaginationQuery(this.followRequestsRepository.createQueryBuilder('request'), ps.sinceId, ps.untilId) + .andWhere('request.followerId = :meId', { meId: me.id }); + + const requests = await query + .limit(ps.limit) + .getMany(); + + return await this.followRequestEntityService.packMany(requests, me); + }); + } +} diff --git a/packages/backend/test/unit/WebhookTestService.ts b/packages/backend/test/unit/WebhookTestService.ts index 5e63b86f8f..be84ae9b84 100644 --- a/packages/backend/test/unit/WebhookTestService.ts +++ b/packages/backend/test/unit/WebhookTestService.ts @@ -7,7 +7,7 @@ import { Test, TestingModule } from '@nestjs/testing'; import { beforeAll, describe, jest } from '@jest/globals'; import { WebhookTestService } from '@/core/WebhookTestService.js'; -import { UserWebhookService } from '@/core/UserWebhookService.js'; +import { UserWebhookPayload, UserWebhookService } from '@/core/UserWebhookService.js'; import { SystemWebhookService } from '@/core/SystemWebhookService.js'; import { GlobalModule } from '@/GlobalModule.js'; import { MiSystemWebhook, MiUser, MiWebhook, UserProfilesRepository, UsersRepository } from '@/models/_.js'; @@ -122,7 +122,7 @@ describe('WebhookTestService', () => { const calls = queueService.userWebhookDeliver.mock.calls[0]; expect((calls[0] as any).id).toBe('dummy-webhook'); expect(calls[1]).toBe('note'); - expect((calls[2] as any).id).toBe('dummy-note-1'); + expect((calls[2] as UserWebhookPayload<'note'>).note.id).toBe('dummy-note-1'); }); test('reply', async () => { @@ -131,7 +131,7 @@ describe('WebhookTestService', () => { const calls = queueService.userWebhookDeliver.mock.calls[0]; expect((calls[0] as any).id).toBe('dummy-webhook'); expect(calls[1]).toBe('reply'); - expect((calls[2] as any).id).toBe('dummy-reply-1'); + expect((calls[2] as UserWebhookPayload<'reply'>).note.id).toBe('dummy-reply-1'); }); test('renote', async () => { @@ -140,7 +140,7 @@ describe('WebhookTestService', () => { const calls = queueService.userWebhookDeliver.mock.calls[0]; expect((calls[0] as any).id).toBe('dummy-webhook'); expect(calls[1]).toBe('renote'); - expect((calls[2] as any).id).toBe('dummy-renote-1'); + expect((calls[2] as UserWebhookPayload<'renote'>).note.id).toBe('dummy-renote-1'); }); test('mention', async () => { @@ -149,7 +149,7 @@ describe('WebhookTestService', () => { const calls = queueService.userWebhookDeliver.mock.calls[0]; expect((calls[0] as any).id).toBe('dummy-webhook'); expect(calls[1]).toBe('mention'); - expect((calls[2] as any).id).toBe('dummy-mention-1'); + expect((calls[2] as UserWebhookPayload<'mention'>).note.id).toBe('dummy-mention-1'); }); test('follow', async () => { @@ -158,7 +158,7 @@ describe('WebhookTestService', () => { const calls = queueService.userWebhookDeliver.mock.calls[0]; expect((calls[0] as any).id).toBe('dummy-webhook'); expect(calls[1]).toBe('follow'); - expect((calls[2] as any).id).toBe('dummy-user-1'); + expect((calls[2] as UserWebhookPayload<'follow'>).user.id).toBe('dummy-user-1'); }); test('followed', async () => { @@ -167,7 +167,7 @@ describe('WebhookTestService', () => { const calls = queueService.userWebhookDeliver.mock.calls[0]; expect((calls[0] as any).id).toBe('dummy-webhook'); expect(calls[1]).toBe('followed'); - expect((calls[2] as any).id).toBe('dummy-user-2'); + expect((calls[2] as UserWebhookPayload<'followed'>).user.id).toBe('dummy-user-2'); }); test('unfollow', async () => { @@ -176,7 +176,7 @@ describe('WebhookTestService', () => { const calls = queueService.userWebhookDeliver.mock.calls[0]; expect((calls[0] as any).id).toBe('dummy-webhook'); expect(calls[1]).toBe('unfollow'); - expect((calls[2] as any).id).toBe('dummy-user-3'); + expect((calls[2] as UserWebhookPayload<'unfollow'>).user.id).toBe('dummy-user-3'); }); describe('NoSuchWebhookError', () => { diff --git a/packages/frontend-embed/package.json b/packages/frontend-embed/package.json index cb62191c3b..59b744e43a 100644 --- a/packages/frontend-embed/package.json +++ b/packages/frontend-embed/package.json @@ -14,11 +14,11 @@ "@discordapp/twemoji": "15.1.0", "@rollup/plugin-json": "6.1.0", "@rollup/plugin-replace": "5.0.7", - "@rollup/pluginutils": "5.1.2", + "@rollup/pluginutils": "5.1.3", "@tabler/icons-webfont": "3.3.0", "@twemoji/parser": "15.1.1", - "@vitejs/plugin-vue": "5.1.4", - "@vue/compiler-sfc": "3.5.11", + "@vitejs/plugin-vue": "5.2.0", + "@vue/compiler-sfc": "3.5.12", "astring": "1.9.0", "buraha": "0.0.1", "estree-walker": "3.0.3", @@ -26,47 +26,47 @@ "misskey-js": "workspace:*", "frontend-shared": "workspace:*", "punycode": "2.3.1", - "rollup": "4.22.5", + "rollup": "4.26.0", "sass": "1.79.4", - "shiki": "1.21.0", + "shiki": "1.22.2", "tinycolor2": "1.6.0", "tsc-alias": "1.8.10", "tsconfig-paths": "4.2.0", - "typescript": "5.6.2", + "typescript": "5.6.3", "uuid": "10.0.0", "json5": "2.2.3", - "vite": "5.4.8", - "vue": "3.5.11" + "vite": "5.4.11", + "vue": "3.5.12" }, "devDependencies": { "@misskey-dev/summaly": "5.1.0", "@testing-library/vue": "8.1.0", "@types/estree": "1.0.6", "@types/micromatch": "4.0.9", - "@types/node": "20.14.12", + "@types/node": "22.9.0", "@types/punycode": "2.1.4", "@types/tinycolor2": "1.4.6", "@types/uuid": "10.0.0", - "@types/ws": "8.5.12", + "@types/ws": "8.5.13", "@typescript-eslint/eslint-plugin": "7.17.0", "@typescript-eslint/parser": "7.17.0", "@vitest/coverage-v8": "1.6.0", - "@vue/runtime-core": "3.5.11", - "acorn": "8.12.1", + "@vue/runtime-core": "3.5.12", + "acorn": "8.14.0", "cross-env": "7.0.3", "eslint-plugin-import": "2.31.0", - "eslint-plugin-vue": "9.28.0", + "eslint-plugin-vue": "9.31.0", "fast-glob": "3.3.2", "happy-dom": "10.0.3", "intersection-observer": "0.12.2", "micromatch": "4.0.8", - "msw": "2.3.4", + "msw": "2.6.4", "nodemon": "3.1.7", "prettier": "3.3.3", "start-server-and-test": "2.0.8", "vite-plugin-turbosnap": "1.0.3", - "vue-component-type-helpers": "2.1.6", + "vue-component-type-helpers": "2.1.10", "vue-eslint-parser": "9.4.3", - "vue-tsc": "2.1.6" + "vue-tsc": "2.1.10" } } diff --git a/packages/frontend-shared/package.json b/packages/frontend-shared/package.json index 9981d10dd2..f8770f33f2 100644 --- a/packages/frontend-shared/package.json +++ b/packages/frontend-shared/package.json @@ -21,12 +21,12 @@ "lint": "pnpm typecheck && pnpm eslint" }, "devDependencies": { - "@types/node": "20.14.12", + "@types/node": "22.9.0", "@typescript-eslint/eslint-plugin": "7.17.0", "@typescript-eslint/parser": "7.17.0", - "esbuild": "0.23.0", - "eslint-plugin-vue": "9.27.0", - "typescript": "5.5.4", + "esbuild": "0.24.0", + "eslint-plugin-vue": "9.31.0", + "typescript": "5.6.3", "vue-eslint-parser": "9.4.3" }, "files": [ @@ -34,6 +34,6 @@ ], "dependencies": { "misskey-js": "workspace:*", - "vue": "3.4.37" + "vue": "3.5.12" } } diff --git a/packages/frontend/package.json b/packages/frontend/package.json index 3226a554a9..4f132ab500 100644 --- a/packages/frontend/package.json +++ b/packages/frontend/package.json @@ -23,23 +23,23 @@ "@misskey-dev/browser-image-resizer": "2024.1.0", "@rollup/plugin-json": "6.1.0", "@rollup/plugin-replace": "5.0.7", - "@rollup/pluginutils": "5.1.2", + "@rollup/pluginutils": "5.1.3", "@syuilo/aiscript": "0.19.0", "@tabler/icons-webfont": "3.3.0", "@twemoji/parser": "15.1.1", - "@vitejs/plugin-vue": "5.1.4", - "@vue/compiler-sfc": "3.5.11", + "@vitejs/plugin-vue": "5.2.0", + "@vue/compiler-sfc": "3.5.12", "aiscript-vscode": "github:aiscript-dev/aiscript-vscode#v0.1.11", "astring": "1.9.0", "broadcast-channel": "7.0.0", "buraha": "0.0.1", "canvas-confetti": "1.9.3", - "chart.js": "4.4.4", + "chart.js": "4.4.6", "chartjs-adapter-date-fns": "3.0.0", "chartjs-chart-matrix": "2.0.1", "chartjs-plugin-gradient": "0.6.1", "chartjs-plugin-zoom": "2.0.1", - "chromatic": "11.11.0", + "chromatic": "11.18.1", "compare-versions": "6.1.1", "cropperjs": "2.0.0-rc.2", "date-fns": "2.30.0", @@ -57,10 +57,10 @@ "misskey-reversi": "workspace:*", "photoswipe": "5.4.4", "punycode": "2.3.1", - "rollup": "4.22.5", + "rollup": "4.26.0", "sanitize-html": "2.13.1", "sass": "1.79.3", - "shiki": "1.21.0", + "shiki": "1.22.2", "strict-event-emitter-types": "2.0.0", "textarea-caret": "3.1.0", "three": "0.169.0", @@ -68,74 +68,74 @@ "tinycolor2": "1.6.0", "tsc-alias": "1.8.10", "tsconfig-paths": "4.2.0", - "typescript": "5.6.2", + "typescript": "5.6.3", "uuid": "10.0.0", "v-code-diff": "1.13.1", - "vite": "5.4.8", - "vue": "3.5.11", + "vite": "5.4.11", + "vue": "3.5.12", "vuedraggable": "next" }, "devDependencies": { "@misskey-dev/summaly": "5.1.0", - "@storybook/addon-actions": "8.3.4", - "@storybook/addon-essentials": "8.3.4", - "@storybook/addon-interactions": "8.3.4", - "@storybook/addon-links": "8.3.4", - "@storybook/addon-mdx-gfm": "8.3.4", - "@storybook/addon-storysource": "8.3.4", - "@storybook/blocks": "8.3.4", - "@storybook/components": "8.3.4", - "@storybook/core-events": "8.3.4", - "@storybook/manager-api": "8.3.4", - "@storybook/preview-api": "8.3.4", - "@storybook/react": "8.3.4", - "@storybook/react-vite": "8.3.4", - "@storybook/test": "8.3.4", - "@storybook/theming": "8.3.4", - "@storybook/types": "8.3.4", - "@storybook/vue3": "8.3.4", - "@storybook/vue3-vite": "8.3.4", + "@storybook/addon-actions": "8.4.4", + "@storybook/addon-essentials": "8.4.4", + "@storybook/addon-interactions": "8.4.4", + "@storybook/addon-links": "8.4.4", + "@storybook/addon-mdx-gfm": "8.4.4", + "@storybook/addon-storysource": "8.4.4", + "@storybook/blocks": "8.4.4", + "@storybook/components": "8.4.4", + "@storybook/core-events": "8.4.4", + "@storybook/manager-api": "8.4.4", + "@storybook/preview-api": "8.4.4", + "@storybook/react": "8.4.4", + "@storybook/react-vite": "8.4.4", + "@storybook/test": "8.4.4", + "@storybook/theming": "8.4.4", + "@storybook/types": "8.4.4", + "@storybook/vue3": "8.4.4", + "@storybook/vue3-vite": "8.4.4", "@testing-library/vue": "8.1.0", "@types/canvas-confetti": "^1.6.4", "@types/estree": "1.0.6", "@types/matter-js": "0.19.7", "@types/micromatch": "4.0.9", - "@types/node": "20.14.12", + "@types/node": "22.9.0", "@types/punycode": "2.1.4", "@types/sanitize-html": "2.13.0", "@types/seedrandom": "3.0.8", "@types/throttle-debounce": "5.0.2", "@types/tinycolor2": "1.4.6", "@types/uuid": "10.0.0", - "@types/ws": "8.5.12", + "@types/ws": "8.5.13", "@typescript-eslint/eslint-plugin": "7.17.0", "@typescript-eslint/parser": "7.17.0", "@vitest/coverage-v8": "1.6.0", - "@vue/runtime-core": "3.5.11", - "acorn": "8.12.1", + "@vue/runtime-core": "3.5.12", + "acorn": "8.14.0", "cross-env": "7.0.3", - "cypress": "13.15.0", + "cypress": "13.15.2", "eslint-plugin-import": "2.31.0", - "eslint-plugin-vue": "9.28.0", + "eslint-plugin-vue": "9.31.0", "fast-glob": "3.3.2", "happy-dom": "10.0.3", "intersection-observer": "0.12.2", "micromatch": "4.0.8", - "msw": "2.4.9", - "msw-storybook-addon": "2.0.3", + "msw": "2.6.4", + "msw-storybook-addon": "2.0.4", "nodemon": "3.1.7", "prettier": "3.3.3", "react": "18.3.1", "react-dom": "18.3.1", "seedrandom": "3.0.5", "start-server-and-test": "2.0.8", - "storybook": "8.3.4", + "storybook": "8.4.4", "storybook-addon-misskey-theme": "github:misskey-dev/storybook-addon-misskey-theme", "vite-plugin-turbosnap": "1.0.3", "vitest": "1.6.0", "vitest-fetch-mock": "0.2.2", - "vue-component-type-helpers": "2.1.6", + "vue-component-type-helpers": "2.1.10", "vue-eslint-parser": "9.4.3", - "vue-tsc": "2.1.6" + "vue-tsc": "2.1.10" } } diff --git a/packages/frontend/src/components/MkFollowButton.vue b/packages/frontend/src/components/MkFollowButton.vue index 84a6986b1f..703805107b 100644 --- a/packages/frontend/src/components/MkFollowButton.vue +++ b/packages/frontend/src/components/MkFollowButton.vue @@ -91,7 +91,10 @@ async function onClick() { text: i18n.tsx.unfollowConfirm({ name: props.user.name || props.user.username }), }); - if (canceled) return; + if (canceled) { + wait.value = false; + return; + } await misskeyApi('following/delete', { userId: props.user.id, @@ -133,7 +136,10 @@ async function onClick() { }); hasPendingFollowRequestFromYou.value = true; - if ($i == null) return; + if ($i == null) { + wait.value = false; + return; + } claimAchievement('following1'); diff --git a/packages/frontend/src/components/MkNoteDetailed.vue b/packages/frontend/src/components/MkNoteDetailed.vue index e0473dce5e..4a350388c2 100644 --- a/packages/frontend/src/components/MkNoteDetailed.vue +++ b/packages/frontend/src/components/MkNoteDetailed.vue @@ -62,7 +62,14 @@ SPDX-License-Identifier: AGPL-3.0-only -
+
+
+ +
+
+ +
+
@@ -679,12 +686,30 @@ function loadConversation() { float: right; } +.noteHeaderUsernameAndBadgeRoles { + display: flex; +} + .noteHeaderUsername { margin-bottom: 2px; + margin-right: 0.5em; line-height: 1.3; word-wrap: anywhere; } +.noteHeaderBadgeRoles { + margin: 0 .5em 0 0; +} + +.noteHeaderBadgeRole { + height: 1.3em; + vertical-align: -20%; + + & + .noteHeaderBadgeRole { + margin-left: 0.2em; + } +} + .noteContent { container-type: inline-size; overflow-wrap: break-word; diff --git a/packages/frontend/src/navbar.ts b/packages/frontend/src/navbar.ts index ac730f8021..096d404a57 100644 --- a/packages/frontend/src/navbar.ts +++ b/packages/frontend/src/navbar.ts @@ -40,7 +40,6 @@ export const navbarItemDef = reactive({ followRequests: { title: i18n.ts.followRequests, icon: 'ti ti-user-plus', - show: computed(() => $i != null && $i.isLocked), indicated: computed(() => $i != null && $i.hasPendingReceivedFollowRequest), to: '/my/follow-requests', }, diff --git a/packages/frontend/src/pages/about-misskey.vue b/packages/frontend/src/pages/about-misskey.vue index fbbfb6ea61..f2becfd8f5 100644 --- a/packages/frontend/src/pages/about-misskey.vue +++ b/packages/frontend/src/pages/about-misskey.vue @@ -272,6 +272,9 @@ const patronsWithIcon = [{ }, { name: 'Yatoigawa', icon: 'https://assets.misskey-hub.net/patrons/505e3568885a4a488431a8f22b4553d0.jpg', +}, { + name: '秋瀬カヲル', + icon: 'https://assets.misskey-hub.net/patrons/0f22aeb866484f4fa51db6721e3f9847.jpg', }]; const patrons = [ @@ -380,6 +383,7 @@ const patrons = [ 'ケモナーのケシン', 'こまつぶり', 'まゆつな空高', + 'asata', ]; const thereIsTreasure = ref($i && !claimedAchievements.includes('foundTreasure')); diff --git a/packages/frontend/src/pages/admin-user.vue b/packages/frontend/src/pages/admin-user.vue index 948e7a3cce..30d7e38638 100644 --- a/packages/frontend/src/pages/admin-user.vue +++ b/packages/frontend/src/pages/admin-user.vue @@ -627,6 +627,7 @@ definePageMetadata(() => ({