Merge branch 'develop' into fix/word-mutes

This commit is contained in:
naskya 2023-05-04 05:36:29 +00:00
commit 137cef81b6
54 changed files with 1589 additions and 282 deletions

View File

@ -1,27 +1,44 @@
# 🚚 Migrating from Misskey to Calckey # 🚚 Migrating from Misskey to Calckey
The following procedure may not work depending on your environment and version of Misskey.
**Make sure you**
- **stopped all master and worker processes of Misskey.**
- **have backups of the database before performing any commands.**
## Misskey v13 and above ## Misskey v13 and above
Tested with Misskey v13.11.3.
If your Misskey v13 is older, we recommend updating your Misskey to v13.11.3.
```sh ```sh
wget -O mkv13.patch https://codeberg.org/calckey/calckey/raw/branch/develop/docs/mkv13.patch wget -O mkv13.patch https://codeberg.org/calckey/calckey/raw/branch/develop/docs/mkv13.patch
git apply mkv13.patch wget -O mkv13_restore.patch https://codeberg.org/calckey/calckey/raw/branch/develop/docs/mkv13_restore.patch
git apply mkv13.patch mkv13_restore.patch
cd packages/backend cd packages/backend
LINE_NUM="$(npx typeorm migration:show -d ormconfig.js | grep -n activeEmailValidation1657346559800 | cut -d ':' -f 1)" LINE_NUM="$(pnpm typeorm migration:show -d ormconfig.js | grep -n activeEmailValidation1657346559800 | cut -d ':' -f 1)"
NUM_MIGRATIONS="$(npx typeorm migration:show -d ormconfig.js | tail -n+"$LINE_NUM" | grep '\[X\]' | nl)" NUM_MIGRATIONS="$(pnpm 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 pnpm typeorm migration:revert -d ormconfig.js; done
npx typeorm migration:revert -d ormconfig.js
done cd ../../
git remote set-url origin https://codeberg.org/calckey/calckey.git git remote set-url origin https://codeberg.org/calckey/calckey.git
git fetch git fetch origin
git checkout main # or beta or develop git stash push
rm -rf fluent-emojis misskey-assets
git switch main # or beta or develop
git pull --ff git pull --ff
wget -O renote_muting.patch https://codeberg.org/calckey/calckey/raw/branch/develop/docs/renote_muting.patch
git apply renote_muting.patch
NODE_ENV=production pnpm run migrate pnpm install
# build using prefered method NODE_ENV=production pnpm run build
pnpm run migrate
git stash push
``` ```
Depending on the version you're migrating from, you may have to open Postgres with `psql -d your_database` and run the following commands: Depending on the version you're migrating from, you may have to open Postgres with `psql -d your_database` and run the following commands:
@ -44,6 +61,10 @@ ALTER TABLE "instance" ADD COLUMN "lastCommunicatedAt" date;
then quit with `\q`, and restart Calckey. then quit with `\q`, and restart Calckey.
Note: Ignore errors of `column "xxx" of relation "xxx" already exists`.
If no other errors happened, your Calckey is ready to launch!
## Misskey v12.119 and before ## Misskey v12.119 and before
```sh ```sh

127
docs/mkv13_restore.patch Normal file
View File

@ -0,0 +1,127 @@
diff --git a/packages/backend/migration/1680491187535-cleanup.js b/packages/backend/migration/1680491187535-cleanup.js
index 1e609ca06..0e6accf3e 100644
--- a/packages/backend/migration/1680491187535-cleanup.js
+++ b/packages/backend/migration/1680491187535-cleanup.js
@@ -1,10 +1,40 @@
export class cleanup1680491187535 {
- name = 'cleanup1680491187535'
+ name = "cleanup1680491187535";
- async up(queryRunner) {
- await queryRunner.query(`DROP TABLE "antenna_note" `);
- }
+ async up(queryRunner) {
+ await queryRunner.query(`DROP TABLE "antenna_note" `);
+ }
- async down(queryRunner) {
- }
+ async down(queryRunner) {
+ await queryRunner.query(
+ `CREATE TABLE antenna_note ( id character varying(32) NOT NULL, "noteId" character varying(32) NOT NULL, "antennaId" character varying(32) NOT NULL, read boolean DEFAULT false NOT NULL)`,
+ );
+ await queryRunner.query(
+ `COMMENT ON COLUMN antenna_note."noteId" IS 'The note ID.'`,
+ );
+ await queryRunner.query(
+ `COMMENT ON COLUMN antenna_note."antennaId" IS 'The antenna ID.'`,
+ );
+ await queryRunner.query(
+ `ALTER TABLE ONLY antenna_note ADD CONSTRAINT "PK_fb28d94d0989a3872df19fd6ef8" PRIMARY KEY (id)`,
+ );
+ await queryRunner.query(
+ `CREATE INDEX "IDX_0d775946662d2575dfd2068a5f" ON antenna_note USING btree ("antennaId")`,
+ );
+ await queryRunner.query(
+ `CREATE UNIQUE INDEX "IDX_335a0bf3f904406f9ef3dd51c2" ON antenna_note USING btree ("noteId", "antennaId")`,
+ );
+ await queryRunner.query(
+ `CREATE INDEX "IDX_9937ea48d7ae97ffb4f3f063a4" ON antenna_note USING btree (read)`,
+ );
+ await queryRunner.query(
+ `CREATE INDEX "IDX_bd0397be22147e17210940e125" ON antenna_note USING btree ("noteId")`,
+ );
+ await queryRunner.query(
+ `ALTER TABLE ONLY antenna_note ADD CONSTRAINT "FK_0d775946662d2575dfd2068a5f5" FOREIGN KEY ("antennaId") REFERENCES antenna(id) ON DELETE CASCADE`,
+ );
+ await queryRunner.query(
+ `ALTER TABLE ONLY antenna_note ADD CONSTRAINT "FK_bd0397be22147e17210940e125b" FOREIGN KEY ("noteId") REFERENCES note(id) ON DELETE CASCADE`,
+ );
+ }
}
diff --git a/packages/backend/migration/1680582195041-cleanup.js b/packages/backend/migration/1680582195041-cleanup.js
index c587e456a..a91d6ff3c 100644
--- a/packages/backend/migration/1680582195041-cleanup.js
+++ b/packages/backend/migration/1680582195041-cleanup.js
@@ -1,11 +1,64 @@
export class cleanup1680582195041 {
- name = 'cleanup1680582195041'
+ name = "cleanup1680582195041";
- async up(queryRunner) {
- await queryRunner.query(`DROP TABLE "notification" `);
- }
+ async up(queryRunner) {
+ await queryRunner.query(`DROP TABLE "notification"`);
+ }
- async down(queryRunner) {
-
- }
+ async down(queryRunner) {
+ await queryRunner.query(
+ `CREATE TABLE notification ( id character varying(32) NOT NULL, "createdAt" timestamp with time zone NOT NULL, "notifieeId" character varying(32) NOT NULL, "notifierId" character varying(32), "isRead" boolean DEFAULT false NOT NULL, "noteId" character varying(32), reaction character varying(128), choice integer, "followRequestId" character varying(32), type notification_type_enum NOT NULL, "customBody" character varying(2048), "customHeader" character varying(256), "customIcon" character varying(1024), "appAccessTokenId" character varying(32), achievement character varying(128))`,
+ );
+ await queryRunner.query(
+ `COMMENT ON COLUMN notification."createdAt" IS 'The created date of the Notification.'`,
+ );
+ await queryRunner.query(
+ `COMMENT ON COLUMN notification."notifieeId" IS 'The ID of recipient user of the Notification.'`,
+ );
+ await queryRunner.query(
+ `COMMENT ON COLUMN notification."notifierId" IS 'The ID of sender user of the Notification.'`,
+ );
+ await queryRunner.query(
+ `COMMENT ON COLUMN notification."isRead" IS 'Whether the Notification is read.'`,
+ );
+ await queryRunner.query(
+ `COMMENT ON COLUMN notification.type IS 'The type of the Notification.'`,
+ );
+ await queryRunner.query(
+ `ALTER TABLE ONLY notification ADD CONSTRAINT "PK_705b6c7cdf9b2c2ff7ac7872cb7" PRIMARY KEY (id)`,
+ );
+ await queryRunner.query(
+ `CREATE INDEX "IDX_080ab397c379af09b9d2169e5b" ON notification USING btree ("isRead")`,
+ );
+ await queryRunner.query(
+ `CREATE INDEX "IDX_33f33cc8ef29d805a97ff4628b" ON notification USING btree (type)`,
+ );
+ await queryRunner.query(
+ `CREATE INDEX "IDX_3b4e96eec8d36a8bbb9d02aa71" ON notification USING btree ("notifierId")`,
+ );
+ await queryRunner.query(
+ `CREATE INDEX "IDX_3c601b70a1066d2c8b517094cb" ON notification USING btree ("notifieeId")`,
+ );
+ await queryRunner.query(
+ `CREATE INDEX "IDX_b11a5e627c41d4dc3170f1d370" ON notification USING btree ("createdAt")`,
+ );
+ await queryRunner.query(
+ `CREATE INDEX "IDX_e22bf6bda77b6adc1fd9e75c8c" ON notification USING btree ("appAccessTokenId")`,
+ );
+ await queryRunner.query(
+ `ALTER TABLE ONLY notification ADD CONSTRAINT "FK_3b4e96eec8d36a8bbb9d02aa710" FOREIGN KEY ("notifierId") REFERENCES "user"(id) ON DELETE CASCADE`,
+ );
+ await queryRunner.query(
+ `ALTER TABLE ONLY notification ADD CONSTRAINT "FK_3c601b70a1066d2c8b517094cb9" FOREIGN KEY ("notifieeId") REFERENCES "user"(id) ON DELETE CASCADE`,
+ );
+ await queryRunner.query(
+ `ALTER TABLE ONLY notification ADD CONSTRAINT "FK_769cb6b73a1efe22ddf733ac453" FOREIGN KEY ("noteId") REFERENCES note(id) ON DELETE CASCADE`,
+ );
+ await queryRunner.query(
+ `ALTER TABLE ONLY notification ADD CONSTRAINT "FK_bd7fab507621e635b32cd31892c" FOREIGN KEY ("followRequestId") REFERENCES follow_request(id) ON DELETE CASCADE`,
+ );
+ await queryRunner.query(
+ `ALTER TABLE ONLY notification ADD CONSTRAINT "FK_e22bf6bda77b6adc1fd9e75c8c9" FOREIGN KEY ("appAccessTokenId") REFERENCES access_token(id) ON DELETE CASCADE`,
+ );
+ }
}

23
docs/renote_muting.patch Normal file
View File

@ -0,0 +1,23 @@
diff --git a/packages/backend/migration/1665091090561-add-renote-muting.js b/packages/backend/migration/1665091090561-add-renote-muting.js
index 2c76aaff5..f8541c818 100644
--- a/packages/backend/migration/1665091090561-add-renote-muting.js
+++ b/packages/backend/migration/1665091090561-add-renote-muting.js
@@ -4,18 +4,6 @@ export class addRenoteMuting1665091090561 {
}
async up(queryRunner) {
- await queryRunner.query(
- `CREATE TABLE "renote_muting" ("id" character varying(32) NOT NULL, "createdAt" TIMESTAMP WITH TIME ZONE NOT NULL, "muteeId" character varying(32) NOT NULL, "muterId" character varying(32) NOT NULL, CONSTRAINT "PK_renoteMuting_id" PRIMARY KEY ("id"))`,
- );
- await queryRunner.query(
- `CREATE INDEX "IDX_renote_muting_createdAt" ON "muting" ("createdAt") `,
- );
- await queryRunner.query(
- `CREATE INDEX "IDX_renote_muting_muteeId" ON "muting" ("muteeId") `,
- );
- await queryRunner.query(
- `CREATE INDEX "IDX_renote_muting_muterId" ON "muting" ("muterId") `,
- );
}
async down(queryRunner) {}

View File

@ -14,8 +14,8 @@ ok: "OK"
gotIt: "Ho he entès!" gotIt: "Ho he entès!"
cancel: "Cancel·lar" cancel: "Cancel·lar"
enterUsername: "Introdueix el teu nom d'usuari" enterUsername: "Introdueix el teu nom d'usuari"
renotedBy: "Resignat per {user}" renotedBy: "Impulsat per {user}"
noNotes: "Cap publicació" noNotes: "Cap nota"
noNotifications: "Cap notificació" noNotifications: "Cap notificació"
instance: "Instància" instance: "Instància"
settings: "Preferències" settings: "Preferències"
@ -46,7 +46,7 @@ copyLink: "Còpia l'enllaç"
delete: "Esborra" delete: "Esborra"
deleteAndEdit: "Esborrar i edita" deleteAndEdit: "Esborrar i edita"
deleteAndEditConfirm: "Estàs segur que vols esborrar aquesta nota i editar-la? Perdràs\ deleteAndEditConfirm: "Estàs segur que vols esborrar aquesta nota i editar-la? Perdràs\
\ totes les reaccions, resignats i respostes." \ totes les reaccions, impulsos i respostes."
addToList: "Afegir a la llista" addToList: "Afegir a la llista"
sendMessage: "Enviar un missatge" sendMessage: "Enviar un missatge"
copyUsername: "Còpia nom d'usuari" copyUsername: "Còpia nom d'usuari"
@ -73,8 +73,8 @@ exportRequested: "Has sol·licitat una exportació. Això pot trigar una estona.
importRequested: "Has sol·licitat una importació. Això pot trigar una estona." importRequested: "Has sol·licitat una importació. Això pot trigar una estona."
lists: "Llistes" lists: "Llistes"
noLists: "No tens cap llista" noLists: "No tens cap llista"
note: "Publicació" note: "Nota"
notes: "Publicacions" notes: "Notes"
following: "Seguint" following: "Seguint"
followers: "Seguidors" followers: "Seguidors"
followsYou: "Et segueix" followsYou: "Et segueix"
@ -94,18 +94,18 @@ enterListName: "Introdueix un nom per a la llista"
privacy: "Privadesa" privacy: "Privadesa"
makeFollowManuallyApprove: "Les sol·licituds de seguiment requereixen aprovació" makeFollowManuallyApprove: "Les sol·licituds de seguiment requereixen aprovació"
defaultNoteVisibility: "Visibilitat per defecte" defaultNoteVisibility: "Visibilitat per defecte"
follow: "Seguint" follow: "Seguir"
followRequest: "Enviar la sol·licitud de seguiment" followRequest: "Enviar sol·licitud de seguiment"
followRequests: "Sol·licituds de seguiment" followRequests: "Sol·licituds de seguiment"
unfollow: "Deixar de seguir" unfollow: "Deixar de seguir"
followRequestPending: "Sol·licituds de seguiment pendents" followRequestPending: "Sol·licituds de seguiment pendents"
enterEmoji: "Introduir un emoji" enterEmoji: "Introduir un emoji"
renote: "Impulsà" renote: "Impuls"
unrenote: "Anul·lar impuls" unrenote: "Anul·lar impuls"
renoted: "Impulsat." renoted: "Impulsat."
cantRenote: "Aquesta publicació no pot ser impulsada." cantRenote: "Aquesta nota no pot ser impulsada."
cantReRenote: "No es pot impulsar un impuls." cantReRenote: "No es pot impulsar un impuls."
quote: "Citar" quote: "Cita"
pinnedNote: "Publicació fixada" pinnedNote: "Publicació fixada"
pinned: "Fixar al perfil" pinned: "Fixar al perfil"
you: "Tu" you: "Tu"
@ -116,17 +116,17 @@ reaction: "Reaccions"
reactionSetting: "Reaccions a mostrar al selector de reaccions" reactionSetting: "Reaccions a mostrar al selector de reaccions"
reactionSettingDescription2: "Arrossega per reordenar, fes clic per suprimir, prem\ reactionSettingDescription2: "Arrossega per reordenar, fes clic per suprimir, prem\
\ \"+\" per afegir." \ \"+\" per afegir."
rememberNoteVisibility: "Recorda la configuració de visibilitat de les publicacions" rememberNoteVisibility: "Recorda la configuració de visibilitat de les notes"
attachCancel: "Eliminar el fitxer adjunt" attachCancel: "Eliminar el fitxer adjunt"
markAsSensitive: "Marcar com a NSFW" markAsSensitive: "Marcar com a NSFW"
unmarkAsSensitive: "Deixar de marcar com a sensible" unmarkAsSensitive: "Desmarcar com a NSFW"
enterFileName: "Defineix nom del fitxer" enterFileName: "Introdueix un nom de fitxer"
mute: "Silencia" mute: "Silencia"
unmute: "Deixa de silenciar" unmute: "Deixa de silenciar"
block: "Bloqueja" block: "Bloqueja"
unblock: "Desbloqueja" unblock: "Desbloqueja"
suspend: "Suspèn" suspend: "Suspèn"
unsuspend: "Deixa de suspendre" unsuspend: "Treu la suspensió"
instances: "Instàncies" instances: "Instàncies"
remove: "Eliminar" remove: "Eliminar"
nsfw: "NSFW" nsfw: "NSFW"
@ -134,7 +134,7 @@ pinnedNotes: "Publicació fixada"
userList: "Llistes" userList: "Llistes"
smtpUser: "Nom d'usuari" smtpUser: "Nom d'usuari"
smtpPass: "Contrasenya" smtpPass: "Contrasenya"
user: "Usuaris" user: "Usuari"
searchByGoogle: "Cercar" searchByGoogle: "Cercar"
file: "Fitxers" file: "Fitxers"
_email: _email:
@ -151,10 +151,9 @@ _mfm:
intro: MFM és un llenguatge de marques utilitzat a Misskey, Calckey, Akkoma i més intro: MFM és un llenguatge de marques utilitzat a Misskey, Calckey, Akkoma i més
que es pot utilitzar en molts llocs. Aquí podeu veure una llista de tota la sintaxi que es pot utilitzar en molts llocs. Aquí podeu veure una llista de tota la sintaxi
MFM disponible. MFM disponible.
hashtagDescription: Podeu especificar un hashtag mitjançant un signe de coixinet hashtagDescription: Podeu especificar una etiqueta mitjançant un coixinet i un text.
i un text.
url: URL url: URL
urlDescription: Es poden mostrar URL. urlDescription: Es poden mostrar URLS.
link: Enllaç link: Enllaç
linkDescription: Parts específiques del text es poden mostrar com a URL. linkDescription: Parts específiques del text es poden mostrar com a URL.
bold: Negreta bold: Negreta
@ -299,7 +298,7 @@ _theme:
lighten: Clar lighten: Clar
install: Instal·lar un tema install: Instal·lar un tema
_sfx: _sfx:
note: "Posts" note: "Nota nova"
notification: "Notificacions" notification: "Notificacions"
antenna: Antenes antenna: Antenes
channel: Notificacions del canal channel: Notificacions del canal
@ -740,9 +739,9 @@ _deck:
renameProfile: Canvia el nom de l'espai de treball renameProfile: Canvia el nom de l'espai de treball
nameAlreadyExists: Aquest nom d'espai de treball ja existeix. nameAlreadyExists: Aquest nom d'espai de treball ja existeix.
blockConfirm: Estás segur que vols bloquejar aquest compte? blockConfirm: Estás segur que vols bloquejar aquest compte?
unsuspendConfirm: Estás segur que vols treure la suspensió d'aquesta compte? unsuspendConfirm: Estás segur que vols treure la suspensió d'aquest compte?
unblockConfirm: Estás segur que vols treure el bloqueig d'aquesta compte? unblockConfirm: Estás segur que vols treure el bloqueig d'aquest compte?
suspendConfirm: Estás segur que vols suspendre aquesta compte? suspendConfirm: Estás segur que vols suspendre aquest compte?
selectList: Selecciona una llista selectList: Selecciona una llista
selectAntenna: Selecciona una antena selectAntenna: Selecciona una antena
selectWidget: Selecciona un giny selectWidget: Selecciona un giny
@ -751,13 +750,12 @@ editWidgetsExit: Fet
customEmojis: Emoji personalitzat customEmojis: Emoji personalitzat
cacheRemoteFilesDescription: Quant aquesta opció es deshabilitada, els fitxers remots cacheRemoteFilesDescription: Quant aquesta opció es deshabilitada, els fitxers remots
es carregant directament de l'instància remota. Deshabilitar això farà que baixi es carregant directament de l'instància remota. Deshabilitar això farà que baixi
l'ús d'emmagatzematge, però incrementa el tràfic, perquè les previsualitzacions l'ús d'emmagatzematge, però incrementa el tràfic, perquè les miniatures no es generarán.
no es generarán.
flagAsBot: Marca aquest compte com un bot flagAsBot: Marca aquest compte com un bot
flagAsBotDescription: Activa aquesta opció si aquest compte és controlat per un programa. flagAsBotDescription: Activa aquesta opció si aquest compte és controlat per un programa.
Si s'activa, això actuarà com una bandera per a altres desenvolupadors i prevenir Si s'activa, això actuarà com una bandera per a altres desenvolupadors i ajuda a
cadenes de interaccions infinites amb altres bots a més d'ajustar els sistemes interns prevenir cadenes de interaccions infinites amb altres bots a més d'ajustar els sistemes
de Calckey per tractar aquest compte com un bot. interns de Calckey per tractar aquest compte com un bot.
flagAsCat: Ets un gat? 🐱 flagAsCat: Ets un gat? 🐱
flagShowTimelineReplies: Mostrar respostes a la línea de temps flagShowTimelineReplies: Mostrar respostes a la línea de temps
flagAsCatDescription: Guanyaràs unes orelles de gat i parlares com un gat! flagAsCatDescription: Guanyaràs unes orelles de gat i parlares com un gat!
@ -767,7 +765,7 @@ general: General
autoAcceptFollowed: Aprova automàticament les peticions de seguiment d'usuaris que autoAcceptFollowed: Aprova automàticament les peticions de seguiment d'usuaris que
segueixes segueixes
accountMoved: "L'usuari s'ha mogut a un compte nou:" accountMoved: "L'usuari s'ha mogut a un compte nou:"
addAccount: Afegir compte addAccount: Afegir un compte
loginFailed: No s'ha pogut iniciar sessió loginFailed: No s'ha pogut iniciar sessió
showOnRemote: Veure a l'instància remota showOnRemote: Veure a l'instància remota
wallpaper: Fons de pantalla wallpaper: Fons de pantalla
@ -794,7 +792,7 @@ network: Xarxa
disk: Disc disk: Disc
instanceInfo: Informació de l'instància instanceInfo: Informació de l'instància
statistics: Estadístiques statistics: Estadístiques
clearCachedFiles: Neteja memòria cau clearCachedFiles: Neteja la memòria cau
clearQueueConfirmText: Qualsevol nota que continuï a la cua sense entrega no será clearQueueConfirmText: Qualsevol nota que continuï a la cua sense entrega no será
federada. Normalment aquesta operació no es necessària. federada. Normalment aquesta operació no es necessària.
clearCachedFilesConfirm: Segur que vols esborrar els fitxers remots de la memòria clearCachedFilesConfirm: Segur que vols esborrar els fitxers remots de la memòria
@ -858,14 +856,14 @@ agreeTo: Estic d'acord amb {0}
activity: Activitat activity: Activitat
home: Inici home: Inici
remoteUserCaution: L'informació d'usuaris remots pot estar incompleta. remoteUserCaution: L'informació d'usuaris remots pot estar incompleta.
themeForDarkMode: En Mode Fosc fes servir el tema themeForDarkMode: Tema a fer servir en mode fosc
light: Clar light: Clar
registeredDate: Data de registre registeredDate: Data de registre
dark: Fosc dark: Fosc
lightThemes: Temes clars lightThemes: Temes clars
location: Lloc location: Lloc
theme: Temes theme: Temes
themeForLightMode: En Mode Clar fes servir el tema themeForLightMode: Tema a fer servir en mode clar
drive: Disc drive: Disc
selectFile: Tria un fitxer selectFile: Tria un fitxer
selectFiles: Tria fitxers selectFiles: Tria fitxers
@ -930,17 +928,17 @@ enableGlobalTimeline: Activa la línea de temps global
disablingTimelinesInfo: Els Administradors i Moderadors sempre tenen accés a totes disablingTimelinesInfo: Els Administradors i Moderadors sempre tenen accés a totes
les líneas temporals, inclòs si hi són desactivades. les líneas temporals, inclòs si hi són desactivades.
showLess: Tanca showLess: Tanca
clearQueue: Neteja cua clearQueue: Neteja la cua
uploadFromUrlMayTakeTime: Pot trigar un temps fins que la pujada es completi. uploadFromUrlMayTakeTime: Pot trigar un temps fins que la pujada es completi.
noThankYou: No, gràcies noThankYou: No, gràcies
addInstance: Afegeix una instància addInstance: Afegir una instància
emoji: Emoji emoji: Emoji
emojis: Emoji emojis: Emoji
emojiName: Nom del emoji emojiName: Nom del emoji
emojiUrl: URL del emoji emojiUrl: URL del emoji
addEmoji: Afegir addEmoji: Afegir
settingGuide: Configuració recomenada settingGuide: Configuració recomenada
searchWith: 'Buscar: {q}' searchWith: 'Cercar: {q}'
youHaveNoLists: No tens cap llista youHaveNoLists: No tens cap llista
flagSpeakAsCat: Parla com un gat flagSpeakAsCat: Parla com un gat
selectInstance: Selecciona una instància selectInstance: Selecciona una instància
@ -952,10 +950,9 @@ blockedInstances: Instàncies Bloquejades
blockedInstancesDescription: Llista les adreces de les instàncies que vols bloquejar. blockedInstancesDescription: Llista les adreces de les instàncies que vols bloquejar.
Les instàncies de la llista no podrán comunicarse amb aquesta instància. Les instàncies de la llista no podrán comunicarse amb aquesta instància.
hiddenTags: Etiquetes Ocultes hiddenTags: Etiquetes Ocultes
hiddenTagsDescription: 'Enumereu els etiquetes (sense el #) de les etiquetes que voleu hiddenTagsDescription: 'Enumereu les etiquetes (sense el #) que voleu ocultar de tendències
ocultar de tendències i explorar. Les etiquetes ocultes encara es poden descobrir i explorar. Les etiquetes ocultes encara es poden descobrir per altres mitjans.
per altres mitjans. Les instàncies bloquejades no es veuen afectades encara que Les instàncies bloquejades no es veuen afectades encara que s''enumerin aquí.'
s''enumeren aquí.'
noInstances: No hi han instàncies noInstances: No hi han instàncies
defaultValueIs: 'Per defecte: {value}' defaultValueIs: 'Per defecte: {value}'
suspended: Suspès suspended: Suspès
@ -976,8 +973,8 @@ enableEmojiReactions: Activa reaccions amb emojis
blockThisInstance: Bloqueja aquesta instància blockThisInstance: Bloqueja aquesta instància
registration: Registre registration: Registre
showEmojisInReactionNotifications: Mostra els emojis a les notificacions de les reaccions showEmojisInReactionNotifications: Mostra els emojis a les notificacions de les reaccions
renoteMute: Silencia les renotas renoteMute: Silencia els impulsos
renoteUnmute: Treu el silenci a les renotas renoteUnmute: Treu el silenci als impulsos
cacheRemoteFiles: Fitxers remots a la memoria cau cacheRemoteFiles: Fitxers remots a la memoria cau
federation: Federació federation: Federació
registeredAt: Registrat a registeredAt: Registrat a
@ -1003,7 +1000,7 @@ pages: Pàgines
disconnectService: Desconnectar disconnectService: Desconnectar
connectService: Connectar connectService: Connectar
enableLocalTimeline: Activa la línea de temps local enableLocalTimeline: Activa la línea de temps local
enableRecommendedTimeline: Activa la línea de temps de recomanats enableRecommendedTimeline: Activa la línea de temps de recomanacions
pinnedClipId: ID del clip que vols fixar pinnedClipId: ID del clip que vols fixar
hcaptcha: hCaptcha hcaptcha: hCaptcha
manageAntennas: Gestiona les Antenes manageAntennas: Gestiona les Antenes
@ -1034,7 +1031,7 @@ notFoundDescription: No es pot trobar cap pàgina que correspongui a aquesta adr
uploadFolder: Carpeta per defecte per pujar arxius uploadFolder: Carpeta per defecte per pujar arxius
cacheClear: Netejar la memòria cau cacheClear: Netejar la memòria cau
markAsReadAllNotifications: Marca totes les notificacions com llegides markAsReadAllNotifications: Marca totes les notificacions com llegides
markAsReadAllUnreadNotes: Marca totes les publicacions com a llegides markAsReadAllUnreadNotes: Marca totes les notes com a llegides
markAsReadAllTalkMessages: Marca tots els missatges com llegits markAsReadAllTalkMessages: Marca tots els missatges com llegits
help: Ajuda help: Ajuda
inputMessageHere: Escriu aquí el missatge inputMessageHere: Escriu aquí el missatge
@ -1053,7 +1050,7 @@ text: Text
enable: Activar enable: Activar
next: Següent next: Següent
retype: Torna a entrar retype: Torna a entrar
noteOf: Publicat per {user} noteOf: Nota de {user}
inviteToGroup: Invitar a un grup inviteToGroup: Invitar a un grup
quoteAttached: Cita quoteAttached: Cita
quoteQuestion: Adjuntar com a cita? quoteQuestion: Adjuntar com a cita?
@ -1078,7 +1075,7 @@ groupInvited: T'han invitat a un grup
aboutX: Sobre {x} aboutX: Sobre {x}
youHaveNoGroups: No tens grups youHaveNoGroups: No tens grups
disableDrawer: No facis servir els menús amb estil de calaix disableDrawer: No facis servir els menús amb estil de calaix
noHistory: No ha historial disponible noHistory: No hi ha historial disponible
signinHistory: Historial d'inicis de sessió signinHistory: Historial d'inicis de sessió
disableAnimatedMfm: Desactiva les animacions amb MFM disableAnimatedMfm: Desactiva les animacions amb MFM
doing: Processant... doing: Processant...
@ -1103,8 +1100,8 @@ promotion: Promogut
promote: Promoure promote: Promoure
numberOfDays: Nombre de dies numberOfDays: Nombre de dies
objectStorageBaseUrl: Adreça URL base objectStorageBaseUrl: Adreça URL base
hideThisNote: Amaga aquest article hideThisNote: Amaga aquesta nota
showFeaturedNotesInTimeline: Mostra els articles destacats a la línea de temps showFeaturedNotesInTimeline: Mostra les notes destacades a les líneas de temps
objectStorage: Emmagatzematge d'objectes objectStorage: Emmagatzematge d'objectes
useObjectStorage: Fes servir l'emmagatzema d'objectes useObjectStorage: Fes servir l'emmagatzema d'objectes
expandTweet: Amplia el tuit expandTweet: Amplia el tuit
@ -1114,7 +1111,7 @@ leaveConfirm: Hi han canvis que no s'han desat. Els vols descartar?
manage: Administració manage: Administració
plugins: Afegits plugins: Afegits
preferencesBackups: Preferències de còpies de seguretat preferencesBackups: Preferències de còpies de seguretat
undeck: Treure el Deck undeck: Treure el Taulell
useBlurEffectForModal: Fes servir efectes de difuminació en les finestres modals useBlurEffectForModal: Fes servir efectes de difuminació en les finestres modals
useFullReactionPicker: Fes servir el selector de reaccions a tamany complert useFullReactionPicker: Fes servir el selector de reaccions a tamany complert
deck: Taulell deck: Taulell
@ -1174,14 +1171,14 @@ large: Gran
notificationSetting: Preferències de notificacions notificationSetting: Preferències de notificacions
makeActive: Activar makeActive: Activar
notificationSettingDesc: Tria el tipus de notificació que es veure. notificationSettingDesc: Tria el tipus de notificació que es veure.
notifyAntenna: Notificar noves articles notifyAntenna: Notificar noves notes
withFileAntenna: Només articles amb fitxers withFileAntenna: Només notes amb fitxers
enableServiceworker: Activa les notificacions push per al teu navegador enableServiceworker: Activa les notificacions push per al teu navegador
antennaUsersDescription: Escriu un nom d'usuari per línea antennaUsersDescription: Escriu un nom d'usuari per línea
antennaInstancesDescription: Escriu la adreça d'una instància per línea antennaInstancesDescription: Escriu la adreça d'una instància per línea
tags: Etiquetes tags: Etiquetes
antennaSource: Font de la antena antennaSource: Font de la antena
antennaKeywords: Paraules claus a escolta antennaKeywords: Paraules claus a escoltar
antennaExcludeKeywords: Paraules clau a excluir antennaExcludeKeywords: Paraules clau a excluir
antennaKeywordsDescription: Separades amb espais per fer una condició AND i amb una antennaKeywordsDescription: Separades amb espais per fer una condició AND i amb una
línea nova per fer una condició OR. línea nova per fer una condició OR.
@ -1200,8 +1197,8 @@ tapSecurityKey: Escriu la teva clau de seguretat
nUsersMentioned: Esmentat per {n} usuari(s) nUsersMentioned: Esmentat per {n} usuari(s)
securityKey: Clau de seguretat securityKey: Clau de seguretat
resetPassword: Restablir contrasenya resetPassword: Restablir contrasenya
describeFile: Afegeix un subtítol describeFile: Afegeix una descripció
enterFileDescription: Entra un subtítol enterFileDescription: Entra una descripció
author: Autor author: Autor
disableAll: Desactiva tots disableAll: Desactiva tots
userSaysSomethingReason: '{name} va dir {reason}' userSaysSomethingReason: '{name} va dir {reason}'
@ -1221,7 +1218,7 @@ inboxUrl: Adreça de la safata d'entrada
addedRelays: Relés afegits addedRelays: Relés afegits
serviceworkerInfo: Ha de estar activat per les notificacions push. serviceworkerInfo: Ha de estar activat per les notificacions push.
poll: Enquesta poll: Enquesta
deletedNote: Article eliminat deletedNote: Nota esborrada
disablePlayer: Tancar el reproductor de vídeo disablePlayer: Tancar el reproductor de vídeo
fileIdOrUrl: ID o adreça URL del fitxer fileIdOrUrl: ID o adreça URL del fitxer
behavior: Comportament behavior: Comportament
@ -1229,7 +1226,7 @@ regenerateLoginTokenDescription: Regenera el token que es fa servir de manera in
durant l'inici de sessió. Normalment això no és necessari. Si es torna a genera durant l'inici de sessió. Normalment això no és necessari. Si es torna a genera
el token, es tancarà la sessió a tots els dispositius. el token, es tancarà la sessió a tots els dispositius.
setMultipleBySeparatingWithSpace: Separa diferents entrades amb espais. setMultipleBySeparatingWithSpace: Separa diferents entrades amb espais.
reportAbuseOf: Informa sobre {name} reportAbuseOf: Informa d'un abús de {name}
sample: Exemple sample: Exemple
abuseReports: Informes abuseReports: Informes
reportAbuse: Informe reportAbuse: Informe
@ -1243,13 +1240,13 @@ abuseMarkAsResolved: Marcar l'informe com a resolt
visibility: Visibilitat visibility: Visibilitat
useCw: Amaga el contingut useCw: Amaga el contingut
enablePlayer: Obre el reproductor de vídeo enablePlayer: Obre el reproductor de vídeo
yourAccountSuspendedDescription: Aquest compte ha sigut suspesa per no seguir els yourAccountSuspendedDescription: Aquest compte ha sigut suspès per no seguir els termes
termes de servei del servidor o quelcom similar. Contacte amb l'administrador si de servei d'aquest servidor o quelcom similar. Contacte amb l'administrador si vols
vols conèixer la raó amb més detall. Si us plau no facis un compte nou. conèixer la raó amb més detall. Si us plau no facis un compte nou.
invisibleNote: Article ocult invisibleNote: Nota oculta
enableInfiniteScroll: Carregar més de forma automàtica enableInfiniteScroll: Carregar més de forma automàtica
fillAbuseReportDescription: Si us plau omple els detalls sobre aquest informe. Si fillAbuseReportDescription: Si us plau omple els detalls sobre aquest informe. Si
es sobre un article en concret, si us plau inclou l'adreça URL. es sobre una nota en concret, si us plau, inclou l'adreça URL.
forwardReportIsAnonymous: Com a informador a l'instància remota no es mostrarà el forwardReportIsAnonymous: Com a informador a l'instància remota no es mostrarà el
teu compte, si no un compte anònim. teu compte, si no un compte anònim.
openInNewTab: Obrir en una pestanya nova openInNewTab: Obrir en una pestanya nova
@ -1266,7 +1263,7 @@ switchUi: Interfície d'usuari
createNewClip: Crear un clip nou createNewClip: Crear un clip nou
unclip: Treure clip unclip: Treure clip
public: Públic public: Públic
renotesCount: Nombre de re-notes fetes renotesCount: Nombre d'impulsos fets
sentReactionsCount: Nombre de reaccions fetes sentReactionsCount: Nombre de reaccions fetes
receivedReactionsCount: Nombre de reaccions rebudes receivedReactionsCount: Nombre de reaccions rebudes
pollVotesCount: Nombre de vots fets en enquestes pollVotesCount: Nombre de vots fets en enquestes
@ -1278,14 +1275,14 @@ driveUsage: Espai fet servir al Disk
noCrawleDescription: No permetre que els buscadors guardin la informació de les pàgines noCrawleDescription: No permetre que els buscadors guardin la informació de les pàgines
de perfil, notes, Pàgines, etc. de perfil, notes, Pàgines, etc.
alwaysMarkSensitive: Marcar per defecte com a NSFW alwaysMarkSensitive: Marcar per defecte com a NSFW
lockedAccountInfo: Només si has configurat la visibilitat del compte per "Només seguidors" lockedAccountInfo: Si has configurat la visibilitat del compte per "Només seguidors"
les teves notes no serem visibles per a ningú, inclús si has d'aprovar els teus les teves notes no seren visibles per a ningú més, inclús si has d'aprovar els teus
seguiments manualment. seguidors manualment.
disableShowingAnimatedImages: No reproduir les imatges animades disableShowingAnimatedImages: No reproduir les imatges animades
verificationEmailSent: S'ha enviat correu electrònic de verificació. Si us plau segueix verificationEmailSent: S'ha enviat correu electrònic de verificació. Si us plau segueix
les instruccions per completar la verificació. les instruccions per completar la verificació.
notSet: Sense especificar notSet: Sense especificar
emailVerified: Correu electrònic enviat emailVerified: El correu electrònic s'ha verificat
loadRawImages: Carregar les imatges originals en comptes de mostrar les miniatures loadRawImages: Carregar les imatges originals en comptes de mostrar les miniatures
noteFavoritesCount: Nombre de notes afegides a favorits noteFavoritesCount: Nombre de notes afegides a favorits
useSystemFont: Fes servir la font per defecte del sistema useSystemFont: Fes servir la font per defecte del sistema
@ -1327,7 +1324,7 @@ breakFollow: Suprimeix el seguidor
makeReactionsPublicDescription: Això farà que la llista de totes les vostres reaccions makeReactionsPublicDescription: Això farà que la llista de totes les vostres reaccions
passades sigui visible públicament. passades sigui visible públicament.
hide: Amagar hide: Amagar
leaveGroupConfirm: Estàs segur que vols deixar "{nom}"? leaveGroupConfirm: Estàs segur que vols deixar "{name}"?
voteConfirm: Vols confirmar el teu vot per a "{choice}"? voteConfirm: Vols confirmar el teu vot per a "{choice}"?
leaveGroup: Sortir del grup leaveGroup: Sortir del grup
rateLimitExceeded: S'ha excedit el límit proporcionat rateLimitExceeded: S'ha excedit el límit proporcionat
@ -1454,7 +1451,7 @@ _registry:
silenced: Silenciat silenced: Silenciat
objectStorageUseSSL: Fes servir SSL objectStorageUseSSL: Fes servir SSL
yourAccountSuspendedTitle: Aquest compte està suspès yourAccountSuspendedTitle: Aquest compte està suspès
i18nInfo: Calckey està sent traduïts a diversos idiomes per voluntaris. Pots ajudar i18nInfo: Calckey està sent traduït a diversos idiomes per voluntaris. Pots ajudar
{link}. {link}.
manageAccessTokens: Administrar tokens d'accés manageAccessTokens: Administrar tokens d'accés
accountInfo: Informació del compte accountInfo: Informació del compte
@ -1498,15 +1495,15 @@ shareWithNote: Comparteix amb una nota
expiration: Data límit expiration: Data límit
memo: Memo memo: Memo
priority: Prioritat priority: Prioritat
high: Alt high: Alta
middle: Mitjana middle: Mitjana
low: Baixa low: Baixa
emailNotConfiguredWarning: L'adreça de correu electrònic no està definida. emailNotConfiguredWarning: L'adreça de correu electrònic no està definida.
instanceSecurity: Seguretat de la instància instanceSecurity: Seguretat de la instància
privateMode: Mode Privat privateMode: Mode Privat
allowedInstances: Instàncies a la llista blanca allowedInstances: Instàncies a la llista blanca
allowedInstancesDescription: Amfitrions d'instàncies a la llista blanca per a la federació, allowedInstancesDescription: Llista blanca de Hosts amb qui federar, cadascún separat
cadascuna separat per una línia nova (només s'aplica en mode privat). per una línia nova (només s'aplica en mode privat).
previewNoteText: Mostra la vista prèvia previewNoteText: Mostra la vista prèvia
customCss: CSS personalitzat customCss: CSS personalitzat
recommended: Recomanat recommended: Recomanat
@ -1550,8 +1547,8 @@ remoteOnly: Només remotes
failedToUpload: S'ha produït un error en la càrrega failedToUpload: S'ha produït un error en la càrrega
cannotUploadBecauseInappropriate: Aquest fitxer no s'ha pogut carregar perquè s'han cannotUploadBecauseInappropriate: Aquest fitxer no s'ha pogut carregar perquè s'han
detectat parts d'aquest com a potencialment NSFW. detectat parts d'aquest com a potencialment NSFW.
cannotUploadBecauseNoFreeSpace: La pujada ha fallat a causa de la manca de capacitat cannotUploadBecauseNoFreeSpace: La pujada ha fallat a causa de la manca d'espai al
del Disc. Disc.
enableAutoSensitive: Marcatge automàtic NSFW enableAutoSensitive: Marcatge automàtic NSFW
moveTo: Mou el compte actual al compte nou moveTo: Mou el compte actual al compte nou
customKaTeXMacro: Macros KaTeX personalitzats customKaTeXMacro: Macros KaTeX personalitzats
@ -1575,19 +1572,19 @@ desktop: Escritori
notesCount: Nombre de notes notesCount: Nombre de notes
confirmToUnclipAlreadyClippedNote: Aquesta nota ja és al clip "{name}". Vols treure'l confirmToUnclipAlreadyClippedNote: Aquesta nota ja és al clip "{name}". Vols treure'l
d'aquest clip? d'aquest clip?
driveFilesCount: Nombre de fitxers el Disk driveFilesCount: Nombre de fitxers al Disk
silencedInstances: Instàncies silenciades silencedInstances: Instàncies silenciades
silenceThisInstance: Silencia la instància silenceThisInstance: Silencia la instància
silencedInstancesDescription: Llista amb els noms de les instàncies que vols silenciar. silencedInstancesDescription: Llista amb els noms de les instàncies que vols silenciar.
Les comptes en les instàncies silenciades seran tractades com "Silenciades", només Els comptes en les instàncies silenciades seran tractades com "Silenciades", només
poden fer sol·licitud de seguiments, i no poden mencionar comptes locals si no les poden fer sol·licituds de seguiments, i no poden mencionar comptes locals si no
segueixen. Això no afectarà les instàncies silenciades. les segueixen. Això no afectarà les instàncies bloquejades.
objectStorageEndpointDesc: Deixa això buit si fas servir AWS, S3, d'una altre manera objectStorageEndpointDesc: Deixa això buit si fas servir AWS, S3, d'una altre manera
específica un "endpoint" com a '<host>' o '<host>:<port>', depend del proveïdor específica un "endpoint" com a '<host>' o '<host>:<port>', depend del proveïdor
que facis servir. que facis servir.
objectStorageRegionDesc: Especifica una regió com a 'xx-east-1'. Si el teu proveïdor objectStorageRegionDesc: Especifica una regió com a 'xx-east-1'. Si el teu proveïdor
no distingeix entre regions, deixa això en buit o pots escriure 'us-east-1'. no distingeix entre regions, deixa això en buit o pots escriure 'us-east-1'.
userPagePinTip: Pots mostrar notes aquí escollint "Pin al perfil" dintre del menú userPagePinTip: Pots mostrar notes aquí escollint "Fixar al perfil" dintre del menú
de cada nota. de cada nota.
userInfo: Informació d'usuari userInfo: Informació d'usuari
hideOnlineStatusDescription: Amagant el teu estat en línea redueix la comoditat d'ús hideOnlineStatusDescription: Amagant el teu estat en línea redueix la comoditat d'ús
@ -1599,10 +1596,10 @@ secureMode: Mode segur (Recuperació Autoritzada)
customCssWarn: Aquesta configuració només s'ha d'utilitzar si sabeu què fa. La introducció customCssWarn: Aquesta configuració només s'ha d'utilitzar si sabeu què fa. La introducció
de valors indeguts pot provocar que el client deixi de funcionar amb normalitat. de valors indeguts pot provocar que el client deixi de funcionar amb normalitat.
squareAvatars: Mostra avatars quadrats squareAvatars: Mostra avatars quadrats
secureModeInfo: Quan sol·liciteu des d'altres instàncies, no envieu de tornada sense secureModeInfo: Quan es faci una solicitut d'altres instàncies no contestar sense
prova. una prova.
privateModeInfo: Quan està activat, només les instàncies de la llista blanca es poden privateModeInfo: Quan està activat, només les instàncies de la llista blanca es poden
federar amb les vostres instàncies. Totes les publicacions s'amagaran al públic. federar amb les vostres instàncies. Totes les notes s'amagaran al públic.
useBlurEffect: Utilitzeu efectes de desenfocament a la interfície d'usuari useBlurEffect: Utilitzeu efectes de desenfocament a la interfície d'usuari
accountDeletionInProgress: La supressió del compte està en curs accountDeletionInProgress: La supressió del compte està en curs
unmuteThread: Desfés el silenci al fil unmuteThread: Desfés el silenci al fil
@ -1633,7 +1630,8 @@ none: Res
showInPage: Mostrar a la página showInPage: Mostrar a la página
popout: Apareixa popout: Apareixa
volume: Volum volume: Volum
objectStorageUseSSLDesc: Desactiva això si no fas servir HTTP per les connexions API objectStorageUseSSLDesc: Desactiva això si no fas servir HTTPS per les connexions
API
objectStorageUseProxy: Conectarse mitjançant un Proxy objectStorageUseProxy: Conectarse mitjançant un Proxy
objectStorageUseProxyDesc: Desactiva això si no faràs servir un servidor Proxy per objectStorageUseProxyDesc: Desactiva això si no faràs servir un servidor Proxy per
conexions API conexions API
@ -1668,12 +1666,12 @@ disablePagesScript: Desactivar AiScript a les pàgines
updateRemoteUser: Actualitzar la informació de l'usuari remot updateRemoteUser: Actualitzar la informació de l'usuari remot
deleteAllFiles: Esborrar tots els fitxers deleteAllFiles: Esborrar tots els fitxers
deleteAllFilesConfirm: Segur que vols esborrar tots els fitxers? deleteAllFilesConfirm: Segur que vols esborrar tots els fitxers?
removeAllFollowing: Deixar de seguir a tots els usuaris removeAllFollowing: Deixar de seguir a tots els que segueixis
accentColor: Color principal accentColor: Color principal
textColor: Color del text textColor: Color del text
value: Valor value: Valor
sendErrorReportsDescription: "Quant està activat, es compartirà amb els desenvolupadors\ sendErrorReportsDescription: "Quant està activat quant aparegui un error, es compartirà\
\ de Calckey quant aparegui un problema quan ajudarà a millorar la qualitat.\nAixò\ \ amb els desenvolupadors de Calckey, que ajudarà a millorar la qualitat.\nAixò\
\ inclourà informació com la versió del teu sistema operatiu, el navegador que estiguis\ \ inclourà informació com la versió del teu sistema operatiu, el navegador que estiguis\
\ fent servir, la teva activitat a Calckey, etc." \ fent servir, la teva activitat a Calckey, etc."
myTheme: El meu tema myTheme: El meu tema
@ -1681,7 +1679,7 @@ backgroundColor: Color de fons
saveAs: Desa com... saveAs: Desa com...
advanced: Avançat advanced: Avançat
invalidValue: Valor invàlid. invalidValue: Valor invàlid.
createdAt: Dada de creació createdAt: Data de creació
updatedAt: Data d'actualització updatedAt: Data d'actualització
saveConfirm: Desa canvis? saveConfirm: Desa canvis?
deleteConfirm: De veritat ho vols esborrar? deleteConfirm: De veritat ho vols esborrar?
@ -1715,15 +1713,15 @@ sendPushNotificationReadMessageCaption: Es mostrarà una notificació amb el tex
showAds: Mostrar anuncis showAds: Mostrar anuncis
enterSendsMessage: Pren retorn al formulari del missatge per enviar (quant no s'activa enterSendsMessage: Pren retorn al formulari del missatge per enviar (quant no s'activa
es Ctrl + Return) es Ctrl + Return)
customMOTD: MOTD personalitzat (missatges de la pantalla d'inici) customMOTD: MOTD personalitzat (missatges de la pantalla de benvinguda)
customMOTDDescription: Missatges personalitzats per al MOTD (pantalla de presentació) customMOTDDescription: Missatges personalitzats per al MOTD (pantalla de benvinguda)
separats per salts de línia es mostraran aleatòriament cada vegada que un usuari separats per salts de línia, es mostraran aleatòriament cada vegada que un usuari
carrega/recarrega la pàgina. carrega/recarrega la pàgina.
customSplashIcons: Icones personalitzades de la pantalla d'inici (urls) customSplashIcons: Icones personalitzades de la pantalla de benvinguda (urls)
customSplashIconsDescription: La URL de les icones de pantalla de presentació personalitzades customSplashIconsDescription: Les URLS de les icones personalitzades a la pantalla
separades per salts de línia es mostraran aleatòriament cada vegada que un usuari de benvinguda separades per salts de línia. Es mostraran aleatòriament cada vegada
carrega/recarrega la pàgina. Si us plau, assegureu-vos que les imatges estiguin que un usuari carrega/recarrega la pàgina. Si us plau, assegureu-vos que les imatges
en una URL estàtica, preferiblement totes a la mida de 192 x 192. estiguin en una URL estàtica, preferiblement amb imatges amb la de 192 x 192.
moveFrom: Mou a aquest compte des d'un compte anterior moveFrom: Mou a aquest compte des d'un compte anterior
moveFromLabel: 'Compte des del qual us moveu:' moveFromLabel: 'Compte des del qual us moveu:'
migrationConfirm: "Esteu absolutament segur que voleu migrar el vostre compte a {account}?\ migrationConfirm: "Esteu absolutament segur que voleu migrar el vostre compte a {account}?\
@ -1753,7 +1751,7 @@ showingPastTimeline: Ara es mostra un línea de temps antiga
clear: Tornar clear: Tornar
markAllAsRead: Marcar tot com a llegit markAllAsRead: Marcar tot com a llegit
recentPosts: Pàgines recents recentPosts: Pàgines recents
noMaintainerInformationWarning: La informació del responsable no està configurada. noMaintainerInformationWarning: La informació de l'administrador no està configurada.
resolved: Resolt resolved: Resolt
unresolved: Sense resoldre unresolved: Sense resoldre
filter: Filtre filter: Filtre
@ -1762,14 +1760,14 @@ useDrawerReactionPickerForMobile: Mostra el selector de reaccions com a calaix a
mòbil mòbil
welcomeBackWithName: Benvingut de nou, {name} welcomeBackWithName: Benvingut de nou, {name}
showLocalPosts: 'Mostra les notes locals a:' showLocalPosts: 'Mostra les notes locals a:'
homeTimeline: Línea de temps Local homeTimeline: Línea de temps Inicial
socialTimeline: Línea de temps Social socialTimeline: Línea de temps Social
themeColor: Color del Ticker de la instància themeColor: Color del Ticker de la instància
size: Mida size: Mida
numberOfColumn: Nombre de columnes numberOfColumn: Nombre de columnes
numberOfPageCache: Nombre de pàgines emmagatzemades a la memòria cau numberOfPageCache: Nombre de pàgines emmagatzemades a la memòria cau
numberOfPageCacheDescription: L'augment d'aquest nombre millorarà la comoditat dels numberOfPageCacheDescription: L'augment d'aquest nombre millorarà la comoditat dels
usuaris, però provocarà més càrrega del servidor i més memòria per utilitzar-la. usuaris, però provocarà més càrrega del servidor i utilitzarà més memòria.
logoutConfirm: Vols tancar la sessió? logoutConfirm: Vols tancar la sessió?
lastActiveDate: Data d'últim ús lastActiveDate: Data d'últim ús
statusbar: Barra d'estat statusbar: Barra d'estat
@ -1791,7 +1789,7 @@ subscribePushNotification: Activar les notificacions push
unsubscribePushNotification: Desactivar les notificacions push unsubscribePushNotification: Desactivar les notificacions push
pushNotificationAlreadySubscribed: Les notificacions push ja estan activades pushNotificationAlreadySubscribed: Les notificacions push ja estan activades
pushNotificationNotSupported: El vostre navegador o instància no admet notificacions pushNotificationNotSupported: El vostre navegador o instància no admet notificacions
automàtiques push
license: Llicència license: Llicència
indexPosts: Índex de notes indexPosts: Índex de notes
indexFrom: Índex a partir de l'identificador de notes (deixeu en blanc per indexar indexFrom: Índex a partir de l'identificador de notes (deixeu en blanc per indexar
@ -1869,8 +1867,8 @@ _tutorial:
step3_2: "Les teves líneas de temps domèstiques i socials es basen en qui seguiu,\ step3_2: "Les teves líneas de temps domèstiques i socials es basen en qui seguiu,\
\ així que proveu de seguir un parell de comptes per començar.\nFeu clic al cercle\ \ així que proveu de seguir un parell de comptes per començar.\nFeu clic al cercle\
\ més situat a la part superior dreta d'un perfil per seguir-los." \ més situat a la part superior dreta d'un perfil per seguir-los."
step4_2: Per a la vostra primera nota, a algunes persones els agrada fer una nota step4_2: A algunes persones els agrada fer una nota de {introduction} o un senzill
de {introduction} o un senzill "Hola món!" "Hola món!"
step5_1: Línies de temps, línies de temps a tot arreu! step5_1: Línies de temps, línies de temps a tot arreu!
step6_2: Bé, no només t'has unit a Calckey. T'has unit a un portal al Fediverse, step6_2: Bé, no només t'has unit a Calckey. T'has unit a un portal al Fediverse,
una xarxa interconnectada de milers de servidors, anomenats "instàncies". una xarxa interconnectada de milers de servidors, anomenats "instàncies".
@ -1888,7 +1886,7 @@ _permissions:
"write:blocks": Editar la llista d'usuaris bloquejats "write:blocks": Editar la llista d'usuaris bloquejats
"write:notes": Redactar o suprimir notes "write:notes": Redactar o suprimir notes
"write:channels": Editar els teus canals "write:channels": Editar els teus canals
"read:gallery-likes": Consulta la llista de notes de la galeria que t'agraden "read:gallery-likes": Consulta la llista de notes que t'agraden de la galeria
"write:drive": Editar o suprimir fitxers i carpetes del Disc "write:drive": Editar o suprimir fitxers i carpetes del Disc
"read:favorites": Consulta la teva llista d'adreces d'interès "read:favorites": Consulta la teva llista d'adreces d'interès
"write:favorites": Editeu la teva llista d'adreces d'interès "write:favorites": Editeu la teva llista d'adreces d'interès
@ -1896,13 +1894,13 @@ _permissions:
"read:mutes": Consulta la teva llista d'usuaris silenciats "read:mutes": Consulta la teva llista d'usuaris silenciats
"write:reactions": Edita les teves reaccions "write:reactions": Edita les teves reaccions
"write:votes": Vota en una enquesta "write:votes": Vota en una enquesta
"write:pages": Editeu o suprimeix la teva pàgina "write:pages": Edita o suprimeix la teva pàgina
"write:page-likes": Editar les pàgines que t'agraden "write:page-likes": Editar les pàgines que t'agraden
"read:user-groups": Consulta els teus grups d'usuaris "read:user-groups": Consulta els teus grups d'usuaris
"read:channels": Consulta els teus canals "read:channels": Consulta els teus canals
"read:gallery": Consulta la teva galeria "read:gallery": Consulta la teva galeria
"write:gallery": Edita la teva galeria "write:gallery": Edita la teva galeria
"write:gallery-likes": Edita la llista de notes de la galeria que t'agraden "write:gallery-likes": Edita la llista de notes que t'agraden de la galeria
"read:following": Consulta la informació sobre a qui segueixes "read:following": Consulta la informació sobre a qui segueixes
"read:reactions": Consulta les teves reaccions "read:reactions": Consulta les teves reaccions
"read:pages": Consulta la teva pàgina "read:pages": Consulta la teva pàgina
@ -2039,3 +2037,6 @@ _apps:
paid: Pagament paid: Pagament
theDesk: TheDesk theDesk: TheDesk
apps: Aplicacions apps: Aplicacions
deleted: Esborrat
editNote: Editar nota
edited: Editat

View File

@ -1,10 +1,8 @@
_lang_: "Deutsch" _lang_: "Deutsch"
headlineMisskey: "Ein durch Posts verbundenes Netzwerk" headlineMisskey: "Eine dezentralisierte Open-Source Social Media Plattform, die für\
introMisskey: "Willkommen! Calckey ist eine dezentralisierte Open-Source Microblogging-Platform.\n\ \ immer gratis bleibt! \U0001F680"
Verfasse „Posts“ um mitzuteilen, was gerade passiert oder um Ereignisse mit anderen\ introMisskey: "Willkommen! Calckey ist eine dezentralisierte Open-Source Social Media\
\ zu teilen. \U0001F4E1\nMit „Reaktionen“ kannst du außerdem schnell deine Gefühle\ \ Plattform, die für immer gratis bleibt!\U0001F680"
\ über Posts anderer Benutzer zum Ausdruck bringen. \U0001F44D\nEine neue Welt wartet\
\ auf dich! \U0001F680"
monthAndDay: "{day}.{month}." monthAndDay: "{day}.{month}."
search: "Suchen" search: "Suchen"
notifications: "Benachrichtigungen" notifications: "Benachrichtigungen"
@ -26,9 +24,9 @@ otherSettings: "Weitere Einstellungen"
openInWindow: "In einem Fenster öffnen" openInWindow: "In einem Fenster öffnen"
profile: "Profil" profile: "Profil"
timeline: "Chronik" timeline: "Chronik"
noAccountDescription: "Dieser Nutzer hat seine Profilbeschreibung noch nicht ausgefüllt" noAccountDescription: "Dieser Nutzer hat seine Profilbeschreibung noch nicht ausgefüllt."
login: "Anmelden" login: "Anmelden"
loggingIn: "Du wirst angemeldet" loggingIn: "Du wirst angemeldet"
logout: "Abmelden" logout: "Abmelden"
signup: "Registrieren" signup: "Registrieren"
uploading: "Wird hochgeladen …" uploading: "Wird hochgeladen …"
@ -57,7 +55,7 @@ reply: "Antworten"
loadMore: "Mehr laden" loadMore: "Mehr laden"
showMore: "Mehr anzeigen" showMore: "Mehr anzeigen"
showLess: "Schließen" showLess: "Schließen"
youGotNewFollower: "ist dir gefolgt" youGotNewFollower: "folgt dir nun"
receiveFollowRequest: "Follow-Anfrage erhalten" receiveFollowRequest: "Follow-Anfrage erhalten"
followRequestAccepted: "Follow-Anfrage akzeptiert" followRequestAccepted: "Follow-Anfrage akzeptiert"
mention: "Erwähnung" mention: "Erwähnung"
@ -68,8 +66,8 @@ import: "Import"
export: "Export" export: "Export"
files: "Dateien" files: "Dateien"
download: "Herunterladen" download: "Herunterladen"
driveFileDeleteConfirm: "Möchtest du die Datei „{name}“ wirklich löschen? Notizen\ driveFileDeleteConfirm: "Möchtest du die Datei „{name}“ wirklich löschen? Es wird\
\ mit dieser Datei werden ebenso verschwinden." \ aus allen Notizen entfernt, die es als Anhang enthalten."
unfollowConfirm: "Möchtest du {name} nicht mehr folgen?" unfollowConfirm: "Möchtest du {name} nicht mehr folgen?"
exportRequested: "Du hast einen Export angefragt. Dies kann etwas Zeit in Anspruch\ exportRequested: "Du hast einen Export angefragt. Dies kann etwas Zeit in Anspruch\
\ nehmen. Sobald der Export abgeschlossen ist, wird er deiner Drive hinzugefügt." \ nehmen. Sobald der Export abgeschlossen ist, wird er deiner Drive hinzugefügt."
@ -120,11 +118,11 @@ add: "Hinzufügen"
reaction: "Reaktionen" reaction: "Reaktionen"
reactionSetting: "In der Reaktionsauswahl anzuzeigende Reaktionen" reactionSetting: "In der Reaktionsauswahl anzuzeigende Reaktionen"
reactionSettingDescription2: "Ziehe um Anzuordnen, klicke um zu löschen, drücke „+“\ reactionSettingDescription2: "Ziehe um Anzuordnen, klicke um zu löschen, drücke „+“\
\ um hinzuzufügen" \ um hinzuzufügen."
rememberNoteVisibility: "Notizsichtbarkeit merken" rememberNoteVisibility: "Notizsichtbarkeit merken"
attachCancel: "Anhang entfernen" attachCancel: "Anhang entfernen"
markAsSensitive: "Als NSFW markieren" markAsSensitive: "Als NSFW markieren"
accountMoved: "Benutzer hat zu einem anderen Account gewechselt." accountMoved: "Benutzer hat zu einem anderen Account gewechselt:"
unmarkAsSensitive: "Als nicht NSFW markieren" unmarkAsSensitive: "Als nicht NSFW markieren"
enterFileName: "Dateinamen eingeben" enterFileName: "Dateinamen eingeben"
mute: "Stummschalten" mute: "Stummschalten"
@ -157,7 +155,7 @@ cacheRemoteFilesDescription: "Ist diese Einstellung deaktiviert, so werden Datei
flagAsBot: "Als Bot markieren" flagAsBot: "Als Bot markieren"
flagAsBotDescription: "Aktiviere diese Option, falls dieses Benutzerkonto durch ein\ flagAsBotDescription: "Aktiviere diese Option, falls dieses Benutzerkonto durch ein\
\ Programm gesteuert wird. Falls aktiviert, agiert es als Flag für andere Entwickler\ \ Programm gesteuert wird. Falls aktiviert, agiert es als Flag für andere Entwickler\
\ zur Verhinderung von endlosen Kettenreaktionen mit anderen Bots und lässt Misskeys\ \ zur Verhinderung von endlosen Kettenreaktionen mit anderen Bots und lässt Calckeys\
\ interne Systeme dieses Benutzerkonto als Bot behandeln." \ interne Systeme dieses Benutzerkonto als Bot behandeln."
flagAsCat: "Als Katze markieren" flagAsCat: "Als Katze markieren"
flagAsCatDescription: "Aktiviere diese Option, um dieses Benutzerkonto als Katze zu\ flagAsCatDescription: "Aktiviere diese Option, um dieses Benutzerkonto als Katze zu\
@ -228,8 +226,8 @@ blockedUsers: "Blockierte Benutzer"
noUsers: "Keine Benutzer gefunden" noUsers: "Keine Benutzer gefunden"
editProfile: "Profil bearbeiten" editProfile: "Profil bearbeiten"
noteDeleteConfirm: "Möchtest du diese Notiz wirklich löschen?" noteDeleteConfirm: "Möchtest du diese Notiz wirklich löschen?"
pinLimitExceeded: "Du kannst nicht noch mehr Notizen anheften." pinLimitExceeded: "Du kannst nicht noch mehr Notizen anheften"
intro: "Misskey ist installiert! Lass uns nun ein Administratorkonto einrichten." intro: "Calckey ist installiert! Lass uns nun ein Administratorkonto einrichten."
done: "Fertig" done: "Fertig"
processing: "In Bearbeitung …" processing: "In Bearbeitung …"
preview: "Vorschau" preview: "Vorschau"
@ -374,7 +372,7 @@ pinnedUsersDescription: "Gib durch Leerzeichen getrennte Benutzer an, die an die
Erkunden\"-Seite angeheftet werden sollen." Erkunden\"-Seite angeheftet werden sollen."
pinnedPages: "Angeheftete Seiten" pinnedPages: "Angeheftete Seiten"
pinnedPagesDescription: "Gib durch Leerzeilen getrennte Pfäde zu Seiten an, die an\ pinnedPagesDescription: "Gib durch Leerzeilen getrennte Pfäde zu Seiten an, die an\
\ die Startseite dieser Instanz angeheftet werden sollen.\n" \ die Startseite dieser Instanz angeheftet werden sollen."
pinnedClipId: "ID des anzuheftenden Clips" pinnedClipId: "ID des anzuheftenden Clips"
pinnedNotes: "Angeheftete Notizen" pinnedNotes: "Angeheftete Notizen"
hcaptcha: "hCaptcha" hcaptcha: "hCaptcha"
@ -396,7 +394,7 @@ antennaKeywords: "Zu beobachtende Schlüsselwörter"
antennaExcludeKeywords: "Zu ignorierende Schlüsselwörter" antennaExcludeKeywords: "Zu ignorierende Schlüsselwörter"
antennaKeywordsDescription: "Zum Nutzen einer \"UND\"-Verknüpfung Einträge mit Leerzeichen\ antennaKeywordsDescription: "Zum Nutzen einer \"UND\"-Verknüpfung Einträge mit Leerzeichen\
\ trennen, zum Nutzen einer \"ODER\"-Verknüpfung Einträge mit einem Zeilenumbruch\ \ trennen, zum Nutzen einer \"ODER\"-Verknüpfung Einträge mit einem Zeilenumbruch\
\ trennen" \ trennen."
notifyAntenna: "Über neue Notizen benachrichtigen" notifyAntenna: "Über neue Notizen benachrichtigen"
withFileAntenna: "Nur Notizen mit Dateien" withFileAntenna: "Nur Notizen mit Dateien"
enableServiceworker: "Push-Benachrichtigungen im Browser aktivieren" enableServiceworker: "Push-Benachrichtigungen im Browser aktivieren"
@ -420,7 +418,7 @@ exploreFediverse: "Das Fediverse erkunden"
popularTags: "Beliebte Schlagwörter" popularTags: "Beliebte Schlagwörter"
userList: "Liste" userList: "Liste"
about: "Über" about: "Über"
aboutMisskey: "Über Misskey" aboutMisskey: "Über Calckey"
administrator: "Administrator" administrator: "Administrator"
token: "Token" token: "Token"
twoStepAuthentication: "Zwei-Faktor-Authentifizierung" twoStepAuthentication: "Zwei-Faktor-Authentifizierung"
@ -477,7 +475,7 @@ checking: "Wird überprüft …"
available: "Verfügbar" available: "Verfügbar"
unavailable: "Unverfügbar" unavailable: "Unverfügbar"
usernameInvalidFormat: "Du kannst Klein- und Großbuchstaben, Zahlen sowie Unterstriche\ usernameInvalidFormat: "Du kannst Klein- und Großbuchstaben, Zahlen sowie Unterstriche\
\ verwenden" \ verwenden."
tooShort: "Zu kurz" tooShort: "Zu kurz"
tooLong: "Zu lang" tooLong: "Zu lang"
weakPassword: "Schwaches Passwort" weakPassword: "Schwaches Passwort"
@ -528,7 +526,7 @@ objectStorage: "Object Storage"
useObjectStorage: "Object Storage verwenden" useObjectStorage: "Object Storage verwenden"
objectStorageBaseUrl: "Basis-URL" objectStorageBaseUrl: "Basis-URL"
objectStorageBaseUrlDesc: "Die als Referenz verwendete URL. Verwendest du einen CDN\ objectStorageBaseUrlDesc: "Die als Referenz verwendete URL. Verwendest du einen CDN\
\ oder Proxy, gib dessen URL an. Für S3 verwende 'https://<bucket>.s3.amazonaws.com'.\ \ oder Proxy, gib dessen URL an. \nFür S3 verwende 'https://<bucket>.s3.amazonaws.com'.\
\ Für GCS o.ä. verwende 'https://storage.googleapis.com/<bucket>'." \ Für GCS o.ä. verwende 'https://storage.googleapis.com/<bucket>'."
objectStorageBucket: "Bucket" objectStorageBucket: "Bucket"
objectStorageBucketDesc: "Bitte gib den Namen des Buckets an, der bei deinem Anbieter\ objectStorageBucketDesc: "Bitte gib den Namen des Buckets an, der bei deinem Anbieter\
@ -576,7 +574,7 @@ ascendingOrder: "Aufsteigende Reihenfolge"
descendingOrder: "Absteigende Reihenfolge" descendingOrder: "Absteigende Reihenfolge"
scratchpad: "Testumgebung" scratchpad: "Testumgebung"
scratchpadDescription: "Die Testumgebung bietet einen Bereich für AiScript-Experimente.\ scratchpadDescription: "Die Testumgebung bietet einen Bereich für AiScript-Experimente.\
\ Dort kannst du AiScript schreiben, ausführen sowie dessen Auswirkungen auf Misskey\ \ Dort kannst du AiScript schreiben, ausführen sowie dessen Auswirkungen auf Calckey\
\ überprüfen." \ überprüfen."
output: "Ausgabe" output: "Ausgabe"
script: "Skript" script: "Skript"
@ -652,7 +650,7 @@ smtpPass: "Passwort"
emptyToDisableSmtpAuth: "Benutzername und Passwort leer lassen, um SMTP-Verifizierung\ emptyToDisableSmtpAuth: "Benutzername und Passwort leer lassen, um SMTP-Verifizierung\
\ zu deaktivieren" \ zu deaktivieren"
smtpSecure: "Für SMTP-Verbindungen implizit SSL/TLS verwenden" smtpSecure: "Für SMTP-Verbindungen implizit SSL/TLS verwenden"
smtpSecureInfo: "Schalte dies aus, falls du STARTTLS verwendest." smtpSecureInfo: "Schalte dies aus, falls du STARTTLS verwendest"
testEmail: "Emailversand testen" testEmail: "Emailversand testen"
wordMute: "Wortstummschaltung" wordMute: "Wortstummschaltung"
regexpError: "Fehler in einem regulären Ausdruck" regexpError: "Fehler in einem regulären Ausdruck"
@ -705,7 +703,7 @@ defaultNavigationBehaviour: "Standardnavigationsverhalten"
editTheseSettingsMayBreakAccount: "Bei Bearbeitung dieser Einstellungen besteht die\ editTheseSettingsMayBreakAccount: "Bei Bearbeitung dieser Einstellungen besteht die\
\ Gefahr, dein Benutzerkonto zu beschädigen." \ Gefahr, dein Benutzerkonto zu beschädigen."
instanceTicker: "Instanz-Informationen von Notizen" instanceTicker: "Instanz-Informationen von Notizen"
waitingFor: "Warte auf {x}" waitingFor: "Warte auf {x}"
random: "Zufällig" random: "Zufällig"
system: "System" system: "System"
switchUi: "Layout" switchUi: "Layout"
@ -810,7 +808,7 @@ emailNotification: "Email-Benachrichtigungen"
publish: "Veröffentlichen" publish: "Veröffentlichen"
inChannelSearch: "In Kanal suchen" inChannelSearch: "In Kanal suchen"
useReactionPickerForContextMenu: "Reaktionsauswahl durch Rechtsklick öffnen" useReactionPickerForContextMenu: "Reaktionsauswahl durch Rechtsklick öffnen"
typingUsers: "{users} ist/sind am schreiben" typingUsers: "{users} ist/sind am schreiben"
jumpToSpecifiedDate: "Zu bestimmtem Datum springen" jumpToSpecifiedDate: "Zu bestimmtem Datum springen"
showingPastTimeline: "Es wird eine alte Chronik angezeigt" showingPastTimeline: "Es wird eine alte Chronik angezeigt"
clear: "Zurückkehren" clear: "Zurückkehren"
@ -876,11 +874,11 @@ hashtags: "Hashtags"
troubleshooting: "Problembehandlung" troubleshooting: "Problembehandlung"
useBlurEffect: "Weichzeichnungseffekt in der Benutzeroberfläche verwenden" useBlurEffect: "Weichzeichnungseffekt in der Benutzeroberfläche verwenden"
learnMore: "Mehr erfahren" learnMore: "Mehr erfahren"
misskeyUpdated: "Misskey wurde aktualisiert!" misskeyUpdated: "Calckey wurde aktualisiert!"
whatIsNew: "Änderungen anzeigen" whatIsNew: "Änderungen anzeigen"
translate: "Übersetzen" translate: "Übersetzen"
translatedFrom: "Aus {x} übersetzt" translatedFrom: "Aus {x} übersetzt"
accountDeletionInProgress: "Die Löschung deines Benutzerkontos ist momentan in Bearbeitung." accountDeletionInProgress: "Die Löschung deines Benutzerkontos ist momentan in Bearbeitung"
usernameInfo: "Ein Name, durch den dein Benutzerkonto auf diesem Server identifiziert\ usernameInfo: "Ein Name, durch den dein Benutzerkonto auf diesem Server identifiziert\
\ werden kann. Du kannst das Alphabet (a~z, A~Z), Ziffern (0~9) oder Unterstriche\ \ werden kann. Du kannst das Alphabet (a~z, A~Z), Ziffern (0~9) oder Unterstriche\
\ (_) verwenden. Benutzernamen können später nicht geändert werden." \ (_) verwenden. Benutzernamen können später nicht geändert werden."
@ -967,7 +965,7 @@ statusbar: "Statusleiste"
pleaseSelect: "Wähle eine Option" pleaseSelect: "Wähle eine Option"
reverse: "Umkehren" reverse: "Umkehren"
colored: "Farbig" colored: "Farbig"
refreshInterval: "Aktualisierungsrate" refreshInterval: "Aktualisierungsrate "
label: "Beschriftung" label: "Beschriftung"
type: "Art" type: "Art"
speed: "Geschwindigkeit" speed: "Geschwindigkeit"
@ -1079,7 +1077,7 @@ _preferencesBackups:
createdAt: "Erstellt am: {date} {time}" createdAt: "Erstellt am: {date} {time}"
updatedAt: "Aktualisiert am: {date} {time}" updatedAt: "Aktualisiert am: {date} {time}"
cannotLoad: "Laden fehlgeschlagen" cannotLoad: "Laden fehlgeschlagen"
invalidFile: "Ungültiges Dateiformat." invalidFile: "Ungültiges Dateiformat"
_registry: _registry:
scope: "Scope" scope: "Scope"
key: "Schlüssel" key: "Schlüssel"
@ -1087,13 +1085,13 @@ _registry:
domain: "Domain" domain: "Domain"
createKey: "Schlüssel erstellen" createKey: "Schlüssel erstellen"
_aboutMisskey: _aboutMisskey:
about: "Misskey ist Open-Source-Software, welche von syuilo seit 2014 entwickelt\ about: "Calckey ist ein Fork von Misskey, der seit 2022 von ThatOneCalculator entwickelt\
\ wird." \ wird."
contributors: "Hauptmitwirkende" contributors: "Hauptmitwirkende"
allContributors: "Alle Mitwirkenden" allContributors: "Alle Mitwirkenden"
source: "Quellcode" source: "Quellcode"
translation: "Misskey übersetzen" translation: "Calckey übersetzen"
donate: "An Misskey spenden" donate: "An Calckey spenden"
morePatrons: "Wir schätzen ebenso die Unterstützung vieler anderer hier nicht gelisteter\ morePatrons: "Wir schätzen ebenso die Unterstützung vieler anderer hier nicht gelisteter\
\ Personen sehr. Danke! \U0001F970" \ Personen sehr. Danke! \U0001F970"
patrons: "UnterstützerInnen" patrons: "UnterstützerInnen"
@ -1106,7 +1104,7 @@ _mfm:
intro: "MFM ist eine Misskey-exklusive Markup-Sprache, die in Misskey an vielen\ intro: "MFM ist eine Misskey-exklusive Markup-Sprache, die in Misskey an vielen\
\ Stellen verwendet werden kann. Hier kannst du eine Liste von verfügbarer MFM-Syntax\ \ Stellen verwendet werden kann. Hier kannst du eine Liste von verfügbarer MFM-Syntax\
\ einsehen." \ einsehen."
dummy: "Misskey erweitert die Welt des Fediverse" dummy: "Calckey erweitert die Welt des Fediverse"
mention: "Erwähnung" mention: "Erwähnung"
mentionDescription: "Mit At-Zeichen und Benutzername kann ein individueller Nutzer\ mentionDescription: "Mit At-Zeichen und Benutzername kann ein individueller Nutzer\
\ angegeben werden." \ angegeben werden."
@ -1128,9 +1126,9 @@ _mfm:
blockCodeDescription: "Syntax-Hervorhebung für mehrzeiligen (Programm-)Code als\ blockCodeDescription: "Syntax-Hervorhebung für mehrzeiligen (Programm-)Code als\
\ Block anzeigen." \ Block anzeigen."
inlineMath: "Mathe (Eingebettet)" inlineMath: "Mathe (Eingebettet)"
inlineMathDescription: "Mathematische Formeln (KaTeX) eingebettet anzeigen." inlineMathDescription: "Mathematische Formeln (KaTeX) eingebettet anzeigen"
blockMath: "Mathe (Block)" blockMath: "Mathe (Block)"
blockMathDescription: "Mehrzeilige mathematische Formeln (KaTeX) als Block einbetten." blockMathDescription: "Mathematische Formeln (KaTeX) als Block einbetten"
quote: "Zitationen" quote: "Zitationen"
quoteDescription: "Inhalt als Zitat anzeigen." quoteDescription: "Inhalt als Zitat anzeigen."
emoji: "Benutzerdefinierte Emojis" emoji: "Benutzerdefinierte Emojis"
@ -1143,7 +1141,7 @@ _mfm:
jelly: "Animation (Dehnen)" jelly: "Animation (Dehnen)"
jellyDescription: "Verleiht Inhalt eine sich dehnende Animation." jellyDescription: "Verleiht Inhalt eine sich dehnende Animation."
tada: "Animation (Tada)" tada: "Animation (Tada)"
tadaDescription: "Verleiht Inhalt eine Animation mit \"Tada!\"-Gefühl" tadaDescription: "Verleiht Inhalt eine Animation mit \"Tada!\"-Gefühl."
jump: "Animation (Sprung)" jump: "Animation (Sprung)"
jumpDescription: "Verleiht Inhalt eine springende Animation." jumpDescription: "Verleiht Inhalt eine springende Animation."
bounce: "Animation (Federn)" bounce: "Animation (Federn)"
@ -1325,14 +1323,18 @@ _tutorial:
\ erkennen, ob sie deine Notizen sehen oder dir folgen wollen." \ erkennen, ob sie deine Notizen sehen oder dir folgen wollen."
step3_1: "Jetzt ist es Zeit, einigen Leuten zu folgen!" step3_1: "Jetzt ist es Zeit, einigen Leuten zu folgen!"
step3_2: "Deine Home- und Social-Timeline basiert darauf, wem du folgst, also folge\ step3_2: "Deine Home- und Social-Timeline basiert darauf, wem du folgst, also folge\
\ für den Anfang ein paar Accounts." \ für den Anfang ein paar Accounts.\nKlicke das Plus Symbol oben links in einem\
\ Profil um es zu folgen."
step4_1: "Wir bringen dich nach draußen." step4_1: "Wir bringen dich nach draußen."
step4_2: "Für deinen ersten Beitrag machen manche Leute gerne einen {introduction}\ step4_2: "Für deinen ersten Beitrag machen manche Leute gerne einen {introduction}\
\ Beitrag oder ein einfaches \"Hallo Welt!\"" \ Beitrag oder ein einfaches \"Hallo Welt!\""
step5_1: "Timelines, Timelines überall!" step5_1: "Timelines, Timelines überall!"
step5_2: "Deine Instanz hat {Zeitleisten} verschiedene Zeitleisten aktiviert." step5_2: "Deine Instanz hat {Zeitleisten} verschiedene Zeitleisten aktiviert."
step5_3: "Die Zeitleiste Home {icon} ist die Zeitleiste, in der du die Beiträge\ step5_3: "Die Zeitleiste Home {icon} ist die Zeitleiste, in der du die Beiträge\
\ deiner Follower sehen kannst." \ der Accounts sehen kannst, denen du folgst und von jedem anderen auf dieser\
\ Instanz. Solltest du bevorzugen, dass deine Home Zeitleiste nur Beiträge von\
\ den Accounts enthält, denen du folgst, kannst du das ganz einfach in den Einstellungen\
\ ändern!"
step5_4: "In der lokalen {Icon} Zeitleiste kannst du die Beiträge aller anderen\ step5_4: "In der lokalen {Icon} Zeitleiste kannst du die Beiträge aller anderen\
\ Mitglieder dieser Instanz sehen." \ Mitglieder dieser Instanz sehen."
step5_5: "In der Zeitleiste Empfohlen {icon} kannst du Beiträge von Instanzen sehen,\ step5_5: "In der Zeitleiste Empfohlen {icon} kannst du Beiträge von Instanzen sehen,\
@ -1486,7 +1488,7 @@ _visibility:
_postForm: _postForm:
replyPlaceholder: "Dieser Notiz antworten …" replyPlaceholder: "Dieser Notiz antworten …"
quotePlaceholder: "Diese Notiz zitieren …" quotePlaceholder: "Diese Notiz zitieren …"
channelPlaceholder: "In einen Kanal senden" channelPlaceholder: "In einen Kanal senden..."
_placeholders: _placeholders:
a: "Was machst du momentan?" a: "Was machst du momentan?"
b: "Was ist um dich herum los?" b: "Was ist um dich herum los?"
@ -1535,7 +1537,7 @@ _instanceCharts:
usersTotal: "Gesamtanzahl an Benutzern" usersTotal: "Gesamtanzahl an Benutzern"
notes: "Unterschied in der Anzahl an Notizen" notes: "Unterschied in der Anzahl an Notizen"
notesTotal: "Gesamtanzahl an Notizen" notesTotal: "Gesamtanzahl an Notizen"
ff: "Unterschied in der Anzahl an gefolgten Benutzern und Followern" ff: "Unterschied in der Anzahl an gefolgten Benutzern und Followern "
ffTotal: "Gesamtanzahl an gefolgten Benutzern und Followern" ffTotal: "Gesamtanzahl an gefolgten Benutzern und Followern"
cacheSize: "Unterschied in der Größe des Caches" cacheSize: "Unterschied in der Größe des Caches"
cacheSizeTotal: "Gesamtgröße des Caches" cacheSizeTotal: "Gesamtgröße des Caches"
@ -1851,7 +1853,7 @@ _notification:
youGotMessagingMessageFromUser: "{name} hat dir eine Chatnachricht gesendet" youGotMessagingMessageFromUser: "{name} hat dir eine Chatnachricht gesendet"
youGotMessagingMessageFromGroup: "In die Gruppe {name} wurde eine Chatnachricht\ youGotMessagingMessageFromGroup: "In die Gruppe {name} wurde eine Chatnachricht\
\ gesendet" \ gesendet"
youWereFollowed: "ist dir gefolgt" youWereFollowed: "folgt dir nun"
youReceivedFollowRequest: "Du hast eine Follow-Anfrage erhalten" youReceivedFollowRequest: "Du hast eine Follow-Anfrage erhalten"
yourFollowRequestAccepted: "Deine Follow-Anfrage wurde akzeptiert" yourFollowRequestAccepted: "Deine Follow-Anfrage wurde akzeptiert"
youWereInvitedToGroup: "{userName} hat dich in eine Gruppe eingeladen" youWereInvitedToGroup: "{userName} hat dich in eine Gruppe eingeladen"
@ -1914,7 +1916,8 @@ flagSpeakAsCat: Wie eine Katze sprechen
showEmojisInReactionNotifications: Emojis in Reaktionsbenachrichtigungen anzeigen showEmojisInReactionNotifications: Emojis in Reaktionsbenachrichtigungen anzeigen
userSaysSomethingReason: '{name} sagte {reason}' userSaysSomethingReason: '{name} sagte {reason}'
hiddenTagsDescription: 'Liste die Hashtags (ohne #) welche du von Trending und Explore hiddenTagsDescription: 'Liste die Hashtags (ohne #) welche du von Trending und Explore
verstecken möchtest. Versteckte Hashtags sind durch andere Wege weiterhin auffindbar.' verstecken möchtest. Versteckte Hashtags sind durch andere Wege weiterhin auffindbar.
Blockierte Instanzen sind nicht betroffen, auch wenn sie hier aufgeführt sind.'
addInstance: Instanz hinzufügen addInstance: Instanz hinzufügen
flagSpeakAsCatDescription: Deine Posts werden im Katzenmodus "nya-ifiziert" flagSpeakAsCatDescription: Deine Posts werden im Katzenmodus "nya-ifiziert"
hiddenTags: Versteckte Hashtags hiddenTags: Versteckte Hashtags
@ -1927,3 +1930,13 @@ privateModeInfo: Wenn diese Option aktiviert ist, können nur Instanzen auf der
mit Deinen Instanzen föderieren. Alle Beiträge werden für die Öffentlichkeit verborgen. mit Deinen Instanzen föderieren. Alle Beiträge werden für die Öffentlichkeit verborgen.
allowedInstances: Instanzen auf der Whitelist allowedInstances: Instanzen auf der Whitelist
selectInstance: Wähle eine Instanz selectInstance: Wähle eine Instanz
silencedInstancesDescription: Liste die Hostnamen der Instanzen auf, die du stummschalten
möchtest. Konten in den aufgelisteten Instanzen werden als "Stumm" behandelt, können
nur Follow-Anfragen stellen und können keine lokalen Konten erwähnen, wenn sie nicht
gefolgt werden. Dies wirkt sich nicht auf die blockierten Instanzen aus.
editNote: Notiz bearbeiten
edited: Bearbeitet
silenceThisInstance: Diese Instanz stummschalten
silencedInstances: Stummgeschaltete Instanzen
silenced: Stummgeschaltet
deleted: Gelöscht

View File

@ -46,9 +46,12 @@ unpin: "Unpin from profile"
copyContent: "Copy contents" copyContent: "Copy contents"
copyLink: "Copy link" copyLink: "Copy link"
delete: "Delete" delete: "Delete"
deleted: "Deleted"
deleteAndEdit: "Delete and edit" deleteAndEdit: "Delete and edit"
deleteAndEditConfirm: "Are you sure you want to delete this post and edit it? You\ deleteAndEditConfirm: "Are you sure you want to delete this post and edit it? You\
\ will lose all reactions, boosts and replies to it." \ will lose all reactions, boosts and replies to it."
editNote: "Edit note"
edited: "Edited"
addToList: "Add to list" addToList: "Add to list"
sendMessage: "Send a message" sendMessage: "Send a message"
copyUsername: "Copy username" copyUsername: "Copy username"
@ -68,8 +71,8 @@ import: "Import"
export: "Export" export: "Export"
files: "Files" files: "Files"
download: "Download" download: "Download"
driveFileDeleteConfirm: "Are you sure you want to delete the file \"{name}\"? It\ driveFileDeleteConfirm: "Are you sure you want to delete the file \"{name}\"? It will\
\ will be removed from all posts that contain it as an attachment." \ be removed from all posts that contain it as an attachment."
unfollowConfirm: "Are you sure that you want to unfollow {name}?" unfollowConfirm: "Are you sure that you want to unfollow {name}?"
exportRequested: "You've requested an export. This may take a while. It will be added\ exportRequested: "You've requested an export. This may take a while. It will be added\
\ to your Drive once completed." \ to your Drive once completed."
@ -221,7 +224,9 @@ blockedInstancesDescription: "List the hostnames of the instances that you want
\ block. Listed instances will no longer be able to communicate with this instance." \ block. Listed instances will no longer be able to communicate with this instance."
silencedInstances: "Silenced Instances" silencedInstances: "Silenced Instances"
silencedInstancesDescription: "List the hostnames of the instances that you want to\ silencedInstancesDescription: "List the hostnames of the instances that you want to\
\ silence. Accounts in the listed instances are treated as \"Silenced\", can only make follow requests, and cannot mention local accounts if not followed. This will not affect the blocked instances." \ silence. Accounts in the listed instances are treated as \"Silenced\", can only\
\ make follow requests, and cannot mention local accounts if not followed. This\
\ will not affect the blocked instances."
hiddenTags: "Hidden Hashtags" hiddenTags: "Hidden Hashtags"
hiddenTagsDescription: "List the hashtags (without the #) of the hashtags you wish\ hiddenTagsDescription: "List the hashtags (without the #) of the hashtags you wish\
\ to hide from trending and explore. Hidden hashtags are still discoverable via\ \ to hide from trending and explore. Hidden hashtags are still discoverable via\
@ -1405,12 +1410,12 @@ _tutorial:
step2_1: "First, please fill out your profile." step2_1: "First, please fill out your profile."
step2_2: "Providing some information about who you are will make it easier for others\ step2_2: "Providing some information about who you are will make it easier for others\
\ to tell if they want to see your posts or follow you." \ to tell if they want to see your posts or follow you."
step3_1: "Now time to follow some people!" step3_1: "Now it's time to follow some people!"
step3_2: "Your home and social timelines are based off of who you follow, so try\ step3_2: "Your home and social timelines are based off of who you follow, so try\
\ following a couple accounts to get started.\nClick the plus circle on the top\ \ following a couple accounts to get started.\nClick the plus circle on the top\
\ right of a profile to follow them." \ right of a profile to follow them."
step4_1: "Let's get you out there." step4_1: "Let's get you out there."
step4_2: "For your first post, some people like to made a {introduction} post or\ step4_2: "For your first post, some people like to make an {introduction} post or\
\ a simple \"Hello world!\"" \ a simple \"Hello world!\""
step5_1: "Timelines, timelines everywhere!" step5_1: "Timelines, timelines everywhere!"
step5_2: "Your instance has {timelines} different timelines enabled." step5_2: "Your instance has {timelines} different timelines enabled."

View File

@ -75,8 +75,8 @@ files: Tiedostot
download: Lataa download: Lataa
unfollowConfirm: Oletko varma, ettet halua seurata enää käyttäjää {name}? unfollowConfirm: Oletko varma, ettet halua seurata enää käyttäjää {name}?
noLists: Sinulla ei ole listoja noLists: Sinulla ei ole listoja
note: Lähetys note: Viesti
notes: Lähetykset notes: Viestit
following: Seuraa following: Seuraa
createList: Luo lista createList: Luo lista
manageLists: Hallitse listoja manageLists: Hallitse listoja
@ -221,3 +221,599 @@ clearQueueConfirmText: Mitkään välittämättömät lähetykset, jotka ovat jo
federoidu. Yleensä tätä toimintoa ei tarvita. federoidu. Yleensä tätä toimintoa ei tarvita.
blockedInstancesDescription: Lista instanssien isäntänimistä, jotka haluat estää. blockedInstancesDescription: Lista instanssien isäntänimistä, jotka haluat estää.
Listatut instanssit eivät kykene kommunikoimaan enää tämän instanssin kanssa. Listatut instanssit eivät kykene kommunikoimaan enää tämän instanssin kanssa.
security: Turvallisuus
retypedNotMatch: Syöte ei kelpaa.
fromDrive: Asemasta
keepOriginalUploading: Säilytä alkuperäinen kuva
uploadFromUrlDescription: Tiedoston URL, jonka haluat ylösladata
themeForLightMode: Teema vaaleassa tilassa
theme: Teemat
themeForDarkMode: Teema tummassa tilassa
drive: Asema
darkThemes: Tummat teemat
copyUrl: Kopioi URL-linkki
rename: Uudelleennimeä
maintainerName: Ylläpitäjä
maintainerEmail: Ylläpitäjän sähköposti
tosUrl: Palvelun ehdot URL-linkki
thisYear: Vuosi
backgroundImageUrl: Taustakuvan URL-linkki
basicInfo: Perustiedot
pinnedPagesDescription: Kirjoita niiden sivujen polut, jotka haluat liittää tämän
instanssin yläsivulle rivinvaihdoin erotettuna.
hcaptchaSiteKey: Sivuston avain
hcaptchaSecretKey: Salausavain
silencedInstances: Hiljennetyt instanssit
muteAndBlock: Hiljennykset ja estetyt
mutedUsers: Hiljennetyt käyttäjät
blockedUsers: Estetyt käyttäjät
noUsers: Ei yhtään käyttäjää
noInstances: Ei yhtään instanssia
editProfile: Muokkaa profiilia
noteDeleteConfirm: Oletko varma, että haluat poistaa tämän viestin?
pinLimitExceeded: Et voi kiinnittää enempää viestejä
intro: Calckey -asennus valmis! Ole hyvä ja luo admin-käyttäjä.
done: Valmis
processing: Suorittaa...
preview: Esikatselu
default: Oletus
defaultValueIs: 'Oletus: {value}'
noCustomEmojis: Ei emojia
noJobs: Ei töitä
federating: Federoi
blocked: Estetty
silenced: Hiljennetty
suspended: Keskeytetty
all: Kaikki
publishing: Julkaisee
subscribing: Tilaa
notResponding: Ei vastaa
instanceFollowing: Seuraa instanssia
instanceFollowers: Instanssin seuraajat
instanceUsers: Instanssin käyttäjät
changePassword: Muuta salasana
newPasswordRetype: Uudelleensyötä uusi salasana
more: Lisää!
featured: Esillä
usernameOrUserId: Käyttäjänimi tai käyttäjä id
noSuchUser: Käyttäjää ei löydy
lookup: Hae
announcements: Tiedoitteet
imageUrl: Kuva URL-linkki
removed: Onnistuneesti poistettu
removeAreYouSure: Oletko varma, että haluat poistaa " {x}"?
resetAreYouSure: Haluatko nollata?
saved: Tallennettu
messaging: Juttele
upload: Lataa ylös
fromUrl: URL:stä
uploadFromUrl: Ylöslataa URL:stä
uploadFromUrlRequested: Ylöslataus pyydetty
uploadFromUrlMayTakeTime: Voi viedä hetki, kun ylöslataus on valmis.
explore: Tutustu
messageRead: Lue
noMoreHistory: Ei lisää historiaa
startMessaging: Aloita uusi juttelu
manageGroups: Hallitse ryhmiä
nUsersRead: lukenut {n}
agreeTo: Hyväksyn {0}
tos: Palvelun ehdot
start: Aloita
home: Koti
remoteUserCaution: Etäkäyttäjän tiedot saattavat olla puutteellisia.
light: Vaalea
dark: Tumma
lightThemes: Vaaleat teemat
syncDeviceDarkMode: Synkronoi tumma tila laitteen asetuksen mukaan
fileName: Tiedostonimi
selectFile: Valitse tiedosto
selectFiles: Valitse tiedostot
selectFolder: Valitse kansio
selectFolders: Valitse kansiot
renameFile: Uudelleennimeä tiedosto
folderName: Kansionimi
createFolder: Luo kansio
renameFolder: Uudelleennimeä kansio
deleteFolder: Poista kansio
addFile: Lisää tiedosto
emptyDrive: Asemasi on tyhjä
emptyFolder: Tämä kansio on tyhjä
unableToDelete: Ei voitu poistaa
inputNewFileName: Syötä uusi tiedostonimi
inputNewDescription: Syötä uusi kuvateksti
inputNewFolderName: Syötä uusi kansionimi
hasChildFilesOrFolders: Koska kansio ei ole tyhjä, sitä ei voi poistaa.
avatar: Kuvake
banner: Banneri
nsfw: Herkkää sisältöä (NSFW)
whenServerDisconnected: Kun yhteys palvelimeen menetetään
disconnectedFromServer: Yhteys palvelimeen katkennut
reload: Päivitä
doNothing: Hylkää
reloadConfirm: Haluaisitko päivittää aikajanan?
unwatch: Lopeta katselu
watch: Katsele
accept: Hyväksy
reject: Hylkää
normal: Normaali
instanceName: Instanssin nimi
thisMonth: Kuukausi
today: Tänään
monthX: '{month}'
connectService: Yhdistä
disconnectService: Katkaise yhteys
enableLocalTimeline: Ota käyttöön paikallinen aikajana
enableGlobalTimeline: Ota käyttöön globaali aikajana
enableRecommendedTimeline: Ota käyttöön suositellut -aikajana
registration: Rekisteröinti
enableRegistration: Ota käyttöön uuden käyttäjän rekisteröinti
driveCapacityPerLocalAccount: Aseman kapasiteetti paikallista käyttäjää kohti
driveCapacityPerRemoteAccount: Aseman kapasiteetti etäkäyttäjää kohti
inMb: megatavuissa
bannerUrl: Bannerikuvan URL-linkki
pinnedUsers: Kiinnitetyt käyttäjät
pinnedPages: Kiinnitetyt sivut
pinnedClipId: Kiinnitettävän leikkeen ID
enableHcaptcha: Ota käyttöön hCaptcha-tunnistus
recaptcha: CAPTCHA uudelleen
enableRecaptcha: Ota käyttöön CAPTCHA uudelleen
recaptchaSiteKey: Sivuston avain
recaptchaSecretKey: Salausavain
silenceThisInstance: Hiljennä tämä instanssi
silencedInstancesDescription: Lista isäntänimistä, joka haluat hiljentää. Tilejä listassa
kohdellaan "hiljennettynä", ne voivat tehdä seuraajapyyntöjä ja eivät voi tehdä
mainintoja paikallistileistä jossei seurattu. Tämä ei vaikuta estettyihin instansseihin.
hiddenTagsDescription: 'Listaa aihetunnisteet (ilman #-merkkiä) aihetunnisteet, jotka
haluat piilottaa trendaavista ja Tutustu-osiosta. Piilotetut aihetunnisteet ovat
kuitenkin löydettävissä muilla keinoilla. Estetyt instanssit eivät vaikuta, vaikka
listattu tähän.'
currentPassword: Nykyinen salasana
newPassword: Uusi salasana
attachFile: Liitetyt tiedostot
keepOriginalUploadingDescription: Tallentaa alkuperäisen kuvan sellaisenaan. Jos kytketty
päältä, webissä näytettävä versio luodaan ylöslatauksen yhteydessä.
remove: Poista
circularReferenceFolder: Kohdekansio on kansion alikansio, jonka haluat siirtää.
deleteAreYouSure: Oletko varma, että haluat poistaa kokonaan" {x}"?
yearsOld: '{age} vuotias'
activity: Aktiivisuus
images: Kuvat
birthday: Syntymäpäivä
registeredDate: Liittynyt
location: Sijainti
disablingTimelinesInfo: Järjestelmänvalvojilla ja moderaattoreilla on aina pääsy kaikille
aikajanoille, vaikka olisikin poistettu käytöstä.
dayX: '{day}'
yearX: '{year}'
pages: Sivut
integration: Integraatiot
instanceDescription: Instanssin kuvaus
invite: Kutsu
iconUrl: Ikoni URL-linkki
pinnedUsersDescription: Listaa käyttäjänimet eroteltuna rivivaihdoin kiinnittääksesi
ne "Tutustu" välilehteen.
pinnedNotes: Kiinnitetyt viestit
hcaptcha: hCaptcha-tunnistus
antennaSource: Antennin lähde
invitationCode: Kutsukoodi
checking: Tarkistetaan...
passwordNotMatched: Ei vastaa
doing: Käsittelee...
category: Kategoria
tags: Tagit
disableAnimatedMfm: Poista MFM -animaatiot käytöstä
openImageInNewTab: Avaa kuvat uuteen välilehteen
dashboard: Kojelauta
local: Paikallinen
remote: Etä
total: Yhteensä
weekOverWeekChanges: Muutokset viime viikkoon
objectStorageRegion: Alue
popout: Ulosvedettävä
volume: Äänenvoimakkuus
masterVolume: Master äänenvoimakkuus
details: Yksityiskohdat
chooseEmoji: Valitse emoji
descendingOrder: Laskevasti
scratchpad: Raaputusalusta
output: Ulostulo
invisibleNote: Näkymätön viesti
enableInfiniteScroll: Lataa enemmän automaattisesti
visibility: Näkyvyys
useCw: Piilota sisältö
poll: Kysely
enablePlayer: Avaa videotoistimeen
enterFileDescription: Syötä tiedostokuvaus
author: Kirjoittaja
manage: Hallinta
description: Kuvaus
describeFile: Lisää tiedostokuvaus
height: Korkeus
large: Suuri
medium: Keskikokoinen
small: Pieni
other: Muu
create: Luo
regenerateLoginTokenDescription: Luo uudelleen kirjautumisen aikana sisäisesti käytettävän
tunnuksen. Normaalisti tämä toiminto ei ole tarpeen. Jos tunniste luodaan uudelleen,
kaikki laitteet kirjautuvat ulos.
setMultipleBySeparatingWithSpace: Erottele useat merkinnät välilyönneillä.
fileIdOrUrl: Tiedosto ID tai URL-linkki
behavior: Käytös
instanceTicker: Viestejä koskevat instanssitiedot
waitingFor: Odottaa {x}
random: Satunnainen
system: Järjestelmä
switchUi: Ulkoasu
createNew: Luo uusi
followersCount: Seuraajien määrä
renotedCount: Saatujen buustausten määrä
followingCount: Seurattujen tilien määrä
notSet: Ei asetettu
nUsers: '{n} Käyttäjää'
nNotes: '{n} Viestiä'
sendErrorReports: Lähetä virheraportteja
backgroundColor: Taustaväri
accentColor: Korostusväri
textColor: Tekstin väri
advanced: Edistynyt
saveAs: Tallenna nimellä...
invalidValue: Epäkelpo arvo.
registry: Rekisteri
closeAccount: Sulje tili
currentVersion: Nykyinen versio
capacity: Kapasiteetti
clear: Palaa
_theme:
explore: Tutustu teemoihin
silenceConfirm: Oletko varma, että haluat hiljentää tämän käyttäjän?
notesAndReplies: Viestit ja vastaukset
withFiles: Tiedostot sisältyvät
silence: Hiljennä
popularTags: Suositut tagit
userList: Listat
about: Tietoja
aboutMisskey: Tietoja Calckeystä
exploreFediverse: Tutustu fediverseen
recentlyUpdatedUsers: Vastikään lisätyt käyttäjät
recentlyRegisteredUsers: Uudet liittyneet jäyttäjät
recentlyDiscoveredUsers: Vastikään löydetyt käyttäjät
exploreUsersCount: Täällä on {count} käyttäjää
share: Jaa
moderation: Sisällön valvonta
nUsersMentioned: Mainittu {n} käyttäjältä
securityKey: Turva-avain
securityKeyName: Avainnimi
registerSecurityKey: Rekisteröi turva-avain
lastUsed: Viimeksi käytetty
unregister: Poista rekisteröinti
passwordLessLogin: Salasanaton sisäänkirjautuminen
cacheClear: Tyhjennä välimuisti
markAsReadAllNotifications: Merkitse kaikki ilmoitukset luetuksi
markAsReadAllUnreadNotes: Merkitse kaikki viestit luetuiksi
uploadFolder: Oletuskansio ylöslatauksille
createGroup: Luo ryhmä
group: Ryhmä
groups: Ryhmät
ownedGroups: Omistetut ryhmät
help: Apua
inputMessageHere: Syötä viesti tähän
close: Sulje
joinedGroups: Liittyneet ryhmät
invites: Kutsut
groupName: Ryhmänimi
members: Jäsenet
language: Kieli
signinHistory: Kirjautumishistoria
docSource: Tämän dokumentin lähde
createAccount: Luo tili
existingAccount: Olemassa oleva tili
promotion: Edistetty
promote: Edistää
numberOfDays: Päivien määrä
accountSettings: Tilin asetukset
objectStorage: Objektitallennus
useObjectStorage: Käytä objektitallennusta
objectStorageBaseUrl: Perus URL-linkki
objectStorageBaseUrlDesc: "Viitteenä käytetty URL-linkki. Määritä CDN:n tai välityspalvelimen\
\ URL-linkki, jos käytät kumpaakin.\nKäytä S3:lle 'https://<bucket>.s3.amazonaws.com'\
\ ja GCS:lle tai vastaaville palveluille 'https://storage.googleapis.com/<bucket>'\
\ jne."
objectStorageBucket: Kauha
newNoteRecived: Uusia viestejä
smtpPort: Portti
instanceMute: Instanssin mykistys
repliesCount: Lähetettyjen vastausten määrä
updatedAt: Päivitetty
notFound: Ei löydy
useOsNativeEmojis: Käytä käyttöjärjestelmän natiivi-Emojia
joinOrCreateGroup: Tule kutsutuksi ryhmään tai luo oma ryhmä.
text: Teksti
usernameInvalidFormat: Käytä isoja ja pieniä kirjaimia, numeroita ja erikoismerkkejä.
unsilenceConfirm: Oletko varma, että haluat poistaa käyttäjän hiljennyksen?
popularUsers: Suositut käyttäjät
moderator: Moderaattori
twoStepAuthentication: Kaksivaiheinen tunnistus
notFoundDescription: URL-linkkiin liittyvää sivua ei löytynyt.
antennaKeywords: Kuunneltavat avainsanat
antennaExcludeKeywords: Poislasketut avainsanat
antennaKeywordsDescription: Erottele välilyönneillä AND-ehtoa varten tai rivinvaihdolla
OR-ehtoa varten.
notifyAntenna: Ilmoita uusista viesteistä
withFileAntenna: Vain viestit tiedoston kanssa
enableServiceworker: Ota käyttöön Push-notifikaatiot selaimessasi
antennaUsersDescription: Luettele yksi käyttäjänimi rivi kohti
antennaInstancesDescription: Luettele yksi instanssi riviä kohti
caseSensitive: Isot ja pienet kirjaimet
withReplies: Sisällytä vastaukset
connectedTo: Seuraavat tili(t) on yhdistetty
unsilence: Poista hiljennys
administrator: Järjestelmänvalvoja
token: Merkki
resetPassword: Resetoi salasana
reduceUiAnimation: Vähennä käyttöliittymän animaatioita
transfer: Siirrä
messagingWithUser: Yksityisjuttelu
title: Otsikko
enable: Ota käyttöön
next: Seuraava
retype: Syötä uudelleen
noteOf: Lähettänyt {user}
inviteToGroup: Kutsu ryhmään
quoteAttached: Lainaus
quoteQuestion: Liitä lainauksena?
noMessagesYet: Ei vielä viestejä
newMessageExists: Uusia viestejä
onlyOneFileCanBeAttached: Voit liittää vain yhden tiedoston viestiin
signinRequired: Ole hyvä ja rekisteröidy tai kirjaudu sisään jatkaaksesi
invitations: Kutsut
available: Saatavilla
unavailable: Ei saatavissa
tooShort: Liian lyhyt
tooLong: Liian pitkä
weakPassword: Heikko salasana
normalPassword: Kohtalainen salasana
strongPassword: Vahva salasana
passwordMatched: Vastaa
signinWith: Kirjaudu sisään {x}
signinFailed: Ei voitu kirjautua sisään. Annettu käyttäjänimi tai salasana virheellinen.
tapSecurityKey: Napsauta turva-avaintasi
or: Tai
uiLanguage: Anna käyttöliittymän kieli
groupInvited: Sinut on kutsuttu ryhmään
aboutX: Tietoja {x}
disableDrawer: Älä käytä laatikkotyyppisiä valikoita
youHaveNoGroups: Sinulla ei ole ryhmiä
noHistory: Ei historiaa saatavilla
regenerate: Uudelleenluo
fontSize: Kirjasinkoko
dayOverDayChanges: Muutokset eiliseen
clientSettings: Asiakkaan asetukset
hideThisNote: Piilota tämä viesti
showFeaturedNotesInTimeline: Näytä esillä olevat viestit aikajanalla
objectStorageBucketDesc: Määritä palveluntarjoajasi käyttämä kauhan nimi.
objectStoragePrefix: Etuliite
objectStorageEndpoint: Päätepiste
objectStorageRegionDesc: Määritä alue, kuten "xx-east-1". Jos palvelusi ei tee eroa
alueiden välillä, jätä tämä kohta tyhjäksi tai kirjoita "us-east-1".
objectStorageUseSSL: Käytä SSL-salausta
objectStorageUseSSLDesc: Poista tämä käytöstä, jos et aio käyttää HTTPS:ää API-yhteyksissä
objectStorageUseProxy: Yhdistä välityspalvelimen kautta
objectStorageUseProxyDesc: Poista tämä käytöstä, jos et aio käyttää välityspalvelinta
API-yhteyksiä varten
objectStorageSetPublicRead: Aseta "public-read" ylöslataukseen
serverLogs: Palvelimen lokit
deleteAll: Poista kaikki
showFixedPostForm: Näytä viesti-ikkuna aikajanan yläpuolella
sounds: Äänet
listen: Kuuntele
none: Ei mitään
showInPage: Näytä sivulla
recentUsed: Vastikään käytetty
install: Asenna
uninstall: Poista asennus
installedApps: Hyväksytyt sovellukset
nothing: Ei nähtävää täällä
state: Tila
sort: Järjestä
ascendingOrder: Nousevasti
scratchpadDescription: Raaputusalusta tarjoaa ympäristön AiScript-kokeiluja varten.
Voit kirjoittaa, suorittaa ja tarkistaa sen tulokset vuorovaikutuksessa siinä olevan
Calckeyn kanssa.
script: Skripti
disablePagesScript: Poista AiScript käytöstä sivuilla
updateRemoteUser: Päivitä etäkäyttäjän tiedot
deleteAllFiles: Poista kaikki tiedostot
deleteAllFilesConfirm: Oletko varma, että haluat poistaa kaikki tiedostot?
removeAllFollowing: Poista seuraaminen kaikista seuratuista käyttäjistä
removeAllFollowingDescription: Tämän suorittaminen poistaa kaikki {host}:n tilit.
Suorita tämä, jos instanssia ei esimerkiksi enää ole olemassa.
userSuspended: Tämä käyttäjä on hyllytetty.
userSilenced: Tämä käyttäjä on hiljennetty.
yourAccountSuspendedTitle: Tämä tili on hyllytetty
yourAccountSuspendedDescription: Tämä tili on hyllytetty palvelimen palveluehtojen
tai vastaavien rikkomisen vuoksi. Ota yhteyttä ylläpitäjään, jos haluat tietää tarkemman
syyn. Älä luo uutta tiliä.
menu: Valikko
divider: Jakaja
addItem: Lisää kohde
relays: Releet
addRelay: Lisää rele
inboxUrl: Saavuneen postin URL
addedRelays: Lisätyt releet
serviceworkerInfo: Pitää ottaa käyttöön Push-notifikaatioissa.
deletedNote: Poistetut viestit
disablePlayer: Sulje videotoistin
expandTweet: Laajenna twiittiä
themeEditor: Teemaeditori
leaveConfirm: Tallentamattomia muutoksia olemassa. Hylätäänkö ne?
plugins: Liitännäiset
preferencesBackups: Asetusten varmuuskopiot
deck: Kansi
undeck: Jätä kansi
useBlurEffectForModal: Käytä blur-efektiä modaaleissa
useFullReactionPicker: Käytä täysikokoista reaktiovalitsinta
width: Leveys
generateAccessToken: Luo käyttöoikeustunniste
enableAll: Ota käyttöön kaikki
disableAll: Poista käytöstä kaikki
tokenRequested: Myönnä oikeus tiliin
notificationType: Ilmoituksen tyyppi
edit: Muokkaa
emailServer: Sähköpostipalvelin
enableEmail: Ota sähköpostin jakelu käyttöön
emailConfigInfo: Käytetään vahvistamaan sähköpostiosoitteesi rekisteröitymisen yhteydessä
tai jos unohdat salasanasi
email: Sähköposti
smtpHost: Isäntä
smtpUser: Käyttäjänimi
smtpPass: Salasana
emptyToDisableSmtpAuth: Jätä käyttäjänimi ja salasana tyhjäksi ohittaaksesi SMTP verifioinnin
smtpSecureInfo: Kytke tämä päältä kun käytät STARTTLS
testEmail: Kokeile email-lähetystä
wordMute: Sanan hiljennys
regexpError: Säännöllinen lausekevirhe
userSaysSomething: '{name} sanoi jotakin'
userSaysSomethingReason: '{name} sanoi {reason}'
makeActive: Aktivoi
display: Näyttö
copy: Kopioi
metrics: Mittarit
overview: Yleiskatsaus
logs: Lokit
delayed: Viivästynyt
database: Tietokanta
channel: Kanavat
notificationSetting: Ilmoitusasetukset
notificationSettingDesc: Valitse näytettävät ilmoitustyypit.
useGlobalSetting: Käytä globaaleja asetuksia
regenerateLoginToken: Luo kirjautumistunniste uudelleen
sample: Näyte
abuseReports: Raportit
reportAbuse: Raportti
reportAbuseOf: Raportti {name}
fillAbuseReportDescription: Täytä tätä raporttia koskevat tiedot. Jos se koskee tiettyä
viestiä, ilmoita sen URL-linkki.
abuseReported: Raporttisi on lähetetty. Kiitoksia paljon.
reporter: Raportoija
reporteeOrigin: Ilmoittajan alkuperä
reporterOrigin: Raportoijan alkuperä
forwardReport: Välitä raportti etäinstanssille
forwardReportIsAnonymous: Tilisi sijasta anonyymi järjestelmätili näytetään toimittajana
etäinstanssissa.
send: Lähetä
abuseMarkAsResolved: Merkitse raportti ratkaistuksi
openInNewTab: Avaa uuteen välilehteen
openInSideView: Avaa sivunäkymään
defaultNavigationBehaviour: Navigoinnin oletuskäyttäytyminen
editTheseSettingsMayBreakAccount: Näiden asetusten muuttaminen voi vahingoittaa tiliäsi.
desktop: Työpöytä
clip: Leike
optional: Vaihtoehtoinen
createNewClip: Luo uusi leike
unclip: Poista leike
confirmToUnclipAlreadyClippedNote: Tämä viesti on jo osa "{name}"-leikettä. Haluatko
sen sijaan poistaa sen tästä leikkeestä?
manageAccessTokens: Hallitse käyttöoikeuskoodeja
accountInfo: Tilin tiedot
notesCount: Viestien määrä
renotesCount: Lähetettyjen buustausten määrä
repliedCount: Saatujen vastausten määrä
sentReactionsCount: Lähetettyjen reaktioiden määrä
receivedReactionsCount: Saatujen reaktioiden määrä
pollVotesCount: Lähetettyjen kyselyäänien määrä
pollVotedCount: Saatujen kyselyäänien määrä
yes: Kyllä
no: Ei
driveFilesCount: Tiedostojen määrä asemalla
driveUsage: Aseman tilankäyttö
noCrawle: Hylkää hakukoneindeksointi
noCrawleDescription: Pyydä hakukoneita olemaan indeksoimatta profiilisivuasi, viestejäsi,
sivujasi jne.
alwaysMarkSensitive: Merkitse oletusarvoisesti herkäksi sisällöksi (NSFW)
loadRawImages: Alkuperäisten kuvien lataaminen pikkukuvien näyttämisen sijaan
disableShowingAnimatedImages: Älä näytä animoituja kuvia
verificationEmailSent: Vahvistussähköposti on lähetetty. Seuraa mukana olevaa linkkiä
suorittaaksesi vahvistuksen loppuun.
emailVerified: Sähköposti on vahvistettu
noteFavoritesCount: Kirjanmerkittyjen viestien määrä
pageLikedCount: Saatujen Sivu-tykkäysten määrä
pageLikesCount: Sivut-tykkäysten määrä
contact: Yhteystieto
useSystemFont: Käytä järjestelmän oletuskirjasinta
clips: Leikkeet
experimentalFeatures: Kokeiluluontoiset ominaisuudet
developer: Kehittäjä
makeExplorable: Tee tili näkyväksi osiossa "Tutustu"
makeExplorableDescription: Jos otat tämän pois käytöstä, tilisi ei näy "Tutustu"-osiossa.
showGapBetweenNotesInTimeline: Näytä väli viestien välissä aikajanalla
duplicate: Monista
left: Vasen
center: Keskellä
wide: Leveä
narrow: Kapea
reloadToApplySetting: Asetus otetaan käyttöön vain uudelleenladattaessa. Ladataanko
uudelleen nyt?
showTitlebar: Näytä otsikkorivi
clearCache: Tyhjennä välimuisti
onlineUsersCount: '{n} käyttäjää online-tilassa'
myTheme: Minun teemani
value: Arvo
saveConfirm: Tallenna muutokset?
deleteConfirm: Poistetaanko tosiaan?
latestVersion: Uusin versio
newVersionOfClientAvailable: Asiakasohjelmiston uudempi versio saatavilla.
usageAmount: Käyttö
inUse: Käytetty
editCode: Muokkaa koodia
apply: Käytä
receiveAnnouncementFromInstance: Vastaanota ilmoituksia tästä instanssista
emailNotification: Sähköposti-ilmoitukset
publish: Julkaise
inChannelSearch: Etsi kanavalta
useReactionPickerForContextMenu: Avaa reaktiovalitsin napsauttamalla oikeaa
typingUsers: '{users} kirjoittaa'
jumpToSpecifiedDate: Hyppää tiettyyn päivään
markAllAsRead: Merkitse kaikki luetuksi
goBack: Takaisin
unlikeConfirm: Poistatko todella tykkäyksesi?
fullView: Täysi koko
quitFullView: Poistu täydestä koosta
addDescription: Lisää kuvaus
markAsReadAllTalkMessages: Merkitse kaikki yksityisviestit luetuiksi
appearance: Ulkonäkö
messagingWithGroup: Ryhmäjuttelu
newPasswordIs: Uusi salasana on "{password}"
noFollowRequests: Sinulla ei ole odottavia seuraajapyyntöjä
objectStoragePrefixDesc: Tiedostot tallennetaan hakemistoihin tällä etuliitteellä.
objectStorageEndpointDesc: Jätä tämä tyhjäksi, jos käytät AWS S3:a. Muuten määritä
päätepisteeksi '<host>' tai '<host>:<port>' käyttämästäsi palvelusta riippuen.
unableToProcess: Toimenpidettä ei voida suorittaa loppuun
installedDate: Hyväksynyt
lastUsedDate: Viimeksi käytetty
pluginTokenRequestedDescription: Tämä litännäinen voi käyttää tässä asetettuja käyttöoikeuksia.
permission: Oikeudet
smtpConfig: Lähtevän sähköpostin palvelimen (SMTP) asetukset
regexpErrorDescription: 'Säännöllisessä lausekkeessa tapahtui virhe rivillä {line}
sanan {tab} sanan mykistäminen rivillä {line}:'
emailAddress: Sähköpostiosoite
smtpSecure: Käytä implisiittistä SSL/TLS:ää SMTP-yhteyksissä
useGlobalSettingDesc: Jos se on päällä, käytetään tilisi ilmoitusasetuksia. Jos se
on pois päältä, voit tehdä yksilöllisiä asetuksia.
public: Julkinen
i18nInfo: Vapaaehtoiset kääntävät Calckeyta eri kielille. Voit auttaa osoitteessa
{link}.
lockedAccountInfo: Ellet aseta postauksen näkyvyydeksi "Vain seuraajille", postauksesi
näkyvät kaikille, vaikka vaatisitkin seuraajilta manuaalista hyväksyntää.
sendErrorReportsDescription: "Kun tämä on päällä, yksityiskohtaiset virhetiedot jaetaan\
\ Calckeyn kanssa ongelman ilmetessä, mikä auttaa parantamaan Calckeyn laatua.\n\
Näihin tietoihin sisältyy esimerkiksi käyttöjärjestelmäversio, käyttämäsi selain,\
\ toimintasi Calckeyssä jne."
createdAt: Luotu
youAreRunningUpToDateClient: Käytössäsi on asiakasohjelman uusin versio.
needReloadToApply: Uudelleenlataus vaaditaan, jotta tämä näkyy.
showingPastTimeline: Näytetään parhaillaan vanhaa aikajanaa
userPagePinTip: Voit näyttää viestit täällä valitsemalla yksittäisten viestien valikosta
"Kiinnitä profiiliin".
notSpecifiedMentionWarning: Tämä viesti sisältää mainintoja käyttäjistä, joita ei
ole mainittu vastaanottajina

View File

@ -756,7 +756,7 @@ active: "最近活躍"
offline: "離線" offline: "離線"
notRecommended: "不推薦" notRecommended: "不推薦"
botProtection: "Bot防護" botProtection: "Bot防護"
instanceBlocking: "已封鎖的實例" instanceBlocking: "聯邦封鎖/靜音"
selectAccount: "選擇帳戶" selectAccount: "選擇帳戶"
switchAccount: "切換帳戶" switchAccount: "切換帳戶"
enabled: "已啟用" enabled: "已啟用"
@ -1808,3 +1808,6 @@ logoImageUrl: 圖標網址
addInstance: 增加一個實例 addInstance: 增加一個實例
noInstances: 沒有實例 noInstances: 沒有實例
flagSpeakAsCat: 像貓一樣地說話 flagSpeakAsCat: 像貓一樣地說話
silenceThisInstance: 靜音此實例
silencedInstances: 已靜音的實例
silenced: 已靜音

View File

@ -0,0 +1,53 @@
export class NoteEdit1682753227899 {
name = "NoteEdit1682753227899";
async up(queryRunner) {
await queryRunner.query(`
CREATE TABLE "note_edit" (
"id" character varying(32) NOT NULL,
"noteId" character varying(32) NOT NULL,
"text" text,
"cw" character varying(512),
"fileIds" character varying(32) array NOT NULL DEFAULT '{}',
"updatedAt" TIMESTAMP WITH TIME ZONE NOT NULL,
CONSTRAINT "PK_736fc6e0d4e222ecc6f82058e08" PRIMARY KEY ("id")
)
`);
await queryRunner.query(`
COMMENT ON COLUMN "note_edit"."noteId" IS 'The ID of note.'
`);
await queryRunner.query(`
COMMENT ON COLUMN "note_edit"."updatedAt" IS 'The updated date of the Note.'
`);
await queryRunner.query(`
CREATE INDEX "IDX_702ad5ae993a672e4fbffbcd38" ON "note_edit" ("noteId")
`);
await queryRunner.query(`
ALTER TABLE "note"
ADD "updatedAt" TIMESTAMP WITH TIME ZONE
`);
await queryRunner.query(`
COMMENT ON COLUMN "note"."updatedAt" IS 'The updated date of the Note.'
`);
await queryRunner.query(`
ALTER TABLE "note_edit"
ADD CONSTRAINT "FK_702ad5ae993a672e4fbffbcd38c"
FOREIGN KEY ("noteId")
REFERENCES "note"("id")
ON DELETE CASCADE
ON UPDATE NO ACTION
`);
}
async down(queryRunner) {
await queryRunner.query(`
ALTER TABLE "note_edit" DROP CONSTRAINT "FK_702ad5ae993a672e4fbffbcd38c"
`);
await queryRunner.query(`
ALTER TABLE "note" DROP COLUMN "updatedAt"
`);
await queryRunner.query(`
DROP TABLE "note_edit"
`);
}
}

View File

@ -72,6 +72,7 @@ import { PasswordResetRequest } from "@/models/entities/password-reset-request.j
import { UserPending } from "@/models/entities/user-pending.js"; import { UserPending } from "@/models/entities/user-pending.js";
import { Webhook } from "@/models/entities/webhook.js"; import { Webhook } from "@/models/entities/webhook.js";
import { UserIp } from "@/models/entities/user-ip.js"; import { UserIp } from "@/models/entities/user-ip.js";
import { NoteEdit } from "@/models/entities/note-edit.js";
import { entities as charts } from "@/services/chart/entities.js"; import { entities as charts } from "@/services/chart/entities.js";
import { envOption } from "../env.js"; import { envOption } from "../env.js";
@ -140,6 +141,7 @@ export const entities = [
RenoteMuting, RenoteMuting,
Blocking, Blocking,
Note, Note,
NoteEdit,
NoteFavorite, NoteFavorite,
NoteReaction, NoteReaction,
NoteWatching, NoteWatching,

View File

@ -30,6 +30,7 @@ import { packedFederationInstanceSchema } from "@/models/schema/federation-insta
import { packedQueueCountSchema } from "@/models/schema/queue.js"; import { packedQueueCountSchema } from "@/models/schema/queue.js";
import { packedGalleryPostSchema } from "@/models/schema/gallery-post.js"; import { packedGalleryPostSchema } from "@/models/schema/gallery-post.js";
import { packedEmojiSchema } from "@/models/schema/emoji.js"; import { packedEmojiSchema } from "@/models/schema/emoji.js";
import { packedNoteEdit } from "@/models/schema/note-edit.js";
export const refs = { export const refs = {
UserLite: packedUserLiteSchema, UserLite: packedUserLiteSchema,
@ -45,6 +46,7 @@ export const refs = {
App: packedAppSchema, App: packedAppSchema,
MessagingMessage: packedMessagingMessageSchema, MessagingMessage: packedMessagingMessageSchema,
Note: packedNoteSchema, Note: packedNoteSchema,
NoteEdit: packedNoteEdit,
NoteReaction: packedNoteReactionSchema, NoteReaction: packedNoteReactionSchema,
NoteFavorite: packedNoteFavoriteSchema, NoteFavorite: packedNoteFavoriteSchema,
Notification: packedNotificationSchema, Notification: packedNotificationSchema,

View File

@ -0,0 +1,51 @@
import {
Entity,
JoinColumn,
Column,
ManyToOne,
PrimaryColumn,
Index,
} from "typeorm";
import { Note } from "./note.js";
import { id } from "../id.js";
import { DriveFile } from "./drive-file.js";
@Entity()
export class NoteEdit {
@PrimaryColumn(id())
public id: string;
@Index()
@Column({
...id(),
comment: 'The ID of note.',
})
public noteId: Note["id"];
@ManyToOne(type => Note, {
onDelete: 'CASCADE',
})
@JoinColumn()
public note: Note | null;
@Column('text', {
nullable: true,
})
public text: string | null;
@Column('varchar', {
length: 512, nullable: true,
})
public cw: string | null;
@Column({
...id(),
array: true, default: '{}',
})
public fileIds: DriveFile["id"][];
@Column('timestamp with time zone', {
comment: 'The updated date of the Note.',
})
public updatedAt: Date;
}

View File

@ -230,6 +230,12 @@ export class Note {
comment: '[Denormalized]', comment: '[Denormalized]',
}) })
public renoteUserHost: string | null; public renoteUserHost: string | null;
@Column('timestamp with time zone', {
nullable: true,
comment: 'The updated date of the Note.',
})
public updatedAt: Date;
//#endregion //#endregion
constructor(data: Partial<Note>) { constructor(data: Partial<Note>) {

View File

@ -67,11 +67,13 @@ import { UserPending } from "./entities/user-pending.js";
import { InstanceRepository } from "./repositories/instance.js"; import { InstanceRepository } from "./repositories/instance.js";
import { Webhook } from "./entities/webhook.js"; import { Webhook } from "./entities/webhook.js";
import { UserIp } from "./entities/user-ip.js"; import { UserIp } from "./entities/user-ip.js";
import { NoteEdit } from "./entities/note-edit.js";
export const Announcements = db.getRepository(Announcement); export const Announcements = db.getRepository(Announcement);
export const AnnouncementReads = db.getRepository(AnnouncementRead); export const AnnouncementReads = db.getRepository(AnnouncementRead);
export const Apps = AppRepository; export const Apps = AppRepository;
export const Notes = NoteRepository; export const Notes = NoteRepository;
export const NoteEdits = db.getRepository(NoteEdit);
export const NoteFavorites = NoteFavoriteRepository; export const NoteFavorites = NoteFavoriteRepository;
export const NoteWatchings = db.getRepository(NoteWatching); export const NoteWatchings = db.getRepository(NoteWatching);
export const NoteThreadMutings = db.getRepository(NoteThreadMuting); export const NoteThreadMutings = db.getRepository(NoteThreadMuting);

View File

@ -235,6 +235,7 @@ export const NoteRepository = db.getRepository(Note).extend({
mentions: note.mentions.length > 0 ? note.mentions : undefined, mentions: note.mentions.length > 0 ? note.mentions : undefined,
uri: note.uri || undefined, uri: note.uri || undefined,
url: note.url || undefined, url: note.url || undefined,
updatedAt: note.updatedAt?.toISOString() || undefined,
...(opts.detail ...(opts.detail
? { ? {

View File

@ -0,0 +1,49 @@
export const packedNoteEdit = {
type: "object",
properties: {
id: {
type: "string",
optional: false,
nullable: false,
format: "id",
example: "xxxxxxxxxx",
},
updatedAt: {
type: "string",
optional: false,
nullable: false,
format: "date-time",
},
note: {
type: "object",
optional: false,
nullable: false,
ref: "Note",
},
noteId: {
type: "string",
optional: false,
nullable: false,
format: "id",
},
text: {
type: "string",
optional: true,
nullable: true,
},
cw: {
type: "string",
optional: true,
nullable: true,
},
fileIds: {
type: "array",
optional: true,
nullable: true,
items: {
type: "string",
format: "id",
},
},
},
} as const;

View File

@ -2,7 +2,7 @@ import type { CacheableRemoteUser } from "@/models/entities/user.js";
import type { IUpdate } from "../../type.js"; import type { IUpdate } from "../../type.js";
import { getApType, isActor } from "../../type.js"; import { getApType, isActor } from "../../type.js";
import { apLogger } from "../../logger.js"; import { apLogger } from "../../logger.js";
import { updateQuestion } from "../../models/question.js"; import { updateNote } from "../../models/note.js";
import Resolver from "../../resolver.js"; import Resolver from "../../resolver.js";
import { updatePerson } from "../../models/person.js"; import { updatePerson } from "../../models/person.js";
@ -29,10 +29,22 @@ export default async (
if (isActor(object)) { if (isActor(object)) {
await updatePerson(actor.uri!, resolver, object); await updatePerson(actor.uri!, resolver, object);
return "ok: Person updated"; return "ok: Person updated";
} else if (getApType(object) === "Question") { }
await updateQuestion(object, resolver).catch((e) => console.log(e));
return "ok: Question updated"; const objectType = getApType(object);
} else { switch (objectType) {
return `skip: Unknown type: ${getApType(object)}`; case "Question":
case "Note":
case "Article":
case "Document":
case "Page":
let failed = false;
await updateNote(object, resolver).catch((e: Error) => {
failed = true;
});
return failed ? "skip: Note update failed" : "ok: Note updated";
default:
return `skip: Unknown type: ${objectType}`;
} }
}; };

View File

@ -1,22 +1,33 @@
import promiseLimit from "promise-limit"; import promiseLimit from "promise-limit";
import * as mfm from "mfm-js";
import config from "@/config/index.js"; import config from "@/config/index.js";
import Resolver from "../resolver.js"; import Resolver from "../resolver.js";
import post from "@/services/note/create.js"; import post from "@/services/note/create.js";
import { extractMentionedUsers } from "@/services/note/create.js";
import { resolvePerson } from "./person.js"; import { resolvePerson } from "./person.js";
import { resolveImage } from "./image.js"; import { resolveImage } from "./image.js";
import type { CacheableRemoteUser } from "@/models/entities/user.js"; import type {
ILocalUser,
CacheableRemoteUser,
} from "@/models/entities/user.js";
import { htmlToMfm } from "../misc/html-to-mfm.js"; import { htmlToMfm } from "../misc/html-to-mfm.js";
import { extractApHashtags } from "./tag.js"; import { extractApHashtags } from "./tag.js";
import { unique, toArray, toSingle } from "@/prelude/array.js"; import { unique, toArray, toSingle } from "@/prelude/array.js";
import { extractPollFromQuestion } from "./question.js"; import { extractPollFromQuestion, updateQuestion } from "./question.js";
import vote from "@/services/note/polls/vote.js"; import vote from "@/services/note/polls/vote.js";
import { apLogger } from "../logger.js"; import { apLogger } from "../logger.js";
import type { DriveFile } from "@/models/entities/drive-file.js"; import { DriveFile } from "@/models/entities/drive-file.js";
import { deliverQuestionUpdate } from "@/services/note/polls/update.js"; import { deliverQuestionUpdate } from "@/services/note/polls/update.js";
import { extractDbHost, toPuny } from "@/misc/convert-host.js"; import { extractDbHost, toPuny } from "@/misc/convert-host.js";
import { Emojis, Polls, MessagingMessages } from "@/models/index.js"; import {
import type { Note } from "@/models/entities/note.js"; Emojis,
Polls,
MessagingMessages,
Notes,
NoteEdits,
DriveFiles,
} from "@/models/index.js";
import type { IMentionedRemoteUsers, Note } from "@/models/entities/note.js";
import type { IObject, IPost } from "../type.js"; import type { IObject, IPost } from "../type.js";
import { import {
getOneApId, getOneApId,
@ -28,7 +39,6 @@ import {
} from "../type.js"; } from "../type.js";
import type { Emoji } from "@/models/entities/emoji.js"; import type { Emoji } from "@/models/entities/emoji.js";
import { genId } from "@/misc/gen-id.js"; import { genId } from "@/misc/gen-id.js";
import { fetchMeta } from "@/misc/fetch-meta.js";
import { getApLock } from "@/misc/app-lock.js"; import { getApLock } from "@/misc/app-lock.js";
import { createMessage } from "@/services/messages/create.js"; import { createMessage } from "@/services/messages/create.js";
import { parseAudience } from "../audience.js"; import { parseAudience } from "../audience.js";
@ -36,6 +46,12 @@ import { extractApMentions } from "./mention.js";
import DbResolver from "../db-resolver.js"; import DbResolver from "../db-resolver.js";
import { StatusError } from "@/misc/fetch.js"; import { StatusError } from "@/misc/fetch.js";
import { shouldBlockInstance } from "@/misc/should-block-instance.js"; import { shouldBlockInstance } from "@/misc/should-block-instance.js";
import { publishNoteStream } from "@/services/stream.js";
import { extractHashtags } from "@/misc/extract-hashtags.js";
import { UserProfiles } from "@/models/index.js";
import { In } from "typeorm";
import { DB_MAX_IMAGE_COMMENT_LENGTH } from "@/misc/hard-limits.js";
import { truncate } from "@/misc/truncate.js";
const logger = apLogger; const logger = apLogger;
@ -497,3 +513,236 @@ export async function extractEmojis(
}), }),
); );
} }
type TagDetail = {
type: string;
name: string;
};
function notEmpty(partial: Partial<any>) {
return Object.keys(partial).length > 0;
}
export async function updateNote(value: string | IObject, resolver?: Resolver) {
const uri = typeof value === "string" ? value : value.id;
if (!uri) throw new Error("Missing note uri");
// Skip if URI points to this server
if (uri.startsWith(`${config.url}/`)) throw new Error("uri points local");
// A new resolver is created if not specified
if (resolver == null) resolver = new Resolver();
// Resolve the updated Note object
const post = (await resolver.resolve(value)) as IPost;
const actor = (await resolvePerson(
getOneApId(post.attributedTo),
resolver,
)) as CacheableRemoteUser;
// Already registered with this server?
const note = await Notes.findOneBy({ uri });
if (note == null) {
return await createNote(post, resolver);
}
// Whether to tell clients the note has been updated and requires refresh.
let publishing = false;
// Text parsing
let text: string | null = null;
if (
post.source?.mediaType === "text/x.misskeymarkdown" &&
typeof post.source?.content === "string"
) {
text = post.source.content;
} else if (typeof post._misskey_content !== "undefined") {
text = post._misskey_content;
} else if (typeof post.content === "string") {
text = htmlToMfm(post.content, post.tag);
}
const cw = post.sensitive && post.summary;
// File parsing
const fileList = post.attachment
? Array.isArray(post.attachment)
? post.attachment
: [post.attachment]
: [];
const files = fileList.map((f) => (f.sensitive = post.sensitive));
// Fetch files
const limit = promiseLimit(2);
const driveFiles = (
await Promise.all(
fileList.map(
(x) =>
limit(async () => {
const file = await resolveImage(actor, x);
const update: Partial<DriveFile> = {};
const altText = truncate(x.name, DB_MAX_IMAGE_COMMENT_LENGTH);
if (file.comment !== altText) {
update.comment = altText;
}
// Don't unmark previously marked sensitive files,
// but if edited post contains sensitive marker, update it.
if (post.sensitive && !file.isSensitive) {
update.isSensitive = post.sensitive;
}
if (notEmpty(update)) {
await DriveFiles.update(file.id, update);
publishing = true;
}
return file;
}) as Promise<DriveFile>,
),
)
).filter((file) => file != null);
const fileIds = driveFiles.map((file) => file.id);
const fileTypes = driveFiles.map((file) => file.type);
const apEmojis = (
await extractEmojis(post.tag || [], actor.host).catch((e) => [])
).map((emoji) => emoji.name);
const apMentions = await extractApMentions(post.tag);
const apHashtags = await extractApHashtags(post.tag);
const poll = await extractPollFromQuestion(post, resolver).catch(
() => undefined,
);
const choices = poll?.choices.flatMap((choice) => mfm.parse(choice)) ?? [];
const tokens = mfm
.parse(text || "")
.concat(mfm.parse(cw || ""))
.concat(choices);
const hashTags: string[] = apHashtags || extractHashtags(tokens);
const mentionUsers =
apMentions || (await extractMentionedUsers(actor, tokens));
const mentionUserIds = mentionUsers.map((user) => user.id);
const remoteUsers = mentionUsers.filter((user) => user.host != null);
const remoteUserIds = remoteUsers.map((user) => user.id);
const remoteProfiles = await UserProfiles.findBy({
userId: In(remoteUserIds),
});
const mentionedRemoteUsers = remoteUsers.map((user) => {
const profile = remoteProfiles.find(
(profile) => profile.userId === user.id,
);
return {
username: user.username,
host: user.host ?? null,
uri: user.uri,
url: profile ? profile.url : undefined,
} as IMentionedRemoteUsers[0];
});
const update = {} as Partial<Note>;
if (text && text !== note.text) {
update.text = text;
}
if (cw !== note.cw) {
update.cw = cw ? cw : null;
}
if (fileIds.sort().join(",") !== note.fileIds.sort().join(",")) {
update.fileIds = fileIds;
update.attachedFileTypes = fileTypes;
}
if (hashTags.sort().join(",") !== note.tags.sort().join(",")) {
update.tags = hashTags;
}
if (mentionUserIds.sort().join(",") !== note.mentions.sort().join(",")) {
update.mentions = mentionUserIds;
update.mentionedRemoteUsers = JSON.stringify(mentionedRemoteUsers);
}
if (apEmojis.sort().join(",") !== note.emojis.sort().join(",")) {
update.emojis = apEmojis;
}
if (note.hasPoll !== !!poll) {
update.hasPoll = !!poll;
}
if (poll) {
const dbPoll = await Polls.findOneBy({ noteId: note.id });
if (dbPoll == null) {
await Polls.insert({
noteId: note.id,
choices: poll?.choices,
multiple: poll?.multiple,
votes: poll?.votes,
expiresAt: poll?.expiresAt,
noteVisibility: note.visibility,
userId: actor.id,
userHost: actor.host,
});
updating = true;
} else if (
dbPoll.multiple !== poll.multiple ||
dbPoll.expiresAt !== poll.expiresAt ||
dbPoll.noteVisibility !== note.visibility ||
JSON.stringify(dbPoll.choices) !== JSON.stringify(poll.choices)
) {
await Polls.update(
{ noteId: note.id },
{
choices: poll?.choices,
multiple: poll?.multiple,
votes: poll?.votes,
expiresAt: poll?.expiresAt,
noteVisibility: note.visibility,
},
);
updating = true;
} else {
for (let i = 0; i < poll.choices.length; i++) {
if (dbPoll.votes[i] !== poll.votes?.[i]) {
await Polls.update({ noteId: note.id }, { votes: poll?.votes });
publishing = true;
break;
}
}
}
}
// Update Note
if (notEmpty(update)) {
update.updatedAt = new Date();
// Save updated note to the database
await Notes.update({ uri }, update);
// Save an edit history for the previous note
await NoteEdits.insert({
id: genId(),
noteId: note.id,
text: note.text,
cw: note.cw,
fileIds: note.fileIds,
updatedAt: update.updatedAt,
});
publishing = true;
}
if (publishing) {
// Publish update event for the updated note details
publishNoteStream(note.id, "updated", {
updatedAt: update.updatedAt,
});
}
}

View File

@ -191,7 +191,7 @@ export async function createPerson(
.map((tag) => normalizeForSearch(tag)) .map((tag) => normalizeForSearch(tag))
.splice(0, 32); .splice(0, 32);
const isBot = getApType(object) === "Service"; const isBot = getApType(object) !== "Person";
const bday = person["vcard:bday"]?.match(/^\d{4}-\d{2}-\d{2}/); const bday = person["vcard:bday"]?.match(/^\d{4}-\d{2}-\d{2}/);
@ -502,7 +502,7 @@ export async function updatePerson(
emojis: emojiNames, emojis: emojiNames,
name: truncate(person.name, nameLength), name: truncate(person.name, nameLength),
tags, tags,
isBot: getApType(object) === "Service", isBot: getApType(object) !== "Person",
isCat: (person as any).isCat === true, isCat: (person as any).isCat === true,
isLocked: !!person.manuallyApprovesFollowers, isLocked: !!person.manuallyApprovesFollowers,
movedToUri: person.movedTo || null, movedToUri: person.movedTo || null,

View File

@ -533,7 +533,7 @@ const eps = [
["i/export-following", ep___i_exportFollowing], ["i/export-following", ep___i_exportFollowing],
["i/export-mute", ep___i_exportMute], ["i/export-mute", ep___i_exportMute],
["i/export-notes", ep___i_exportNotes], ["i/export-notes", ep___i_exportNotes],
["i/import-posts", ep___i_importPosts], // ["i/import-posts", ep___i_importPosts],
["i/export-user-lists", ep___i_exportUserLists], ["i/export-user-lists", ep___i_exportUserLists],
["i/favorites", ep___i_favorites], ["i/favorites", ep___i_favorites],
["i/gallery/likes", ep___i_gallery_likes], ["i/gallery/likes", ep___i_gallery_likes],

View File

@ -145,6 +145,9 @@ export interface NoteStreamTypes {
replied: { replied: {
id: Note["id"]; id: Note["id"];
}; };
updated: {
updatedAt?: Note["updatedAt"];
};
} }
type NoteStreamEventTypes = { type NoteStreamEventTypes = {
[key in keyof NoteStreamTypes]: { [key in keyof NoteStreamTypes]: {

View File

@ -30,7 +30,11 @@ export default class NotesChart extends Chart<typeof schema> {
return {}; return {};
} }
public async update(note: Note, isAdditional: boolean): Promise<void> { public async update(
note: Note,
isAdditional: boolean,
byBot = false,
): Promise<void> {
const prefix = note.userHost === null ? "local" : "remote"; const prefix = note.userHost === null ? "local" : "remote";
await this.commit({ await this.commit({
@ -44,7 +48,7 @@ export default class NotesChart extends Chart<typeof schema> {
: -1 : -1
: 0, : 0,
[`${prefix}.diffs.renote`]: [`${prefix}.diffs.renote`]:
note.renoteId != null ? (isAdditional ? 1 : -1) : 0, note.renoteId != null && !byBot ? (isAdditional ? 1 : -1) : 0,
[`${prefix}.diffs.reply`]: [`${prefix}.diffs.reply`]:
note.replyId != null ? (isAdditional ? 1 : -1) : 0, note.replyId != null ? (isAdditional ? 1 : -1) : 0,
[`${prefix}.diffs.withFile`]: [`${prefix}.diffs.withFile`]:

View File

@ -32,6 +32,7 @@ export default class PerUserNotesChart extends Chart<typeof schema> {
user: { id: User["id"] }, user: { id: User["id"] },
note: Note, note: Note,
isAdditional: boolean, isAdditional: boolean,
byBot = false,
): Promise<void> { ): Promise<void> {
await this.commit( await this.commit(
{ {
@ -44,7 +45,8 @@ export default class PerUserNotesChart extends Chart<typeof schema> {
? 1 ? 1
: -1 : -1
: 0, : 0,
"diffs.renote": note.renoteId != null ? (isAdditional ? 1 : -1) : 0, "diffs.renote":
note.renoteId != null && !byBot ? (isAdditional ? 1 : -1) : 0,
"diffs.reply": note.replyId != null ? (isAdditional ? 1 : -1) : 0, "diffs.reply": note.replyId != null ? (isAdditional ? 1 : -1) : 0,
"diffs.withFile": note.fileIds.length > 0 ? (isAdditional ? 1 : -1) : 0, "diffs.withFile": note.fileIds.length > 0 ? (isAdditional ? 1 : -1) : 0,
}, },

View File

@ -163,6 +163,7 @@ export default async (
host: User["host"]; host: User["host"];
isSilenced: User["isSilenced"]; isSilenced: User["isSilenced"];
createdAt: User["createdAt"]; createdAt: User["createdAt"];
isBot: User["isBot"];
}, },
data: Option, data: Option,
silent = false, silent = false,
@ -323,8 +324,8 @@ export default async (
res(note); res(note);
// 統計を更新 // 統計を更新
notesChart.update(note, true); notesChart.update(note, true, user.isBot);
perUserNotesChart.update(user, note, true); perUserNotesChart.update(user, note, true, user.isBot);
// Register host // Register host
if (Users.isRemoteUser(user)) { if (Users.isRemoteUser(user)) {
@ -399,6 +400,7 @@ export default async (
// この投稿を除く指定したユーザーによる指定したノートのリノートが存在しないとき // この投稿を除く指定したユーザーによる指定したノートのリノートが存在しないとき
if ( if (
data.renote && data.renote &&
!user.isBot &&
(await countSameRenotes(user.id, data.renote.id, note.id)) === 0 (await countSameRenotes(user.id, data.renote.id, note.id)) === 0
) { ) {
incRenoteCount(data.renote); incRenoteCount(data.renote);
@ -857,7 +859,7 @@ function incNotesCountOfUser(user: { id: User["id"] }) {
.execute(); .execute();
} }
async function extractMentionedUsers( export async function extractMentionedUsers(
user: { host: User["host"] }, user: { host: User["host"] },
tokens: mfm.MfmNode[], tokens: mfm.MfmNode[],
): Promise<User[]> { ): Promise<User[]> {

View File

@ -1,4 +1,4 @@
import { import type {
Antenna, Antenna,
CustomEmoji, CustomEmoji,
DriveFile, DriveFile,
@ -171,6 +171,13 @@ export type NoteUpdatedEvent =
body: { body: {
id: Note["id"]; id: Note["id"];
}; };
}
| {
id: Note["id"];
type: "updated";
body: {
updatedAt: string;
};
}; };
export type BroadcastEvents = { export type BroadcastEvents = {

View File

@ -524,7 +524,7 @@ function readPromo() {
display: block; display: block;
margin-bottom: -10px; margin-bottom: -10px;
margin-top: 16px; margin-top: 16px;
border-left: 2px solid var(--divider); border-left: 2px solid var(--X13);
margin-left: calc((var(--avatarSize) / 2) - 1px); margin-left: calc((var(--avatarSize) / 2) - 1px);
} }
} }
@ -641,14 +641,11 @@ function readPromo() {
> .body { > .body {
margin-top: 0.7em; margin-top: 0.7em;
> .translation {
> .content { border: solid 0.5px var(--divider);
> .translation { border-radius: var(--radius);
border: solid 0.5px var(--divider); padding: 12px;
border-radius: var(--radius); margin-top: 8px;
padding: 12px;
margin-top: 8px;
}
} }
> .renote { > .renote {
padding-top: 8px; padding-top: 8px;

View File

@ -188,15 +188,12 @@ useNoteCapture({
function reply(viaKeyboard = false): void { function reply(viaKeyboard = false): void {
pleaseLogin(); pleaseLogin();
os.post( os.post({
{ reply: appearNote,
reply: appearNote, animation: !viaKeyboard,
animation: !viaKeyboard, }).then(() => {
}, focus();
() => { });
focus();
}
);
} }
function react(viaKeyboard = false): void { function react(viaKeyboard = false): void {
@ -323,19 +320,46 @@ if (appearNote.replyId) {
}); });
} }
function onNoteReplied(noteData: NoteUpdatedEvent): void { async function onNoteUpdated(noteData: NoteUpdatedEvent): Promise<void> {
const { type, id, body } = noteData; const { type, id, body } = noteData;
if (type === "replied" && id === appearNote.id) {
const { id: createdId } = body;
os.api("notes/show", { let found = -1;
noteId: createdId, if (id === appearNote.id) {
}).then((note) => { found = 0;
if (note.replyId === appearNote.id) { } else {
replies.value.unshift(note); for (let i = 0; i < replies.value.length; i++) {
directReplies.value.unshift(note); const reply = replies.value[i];
if (reply.id === id) {
found = i + 1;
break;
} }
}); }
}
if (found === -1) {
return;
}
switch (type) {
case "replied":
const { id: createdId } = body;
const replyNote = await os.api("notes/show", {
noteId: createdId,
});
replies.value.splice(found, 0, replyNote);
if (found === 0) {
directReplies.value.unshift(replyNote);
}
break;
case "deleted":
if (found === 0) {
isDeleted.value = true;
} else {
replies.value.splice(found - 1, 1);
}
break;
} }
} }
@ -344,19 +368,19 @@ document.addEventListener("wheel", () => {
}); });
onMounted(() => { onMounted(() => {
stream.on("noteUpdated", onNoteReplied); stream.on("noteUpdated", onNoteUpdated);
isScrolling = false; isScrolling = false;
noteEl.scrollIntoView(); noteEl?.scrollIntoView();
}); });
onUpdated(() => { onUpdated(() => {
if (!isScrolling) { if (!isScrolling) {
noteEl.scrollIntoView(); noteEl?.scrollIntoView();
} }
}); });
onUnmounted(() => { onUnmounted(() => {
stream.off("noteUpdated", onNoteReplied); stream.off("noteUpdated", onNoteUpdated);
}); });
</script> </script>

View File

@ -18,6 +18,13 @@
<div class="info"> <div class="info">
<MkA class="created-at" :to="notePage(note)"> <MkA class="created-at" :to="notePage(note)">
<MkTime :time="note.createdAt" /> <MkTime :time="note.createdAt" />
<MkTime
v-if="note.updatedAt"
:time="note.updatedAt"
mode="none"
>(<i class="ph-pencil-line ph-bold"></i
>{{ i18n.ts.edited }})</MkTime
>
</MkA> </MkA>
<MkVisibility :note="note" /> <MkVisibility :note="note" />
</div> </div>
@ -39,14 +46,14 @@ import MkVisibility from "@/components/MkVisibility.vue";
import MkInstanceTicker from "@/components/MkInstanceTicker.vue"; import MkInstanceTicker from "@/components/MkInstanceTicker.vue";
import { notePage } from "@/filters/note"; import { notePage } from "@/filters/note";
import { userPage } from "@/filters/user"; import { userPage } from "@/filters/user";
import { deepClone } from "@/scripts/clone"; import { i18n } from "@/i18n";
const props = defineProps<{ const props = defineProps<{
note: misskey.entities.Note; note: misskey.entities.Note;
pinned?: boolean; pinned?: boolean;
}>(); }>();
let note = $ref(deepClone(props.note)); let note = $ref(props.note);
const showTicker = const showTicker =
defaultStore.state.instanceTicker === "always" || defaultStore.state.instanceTicker === "always" ||

View File

@ -200,9 +200,9 @@ import * as os from "@/os";
import { reactionPicker } from "@/scripts/reaction-picker"; import { reactionPicker } from "@/scripts/reaction-picker";
import { $i } from "@/account"; import { $i } from "@/account";
import { i18n } from "@/i18n"; import { i18n } from "@/i18n";
import { deepClone } from "@/scripts/clone";
import { useNoteCapture } from "@/scripts/use-note-capture"; import { useNoteCapture } from "@/scripts/use-note-capture";
import { defaultStore } from "@/store"; import { defaultStore } from "@/store";
import { deepClone } from "@/scripts/clone";
const router = useRouter(); const router = useRouter();
@ -271,19 +271,17 @@ const enableEmojiReactions = defaultStore.state.enableEmojiReactions;
useNoteCapture({ useNoteCapture({
rootEl: el, rootEl: el,
note: $$(appearNote), note: $$(appearNote),
isDeletedRef: isDeleted,
}); });
function reply(viaKeyboard = false): void { function reply(viaKeyboard = false): void {
pleaseLogin(); pleaseLogin();
os.post( os.post({
{ reply: appearNote,
reply: appearNote, animation: !viaKeyboard,
animation: !viaKeyboard, }).then(() => {
}, focus();
() => { });
focus();
}
);
} }
function react(viaKeyboard = false): void { function react(viaKeyboard = false): void {

View File

@ -1,9 +1,14 @@
<template> <template>
<span v-if="note.visibility !== 'public'" :class="$style.visibility"> <span v-if="note.visibility !== 'public'" :class="$style.visibility">
<i v-if="note.visibility === 'home'" class="ph-house ph-bold ph-lg"></i> <i
v-if="note.visibility === 'home'"
class="ph-house ph-bold ph-lg"
v-tooltip="i18n.ts._visibility.home"
></i>
<i <i
v-else-if="note.visibility === 'followers'" v-else-if="note.visibility === 'followers'"
class="ph-lock-simple-open ph-bold ph-lg" class="ph-lock-simple-open ph-bold ph-lg"
v-tooltip="i18n.ts._visibility.followers"
></i> ></i>
<i <i
v-else-if="note.visibility === 'specified'" v-else-if="note.visibility === 'specified'"
@ -12,7 +17,10 @@
></i> ></i>
</span> </span>
<span v-if="note.localOnly" :class="$style.localOnly" <span v-if="note.localOnly" :class="$style.localOnly"
><i class="ph-hand-fist ph-bold ph-lg"></i ><i
class="ph-hand-fist ph-bold ph-lg"
v-tooltip="i18n.ts._visibility.localOnly"
></i
></span> ></span>
</template> </template>
@ -21,6 +29,7 @@ import { ref } from "vue";
import XDetails from "@/components/MkUsersTooltip.vue"; import XDetails from "@/components/MkUsersTooltip.vue";
import * as os from "@/os"; import * as os from "@/os";
import { useTooltip } from "@/scripts/use-tooltip"; import { useTooltip } from "@/scripts/use-tooltip";
import { i18n } from "@/i18n";
const props = defineProps<{ const props = defineProps<{
note: { note: {

View File

@ -5,6 +5,7 @@
<template v-else-if="mode === 'detail'" <template v-else-if="mode === 'detail'"
>{{ absolute }} ({{ relative }})</template >{{ absolute }} ({{ relative }})</template
> >
<slot></slot>
</time> </time>
</template> </template>
@ -15,7 +16,7 @@ import { i18n } from "@/i18n";
const props = withDefaults( const props = withDefaults(
defineProps<{ defineProps<{
time: Date | string; time: Date | string;
mode?: "relative" | "absolute" | "detail"; mode?: "relative" | "absolute" | "detail" | "none";
}>(), }>(),
{ {
mode: "relative", mode: "relative",

View File

@ -3,7 +3,7 @@
:is="self ? 'MkA' : 'a'" :is="self ? 'MkA' : 'a'"
ref="el" ref="el"
class="ieqqeuvs _link" class="ieqqeuvs _link"
:[attr]="self ? url.substr(local.length) : url" :[attr]="self ? props.url.substring(local.length) : props.url"
:rel="rel" :rel="rel"
:target="target" :target="target"
@contextmenu.stop="() => {}" @contextmenu.stop="() => {}"
@ -18,7 +18,7 @@
<span class="self">{{ hostname }}</span> <span class="self">{{ hostname }}</span>
</template> </template>
<span v-if="pathname != ''" class="pathname">{{ <span v-if="pathname != ''" class="pathname">{{
self ? pathname.substr(1) : pathname self ? pathname.substring(1) : pathname
}}</span> }}</span>
<span class="query">{{ query }}</span> <span class="query">{{ query }}</span>
<span class="hash">{{ hash }}</span> <span class="hash">{{ hash }}</span>

View File

@ -100,9 +100,9 @@
<FormLink to="/@cleo@bz.pawdev.me" <FormLink to="/@cleo@bz.pawdev.me"
><Mfm :text="'@cleo@bz.pawdev.me (Maintainer)'" ><Mfm :text="'@cleo@bz.pawdev.me (Maintainer)'"
/></FormLink> /></FormLink>
<FormLink to="/@panos@i.calckey.cloud" <FormLink to="/@panos@calckey.social"
><Mfm ><Mfm
:text="'@panos@i.calckey.cloud (Management)'" :text="'@panos@calckey.social (Project Coordinator)'"
/></FormLink> /></FormLink>
<FormLink to="/@freeplay@bz.pawdev.me" <FormLink to="/@freeplay@bz.pawdev.me"
><Mfm ><Mfm

View File

@ -16,23 +16,20 @@
{{ i18n.ts.export }}</MkButton {{ i18n.ts.export }}</MkButton
> >
</FormFolder> </FormFolder>
<FormFolder class="_formBlock"> <!-- <FormFolder class="_formBlock">
<template #label>{{ i18n.ts.import }}</template> <template #label>{{ i18n.ts.import }}</template>
<template #icon <template #icon
><i class="ph-upload-simple ph-bold ph-lg"></i ><i class="ph-upload-simple ph-bold ph-lg"></i
></template> ></template>
<!-- <FormSwitch v-model="signatureCheck" class="_formBlock">
Mastodon import? (not Akkoma!)
</FormSwitch> -->
<FormRadios v-model="importType" class="_formBlock"> <FormRadios v-model="importType" class="_formBlock">
<option value="calckey">Calckey/Misskey</option> <option value="calckey">Calckey/Misskey</option>
<option value="mastodon">Mastodon</option> <option value="mastodon">Mastodon</option>
<!-- <option :disabled="true" value="akkoma"> <option :disabled="true" value="akkoma">
Pleroma/Akkoma (soon) Pleroma/Akkoma (soon)
</option> </option>
<option :disabled="true" value="twitter"> <option :disabled="true" value="twitter">
Twitter (soon) Twitter (soon)
</option> --> </option>
</FormRadios> </FormRadios>
<MkButton <MkButton
primary primary
@ -42,7 +39,7 @@
><i class="ph-upload-simple ph-bold ph-lg"></i> ><i class="ph-upload-simple ph-bold ph-lg"></i>
{{ i18n.ts.import }}</MkButton {{ i18n.ts.import }}</MkButton
> >
</FormFolder> </FormFolder> -->
</FormSection> </FormSection>
<FormSection> <FormSection>
<template #label>{{ <template #label>{{

View File

@ -105,16 +105,14 @@ export function getNoteMenu(props: {
noteId: appearNote.id, noteId: appearNote.id,
}, },
undefined, undefined,
null, ).catch((res) => {
(res) => { if (res.id === "72dab508-c64d-498f-8740-a8eec1ba385a") {
if (res.id === "72dab508-c64d-498f-8740-a8eec1ba385a") { os.alert({
os.alert({ type: "error",
type: "error", text: i18n.ts.pinLimitExceeded,
text: i18n.ts.pinLimitExceeded, });
}); }
} });
},
);
} }
async function clip(): Promise<void> { async function clip(): Promise<void> {

View File

@ -2,6 +2,7 @@ import { onUnmounted, Ref } from "vue";
import * as misskey from "calckey-js"; import * as misskey from "calckey-js";
import { stream } from "@/stream"; import { stream } from "@/stream";
import { $i } from "@/account"; import { $i } from "@/account";
import * as os from "@/os";
export function useNoteCapture(props: { export function useNoteCapture(props: {
rootEl: Ref<HTMLElement>; rootEl: Ref<HTMLElement>;
@ -11,7 +12,7 @@ export function useNoteCapture(props: {
const note = props.note; const note = props.note;
const connection = $i ? stream : null; const connection = $i ? stream : null;
function onStreamNoteUpdated(noteData): void { async function onStreamNoteUpdated(noteData): Promise<void> {
const { type, id, body } = noteData; const { type, id, body } = noteData;
if (id !== note.value.id) return; if (id !== note.value.id) return;
@ -47,7 +48,7 @@ export function useNoteCapture(props: {
note.value.reactions[reaction] = Math.max(0, currentCount - 1); note.value.reactions[reaction] = Math.max(0, currentCount - 1);
if ($i && body.userId === $i.id) { if ($i && body.userId === $i.id) {
note.value.myReaction = null; note.value.myReaction = undefined;
} }
break; break;
} }
@ -55,18 +56,20 @@ export function useNoteCapture(props: {
case "pollVoted": { case "pollVoted": {
const choice = body.choice; const choice = body.choice;
const choices = [...note.value.poll.choices]; if (note.value.poll) {
choices[choice] = { const choices = [...note.value.poll.choices];
...choices[choice], choices[choice] = {
votes: choices[choice].votes + 1, ...choices[choice],
...($i && body.userId === $i.id votes: choices[choice].votes + 1,
? { ...($i && body.userId === $i.id
isVoted: true, ? {
} isVoted: true,
: {}), }
}; : {}),
};
note.value.poll.choices = choices;
}
note.value.poll.choices = choices;
break; break;
} }
@ -74,6 +77,21 @@ export function useNoteCapture(props: {
props.isDeletedRef.value = true; props.isDeletedRef.value = true;
break; break;
} }
case "updated": {
const editedNote = await os.api("notes/show", {
noteId: id,
});
const keys = new Set<string>();
Object.keys(editedNote)
.concat(Object.keys(note.value))
.forEach((key) => keys.add(key));
keys.forEach((key) => {
note.value[key] = editedNote[key];
});
break;
}
} }
} }

View File

@ -1,7 +1,7 @@
{ {
id: '080a01c5-377d-4fbb-88cc-6bb5d04977ea', id: '080a01c5-377d-4fbb-88cc-6bb5d04977ea',
base: 'dark', base: 'dark',
name: 'Astro Dark', name: 'Mi Astro Dark',
author: 'syuilo', author: 'syuilo',
props: { props: {
bg: '#232125', bg: '#232125',

View File

@ -1,7 +1,7 @@
{ {
id: '504debaf-4912-6a4c-5059-1db08a76b737', id: '504debaf-4912-6a4c-5059-1db08a76b737',
name: 'Botanical Dark', name: 'Mi Botanical Dark',
author: 'syuilo', author: 'syuilo',
base: 'dark', base: 'dark',

View File

@ -1,7 +1,7 @@
{ {
id: 'ffcd3328-5c57-4ca3-9dac-4580cbf7742f', id: 'ffcd3328-5c57-4ca3-9dac-4580cbf7742f',
base: 'dark', base: 'dark',
name: 'Catppuccin Frappe', name: 'Catppuccin frappe',
props: { props: {
X2: ':darken<2<@panel', X2: ':darken<2<@panel',
X3: 'rgba(255, 255, 255, 0.05)', X3: 'rgba(255, 255, 255, 0.05)',

View File

@ -1,7 +1,7 @@
{ {
id: 'd413f41f-a489-48be-9e20-3532ffbb4363', id: 'd413f41f-a489-48be-9e20-3532ffbb4363',
base: 'dark', base: 'dark',
name: 'Catppuccin Mocha', name: 'Catppuccin mocha',
props: { props: {
X2: ':darken<2<@panel', X2: ':darken<2<@panel',
X3: 'rgba(255, 255, 255, 0.05)', X3: 'rgba(255, 255, 255, 0.05)',

View File

@ -1,7 +1,7 @@
{ {
id: '679b3b87-a4e9-4789-8696-b56c15cc33b0', id: '679b3b87-a4e9-4789-8696-b56c15cc33b0',
name: 'Cherry Dark', name: 'Mi Cherry Dark',
author: 'syuilo', author: 'syuilo',
base: 'dark', base: 'dark',

View File

@ -1,7 +1,7 @@
{ {
id: '32a637ef-b47a-4775-bb7b-bacbb823f865', id: '32a637ef-b47a-4775-bb7b-bacbb823f865',
name: 'Future Dark', name: 'Mi Future Dark',
author: 'syuilo', author: 'syuilo',
base: 'dark', base: 'dark',

View File

@ -1,7 +1,7 @@
{ {
id: '02816013-8107-440f-877e-865083ffe194', id: '02816013-8107-440f-877e-865083ffe194',
name: 'Mi Dark', name: 'Mi Green+Lime Dark',
author: 'syuilo', author: 'syuilo',
base: 'dark', base: 'dark',

View File

@ -0,0 +1,24 @@
{
id: 'dc489603-27b5-424a-9b25-1ff6aec9824a',
name: 'Mi Green+Orange Dark',
author: 'syuilo',
base: 'dark',
props: {
accent: '#e97f00',
bg: '#0C1210',
fg: '#dee7e4',
fgHighlighted: '#fff',
fgOnAccent: '#192320',
divider: '#e7fffb24',
panel: '#192320',
panelHeaderBg: '@panel',
panelHeaderDivider: '@divider',
popup: '#293330',
renote: '@accent',
mentionMe: '#b4e900',
link: '#24d7ce',
},
}

View File

@ -1,7 +1,7 @@
{ {
id: '66e7e5a9-cd43-42cd-837d-12f47841fa34', id: '66e7e5a9-cd43-42cd-837d-12f47841fa34',
name: 'Ice Dark', name: 'Mi Ice Dark',
author: 'syuilo', author: 'syuilo',
base: 'dark', base: 'dark',

View File

@ -1,7 +1,7 @@
{ {
id: 'c503d768-7c70-4db2-a4e6-08264304bc8d', id: 'c503d768-7c70-4db2-a4e6-08264304bc8d',
name: 'Persimmon Dark', name: 'Mi Persimmon Dark',
author: 'syuilo', author: 'syuilo',
base: 'dark', base: 'dark',

View File

@ -1,7 +1,7 @@
{ {
id: '7a5bc13b-df8f-4d44-8e94-4452f0c634bb', id: '7a5bc13b-df8f-4d44-8e94-4452f0c634bb',
base: 'dark', base: 'dark',
name: 'U0 Dark', name: 'Mi U0 Dark',
props: { props: {
X2: ':darken<2<@panel', X2: ':darken<2<@panel',
X3: 'rgba(255, 255, 255, 0.05)', X3: 'rgba(255, 255, 255, 0.05)',

View File

@ -1,7 +1,7 @@
{ {
id: '0ff48d43-aab3-46e7-ab12-8492110d2e2b', id: '0ff48d43-aab3-46e7-ab12-8492110d2e2b',
name: 'Apricot Light', name: 'Mi Apricot Light',
author: 'syuilo', author: 'syuilo',
base: 'light', base: 'light',

View File

@ -1,7 +1,7 @@
{ {
id: 'ac168876-f737-4074-a3fc-a370c732ef48', id: 'ac168876-f737-4074-a3fc-a370c732ef48',
name: 'Cherry Light', name: 'Mi Cherry Light',
author: 'syuilo', author: 'syuilo',
base: 'light', base: 'light',

View File

@ -1,7 +1,7 @@
{ {
id: '6ed80faa-74f0-42c2-98e4-a64d9e138eab', id: '6ed80faa-74f0-42c2-98e4-a64d9e138eab',
name: 'Coffee Light', name: 'Mi Coffee Light',
author: 'syuilo', author: 'syuilo',
base: 'light', base: 'light',

View File

@ -1,7 +1,7 @@
{ {
id: 'a58a0abb-ff8c-476a-8dec-0ad7837e7e96', id: 'a58a0abb-ff8c-476a-8dec-0ad7837e7e96',
name: 'Rainy Light', name: 'Mi Rainy Light',
author: 'syuilo', author: 'syuilo',
base: 'light', base: 'light',

View File

@ -1,7 +1,7 @@
{ {
id: '213273e5-7d20-d5f0-6e36-1b6a4f67115c', id: '213273e5-7d20-d5f0-6e36-1b6a4f67115c',
name: 'Sushi Light', name: 'Mi Sushi Light',
author: 'syuilo', author: 'syuilo',
base: 'light', base: 'light',

View File

@ -1,7 +1,7 @@
{ {
id: 'e2c940b5-6e9a-4c03-b738-261c720c426d', id: 'e2c940b5-6e9a-4c03-b738-261c720c426d',
base: 'light', base: 'light',
name: 'U0 Light', name: 'Mi U0 Light',
props: { props: {
X2: ':darken<2<@panel', X2: ':darken<2<@panel',
X3: 'rgba(255, 255, 255, 0.05)', X3: 'rgba(255, 255, 255, 0.05)',

View File

@ -1,7 +1,7 @@
{ {
id: '6128c2a9-5c54-43fe-a47d-17942356470b', id: '6128c2a9-5c54-43fe-a47d-17942356470b',
name: 'Vivid Light', name: 'Mi Vivid Light',
author: 'syuilo', author: 'syuilo',
base: 'light', base: 'light',