Compare commits
7 commits
develop
...
pyrox-aisc
Author | SHA1 | Date | |
---|---|---|---|
|
10b146fb2d | ||
|
07c80c6023 | ||
|
0fe9799a3e | ||
|
2eb71791fe | ||
|
00a3d18627 | ||
|
4c82b54686 | ||
|
2cc6276b3b |
165 changed files with 3551 additions and 3941 deletions
|
@ -10,7 +10,6 @@ packages/backend/.idea/vcs.xml
|
|||
|
||||
# Node.js
|
||||
node_modules
|
||||
**/node_modules
|
||||
report.*.json
|
||||
|
||||
# Cypress
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
- Rewrite backend in Rust and [Rocket](https://rocket.rs/)
|
||||
- Use [Magic RegExP](https://regexp.dev/) for RegEx 🦄
|
||||
- Function
|
||||
- Federate with note edits
|
||||
- User "choices" (recommended users) like Mastodon and Soapbox
|
||||
- Join Reason system like Mastodon/Pleroma
|
||||
- Option to publicize server blocks
|
||||
|
@ -123,8 +124,6 @@
|
|||
- Improve system emails
|
||||
- Mod mail
|
||||
- Focus trapping and button labels
|
||||
- Meilisearch with filters
|
||||
- Post editing
|
||||
|
||||
## Implemented (remote)
|
||||
|
||||
|
|
|
@ -27,8 +27,6 @@
|
|||
- Read **[this document](./CALCKEY.md)** all for current and future differences.
|
||||
- Notable differences:
|
||||
- Improved UI/UX (especially on mobile)
|
||||
- Post editing
|
||||
- Content importing
|
||||
- Improved notifications
|
||||
- Improved server security
|
||||
- Improved accessibility
|
||||
|
@ -39,7 +37,7 @@
|
|||
- Better intro tutorial
|
||||
- Compatibility with Mastodon clients/apps
|
||||
- Backfill user information
|
||||
- Advanced search
|
||||
- Sonic search
|
||||
- Many more user and admin settings
|
||||
- [So much more!](./CALCKEY.md)
|
||||
|
||||
|
@ -155,7 +153,7 @@ In Calckey's directory, fill out the `db` section of `.config/default.yml` with
|
|||
|
||||
### 🦔 Sonic
|
||||
|
||||
Sonic is better suited for self hosters with smaller deployments. It uses almost no resources, barely any any disk space, and is relatively fast.
|
||||
Sonic is better suited for self hosters with smaller deployments. It's easier to use, uses almost no resources, and takes barely any any disk space.
|
||||
|
||||
Follow sonic's [installation guide](https://github.com/valeriansaliou/sonic#installation)
|
||||
|
||||
|
@ -249,4 +247,4 @@ pm2 start "NODE_ENV=production pnpm run start" --name Calckey
|
|||
- Go back to Overview > click the clipboard icon next to the ID
|
||||
- Run `psql -d calckey` (or whatever the database name is)
|
||||
- Run `UPDATE "user" SET "isAdmin" = true WHERE id='999999';` (replace `999999` with the copied ID)
|
||||
- Restart your Calckey server
|
||||
- Have the new admin log out and log back in
|
||||
|
|
|
@ -68,5 +68,5 @@ body:
|
|||
options:
|
||||
- label: I agree to follow this project's Contribution Guidelines
|
||||
required: true
|
||||
- label: I have searched the issue tracker for similar issues, and this is not a duplicate.
|
||||
- label: I have searched the issue tracker for similar issues, and this is not a duplicate.
|
||||
required: true
|
||||
|
|
|
@ -40,6 +40,26 @@ body:
|
|||
placeholder: stop.voring.me
|
||||
validations:
|
||||
required: false
|
||||
- type: dropdown
|
||||
id: browsers
|
||||
attributes:
|
||||
label: What browser are you using?
|
||||
multiple: false
|
||||
options:
|
||||
- Firefox
|
||||
- Chrome
|
||||
- Brave
|
||||
- Librewolf
|
||||
- Chromium
|
||||
- Safari
|
||||
- Microsoft Edge
|
||||
- Other (Please Specify)
|
||||
- type: textarea
|
||||
id: logs
|
||||
attributes:
|
||||
label: Relevant log output
|
||||
description: Please copy and paste any relevant log output. You can find your log by inspecting the page, and going to the "console" tab. This will be automatically formatted into code, so no need for backticks.
|
||||
render: shell
|
||||
- type: checkboxes
|
||||
id: terms
|
||||
attributes:
|
||||
|
@ -48,5 +68,5 @@ body:
|
|||
options:
|
||||
- label: I agree to follow this project's Contribution Guidelines
|
||||
required: true
|
||||
- label: I have searched the issue tracker for similar requests, and this is not a duplicate.
|
||||
- label: I have searched the issue tracker for similar requests, and this is not a duplicate.
|
||||
required: true
|
||||
|
|
|
@ -1049,8 +1049,8 @@ _tutorial:
|
|||
step6_4: "Now go, explore, and have fun!"
|
||||
_2fa:
|
||||
alreadyRegistered: "سجلت سلفًا جهازًا للاستيثاق بعاملين."
|
||||
registerTOTP: "سجّل جهازًا جديدًا"
|
||||
registerSecurityKey: "تسجيل مفتاح أمان جديد"
|
||||
registerDevice: "سجّل جهازًا جديدًا"
|
||||
registerKey: "تسجيل مفتاح أمان جديد"
|
||||
step1: "أولًا ثبّت تطبيق استيثاق على جهازك (مثل {a} و{b})."
|
||||
step2: "امسح رمز الاستجابة السريعة الموجد على الشاشة."
|
||||
step3: "أدخل الرمز الموجود في تطبيقك لإكمال التثبيت."
|
||||
|
|
|
@ -1130,8 +1130,8 @@ _tutorial:
|
|||
step6_4: "Now go, explore, and have fun!"
|
||||
_2fa:
|
||||
alreadyRegistered: "আপনি ইতিমধ্যে একটি 2-ফ্যাক্টর অথেনটিকেশন ডিভাইস নিবন্ধন করেছেন৷"
|
||||
registerTOTP: "নতুন ডিভাইস নিবন্ধন করুন"
|
||||
registerSecurityKey: "সিকিউরিটি কী নিবন্ধন করুন"
|
||||
registerDevice: "নতুন ডিভাইস নিবন্ধন করুন"
|
||||
registerKey: "সিকিউরিটি কী নিবন্ধন করুন"
|
||||
step1: "প্রথমে, আপনার ডিভাইসে {a} বা {b} এর মতো একটি অথেনটিকেশন অ্যাপ ইনস্টল করুন৷"
|
||||
step2: "এরপরে, অ্যাপের সাহায্যে প্রদর্শিত QR কোডটি স্ক্যান করুন।"
|
||||
step2Url: "ডেস্কটপ অ্যাপে, নিম্নলিখিত URL লিখুন:"
|
||||
|
|
|
@ -136,7 +136,7 @@ smtpUser: "Nom d'usuari"
|
|||
smtpPass: "Contrasenya"
|
||||
user: "Usuari"
|
||||
searchByGoogle: "Cercar"
|
||||
file: "Fitxer"
|
||||
file: "Fitxers"
|
||||
_email:
|
||||
_follow:
|
||||
title: "Tens un nou seguidor"
|
||||
|
@ -228,11 +228,6 @@ _mfm:
|
|||
alwaysPlay: Reprodueix automàticament tots els MFM animats
|
||||
fade: Esvair
|
||||
fadeDescription: Esvaeix el contingut cap a dintre i cap en fora.
|
||||
crop: Retallar
|
||||
advanced: MFM avançat
|
||||
advancedDescription: Si està desactivat, només permet l'etiquetatge bàsic tret que
|
||||
es reproduïnt un MFM animat
|
||||
cropDescription: Retalla el contingut.
|
||||
_theme:
|
||||
keys:
|
||||
mention: "Menció"
|
||||
|
@ -319,40 +314,21 @@ _sfx:
|
|||
_2fa:
|
||||
step2Url: "També pots inserir aquest enllaç i utilitzes una aplicació d'escriptori:"
|
||||
alreadyRegistered: Ja heu registrat un dispositiu d'autenticació de dos factors.
|
||||
registerTOTP: Registrar un dispositiu nou
|
||||
registerDevice: Registrar un dispositiu nou
|
||||
securityKeyInfo: A més de l'autenticació d'empremta digital o PIN, també podeu configurar
|
||||
l'autenticació mitjançant claus de seguretat de maquinari compatibles amb FIDO2
|
||||
per protegir encara més el vostre compte.
|
||||
step4: A partir d'ara, qualsevol intent d'inici de sessió futur demanarà aquest
|
||||
token d'inici de sessió.
|
||||
registerSecurityKey: Registrar una clau de seguretat o d'accés
|
||||
registerKey: Registra una clau de seguretat
|
||||
step1: En primer lloc, instal·la una aplicació d'autenticació (com ara {a} o {b})
|
||||
al dispositiu.
|
||||
step2: A continuació, escaneja el codi QR que es mostra en aquesta pantalla.
|
||||
step3: Introdueix el token que t'ha proporcionat l'aplicació per finalitzar la configuració.
|
||||
step3Title: Introduïu un codi d'autenticació
|
||||
chromePasskeyNotSupported: Les claus de pas de Chrome actualment no s'admeten.
|
||||
securityKeyName: Introduïu un nom de clau
|
||||
removeKey: Suprimeix la clau de seguretat
|
||||
removeKeyConfirm: Vols suprimir la clau {name}?
|
||||
renewTOTP: Tornar a configurar l'aplicació d'autenticació
|
||||
renewTOTPOk: Reconfigurar
|
||||
renewTOTPCancel: Cancel·lar
|
||||
step2Click: Fer clic en aquest codi QR us permetrà registrar 2FA a la vostra clau
|
||||
de seguretat o aplicació d'autenticació del telèfon.
|
||||
securityKeyNotSupported: El vostre navegador no admet claus de seguretat.
|
||||
registerTOTPBeforeKey: Configureu una aplicació d'autenticació per registrar una
|
||||
clau de seguretat o de passi.
|
||||
tapSecurityKey: Si us plau, seguiu el vostre navegador per registrar la clau de
|
||||
seguretat o d'accés
|
||||
renewTOTPConfirm: Això farà que els codis de verificació de l'aplicació anterior
|
||||
deixin de funcionar
|
||||
whyTOTPOnlyRenew: L’aplicació d’autenticació no es pot eliminar sempre que es hi
|
||||
hagi una clau de seguretat registrada.
|
||||
_widgets:
|
||||
notifications: "Notificacions"
|
||||
timeline: "Línia de temps"
|
||||
unixClock: Rellotge d'UNIX
|
||||
unixClock: Rellotge UNIX
|
||||
federation: Federació
|
||||
instanceCloud: Núvol de servidors
|
||||
trends: Tendència
|
||||
|
@ -364,9 +340,9 @@ _widgets:
|
|||
onlineUsers: Usuaris en línia
|
||||
memo: Notes adhesives
|
||||
digitalClock: Rellotge digital
|
||||
postForm: Formulari per publicar
|
||||
postForm: Formulari de notes
|
||||
slideshow: Presentació de diapositives
|
||||
serverMetric: Estadístiques del servidor
|
||||
serverMetric: Mètriques del servidor
|
||||
userList: Llista d'usuaris
|
||||
rss: Lector d'RSS
|
||||
jobQueue: Cua de treball
|
||||
|
@ -374,10 +350,6 @@ _widgets:
|
|||
chooseList: Selecciona una llista
|
||||
aiscript: Consola AiScript
|
||||
button: Botó
|
||||
serverInfo: Informació del servidor
|
||||
meiliStatus: Estat del servidor
|
||||
meiliSize: Mida de l'índex
|
||||
meiliIndexCount: Publicacions indexades
|
||||
_cw:
|
||||
show: "Carregar més"
|
||||
files: '{count} fitxers'
|
||||
|
@ -753,9 +725,8 @@ _deck:
|
|||
mentions: "Mencions"
|
||||
widgets: Ginys
|
||||
main: Principal
|
||||
antenna: Antena
|
||||
antenna: Antenes
|
||||
direct: Missatges directes
|
||||
channel: Canal
|
||||
alwaysShowMainColumn: Mostra sempre la columna principal
|
||||
columnAlign: Alinear columnes
|
||||
introduction: Crea la interfície perfecta per a tu organitzant columnes lliurement!
|
||||
|
@ -1007,7 +978,7 @@ avoidMultiCaptchaConfirm: Fent servir diferents sistemes de Captcha pot causar i
|
|||
antennas: Antenes
|
||||
enableEmojiReactions: Activa reaccions amb emojis
|
||||
blockThisInstance: Bloqueja aquest servidor
|
||||
registration: Registra't
|
||||
registration: Registre
|
||||
showEmojisInReactionNotifications: Mostra els emojis a les notificacions de les reaccions
|
||||
renoteMute: Silencia els impulsos
|
||||
renoteUnmute: Treu el silenci als impulsos
|
||||
|
@ -1054,7 +1025,7 @@ recentlyRegisteredUsers: Usuaris registrats fa poc
|
|||
recentlyDiscoveredUsers: Nous suaris descoberts
|
||||
administrator: Administrador
|
||||
token: Token
|
||||
registerSecurityKey: Registreu una clau de seguretat
|
||||
registerSecurityKey: Registra una clau de seguretat
|
||||
securityKeyName: Nom clau
|
||||
lastUsed: Feta servir per última vegada
|
||||
unregister: Anul·lar el registre
|
||||
|
@ -1207,7 +1178,7 @@ large: Gran
|
|||
notificationSetting: Preferències de notificacions
|
||||
makeActive: Activar
|
||||
notificationSettingDesc: Tria el tipus de notificació que es veure.
|
||||
notifyAntenna: Notificar publicacions noves
|
||||
notifyAntenna: Notificar noves notes
|
||||
withFileAntenna: Només notes amb fitxers
|
||||
enableServiceworker: Activa les notificacions push per al teu navegador
|
||||
antennaUsersDescription: Escriu un nom d'usuari per línea
|
||||
|
@ -1647,7 +1618,7 @@ enableAutoSensitiveDescription: Permet la detecció i el marcatge automàtics de
|
|||
localOnly: Només local
|
||||
customKaTeXMacroDescription: "Configura macros per escriure expressions matemàtiques
|
||||
fàcilment! La notació s'ajusta a les definicions de l'ordre LaTeX i s'escriu com
|
||||
a \\newcommand{\\ name}{content} o \\newcommand{\\name}[nombre d'arguments]{content}.
|
||||
a \\newcommand{\\name}{content} o \\newcommand{\\name}[nombre d'arguments]{contingut}.
|
||||
Per exemple, \\newcommand{\\add}[2]{#1 + #2} ampliarà \\add{3}{foo} a 3 + foo. Els
|
||||
claudàtors que envolten el nom de la macro es poden canviar per claudàtors rodons
|
||||
o quadrats. Això afecta els claudàtors utilitzats per als arguments. Es pot definir
|
||||
|
@ -1706,10 +1677,10 @@ removeAllFollowing: Deixar de seguir a tots els usuaris que segueixes
|
|||
accentColor: Color principal
|
||||
textColor: Color del text
|
||||
value: Valor
|
||||
sendErrorReportsDescription: "Quan està activat, quan es produeixi un problema la
|
||||
informació detallada d'errors es compartirà amb Calckey, ajudant a millorar la qualitat
|
||||
de Calckey.\nAixò inclourà informació com la versió del vostre sistema operatiu,
|
||||
quin navegador utilitzeu, la vostra activitat a Calckey, etc."
|
||||
sendErrorReportsDescription: "Quant està activat quant aparegui un error, es compartirà
|
||||
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 fent
|
||||
servir, la teva activitat a Calckey, etc."
|
||||
myTheme: El meu tema
|
||||
backgroundColor: Color de fons
|
||||
saveAs: Desa com...
|
||||
|
@ -1786,7 +1757,7 @@ createNew: Crear una nova
|
|||
optional: Opcional
|
||||
jumpToSpecifiedDate: Vés a una data concreta
|
||||
showingPastTimeline: Ara es mostra un línea de temps antiga
|
||||
clear: Netejar
|
||||
clear: Tornar
|
||||
markAllAsRead: Marcar tot com a llegit
|
||||
recentPosts: Pàgines recents
|
||||
noMaintainerInformationWarning: La informació de l'administrador no està configurada.
|
||||
|
@ -1869,7 +1840,7 @@ _ago:
|
|||
hoursAgo: Fa {n}h
|
||||
daysAgo: Fa {n}d
|
||||
secondsAgo: Fa {n}s
|
||||
weeksAgo: Fa {n}set
|
||||
weeksAgo: Fa {n}s
|
||||
monthsAgo: Fa {n}me
|
||||
yearsAgo: Fa {n}a
|
||||
_time:
|
||||
|
@ -1884,7 +1855,7 @@ _tutorial:
|
|||
step5_3: La línea de temps d'inici {icon} es on pots veure les publicacions dels
|
||||
comptes que segueixes.
|
||||
step5_6: La línia de temps de Recomanats {icon} és on pots veure les publicacions
|
||||
dels servidors que recomanen els administradors.
|
||||
dels servidors recomanen els administradors.
|
||||
step5_7: La línia de temps Global {icon} és on pots veure les publicacions de tots
|
||||
els servidors connectats.
|
||||
step6_1: Aleshores, què és aquest lloc?
|
||||
|
@ -2060,7 +2031,7 @@ _relayStatus:
|
|||
rejected: Rebutjat
|
||||
deleted: Eliminat
|
||||
editNote: Edita la nota
|
||||
edited: 'Editat a {date} {time}'
|
||||
edited: Editat
|
||||
findOtherInstance: Cercar un altre servidor
|
||||
signupsDisabled: Actualment, les inscripcions en aquest servidor estan desactivades,
|
||||
però sempre podeu registrar-vos en un altre servidor. Si teniu un codi d'invitació
|
||||
|
@ -2082,12 +2053,7 @@ _experiments:
|
|||
enablePostEditing: Activà l'edició de publicacions
|
||||
title: Experiments
|
||||
postEditingCaption: Mostra l'opció perquè els usuaris editin les seves publicacions
|
||||
mitjançant el menú d'opcions de publicació, i permet rebre publicacions editades
|
||||
d'altres servidors.
|
||||
enablePostImports: Activar l'importació de publicacions
|
||||
postImportsCaption: Permet els usuaris importar publicacions desde comptes a Calckey,
|
||||
Misskey, Mastodon, Akkoma i Pleroma. Pot fer que el servidor vagi més lent durant
|
||||
la càrrega si tens un coll d'ampolla a la cua.
|
||||
existents mitjançant el menú d'opcions de publicació
|
||||
noGraze: Si us plau, desactiva l'extensió del navegador "Graze for Mastodon", ja que
|
||||
interfereix amb Calckey.
|
||||
accessibility: Accessibilitat
|
||||
|
@ -2098,36 +2064,3 @@ silencedWarning: S'està mostrant aquesta pàgina per què aquest usuari és d'u
|
|||
que l'administrador a silenciat, així que pot ser spam.
|
||||
jumpToPrevious: Vés a l'anterior
|
||||
cw: Avís de contingut
|
||||
antennasDesc: "Les antenes mostren publicacions noves que coincideixen amb els criteris
|
||||
establerts!\nS'hi pot accedir des de la pàgina de línies de temps."
|
||||
expandOnNoteClick: Obre la publicació amb un clic
|
||||
expandOnNoteClickDesc: Si està desactivat, encara pots obrir les publicacions al menú
|
||||
del botó dret o fent clic a la marca de temps.
|
||||
channelFederationWarn: Els canals encara no es federen amb altres servidors
|
||||
searchPlaceholder: Cerca a Calckey
|
||||
listsDesc: Les llistes et permeten crear línies de temps amb usuaris específics. Es
|
||||
pot accedir des de la pàgina de línies de temps.
|
||||
clipsDesc: Els clips són com marcadors categoritzats que es poden compartir. Podeu
|
||||
crear clips des del menú de publicacions individuals.
|
||||
selectChannel: Selecciona un canal
|
||||
isLocked: Aquest compte té les següents aprovacions
|
||||
isPatron: Mecenes de Calkey
|
||||
isBot: Aquest compte és un bot
|
||||
isModerator: Moderador
|
||||
isAdmin: Administrador
|
||||
_filters:
|
||||
fromDomain: Des del domini
|
||||
notesBefore: Publicacions anteriors
|
||||
notesAfter: Publicacions posteriors
|
||||
followingOnly: Només seguint
|
||||
followersOnly: Només seguidors
|
||||
withFile: Amb arxiu
|
||||
fromUser: De l'usuari
|
||||
image: Imatge
|
||||
video: Vídeo
|
||||
audio: Àudio
|
||||
_dialog:
|
||||
charactersExceeded: "S'han superat el màxim de caràcters! Actual: {current}/Límit:
|
||||
{max}"
|
||||
charactersBelow: 'No hi ha caràcters suficients! Corrent: {current}/Limit: {min}'
|
||||
removeReaction: Elimina la teva reacció
|
||||
|
|
|
@ -698,8 +698,8 @@ _time:
|
|||
minute: "Minut"
|
||||
hour: "Hodin"
|
||||
_2fa:
|
||||
registerTOTP: "Přidat zařízení"
|
||||
registerSecurityKey: "Přidat bezpečnostní klíč"
|
||||
registerDevice: "Přidat zařízení"
|
||||
registerKey: "Přidat bezpečnostní klíč"
|
||||
_weekday:
|
||||
sunday: "Neděle"
|
||||
monday: "Pondělí"
|
||||
|
@ -963,7 +963,7 @@ disablingTimelinesInfo: Administrátoři a moderátoři budou vždy mít příst
|
|||
časovým osám, i pokud jsou vypnuté.
|
||||
deleted: Vymazáno
|
||||
editNote: Upravit poznámku
|
||||
edited: 'Upraveno dne {date} {time}'
|
||||
edited: Upraveno
|
||||
silencedInstancesDescription: Vypište hostnames instancí, které chcete ztlumit. Účty
|
||||
v uvedených instancích jsou považovány za "ztlumené", mohou pouze zadávat požadavky
|
||||
na sledování a nemohou zmiňovat místní účty, pokud nejsou sledovány. Na blokované
|
||||
|
|
|
@ -83,7 +83,7 @@ deleteAndEditConfirm: Er du sikker på at du vil slet denne opslag og ændre det
|
|||
vil tabe alle reaktioner, forstærkninger og svarer indenfor denne opslag.
|
||||
editNote: Ændre note
|
||||
deleted: Slettet
|
||||
edited: 'Ændret den {date} {time}'
|
||||
edited: Ændret
|
||||
sendMessage: Send en besked
|
||||
youShouldUpgradeClient: Til at vise denne side, vær sød at refresh til at opdatere
|
||||
din brugerenhed.
|
||||
|
|
|
@ -663,7 +663,7 @@ display: "Anzeigeart"
|
|||
copy: "Kopieren"
|
||||
metrics: "Metriken"
|
||||
overview: "Übersicht"
|
||||
logs: "Protokolle"
|
||||
logs: "Logs"
|
||||
delayed: "Verzögert"
|
||||
database: "Datenbank"
|
||||
channel: "Channels"
|
||||
|
@ -812,7 +812,7 @@ useReactionPickerForContextMenu: "Reaktionsauswahl durch Rechtsklick öffnen"
|
|||
typingUsers: "{users} ist/sind am schreiben"
|
||||
jumpToSpecifiedDate: "Zu bestimmtem Datum springen"
|
||||
showingPastTimeline: "Es wird eine alte Timeline angezeigt"
|
||||
clear: "Leeren"
|
||||
clear: "Zurückkehren"
|
||||
markAllAsRead: "Alle als gelesen markieren"
|
||||
goBack: "Zurück"
|
||||
unlikeConfirm: "\"Gefällt mir\" wirklich entfernen?"
|
||||
|
@ -1189,8 +1189,6 @@ _mfm:
|
|||
stop: MFM anhalten
|
||||
warn: MFM können schnell bewegte oder anderweitig auffallende Animationen enthalten
|
||||
alwaysPlay: Alle animierten MFM immer automatisch abspielen
|
||||
advancedDescription: Wenn diese Funktion deaktiviert ist, können nur einfache Formatierungen
|
||||
vorgenommen werden, es sei denn, animiertes MFM ist aktiviert
|
||||
_instanceTicker:
|
||||
none: "Nie anzeigen"
|
||||
remote: "Für Nutzer eines anderen Servers anzeigen"
|
||||
|
@ -1358,8 +1356,8 @@ _tutorial:
|
|||
der/die auf diesem Server registriert ist."
|
||||
step5_5: "Die Social-Timeline {icon} ist eine Kombination aus der Home-Timeline
|
||||
und der Local-Timeline."
|
||||
step5_6: "In der Empfohlen-Timeline {icon} kannst du Posts sehen, die von den Admins
|
||||
vorgeschlagen wurden."
|
||||
step5_6: "In der {icon} \"Favoriten\"-Timeline können sie Beiträge von Servern sehen,
|
||||
die von den Server-Administratoren vorgeschlagen werden."
|
||||
step5_7: "In der {icon} Global-Timeline können Sie Beiträge von allen verknüpften
|
||||
Servern aus dem Fediverse sehen."
|
||||
step6_1: "Also, was ist das hier?"
|
||||
|
@ -1373,8 +1371,8 @@ _tutorial:
|
|||
_2fa:
|
||||
alreadyRegistered: "Du hast bereits ein Gerät für Zwei-Faktor-Authentifizierung
|
||||
registriert."
|
||||
registerTOTP: "Neues Gerät registrieren"
|
||||
registerSecurityKey: "Neuen Sicherheitsschlüssel registrieren"
|
||||
registerDevice: "Neues Gerät registrieren"
|
||||
registerKey: "Neuen Sicherheitsschlüssel registrieren"
|
||||
step1: "Installiere zuerst eine Authentifizierungsapp (z.B. {a} oder {b}) auf deinem
|
||||
Gerät."
|
||||
step2: "Dann, scanne den angezeigten QR-Code mit deinem Gerät."
|
||||
|
@ -1385,25 +1383,6 @@ _2fa:
|
|||
securityKeyInfo: "Du kannst neben Fingerabdruck- oder PIN-Authentifizierung auf
|
||||
deinem Gerät auch Anmeldung mit Hilfe eines FIDO2-kompatiblen Hardware-Sicherheitsschlüssels
|
||||
einrichten."
|
||||
step3Title: Gib deinen Authentifizierungscode ein
|
||||
renewTOTPOk: Neu konfigurieren
|
||||
securityKeyNotSupported: Dein Browser unterstützt Hardware-Security-Keys nicht.
|
||||
chromePasskeyNotSupported: Chrome Passkeys werden momentan nicht unterstützt.
|
||||
renewTOTP: Konfiguriere deine Authenticator App neu
|
||||
renewTOTPCancel: Abbrechen
|
||||
tapSecurityKey: Bitte folge den Anweisungen deines Browsers, um einen Hardware-Security-Key
|
||||
oder einen Passkey zu registrieren
|
||||
removeKey: Entferne deinen Hardware-Security-Key
|
||||
removeKeyConfirm: Möchtest du wirklich deinen Key mit der Bezeichnung {name} löschen?
|
||||
renewTOTPConfirm: Das wird dazu führen, dass du Verifizierungscodes deiner vorherigen
|
||||
Authenticator App nicht mehr nutzen kannst
|
||||
whyTOTPOnlyRenew: Die Authentificator App kann nicht entfernt werden, solange ein
|
||||
Hardware-Security-Key registriert ist.
|
||||
step2Click: Ein Klick auf diesen QR-Code erlaubt es dir eine 2FA-Methode zu deinem
|
||||
Security Key oder deiner Authenticator App hinzuzufügen.
|
||||
registerTOTPBeforeKey: Bitte registriere eine Authentificator App, um einen Hardware-Security-Key
|
||||
oder einen Passkey zu nutzen.
|
||||
securityKeyName: Gib einen Namen für den Key ein
|
||||
_permissions:
|
||||
"read:account": "Deine Nutzerkontoinformationen lesen"
|
||||
"write:account": "Deine Nutzerkontoinformationen bearbeiten"
|
||||
|
@ -1472,7 +1451,7 @@ _widgets:
|
|||
trends: "Trends"
|
||||
clock: "Uhr"
|
||||
rss: "RSS-Reader"
|
||||
rssTicker: "RSS Ticker"
|
||||
rssTicker: "RSS-Laufschrift (Ticker)"
|
||||
activity: "Aktivität"
|
||||
photos: "Fotos"
|
||||
digitalClock: "Digitaluhr"
|
||||
|
@ -1489,13 +1468,9 @@ _widgets:
|
|||
aichan: "Ai"
|
||||
_userList:
|
||||
chooseList: Wählen Sie eine Liste aus
|
||||
userList: Benutzerliste
|
||||
serverInfo: Server-Infos
|
||||
meiliStatus: Server-Status
|
||||
meiliSize: Indexgröße
|
||||
meiliIndexCount: Indexierte Beiträge
|
||||
userList: Nutzerliste
|
||||
_cw:
|
||||
hide: "Verbergen"
|
||||
hide: "Inhalt verbergen"
|
||||
show: "Inhalt anzeigen"
|
||||
chars: "{count} Zeichen"
|
||||
files: "{count} Datei(en)"
|
||||
|
@ -1954,11 +1929,10 @@ _deck:
|
|||
widgets: "Widgets"
|
||||
notifications: "Benachrichtigungen"
|
||||
tl: "Timeline"
|
||||
antenna: "Antenne"
|
||||
antenna: "News-Picker"
|
||||
list: "Listen"
|
||||
mentions: "Erwähnungen"
|
||||
direct: "Direktnachrichten"
|
||||
channel: Kanal
|
||||
renameProfile: Arbeitsbereich umbenennen
|
||||
nameAlreadyExists: Der Name für den Arbeitsbereich ist bereits vorhanden.
|
||||
enableRecommendedTimeline: '"Favoriten"-Timeline einschalten'
|
||||
|
@ -1993,7 +1967,7 @@ silencedInstancesDescription: Liste die Hostnamen der Server auf, die du stummsc
|
|||
wenn sie nicht gefolgt werden. Dies wirkt sich nicht auf die blockierten Server
|
||||
aus.
|
||||
editNote: Beitrag bearbeiten
|
||||
edited: 'Bearbeitet um {date} {time}'
|
||||
edited: Bearbeitet
|
||||
silenceThisInstance: Diesen Server stummschalten
|
||||
silencedInstances: Stummgeschaltete Server
|
||||
silenced: Stummgeschaltet
|
||||
|
@ -2099,15 +2073,11 @@ _experiments:
|
|||
title: Funktionstests
|
||||
postEditingCaption: Zeigt die Option für Nutzer an, ihre bestehenden Beiträge über
|
||||
das Menü "Beitragsoptionen" zu bearbeiten
|
||||
enablePostImports: Beitragsimporte aktivieren
|
||||
postImportsCaption: Erlaubt es Nutzer:innen ihre Posts von alten Calckey, Misskey,
|
||||
Mastodon, Akkoma und Pleroma Accounts zu importieren. Bei Engpässen in der Warteschlange
|
||||
kann es zu Verlangsamungen beim Laden während des Imports kommen.
|
||||
noGraze: Bitte deaktivieren Sie die Browsererweiterung "Graze for Mastodon", da sie
|
||||
die Funktion von Calckey stört.
|
||||
indexFrom: Indexieren ab Beitragskennung aufwärts
|
||||
indexNotice: Wird jetzt indexiert. Dies wird wahrscheinlich eine Weile dauern, bitte
|
||||
starten Sie Ihren Server für mindestens eine Stunde nicht neu.
|
||||
indexFrom: Indizieren ab Beitrags-ID (frei lassen, um jeden Beitrag zu indizieren)
|
||||
indexNotice: Indizierung gestartet. Dies wird wahrscheinlich eine Weile dauern. Bitte
|
||||
starte den Server für mindestens eine Stunde nicht neu.
|
||||
customKaTeXMacroDescription: "Richten Sie Makros ein, um mathematische Ausdrücke einfach
|
||||
zu schreiben! Die Notation entspricht den LaTeX-Befehlsdefinitionen und wird als\n
|
||||
\\newcommand{\\name}{content} or \\newcommand{\\name}[number of arguments]{content}\n
|
||||
|
@ -2119,35 +2089,3 @@ customKaTeXMacroDescription: "Richten Sie Makros ein, um mathematische Ausdrück
|
|||
Zeilen werden einfach ignoriert. Es werden nur einfache Funktionen zur Substitution
|
||||
von Zeichenketten unterstützt; erweiterte Syntax, wie z. B. bedingte Verzweigungen,
|
||||
können hier nicht verwendet werden."
|
||||
expandOnNoteClickDesc: Wenn deaktiviert, können Sie Beiträge trotzdem über das Rechtsklickmenü
|
||||
oder durch Anklicken des Zeitstempels öffnen.
|
||||
selectChannel: Wählen Sie einen Kanal aus
|
||||
expandOnNoteClick: Beitrag bei Klick öffnen
|
||||
image: Bild
|
||||
video: Video
|
||||
audio: Audio
|
||||
indexFromDescription: Leer lassen, um jeden Beitrag zu indexieren
|
||||
_filters:
|
||||
fromUser: Von Benutzer
|
||||
notesAfter: Beiträge nach
|
||||
withFile: Mit Datei
|
||||
fromDomain: Von Domain
|
||||
notesBefore: Beiträge vor
|
||||
followingOnly: Nur Folgende
|
||||
isBot: Dieses Konto ist ein Bot
|
||||
isModerator: Moderator
|
||||
isAdmin: Administrator
|
||||
_dialog:
|
||||
charactersExceeded: 'Maximale Anzahl an Zeichen aufgebraucht! Limit: {current} /
|
||||
{max}'
|
||||
charactersBelow: Nicht genug Zeichen! Du hast aktuell {current} von {min} Zeichen
|
||||
searchPlaceholder: Calckey durchsuchen
|
||||
antennasDesc: "Antennen zeigen neue Posts an, die deinen definierten Kriterien entsprechen!\n
|
||||
Sie können von der Timeline-Seite aufgerufen werden."
|
||||
isPatron: Calckey Patron
|
||||
removeReaction: Entferne deine Reaktion
|
||||
listsDesc: Listen lassen dich Timelines mit bestimmten Nutzer:innen erstellen. Sie
|
||||
können von der Timeline-Seite erreicht werden.
|
||||
clipsDesc: Clips sind wie teilbare, kategorisierte Lesezeichen. Du kannst Clips vom
|
||||
Menü individueller Posts aus erstellen.
|
||||
channelFederationWarn: Kanäle föderieren noch nicht zu anderen Servern
|
||||
|
|
|
@ -52,7 +52,7 @@ deleteAndEdit: "Delete and edit"
|
|||
deleteAndEditConfirm: "Are you sure you want to delete this post and edit it? You
|
||||
will lose all reactions, boosts and replies to it."
|
||||
editNote: "Edit note"
|
||||
edited: "Edited at {date} {time}"
|
||||
edited: "Edited"
|
||||
addToList: "Add to list"
|
||||
sendMessage: "Send a message"
|
||||
copyUsername: "Copy username"
|
||||
|
@ -123,7 +123,6 @@ clickToShow: "Click to show"
|
|||
sensitive: "NSFW"
|
||||
add: "Add"
|
||||
reaction: "Reactions"
|
||||
removeReaction: "Remove your reaction"
|
||||
enableEmojiReactions: "Enable emoji reactions"
|
||||
showEmojisInReactionNotifications: "Show emojis in reaction notifications"
|
||||
reactionSetting: "Reactions to show in the reaction picker"
|
||||
|
@ -148,7 +147,6 @@ unsuspendConfirm: "Are you sure that you want to unsuspend this account?"
|
|||
selectList: "Select a list"
|
||||
selectAntenna: "Select an antenna"
|
||||
selectWidget: "Select a widget"
|
||||
selectChannel: "Select a channel"
|
||||
editWidgets: "Edit widgets"
|
||||
editWidgetsExit: "Done"
|
||||
customEmojis: "Custom Emoji"
|
||||
|
@ -830,7 +828,7 @@ useReactionPickerForContextMenu: "Open reaction picker on right-click"
|
|||
typingUsers: "{users} is typing"
|
||||
jumpToSpecifiedDate: "Jump to specific date"
|
||||
showingPastTimeline: "Currently displaying an old timeline"
|
||||
clear: "Clear"
|
||||
clear: "Return"
|
||||
markAllAsRead: "Mark all as read"
|
||||
goBack: "Back"
|
||||
unlikeConfirm: "Really remove your like?"
|
||||
|
@ -969,9 +967,6 @@ rateLimitExceeded: "Rate limit exceeded"
|
|||
cropImage: "Crop image"
|
||||
cropImageAsk: "Do you want to crop this image?"
|
||||
file: "File"
|
||||
image: "Image"
|
||||
video: "Video"
|
||||
audio: "Audio"
|
||||
recentNHours: "Last {n} hours"
|
||||
recentNDays: "Last {n} days"
|
||||
noEmailServerWarning: "Email server not configured."
|
||||
|
@ -1104,11 +1099,6 @@ noGraze: "Please disable the \"Graze for Mastodon\" browser extension, as it int
|
|||
with Calckey."
|
||||
silencedWarning: "This page is showing because these users are from servers your admin
|
||||
silenced, so they may potentially be spam."
|
||||
isBot: "This account is a bot"
|
||||
isLocked: "This account has follow approvals"
|
||||
isModerator: "Moderator"
|
||||
isAdmin: "Administrator"
|
||||
isPatron: "Calckey Patron"
|
||||
|
||||
_sensitiveMediaDetection:
|
||||
description: "Reduces the effort of server moderation through automatically recognizing
|
||||
|
@ -1446,14 +1436,6 @@ _time:
|
|||
minute: "Minute(s)"
|
||||
hour: "Hour(s)"
|
||||
day: "Day(s)"
|
||||
_filters:
|
||||
fromUser: "From user"
|
||||
withFile: "With file"
|
||||
fromDomain: "From domain"
|
||||
notesBefore: "Posts before"
|
||||
notesAfter: "Posts after"
|
||||
followingOnly: "Following only"
|
||||
followersOnly: "Followers only"
|
||||
_tutorial:
|
||||
title: "How to use Calckey"
|
||||
step1_1: "Welcome!"
|
||||
|
@ -1488,28 +1470,16 @@ _tutorial:
|
|||
step6_4: "Now go, explore, and have fun!"
|
||||
_2fa:
|
||||
alreadyRegistered: "You have already registered a 2-factor authentication device."
|
||||
registerTOTP: "Register authenticator app"
|
||||
registerDevice: "Register a new device"
|
||||
registerKey: "Register a security key"
|
||||
step1: "First, install an authentication app (such as {a} or {b}) on your device."
|
||||
step2: "Then, scan the QR code displayed on this screen."
|
||||
step2Click: "Clicking on this QR code will allow you to register 2FA to your security key or phone authenticator app."
|
||||
step2Url: "You can also enter this URL if you're using a desktop program:"
|
||||
step3Title: "Enter an authentication code"
|
||||
step3: "Enter the token provided by your app to finish setup."
|
||||
step4: "From now on, any future login attempts will ask for such a login token."
|
||||
securityKeyNotSupported: "Your browser does not support security keys."
|
||||
registerTOTPBeforeKey: "Please set up an authenticator app to register a security or pass key."
|
||||
securityKeyInfo: "Besides fingerprint or PIN authentication, you can also setup authentication via hardware security keys that support FIDO2 to further secure your account."
|
||||
chromePasskeyNotSupported: "Chrome passkeys are currently not supported."
|
||||
registerSecurityKey: "Register a security or pass key"
|
||||
securityKeyName: "Enter a key name"
|
||||
tapSecurityKey: "Please follow your browser to register the security or pass key"
|
||||
removeKey: "Remove security key"
|
||||
removeKeyConfirm: "Really delete the {name} key?"
|
||||
whyTOTPOnlyRenew: "The authenticator app cannot be removed as long as a security key is registered."
|
||||
renewTOTP: "Reconfigure authenticator app"
|
||||
renewTOTPConfirm: "This will cause verification codes from your previous app to stop working"
|
||||
renewTOTPOk: "Reconfigure"
|
||||
renewTOTPCancel: "Cancel"
|
||||
securityKeyInfo: "Besides fingerprint or PIN authentication, you can also setup
|
||||
authentication via hardware security keys that support FIDO2 to further secure
|
||||
your account."
|
||||
_permissions:
|
||||
"read:account": "View your account information"
|
||||
"write:account": "Edit your account information"
|
||||
|
@ -2057,9 +2027,8 @@ _deck:
|
|||
widgets: "Widgets"
|
||||
notifications: "Notifications"
|
||||
tl: "Timeline"
|
||||
antenna: "Antenna"
|
||||
antenna: "Antennas"
|
||||
list: "List"
|
||||
channel: "Channel"
|
||||
mentions: "Mentions"
|
||||
direct: "Direct messages"
|
||||
_experiments:
|
||||
|
@ -2071,7 +2040,3 @@ _experiments:
|
|||
postImportsCaption: "Allows users to import their posts from past Calckey,\
|
||||
\ Misskey, Mastodon, Akkoma, and Pleroma accounts. It may cause slowdowns during\
|
||||
\ load if your queue is bottlenecked."
|
||||
|
||||
_dialog:
|
||||
charactersExceeded: "Max characters exceeded! Current: {current}/Limit: {max}"
|
||||
charactersBelow: "Not enough characters! Current: {current}/Limit: {min}"
|
||||
|
|
|
@ -1331,8 +1331,8 @@ _tutorial:
|
|||
step6_4: "¡Ahora ve, explora y diviértete!"
|
||||
_2fa:
|
||||
alreadyRegistered: "Ya has completado la configuración."
|
||||
registerTOTP: "Registrar dispositivo"
|
||||
registerSecurityKey: "Registrar clave"
|
||||
registerDevice: "Registrar dispositivo"
|
||||
registerKey: "Registrar clave"
|
||||
step1: "Primero, instale en su dispositivo la aplicación de autenticación {a} o\
|
||||
\ {b} u otra."
|
||||
step2: "Luego, escanee con la aplicación el código QR mostrado en pantalla."
|
||||
|
@ -1922,7 +1922,7 @@ apps: Aplicaciones
|
|||
migration: Migración
|
||||
silenced: Silenciado
|
||||
deleted: Eliminado
|
||||
edited: 'Editado a las {date} {time}'
|
||||
edited: Editado
|
||||
editNote: Editar nota
|
||||
silenceThisInstance: Silenciar esta instancia
|
||||
findOtherInstance: Buscar otro servidor
|
||||
|
|
|
@ -831,7 +831,7 @@ makeReactionsPublic: Aseta reaktiohistoria julkiseksi
|
|||
unread: Lukematon
|
||||
deleted: Poistettu
|
||||
editNote: Muokkaa viestiä
|
||||
edited: 'Muokattu klo {date} {time}'
|
||||
edited: Muokattu
|
||||
avoidMultiCaptchaConfirm: Useiden Captcha-järjestelmien käyttö voi aiheuttaa häiriöitä
|
||||
niiden välillä. Haluatko poistaa käytöstä muut tällä hetkellä käytössä olevat Captcha-järjestelmät?
|
||||
Jos haluat, että ne pysyvät käytössä, paina peruutusnäppäintä.
|
||||
|
|
|
@ -1262,8 +1262,8 @@ _tutorial:
|
|||
step6_4: "Maintenant, allez-y, explorez et amusez-vous !"
|
||||
_2fa:
|
||||
alreadyRegistered: "Configuration déjà achevée."
|
||||
registerTOTP: "Ajouter un nouvel appareil"
|
||||
registerSecurityKey: "Enregistrer une clef"
|
||||
registerDevice: "Ajouter un nouvel appareil"
|
||||
registerKey: "Enregistrer une clef"
|
||||
step1: "Tout d'abord, installez une application d'authentification, telle que {a}\
|
||||
\ ou {b}, sur votre appareil."
|
||||
step2: "Ensuite, scannez le code QR affiché sur l’écran."
|
||||
|
@ -2022,7 +2022,7 @@ silencedInstances: Instances silencieuses
|
|||
silenced: Silencieux
|
||||
deleted: Effacé
|
||||
editNote: Modifier note
|
||||
edited: 'Modifié à {date} {time}'
|
||||
edited: Modifié
|
||||
flagShowTimelineRepliesDescription: Si activé, affiche dans le fil les réponses des
|
||||
personnes aux publications des autres.
|
||||
_experiments:
|
||||
|
|
|
@ -1254,8 +1254,8 @@ _tutorial:
|
|||
step7_3: "Semoga berhasil dan bersenang-senanglah! \U0001F680"
|
||||
_2fa:
|
||||
alreadyRegistered: "Kamu telah mendaftarkan perangkat otentikasi dua faktor."
|
||||
registerTOTP: "Daftarkan perangkat baru"
|
||||
registerSecurityKey: "Daftarkan kunci keamanan baru"
|
||||
registerDevice: "Daftarkan perangkat baru"
|
||||
registerKey: "Daftarkan kunci keamanan baru"
|
||||
step1: "Pertama, pasang aplikasi otentikasi (seperti {a} atau {b}) di perangkat\
|
||||
\ kamu."
|
||||
step2: "Lalu, pindai kode QR yang ada di layar."
|
||||
|
|
113
locales/index.js
113
locales/index.js
|
@ -2,90 +2,59 @@
|
|||
* Languages Loader
|
||||
*/
|
||||
|
||||
const fs = require("fs");
|
||||
const yaml = require("js-yaml");
|
||||
const languages = [];
|
||||
const languages_custom = [];
|
||||
const fs = require('fs');
|
||||
const yaml = require('js-yaml');
|
||||
let languages = []
|
||||
let languages_custom = []
|
||||
|
||||
const merge = (...args) => args.reduce((a, c) => ({
|
||||
...a,
|
||||
...c,
|
||||
...Object.entries(a)
|
||||
.filter(([k]) => c && typeof c[k] === 'object')
|
||||
.reduce((a, [k, v]) => (a[k] = merge(v, c[k]), a), {})
|
||||
}), {});
|
||||
|
||||
const merge = (...args) =>
|
||||
args.reduce(
|
||||
(a, c) => ({
|
||||
...a,
|
||||
...c,
|
||||
...Object.entries(a)
|
||||
.filter(([k]) => c && typeof c[k] === "object")
|
||||
.reduce((a, [k, v]) => ((a[k] = merge(v, c[k])), a), {}),
|
||||
}),
|
||||
{},
|
||||
);
|
||||
|
||||
fs.readdirSync(__dirname).forEach((file) => {
|
||||
if (file.includes(".yml")) {
|
||||
file = file.slice(0, file.indexOf("."));
|
||||
if (file.includes('.yml')){
|
||||
file = file.slice(0, file.indexOf('.'))
|
||||
languages.push(file);
|
||||
}
|
||||
});
|
||||
})
|
||||
|
||||
fs.readdirSync(__dirname + "/../custom/locales").forEach((file) => {
|
||||
if (file.includes(".yml")) {
|
||||
file = file.slice(0, file.indexOf("."));
|
||||
fs.readdirSync(__dirname + '/../custom/locales').forEach((file) => {
|
||||
if (file.includes('.yml')){
|
||||
file = file.slice(0, file.indexOf('.'))
|
||||
languages_custom.push(file);
|
||||
}
|
||||
});
|
||||
})
|
||||
|
||||
const primaries = {
|
||||
en: "US",
|
||||
ja: "JP",
|
||||
zh: "CN",
|
||||
'en': 'US',
|
||||
'ja': 'JP',
|
||||
'zh': 'CN',
|
||||
};
|
||||
|
||||
// 何故か文字列にバックスペース文字が混入することがあり、YAMLが壊れるので取り除く
|
||||
const clean = (text) =>
|
||||
text.replace(new RegExp(String.fromCodePoint(0x08), "g"), "");
|
||||
const clean = (text) => text.replace(new RegExp(String.fromCodePoint(0x08), 'g'), '');
|
||||
|
||||
const locales = languages.reduce(
|
||||
(a, c) => (
|
||||
(a[c] =
|
||||
yaml.load(clean(fs.readFileSync(`${__dirname}/${c}.yml`, "utf-8"))) ||
|
||||
{}),
|
||||
a
|
||||
),
|
||||
{},
|
||||
);
|
||||
const locales_custom = languages_custom.reduce(
|
||||
(a, c) => (
|
||||
(a[c] =
|
||||
yaml.load(
|
||||
clean(
|
||||
fs.readFileSync(`${__dirname}/../custom/locales/${c}.yml`, "utf-8"),
|
||||
),
|
||||
) || {}),
|
||||
a
|
||||
),
|
||||
{},
|
||||
);
|
||||
Object.assign(locales, locales_custom);
|
||||
const locales = languages.reduce((a, c) => (a[c] = yaml.load(clean(fs.readFileSync(`${__dirname}/${c}.yml`, 'utf-8'))) || {}, a), {});
|
||||
const locales_custom = languages_custom.reduce((a, c) => (a[c] = yaml.load(clean(fs.readFileSync(`${__dirname}/../custom/locales/${c}.yml`, 'utf-8'))) || {}, a), {});
|
||||
Object.assign(locales, locales_custom)
|
||||
|
||||
module.exports = Object.entries(locales).reduce(
|
||||
(a, [k, v]) => (
|
||||
(a[k] = (() => {
|
||||
const [lang] = k.split("-");
|
||||
switch (k) {
|
||||
case "ja-JP":
|
||||
return v;
|
||||
case "ja-KS":
|
||||
case "en-US":
|
||||
return merge(locales["ja-JP"], v);
|
||||
default:
|
||||
return merge(
|
||||
locales["ja-JP"],
|
||||
locales["en-US"],
|
||||
locales[`${lang}-${primaries[lang]}`] || {},
|
||||
v,
|
||||
);
|
||||
}
|
||||
})()),
|
||||
a
|
||||
),
|
||||
{},
|
||||
);
|
||||
module.exports = Object.entries(locales)
|
||||
.reduce((a, [k ,v]) => (a[k] = (() => {
|
||||
const [lang] = k.split('-');
|
||||
switch (k) {
|
||||
case 'ja-JP': return v;
|
||||
case 'ja-KS':
|
||||
case 'en-US': return merge(locales['ja-JP'], v);
|
||||
default: return merge(
|
||||
locales['ja-JP'],
|
||||
locales['en-US'],
|
||||
locales[`${lang}-${primaries[lang]}`] || {},
|
||||
v
|
||||
);
|
||||
}
|
||||
})(), a), {});
|
||||
|
|
|
@ -1,10 +1,7 @@
|
|||
---
|
||||
_lang_: "Italiano"
|
||||
headlineMisskey: "Rete collegata tramite note"
|
||||
introMisskey: "Benvenut@! Calckey è un servizio di microblogging decentralizzato,
|
||||
libero e aperto. \nScrivi \"note\" per condividere ciò che sta succedendo adesso
|
||||
o per dire a tutti qualcosa di te. 📡\nGrazie alla funzione \"reazioni\" puoi anche
|
||||
mandare reazioni rapide alle note delle altre persone del Fediverso. 👍\nEsplora
|
||||
un nuovo mondo! 🚀"
|
||||
introMisskey: "Benvenut@! Calckey è un servizio di microblogging decentralizzato, libero e aperto. \nScrivi \"note\" per condividere ciò che sta succedendo adesso o per dire a tutti qualcosa di te. 📡\nGrazie alla funzione \"reazioni\" puoi anche mandare reazioni rapide alle note delle altre persone del Fediverso. 👍\nEsplora un nuovo mondo! 🚀"
|
||||
monthAndDay: "{day}/{month}"
|
||||
search: "Cerca"
|
||||
notifications: "Notifiche"
|
||||
|
@ -13,7 +10,7 @@ password: "Password"
|
|||
forgotPassword: "Hai dimenticato la tua password?"
|
||||
fetchingAsApObject: "Recuperando dal Fediverso"
|
||||
ok: "OK"
|
||||
gotIt: "Ho capito!"
|
||||
gotIt: "Ho capito"
|
||||
cancel: "Annulla"
|
||||
enterUsername: "Inserisci un nome utente"
|
||||
renotedBy: "Rinotato da {user}"
|
||||
|
@ -47,8 +44,7 @@ copyContent: "Copia il contenuto"
|
|||
copyLink: "Copia il link"
|
||||
delete: "Elimina"
|
||||
deleteAndEdit: "Elimina e modifica"
|
||||
deleteAndEditConfirm: "Vuoi davvero cancellare questa nota e scriverla di nuovo? Verrano
|
||||
eliminate anche tutte le reazioni, Rinote e risposte collegate."
|
||||
deleteAndEditConfirm: "Vuoi davvero cancellare questa nota e scriverla di nuovo? Verrano eliminate anche tutte le reazioni, Rinote e risposte collegate."
|
||||
addToList: "Aggiungi alla lista"
|
||||
sendMessage: "Invia messaggio"
|
||||
copyUsername: "Copia nome utente"
|
||||
|
@ -68,11 +64,9 @@ import: "Importa"
|
|||
export: "Esporta"
|
||||
files: "Allegati"
|
||||
download: "Scarica"
|
||||
driveFileDeleteConfirm: "Vuoi davvero eliminare il file「{name}? Anche gli allegati
|
||||
verranno eliminati."
|
||||
driveFileDeleteConfirm: "Vuoi davvero eliminare il file「{name}? Anche gli allegati verranno eliminati."
|
||||
unfollowConfirm: "Vuoi davvero smettere di seguire {name}?"
|
||||
exportRequested: "Hai richiesto un'esportazione, e potrebbe volerci tempo. Quando
|
||||
sarà compiuta, il file verrà aggiunto direttamente al Drive."
|
||||
exportRequested: "Hai richiesto un'esportazione, e potrebbe volerci tempo. Quando sarà compiuta, il file verrà aggiunto direttamente al Drive."
|
||||
importRequested: "Hai richiesto un'importazione. Può volerci tempo. "
|
||||
lists: "Liste"
|
||||
noLists: "Nessuna lista"
|
||||
|
@ -87,11 +81,9 @@ error: "Errore"
|
|||
somethingHappened: "Si è verificato un problema"
|
||||
retry: "Riprova"
|
||||
pageLoadError: "Caricamento pagina non riuscito. "
|
||||
pageLoadErrorDescription: "Questo viene normalmente causato dalla rete o dalla cache
|
||||
del browser. Si prega di pulire la cache, o di attendere e riprovare più tardi."
|
||||
pageLoadErrorDescription: "Questo viene normalmente causato dalla rete o dalla cache del browser. Si prega di pulire la cache, o di attendere e riprovare più tardi."
|
||||
serverIsDead: "Il server non risponde. Si prega di attendere e riprovare più tardi."
|
||||
youShouldUpgradeClient: "Per visualizzare la pagina è necessario aggiornare il client
|
||||
alla nuova versione e ricaricare."
|
||||
youShouldUpgradeClient: "Per visualizzare la pagina è necessario aggiornare il client alla nuova versione e ricaricare."
|
||||
enterListName: "Nome della lista"
|
||||
privacy: "Privacy"
|
||||
makeFollowManuallyApprove: "Richiedi di approvare i follower manualmente"
|
||||
|
@ -116,8 +108,7 @@ sensitive: "Contenuto sensibile"
|
|||
add: "Aggiungi"
|
||||
reaction: "Reazione"
|
||||
reactionSetting: "Reazioni visualizzate sul pannello"
|
||||
reactionSettingDescription2: "Trascina per riorganizzare, clicca per cancellare, usa
|
||||
il pulsante \"+\" per aggiungere."
|
||||
reactionSettingDescription2: "Trascina per riorganizzare, clicca per cancellare, usa il pulsante \"+\" per aggiungere."
|
||||
rememberNoteVisibility: "Ricordare le impostazioni di visibilità delle note"
|
||||
attachCancel: "Rimuovi allegato"
|
||||
markAsSensitive: "Segna come sensibile"
|
||||
|
@ -146,19 +137,12 @@ emojiUrl: "URL dell'emoji"
|
|||
addEmoji: "Aggiungi un emoji"
|
||||
settingGuide: "Configurazione suggerita"
|
||||
cacheRemoteFiles: "Memorizzazione nella cache dei file remoti"
|
||||
cacheRemoteFilesDescription: "Disabilitando questa opzione, i file remoti verranno
|
||||
linkati direttamente senza essere memorizzati nella cache. Sarà possibile risparmiare
|
||||
spazio di archiviazione sul server, ma il traffico aumenterà in quanto non verranno
|
||||
generate anteprime."
|
||||
cacheRemoteFilesDescription: "Disabilitando questa opzione, i file remoti verranno linkati direttamente senza essere memorizzati nella cache. Sarà possibile risparmiare spazio di archiviazione sul server, ma il traffico aumenterà in quanto non verranno generate anteprime."
|
||||
flagAsBot: "Io sono un robot"
|
||||
flagAsBotDescription: "Se l'account esegue principalmente operazioni automatiche,
|
||||
attiva quest'opzione. Quando attivata, opera come un segnalatore per gli altri sviluppatori
|
||||
allo scopo di prevenire catene d’interazione senza fine con altri bot, e di adeguare
|
||||
i sistemi interni di Calckey perché trattino questo account come un bot."
|
||||
flagAsBotDescription: "Se l'account esegue principalmente operazioni automatiche, attiva quest'opzione. Quando attivata, opera come un segnalatore per gli altri sviluppatori allo scopo di prevenire catene d’interazione senza fine con altri bot, e di adeguare i sistemi interni di Calckey perché trattino questo account come un bot."
|
||||
flagAsCat: "Io sono un gatto"
|
||||
flagAsCatDescription: "Abilita l'opzione \"Io sono un gatto\" per l'account."
|
||||
autoAcceptFollowed: "Accetta automaticamente le richieste di follow da utenti che
|
||||
già segui"
|
||||
autoAcceptFollowed: "Accetta automaticamente le richieste di follow da utenti che già segui"
|
||||
addAccount: "Aggiungi account"
|
||||
loginFailed: "Accesso non riuscito"
|
||||
showOnRemote: "Sfoglia sull'istanza remota"
|
||||
|
@ -170,10 +154,7 @@ searchWith: "Cerca: {q}"
|
|||
youHaveNoLists: "Non hai ancora creato nessuna lista"
|
||||
followConfirm: "Sei sicur@ di voler seguire {name}?"
|
||||
proxyAccount: "Account proxy"
|
||||
proxyAccountDescription: "Un account proxy è un account che funziona da follower remoto
|
||||
per gli utenti sotto certe condizioni. Ad esempio, quando un utente aggiunge un
|
||||
utente remoto alla lista, dato che se nessun utente locale segue quell'utente le
|
||||
sue attività non verranno distribuite, al suo posto lo seguirà un account proxy."
|
||||
proxyAccountDescription: "Un account proxy è un account che funziona da follower remoto per gli utenti sotto certe condizioni. Ad esempio, quando un utente aggiunge un utente remoto alla lista, dato che se nessun utente locale segue quell'utente le sue attività non verranno distribuite, al suo posto lo seguirà un account proxy."
|
||||
host: "Server remoto"
|
||||
selectUser: "Seleziona utente"
|
||||
recipient: "Destinatario"
|
||||
|
@ -203,13 +184,11 @@ instanceInfo: "Informazioni sull'istanza"
|
|||
statistics: "Statistiche"
|
||||
clearQueue: "Svuota coda"
|
||||
clearQueueConfirmTitle: "Vuoi davvero svuotare la coda?"
|
||||
clearQueueConfirmText: "Le note ancora non distribuite non verranno rilasciate. Solitamente,
|
||||
non è necessario eseguire questa operazione."
|
||||
clearQueueConfirmText: "Le note ancora non distribuite non verranno rilasciate. Solitamente, non è necessario eseguire questa operazione."
|
||||
clearCachedFiles: "Svuota cache"
|
||||
clearCachedFilesConfirm: "Vuoi davvero svuotare la cache da tutti i file remoti?"
|
||||
blockedInstances: "Istanze bloccate"
|
||||
blockedInstancesDescription: "Elenca le istanze che vuoi bloccare, una per riga. Esse
|
||||
non potranno più interagire con la tua istanza."
|
||||
blockedInstancesDescription: "Elenca le istanze che vuoi bloccare, una per riga. Esse non potranno più interagire con la tua istanza."
|
||||
muteAndBlock: "Silenziati / Bloccati"
|
||||
mutedUsers: "Account silenziati"
|
||||
blockedUsers: "Account bloccati"
|
||||
|
@ -271,8 +250,7 @@ agreeTo: "Sono d'accordo con {0}"
|
|||
tos: "Termini di servizio"
|
||||
start: "Inizia!"
|
||||
home: "Home"
|
||||
remoteUserCaution: "Può darsi che le informazioni siano incomplete perché questo è
|
||||
un utente remoto."
|
||||
remoteUserCaution: "Può darsi che le informazioni siano incomplete perché questo è un utente remoto."
|
||||
activity: "Attività"
|
||||
images: "Immagini"
|
||||
birthday: "Compleanno"
|
||||
|
@ -305,8 +283,7 @@ unableToDelete: "Eliminazione impossibile"
|
|||
inputNewFileName: "Inserisci nome del nuovo file"
|
||||
inputNewDescription: "Inserisci una nuova descrizione"
|
||||
inputNewFolderName: "Inserisci nome della nuova cartella"
|
||||
circularReferenceFolder: "La cartella di destinazione è una sottocartella della cartella
|
||||
che vuoi spostare."
|
||||
circularReferenceFolder: "La cartella di destinazione è una sottocartella della cartella che vuoi spostare."
|
||||
hasChildFilesOrFolders: "Impossibile eliminare la cartella perché non è vuota"
|
||||
copyUrl: "Copia URL"
|
||||
rename: "Modifica nome"
|
||||
|
@ -340,8 +317,7 @@ connectService: "Connessione"
|
|||
disconnectService: "Disconnessione "
|
||||
enableLocalTimeline: "Abilita Timeline locale"
|
||||
enableGlobalTimeline: "Abilita Timeline federata"
|
||||
disablingTimelinesInfo: "Anche se disabiliti queste timeline, gli amministratori e
|
||||
i moderatori potranno sempre accederci."
|
||||
disablingTimelinesInfo: "Anche se disabiliti queste timeline, gli amministratori e i moderatori potranno sempre accederci."
|
||||
registration: "Iscriviti"
|
||||
enableRegistration: "Permettere nuove registrazioni"
|
||||
invite: "Invita"
|
||||
|
@ -353,11 +329,9 @@ bannerUrl: "URL dell'immagine d'intestazione"
|
|||
backgroundImageUrl: "URL dello sfondo"
|
||||
basicInfo: "Informazioni fondamentali"
|
||||
pinnedUsers: "Utenti in evidenza"
|
||||
pinnedUsersDescription: "Elenca gli/le utenti che vuoi fissare in cima alla pagina
|
||||
\"Esplora\", un@ per riga."
|
||||
pinnedUsersDescription: "Elenca gli/le utenti che vuoi fissare in cima alla pagina \"Esplora\", un@ per riga."
|
||||
pinnedPages: "Pagine in evidenza"
|
||||
pinnedPagesDescription: "Specifica il percorso delle pagine che vuoi fissare in cima
|
||||
alla pagina dell'istanza. Una pagina per riga."
|
||||
pinnedPagesDescription: "Specifica il percorso delle pagine che vuoi fissare in cima alla pagina dell'istanza. Una pagina per riga."
|
||||
pinnedClipId: "ID della clip in evidenza"
|
||||
pinnedNotes: "Nota fissata"
|
||||
hcaptcha: "hCaptcha"
|
||||
|
@ -368,17 +342,14 @@ recaptcha: "reCAPTCHA"
|
|||
enableRecaptcha: "Abilita reCAPTCHA"
|
||||
recaptchaSiteKey: "Chiave del sito"
|
||||
recaptchaSecretKey: "Chiave segreta"
|
||||
avoidMultiCaptchaConfirm: "Utilizzare diversi Captcha può causare interferenze. Vuoi
|
||||
disattivare l'altro Captcha? Puoi lasciare diversi Captcha attivi premendo \"Cancella\"\
|
||||
."
|
||||
avoidMultiCaptchaConfirm: "Utilizzare diversi Captcha può causare interferenze. Vuoi disattivare l'altro Captcha? Puoi lasciare diversi Captcha attivi premendo \"Cancella\"."
|
||||
antennas: "Antenne"
|
||||
manageAntennas: "Gestore delle antenne"
|
||||
name: "Nome"
|
||||
antennaSource: "Fonte dell'antenna"
|
||||
antennaKeywords: "Parole chiavi da ricevere"
|
||||
antennaExcludeKeywords: "Parole chiavi da escludere"
|
||||
antennaKeywordsDescription: "Separare con uno spazio indica la condizione \"E\". Separare
|
||||
con un'interruzzione riga indica la condizione \"O\"."
|
||||
antennaKeywordsDescription: "Separare con uno spazio indica la condizione \"E\". Separare con un'interruzzione riga indica la condizione \"O\"."
|
||||
notifyAntenna: "Invia notifiche delle nuove note"
|
||||
withFileAntenna: "Solo note con file in allegato"
|
||||
enableServiceworker: "Abilita ServiceWorker"
|
||||
|
@ -506,26 +477,19 @@ showFeaturedNotesInTimeline: "Mostrare le note di tendenza nella tua timeline"
|
|||
objectStorage: "Stoccaggio oggetti"
|
||||
useObjectStorage: "Utilizza stoccaggio oggetti"
|
||||
objectStorageBaseUrl: "Base URL"
|
||||
objectStorageBaseUrlDesc: "URL di riferimento. In caso di utilizzo di proxy o CDN
|
||||
l'URL è 'https://<bucket>.s3.amazonaws.com' per S3, 'https://storage.googleapis.com/<bucket>'
|
||||
per GCS eccetera. "
|
||||
objectStorageBaseUrlDesc: "URL di riferimento. In caso di utilizzo di proxy o CDN l'URL è 'https://<bucket>.s3.amazonaws.com' per S3, 'https://storage.googleapis.com/<bucket>' per GCS eccetera. "
|
||||
objectStorageBucket: "Bucket"
|
||||
objectStorageBucketDesc: "Specificare il nome del bucket utilizzato dal provider."
|
||||
objectStoragePrefix: "Prefix"
|
||||
objectStoragePrefixDesc: "I file saranno conservati sotto la directory di questo prefisso."
|
||||
objectStorageEndpoint: "Endpoint"
|
||||
objectStorageEndpointDesc: "Lasciare vuoto se si sta utilizzando S3. In caso contrario
|
||||
si prega di specificare l'endpoint come '<host>' oppure '<host>:<port>' a seconda
|
||||
del servizio utilizzato."
|
||||
objectStorageEndpointDesc: "Lasciare vuoto se si sta utilizzando S3. In caso contrario si prega di specificare l'endpoint come '<host>' oppure '<host>:<port>' a seconda del servizio utilizzato."
|
||||
objectStorageRegion: "Region"
|
||||
objectStorageRegionDesc: "Specificate una regione, quale 'xx-east-1'. Se il servizio
|
||||
in utilizzo non distingue tra regioni, lasciate vuoto o inserite 'us-east-1'."
|
||||
objectStorageRegionDesc: "Specificate una regione, quale 'xx-east-1'. Se il servizio in utilizzo non distingue tra regioni, lasciate vuoto o inserite 'us-east-1'."
|
||||
objectStorageUseSSL: "Usare SSL"
|
||||
objectStorageUseSSLDesc: "Disabilita quest'opzione se non utilizzi HTTPS per le connessioni
|
||||
API."
|
||||
objectStorageUseSSLDesc: "Disabilita quest'opzione se non utilizzi HTTPS per le connessioni API."
|
||||
objectStorageUseProxy: "Usa proxy"
|
||||
objectStorageUseProxyDesc: "Disabilita quest'opzione se non usi proxy per la connessione
|
||||
API."
|
||||
objectStorageUseProxyDesc: "Disabilita quest'opzione se non usi proxy per la connessione API."
|
||||
objectStorageSetPublicRead: "Imposta \"visibilità pubblica\" al momento di caricare"
|
||||
serverLogs: "Log del server"
|
||||
deleteAll: "Cancella cronologia"
|
||||
|
@ -553,9 +517,7 @@ sort: "Ordina per"
|
|||
ascendingOrder: "Ascendente"
|
||||
descendingOrder: "Discendente"
|
||||
scratchpad: "ScratchPad"
|
||||
scratchpadDescription: "Lo Scratchpad offre un ambiente per esperimenti di AiScript.
|
||||
È possibile scrivere, eseguire e confermare i risultati dell'interazione del codice
|
||||
con Calckey."
|
||||
scratchpadDescription: "Lo Scratchpad offre un ambiente per esperimenti di AiScript. È possibile scrivere, eseguire e confermare i risultati dell'interazione del codice con Calckey."
|
||||
output: "Uscita"
|
||||
script: "Script"
|
||||
disablePagesScript: "Disabilita AiScript nelle pagine"
|
||||
|
@ -563,14 +525,11 @@ updateRemoteUser: "Aggiornare le informazioni di utente remot@"
|
|||
deleteAllFiles: "Elimina tutti i file"
|
||||
deleteAllFilesConfirm: "Vuoi davvero eliminare tutti i file?"
|
||||
removeAllFollowing: "Cancella tutti i follows"
|
||||
removeAllFollowingDescription: "Cancella tutti i follows del server {host}. Per favore,
|
||||
esegui se, ad esempio, l'istanza non esiste più."
|
||||
removeAllFollowingDescription: "Cancella tutti i follows del server {host}. Per favore, esegui se, ad esempio, l'istanza non esiste più."
|
||||
userSuspended: "L'utente è sospes@."
|
||||
userSilenced: "L'utente è silenziat@."
|
||||
yourAccountSuspendedTitle: "Questo account è sospeso."
|
||||
yourAccountSuspendedDescription: "Questo account è stato sospeso a causa di una violazione
|
||||
dei termini di servizio del server. Contattare l'amministrazione per i dettagli.
|
||||
Si prega di non creare un nuovo account."
|
||||
yourAccountSuspendedDescription: "Questo account è stato sospeso a causa di una violazione dei termini di servizio del server. Contattare l'amministrazione per i dettagli. Si prega di non creare un nuovo account."
|
||||
menu: "Menù"
|
||||
divider: "Linea di separazione"
|
||||
addItem: "Aggiungi elemento"
|
||||
|
@ -610,14 +569,12 @@ permission: "Autorizzazioni "
|
|||
enableAll: "Abilita tutto"
|
||||
disableAll: "Disabilita tutto"
|
||||
tokenRequested: "Autorizza accesso all'account"
|
||||
pluginTokenRequestedDescription: "Il plugin potrà utilizzare le autorizzazioni impostate
|
||||
qui."
|
||||
pluginTokenRequestedDescription: "Il plugin potrà utilizzare le autorizzazioni impostate qui."
|
||||
notificationType: "Tipo di notifiche"
|
||||
edit: "Modifica"
|
||||
emailServer: "Server email"
|
||||
enableEmail: "Abilita consegna email"
|
||||
emailConfigInfo: "Utilizzato per verificare il tuo indirizzo di posta elettronica
|
||||
e per reimpostare la tua password"
|
||||
emailConfigInfo: "Utilizzato per verificare il tuo indirizzo di posta elettronica e per reimpostare la tua password"
|
||||
email: "Email"
|
||||
emailAddress: "Indirizzo di posta elettronica"
|
||||
smtpConfig: "Impostazioni del server SMTP"
|
||||
|
@ -625,8 +582,7 @@ smtpHost: "Server remoto"
|
|||
smtpPort: "Porta"
|
||||
smtpUser: "Nome utente"
|
||||
smtpPass: "Password"
|
||||
emptyToDisableSmtpAuth: "Lasciare il nome utente e la password vuoti per disabilitare
|
||||
la verifica SMTP"
|
||||
emptyToDisableSmtpAuth: "Lasciare il nome utente e la password vuoti per disabilitare la verifica SMTP"
|
||||
smtpSecure: "Usare la porta SSL/TLS implicito per le connessioni SMTP"
|
||||
smtpSecureInfo: "Disabilitare quando è attivo STARTTLS."
|
||||
testEmail: "Testare la consegna di posta elettronica"
|
||||
|
@ -646,13 +602,10 @@ create: "Crea"
|
|||
notificationSetting: "Impostazioni notifiche"
|
||||
notificationSettingDesc: "Seleziona il tipo di notifiche da visualizzare."
|
||||
useGlobalSetting: "Usa impostazioni generali"
|
||||
useGlobalSettingDesc: "Se abilitato, le impostazioni notifiche dell'account verranno
|
||||
utilizzate. Se disabilitato, si possono definire diverse singole impostazioni."
|
||||
useGlobalSettingDesc: "Se abilitato, le impostazioni notifiche dell'account verranno utilizzate. Se disabilitato, si possono definire diverse singole impostazioni."
|
||||
other: "Avanzate"
|
||||
regenerateLoginToken: "Genera di nuovo un token di connessione"
|
||||
regenerateLoginTokenDescription: "Genera un nuovo token di autenticazione. Solitamente
|
||||
questa operazione non è necessaria: quando si genera un nuovo token, tutti i dispositivi
|
||||
vanno disconnessi."
|
||||
regenerateLoginTokenDescription: "Genera un nuovo token di autenticazione. Solitamente questa operazione non è necessaria: quando si genera un nuovo token, tutti i dispositivi vanno disconnessi."
|
||||
setMultipleBySeparatingWithSpace: "È possibile creare multiple voci separate da spazi."
|
||||
fileIdOrUrl: "ID o URL del file"
|
||||
behavior: "Comportamento"
|
||||
|
@ -660,8 +613,7 @@ sample: "Esempio"
|
|||
abuseReports: "Segnalazioni"
|
||||
reportAbuse: "Segnalazioni"
|
||||
reportAbuseOf: "Segnala {name}"
|
||||
fillAbuseReportDescription: "Si prega di spiegare il motivo della segnalazione. Se
|
||||
riguarda una nota precisa, si prega di collegare anche l'URL della nota."
|
||||
fillAbuseReportDescription: "Si prega di spiegare il motivo della segnalazione. Se riguarda una nota precisa, si prega di collegare anche l'URL della nota."
|
||||
abuseReported: "La segnalazione è stata inviata. Grazie."
|
||||
reporter: "il corrispondente"
|
||||
reporteeOrigin: "Origine del segnalato"
|
||||
|
@ -671,8 +623,7 @@ abuseMarkAsResolved: "Contrassegna la segnalazione come risolta"
|
|||
openInNewTab: "Apri in una nuova scheda"
|
||||
openInSideView: "Apri in vista laterale"
|
||||
defaultNavigationBehaviour: "Navigazione preimpostata"
|
||||
editTheseSettingsMayBreakAccount: "Modificare queste impostazioni può danneggiare
|
||||
l'account."
|
||||
editTheseSettingsMayBreakAccount: "Modificare queste impostazioni può danneggiare l'account."
|
||||
instanceTicker: "Informazioni sull'istanza da cui vengono le note"
|
||||
waitingFor: "Aspettando {x}"
|
||||
random: "Casuale"
|
||||
|
@ -684,8 +635,7 @@ createNew: "Crea nuov@"
|
|||
optional: "Opzionale"
|
||||
createNewClip: "Nuova clip"
|
||||
public: "Pubblica"
|
||||
i18nInfo: "Calckey è tradotto in diverse lingue da volontari. Anche tu puoi contribuire
|
||||
su {link}."
|
||||
i18nInfo: "Calckey è tradotto in diverse lingue da volontari. Anche tu puoi contribuire su {link}."
|
||||
manageAccessTokens: "Gestisci token di accesso"
|
||||
accountInfo: "Informazioni account"
|
||||
notesCount: "Conteggio note"
|
||||
|
@ -704,16 +654,12 @@ no: "No"
|
|||
driveFilesCount: "Numero di file nel Drive"
|
||||
driveUsage: "Utilizzazione del Drive"
|
||||
noCrawle: "Rifiuta l'indicizzazione dai robot."
|
||||
noCrawleDescription: "Richiedi che i motori di ricerca non indicizzino la tua pagina
|
||||
di profilo, le tue note, pagine, ecc."
|
||||
lockedAccountInfo: "A meno che non imposti la visibilità delle tue note su \"Solo
|
||||
ai follower\", le tue note sono visibili da tutti, anche se hai configurato l'account
|
||||
per confermare manualmente le richieste di follow."
|
||||
noCrawleDescription: "Richiedi che i motori di ricerca non indicizzino la tua pagina di profilo, le tue note, pagine, ecc."
|
||||
lockedAccountInfo: "A meno che non imposti la visibilità delle tue note su \"Solo ai follower\", le tue note sono visibili da tutti, anche se hai configurato l'account per confermare manualmente le richieste di follow."
|
||||
alwaysMarkSensitive: "Segnare i media come sensibili per impostazione predefinita"
|
||||
loadRawImages: "Visualizza le intere immagini allegate invece delle miniature."
|
||||
disableShowingAnimatedImages: "Disabilita le immagini animate"
|
||||
verificationEmailSent: "Una mail di verifica è stata inviata. Si prega di accedere
|
||||
al collegamento per compiere la verifica."
|
||||
verificationEmailSent: "Una mail di verifica è stata inviata. Si prega di accedere al collegamento per compiere la verifica."
|
||||
notSet: "Non impostato"
|
||||
emailVerified: "Il tuo indirizzo email è stato verificato"
|
||||
noteFavoritesCount: "Conteggio note tra i preferiti"
|
||||
|
@ -725,15 +671,13 @@ clips: "Clip"
|
|||
experimentalFeatures: "Funzioni sperimentali"
|
||||
developer: "Sviluppatore"
|
||||
makeExplorable: "Account visibile sulla pagina \"Esplora\""
|
||||
makeExplorableDescription: "Se disabiliti l'opzione, il tuo account non verrà visualizzato
|
||||
sulla pagina \"Esplora\"."
|
||||
makeExplorableDescription: "Se disabiliti l'opzione, il tuo account non verrà visualizzato sulla pagina \"Esplora\"."
|
||||
showGapBetweenNotesInTimeline: "Mostrare un intervallo tra le note sulla timeline"
|
||||
duplicate: "Duplica"
|
||||
left: "Sinistra"
|
||||
center: "Centro"
|
||||
wide: "Largo"
|
||||
reloadToApplySetting: "Le tue preferenze verranno impostate dopo il ricaricamento
|
||||
della pagina. Vuoi ricaricare adesso?"
|
||||
reloadToApplySetting: "Le tue preferenze verranno impostate dopo il ricaricamento della pagina. Vuoi ricaricare adesso?"
|
||||
needReloadToApply: "È necessario riavviare per rendere effettive le modifiche."
|
||||
showTitlebar: "Visualizza la barra del titolo"
|
||||
clearCache: "Svuota cache"
|
||||
|
@ -741,10 +685,7 @@ onlineUsersCount: "{n} utenti online"
|
|||
nUsers: "{n} utenti"
|
||||
nNotes: "{n}Note"
|
||||
sendErrorReports: "Invia segnalazioni di errori"
|
||||
sendErrorReportsDescription: "Quando abilitato, se si verifica un problema, informazioni
|
||||
dettagliate sugli errori verranno condivise con Calckey in modo da aiutare a migliorare
|
||||
la qualità del software.\nCiò include informazioni come la versione del sistema
|
||||
operativo, il tipo di navigatore web che usi, la cronologia delle attività, ecc."
|
||||
sendErrorReportsDescription: "Quando abilitato, se si verifica un problema, informazioni dettagliate sugli errori verranno condivise con Calckey in modo da aiutare a migliorare la qualità del software.\nCiò include informazioni come la versione del sistema operativo, il tipo di navigatore web che usi, la cronologia delle attività, ecc."
|
||||
myTheme: "I miei temi"
|
||||
backgroundColor: "Sfondo"
|
||||
textColor: "Testo"
|
||||
|
@ -770,8 +711,7 @@ receiveAnnouncementFromInstance: "Ricevi i messaggi informativi dall'istanza"
|
|||
emailNotification: "Eventi per notifiche via mail"
|
||||
publish: "Pubblico"
|
||||
inChannelSearch: "Cerca in canale"
|
||||
useReactionPickerForContextMenu: "Cliccare sul tasto destro per aprire il pannello
|
||||
di reazioni"
|
||||
useReactionPickerForContextMenu: "Cliccare sul tasto destro per aprire il pannello di reazioni"
|
||||
typingUsers: "{users} sta(nno) scrivendo"
|
||||
jumpToSpecifiedDate: "Vai alla data "
|
||||
showingPastTimeline: "Stai visualizzando una vecchia timeline"
|
||||
|
@ -782,17 +722,14 @@ unlikeConfirm: "Non ti piace più?"
|
|||
fullView: "Schermo intero"
|
||||
quitFullView: "Esci dalla modalità a schermo intero"
|
||||
addDescription: "Aggiungi descrizione"
|
||||
userPagePinTip: "Qui puoi appuntare note, premendo \"Fissa sul profilo\" nel menù
|
||||
delle singole note."
|
||||
notSpecifiedMentionWarning: "Sono menzionati account che non vengono inclusi fra i
|
||||
destinatari"
|
||||
userPagePinTip: "Qui puoi appuntare note, premendo \"Fissa sul profilo\" nel menù delle singole note."
|
||||
notSpecifiedMentionWarning: "Sono menzionati account che non vengono inclusi fra i destinatari"
|
||||
info: "Informazioni"
|
||||
userInfo: "Informazioni utente"
|
||||
unknown: "Sconosciuto"
|
||||
onlineStatus: "Stato di connessione"
|
||||
hideOnlineStatus: "Stato invisibile"
|
||||
hideOnlineStatusDescription: "Abilitare l'opzione di stato invisibile può guastare
|
||||
la praticità di singole funzioni, come la ricerca."
|
||||
hideOnlineStatusDescription: "Abilitare l'opzione di stato invisibile può guastare la praticità di singole funzioni, come la ricerca."
|
||||
online: "Online"
|
||||
active: "Attiv@"
|
||||
offline: "Offline"
|
||||
|
@ -840,9 +777,7 @@ whatIsNew: "Visualizza le informazioni sull'aggiornamento"
|
|||
translate: "Traduzione"
|
||||
translatedFrom: "Tradotto da {x}"
|
||||
accountDeletionInProgress: "La cancellazione dell'account è in corso"
|
||||
usernameInfo: "Un nome per identificare univocamente il tuo account sul server. È
|
||||
possibile utilizzare caratteri alfanumerici (a~z, A~Z, 0~9) e il trattino basso
|
||||
(_). Non sarà possibile cambiare il nome utente in seguito."
|
||||
usernameInfo: "Un nome per identificare univocamente il tuo account sul server. È possibile utilizzare caratteri alfanumerici (a~z, A~Z, 0~9) e il trattino basso (_). Non sarà possibile cambiare il nome utente in seguito."
|
||||
aiChanMode: "Modalità Ai"
|
||||
keepCw: "Mantieni il CW"
|
||||
resolved: "Risolto"
|
||||
|
@ -866,8 +801,7 @@ leaveGroup: "Esci dal gruppo"
|
|||
leaveGroupConfirm: "Uscire da「{name}」?"
|
||||
useDrawerReactionPickerForMobile: "Mostra sul drawer da dispositivo mobile"
|
||||
welcomeBackWithName: "Bentornato/a, {name}"
|
||||
clickToFinishEmailVerification: "Fai click su [{ok}] per completare la verifica dell'indirizzo
|
||||
email."
|
||||
clickToFinishEmailVerification: "Fai click su [{ok}] per completare la verifica dell'indirizzo email."
|
||||
searchByGoogle: "Cerca"
|
||||
indefinitely: "Non scade"
|
||||
tenMinutes: "10 minuti"
|
||||
|
@ -895,8 +829,7 @@ _signup:
|
|||
emailAddressInfo: "Inserisci il tuo indirizzo email. Non verrà reso pubblico."
|
||||
_accountDelete:
|
||||
accountDelete: "Cancellazione account"
|
||||
sendEmail: "Al termine della cancellazione dell'account, verrà inviata una mail
|
||||
all'indirizzo a cui era registrato."
|
||||
sendEmail: "Al termine della cancellazione dell'account, verrà inviata una mail all'indirizzo a cui era registrato."
|
||||
requestAccountDelete: "Richiesta di cancellazione account"
|
||||
started: "Il processo di cancellazione è iniziato."
|
||||
inProgress: "Cancellazione in corso"
|
||||
|
@ -904,13 +837,9 @@ _ad:
|
|||
back: "Indietro"
|
||||
reduceFrequencyOfThisAd: "Visualizza questa pubblicità meno spesso"
|
||||
_forgotPassword:
|
||||
enterEmail: "Inserisci l'indirizzo di posta elettronica che hai registrato nel tuo
|
||||
profilo. Il collegamento necessario per ripristinare la password verrà inviato
|
||||
a questo indirizzo."
|
||||
ifNoEmail: "Se nessun indirizzo e-mail è stato registrato, si prega di contattare
|
||||
l'amministratore·trice dell'istanza."
|
||||
contactAdmin: "Poiché questa istanza non permette l'utilizzo di una mail, si prega
|
||||
di contattare l'amministratore·trice dell'istanza per poter ripristinare la password."
|
||||
enterEmail: "Inserisci l'indirizzo di posta elettronica che hai registrato nel tuo profilo. Il collegamento necessario per ripristinare la password verrà inviato a questo indirizzo."
|
||||
ifNoEmail: "Se nessun indirizzo e-mail è stato registrato, si prega di contattare l'amministratore·trice dell'istanza."
|
||||
contactAdmin: "Poiché questa istanza non permette l'utilizzo di una mail, si prega di contattare l'amministratore·trice dell'istanza per poter ripristinare la password."
|
||||
_gallery:
|
||||
my: "Le mie pubblicazioni"
|
||||
liked: "Pubblicazioni che mi piacciono"
|
||||
|
@ -923,8 +852,7 @@ _email:
|
|||
title: "Hai ricevuto una richiesta di follow"
|
||||
_plugin:
|
||||
install: "Installa estensioni"
|
||||
installWarn: "Si prega di installare soltanto estensioni che provengono da fonti
|
||||
affidabili."
|
||||
installWarn: "Si prega di installare soltanto estensioni che provengono da fonti affidabili."
|
||||
manage: "Gestisci estensioni"
|
||||
_registry:
|
||||
key: "Dati"
|
||||
|
@ -938,8 +866,7 @@ _aboutMisskey:
|
|||
source: "Codice sorgente"
|
||||
translation: "Tradurre Calckey"
|
||||
donate: "Sostieni Calckey"
|
||||
morePatrons: "Apprezziamo sinceramente il supporto di tante altre persone. Grazie
|
||||
mille! 🥰"
|
||||
morePatrons: "Apprezziamo sinceramente il supporto di tante altre persone. Grazie mille! 🥰"
|
||||
patrons: "Sostenitori"
|
||||
_nsfw:
|
||||
respect: "Nascondere i media segnati come sensibli"
|
||||
|
@ -947,12 +874,10 @@ _nsfw:
|
|||
force: "Nascondere tutti i media"
|
||||
_mfm:
|
||||
cheatSheet: "Bigliettino MFM"
|
||||
intro: "MFM è un linguaggio Markdown particolare che si può usare in diverse parti
|
||||
di Calckey. Qui puoi visualizzare a colpo d'occhio tutta la sintassi MFM utile."
|
||||
intro: "MFM è un linguaggio Markdown particolare che si può usare in diverse parti di Calckey. Qui puoi visualizzare a colpo d'occhio tutta la sintassi MFM utile."
|
||||
dummy: "Il Fediverso si espande con Calckey"
|
||||
mention: "Menzioni"
|
||||
mentionDescription: "Si può menzionare un utente specifico digitando il suo nome
|
||||
utente subito dopo il segno @."
|
||||
mentionDescription: "Si può menzionare un utente specifico digitando il suo nome utente subito dopo il segno @."
|
||||
hashtag: "Hashtag"
|
||||
url: "URL"
|
||||
link: "Link"
|
||||
|
@ -979,8 +904,7 @@ _mfm:
|
|||
x4: "Estremamente più grande"
|
||||
x4Description: "Mostra il contenuto estremamente più ingrandito."
|
||||
blur: "Sfocatura"
|
||||
blurDescription: "È possibile rendere sfocato il contenuto. Spostando il cursore
|
||||
su di esso tornerà visibile chiaramente."
|
||||
blurDescription: "È possibile rendere sfocato il contenuto. Spostando il cursore su di esso tornerà visibile chiaramente."
|
||||
font: "Tipo di carattere"
|
||||
fontDescription: "Puoi scegliere il tipo di carattere per il contenuto."
|
||||
rainbow: "Arcobaleno"
|
||||
|
@ -1009,15 +933,10 @@ _menuDisplay:
|
|||
hide: "Nascondere"
|
||||
_wordMute:
|
||||
muteWords: "Parole da filtrare"
|
||||
muteWordsDescription: "Separare con uno spazio indica la condizione \"E\". Separare
|
||||
con un'interruzzione riga indica la condizione \"O\"."
|
||||
muteWordsDescription2: "Metti le parole chiavi tra slash per usare espressioni regolari
|
||||
(regexp)."
|
||||
softDescription: "Nascondi della timeline note che rispondono alle condizioni impostate
|
||||
qui."
|
||||
hardDescription: "Impedisci alla timeline di caricare le note che rispondono alle
|
||||
condizioni impostate qui. Inoltre, le note scompariranno in modo irreversibile,
|
||||
anche se le condizioni verranno successivamente rimosse."
|
||||
muteWordsDescription: "Separare con uno spazio indica la condizione \"E\". Separare con un'interruzzione riga indica la condizione \"O\"."
|
||||
muteWordsDescription2: "Metti le parole chiavi tra slash per usare espressioni regolari (regexp)."
|
||||
softDescription: "Nascondi della timeline note che rispondono alle condizioni impostate qui."
|
||||
hardDescription: "Impedisci alla timeline di caricare le note che rispondono alle condizioni impostate qui. Inoltre, le note scompariranno in modo irreversibile, anche se le condizioni verranno successivamente rimosse."
|
||||
soft: "Moderato"
|
||||
hard: "Severo"
|
||||
mutedNotes: "Note silenziate"
|
||||
|
@ -1111,35 +1030,24 @@ _tutorial:
|
|||
step1_1: "Benvenuto!"
|
||||
step1_2: "Vediamo di configurarla. Sarete operativi in men che non si dica!"
|
||||
step2_1: "Per prima cosa, compila il tuo profilo"
|
||||
step2_2: "Fornendo alcune informazioni su chi siete, sarà più facile per gli altri
|
||||
capire se vogliono vedere le vostre note o seguirvi"
|
||||
step2_2: "Fornendo alcune informazioni su chi siete, sarà più facile per gli altri capire se vogliono vedere le vostre note o seguirvi"
|
||||
step3_1: "Ora è il momento di seguire alcune persone!"
|
||||
step3_2: "La vostra home e le vostre timeline social si basano su chi seguite, quindi
|
||||
provate a seguire un paio di account per iniziare.\nCliccate sul cerchio più in
|
||||
alto a destra di un profilo per seguirlo"
|
||||
step3_2: "La vostra home e le vostre timeline social si basano su chi seguite, quindi provate a seguire un paio di account per iniziare.\nCliccate sul cerchio più in alto a destra di un profilo per seguirlo"
|
||||
step4_1: "Fatevi conoscere"
|
||||
step4_2: "Per il vostro primo post, alcuni preferiscono fare un post di {introduction}
|
||||
o un semplice \"Ciao mondo!\""
|
||||
step4_2: "Per il vostro primo post, alcuni preferiscono fare un post di {introduction} o un semplice \"Ciao mondo!\""
|
||||
step5_1: "Linee temporali, linee temporali dappertutto!"
|
||||
step5_2: "La tua istanza ha attivato {timelines} diverse timelines"
|
||||
step5_3: "La timeline Home {icon} è quella in cui si possono vedere i post dei propri
|
||||
follower"
|
||||
step5_4: "La timeline Locale {icon} è quella in cui si possono vedere i post di
|
||||
tutti gli altri utenti di questa istanza"
|
||||
step5_5: "La timeline Raccomandati {icon} è quella in cui si possono vedere i post
|
||||
delle istanze raccomandate dagli amministratori"
|
||||
step5_6: "La timeline Social {icon} è quella in cui si possono vedere i post degli
|
||||
amici dei propri follower"
|
||||
step5_7: "La timeline Globale {icon} è quella in cui si possono vedere i post di
|
||||
ogni altra istanza collegata"
|
||||
step5_3: "La timeline Home {icon} è quella in cui si possono vedere i post dei propri follower"
|
||||
step5_4: "La timeline Locale {icon} è quella in cui si possono vedere i post di tutti gli altri utenti di questa istanza"
|
||||
step5_5: "La timeline Raccomandati {icon} è quella in cui si possono vedere i post delle istanze raccomandate dagli amministratori"
|
||||
step5_6: "La timeline Social {icon} è quella in cui si possono vedere i post degli amici dei propri follower"
|
||||
step5_7: "La timeline Globale {icon} è quella in cui si possono vedere i post di ogni altra istanza collegata"
|
||||
step6_1: "Allora, cos'è questo posto?"
|
||||
step6_2: "Beh, non ti sei semplicemente unito a Calckey. Sei entrato in un portale
|
||||
del Fediverse, una rete interconnessa di migliaia di server, chiamata \"istanze\""
|
||||
step6_3: "Ogni server funziona in modo diverso, e non tutti i server eseguono Calckey.
|
||||
Questo però lo fa! È un po' complicato, ma ci riuscirete in poco tempo"
|
||||
step6_2: "Beh, non ti sei semplicemente unito a Calckey. Sei entrato in un portale del Fediverse, una rete interconnessa di migliaia di server, chiamata \"istanze\""
|
||||
step6_3: "Ogni server funziona in modo diverso, e non tutti i server eseguono Calckey. Questo però lo fa! È un po' complicato, ma ci riuscirete in poco tempo"
|
||||
step6_4: "Ora andate, esplorate e divertitevi!"
|
||||
_2fa:
|
||||
registerTOTP: "Aggiungi dispositivo"
|
||||
registerDevice: "Aggiungi dispositivo"
|
||||
_permissions:
|
||||
"read:account": "Visualizzare le informazioni dell'account"
|
||||
"write:account": "Modificare le informazioni dell'account"
|
||||
|
@ -1265,8 +1173,7 @@ _profile:
|
|||
youCanIncludeHashtags: "Puoi anche includere hashtag."
|
||||
metadata: "Informazioni aggiuntive"
|
||||
metadataEdit: "Modifica informazioni aggiuntive"
|
||||
metadataDescription: "Puoi pubblicare fino a quattro informazioni aggiuntive sul
|
||||
profilo."
|
||||
metadataDescription: "Puoi pubblicare fino a quattro informazioni aggiuntive sul profilo."
|
||||
metadataLabel: "Etichetta"
|
||||
metadataContent: "Contenuto"
|
||||
changeAvatar: "Modifica immagine profilo"
|
||||
|
@ -1558,4 +1465,3 @@ _deck:
|
|||
list: "Liste"
|
||||
mentions: "Menzioni"
|
||||
direct: "Diretta"
|
||||
noThankYou: No grazie
|
||||
|
|
|
@ -133,7 +133,6 @@ unsuspendConfirm: "解凍しますか?"
|
|||
selectList: "リストを選択"
|
||||
selectAntenna: "アンテナを選択"
|
||||
selectWidget: "ウィジェットを選択"
|
||||
selectChannel: "チャンネルを選択"
|
||||
editWidgets: "ウィジェットを編集"
|
||||
editWidgetsExit: "編集を終了"
|
||||
customEmojis: "カスタム絵文字"
|
||||
|
@ -723,8 +722,7 @@ onlineUsersCount: "{n}人がオンライン"
|
|||
nUsers: "{n}ユーザー"
|
||||
nNotes: "{n}投稿"
|
||||
sendErrorReports: "エラーリポートを送信"
|
||||
sendErrorReportsDescription: "オンにすると、問題が発生したときにエラーの詳細情報がCalckeyに共有され、ソフトウェアの品質向上に役立てられます。\n\
|
||||
エラー情報には、OSのバージョン、ブラウザの種類、行動履歴などが含まれます。"
|
||||
sendErrorReportsDescription: "オンにすると、問題が発生したときにエラーの詳細情報がCalckeyに共有され、ソフトウェアの品質向上に役立てられます。エラー情報には、OSのバージョン、ブラウザの種類、行動履歴などが含まれます。"
|
||||
myTheme: "マイテーマ"
|
||||
backgroundColor: "背景"
|
||||
accentColor: "アクセント"
|
||||
|
@ -1146,10 +1144,6 @@ _mfm:
|
|||
foregroundDescription: 文字の色を変更します。
|
||||
fade: フェード
|
||||
fadeDescription: フェードインとフェードアウトする。
|
||||
crop: 切り抜き
|
||||
cropDescription: 内容を切り抜く。
|
||||
advancedDescription: オフにすると、アニメーション再生中を除いて基本的なMFMだけ表示します。
|
||||
advanced: 高度なMFM
|
||||
_instanceTicker:
|
||||
none: "表示しない"
|
||||
remote: "リモートユーザーに表示"
|
||||
|
@ -1314,28 +1308,14 @@ _tutorial:
|
|||
step6_4: "これで完了です。お楽しみください!"
|
||||
_2fa:
|
||||
alreadyRegistered: "既に設定は完了しています。"
|
||||
registerTOTP: "認証アプリの設定を開始"
|
||||
registerDevice: "デバイスを登録"
|
||||
registerKey: "キーを登録"
|
||||
step1: "まず、{a}や{b}などの認証アプリをお使いのデバイスにインストールします。"
|
||||
step2: "次に、表示されているQRコードをアプリでスキャンします。"
|
||||
step2Click: "QRコードをクリックすると、お使いの端末にインストールされている認証アプリやキーリングに登録できます。"
|
||||
step2Url: "デスクトップアプリでは次のURIを入力します:"
|
||||
step3Title: "確認コードを入力"
|
||||
step3: "アプリに表示されている確認コード(トークン)を入力して完了です。"
|
||||
step4: "これからログインするときも、同じように確認コードを入力します。"
|
||||
securityKeyNotSupported: "お使いのブラウザはセキュリティキーに対応していません。"
|
||||
registerTOTPBeforeKey: "セキュリティキー・パスキーを登録するには、まず認証アプリの設定を行なってください。"
|
||||
securityKeyInfo: "FIDO2をサポートするハードウェアセキュリティキー、端末の生体認証やPINロック、パスキーといった、WebAuthn由来の鍵を登録します。"
|
||||
chromePasskeyNotSupported: "Chromeのパスキーは現在サポートしていません。"
|
||||
registerSecurityKey: "セキュリティキー・パスキーを登録する"
|
||||
securityKeyName: "キーの名前を入力"
|
||||
tapSecurityKey: "ブラウザの指示に従い、セキュリティキーやパスキーを登録してください"
|
||||
removeKey: "セキュリティキーを削除"
|
||||
removeKeyConfirm: "{name}を削除しますか?"
|
||||
whyTOTPOnlyRenew: "セキュリティキーが登録されている場合、認証アプリの設定は解除できません。"
|
||||
renewTOTP: "認証アプリを再設定"
|
||||
renewTOTPConfirm: "今までの認証アプリの確認コードは使用できなくなります"
|
||||
renewTOTPOk: "再設定する"
|
||||
renewTOTPCancel: "やめておく"
|
||||
step2Url: "デスクトップアプリでは次のURLを入力します:"
|
||||
step3: "アプリに表示されているトークンを入力して完了です。"
|
||||
step4: "これからログインするときも、同じようにトークンを入力します。"
|
||||
securityKeyInfo: "FIDO2をサポートするハードウェアセキュリティキーもしくは端末の指紋認証やPINを使用してログインするように設定できます。"
|
||||
_permissions:
|
||||
"read:account": "アカウントの情報を見る"
|
||||
"write:account": "アカウントの情報を変更する"
|
||||
|
@ -1417,10 +1397,6 @@ _widgets:
|
|||
userList: "ユーザーリスト"
|
||||
_userList:
|
||||
chooseList: "リストを選択"
|
||||
meiliStatus: サーバーステータス
|
||||
serverInfo: サーバー情報
|
||||
meiliSize: インデックスサイズ
|
||||
meiliIndexCount: インデックス済みの投稿
|
||||
_cw:
|
||||
hide: "隠す"
|
||||
show: "もっと見る"
|
||||
|
@ -1878,7 +1854,6 @@ _deck:
|
|||
tl: "タイムライン"
|
||||
antenna: "アンテナ"
|
||||
list: "リスト"
|
||||
channel: "チャンネル"
|
||||
mentions: "あなた宛て"
|
||||
direct: "ダイレクト"
|
||||
noteId: 投稿のID
|
||||
|
@ -1888,15 +1863,12 @@ apps: "アプリ"
|
|||
_experiments:
|
||||
enablePostEditing: 投稿の編集機能を有効にする
|
||||
title: 試験的な機能
|
||||
postEditingCaption: 投稿のメニューに既存の投稿を編集するボタンを表示し、他サーバーの編集も受信できるようにします。
|
||||
postImportsCaption:
|
||||
ユーザーが過去の投稿をCalckey・Misskey・Mastodon・Akkoma・Pleromaからインポートすることを許可します。キューが溜まっているときにインポートするとサーバーに負荷がかかる可能性があります。
|
||||
enablePostImports: 投稿のインポートを有効にする
|
||||
sendModMail: モデレーション通知を送る
|
||||
postEditingCaption: 投稿のメニューに既存の投稿を編集するボタンを表示します。
|
||||
sendModMail: モデレーションノートを送る
|
||||
deleted: 削除済み
|
||||
editNote: 投稿を編集
|
||||
edited: '編集済み: {date} {time}'
|
||||
signupsDisabled:
|
||||
edited: 編集済み
|
||||
signupsDisabled:
|
||||
現在、このサーバーでは新規登録が一般開放されていません。招待コードをお持ちの場合には、以下の欄に入力してください。招待コードをお持ちでない場合にも、新規登録を開放している他のサーバーには入れますよ!
|
||||
findOtherInstance: 他のサーバーを探す
|
||||
newer: 新しい投稿
|
||||
|
@ -1905,29 +1877,3 @@ accessibility: アクセシビリティ
|
|||
jumpToPrevious: 前に戻る
|
||||
cw: 閲覧注意
|
||||
silencedWarning: スパムの可能性があるため、これらのユーザーが所属するサーバーは管理者によりサイレンスされています。
|
||||
searchPlaceholder: Calckeyを検索
|
||||
channelFederationWarn: 現時点では、チャンネルは他のサーバーへ連合しません
|
||||
listsDesc: リストでは指定したユーザーだけのタイムラインを作れます。リストには「タイムライン」のページからアクセスできます。
|
||||
antennasDesc: "アンテナでは指定した条件に合致する投稿が表示されます。\nアンテナには「タイムライン」のページからアクセスできます。"
|
||||
expandOnNoteClickDesc: オフの場合、右クリックメニューか日付をクリックすることで開けます。
|
||||
expandOnNoteClick: クリックで投稿の詳細を開く
|
||||
clipsDesc: クリップは分類と共有ができるブックマークです。各投稿のメニューからクリップを作成できます。
|
||||
_dialog:
|
||||
charactersExceeded: "最大文字数を超えています! 現在 {current} / 制限 {max}"
|
||||
charactersBelow: "最小文字数を下回っています! 現在 {current} / 制限 {min}"
|
||||
_filters:
|
||||
followersOnly: フォロワーのみ
|
||||
fromUser: ユーザーを指定
|
||||
withFile: 添付ファイルあり
|
||||
fromDomain: ドメインを指定
|
||||
notesBefore: 指定の日付以前
|
||||
notesAfter: 指定の日付以降
|
||||
followingOnly: フォロー中のみ
|
||||
isModerator: モデレーター
|
||||
audio: 音声
|
||||
image: 画像
|
||||
video: 動画
|
||||
isBot: このアカウントはBotです
|
||||
isLocked: このアカウントのフォローは承認制です
|
||||
isAdmin: 管理者
|
||||
isPatron: Calckey 後援者
|
||||
|
|
|
@ -1179,8 +1179,8 @@ _time:
|
|||
day: "일"
|
||||
_2fa:
|
||||
alreadyRegistered: "이미 설정이 완료되었습니다."
|
||||
registerTOTP: "디바이스 등록"
|
||||
registerSecurityKey: "키를 등록"
|
||||
registerDevice: "디바이스 등록"
|
||||
registerKey: "키를 등록"
|
||||
step1: "먼저, {a}나 {b}등의 인증 앱을 사용 중인 디바이스에 설치합니다."
|
||||
step2: "그 후, 표시되어 있는 QR코드를 앱으로 스캔합니다."
|
||||
step2Url: "데스크톱 앱에서는 다음 URL을 입력하세요:"
|
||||
|
|
|
@ -413,7 +413,7 @@ selectList: Selecteer een lijst
|
|||
selectAntenna: Selecteer een antenne
|
||||
deleted: Verwijderd
|
||||
editNote: Bewerk notitie
|
||||
edited: 'Bewerkt om {date} {time}'
|
||||
edited: Bewerkt
|
||||
emojis: Emojis
|
||||
emojiName: Emoji naam
|
||||
emojiUrl: Emoji URL
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
_lang_: "Polski"
|
||||
headlineMisskey: "Otwartoźródłowa, zdecentralizowana sieć społecznościowa, która zawsze
|
||||
będzie darmowa! 🚀"
|
||||
introMisskey: "Hej! Calckey to otwartoźródłowa oraz zdecentralizowana sieć społecznościowa,
|
||||
która zawsze będzie darmowa! 🚀"
|
||||
headlineMisskey: "Otwartoźródłowa, zdecentralizowana sieć społecznościowa, która zawsze\
|
||||
\ będzie darmowa! \U0001F680"
|
||||
introMisskey: "Hej! Calckey to otwartoźródłowa oraz zdecentralizowana sieć społecznościowa,\
|
||||
\ która zawsze będzie darmowa! \U0001F680"
|
||||
monthAndDay: "{month}-{day}"
|
||||
search: "Szukaj"
|
||||
notifications: "Powiadomienia"
|
||||
|
@ -17,7 +17,7 @@ enterUsername: "Wprowadź nazwę użytkownika"
|
|||
renotedBy: "Podbito przez {user}"
|
||||
noNotes: "Brak wpisów"
|
||||
noNotifications: "Brak powiadomień"
|
||||
instance: "Serwer"
|
||||
instance: "Instancja"
|
||||
settings: "Ustawienia"
|
||||
basicSettings: "Podstawowe ustawienia"
|
||||
otherSettings: "Pozostałe ustawienia"
|
||||
|
@ -45,8 +45,8 @@ copyContent: "Skopiuj zawartość"
|
|||
copyLink: "Skopiuj odnośnik"
|
||||
delete: "Usuń"
|
||||
deleteAndEdit: "Usuń i edytuj"
|
||||
deleteAndEditConfirm: "Czy na pewno chcesz usunąć ten wpis i zedytować go? Utracisz
|
||||
wszystkie reakcje, podbicia i odpowiedzi do tego wpisu."
|
||||
deleteAndEditConfirm: "Czy na pewno chcesz usunąć ten wpis i zedytować go? Utracisz\
|
||||
\ wszystkie reakcje, podbicia i odpowiedzi do tego wpisu."
|
||||
addToList: "Dodaj do listy"
|
||||
sendMessage: "Wyślij wiadomość"
|
||||
copyUsername: "Kopiuj nazwę użytkownika"
|
||||
|
@ -66,11 +66,11 @@ import: "Importuj"
|
|||
export: "Eksportuj"
|
||||
files: "Pliki"
|
||||
download: "Pobierz"
|
||||
driveFileDeleteConfirm: "Czy chcesz usunąć plik \"{name}\"? Wszystkie wpisy zawierające
|
||||
ten plik również zostaną usunięte."
|
||||
driveFileDeleteConfirm: "Czy chcesz usunąć plik \"{name}\"? Wszystkie wpisy zawierające\
|
||||
\ ten plik również zostaną usunięte."
|
||||
unfollowConfirm: "Czy na pewno chcesz przestać obserwować {name}?"
|
||||
exportRequested: "Zażądałeś eksportu. Może to zająć chwilę. Po zakończeniu eksportu
|
||||
zostanie on dodany do Twojego dysku."
|
||||
exportRequested: "Zażądałeś eksportu. Może to zająć chwilę. Po zakończeniu eksportu\
|
||||
\ zostanie on dodany do Twojego dysku."
|
||||
importRequested: "Zażądano importu. Może to zająć chwilę."
|
||||
lists: "Listy"
|
||||
noLists: "Nie masz żadnych list"
|
||||
|
@ -85,8 +85,8 @@ error: "Błąd"
|
|||
somethingHappened: "Coś poszło nie tak"
|
||||
retry: "Spróbuj ponownie"
|
||||
pageLoadError: "Nie udało się załadować strony."
|
||||
pageLoadErrorDescription: "Zwykle jest to spowodowane problemem z siecią lub cache
|
||||
przeglądarki. Spróbuj wyczyścić cache i sprawdź jeszcze raz za chwilę."
|
||||
pageLoadErrorDescription: "Zwykle jest to spowodowane problemem z siecią lub cache\
|
||||
\ przeglądarki. Spróbuj wyczyścić cache i sprawdź jeszcze raz za chwilę."
|
||||
serverIsDead: "Serwer nie odpowiada. Zaczekaj chwilę i spróbuj ponownie."
|
||||
youShouldUpgradeClient: "Aby zobaczyć tą stronę, odśwież ją, by zaaktualizować klienta."
|
||||
enterListName: "Wpisz nazwę listy"
|
||||
|
@ -113,8 +113,8 @@ sensitive: "NSFW"
|
|||
add: "Dodaj"
|
||||
reaction: "Reakcja"
|
||||
reactionSetting: "Reakcje do pokazania w wyborniku reakcji"
|
||||
reactionSettingDescription2: "Przeciągnij aby zmienić kolejność, naciśnij aby usunąć,
|
||||
naciśnij „+” aby dodać."
|
||||
reactionSettingDescription2: "Przeciągnij aby zmienić kolejność, naciśnij aby usunąć,\
|
||||
\ naciśnij „+” aby dodać."
|
||||
rememberNoteVisibility: "Zapamiętuj ustawienia widoczności wpisu"
|
||||
attachCancel: "Usuń załącznik"
|
||||
markAsSensitive: "Oznacz jako NSFW"
|
||||
|
@ -143,22 +143,22 @@ emojiUrl: "Adres URL emoji"
|
|||
addEmoji: "Dodaj emoji"
|
||||
settingGuide: "Proponowana konfiguracja"
|
||||
cacheRemoteFiles: "Przechowuj zdalne pliki w pamięci podręcznej"
|
||||
cacheRemoteFilesDescription: "Gdy ta opcja jest wyłączona, zdalne pliki są ładowane
|
||||
bezpośrednio ze zdalnego serwera. Wyłączenie tej opcji zmniejszy użycie powierzchni
|
||||
dyskowej, ale zwiększy transfer, ponieważ miniaturki nie będą generowane."
|
||||
cacheRemoteFilesDescription: "Gdy ta opcja jest wyłączona, zdalne pliki są ładowane\
|
||||
\ bezpośrednio ze zdalnych instancji. Wyłączenie the opcji zmniejszy użycie powierzchni\
|
||||
\ dyskowej, ale zwiększy transfer, ponieważ miniaturki nie będą generowane."
|
||||
flagAsBot: "To konto jest botem"
|
||||
flagAsBotDescription: "Jeżeli ten kanał jest kontrolowany przez jakiś program, ustaw
|
||||
tę opcję. Jeżeli włączona, będzie działać jako flaga informująca innych programistów,
|
||||
aby zapobiegać nieskończonej interakcji z różnymi botami i dostosowywać wewnętrzne
|
||||
systemy Calckey, traktując konto jako bota."
|
||||
flagAsCat: "Czy jesteś kotem? 😺"
|
||||
flagAsBotDescription: "Jeżeli ten kanał jest kontrolowany przez jakiś program, ustaw\
|
||||
\ tę opcję. Jeżeli włączona, będzie działać jako flaga informująca innych programistów,\
|
||||
\ aby zapobiegać nieskończonej interakcji z różnymi botami i dostosowywać wewnętrzne\
|
||||
\ systemy Calckey, traktując konto jako bota."
|
||||
flagAsCat: "Czy jesteś kotem? \U0001F63A"
|
||||
flagAsCatDescription: "Dostaniesz kocie uszka, oraz będziesz mówić jak kot!"
|
||||
flagShowTimelineReplies: "Pokazuj odpowiedzi na osi czasu"
|
||||
autoAcceptFollowed: "Automatycznie przyjmuj prośby o możliwość obserwacji od użytkowników,
|
||||
których obserwujesz"
|
||||
autoAcceptFollowed: "Automatycznie przyjmuj prośby o możliwość obserwacji od użytkowników,\
|
||||
\ których obserwujesz"
|
||||
addAccount: "Dodaj konto"
|
||||
loginFailed: "Nie udało się zalogować"
|
||||
showOnRemote: "Zobacz na zdalnym serwerze"
|
||||
showOnRemote: "Zobacz na zdalnej instancji"
|
||||
general: "Ogólne"
|
||||
wallpaper: "Tapeta"
|
||||
setWallpaper: "Ustaw tapetę"
|
||||
|
@ -172,7 +172,7 @@ selectUser: "Wybierz użytkownika"
|
|||
recipient: "Odbiorca(-y)"
|
||||
annotation: "Komentarze"
|
||||
federation: "Federacja"
|
||||
instances: "Serwery"
|
||||
instances: "Instancja"
|
||||
registeredAt: "Zarejestrowano"
|
||||
latestRequestSentAt: "Ostatnie żądanie wysłano o"
|
||||
latestRequestReceivedAt: "Ostatnie żądanie otrzymano o"
|
||||
|
@ -182,7 +182,7 @@ charts: "Wykresy"
|
|||
perHour: "co godzinę"
|
||||
perDay: "co dzień"
|
||||
stopActivityDelivery: "Przestań przesyłać aktywności"
|
||||
blockThisInstance: "Zablokuj ten serwer"
|
||||
blockThisInstance: "Zablokuj tę instancję"
|
||||
operations: "Działania"
|
||||
software: "Oprogramowanie"
|
||||
version: "Wersja"
|
||||
|
@ -192,18 +192,18 @@ jobQueue: "Kolejka zadań"
|
|||
cpuAndMemory: "CPU i pamięć"
|
||||
network: "Sieć"
|
||||
disk: "Dysk"
|
||||
instanceInfo: "Informacje o serwerze"
|
||||
instanceInfo: "Informacje o instancji"
|
||||
statistics: "Statystyki"
|
||||
clearQueue: "Wyczyść kolejkę"
|
||||
clearQueueConfirmTitle: "Czy na pewno chcesz wyczyścić kolejkę?"
|
||||
clearQueueConfirmText: "Wszystkie niewysłane wpisy z kolejki nie zostaną wysłane.
|
||||
Zwykle to nie jest konieczne."
|
||||
clearQueueConfirmText: "Wszystkie niewysłane wpisy z kolejki nie zostaną wysłane.\
|
||||
\ Zwykle to nie jest konieczne."
|
||||
clearCachedFiles: "Wyczyść pamięć podręczną"
|
||||
clearCachedFilesConfirm: "Czy na pewno chcesz usunąć wszystkie zdalne pliki z pamięci
|
||||
podręcznej?"
|
||||
blockedInstances: "Zablokowane serwery"
|
||||
blockedInstancesDescription: "Wypisz nazwy hostów serwerów, które chcesz zablokować.
|
||||
Wymienione serwery nie będą mogły dłużej komunikować się z tym serwerem."
|
||||
clearCachedFilesConfirm: "Czy na pewno chcesz usunąć wszystkie zdalne pliki z pamięci\
|
||||
\ podręcznej?"
|
||||
blockedInstances: "Zablokowane instancje"
|
||||
blockedInstancesDescription: "Wypisz nazwy hostów instancji, które powinny zostać\
|
||||
\ zablokowane. Wypisane instancje nie będą mogły dłużej komunikować się z tą instancją."
|
||||
muteAndBlock: "Wyciszenia i blokady"
|
||||
mutedUsers: "Wyciszeni użytkownicy"
|
||||
blockedUsers: "Zablokowani użytkownicy"
|
||||
|
@ -213,7 +213,7 @@ noteDeleteConfirm: "Czy na pewno chcesz usunąć ten wpis?"
|
|||
pinLimitExceeded: "Nie możesz przypiąć więcej wpisów"
|
||||
intro: "Zakończono instalację Calckey! Utwórz konto administratora."
|
||||
done: "Gotowe"
|
||||
processing: "Przetwarzanie"
|
||||
processing: "Przetwarzanie..."
|
||||
preview: "Podgląd"
|
||||
default: "Domyślne"
|
||||
defaultValueIs: "Domyślne: {value}"
|
||||
|
@ -226,9 +226,9 @@ all: "Wszystkie"
|
|||
subscribing: "Subskrybowanie"
|
||||
publishing: "Publikowanie"
|
||||
notResponding: "Nie odpowiada"
|
||||
instanceFollowing: "Obserwowani na serwerze"
|
||||
instanceFollowers: "Obserwujący na serwerze"
|
||||
instanceUsers: "Użytkownicy tego serwera"
|
||||
instanceFollowing: "Obserwowani na instancji"
|
||||
instanceFollowers: "Obserwujący na instancji"
|
||||
instanceUsers: "Użytkownicy tej instancji"
|
||||
changePassword: "Zmień hasło"
|
||||
security: "Bezpieczeństwo"
|
||||
retypedNotMatch: "Wejście nie zgadza się."
|
||||
|
@ -267,8 +267,8 @@ agreeTo: "Wyrażam zgodę na {0}"
|
|||
tos: "Regulamin"
|
||||
start: "Rozpocznij"
|
||||
home: "Strona główna"
|
||||
remoteUserCaution: "Te informacje mogą nie być aktualne, ponieważ użytkownik pochodzi
|
||||
ze zdalnej instancji."
|
||||
remoteUserCaution: "Te informacje mogą nie być aktualne, ponieważ użytkownik pochodzi\
|
||||
\ ze zdalnej instancji."
|
||||
activity: "Aktywność"
|
||||
images: "Zdjęcia"
|
||||
birthday: "Data urodzenia"
|
||||
|
@ -301,8 +301,8 @@ unableToDelete: "Nie można usunąć"
|
|||
inputNewFileName: "Wprowadź nową nazwę pliku"
|
||||
inputNewDescription: "Proszę wpisać nowy napis"
|
||||
inputNewFolderName: "Wprowadź nową nazwę katalogu"
|
||||
circularReferenceFolder: "Katalog docelowy jest podkatalogiem katalogu, który chcesz
|
||||
przenieść."
|
||||
circularReferenceFolder: "Katalog docelowy jest podkatalogiem katalogu, który chcesz\
|
||||
\ przenieść."
|
||||
hasChildFilesOrFolders: "Ponieważ ten katalog nie jest pusty, nie może być usunięty."
|
||||
copyUrl: "Skopiuj adres URL"
|
||||
rename: "Zmień nazwę"
|
||||
|
@ -319,8 +319,8 @@ unwatch: "Przestań śledzić"
|
|||
accept: "Akceptuj"
|
||||
reject: "Odrzuć"
|
||||
normal: "Normalny"
|
||||
instanceName: "Nazwa serwera"
|
||||
instanceDescription: "Opis serwera"
|
||||
instanceName: "Nazwa instancji"
|
||||
instanceDescription: "Opis instancji"
|
||||
maintainerName: "Administrator"
|
||||
maintainerEmail: "E-mail administratora"
|
||||
tosUrl: "Adres URL regulaminu"
|
||||
|
@ -336,8 +336,8 @@ connectService: "Połącz"
|
|||
disconnectService: "Rozłącz"
|
||||
enableLocalTimeline: "Włącz lokalną oś czasu"
|
||||
enableGlobalTimeline: "Włącz globalną oś czasu"
|
||||
disablingTimelinesInfo: "Administratorzy i moderatorzy będą zawsze mieć dostęp do
|
||||
wszystkich osi czasu, nawet gdy są one wyłączone."
|
||||
disablingTimelinesInfo: "Administratorzy i moderatorzy będą zawsze mieć dostęp do\
|
||||
\ wszystkich osi czasu, nawet gdy są one wyłączone."
|
||||
registration: "Zarejestruj się"
|
||||
enableRegistration: "Włącz rejestrację nowych użytkowników"
|
||||
invite: "Zaproś"
|
||||
|
@ -349,11 +349,11 @@ bannerUrl: "Adres URL banera"
|
|||
backgroundImageUrl: "Adres URL tła"
|
||||
basicInfo: "Podstawowe informacje"
|
||||
pinnedUsers: "Przypięty użytkownik"
|
||||
pinnedUsersDescription: "Wypisz po jednej nazwie użytkownika w wierszu. Podani użytkownicy
|
||||
zostaną przypięci pod kartą „Eksploruj”."
|
||||
pinnedUsersDescription: "Wypisz po jednej nazwie użytkownika w wierszu. Podani użytkownicy\
|
||||
\ zostaną przypięci pod kartą „Eksploruj”."
|
||||
pinnedPages: "Przypięte strony"
|
||||
pinnedPagesDescription: "Wprowadź ścieżki stron, które chcesz przypiąć do górnej strony
|
||||
tego serwera, oddzielając je znakami końca wiersza."
|
||||
pinnedPagesDescription: "Wprowadź ścieżki stron które chcesz przypiąć na głównej stronie\
|
||||
\ instancji, oddzielone znakiem nowego wiersza."
|
||||
pinnedClipId: "ID przypiętego klipu"
|
||||
pinnedNotes: "Przypięty wpis"
|
||||
hcaptcha: "hCaptcha"
|
||||
|
@ -364,16 +364,16 @@ recaptcha: "reCAPTCHA"
|
|||
enableRecaptcha: "Włącz reCAPTCHA"
|
||||
recaptchaSiteKey: "Klucz strony"
|
||||
recaptchaSecretKey: "Tajny klucz"
|
||||
avoidMultiCaptchaConfirm: "Używanie wielu Captchy może spowodować zakłócenia. Czy
|
||||
chcesz wyłączyć inną Captchę? Możesz zostawić wiele jednocześnie, klikając Anuluj."
|
||||
avoidMultiCaptchaConfirm: "Używanie wielu Captchy może spowodować zakłócenia. Czy\
|
||||
\ chcesz wyłączyć inną Captchę? Możesz zostawić wiele jednocześnie, klikając Anuluj."
|
||||
antennas: "Anteny"
|
||||
manageAntennas: "Zarządzaj antenami"
|
||||
name: "Nazwa"
|
||||
antennaSource: "Źródło anteny"
|
||||
antennaKeywords: "Słowa kluczowe do obserwacji"
|
||||
antennaExcludeKeywords: "Wykluczone słowa kluczowe"
|
||||
antennaKeywordsDescription: "Oddziel spacjami dla warunku AND, albo wymuś koniec linii
|
||||
dla warunku OR."
|
||||
antennaKeywordsDescription: "Oddziel spacjami dla warunku AND, albo wymuś koniec linii\
|
||||
\ dla warunku OR."
|
||||
notifyAntenna: "Powiadamiaj o nowych wpisach"
|
||||
withFileAntenna: "Filtruj tylko wpisy z załączonym plikiem"
|
||||
enableServiceworker: "Włącz powiadomienia push dla twojej przeglądarki"
|
||||
|
@ -461,8 +461,8 @@ strongPassword: "Silne hasło"
|
|||
passwordMatched: "Pasuje"
|
||||
passwordNotMatched: "Hasła nie pasują do siebie"
|
||||
signinWith: "Zaloguj się z {x}"
|
||||
signinFailed: "Nie udało się zalogować. Wprowadzona nazwa użytkownika lub hasło są
|
||||
nieprawidłowe."
|
||||
signinFailed: "Nie udało się zalogować. Wprowadzona nazwa użytkownika lub hasło są\
|
||||
\ nieprawidłowe."
|
||||
tapSecurityKey: "Wybierz swój klucz bezpieczeństwa"
|
||||
or: "Lub"
|
||||
language: "Język"
|
||||
|
@ -508,18 +508,18 @@ objectStorageBucketDesc: "Podaj nazwę „wiadra” używaną przez konfigurowan
|
|||
objectStoragePrefix: "Prefiks"
|
||||
objectStoragePrefixDesc: "Pliki będą przechowywane w katalogu z tym prefiksem."
|
||||
objectStorageEndpoint: "Punkt końcowy"
|
||||
objectStorageEndpointDesc: "Pozostaw puste jeżeli używasz AWS S3, w innym wypadku
|
||||
określ punkt końcowy jako '<host>' lub '<host>:<port>' zgodnie z instrukcjami usługi,
|
||||
której używasz."
|
||||
objectStorageEndpointDesc: "Pozostaw puste jeżeli używasz AWS S3, w innym wypadku\
|
||||
\ określ punkt końcowy jako '<host>' lub '<host>:<port>' zgodnie z instrukcjami\
|
||||
\ usługi, której używasz."
|
||||
objectStorageRegion: "Region"
|
||||
objectStorageRegionDesc: "Określ region, np. 'xx-east-1'. Jeżeli usługa której używasz
|
||||
nie zawiera rozróżnienia regionów, pozostaw to pustym lub wprowadź 'us-east-1'."
|
||||
objectStorageRegionDesc: "Określ region, np. 'xx-east-1'. Jeżeli usługa której używasz\
|
||||
\ nie zawiera rozróżnienia regionów, pozostaw to pustym lub wprowadź 'us-east-1'."
|
||||
objectStorageUseSSL: "Użyj SSL"
|
||||
objectStorageUseSSLDesc: "Wyłącz, jeżeli nie zamierzasz używać HTTPS dla połączenia
|
||||
z API"
|
||||
objectStorageUseSSLDesc: "Wyłącz, jeżeli nie zamierzasz używać HTTPS dla połączenia\
|
||||
\ z API"
|
||||
objectStorageUseProxy: "Połącz przez proxy"
|
||||
objectStorageUseProxyDesc: "Wyłącz, jeżeli nie zamierzasz używać proxy dla połączenia
|
||||
z pamięcią blokową"
|
||||
objectStorageUseProxyDesc: "Wyłącz, jeżeli nie zamierzasz używać proxy dla połączenia\
|
||||
\ z pamięcią blokową"
|
||||
serverLogs: "Dziennik zdarzeń"
|
||||
deleteAll: "Usuń wszystkie"
|
||||
showFixedPostForm: "Wyświetlaj formularz tworzenia wpisu w górnej części osi czasu"
|
||||
|
@ -546,22 +546,22 @@ sort: "Sortuj"
|
|||
ascendingOrder: "Rosnąco"
|
||||
descendingOrder: "Malejąco"
|
||||
scratchpad: "Brudnopis"
|
||||
scratchpadDescription: "Brudnopis to środowisko dla eksperymentów z AiScript. Możesz
|
||||
pisać, wykonywać i sprawdzać wyniki interakcji skryptu z Calckey."
|
||||
scratchpadDescription: "Brudnopis to środowisko dla eksperymentów z AiScript. Możesz\
|
||||
\ pisać, wykonywać i sprawdzać wyniki interakcji skryptu z Calckey."
|
||||
output: "Wyjście"
|
||||
script: "Skrypt"
|
||||
disablePagesScript: "Wyłącz AiScript na Stronach"
|
||||
updateRemoteUser: "Aktualizuj zdalne dane o użytkowniku"
|
||||
deleteAllFiles: "Usuń wszystkie pliki"
|
||||
deleteAllFilesConfirm: "Czy na pewno chcesz usunąć wszystkie pliki?"
|
||||
removeAllFollowingDescription: "Wykonanie tego polecenia spowoduje usunięcie wszystkich
|
||||
kont z {host}. Zrób to, jeśli serwer np. już nie istnieje."
|
||||
removeAllFollowingDescription: "Przestań obserwować wszystkie konta z {host}. Wykonaj\
|
||||
\ to, jeżeli instancja już nie istnieje."
|
||||
userSuspended: "To konto zostało zawieszone."
|
||||
userSilenced: "Ten użytkownik został wyciszony."
|
||||
yourAccountSuspendedTitle: "To konto jest zawieszone"
|
||||
yourAccountSuspendedDescription: "To konto zostało zawieszone z powodu złamania regulaminu
|
||||
serwera lub innych podobnych. Skontaktuj się z administratorem, jeśli chciałbyś
|
||||
poznać bardziej szczegółowy powód. Proszę nie zakładać nowego konta."
|
||||
yourAccountSuspendedDescription: "To konto zostało zawieszone z powodu złamania regulaminu\
|
||||
\ serwera lub innych podobnych. Skontaktuj się z administratorem, jeśli chciałbyś\
|
||||
\ poznać bardziej szczegółowy powód. Proszę nie zakładać nowego konta."
|
||||
menu: "Menu"
|
||||
divider: "Rozdzielacz"
|
||||
addItem: "Dodaj element"
|
||||
|
@ -600,14 +600,14 @@ permission: "Uprawnienia"
|
|||
enableAll: "Włącz wszystko"
|
||||
disableAll: "Wyłącz wszystko"
|
||||
tokenRequested: "Przydziel dostęp do konta"
|
||||
pluginTokenRequestedDescription: "Ta wtyczka będzie mogła korzystać z ustawionych
|
||||
tu uprawnień."
|
||||
pluginTokenRequestedDescription: "Ta wtyczka będzie mogła korzystać z ustawionych\
|
||||
\ tu uprawnień."
|
||||
notificationType: "Rodzaj powiadomień"
|
||||
edit: "Edytuj"
|
||||
emailServer: "Serwer poczty e-mail"
|
||||
enableEmail: "Włącz dostarczanie wiadomości e-mail"
|
||||
emailConfigInfo: "Wykorzystywany do potwierdzenia adresu e-mail w trakcie rejestracji,
|
||||
lub gdy zapomnisz hasła"
|
||||
emailConfigInfo: "Wykorzystywany do potwierdzenia adresu e-mail w trakcie rejestracji,\
|
||||
\ lub gdy zapomnisz hasła"
|
||||
email: "Adres e-mail"
|
||||
emailAddress: "Adres e-mail"
|
||||
smtpConfig: "Konfiguracja serwera SMTP"
|
||||
|
@ -615,12 +615,12 @@ smtpHost: "Host"
|
|||
smtpPort: "Port"
|
||||
smtpUser: "Nazwa użytkownika"
|
||||
smtpPass: "Hasło"
|
||||
emptyToDisableSmtpAuth: "Pozostaw adres e-mail i hasło puste, aby wyłączyć weryfikację
|
||||
SMTP"
|
||||
emptyToDisableSmtpAuth: "Pozostaw adres e-mail i hasło puste, aby wyłączyć weryfikację\
|
||||
\ SMTP"
|
||||
smtpSecureInfo: "Wyłącz, jeżeli używasz STARTTLS"
|
||||
testEmail: "Przetestuj dostarczanie wiadomości e-mail"
|
||||
wordMute: "Wyciszenie słowa"
|
||||
instanceMute: "Wyciszenie serwera"
|
||||
instanceMute: "Wyciszone instancje"
|
||||
userSaysSomething: "{name} powiedział* coś"
|
||||
makeActive: "Aktywuj"
|
||||
display: "Wyświetlanie"
|
||||
|
@ -635,12 +635,12 @@ create: "Utwórz"
|
|||
notificationSetting: "Ustawienia powiadomień"
|
||||
notificationSettingDesc: "Wybierz rodzaj powiadomień do wyświetlania."
|
||||
useGlobalSetting: "Użyj globalnych ustawień"
|
||||
useGlobalSettingDesc: "Jeżeli włączone, zostaną wykorzystane ustawienia powiadomień
|
||||
Twojego konta. Jeżeli wyłączone, mogą zostać wykonane oddzielne konfiguracje."
|
||||
useGlobalSettingDesc: "Jeżeli włączone, zostaną wykorzystane ustawienia powiadomień\
|
||||
\ Twojego konta. Jeżeli wyłączone, mogą zostać wykonane oddzielne konfiguracje."
|
||||
other: "Inne"
|
||||
regenerateLoginToken: "Generuj token logowania ponownie"
|
||||
regenerateLoginTokenDescription: "Regeneruje token używany wewnętrznie podczas logowania.
|
||||
Zazwyczaj nie jest to konieczne. Po regeneracji wszystkie urządzenia zostaną wylogowane."
|
||||
regenerateLoginTokenDescription: "Regeneruje token używany wewnętrznie podczas logowania.\
|
||||
\ Zazwyczaj nie jest to konieczne. Po regeneracji wszystkie urządzenia zostaną wylogowane."
|
||||
setMultipleBySeparatingWithSpace: "Możesz ustawić wiele, oddzielając je spacjami."
|
||||
fileIdOrUrl: "ID pliku albo URL"
|
||||
behavior: "Zachowanie"
|
||||
|
@ -648,19 +648,19 @@ sample: "Przykład"
|
|||
abuseReports: "Zgłoszenia"
|
||||
reportAbuse: "Zgłoś"
|
||||
reportAbuseOf: "Zgłoś {name}"
|
||||
fillAbuseReportDescription: "Wypełnij szczegóły zgłoszenia. Jeżeli dotyczy ono określonego
|
||||
wpisu, uwzględnij jego adres URL."
|
||||
fillAbuseReportDescription: "Wypełnij szczegóły zgłoszenia. Jeżeli dotyczy ono określonego\
|
||||
\ wpisu, uwzględnij jego adres URL."
|
||||
abuseReported: "Twoje zgłoszenie zostało wysłane. Dziękujemy."
|
||||
reporteeOrigin: "Pochodzenie osoby zgłoszonej"
|
||||
reporterOrigin: "Pochodzenie osoby zgłaszającej"
|
||||
forwardReport: "Przekaż zgłoszenie do zdalnego serwera"
|
||||
forwardReport: "Przekaż zgłoszenie do innej instancji"
|
||||
send: "Wyślij"
|
||||
abuseMarkAsResolved: "Oznacz zgłoszenie jako rozwiązane"
|
||||
openInNewTab: "Otwórz w nowej karcie"
|
||||
openInSideView: "Otwórz w bocznym widoku"
|
||||
defaultNavigationBehaviour: "Domyślne zachowanie nawigacji"
|
||||
editTheseSettingsMayBreakAccount: "Edycja tych ustawień może uszkodzić Twoje konto."
|
||||
instanceTicker: "Informacje o wpisach serwera"
|
||||
instanceTicker: "Informacje o wpisach instancji"
|
||||
waitingFor: "Oczekiwanie na {x}"
|
||||
random: "Losowe"
|
||||
system: "System"
|
||||
|
@ -671,11 +671,11 @@ createNew: "Utwórz nowy"
|
|||
optional: "Nieobowiązkowe"
|
||||
createNewClip: "Utwórz nowy klip"
|
||||
unclip: "Odczep"
|
||||
confirmToUnclipAlreadyClippedNote: "Ten wpis jest już częścią klipu \"{name}\". Czy
|
||||
chcesz ją usunąć z tego klipu?"
|
||||
confirmToUnclipAlreadyClippedNote: "Ten wpis jest już częścią klipu \"{name}\". Czy\
|
||||
\ chcesz ją usunąć z tego klipu?"
|
||||
public: "Publiczny"
|
||||
i18nInfo: "Calckey jest tłumaczone na wiele języków przez wolontariuszy. Możesz pomóc
|
||||
na {link}."
|
||||
i18nInfo: "Calckey jest tłumaczone na wiele języków przez wolontariuszy. Możesz pomóc\
|
||||
\ na {link}."
|
||||
manageAccessTokens: "Zarządzaj tokenami dostępu"
|
||||
accountInfo: "Informacje o koncie"
|
||||
notesCount: "Liczba wpisów"
|
||||
|
@ -694,15 +694,16 @@ no: "Nie"
|
|||
driveFilesCount: "Liczba plików na dysku"
|
||||
driveUsage: "Użycie przestrzeni dyskowej"
|
||||
noCrawle: "Odrzuć indeksowanie przez crawlery"
|
||||
noCrawleDescription: "Proś wyszukiwarki internetowe, aby nie indeksowały Twojego profilu,
|
||||
wpisów, stron itd."
|
||||
lockedAccountInfo: "Dopóki nie ustawisz widoczności wpisu na \"Obserwujący\", twoje
|
||||
wpisy będą mogli widzieć wszyscy, nawet jeśli ustawisz manualne zatwierdzanie obserwujących."
|
||||
noCrawleDescription: "Proś wyszukiwarki internetowe, aby nie indeksowały Twojego profilu,\
|
||||
\ wpisów, stron itd."
|
||||
lockedAccountInfo: "Dopóki nie ustawisz widoczności wpisu na \"Obserwujący\", twoje\
|
||||
\ wpisy będą mogli widzieć wszyscy, nawet jeśli ustawisz manualne zatwierdzanie\
|
||||
\ obserwujących."
|
||||
alwaysMarkSensitive: "Oznacz domyślnie jako NSFW"
|
||||
loadRawImages: "Wyświetlaj zdjęcia w załącznikach w całości zamiast miniatur"
|
||||
disableShowingAnimatedImages: "Nie odtwarzaj animowanych obrazów"
|
||||
verificationEmailSent: "Wiadomość weryfikacyjna została wysłana. Odwiedź uwzględniony
|
||||
odnośnik, aby ukończyć weryfikację."
|
||||
verificationEmailSent: "Wiadomość weryfikacyjna została wysłana. Odwiedź uwzględniony\
|
||||
\ odnośnik, aby ukończyć weryfikację."
|
||||
notSet: "Nie ustawiono"
|
||||
emailVerified: "Adres e-mail został potwierdzony"
|
||||
noteFavoritesCount: "Liczba zakładek"
|
||||
|
@ -714,16 +715,16 @@ clips: "Klipy"
|
|||
experimentalFeatures: "Eksperymentalne funkcje"
|
||||
developer: "Programista"
|
||||
makeExplorable: "Pokazuj konto na stronie „Eksploruj”"
|
||||
makeExplorableDescription: "Jeżeli wyłączysz tę opcję, Twoje konto nie będzie wyświetlać
|
||||
się w sekcji „Eksploruj”."
|
||||
makeExplorableDescription: "Jeżeli wyłączysz tę opcję, Twoje konto nie będzie wyświetlać\
|
||||
\ się w sekcji „Eksploruj”."
|
||||
showGapBetweenNotesInTimeline: "Pokazuj odstęp między wpisami na osi czasu"
|
||||
duplicate: "Duplikuj"
|
||||
left: "Lewo"
|
||||
center: "Wyśrodkuj"
|
||||
wide: "Szerokie"
|
||||
narrow: "Wąskie"
|
||||
reloadToApplySetting: "To ustawienie zostanie zastosowane po odświeżeniu strony. Chcesz
|
||||
odświeżyć?"
|
||||
reloadToApplySetting: "To ustawienie zostanie zastosowane po odświeżeniu strony. Chcesz\
|
||||
\ odświeżyć?"
|
||||
needReloadToApply: "To ustawienie zostanie zastosowane po odświeżeniu strony."
|
||||
showTitlebar: "Pokazuj pasek tytułowy"
|
||||
clearCache: "Wyczyść pamięć podręczną"
|
||||
|
@ -754,7 +755,7 @@ capacity: "Pojemność"
|
|||
inUse: "Użyto"
|
||||
editCode: "Edytuj kod"
|
||||
apply: "Zastosuj"
|
||||
receiveAnnouncementFromInstance: "Otrzymuj powiadomienia e-mail z tego serwera"
|
||||
receiveAnnouncementFromInstance: "Otrzymuj powiadomienia e-mail z tej instancji"
|
||||
emailNotification: "Powiadomienia e-mail"
|
||||
publish: "Publikuj"
|
||||
inChannelSearch: "Szukaj na kanale"
|
||||
|
@ -771,21 +772,21 @@ quitFullView: "Opuść pełny widok"
|
|||
addDescription: "Dodaj opis"
|
||||
userPagePinTip: "Możesz wyświetlać wpisy w tym miejscu po wybraniu \"Przypnij do profilu\"\
|
||||
\ z menu pojedynczego wpisu."
|
||||
notSpecifiedMentionWarning: "Ten wpis zawiera wzmianki o użytkownikach niezawartych
|
||||
jako odbiorcy"
|
||||
notSpecifiedMentionWarning: "Ten wpis zawiera wzmianki o użytkownikach niezawartych\
|
||||
\ jako odbiorcy"
|
||||
info: "Informacje"
|
||||
userInfo: "Informacje o użykowniku"
|
||||
unknown: "Nieznane"
|
||||
onlineStatus: "Status online"
|
||||
hideOnlineStatus: "Ukryj status online"
|
||||
hideOnlineStatusDescription: "Ukrywanie statusu online ogranicza wygody niektórych
|
||||
funkcji, takich jak wyszukiwanie."
|
||||
hideOnlineStatusDescription: "Ukrywanie statusu online ogranicza wygody niektórych\
|
||||
\ funkcji, takich jak wyszukiwanie."
|
||||
online: "Online"
|
||||
active: "Aktywny"
|
||||
offline: "Offline"
|
||||
notRecommended: "Nie zalecane"
|
||||
botProtection: "Zabezpieczenie przed botami"
|
||||
instanceBlocking: "Zarządzanie federacją"
|
||||
instanceBlocking: "Zablokowane/wyciszone instancje"
|
||||
selectAccount: "Wybierz konto"
|
||||
switchAccount: "Przełącz konto"
|
||||
enabled: "Właczono"
|
||||
|
@ -814,8 +815,8 @@ emailNotConfiguredWarning: "Nie podano adresu e-mail."
|
|||
ratio: "Stosunek"
|
||||
previewNoteText: "Pokaż podgląd"
|
||||
customCss: "Własny CSS"
|
||||
customCssWarn: "Używaj tego ustawienia tylko wtedy, gdy wiesz co ono robi. Nieprawidłowe
|
||||
wpisy mogą spowodować, że klient przestanie działać poprawnie."
|
||||
customCssWarn: "Używaj tego ustawienia tylko wtedy, gdy wiesz co ono robi. Nieprawidłowe\
|
||||
\ wpisy mogą spowodować, że klient przestanie działać poprawnie."
|
||||
global: "Globalna"
|
||||
squareAvatars: "Wyświetlaj kwadratowe awatary"
|
||||
sent: "Wysłane"
|
||||
|
@ -831,8 +832,8 @@ translate: "Przetłumacz"
|
|||
translatedFrom: "Przetłumaczone z {x}"
|
||||
accountDeletionInProgress: "Trwa usuwanie konta"
|
||||
usernameInfo: "Nazwa, która identyfikuje Twoje konto spośród innych na tym serwerze.\
|
||||
\ Możesz użyć alfabetu (a~z, A~Z), cyfr (0~9) lub podkreślników (_). Nazwy użytkownika
|
||||
nie mogą być później zmieniane."
|
||||
\ Możesz użyć alfabetu (a~z, A~Z), cyfr (0~9) lub podkreślników (_). Nazwy użytkownika\
|
||||
\ nie mogą być później zmieniane."
|
||||
aiChanMode: "Ai-chan w klasycznym interfejsie"
|
||||
keepCw: "Zostaw ostrzeżenia o zawartości"
|
||||
pubSub: "Konta Pub/Sub"
|
||||
|
@ -846,14 +847,14 @@ filter: "Filtr"
|
|||
controlPanel: "Panel sterowania"
|
||||
manageAccounts: "Zarządzaj kontami"
|
||||
makeReactionsPublic: "Ustaw historię reakcji jako publiczną"
|
||||
makeReactionsPublicDescription: "To spowoduje, że lista wszystkich Twoich dotychczasowych
|
||||
reakcji będzie publicznie widoczna."
|
||||
classic: "Wyśrodkowany"
|
||||
makeReactionsPublicDescription: "To spowoduje, że lista wszystkich Twoich dotychczasowych\
|
||||
\ reakcji będzie publicznie widoczna."
|
||||
classic: "Klasyczny"
|
||||
muteThread: "Wycisz wątek"
|
||||
unmuteThread: "Wyłącz wyciszenie wątku"
|
||||
ffVisibility: "Widoczność obserwowanych/obserwujących"
|
||||
ffVisibilityDescription: "Pozwala skonfigurować, kto może zobaczyć, kogo obserwujesz
|
||||
i kto Cię obserwuje."
|
||||
ffVisibilityDescription: "Pozwala skonfigurować, kto może zobaczyć, kogo obserwujesz\
|
||||
\ i kto Cię obserwuje."
|
||||
continueThread: "Kontynuuj wątek"
|
||||
deleteAccountConfirm: "Spowoduje to nieodwracalne usunięcie Twojego konta. Kontynuować?"
|
||||
incorrectPassword: "Nieprawidłowe hasło."
|
||||
|
@ -861,8 +862,8 @@ voteConfirm: "Potwierdzić swój głos na \"{choice}\"?"
|
|||
hide: "Ukryj"
|
||||
leaveGroup: "Opuść grupę"
|
||||
leaveGroupConfirm: "Czy na pewno chcesz opuścić \"{name}\"?"
|
||||
useDrawerReactionPickerForMobile: "Wyświetlaj wybornik reakcji jako szufladę na urządzeniach
|
||||
mobilnych"
|
||||
useDrawerReactionPickerForMobile: "Wyświetlaj wybornik reakcji jako szufladę na urządzeniach\
|
||||
\ mobilnych"
|
||||
welcomeBackWithName: "Witaj z powrotem, {name}"
|
||||
clickToFinishEmailVerification: "Kliknij [{ok}], aby zakończyć weryfikację e-mail."
|
||||
overridedDeviceKind: "Typ urządzenia"
|
||||
|
@ -885,22 +886,22 @@ type: "Typ"
|
|||
speed: "Prędkość"
|
||||
localOnly: "Tylko lokalne"
|
||||
failedToUpload: "Przesyłanie nie powiodło się"
|
||||
cannotUploadBecauseInappropriate: "Nie można przesłać tego pliku, ponieważ jego części
|
||||
zostały wykryte jako potencjalnie nieodpowiednie."
|
||||
cannotUploadBecauseNoFreeSpace: "Przesyłanie nie powiodło się z powodu braku miejsca
|
||||
na dysku."
|
||||
cannotUploadBecauseInappropriate: "Nie można przesłać tego pliku, ponieważ jego części\
|
||||
\ zostały wykryte jako potencjalnie nieodpowiednie."
|
||||
cannotUploadBecauseNoFreeSpace: "Przesyłanie nie powiodło się z powodu braku miejsca\
|
||||
\ na dysku."
|
||||
beta: "Beta"
|
||||
enableAutoSensitive: "Automatyczne oznaczanie NSFW"
|
||||
enableAutoSensitiveDescription: "Umożliwia automatyczne wykrywanie i oznaczanie zawartości
|
||||
NSFW za pomocą uczenia maszynowego tam, gdzie to możliwe. Nawet jeśli ta opcja jest
|
||||
wyłączona, może być włączona na całym serwerze."
|
||||
enableAutoSensitiveDescription: "Umożliwia automatyczne wykrywanie i oznaczanie zawartości\
|
||||
\ NSFW za pomocą uczenia maszynowego. Nawet jeśli ta opcja jest wyłączona, może\
|
||||
\ być włączona na całej instancji."
|
||||
navbar: "Pasek nawigacyjny"
|
||||
account: "Konta"
|
||||
move: "Przenieś"
|
||||
_sensitiveMediaDetection:
|
||||
description: "Zmniejsza wysiłek związany z moderacją serwera dzięki automatycznemu
|
||||
rozpoznawaniu zawartości NSFW za pomocą uczenia maszynowego. To nieznacznie zwiększy
|
||||
obciążenie serwera."
|
||||
description: "Zmniejsza wysiłek związany z moderacją serwera dzięki automatycznemu\
|
||||
\ rozpoznawaniu zawartości NSFW za pomocą uczenia maszynowego. To nieznacznie\
|
||||
\ zwiększy obciążenie serwera."
|
||||
setSensitiveFlagAutomatically: "Oznacz jako NSFW"
|
||||
sensitivity: Czułość wykrywania
|
||||
analyzeVideosDescription: Analizuje filmy, w dodatku do zdjęć. Zwiększy to nieznacznie
|
||||
|
@ -924,15 +925,15 @@ _ffVisibility:
|
|||
_signup:
|
||||
almostThere: "Prawie na miejscu"
|
||||
emailAddressInfo: "Podaj swój adres e-mail. Nie zostanie on upubliczniony."
|
||||
emailSent: "E-mail z potwierdzeniem został wysłany na Twój adres e-mail ({email}).
|
||||
Kliknij dołączony link, aby dokończyć tworzenie konta."
|
||||
emailSent: "E-mail z potwierdzeniem został wysłany na Twój adres e-mail ({email}).\
|
||||
\ Kliknij dołączony link, aby dokończyć tworzenie konta."
|
||||
_accountDelete:
|
||||
accountDelete: "Usuń konto"
|
||||
mayTakeTime: "Ponieważ usuwanie konta jest procesem wymagającym dużej ilości zasobów,
|
||||
jego ukończenie może zająć trochę czasu, w zależności od ilości utworzonej zawartości
|
||||
i liczby przesłanych plików."
|
||||
sendEmail: "Po zakończeniu usuwania konta na adres e-mail zarejestrowany na tym
|
||||
koncie zostanie wysłana wiadomość e-mail."
|
||||
mayTakeTime: "Ponieważ usuwanie konta jest procesem wymagającym dużej ilości zasobów,\
|
||||
\ jego ukończenie może zająć trochę czasu, w zależności od ilości utworzonej zawartości\
|
||||
\ i liczby przesłanych plików."
|
||||
sendEmail: "Po zakończeniu usuwania konta na adres e-mail zarejestrowany na tym\
|
||||
\ koncie zostanie wysłana wiadomość e-mail."
|
||||
requestAccountDelete: "Poproś o usunięcie konta"
|
||||
started: "Usuwanie się rozpoczęło."
|
||||
inProgress: "Usuwanie jest obecnie w toku"
|
||||
|
@ -940,12 +941,12 @@ _ad:
|
|||
back: "Wróć"
|
||||
reduceFrequencyOfThisAd: "Pokazuj tę reklamę rzadziej"
|
||||
_forgotPassword:
|
||||
enterEmail: "Wpisz adres e-mail użyty do rejestracji. Zostanie do niego wysłany
|
||||
link, za pomocą którego możesz zresetować hasło."
|
||||
ifNoEmail: "Jeśli nie użyłeś adresu e-mail podczas rejestracji, skontaktuj się z
|
||||
administratorem serwera."
|
||||
contactAdmin: "Ten serwer nie obsługuje adresów e-mail, zamiast tego skontaktuj
|
||||
się z administratorem serwera, aby zresetować hasło."
|
||||
enterEmail: "Wpisz adres e-mail użyty do rejestracji. Zostanie do niego wysłany\
|
||||
\ link, za pomocą którego możesz zresetować hasło."
|
||||
ifNoEmail: "Jeżeli nie podano adresu e-mail podczas rejestracji, skontaktuj się\
|
||||
\ z administratorem zamiast tego."
|
||||
contactAdmin: "Jeżeli Twoja instancja nie obsługuje adresów e-mail, skontaktuj się\
|
||||
\ zamiast tego z administratorem, aby zresetować hasło."
|
||||
_gallery:
|
||||
my: "Moja galeria"
|
||||
liked: "Polubione wpisy"
|
||||
|
@ -968,10 +969,10 @@ _preferencesBackups:
|
|||
save: "Zapisz zmiany"
|
||||
inputName: "Proszę podać nazwę dla tej kopii zapasowej"
|
||||
cannotSave: "Zapisanie nie powiodło się"
|
||||
nameAlreadyExists: "Kopia zapasowa o nazwie \"{name}\" już istnieje. Proszę podać
|
||||
inną nazwę."
|
||||
applyConfirm: "Czy na pewno chcesz zastosować kopię zapasową \"{name}\" na tym urządzeniu?
|
||||
Istniejące ustawienia tego urządzenia zostaną nadpisane."
|
||||
nameAlreadyExists: "Kopia zapasowa o nazwie \"{name}\" już istnieje. Proszę podać\
|
||||
\ inną nazwę."
|
||||
applyConfirm: "Czy na pewno chcesz zastosować kopię zapasową \"{name}\" na tym urządzeniu?\
|
||||
\ Istniejące ustawienia tego urządzenia zostaną nadpisane."
|
||||
saveConfirm: "Zapisać kopię zapasową jako {name}?"
|
||||
deleteConfirm: "Usunąć kopię zapasową {name}?"
|
||||
renameConfirm: "Zmienić nazwę kopii zapasowej z \"{old}\" na \"{new}\"?"
|
||||
|
@ -988,15 +989,15 @@ _registry:
|
|||
domain: "Domena"
|
||||
createKey: "Utwórz klucz"
|
||||
_aboutMisskey:
|
||||
about: "Calckey jest forkiem Misskey utworzonym przez ThatOneCalculator, rozwijanym
|
||||
od 2022."
|
||||
about: "Calckey jest forkiem Misskey utworzonym przez ThatOneCalculator, rozwijanym\
|
||||
\ od 2022."
|
||||
contributors: "Główni twórcy"
|
||||
allContributors: "Wszyscy twórcy"
|
||||
source: "Kod źródłowy"
|
||||
translation: "Tłumacz Calckey"
|
||||
donate: "Przekaż darowiznę na Calckey"
|
||||
morePatrons: "Naprawdę doceniam wsparcie ze strony wielu niewymienionych tu osób.
|
||||
Dziękuję! 🥰"
|
||||
morePatrons: "Naprawdę doceniam wsparcie ze strony wielu niewymienionych tu osób.\
|
||||
\ Dziękuję! \U0001F970"
|
||||
patrons: "Wspierający"
|
||||
_nsfw:
|
||||
respect: "Ukrywaj media NSFW"
|
||||
|
@ -1004,13 +1005,13 @@ _nsfw:
|
|||
force: "Ukrywaj wszystkie media"
|
||||
_mfm:
|
||||
cheatSheet: "Ściąga MFM"
|
||||
intro: "MFM jest językiem składniowym używanym przez m.in. Calckey, forki *key (w
|
||||
tym Calckey), oraz Akkomę, który może być użyty w wielu miejscach. Tu znajdziesz
|
||||
listę wszystkich możliwych elementów składni MFM."
|
||||
intro: "MFM jest językiem składniowym używanym przez m.in. Calckey, forki *key (w\
|
||||
\ tym Calckey), oraz Akkomę, który może być użyty w wielu miejscach. Tu znajdziesz\
|
||||
\ listę wszystkich możliwych elementów składni MFM."
|
||||
dummy: "Calckey rozszerza świat Fediwersum"
|
||||
mention: "Wspomnij"
|
||||
mentionDescription: "Używając znaku @ i nazwy użytkownika, możesz określić danego
|
||||
użytkownika."
|
||||
mentionDescription: "Używając znaku @ i nazwy użytkownika, możesz określić danego\
|
||||
\ użytkownika."
|
||||
hashtag: "Hashtag"
|
||||
hashtagDescription: "Używając kratki i tekstu, możesz określić hashtag."
|
||||
url: "Adres URL"
|
||||
|
@ -1025,14 +1026,14 @@ _mfm:
|
|||
centerDescription: "Wyśrodkowuje zawartość."
|
||||
inlineCode: "Kod (w wierszu)"
|
||||
blockCode: "Kod (blok)"
|
||||
blockCodeDescription: "Wyświetla kod z podświetlaną składnią składający się z wielu
|
||||
linii."
|
||||
blockCodeDescription: "Wyświetla kod z podświetlaną składnią składający się z wielu\
|
||||
\ linii."
|
||||
blockMath: "Matematyka (Blok)"
|
||||
quote: "Cytuj"
|
||||
quoteDescription: "Wyświetla treść jako cytat."
|
||||
emoji: "Niestandardowe emoji"
|
||||
emojiDescription: "Otaczając nazwę niestandardowego emoji dwukropkami, możesz użyć
|
||||
niestandardowego emoji."
|
||||
emojiDescription: "Otaczając nazwę niestandardowego emoji dwukropkami, możesz użyć\
|
||||
\ niestandardowego emoji."
|
||||
search: "Szukaj"
|
||||
searchDescription: "Wyświetla pole wyszukiwania z wcześniej wpisanym tekstem."
|
||||
flip: "Odwróć"
|
||||
|
@ -1076,7 +1077,7 @@ _mfm:
|
|||
background: Kolor tła
|
||||
backgroundDescription: Zmień kolor tła tekstu.
|
||||
foregroundDescription: Zmień kolor pierwszoplanowy tekstu.
|
||||
positionDescription: Przesuń zawartość o określoną wartość.
|
||||
positionDescription: Przesuń treść o określoną odległość.
|
||||
position: Pozycjonuj
|
||||
foreground: Kolor pierwszoplanowy
|
||||
scaleDescription: Skaluj treść o określoną wielkość.
|
||||
|
@ -1153,8 +1154,8 @@ _theme:
|
|||
darken: "Ściemnij"
|
||||
lighten: "Rozjaśnij"
|
||||
inputConstantName: "Wprowadź nazwę stałej"
|
||||
importInfo: "Jeżeli wprowadzisz tu kod motywu, możesz zaimportować go w edytorze
|
||||
motywu"
|
||||
importInfo: "Jeżeli wprowadzisz tu kod motywu, możesz zaimportować go w edytorze\
|
||||
\ motywu"
|
||||
deleteConstantConfirm: "Czy na pewno chcesz usunąć stałą {const}?"
|
||||
keys:
|
||||
accent: "Akcent"
|
||||
|
@ -1228,42 +1229,42 @@ _tutorial:
|
|||
step1_1: "Witamy!"
|
||||
step1_2: "Pozwól, że Cię skonfigurujemy. Będziesz działać w mgnieniu oka!"
|
||||
step2_1: "Najpierw, proszę wypełnij swój profil."
|
||||
step2_2: "Podanie kilku informacji o tym, kim jesteś, ułatwi innym stwierdzenie,
|
||||
czy chcą zobaczyć Twoje wpisy lub śledzić Cię."
|
||||
step2_2: "Podanie kilku informacji o tym, kim jesteś, ułatwi innym stwierdzenie,\
|
||||
\ czy chcą zobaczyć Twoje wpisy lub śledzić Cię."
|
||||
step3_1: "Pora znaleźć osoby do śledzenia!"
|
||||
step3_2: "Twoje domowe i społeczne linie czasu opierają się na tym, kogo śledzisz,
|
||||
więc spróbuj śledzić kilka kont, aby zacząć.\nKliknij kółko z plusem w prawym
|
||||
górnym rogu profilu, aby go śledzić."
|
||||
step3_2: "Twoje domowe i społeczne linie czasu opierają się na tym, kogo śledzisz,\
|
||||
\ więc spróbuj śledzić kilka kont, aby zacząć.\nKliknij kółko z plusem w prawym\
|
||||
\ górnym rogu profilu, aby go śledzić."
|
||||
step4_1: "Pozwól, że zabierzemy Cię tam."
|
||||
step4_2: "W pierwszym wpisie możesz się przedstawić lub wysłać powitanie - \"Witaj,
|
||||
świecie!\""
|
||||
step4_2: "W pierwszym wpisie możesz się przedstawić lub wysłać powitanie - \"Witaj,\
|
||||
\ świecie!\""
|
||||
step5_1: "Osie czasu, wszędzie widzę osie czasu!"
|
||||
step5_2: "Twoja instancja ma włączone {timelines} różne osie czasu."
|
||||
step5_3: "Główna {icon} oś czasu to miejsce, w którym możesz zobaczyć posty od użytkowników
|
||||
których obserwujesz, oraz innych użytkowników z tej instancji. Jeśli wolisz, by
|
||||
główna oś czasu pokazywała tylko posty od użytkowników których obserwujesz, możesz
|
||||
łatwo to zmienić w ustawieniach!"
|
||||
step5_4: "Lokalna {icon} oś czasu to miejsce, w którym możesz zobaczyć posty od
|
||||
wszystkich innych osób na tej instancji."
|
||||
step5_5: "Społeczna {icon} oś czasu to miejsce, gdzie możesz zobaczyć posty z instancji,
|
||||
które admini polecają."
|
||||
step5_6: "Polecana {icon} oś czasu to miejsce, gdzie możesz zobaczyć posty z instancji,
|
||||
które admini polecają."
|
||||
step5_7: "Globalna {icon} oś czasu to miejsce, gdzie możesz zobaczyć posty z każdej
|
||||
innej połączonej instancji."
|
||||
step5_3: "Główna {icon} oś czasu to miejsce, w którym możesz zobaczyć posty od użytkowników\
|
||||
\ których obserwujesz, oraz innych użytkowników z tej instancji. Jeśli wolisz,\
|
||||
\ by główna oś czasu pokazywała tylko posty od użytkowników których obserwujesz,\
|
||||
\ możesz łatwo to zmienić w ustawieniach!"
|
||||
step5_4: "Lokalna {icon} oś czasu to miejsce, w którym możesz zobaczyć posty od\
|
||||
\ wszystkich innych osób na tej instancji."
|
||||
step5_5: "Społeczna {icon} oś czasu to miejsce, gdzie możesz zobaczyć posty z instancji,\
|
||||
\ które admini polecają."
|
||||
step5_6: "Polecana {icon} oś czasu to miejsce, gdzie możesz zobaczyć posty z instancji,\
|
||||
\ które admini polecają."
|
||||
step5_7: "Globalna {icon} oś czasu to miejsce, gdzie możesz zobaczyć posty z każdej\
|
||||
\ innej połączonej instancji."
|
||||
step6_1: "Więc, czym to jest to miejsce?"
|
||||
step6_2: "Cóż, nie dołączył*ś po prostu do Calckey. Dołączył*ś do portalu do Fediverse,
|
||||
połączonej sieci tysięcy serwerów, zwanych instancjami."
|
||||
step6_3: "Każdy serwer działa w inny sposób, i nie wszystkie serwery używają Calckey.
|
||||
Ten jednak używa! Jest to trochę skomplikowane, ale w krótkim czasie załapiesz
|
||||
o co chodzi."
|
||||
step6_2: "Cóż, nie dołączył*ś po prostu do Calckey. Dołączył*ś do portalu do Fediverse,\
|
||||
\ połączonej sieci tysięcy serwerów, zwanych instancjami."
|
||||
step6_3: "Każdy serwer działa w inny sposób, i nie wszystkie serwery używają Calckey.\
|
||||
\ Ten jednak używa! Jest to trochę skomplikowane, ale w krótkim czasie załapiesz\
|
||||
\ o co chodzi."
|
||||
step6_4: "A teraz idź, odkrywaj i baw się dobrze!"
|
||||
_2fa:
|
||||
alreadyRegistered: "Zarejestrowałeś już urządzenie do uwierzytelniania dwuskładnikowego."
|
||||
registerTOTP: "Zarejestruj nowe urządzenie"
|
||||
registerSecurityKey: "Zarejestruj klucz bezpieczeństwa"
|
||||
step1: "Najpierw, zainstaluj aplikację uwierzytelniającą (taką jak {a} lub {b})
|
||||
na swoim urządzeniu."
|
||||
registerDevice: "Zarejestruj nowe urządzenie"
|
||||
registerKey: "Zarejestruj klucz bezpieczeństwa"
|
||||
step1: "Najpierw, zainstaluj aplikację uwierzytelniającą (taką jak {a} lub {b})\
|
||||
\ na swoim urządzeniu."
|
||||
step2: "Następnie, zeskanuje kod QR z ekranu."
|
||||
step3: "Wprowadź token podany w aplikacji, aby ukończyć konfigurację."
|
||||
step4: "Od teraz, przy każdej próbie logowania otrzymasz prośbę o token logowania."
|
||||
|
@ -1403,8 +1404,8 @@ _profile:
|
|||
youCanIncludeHashtags: "Możesz umieścić hashtagi w swoim opisie."
|
||||
metadata: "Dodatkowe informacje"
|
||||
metadataEdit: "Edytuj dodatkowe informacje"
|
||||
metadataDescription: "Możesz wyświetlać do czterech sekcji dodatkowych informacji
|
||||
na swoim profilu."
|
||||
metadataDescription: "Możesz wyświetlać do czterech sekcji dodatkowych informacji\
|
||||
\ na swoim profilu."
|
||||
metadataLabel: "Etykieta"
|
||||
metadataContent: "Treść"
|
||||
changeAvatar: "Zmień awatar"
|
||||
|
@ -1814,12 +1815,12 @@ objectStorageSetPublicRead: Ustaw "public-read" podczas wysyłania
|
|||
removeAllFollowing: Przestań obserwować wszystkich obserwowanych użytkowników
|
||||
smtpSecure: Użyj implicit SSL/TLS dla połączeń SMTP
|
||||
secureMode: Tryb bezpieczny (Authorized Fetch)
|
||||
instanceSecurity: Bezpieczeństwo serwera
|
||||
instanceSecurity: Bezpieczeństwo instancji
|
||||
privateMode: Tryb prywatny
|
||||
allowedInstances: Dopuszczone serwery
|
||||
allowedInstances: Dopuszczone instancje
|
||||
recommended: Polecane
|
||||
allowedInstancesDescription: Hosty serwerów, które mają być dopuszczone do federacji,
|
||||
każdy oddzielony nowym wierszem (dotyczy tylko trybu prywatnego).
|
||||
allowedInstancesDescription: Hosty instancji które mają być dopuszczone do federacji,
|
||||
każdy separowany nową linią (dotyczy tylko trybu prywatnego).
|
||||
seperateRenoteQuote: Oddziel przyciski podbicia i cytowania
|
||||
refreshInterval: 'Częstotliwość aktualizacji '
|
||||
slow: Wolna
|
||||
|
@ -1845,34 +1846,34 @@ moveToLabel: 'Konto na które się przenosisz:'
|
|||
moveAccount: Przenieś konto!
|
||||
moveAccountDescription: Ten proces jest nieodwracalny. Upewnij się, że utworzył*ś
|
||||
alias dla tego konta na nowym koncie, przed rozpoczęciem. Proszę wpisz tag konta
|
||||
w formacie @osoba@serwer.com
|
||||
w formacie @person@instance.com
|
||||
moveFrom: Przejdź ze starego konta na obecne
|
||||
moveFromLabel: 'Konto które przenosisz:'
|
||||
showUpdates: Pokaż pop-up po aktualizacji Calckey
|
||||
swipeOnDesktop: Zezwól na przeciąganie w stylu mobilnym na desktopie
|
||||
moveFromDescription: To utworzy alias twojego starego konta, w celu umożliwienia migracji
|
||||
z tamtego konta na to. Zrób to ZANIM rozpoczniesz przenoszenie się z tamtego konta.
|
||||
Proszę wpisz tag konta w formacie @osoba@serwer.com
|
||||
migrationConfirm: "Czy jesteś absolutnie pewn* tego, że chcesz przenieść swoje konto
|
||||
na {account}? Tego działania nie można odwrócić. Nieodwracalnie stracisz możliwość
|
||||
normalnego korzystania z konta.\nUpewnij się, że to konto zostało ustawione jako
|
||||
konto z którego się przenosisz."
|
||||
Proszę wpisz tag konta w formacie @person@instance.com
|
||||
migrationConfirm: "Czy jesteś absolutnie pewn* tego, że chcesz przenieść swoje konto\
|
||||
\ na {account}? Tego działania nie można odwrócić. Nieodwracalnie stracisz możliwość\
|
||||
\ normalnego korzystania z konta.\nUpewnij się, że to konto zostało ustawione jako\
|
||||
\ konto z którego się przenosisz."
|
||||
noThankYou: Nie, dziękuję
|
||||
addInstance: Dodaj serwer
|
||||
addInstance: Dodaj instancję
|
||||
renoteMute: Wycisz podbicia
|
||||
renoteUnmute: Odcisz podbicia
|
||||
flagSpeakAsCat: Mów jak kot
|
||||
flagSpeakAsCatDescription: Twoje posty zostaną znya-izowane, gdy w trybie kota
|
||||
selectInstance: Wybierz serwer
|
||||
noInstances: Brak serwerów
|
||||
selectInstance: Wybierz instancję
|
||||
noInstances: Brak instancji
|
||||
keepOriginalUploadingDescription: Zapisuje oryginalne zdjęcie. Jeśli wyłączone, wersja
|
||||
do wyświetlania w sieci zostanie wygenerowana podczas wysłania.
|
||||
antennaInstancesDescription: Wymień jeden host serwera w każdym wierszu
|
||||
antennaInstancesDescription: Wypisz jednego hosta instancji na linię
|
||||
regexpError: Błąd regularnego wyrażenia
|
||||
regexpErrorDescription: 'Wystąpił błąd w regularnym wyrażeniu znajdującym się w linijce
|
||||
{line} Twoich {tab} wyciszeń słownych:'
|
||||
forwardReportIsAnonymous: Zamiast twojego konta, anonimowe konto systemowe będzie
|
||||
wyświetlane jako zgłaszający na zdalnym serwerze.
|
||||
forwardReportIsAnonymous: Zamiast Twojego konta, anonimowe konto systemowe zostanie
|
||||
wyświetlone na zdalnej instancji jako zgłaszający.
|
||||
breakFollowConfirm: Czy na pewno chcesz usunąć obserwującego?
|
||||
instanceDefaultThemeDescription: Wpisz kod motywu w formacie obiektowym.
|
||||
mutePeriod: Długość wyciszenia
|
||||
|
@ -1886,7 +1887,7 @@ pushNotification: Powiadomienia push
|
|||
subscribePushNotification: Włącz powiadomienia push
|
||||
unsubscribePushNotification: Wyłącz powiadomienia push
|
||||
pushNotificationAlreadySubscribed: Powiadomienia push są już włączone
|
||||
pushNotificationNotSupported: Twoja przeglądarka lub serwer nie obsługuje powiadomień
|
||||
pushNotificationNotSupported: Twoja przeglądarka lub instancja nie obsługuje powiadomień
|
||||
push
|
||||
sendPushNotificationReadMessage: Usuń powiadomienia push, gdy odpowiednie powiadomienia
|
||||
lub wiadomości zostaną odczytane
|
||||
|
@ -1911,20 +1912,21 @@ proxyAccountDescription: Konto proxy jest kontem które w określonych sytuacjac
|
|||
do listy, oraz żaden lokalny użytkownik nie obserwuje tego konta, aktywność owego
|
||||
użytkownika nie zostanie dostarczona na oś czasu. W takim razie, użytkownika zaobserwuje
|
||||
konto proxy.
|
||||
objectStorageBaseUrlDesc: "URL stosowany jako odniesienie. Podaj URL twojego CDN,
|
||||
albo proxy, jeśli używasz któregokolwiek.\nDla S3 użyj 'https://<bucket>.s3.amazonaws.com',
|
||||
a dla GCS i jego odpowiedników użyj 'https://storage.googleapis.com/<bucket>', itd."
|
||||
sendErrorReportsDescription: "Gdy ta opcja jest włączona, szczegółowe informacje o
|
||||
błędach będą udostępnianie z Calckey gdy wystąpi problem, pomagając w ulepszaniu
|
||||
Calckey.\nZawrze to informacje takie jak wersja twojego systemu operacyjnego, przeglądarki,
|
||||
Twoja aktywność na Calckey itd."
|
||||
privateModeInfo: Gdy ta opcja jest włączona, tylko serwery z białej listy mogą federować
|
||||
się z twoim serwerem. Wszystkie posty będą ukryte publicznie.
|
||||
objectStorageBaseUrlDesc: "URL stosowany jako odniesienie. Podaj URL twojego CDN,\
|
||||
\ albo proxy, jeśli używasz któregokolwiek.\nDla S3 użyj 'https://<bucket>.s3.amazonaws.com',\
|
||||
\ a dla GCS i jego odpowiedników użyj 'https://storage.googleapis.com/<bucket>',\
|
||||
\ itd."
|
||||
sendErrorReportsDescription: "Gdy ta opcja jest włączona, szczegółowe informacje o\
|
||||
\ błędach będą udostępnianie z Calckey gdy wystąpi problem, pomagając w ulepszaniu\
|
||||
\ Calckey.\nZawrze to informacje takie jak wersja twojego systemu operacyjnego,\
|
||||
\ przeglądarki, Twoja aktywność na Calckey itd."
|
||||
privateModeInfo: Jeśli włączone, tylko dopuszczone instancje będą mogły federować
|
||||
z Twoją instancją. Wszystkie posty będą jedynie widoczne na Twojej instancji.
|
||||
oneHour: Godzina
|
||||
oneDay: Dzień
|
||||
oneWeek: Tydzień
|
||||
recommendedInstances: Polecane serwery
|
||||
recommendedInstancesDescription: Polecane serwery, mające pojawić się w odpowiedniej
|
||||
recommendedInstances: Polecane instancje
|
||||
recommendedInstancesDescription: Polecane instancje, mające pojawić się w odpowiedniej
|
||||
osi czasu, oddzielane nowymi liniami. NIE dodawaj “https://”, TYLKO samą domenę.
|
||||
rateLimitExceeded: Przekroczono ratelimit
|
||||
cropImage: Kadruj zdjęcie
|
||||
|
@ -1934,9 +1936,7 @@ noEmailServerWarning: Serwer email nie jest skonfigurowany.
|
|||
thereIsUnresolvedAbuseReportWarning: Istnieją nierozwiązane zgłoszenia.
|
||||
check: Sprawdź
|
||||
driveCapOverrideLabel: Zmień pojemność dysku dla tego użytkownika
|
||||
isSystemAccount: To konto jest tworzone i automatycznie obsługiwane przez system.
|
||||
Nie moderuj, nie edytuj, nie usuwaj, ani w żaden inny sposób nie ingeruj w to konto,
|
||||
bowiem może to uszkodzić twój serwer.
|
||||
isSystemAccount: Konto założone i automatycznie zarządzane przez system.
|
||||
typeToConfirm: Wpisz {x} by potwierdzić
|
||||
deleteAccount: Usuń konto
|
||||
document: Dokumentacja
|
||||
|
@ -1982,51 +1982,34 @@ customKaTeXMacroDescription: 'Skonfiguruj makra, aby łatwo pisać wyrażenia ma
|
|||
nie można przerwać linii w środku definicji. Nieprawidłowe linie są po prostu ignorowane.
|
||||
Obsługiwane są tylko proste funkcje podstawiania łańcuchów; nie można tu stosować
|
||||
zaawansowanej składni, takiej jak warunkowe rozgałęzienia.'
|
||||
secureModeInfo: W przypadku żądań z innych serwerów nie odsyłaj bez dowodu.
|
||||
secureModeInfo: Nie odsyłaj bez dowodu przy żądaniu z innych instancji.
|
||||
preferencesBackups: Kopie zapasowe ustawień
|
||||
undeck: Opuść tablicę
|
||||
reporter: Osoba zgłaszająca
|
||||
instanceDefaultDarkTheme: Domyślny ciemny motyw serwera
|
||||
instanceDefaultDarkTheme: Domyślny ciemny motyw instancji
|
||||
lastCommunication: Ostatnie połączenie
|
||||
emailRequiredForSignup: Wymagaj adresu email przy rejestracji
|
||||
themeColor: Kolor znacznika serwera
|
||||
instanceDefaultLightTheme: Domyślny jasny motyw serwera
|
||||
themeColor: Kolor znacznika instancji
|
||||
instanceDefaultLightTheme: Domyślny jasny motyw instancji
|
||||
enableEmojiReactions: Włącz reakcje emoji
|
||||
showEmojisInReactionNotifications: Pokazuj emoji w powiadomieniach reakcyjnych
|
||||
apps: Aplikacje
|
||||
silenceThisInstance: Wycisz ten serwer
|
||||
silencedInstances: Wyciszone serwery
|
||||
silenceThisInstance: Wycisz tę instancję
|
||||
silencedInstances: Wyciszone instancje
|
||||
deleted: Usunięte
|
||||
editNote: Edytuj wpis
|
||||
edited: 'Edytowano o {date} {time}'
|
||||
edited: Edytowany
|
||||
silenced: Wyciszony
|
||||
findOtherInstance: Znajdź inny serwer
|
||||
userSaysSomethingReasonReply: '{name} odpowiedział na wpis zawierający {reason}'
|
||||
userSaysSomethingReasonRenote: '{name} podbił post zawierający {reason}'
|
||||
signupsDisabled: Rejestracja na tym serwerze jest obecnie zamknięta, ale zawsze możesz
|
||||
zarejestrować się na innym serwerze! Jeśli masz kod zaproszenia na ten serwer, wpisz
|
||||
go poniżej.
|
||||
się zapisać na innym! Jeśli masz kod zaproszeniowy na ten serwer, wpisz go poniżej.
|
||||
userSaysSomethingReasonQuote: '{name} zacytował wpis zawierający {reason}'
|
||||
silencedInstancesDescription: Wypisz nazwy hostów serwerów, które chcesz wyciszyć.
|
||||
Konta na wymienionych serwerach są traktowane jako "Wyciszone", mogą jedynie wysyłać
|
||||
prośby obserwacji i nie mogą oznaczać we wzmiankach profili lokalnych jeśli nie
|
||||
są obserwowane. To nie będzie miało wpływu na zablokowane serwery.
|
||||
silencedInstancesDescription: Wymień nazwy domenowe instancji, które chcesz wyciszyć.
|
||||
Profile w wyciszonych instancjach są traktowane jako "Wyciszony", mogą jedynie wysyłać
|
||||
prośby obserwacji, i nie mogą oznaczać w wzmiankach profili lokalnych jeśli nie
|
||||
są obserwowane. To nie będzie miało wpływu na zablokowane instancje.
|
||||
cannotUploadBecauseExceedsFileSizeLimit: Ten plik nie mógł być przesłany, ponieważ
|
||||
jego wielkość przekracza dozwolony limit.
|
||||
sendModMail: Wyślij Powiadomienie Moderacyjne
|
||||
searchPlaceholder: Szukaj Calckey
|
||||
jumpToPrevious: Przejdź do poprzedniej sekcji
|
||||
listsDesc: Listy umożliwiają tworzenie osi czasu z określonymi użytkownikami. Dostęp
|
||||
do nich można uzyskać na stronie osi czasu.
|
||||
accessibility: Dostępność
|
||||
selectChannel: Wybierz kanał
|
||||
antennasDesc: "Anteny wyświetlają nowe posty spełniające ustawione przez Ciebie kryteria!\n
|
||||
Dostęp do nich można uzyskać ze strony osi czasu."
|
||||
expandOnNoteClick: Otwórz post przy kliknięciu
|
||||
expandOnNoteClickDesc: Jeśli opcja ta jest wyłączona, nadal będzie można otwierać
|
||||
posty w menu po kliknięciu prawym przyciskiem myszy lub klikając znacznik czasowy.
|
||||
channelFederationWarn: Kanały nie są jeszcze federowane z innymi serwerami
|
||||
newer: nowsze
|
||||
older: starsze
|
||||
cw: Ostrzeżenie zawartości
|
||||
removeReaction: Usuń reakcję
|
||||
|
|
|
@ -1,87 +0,0 @@
|
|||
username: Nome de usuário
|
||||
ok: OK
|
||||
_lang_: Inglês
|
||||
headlineMisskey: Uma plataforma de mídia social descentralizada e de código aberto
|
||||
que é gratuita para sempre! 🚀
|
||||
search: Pesquisar
|
||||
gotIt: Entendi!
|
||||
introMisskey: Bem vinde! Calckey é uma plataforma de mídia social descentralizada
|
||||
e de código aberto que é gratuita para sempre! 🚀
|
||||
searchPlaceholder: Pesquise no Calckey
|
||||
notifications: Notificações
|
||||
password: Senha
|
||||
forgotPassword: Esqueci a senha
|
||||
cancel: Cancelar
|
||||
noThankYou: Não, obrigade
|
||||
save: Salvar
|
||||
enterUsername: Insira nome de usuário
|
||||
cw: Aviso de conteúdo
|
||||
driveFileDeleteConfirm: Tem a certeza de que pretende apagar o arquivo "{name}"? O
|
||||
arquivo será removido de todas as mensagens que o contenham como anexo.
|
||||
deleteAndEdit: Deletar e editar
|
||||
import: Importar
|
||||
exportRequested: Você pediu uma exportação. Isso pode demorar um pouco. Será adicionado
|
||||
ao seu Drive quando for completo.
|
||||
note: Postar
|
||||
notes: Postagens
|
||||
deleteAndEditConfirm: Você tem certeza que quer deletar esse post e edita-lo? Você
|
||||
vai perder todas as reações, impulsionamentos e respostas dele.
|
||||
showLess: Fechar
|
||||
importRequested: Você requisitou uma importação. Isso pode demorar um pouco.
|
||||
listsDesc: Listas deixam você criar linhas do tempo com usuários específicos. Elas
|
||||
podem ser acessadas pela página de linhas do tempo.
|
||||
edited: 'Editado às {date} {time}'
|
||||
sendMessage: Enviar uma mensagem
|
||||
older: antigo
|
||||
createList: Criar lista
|
||||
loadMore: Carregar mais
|
||||
mentions: Menções
|
||||
importAndExport: Importar/Exportar Dados
|
||||
files: Arquivos
|
||||
lists: Listas
|
||||
manageLists: Gerenciar listas
|
||||
error: Erro
|
||||
somethingHappened: Ocorreu um erro
|
||||
retry: Tentar novamente
|
||||
renotedBy: Impulsionado por {user}
|
||||
noNotes: Nenhum post
|
||||
noNotifications: Nenhuma notificação
|
||||
instance: Servidor
|
||||
settings: Configurações
|
||||
basicSettings: Configurações Básicas
|
||||
otherSettings: Outras Configurações
|
||||
openInWindow: Abrir em janela
|
||||
profile: Perfil
|
||||
noAccountDescription: Esse usuário ainda não escreveu sua bio.
|
||||
login: Entrar
|
||||
loggingIn: Entrando
|
||||
logout: Sair
|
||||
signup: Criar conta
|
||||
uploading: Enviando...
|
||||
users: Usuários
|
||||
addUser: Adicione um usuário
|
||||
addInstance: Adicionar um servidor
|
||||
cantFavorite: Não foi possível adicionar aos marcadores.
|
||||
pin: Fixar no perfil
|
||||
unpin: Desfixar do perfil
|
||||
copyContent: Copiar conteúdos
|
||||
copyLink: Copiar link
|
||||
delete: Deletar
|
||||
deleted: Deletado
|
||||
editNote: Editar anotação
|
||||
addToList: Adicionar a lista
|
||||
copyUsername: Copiar nome de usuário
|
||||
searchUser: Procurar por um usuário
|
||||
reply: Responder
|
||||
jumpToPrevious: Pular para o anterior
|
||||
showMore: Mostrar mais
|
||||
newer: novo
|
||||
youGotNewFollower: seguiu você
|
||||
mention: Mencionar
|
||||
directNotes: Mensagens diretas
|
||||
export: Exportar
|
||||
unfollowConfirm: Você tem certez que deseja para de seguir {name}?
|
||||
noLists: Você não possui nenhuma lista
|
||||
following: Seguindo
|
||||
followers: Seguidores
|
||||
followsYou: Segue você
|
|
@ -1249,8 +1249,8 @@ _tutorial:
|
|||
step6_4: "Теперь идите, изучайте и развлекайтесь!"
|
||||
_2fa:
|
||||
alreadyRegistered: "Двухфакторная аутентификация уже настроена."
|
||||
registerTOTP: "Зарегистрируйте ваше устройство"
|
||||
registerSecurityKey: "Зарегистрировать ключ"
|
||||
registerDevice: "Зарегистрируйте ваше устройство"
|
||||
registerKey: "Зарегистрировать ключ"
|
||||
step1: "Прежде всего, установите на устройство приложение для аутентификации, например,\
|
||||
\ {a} или {b}."
|
||||
step2: "Далее отсканируйте отображаемый QR-код при помощи приложения."
|
||||
|
@ -1987,5 +1987,5 @@ apps: Приложения
|
|||
silenceThisInstance: Заглушить инстанс
|
||||
silencedInstances: Заглушенные инстансы
|
||||
editNote: Редактировать заметку
|
||||
edited: 'Редактировано в {date} {time}'
|
||||
edited: Редактировано
|
||||
deleted: Удалённое
|
||||
|
|
|
@ -1196,8 +1196,8 @@ _tutorial:
|
|||
step6_4: "Now go, explore, and have fun!"
|
||||
_2fa:
|
||||
alreadyRegistered: "Už ste zaregistrovali 2-faktorové autentifikačné zariadenie."
|
||||
registerTOTP: "Registrovať nové zariadenie"
|
||||
registerSecurityKey: "Registrovať bezpečnostný kľúč"
|
||||
registerDevice: "Registrovať nové zariadenie"
|
||||
registerKey: "Registrovať bezpečnostný kľúč"
|
||||
step1: "Najprv si nainštalujte autentifikačnú aplikáciu (napríklad {a} alebo {b}) na svoje zariadenie."
|
||||
step2: "Potom, naskenujte QR kód zobrazený na obrazovke."
|
||||
step2Url: "Do aplikácie zadajte nasledujúcu URL adresu:"
|
||||
|
|
|
@ -959,7 +959,7 @@ _tutorial:
|
|||
step6_3: "Кожен сервер працює по-своєму, і не на всіх серверах працює Calckey. Але цей працює! Це трохи складно, але ви швидко розберетеся"
|
||||
step6_4: "Тепер ідіть, вивчайте і розважайтеся!"
|
||||
_2fa:
|
||||
registerSecurityKey: "Зареєструвати новий ключ безпеки"
|
||||
registerKey: "Зареєструвати новий ключ безпеки"
|
||||
_permissions:
|
||||
"read:account": "Переглядати дані профілю"
|
||||
"write:account": "Змінити дані акаунту"
|
||||
|
|
|
@ -1201,8 +1201,8 @@ _tutorial:
|
|||
step6_4: "Now go, explore, and have fun!"
|
||||
_2fa:
|
||||
alreadyRegistered: "Bạn đã đăng ký thiết bị xác minh 2 bước."
|
||||
registerTOTP: "Đăng ký một thiết bị"
|
||||
registerSecurityKey: "Đăng ký một mã bảo vệ"
|
||||
registerDevice: "Đăng ký một thiết bị"
|
||||
registerKey: "Đăng ký một mã bảo vệ"
|
||||
step1: "Trước tiên, hãy cài đặt một ứng dụng xác minh (chẳng hạn như {a} hoặc {b}) trên thiết bị của bạn."
|
||||
step2: "Sau đó, quét mã QR hiển thị trên màn hình này."
|
||||
step2Url: "Bạn cũng có thể nhập URL này nếu sử dụng một chương trình máy tính:"
|
||||
|
|
|
@ -1210,8 +1210,8 @@ _tutorial:
|
|||
step6_4: "现在去学习并享受乐趣!"
|
||||
_2fa:
|
||||
alreadyRegistered: "此设备已被注册"
|
||||
registerTOTP: "注册设备"
|
||||
registerSecurityKey: "注册密钥"
|
||||
registerDevice: "注册设备"
|
||||
registerKey: "注册密钥"
|
||||
step1: "首先,在您的设备上安装验证应用,例如{a}或{b}。"
|
||||
step2: "然后,扫描屏幕上显示的二维码。"
|
||||
step2Url: "在桌面应用程序中输入以下URL:"
|
||||
|
|
|
@ -1219,8 +1219,8 @@ _tutorial:
|
|||
step6_4: "現在開始探索吧!"
|
||||
_2fa:
|
||||
alreadyRegistered: "你已註冊過一個雙重認證的裝置。"
|
||||
registerTOTP: "註冊裝置"
|
||||
registerSecurityKey: "註冊鍵"
|
||||
registerDevice: "註冊裝置"
|
||||
registerKey: "註冊鍵"
|
||||
step1: "首先,在您的設備上安裝二步驗證程式,例如{a}或{b}。"
|
||||
step2: "然後,掃描螢幕上的QR code。"
|
||||
step2Url: "在桌面版應用中,請輸入以下的URL:"
|
||||
|
@ -1829,7 +1829,7 @@ indexPosts: 索引帖子
|
|||
indexNotice: 現在開始索引。 這可能需要一段時間,請不要在一個小時內重啟你的伺服器。
|
||||
deleted: 已刪除
|
||||
editNote: 編輯筆記
|
||||
edited: '於 {date} {time} 編輯'
|
||||
edited: 已修改
|
||||
userSaysSomethingReason: '{name} 說了 {reason}'
|
||||
allowedInstancesDescription: 要加入聯邦白名單的服務器,每台伺服器用新行分隔(僅適用於私有模式)。
|
||||
defaultReaction: 默認的表情符號反應
|
||||
|
@ -1840,9 +1840,3 @@ subscribePushNotification: 啟用推送通知
|
|||
unsubscribePushNotification: 禁用推送通知
|
||||
pushNotificationAlreadySubscribed: 推送通知已經啟用
|
||||
recommendedInstancesDescription: 以每行分隔的推薦服務器出現在推薦的時間軸中。 不要添加 `https://`,只添加域名。
|
||||
searchPlaceholder: 搜尋 Calckey
|
||||
cw: 內容警告
|
||||
selectChannel: 選擇一個頻道
|
||||
newer: 較新
|
||||
older: 較舊
|
||||
jumpToPrevious: 跳到上一個
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
{
|
||||
"name": "calckey",
|
||||
"version": "14.0.0-dev51",
|
||||
"version": "14.0.0-dev44",
|
||||
"codename": "aqua",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://codeberg.org/calckey/calckey.git"
|
||||
},
|
||||
"packageManager": "pnpm@8.6.2",
|
||||
"packageManager": "pnpm@8.6.1",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"rebuild": "pnpm run clean && pnpm -r run build && pnpm run gulp",
|
||||
|
|
|
@ -1,15 +0,0 @@
|
|||
export class RemoveShowTimelineReplies1684206886988 {
|
||||
name = "RemoveShowTimelineReplies1684206886988";
|
||||
|
||||
async up(queryRunner) {
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "user" DROP COLUMN "showTimelineReplies"`,
|
||||
);
|
||||
}
|
||||
|
||||
async down(queryRunner) {
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "user" ADD "showTimelineReplies" boolean NOT NULL DEFAULT false`,
|
||||
);
|
||||
}
|
||||
}
|
|
@ -1,17 +1,3 @@
|
|||
# Making migrations
|
||||
|
||||
For more information, please read https://www.sea-ql.org/SeaORM/docs/migration/setting-up-migration/
|
||||
|
||||
- Install `sea-orm-cli`
|
||||
```sh
|
||||
cargo install sea-orm-cli
|
||||
```
|
||||
|
||||
- Generate
|
||||
```sh
|
||||
sea-orm-cli migrate generate ****
|
||||
```
|
||||
|
||||
# Running Migrator CLI
|
||||
|
||||
- Generate a new migration file
|
||||
|
|
|
@ -29,7 +29,7 @@ pub fn convert_id(in_id: String, id_convert_type: IdConvertType) -> napi::Result
|
|||
Err(_) => {
|
||||
return Err(Error::new(
|
||||
Status::InvalidArg,
|
||||
"Unable to parse ID as MastodonId",
|
||||
"Unable to parse ID as MasstodonId",
|
||||
))
|
||||
}
|
||||
};
|
||||
|
|
|
@ -63,6 +63,8 @@ pub struct Model {
|
|||
pub hide_online_status: bool,
|
||||
#[sea_orm(column_name = "isDeleted")]
|
||||
pub is_deleted: bool,
|
||||
#[sea_orm(column_name = "showTimelineReplies")]
|
||||
pub show_timeline_replies: bool,
|
||||
#[sea_orm(column_name = "driveCapacityOverrideMb")]
|
||||
pub drive_capacity_override_mb: Option<i32>,
|
||||
#[sea_orm(column_name = "movedToUri")]
|
||||
|
|
|
@ -15,10 +15,10 @@
|
|||
"check:connect": "node ./check_connect.js",
|
||||
"build": "pnpm swc src -d built -D",
|
||||
"watch": "pnpm swc src -d built -D -w",
|
||||
"lint": "pnpm rome check --apply *",
|
||||
"lint": "pnpm rome check \"src/**/*.ts\"",
|
||||
"mocha": "cross-env NODE_ENV=test TS_NODE_FILES=true TS_NODE_TRANSPILE_ONLY=true TS_NODE_PROJECT=\"./test/tsconfig.json\" mocha",
|
||||
"test": "pnpm run mocha",
|
||||
"format": "pnpm rome format * --write"
|
||||
"format": "pnpm rome format * --write && pnpm rome check --apply *"
|
||||
},
|
||||
"resolutions": {
|
||||
"chokidar": "^3.3.1"
|
||||
|
@ -40,7 +40,7 @@
|
|||
"@peertube/http-signature": "1.7.0",
|
||||
"@redocly/openapi-core": "1.0.0-beta.120",
|
||||
"@sinonjs/fake-timers": "9.1.2",
|
||||
"@syuilo/aiscript": "0.11.1",
|
||||
"@syuilo/aiscript": "0.13.3",
|
||||
"@tensorflow/tfjs": "^4.2.0",
|
||||
"adm-zip": "^0.5.10",
|
||||
"ajv": "8.12.0",
|
||||
|
@ -101,7 +101,6 @@
|
|||
"nsfwjs": "2.4.2",
|
||||
"oauth": "^0.10.0",
|
||||
"os-utils": "0.0.14",
|
||||
"otpauth": "^9.1.2",
|
||||
"parse5": "7.1.2",
|
||||
"pg": "8.11.0",
|
||||
"private-ip": "2.3.4",
|
||||
|
@ -124,6 +123,7 @@
|
|||
"semver": "7.5.1",
|
||||
"sharp": "0.32.1",
|
||||
"sonic-channel": "^1.3.1",
|
||||
"speakeasy": "2.0.0",
|
||||
"stringz": "2.1.0",
|
||||
"summaly": "2.7.0",
|
||||
"syslog-pro": "1.0.0",
|
||||
|
@ -181,6 +181,7 @@
|
|||
"@types/semver": "7.5.0",
|
||||
"@types/sharp": "0.31.1",
|
||||
"@types/sinonjs__fake-timers": "8.1.2",
|
||||
"@types/speakeasy": "2.0.7",
|
||||
"@types/tinycolor2": "1.4.3",
|
||||
"@types/tmp": "0.2.3",
|
||||
"@types/uuid": "8.3.4",
|
||||
|
|
|
@ -135,24 +135,6 @@ export type MeilisearchNote = {
|
|||
createdAt: number;
|
||||
};
|
||||
|
||||
function timestampToUnix(timestamp: string) {
|
||||
let unix = 0;
|
||||
|
||||
// Only contains numbers => UNIX timestamp
|
||||
if (/^\d+$/.test(timestamp)) {
|
||||
unix = Number.parseInt(timestamp);
|
||||
}
|
||||
|
||||
if (unix === 0) {
|
||||
// Try to parse the timestamp as JavaScript Date
|
||||
const date = Date.parse(timestamp);
|
||||
if (isNaN(date)) return 0;
|
||||
unix = date / 1000;
|
||||
}
|
||||
|
||||
return unix;
|
||||
}
|
||||
|
||||
export default hasConfig
|
||||
? {
|
||||
search: async (
|
||||
|
@ -184,29 +166,8 @@ export default hasConfig
|
|||
constructedFilters.push(`mediaAttachment = "${fileType}"`);
|
||||
return null;
|
||||
} else if (term.startsWith("from:")) {
|
||||
let user = term.slice(5);
|
||||
|
||||
if (user.length === 0) return null;
|
||||
|
||||
// Cut off leading @, those aren't saved in the DB
|
||||
if (user.charAt(0) === "@") {
|
||||
user = user.slice(1);
|
||||
}
|
||||
|
||||
// Determine if we got a webfinger address or a single username
|
||||
if (user.split("@").length > 1) {
|
||||
let splitUser = user.split("@");
|
||||
|
||||
let domain = splitUser.pop();
|
||||
user = splitUser.join("@");
|
||||
|
||||
constructedFilters.push(
|
||||
`userName = ${user} AND userHost = ${domain}`,
|
||||
);
|
||||
} else {
|
||||
constructedFilters.push(`userName = ${user}`);
|
||||
}
|
||||
|
||||
const user = term.slice(5);
|
||||
constructedFilters.push(`userName = ${user}`);
|
||||
return null;
|
||||
} else if (term.startsWith("domain:")) {
|
||||
const domain = term.slice(7);
|
||||
|
@ -214,18 +175,17 @@ export default hasConfig
|
|||
return null;
|
||||
} else if (term.startsWith("after:")) {
|
||||
const timestamp = term.slice(6);
|
||||
|
||||
let unix = timestampToUnix(timestamp);
|
||||
|
||||
if (unix !== 0) constructedFilters.push(`createdAt > ${unix}`);
|
||||
|
||||
// Try to parse the timestamp as JavaScript Date
|
||||
const date = Date.parse(timestamp);
|
||||
if (isNaN(date)) return null;
|
||||
constructedFilters.push(`createdAt > ${date / 1000}`);
|
||||
return null;
|
||||
} else if (term.startsWith("before:")) {
|
||||
const timestamp = term.slice(7);
|
||||
|
||||
let unix = timestampToUnix(timestamp);
|
||||
if (unix !== 0) constructedFilters.push(`createdAt < ${unix}`);
|
||||
|
||||
// Try to parse the timestamp as JavaScript Date
|
||||
const date = Date.parse(timestamp);
|
||||
if (isNaN(date)) return null;
|
||||
constructedFilters.push(`createdAt < ${date / 1000}`);
|
||||
return null;
|
||||
} else if (term.startsWith("filter:following")) {
|
||||
// Check if we got a context user
|
||||
|
|
|
@ -5,6 +5,8 @@ import config from "@/config/index.js";
|
|||
|
||||
const logger = dbLogger.createSubLogger("sonic", "gray", false);
|
||||
|
||||
logger.info("Connecting to Sonic");
|
||||
|
||||
const handlers = (type: string): SonicChannel.Handlers => ({
|
||||
connected: () => {
|
||||
logger.succ(`Connected to Sonic ${type}`);
|
||||
|
@ -26,10 +28,6 @@ const handlers = (type: string): SonicChannel.Handlers => ({
|
|||
const hasConfig =
|
||||
config.sonic && (config.sonic.host || config.sonic.port || config.sonic.auth);
|
||||
|
||||
if (hasConfig) {
|
||||
logger.info("Connecting to Sonic");
|
||||
}
|
||||
|
||||
const host = hasConfig ? config.sonic.host ?? "localhost" : "";
|
||||
const port = hasConfig ? config.sonic.port ?? 1491 : 0;
|
||||
const auth = hasConfig ? config.sonic.auth ?? "SecretPassword" : "";
|
||||
|
|
|
@ -3,32 +3,6 @@ import { Meta } from "@/models/entities/meta.js";
|
|||
|
||||
let cache: Meta;
|
||||
|
||||
export function metaToPugArgs(meta: Meta): object {
|
||||
let motd = ["Loading..."];
|
||||
if (meta.customMOTD.length > 0) {
|
||||
motd = meta.customMOTD;
|
||||
}
|
||||
let splashIconUrl = meta.iconUrl;
|
||||
if (meta.customSplashIcons.length > 0) {
|
||||
splashIconUrl =
|
||||
meta.customSplashIcons[
|
||||
Math.floor(Math.random() * meta.customSplashIcons.length)
|
||||
];
|
||||
}
|
||||
|
||||
return {
|
||||
img: meta.bannerUrl,
|
||||
title: meta.name || "Calckey",
|
||||
instanceName: meta.name || "Calckey",
|
||||
desc: meta.description,
|
||||
icon: meta.iconUrl,
|
||||
splashIcon: splashIconUrl,
|
||||
themeColor: meta.themeColor,
|
||||
randomMOTD: motd[Math.floor(Math.random() * motd.length)],
|
||||
privateMode: meta.privateMode,
|
||||
};
|
||||
}
|
||||
|
||||
export async function fetchMeta(noCache = false): Promise<Meta> {
|
||||
if (!noCache && cache) return cache;
|
||||
|
||||
|
|
|
@ -249,6 +249,12 @@ export class User {
|
|||
})
|
||||
public followersUri: string | null;
|
||||
|
||||
@Column("boolean", {
|
||||
default: false,
|
||||
comment: "Whether to show users replying to other users in the timeline.",
|
||||
})
|
||||
public showTimelineReplies: boolean;
|
||||
|
||||
@Index({ unique: true })
|
||||
@Column("char", {
|
||||
length: 16,
|
||||
|
|
|
@ -28,7 +28,7 @@ import {
|
|||
import { db } from "@/db/postgre.js";
|
||||
import { IdentifiableError } from "@/misc/identifiable-error.js";
|
||||
|
||||
export async function populatePoll(note: Note, meId: User["id"] | null) {
|
||||
async function populatePoll(note: Note, meId: User["id"] | null) {
|
||||
const poll = await Polls.findOneByOrFail({ noteId: note.id });
|
||||
const choices = poll.choices.map((c) => ({
|
||||
text: c,
|
||||
|
|
|
@ -567,6 +567,7 @@ export const UserRepository = db.getRepository(User).extend({
|
|||
mutedInstances: profile!.mutedInstances,
|
||||
mutingNotificationTypes: profile!.mutingNotificationTypes,
|
||||
emailNotificationTypes: profile!.emailNotificationTypes,
|
||||
showTimelineReplies: user.showTimelineReplies || falsy,
|
||||
}
|
||||
: {}),
|
||||
|
||||
|
|
|
@ -17,7 +17,9 @@ export async function deleteAccount(
|
|||
logger.info(`Deleting account of ${job.data.user.id} ...`);
|
||||
|
||||
const user = await Users.findOneBy({ id: job.data.user.id });
|
||||
if (!user) return;
|
||||
if (user == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
{
|
||||
// Delete notes
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
import type Bull from "bull";
|
||||
import { Notes, PollVotes } from "@/models/index.js";
|
||||
import { In } from "typeorm";
|
||||
import { Notes, Polls, PollVotes } from "@/models/index.js";
|
||||
import { queueLogger } from "../logger.js";
|
||||
import type { EndedPollNotificationJobData } from "@/queue/types.js";
|
||||
import { createNotification } from "@/services/create-notification.js";
|
||||
import { deliverQuestionUpdate } from "@/services/note/polls/update.js";
|
||||
|
||||
const logger = queueLogger.createSubLogger("ended-poll-notification");
|
||||
|
||||
|
@ -32,8 +32,5 @@ export async function endedPollNotification(
|
|||
});
|
||||
}
|
||||
|
||||
// Broadcast the poll result once it ends
|
||||
await deliverQuestionUpdate(note.id);
|
||||
|
||||
done();
|
||||
}
|
||||
|
|
|
@ -34,9 +34,6 @@ export default async (job: Bull.Job<InboxJobData>): Promise<string> => {
|
|||
const info = Object.assign({}, activity) as any;
|
||||
info["@context"] = undefined;
|
||||
logger.debug(JSON.stringify(info, null, 2));
|
||||
|
||||
if (!signature?.keyId) return `Invalid signature: ${signature}`;
|
||||
|
||||
//#endregion
|
||||
const host = toPuny(new URL(signature.keyId).hostname);
|
||||
|
||||
|
|
|
@ -15,11 +15,9 @@ export async function deleteActor(
|
|||
return `skip: delete actor ${actor.uri} !== ${uri}`;
|
||||
}
|
||||
|
||||
const user = await Users.findOneBy({ id: actor.id });
|
||||
if (!user) {
|
||||
return `skip: actor ${actor.id} not found in the local database`;
|
||||
} else if (user.isDeleted) {
|
||||
return `skip: user ${user.id} already deleted`;
|
||||
const user = await Users.findOneByOrFail({ id: actor.id });
|
||||
if (user.isDeleted) {
|
||||
logger.info("skip: already deleted");
|
||||
}
|
||||
|
||||
const job = await createDeleteAccountJob(actor);
|
||||
|
|
|
@ -13,10 +13,11 @@ import type {
|
|||
import { htmlToMfm } from "../misc/html-to-mfm.js";
|
||||
import { extractApHashtags } from "./tag.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 { apLogger } from "../logger.js";
|
||||
import { DriveFile } from "@/models/entities/drive-file.js";
|
||||
import { deliverQuestionUpdate } from "@/services/note/polls/update.js";
|
||||
import { extractDbHost, toPuny } from "@/misc/convert-host.js";
|
||||
import {
|
||||
Emojis,
|
||||
|
@ -333,6 +334,9 @@ export async function createNote(
|
|||
`vote from AP: actor=${actor.username}@${actor.host}, note=${note.id}, choice=${name}`,
|
||||
);
|
||||
await vote(actor, reply, index);
|
||||
|
||||
// リモートフォロワーにUpdate配信
|
||||
deliverQuestionUpdate(reply.id);
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
|
|
@ -279,6 +279,7 @@ export async function createPerson(
|
|||
tags,
|
||||
isBot,
|
||||
isCat: (person as any).isCat === true,
|
||||
showTimelineReplies: false,
|
||||
}),
|
||||
)) as IRemoteUser;
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import config from "@/config/index.js";
|
||||
import Resolver from "../resolver.js";
|
||||
import type { IObject, IQuestion } from "../type.js";
|
||||
import { getApId, isQuestion } from "../type.js";
|
||||
import { isQuestion } from "../type.js";
|
||||
import { apLogger } from "../logger.js";
|
||||
import { Notes, Polls } from "@/models/index.js";
|
||||
import type { IPoll } from "@/models/entities/poll.js";
|
||||
|
@ -47,14 +47,11 @@ export async function extractPollFromQuestion(
|
|||
|
||||
/**
|
||||
* Update votes of Question
|
||||
* @param value URI of AP Question object or object itself
|
||||
* @param uri URI of AP Question object
|
||||
* @returns true if updated
|
||||
*/
|
||||
export async function updateQuestion(
|
||||
value: string | IQuestion,
|
||||
resolver?: Resolver,
|
||||
): Promise<boolean> {
|
||||
const uri = typeof value === "string" ? value : getApId(value);
|
||||
export async function updateQuestion(value: any, resolver?: Resolver) {
|
||||
const uri = typeof value === "string" ? value : value.id;
|
||||
|
||||
// Skip if URI points to this server
|
||||
if (uri.startsWith(`${config.url}/`)) throw new Error("uri points local");
|
||||
|
@ -68,23 +65,22 @@ export async function updateQuestion(
|
|||
//#endregion
|
||||
|
||||
// resolve new Question object
|
||||
const _resolver = resolver ?? new Resolver();
|
||||
const question = (await _resolver.resolve(value)) as IQuestion;
|
||||
if (resolver == null) resolver = new Resolver();
|
||||
const question = (await resolver.resolve(value)) as IQuestion;
|
||||
apLogger.debug(`fetched question: ${JSON.stringify(question, null, 2)}`);
|
||||
|
||||
if (question.type !== "Question") throw new Error("object is not a Question");
|
||||
|
||||
const apChoices = question.oneOf || question.anyOf;
|
||||
if (!apChoices) return false;
|
||||
|
||||
let changed = false;
|
||||
|
||||
for (const choice of poll.choices) {
|
||||
const oldCount = poll.votes[poll.choices.indexOf(choice)];
|
||||
const newCount = apChoices.filter((ap) => ap.name === choice)[0].replies
|
||||
?.totalItems;
|
||||
const newCount = apChoices!.filter((ap) => ap.name === choice)[0].replies!
|
||||
.totalItems;
|
||||
|
||||
if (newCount !== undefined && oldCount !== newCount) {
|
||||
if (oldCount !== newCount) {
|
||||
changed = true;
|
||||
poll.votes[poll.choices.indexOf(choice)] = newCount;
|
||||
}
|
||||
|
|
|
@ -4,8 +4,7 @@ import { Brackets } from "typeorm";
|
|||
|
||||
export function generateRepliesQuery(
|
||||
q: SelectQueryBuilder<any>,
|
||||
withReplies: boolean,
|
||||
me?: Pick<User, "id"> | null,
|
||||
me?: Pick<User, "id" | "showTimelineReplies"> | null,
|
||||
) {
|
||||
if (me == null) {
|
||||
q.andWhere(
|
||||
|
@ -21,21 +20,25 @@ export function generateRepliesQuery(
|
|||
);
|
||||
}),
|
||||
);
|
||||
} else if (!withReplies) {
|
||||
} else if (!me.showTimelineReplies) {
|
||||
q.andWhere(
|
||||
new Brackets((qb) => {
|
||||
qb.where("note.replyId IS NULL") // 返信ではない
|
||||
.orWhere("note.replyUserId = :meId", { meId: me.id }) // 返信だけど自分のノートへの返信
|
||||
.orWhere(
|
||||
new Brackets((qb) => {
|
||||
qb.where("note.replyId IS NOT NULL") // 返信だけど自分の行った返信
|
||||
.andWhere("note.userId = :meId", { meId: me.id });
|
||||
qb.where(
|
||||
// 返信だけど自分の行った返信
|
||||
"note.replyId IS NOT NULL",
|
||||
).andWhere("note.userId = :meId", { meId: me.id });
|
||||
}),
|
||||
)
|
||||
.orWhere(
|
||||
new Brackets((qb) => {
|
||||
qb.where("note.replyId IS NOT NULL") // 返信だけど投稿者自身への返信
|
||||
.andWhere("note.replyUserId = note.userId");
|
||||
qb.where(
|
||||
// 返信だけど投稿者自身への返信
|
||||
"note.replyId IS NOT NULL",
|
||||
).andWhere("note.replyUserId = note.userId");
|
||||
}),
|
||||
);
|
||||
}),
|
||||
|
|
|
@ -174,7 +174,6 @@ import * as ep___i_2fa_keyDone from "./endpoints/i/2fa/key-done.js";
|
|||
import * as ep___i_2fa_passwordLess from "./endpoints/i/2fa/password-less.js";
|
||||
import * as ep___i_2fa_registerKey from "./endpoints/i/2fa/register-key.js";
|
||||
import * as ep___i_2fa_register from "./endpoints/i/2fa/register.js";
|
||||
import * as ep___i_2fa_updateKey from "./endpoints/i/2fa/update-key.js";
|
||||
import * as ep___i_2fa_removeKey from "./endpoints/i/2fa/remove-key.js";
|
||||
import * as ep___i_2fa_unregister from "./endpoints/i/2fa/unregister.js";
|
||||
import * as ep___i_apps from "./endpoints/i/apps.js";
|
||||
|
@ -529,7 +528,6 @@ const eps = [
|
|||
["i/2fa/password-less", ep___i_2fa_passwordLess],
|
||||
["i/2fa/register-key", ep___i_2fa_registerKey],
|
||||
["i/2fa/register", ep___i_2fa_register],
|
||||
["i/2fa/update-key", ep___i_2fa_updateKey],
|
||||
["i/2fa/remove-key", ep___i_2fa_removeKey],
|
||||
["i/2fa/unregister", ep___i_2fa_unregister],
|
||||
["i/apps", ep___i_apps],
|
||||
|
|
|
@ -42,7 +42,6 @@ export default define(meta, paramDef, async (ps, me) => {
|
|||
isModerator: user.isModerator,
|
||||
isSilenced: user.isSilenced,
|
||||
isSuspended: user.isSuspended,
|
||||
moderationNote: profile.moderationNote,
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import define from "../../define.js";
|
||||
import config from "@/config/index.js";
|
||||
import { createPerson } from "@/remote/activitypub/models/person.js";
|
||||
import { createNote } from "@/remote/activitypub/models/note.js";
|
||||
import DbResolver from "@/remote/activitypub/db-resolver.js";
|
||||
|
@ -8,13 +9,11 @@ import { extractDbHost } from "@/misc/convert-host.js";
|
|||
import { Users, Notes } from "@/models/index.js";
|
||||
import type { Note } from "@/models/entities/note.js";
|
||||
import type { CacheableLocalUser, User } from "@/models/entities/user.js";
|
||||
import { fetchMeta } from "@/misc/fetch-meta.js";
|
||||
import { isActor, isPost, getApId } from "@/remote/activitypub/type.js";
|
||||
import type { SchemaType } from "@/misc/schema.js";
|
||||
import { HOUR } from "@/const.js";
|
||||
import { shouldBlockInstance } from "@/misc/should-block-instance.js";
|
||||
import { updateQuestion } from "@/remote/activitypub/models/question.js";
|
||||
import { populatePoll } from "@/models/repositories/note.js";
|
||||
import { redisClient } from "@/db/redis.js";
|
||||
|
||||
export const meta = {
|
||||
tags: ["federation"],
|
||||
|
@ -105,29 +104,18 @@ async function fetchAny(
|
|||
|
||||
const dbResolver = new DbResolver();
|
||||
|
||||
const [user, note] = await Promise.all([
|
||||
dbResolver.getUserFromApId(uri),
|
||||
dbResolver.getNoteFromApId(uri),
|
||||
]);
|
||||
let local = await mergePack(me, user, note);
|
||||
if (local) {
|
||||
if (local.type === "Note" && note?.uri && note.hasPoll) {
|
||||
// Update questions if the stored (remote) note contains the poll
|
||||
const key = `pollFetched:${note.uri}`;
|
||||
if ((await redisClient.exists(key)) === 0) {
|
||||
if (await updateQuestion(note.uri)) {
|
||||
local.object.poll = await populatePoll(note, me?.id ?? null);
|
||||
}
|
||||
// Allow fetching the poll again after 1 minute
|
||||
await redisClient.set(key, 1, "EX", 60);
|
||||
}
|
||||
}
|
||||
return local;
|
||||
}
|
||||
let local = await mergePack(
|
||||
me,
|
||||
...(await Promise.all([
|
||||
dbResolver.getUserFromApId(uri),
|
||||
dbResolver.getNoteFromApId(uri),
|
||||
])),
|
||||
);
|
||||
if (local != null) return local;
|
||||
|
||||
// fetching Object once from remote
|
||||
const resolver = new Resolver();
|
||||
const object = await resolver.resolve(uri);
|
||||
const object = (await resolver.resolve(uri)) as any;
|
||||
|
||||
// /@user If a URI other than the id is specified,
|
||||
// the URI is determined here
|
||||
|
@ -135,8 +123,8 @@ async function fetchAny(
|
|||
local = await mergePack(
|
||||
me,
|
||||
...(await Promise.all([
|
||||
dbResolver.getUserFromApId(getApId(object)),
|
||||
dbResolver.getNoteFromApId(getApId(object)),
|
||||
dbResolver.getUserFromApId(object.id),
|
||||
dbResolver.getNoteFromApId(object.id),
|
||||
])),
|
||||
);
|
||||
if (local != null) return local;
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
import { publishMainStream } from "@/services/stream.js";
|
||||
import * as OTPAuth from "otpauth";
|
||||
import * as speakeasy from "speakeasy";
|
||||
import define from "../../../define.js";
|
||||
import { Users, UserProfiles } from "@/models/index.js";
|
||||
import { UserProfiles } from "@/models/index.js";
|
||||
|
||||
export const meta = {
|
||||
requireCredential: true,
|
||||
|
@ -26,14 +25,13 @@ export default define(meta, paramDef, async (ps, user) => {
|
|||
throw new Error("二段階認証の設定が開始されていません");
|
||||
}
|
||||
|
||||
const delta = OTPAuth.TOTP.validate({
|
||||
secret: OTPAuth.Secret.fromBase32(profile.twoFactorTempSecret),
|
||||
digits: 6,
|
||||
token,
|
||||
window: 1,
|
||||
const verified = (speakeasy as any).totp.verify({
|
||||
secret: profile.twoFactorTempSecret,
|
||||
encoding: "base32",
|
||||
token: token,
|
||||
});
|
||||
|
||||
if (delta === null) {
|
||||
if (!verified) {
|
||||
throw new Error("not verified");
|
||||
}
|
||||
|
||||
|
@ -41,11 +39,4 @@ export default define(meta, paramDef, async (ps, user) => {
|
|||
twoFactorSecret: profile.twoFactorTempSecret,
|
||||
twoFactorEnabled: true,
|
||||
});
|
||||
|
||||
const iObj = await Users.pack(user.id, user, {
|
||||
detail: true,
|
||||
includeSecrets: true,
|
||||
});
|
||||
|
||||
publishMainStream(user.id, "meUpdated", iObj);
|
||||
});
|
||||
|
|
|
@ -28,7 +28,7 @@ export const paramDef = {
|
|||
attestationObject: { type: "string" },
|
||||
password: { type: "string" },
|
||||
challengeId: { type: "string" },
|
||||
name: { type: "string", minLength: 1, maxLength: 30 },
|
||||
name: { type: "string" },
|
||||
},
|
||||
required: [
|
||||
"clientDataJSON",
|
||||
|
|
|
@ -1,20 +1,10 @@
|
|||
import define from "../../../define.js";
|
||||
import { Users, UserProfiles, UserSecurityKeys } from "@/models/index.js";
|
||||
import { publishMainStream } from "@/services/stream.js";
|
||||
import { ApiError } from "../../../error.js";
|
||||
import { UserProfiles } from "@/models/index.js";
|
||||
|
||||
export const meta = {
|
||||
requireCredential: true,
|
||||
|
||||
secure: true,
|
||||
|
||||
errors: {
|
||||
noKey: {
|
||||
message: "No security key.",
|
||||
code: "NO_SECURITY_KEY",
|
||||
id: "f9c54d7f-d4c2-4d3c-9a8g-a70daac86512",
|
||||
},
|
||||
},
|
||||
} as const;
|
||||
|
||||
export const paramDef = {
|
||||
|
@ -26,36 +16,7 @@ export const paramDef = {
|
|||
} as const;
|
||||
|
||||
export default define(meta, paramDef, async (ps, user) => {
|
||||
if (ps.value === true) {
|
||||
// セキュリティキーがなければパスワードレスを有効にはできない
|
||||
const keyCount = await UserSecurityKeys.count({
|
||||
where: {
|
||||
userId: user.id,
|
||||
},
|
||||
select: {
|
||||
id: true,
|
||||
name: true,
|
||||
lastUsed: true,
|
||||
},
|
||||
});
|
||||
|
||||
if (keyCount === 0) {
|
||||
await UserProfiles.update(user.id, {
|
||||
usePasswordLessLogin: false,
|
||||
});
|
||||
|
||||
throw new ApiError(meta.errors.noKey);
|
||||
}
|
||||
}
|
||||
|
||||
await UserProfiles.update(user.id, {
|
||||
usePasswordLessLogin: ps.value,
|
||||
});
|
||||
|
||||
const iObj = await Users.pack(user.id, user, {
|
||||
detail: true,
|
||||
includeSecrets: true,
|
||||
});
|
||||
|
||||
publishMainStream(user.id, "meUpdated", iObj);
|
||||
});
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import * as OTPAuth from "otpauth";
|
||||
import * as speakeasy from "speakeasy";
|
||||
import * as QRCode from "qrcode";
|
||||
import config from "@/config/index.js";
|
||||
import { UserProfiles } from "@/models/index.js";
|
||||
|
@ -30,24 +30,25 @@ export default define(meta, paramDef, async (ps, user) => {
|
|||
}
|
||||
|
||||
// Generate user's secret key
|
||||
const secret = new OTPAuth.Secret();
|
||||
const secret = speakeasy.generateSecret({
|
||||
length: 32,
|
||||
});
|
||||
|
||||
await UserProfiles.update(user.id, {
|
||||
twoFactorTempSecret: secret.base32,
|
||||
});
|
||||
|
||||
// Get the data URL of the authenticator URL
|
||||
const totp = new OTPAuth.TOTP({
|
||||
secret,
|
||||
digits: 6,
|
||||
const url = speakeasy.otpauthURL({
|
||||
secret: secret.base32,
|
||||
encoding: "base32",
|
||||
label: user.username,
|
||||
issuer: config.host,
|
||||
});
|
||||
const url = totp.toString();
|
||||
const qr = await QRCode.toDataURL(url);
|
||||
const dataUrl = await QRCode.toDataURL(url);
|
||||
|
||||
return {
|
||||
qr,
|
||||
qr: dataUrl,
|
||||
url,
|
||||
secret: secret.base32,
|
||||
label: user.username,
|
||||
|
|
|
@ -34,24 +34,6 @@ export default define(meta, paramDef, async (ps, user) => {
|
|||
id: ps.credentialId,
|
||||
});
|
||||
|
||||
// 使われているキーがなくなったらパスワードレスログインをやめる
|
||||
const keyCount = await UserSecurityKeys.count({
|
||||
where: {
|
||||
userId: user.id,
|
||||
},
|
||||
select: {
|
||||
id: true,
|
||||
name: true,
|
||||
lastUsed: true,
|
||||
},
|
||||
});
|
||||
|
||||
if (keyCount === 0) {
|
||||
await UserProfiles.update(me.id, {
|
||||
usePasswordLessLogin: false,
|
||||
});
|
||||
}
|
||||
|
||||
// Publish meUpdated event
|
||||
publishMainStream(
|
||||
user.id,
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
import { publishMainStream } from "@/services/stream.js";
|
||||
import define from "../../../define.js";
|
||||
import { Users, UserProfiles } from "@/models/index.js";
|
||||
import { UserProfiles } from "@/models/index.js";
|
||||
import { comparePassword } from "@/misc/password.js";
|
||||
|
||||
export const meta = {
|
||||
|
@ -30,13 +29,5 @@ export default define(meta, paramDef, async (ps, user) => {
|
|||
await UserProfiles.update(user.id, {
|
||||
twoFactorSecret: null,
|
||||
twoFactorEnabled: false,
|
||||
usePasswordLessLogin: false,
|
||||
});
|
||||
|
||||
const iObj = await Users.pack(user.id, user, {
|
||||
detail: true,
|
||||
includeSecrets: true,
|
||||
});
|
||||
|
||||
publishMainStream(user.id, "meUpdated", iObj);
|
||||
});
|
||||
|
|
|
@ -1,58 +0,0 @@
|
|||
import { publishMainStream } from "@/services/stream.js";
|
||||
import define from "../../../define.js";
|
||||
import { Users, UserSecurityKeys } from "@/models/index.js";
|
||||
import { ApiError } from "../../../error.js";
|
||||
|
||||
export const meta = {
|
||||
requireCredential: true,
|
||||
|
||||
secure: true,
|
||||
|
||||
errors: {
|
||||
noSuchKey: {
|
||||
message: "No such key.",
|
||||
code: "NO_SUCH_KEY",
|
||||
id: "f9c5467f-d492-4d3c-9a8g-a70dacc86512",
|
||||
},
|
||||
|
||||
accessDenied: {
|
||||
message: "You do not have edit privilege of the channel.",
|
||||
code: "ACCESS_DENIED",
|
||||
id: "1fb7cb09-d46a-4fff-b8df-057708cce513",
|
||||
},
|
||||
},
|
||||
} as const;
|
||||
|
||||
export const paramDef = {
|
||||
type: "object",
|
||||
properties: {
|
||||
name: { type: "string", minLength: 1, maxLength: 30 },
|
||||
credentialId: { type: "string" },
|
||||
},
|
||||
required: ["name", "credentialId"],
|
||||
} as const;
|
||||
|
||||
export default define(meta, paramDef, async (ps, user) => {
|
||||
const key = await UserSecurityKeys.findOneBy({
|
||||
id: ps.credentialId,
|
||||
});
|
||||
|
||||
if (key == null) {
|
||||
throw new ApiError(meta.errors.noSuchKey);
|
||||
}
|
||||
|
||||
if (key.userId !== user.id) {
|
||||
throw new ApiError(meta.errors.accessDenied);
|
||||
}
|
||||
|
||||
await UserSecurityKeys.update(key.id, {
|
||||
name: ps.name,
|
||||
});
|
||||
|
||||
const iObj = await Users.pack(user.id, user, {
|
||||
detail: true,
|
||||
includeSecrets: true,
|
||||
});
|
||||
|
||||
publishMainStream(user.id, "meUpdated", iObj);
|
||||
});
|
|
@ -106,6 +106,7 @@ export const paramDef = {
|
|||
isBot: { type: "boolean" },
|
||||
isCat: { type: "boolean" },
|
||||
speakAsCat: { type: "boolean" },
|
||||
showTimelineReplies: { type: "boolean" },
|
||||
injectFeaturedNote: { type: "boolean" },
|
||||
receiveAnnouncementEmail: { type: "boolean" },
|
||||
alwaysMarkNsfw: { type: "boolean" },
|
||||
|
@ -184,6 +185,8 @@ export default define(meta, paramDef, async (ps, _user, token) => {
|
|||
if (typeof ps.publicReactions === "boolean")
|
||||
profileUpdates.publicReactions = ps.publicReactions;
|
||||
if (typeof ps.isBot === "boolean") updates.isBot = ps.isBot;
|
||||
if (typeof ps.showTimelineReplies === "boolean")
|
||||
updates.showTimelineReplies = ps.showTimelineReplies;
|
||||
if (typeof ps.carefulBot === "boolean")
|
||||
profileUpdates.carefulBot = ps.carefulBot;
|
||||
if (typeof ps.autoAcceptFollowed === "boolean")
|
||||
|
|
|
@ -33,7 +33,6 @@ import { renderActivity } from "@/remote/activitypub/renderer/index.js";
|
|||
import renderNote from "@/remote/activitypub/renderer/note.js";
|
||||
import renderUpdate from "@/remote/activitypub/renderer/update.js";
|
||||
import { deliverToRelays } from "@/services/relay.js";
|
||||
// import { deliverQuestionUpdate } from "@/services/note/polls/update.js";
|
||||
import { fetchMeta } from "@/misc/fetch-meta.js";
|
||||
|
||||
export const meta = {
|
||||
|
@ -477,20 +476,14 @@ export default define(meta, paramDef, async (ps, user) => {
|
|||
if (poll.noteVisibility !== ps.visibility) {
|
||||
pollUpdate.noteVisibility = ps.visibility;
|
||||
}
|
||||
// Keep votes for unmodified choices, reset votes if choice is modified or new
|
||||
const oldVoteCounts = new Map<string, number>();
|
||||
for (let i = 0; i < poll.choices.length; i++) {
|
||||
oldVoteCounts.set(poll.choices[i], poll.votes[i]);
|
||||
// We can't do an unordered equal check because the order of choices
|
||||
// is important and if it changes, we need to reset the votes.
|
||||
if (JSON.stringify(poll.choices) !== JSON.stringify(pp.choices)) {
|
||||
pollUpdate.choices = pp.choices;
|
||||
pollUpdate.votes = new Array(pp.choices.length).fill(0);
|
||||
}
|
||||
const newVotes = pp.choices.map(
|
||||
(choice) => oldVoteCounts.get(choice) || 0,
|
||||
);
|
||||
pollUpdate.choices = pp.choices;
|
||||
pollUpdate.votes = newVotes;
|
||||
if (notEmpty(pollUpdate)) {
|
||||
await Polls.update(note.id, pollUpdate);
|
||||
// Seemingly already handled by by the rendered update activity
|
||||
// await deliverQuestionUpdate(note.id);
|
||||
}
|
||||
publishing = true;
|
||||
}
|
||||
|
@ -600,7 +593,7 @@ export default define(meta, paramDef, async (ps, user) => {
|
|||
}
|
||||
|
||||
if (publishing) {
|
||||
index(note, true);
|
||||
index(note);
|
||||
|
||||
// Publish update event for the updated note details
|
||||
publishNoteStream(note.id, "updated", {
|
||||
|
|
|
@ -53,11 +53,6 @@ export const paramDef = {
|
|||
untilId: { type: "string", format: "misskey:id" },
|
||||
sinceDate: { type: "integer" },
|
||||
untilDate: { type: "integer" },
|
||||
withReplies: {
|
||||
type: "boolean",
|
||||
default: false,
|
||||
description: "Show replies in the timeline",
|
||||
},
|
||||
},
|
||||
required: [],
|
||||
} as const;
|
||||
|
@ -92,7 +87,7 @@ export default define(meta, paramDef, async (ps, user) => {
|
|||
.leftJoinAndSelect("renoteUser.avatar", "renoteUserAvatar")
|
||||
.leftJoinAndSelect("renoteUser.banner", "renoteUserBanner");
|
||||
|
||||
generateRepliesQuery(query, ps.withReplies, user);
|
||||
generateRepliesQuery(query, user);
|
||||
if (user) {
|
||||
generateMutedUserQuery(query, user);
|
||||
generateMutedNoteQuery(query, user);
|
||||
|
|
|
@ -60,11 +60,6 @@ export const paramDef = {
|
|||
default: false,
|
||||
description: "Only show notes that have attached files.",
|
||||
},
|
||||
withReplies: {
|
||||
type: "boolean",
|
||||
default: false,
|
||||
description: "Show replies in the timeline",
|
||||
},
|
||||
},
|
||||
required: [],
|
||||
} as const;
|
||||
|
@ -109,7 +104,7 @@ export default define(meta, paramDef, async (ps, user) => {
|
|||
.setParameters(followingQuery.getParameters());
|
||||
|
||||
generateChannelQuery(query, user);
|
||||
generateRepliesQuery(query, ps.withReplies, user);
|
||||
generateRepliesQuery(query, user);
|
||||
generateVisibilityQuery(query, user);
|
||||
generateMutedUserQuery(query, user);
|
||||
generateMutedNoteQuery(query, user);
|
||||
|
|
|
@ -63,11 +63,6 @@ export const paramDef = {
|
|||
untilId: { type: "string", format: "misskey:id" },
|
||||
sinceDate: { type: "integer" },
|
||||
untilDate: { type: "integer" },
|
||||
withReplies: {
|
||||
type: "boolean",
|
||||
default: false,
|
||||
description: "Show replies in the timeline",
|
||||
},
|
||||
},
|
||||
required: [],
|
||||
} as const;
|
||||
|
@ -102,7 +97,7 @@ export default define(meta, paramDef, async (ps, user) => {
|
|||
.leftJoinAndSelect("renoteUser.banner", "renoteUserBanner");
|
||||
|
||||
generateChannelQuery(query, user);
|
||||
generateRepliesQuery(query, ps.withReplies, user);
|
||||
generateRepliesQuery(query, user);
|
||||
generateVisibilityQuery(query, user);
|
||||
if (user) generateMutedUserQuery(query, user);
|
||||
if (user) generateMutedNoteQuery(query, user);
|
||||
|
|
|
@ -4,6 +4,7 @@ import { createNotification } from "@/services/create-notification.js";
|
|||
import { deliver } from "@/queue/index.js";
|
||||
import { renderActivity } from "@/remote/activitypub/renderer/index.js";
|
||||
import renderVote from "@/remote/activitypub/renderer/vote.js";
|
||||
import { deliverQuestionUpdate } from "@/services/note/polls/update.js";
|
||||
import {
|
||||
PollVotes,
|
||||
NoteWatchings,
|
||||
|
@ -177,4 +178,7 @@ export default define(meta, paramDef, async (ps, user) => {
|
|||
pollOwner.inbox,
|
||||
);
|
||||
}
|
||||
|
||||
// リモートフォロワーにUpdate配信
|
||||
deliverQuestionUpdate(note.id);
|
||||
});
|
||||
|
|
|
@ -63,11 +63,6 @@ export const paramDef = {
|
|||
untilId: { type: "string", format: "misskey:id" },
|
||||
sinceDate: { type: "integer" },
|
||||
untilDate: { type: "integer" },
|
||||
withReplies: {
|
||||
type: "boolean",
|
||||
default: false,
|
||||
description: "Show replies in the timeline",
|
||||
},
|
||||
},
|
||||
required: [],
|
||||
} as const;
|
||||
|
@ -105,7 +100,7 @@ export default define(meta, paramDef, async (ps, user) => {
|
|||
.leftJoinAndSelect("renoteUser.banner", "renoteUserBanner");
|
||||
|
||||
generateChannelQuery(query, user);
|
||||
generateRepliesQuery(query, ps.withReplies, user);
|
||||
generateRepliesQuery(query, user);
|
||||
generateVisibilityQuery(query, user);
|
||||
if (user) generateMutedUserQuery(query, user);
|
||||
if (user) generateMutedNoteQuery(query, user);
|
||||
|
|
|
@ -2,9 +2,9 @@ import { In } from "typeorm";
|
|||
import { Notes } from "@/models/index.js";
|
||||
import { Note } from "@/models/entities/note.js";
|
||||
import config from "@/config/index.js";
|
||||
import es from "@/db/elasticsearch.js";
|
||||
import sonic from "@/db/sonic.js";
|
||||
import meilisearch, { MeilisearchNote } from "@/db/meilisearch.js";
|
||||
import es from "../../../../db/elasticsearch.js";
|
||||
import sonic from "../../../../db/sonic.js";
|
||||
import meilisearch, { MeilisearchNote } from "../../../../db/meilisearch.js";
|
||||
import define from "../../define.js";
|
||||
import { makePaginationQuery } from "../../common/make-pagination-query.js";
|
||||
import { generateVisibilityQuery } from "../../common/generate-visibility-query.js";
|
||||
|
|
|
@ -54,11 +54,6 @@ export const paramDef = {
|
|||
default: false,
|
||||
description: "Only show notes that have attached files.",
|
||||
},
|
||||
withReplies: {
|
||||
type: "boolean",
|
||||
default: false,
|
||||
description: "Show replies in the timeline",
|
||||
},
|
||||
},
|
||||
required: [],
|
||||
} as const;
|
||||
|
@ -105,7 +100,7 @@ export default define(meta, paramDef, async (ps, user) => {
|
|||
.setParameters(followingQuery.getParameters());
|
||||
|
||||
generateChannelQuery(query, user);
|
||||
generateRepliesQuery(query, ps.withReplies, user);
|
||||
generateRepliesQuery(query, user);
|
||||
generateVisibilityQuery(query, user);
|
||||
generateMutedUserQuery(query, user);
|
||||
generateMutedNoteQuery(query, user);
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
import define from "../define.js";
|
||||
import { redisClient } from "@/db/redis.js";
|
||||
|
||||
export const meta = {
|
||||
tags: ["meta"],
|
||||
|
@ -17,15 +16,13 @@ export const paramDef = {
|
|||
|
||||
export default define(meta, paramDef, async () => {
|
||||
let patrons;
|
||||
const cachedPatrons = await redisClient.get("patrons");
|
||||
if (cachedPatrons) {
|
||||
patrons = JSON.parse(cachedPatrons);
|
||||
} else {
|
||||
patrons = await fetch(
|
||||
"https://codeberg.org/calckey/calckey/raw/branch/develop/patrons.json",
|
||||
).then((response) => response.json());
|
||||
await redisClient.set("patrons", JSON.stringify(patrons), "EX", 3600);
|
||||
}
|
||||
await fetch(
|
||||
"https://codeberg.org/calckey/calckey/raw/branch/develop/patrons.json",
|
||||
)
|
||||
.then((response) => response.json())
|
||||
.then((data) => {
|
||||
patrons = data["patrons"];
|
||||
});
|
||||
|
||||
return patrons["patrons"];
|
||||
return patrons;
|
||||
});
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { Instances, NoteReactions, Notes, Users } from "@/models/index.js";
|
||||
import define from "../define.js";
|
||||
import { driveChart, notesChart, usersChart } from "@/services/chart/index.js";
|
||||
import {} from "@/services/chart/index.js";
|
||||
import { IsNull } from "typeorm";
|
||||
|
||||
export const meta = {
|
||||
|
@ -60,25 +60,19 @@ export const paramDef = {
|
|||
} as const;
|
||||
|
||||
export default define(meta, paramDef, async () => {
|
||||
const notesChartData = await notesChart.getChart("hour", 1, null);
|
||||
const notesCount =
|
||||
notesChartData.local.total[0] + notesChartData.remote.total[0];
|
||||
const originalNotesCount = notesChartData.local.total[0];
|
||||
|
||||
const usersChartData = await usersChart.getChart("hour", 1, null);
|
||||
const usersCount =
|
||||
usersChartData.local.total[0] + usersChartData.remote.total[0];
|
||||
const originalUsersCount = usersChartData.local.total[0];
|
||||
const driveChartData = await driveChart.getChart("hour", 1, null);
|
||||
//TODO: fixme currently returns 0
|
||||
const driveUsageLocal = driveChartData.local.incSize[0];
|
||||
const driveUsageRemote = driveChartData.remote.incSize[0];
|
||||
|
||||
const [
|
||||
notesCount,
|
||||
originalNotesCount,
|
||||
usersCount,
|
||||
originalUsersCount,
|
||||
reactionsCount,
|
||||
//originalReactionsCount,
|
||||
instances,
|
||||
] = await Promise.all([
|
||||
Notes.count({ cache: 3600000 }), // 1 hour
|
||||
Notes.count({ where: { userHost: IsNull() }, cache: 3600000 }),
|
||||
Users.count({ cache: 3600000 }),
|
||||
Users.count({ where: { host: IsNull() }, cache: 3600000 }),
|
||||
NoteReactions.count({ cache: 3600000 }), // 1 hour
|
||||
//NoteReactions.count({ where: { userHost: IsNull() }, cache: 3600000 }),
|
||||
Instances.count({ cache: 3600000 }),
|
||||
|
@ -92,7 +86,7 @@ export default define(meta, paramDef, async () => {
|
|||
reactionsCount,
|
||||
//originalReactionsCount,
|
||||
instances,
|
||||
driveUsageLocal,
|
||||
driveUsageRemote,
|
||||
driveUsageLocal: 0,
|
||||
driveUsageRemote: 0,
|
||||
};
|
||||
});
|
||||
|
|
|
@ -37,12 +37,6 @@ export const meta = {
|
|||
code: "FORBIDDEN",
|
||||
id: "3c6a84db-d619-26af-ca14-06232a21df8a",
|
||||
},
|
||||
|
||||
nullFollowers: {
|
||||
message: "No followers found.",
|
||||
code: "NULL_FOLLOWERS",
|
||||
id: "174a6507-a6c2-4925-8e5d-92fd08aedc9e",
|
||||
},
|
||||
},
|
||||
} as const;
|
||||
|
||||
|
@ -103,7 +97,7 @@ export default define(meta, paramDef, async (ps, me) => {
|
|||
followerId: me.id,
|
||||
});
|
||||
if (following == null) {
|
||||
throw new ApiError(meta.errors.nullFollowers);
|
||||
throw new ApiError(meta.errors.forbidden);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,7 +12,7 @@ export async function getInstance(response: Entity.Instance) {
|
|||
uri: response.uri,
|
||||
title: response.title || "Calckey",
|
||||
short_description:
|
||||
response.description?.substring(0, 50) || "See real server website",
|
||||
response.description.substring(0, 50) || "See real server website",
|
||||
description:
|
||||
response.description ||
|
||||
"This is a vanilla Calckey Instance. It doesnt seem to have a description. BTW you are using the Mastodon api to access this server :)",
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import type Koa from "koa";
|
||||
import * as OTPAuth from "otpauth";
|
||||
import * as speakeasy from "speakeasy";
|
||||
import signin from "../common/signin.js";
|
||||
import config from "@/config/index.js";
|
||||
import {
|
||||
|
@ -136,18 +136,14 @@ export default async (ctx: Koa.Context) => {
|
|||
return;
|
||||
}
|
||||
|
||||
if (profile.twoFactorSecret == null) {
|
||||
throw new Error("Attempted 2FA signin without 2FA enabled.");
|
||||
}
|
||||
|
||||
const delta = OTPAuth.TOTP.validate({
|
||||
secret: OTPAuth.Secret.fromBase32(profile.twoFactorSecret),
|
||||
digits: 6,
|
||||
token,
|
||||
window: 1,
|
||||
const verified = (speakeasy as any).totp.verify({
|
||||
secret: profile.twoFactorSecret,
|
||||
encoding: "base32",
|
||||
token: token,
|
||||
window: 2,
|
||||
});
|
||||
|
||||
if (delta != null) {
|
||||
if (verified) {
|
||||
signin(ctx, user);
|
||||
return;
|
||||
} else {
|
||||
|
|
|
@ -34,7 +34,7 @@ export default class extends Channel {
|
|||
// 流れてきたNoteがブロックされているユーザーが関わるものだったら無視する
|
||||
if (isUserRelated(note, this.blocking)) return;
|
||||
|
||||
if (note.renote && !note.text && this.renoteMuting.has(note.userId))
|
||||
if (note.renote && !note.text && isUserRelated(note, this.renoteMuting))
|
||||
return;
|
||||
|
||||
this.connection.cacheNote(note);
|
||||
|
|
|
@ -37,7 +37,8 @@ export default class extends Channel {
|
|||
// 流れてきたNoteがブロックされているユーザーが関わるものだったら無視する
|
||||
if (isUserRelated(note, this.blocking)) return;
|
||||
|
||||
if (note.renote && !note.text && this.renoteMuting.has(note.userId)) return;
|
||||
if (note.renote && !note.text && isUserRelated(note, this.renoteMuting))
|
||||
return;
|
||||
|
||||
this.connection.cacheNote(note);
|
||||
|
||||
|
|
|
@ -9,7 +9,6 @@ export default class extends Channel {
|
|||
public readonly chName = "globalTimeline";
|
||||
public static shouldShare = true;
|
||||
public static requireCredential = false;
|
||||
private withReplies: boolean;
|
||||
|
||||
constructor(id: string, connection: Channel["connection"]) {
|
||||
super(id, connection);
|
||||
|
@ -23,8 +22,6 @@ export default class extends Channel {
|
|||
return;
|
||||
}
|
||||
|
||||
this.withReplies = params.withReplies as boolean;
|
||||
|
||||
// Subscribe events
|
||||
this.subscriber.on("notesStream", this.onNote);
|
||||
}
|
||||
|
@ -34,7 +31,7 @@ export default class extends Channel {
|
|||
if (note.channelId != null) return;
|
||||
|
||||
// 関係ない返信は除外
|
||||
if (note.reply && !this.withReplies) {
|
||||
if (note.reply && !this.user!.showTimelineReplies) {
|
||||
const reply = note.reply;
|
||||
// 「チャンネル接続主への返信」でもなければ、「チャンネル接続主が行った返信」でもなければ、「投稿者の投稿者自身への返信」でもない場合
|
||||
if (
|
||||
|
@ -59,7 +56,8 @@ export default class extends Channel {
|
|||
// 流れてきたNoteがブロックされているユーザーが関わるものだったら無視する
|
||||
if (isUserRelated(note, this.blocking)) return;
|
||||
|
||||
if (note.renote && !note.text && this.renoteMuting.has(note.userId)) return;
|
||||
if (note.renote && !note.text && isUserRelated(note, this.renoteMuting))
|
||||
return;
|
||||
|
||||
// 流れてきたNoteがミュートすべきNoteだったら無視する
|
||||
// TODO: 将来的には、単にMutedNoteテーブルにレコードがあるかどうかで判定したい(以下の理由により難しそうではある)
|
||||
|
|
|
@ -38,7 +38,8 @@ export default class extends Channel {
|
|||
// 流れてきたNoteがブロックされているユーザーが関わるものだったら無視する
|
||||
if (isUserRelated(note, this.blocking)) return;
|
||||
|
||||
if (note.renote && !note.text && this.renoteMuting.has(note.userId)) return;
|
||||
if (note.renote && !note.text && isUserRelated(note, this.renoteMuting))
|
||||
return;
|
||||
|
||||
this.connection.cacheNote(note);
|
||||
|
||||
|
|
|
@ -8,7 +8,6 @@ export default class extends Channel {
|
|||
public readonly chName = "homeTimeline";
|
||||
public static shouldShare = true;
|
||||
public static requireCredential = true;
|
||||
private withReplies: boolean;
|
||||
|
||||
constructor(id: string, connection: Channel["connection"]) {
|
||||
super(id, connection);
|
||||
|
@ -16,8 +15,6 @@ export default class extends Channel {
|
|||
}
|
||||
|
||||
public async init(params: any) {
|
||||
this.withReplies = params.withReplies as boolean;
|
||||
|
||||
// Subscribe events
|
||||
this.subscriber.on("notesStream", this.onNote);
|
||||
}
|
||||
|
@ -42,7 +39,7 @@ export default class extends Channel {
|
|||
return;
|
||||
|
||||
// 関係ない返信は除外
|
||||
if (note.reply && !this.withReplies) {
|
||||
if (note.reply && !this.user!.showTimelineReplies) {
|
||||
const reply = note.reply;
|
||||
// 「チャンネル接続主への返信」でもなければ、「チャンネル接続主が行った返信」でもなければ、「投稿者の投稿者自身への返信」でもない場合
|
||||
if (
|
||||
|
@ -58,7 +55,8 @@ export default class extends Channel {
|
|||
// 流れてきたNoteがブロックされているユーザーが関わるものだったら無視する
|
||||
if (isUserRelated(note, this.blocking)) return;
|
||||
|
||||
if (note.renote && !note.text && this.renoteMuting.has(note.userId)) return;
|
||||
if (note.renote && !note.text && isUserRelated(note, this.renoteMuting))
|
||||
return;
|
||||
|
||||
// 流れてきたNoteがミュートすべきNoteだったら無視する
|
||||
// TODO: 将来的には、単にMutedNoteテーブルにレコードがあるかどうかで判定したい(以下の理由により難しそうではある)
|
||||
|
|
|
@ -9,7 +9,6 @@ export default class extends Channel {
|
|||
public readonly chName = "hybridTimeline";
|
||||
public static shouldShare = true;
|
||||
public static requireCredential = true;
|
||||
private withReplies: boolean;
|
||||
|
||||
constructor(id: string, connection: Channel["connection"]) {
|
||||
super(id, connection);
|
||||
|
@ -25,8 +24,6 @@ export default class extends Channel {
|
|||
)
|
||||
return;
|
||||
|
||||
this.withReplies = params.withReplies as boolean;
|
||||
|
||||
// Subscribe events
|
||||
this.subscriber.on("notesStream", this.onNote);
|
||||
}
|
||||
|
@ -59,7 +56,7 @@ export default class extends Channel {
|
|||
return;
|
||||
|
||||
// 関係ない返信は除外
|
||||
if (note.reply && !this.withReplies) {
|
||||
if (note.reply && !this.user!.showTimelineReplies) {
|
||||
const reply = note.reply;
|
||||
// 「チャンネル接続主への返信」でもなければ、「チャンネル接続主が行った返信」でもなければ、「投稿者の投稿者自身への返信」でもない場合
|
||||
if (
|
||||
|
@ -75,7 +72,8 @@ export default class extends Channel {
|
|||
// 流れてきたNoteがブロックされているユーザーが関わるものだったら無視する
|
||||
if (isUserRelated(note, this.blocking)) return;
|
||||
|
||||
if (note.renote && !note.text && this.renoteMuting.has(note.userId)) return;
|
||||
if (note.renote && !note.text && isUserRelated(note, this.renoteMuting))
|
||||
return;
|
||||
|
||||
// 流れてきたNoteがミュートすべきNoteだったら無視する
|
||||
// TODO: 将来的には、単にMutedNoteテーブルにレコードがあるかどうかで判定したい(以下の理由により難しそうではある)
|
||||
|
|
|
@ -8,7 +8,6 @@ export default class extends Channel {
|
|||
public readonly chName = "localTimeline";
|
||||
public static shouldShare = true;
|
||||
public static requireCredential = false;
|
||||
private withReplies: boolean;
|
||||
|
||||
constructor(id: string, connection: Channel["connection"]) {
|
||||
super(id, connection);
|
||||
|
@ -22,8 +21,6 @@ export default class extends Channel {
|
|||
return;
|
||||
}
|
||||
|
||||
this.withReplies = params.withReplies as boolean;
|
||||
|
||||
// Subscribe events
|
||||
this.subscriber.on("notesStream", this.onNote);
|
||||
}
|
||||
|
@ -35,7 +32,7 @@ export default class extends Channel {
|
|||
return;
|
||||
|
||||
// 関係ない返信は除外
|
||||
if (note.reply && !this.withReplies) {
|
||||
if (note.reply && !this.user!.showTimelineReplies) {
|
||||
const reply = note.reply;
|
||||
// 「チャンネル接続主への返信」でもなければ、「チャンネル接続主が行った返信」でもなければ、「投稿者の投稿者自身への返信」でもない場合
|
||||
if (
|
||||
|
@ -51,7 +48,8 @@ export default class extends Channel {
|
|||
// 流れてきたNoteがブロックされているユーザーが関わるものだったら無視する
|
||||
if (isUserRelated(note, this.blocking)) return;
|
||||
|
||||
if (note.renote && !note.text && this.renoteMuting.has(note.userId)) return;
|
||||
if (note.renote && !note.text && isUserRelated(note, this.renoteMuting))
|
||||
return;
|
||||
|
||||
// 流れてきたNoteがミュートすべきNoteだったら無視する
|
||||
// TODO: 将来的には、単にMutedNoteテーブルにレコードがあるかどうかで判定したい(以下の理由により難しそうではある)
|
||||
|
|
|
@ -9,7 +9,6 @@ export default class extends Channel {
|
|||
public readonly chName = "recommendedTimeline";
|
||||
public static shouldShare = true;
|
||||
public static requireCredential = true;
|
||||
private withReplies: boolean;
|
||||
|
||||
constructor(id: string, connection: Channel["connection"]) {
|
||||
super(id, connection);
|
||||
|
@ -25,8 +24,6 @@ export default class extends Channel {
|
|||
)
|
||||
return;
|
||||
|
||||
this.withReplies = params.withReplies as boolean;
|
||||
|
||||
// Subscribe events
|
||||
this.subscriber.on("notesStream", this.onNote);
|
||||
}
|
||||
|
@ -57,7 +54,7 @@ export default class extends Channel {
|
|||
return;
|
||||
|
||||
// 関係ない返信は除外
|
||||
if (note.reply && !this.withReplies) {
|
||||
if (note.reply && !this.user!.showTimelineReplies) {
|
||||
const reply = note.reply;
|
||||
// 「チャンネル接続主への返信」でもなければ、「チャンネル接続主が行った返信」でもなければ、「投稿者の投稿者自身への返信」でもない場合
|
||||
if (
|
||||
|
@ -73,7 +70,8 @@ export default class extends Channel {
|
|||
// 流れてきたNoteがブロックされているユーザーが関わるものだったら無視する
|
||||
if (isUserRelated(note, this.blocking)) return;
|
||||
|
||||
if (note.renote && !note.text && this.renoteMuting.has(note.userId)) return;
|
||||
if (note.renote && !note.text && isUserRelated(note, this.renoteMuting))
|
||||
return;
|
||||
|
||||
// 流れてきたNoteがミュートすべきNoteだったら無視する
|
||||
// TODO: 将来的には、単にMutedNoteテーブルにレコードがあるかどうかで判定したい(以下の理由により難しそうではある)
|
||||
|
|
|
@ -57,7 +57,8 @@ export default class extends Channel {
|
|||
// 流れてきたNoteがブロックされているユーザーが関わるものだったら無視する
|
||||
if (isUserRelated(note, this.blocking)) return;
|
||||
|
||||
if (note.renote && !note.text && this.renoteMuting.has(note.userId)) return;
|
||||
if (note.renote && !note.text && isUserRelated(note, this.renoteMuting))
|
||||
return;
|
||||
|
||||
this.send("note", note);
|
||||
}
|
||||
|
|
|
@ -95,14 +95,9 @@
|
|||
}
|
||||
//#endregion
|
||||
|
||||
let fontSize = localStorage.getItem("fontSize");
|
||||
const fontSize = localStorage.getItem("fontSize");
|
||||
if (fontSize) {
|
||||
if (fontSize < 10) {
|
||||
// need to do this for now, as values before were 1, 2, 3 depending on the option
|
||||
localStorage.setItem("fontSize", null);
|
||||
fontSize = localStorage.getItem("fontSize");
|
||||
}
|
||||
document.documentElement.style.fontSize = fontSize + "px";
|
||||
document.documentElement.classList.add("f-" + fontSize);
|
||||
}
|
||||
|
||||
const useSystemFont = localStorage.getItem("useSystemFont");
|
||||
|
|
|
@ -16,7 +16,7 @@ import { BullAdapter } from "@bull-board/api/bullAdapter.js";
|
|||
import { KoaAdapter } from "@bull-board/koa";
|
||||
|
||||
import { In, IsNull } from "typeorm";
|
||||
import { fetchMeta, metaToPugArgs } from "@/misc/fetch-meta.js";
|
||||
import { fetchMeta } from "@/misc/fetch-meta.js";
|
||||
import config from "@/config/index.js";
|
||||
import {
|
||||
Users,
|
||||
|
@ -362,12 +362,15 @@ const userPage: Router.Middleware = async (ctx, next) => {
|
|||
: [];
|
||||
|
||||
const userDetail = {
|
||||
...metaToPugArgs(meta),
|
||||
user,
|
||||
profile,
|
||||
me,
|
||||
avatarUrl: await Users.getAvatarUrl(user),
|
||||
sub: subParam,
|
||||
instanceName: meta.name || "Calckey",
|
||||
icon: meta.iconUrl,
|
||||
themeColor: meta.themeColor,
|
||||
privateMode: meta.privateMode,
|
||||
};
|
||||
|
||||
await ctx.render("user", userDetail);
|
||||
|
@ -405,7 +408,6 @@ router.get("/notes/:note", async (ctx, next) => {
|
|||
});
|
||||
const meta = await fetchMeta();
|
||||
await ctx.render("note", {
|
||||
...metaToPugArgs(meta),
|
||||
note: _note,
|
||||
profile,
|
||||
avatarUrl: await Users.getAvatarUrl(
|
||||
|
@ -413,12 +415,16 @@ router.get("/notes/:note", async (ctx, next) => {
|
|||
),
|
||||
// TODO: Let locale changeable by instance setting
|
||||
summary: getNoteSummary(_note),
|
||||
instanceName: meta.name || "Calckey",
|
||||
icon: meta.iconUrl,
|
||||
privateMode: meta.privateMode,
|
||||
themeColor: meta.themeColor,
|
||||
});
|
||||
|
||||
ctx.set("Cache-Control", "public, max-age=15");
|
||||
ctx.set(
|
||||
"Content-Security-Policy",
|
||||
"default-src 'self' 'unsafe-inline'; img-src *; frame-ancestors *",
|
||||
"default-src 'self'; frame-ancestors '*'",
|
||||
);
|
||||
|
||||
return;
|
||||
|
@ -439,7 +445,6 @@ router.get("/posts/:note", async (ctx, next) => {
|
|||
const profile = await UserProfiles.findOneByOrFail({ userId: note.userId });
|
||||
const meta = await fetchMeta();
|
||||
await ctx.render("note", {
|
||||
...metaToPugArgs(meta),
|
||||
note: _note,
|
||||
profile,
|
||||
avatarUrl: await Users.getAvatarUrl(
|
||||
|
@ -447,6 +452,10 @@ router.get("/posts/:note", async (ctx, next) => {
|
|||
),
|
||||
// TODO: Let locale changeable by instance setting
|
||||
summary: getNoteSummary(_note),
|
||||
instanceName: meta.name || "Calckey",
|
||||
icon: meta.iconUrl,
|
||||
privateMode: meta.privateMode,
|
||||
themeColor: meta.themeColor,
|
||||
});
|
||||
|
||||
ctx.set("Cache-Control", "public, max-age=15");
|
||||
|
@ -477,12 +486,15 @@ router.get("/@:user/pages/:page", async (ctx, next) => {
|
|||
const profile = await UserProfiles.findOneByOrFail({ userId: page.userId });
|
||||
const meta = await fetchMeta();
|
||||
await ctx.render("page", {
|
||||
...metaToPugArgs(meta),
|
||||
page: _page,
|
||||
profile,
|
||||
avatarUrl: await Users.getAvatarUrl(
|
||||
await Users.findOneByOrFail({ id: page.userId }),
|
||||
),
|
||||
instanceName: meta.name || "Calckey",
|
||||
icon: meta.iconUrl,
|
||||
themeColor: meta.themeColor,
|
||||
privateMode: meta.privateMode,
|
||||
});
|
||||
|
||||
if (["public"].includes(page.visibility)) {
|
||||
|
@ -509,12 +521,15 @@ router.get("/clips/:clip", async (ctx, next) => {
|
|||
const profile = await UserProfiles.findOneByOrFail({ userId: clip.userId });
|
||||
const meta = await fetchMeta();
|
||||
await ctx.render("clip", {
|
||||
...metaToPugArgs(meta),
|
||||
clip: _clip,
|
||||
profile,
|
||||
avatarUrl: await Users.getAvatarUrl(
|
||||
await Users.findOneByOrFail({ id: clip.userId }),
|
||||
),
|
||||
instanceName: meta.name || "Calckey",
|
||||
privateMode: meta.privateMode,
|
||||
icon: meta.iconUrl,
|
||||
themeColor: meta.themeColor,
|
||||
});
|
||||
|
||||
ctx.set("Cache-Control", "public, max-age=15");
|
||||
|
@ -534,12 +549,15 @@ router.get("/gallery/:post", async (ctx, next) => {
|
|||
const profile = await UserProfiles.findOneByOrFail({ userId: post.userId });
|
||||
const meta = await fetchMeta();
|
||||
await ctx.render("gallery-post", {
|
||||
...metaToPugArgs(meta),
|
||||
post: _post,
|
||||
profile,
|
||||
avatarUrl: await Users.getAvatarUrl(
|
||||
await Users.findOneByOrFail({ id: post.userId }),
|
||||
),
|
||||
instanceName: meta.name || "Calckey",
|
||||
icon: meta.iconUrl,
|
||||
themeColor: meta.themeColor,
|
||||
privateMode: meta.privateMode,
|
||||
});
|
||||
|
||||
ctx.set("Cache-Control", "public, max-age=15");
|
||||
|
@ -560,8 +578,11 @@ router.get("/channels/:channel", async (ctx, next) => {
|
|||
const _channel = await Channels.pack(channel);
|
||||
const meta = await fetchMeta();
|
||||
await ctx.render("channel", {
|
||||
...metaToPugArgs(meta),
|
||||
channel: _channel,
|
||||
instanceName: meta.name || "Calckey",
|
||||
icon: meta.iconUrl,
|
||||
themeColor: meta.themeColor,
|
||||
privateMode: meta.privateMode,
|
||||
});
|
||||
|
||||
ctx.set("Cache-Control", "public, max-age=15");
|
||||
|
@ -612,9 +633,27 @@ router.get("/api/v1/streaming", async (ctx) => {
|
|||
// Render base html for all requests
|
||||
router.get("(.*)", async (ctx) => {
|
||||
const meta = await fetchMeta();
|
||||
|
||||
let motd = ["Loading..."];
|
||||
if (meta.customMOTD.length > 0) {
|
||||
motd = meta.customMOTD;
|
||||
}
|
||||
let splashIconUrl = meta.iconUrl;
|
||||
if (meta.customSplashIcons.length > 0) {
|
||||
splashIconUrl =
|
||||
meta.customSplashIcons[
|
||||
Math.floor(Math.random() * meta.customSplashIcons.length)
|
||||
];
|
||||
}
|
||||
await ctx.render("base", {
|
||||
...metaToPugArgs(meta),
|
||||
img: meta.bannerUrl,
|
||||
title: meta.name || "Calckey",
|
||||
instanceName: meta.name || "Calckey",
|
||||
desc: meta.description,
|
||||
icon: meta.iconUrl,
|
||||
splashIcon: splashIconUrl,
|
||||
themeColor: meta.themeColor,
|
||||
randomMOTD: motd[Math.floor(Math.random() * motd.length)],
|
||||
privateMode: meta.privateMode,
|
||||
});
|
||||
ctx.set("Cache-Control", "public, max-age=3");
|
||||
});
|
||||
|
|
|
@ -2,12 +2,6 @@ html {
|
|||
background-color: var(--bg);
|
||||
color: var(--fg);
|
||||
}
|
||||
@media (prefers-color-scheme: dark) {
|
||||
html {
|
||||
--bg: rgb(17, 17, 27);
|
||||
--fg: rgb(224, 222, 244);
|
||||
}
|
||||
}
|
||||
|
||||
#splash {
|
||||
position: fixed;
|
||||
|
|
|
@ -56,7 +56,7 @@ import { checkHitAntenna } from "@/misc/check-hit-antenna.js";
|
|||
import { getWordHardMute } from "@/misc/check-word-mute.js";
|
||||
import { addNoteToAntenna } from "../add-note-to-antenna.js";
|
||||
import { countSameRenotes } from "@/misc/count-same-renotes.js";
|
||||
import { deliverToRelays, getCachedRelays } from "../relay.js";
|
||||
import { deliverToRelays } from "../relay.js";
|
||||
import type { Channel } from "@/models/entities/channel.js";
|
||||
import { normalizeForSearch } from "@/misc/normalize-for-search.js";
|
||||
import { getAntennas } from "@/misc/antenna-cache.js";
|
||||
|
@ -68,7 +68,6 @@ import { db } from "@/db/postgre.js";
|
|||
import { getActiveWebhooks } from "@/misc/webhook-cache.js";
|
||||
import { shouldSilenceInstance } from "@/misc/should-block-instance.js";
|
||||
import meilisearch from "../../db/meilisearch.js";
|
||||
import { redisClient } from "@/db/redis.js";
|
||||
|
||||
const mutedWordsCache = new Cache<
|
||||
{ userId: UserProfile["userId"]; mutedWords: UserProfile["mutedWords"] }[]
|
||||
|
@ -166,7 +165,6 @@ export default async (
|
|||
isSilenced: User["isSilenced"];
|
||||
createdAt: User["createdAt"];
|
||||
isBot: User["isBot"];
|
||||
inbox?: User["inbox"];
|
||||
},
|
||||
data: Option,
|
||||
silent = false,
|
||||
|
@ -455,37 +453,7 @@ export default async (
|
|||
}
|
||||
|
||||
if (!dontFederateInitially) {
|
||||
const relays = await getCachedRelays();
|
||||
// Some relays (e.g., aode-relay) deliver posts by boosting them as
|
||||
// Announce activities. In that case, user is the relay's actor.
|
||||
const boostedByRelay =
|
||||
!!user.inbox &&
|
||||
relays.map((relay) => relay.inbox).includes(user.inbox);
|
||||
|
||||
if (!note.uri) {
|
||||
// Publish if the post is local
|
||||
publishNotesStream(note);
|
||||
} else if (
|
||||
boostedByRelay &&
|
||||
data.renote?.uri &&
|
||||
(await redisClient.exists(`publishedNote:${data.renote.uri}`)) === 0
|
||||
) {
|
||||
// Publish if the post was boosted by a relay and not yet published.
|
||||
publishNotesStream(data.renote);
|
||||
const key = `publishedNote:${data.renote.uri}`;
|
||||
await redisClient.set(key, 1, "EX", 30);
|
||||
} else if (
|
||||
!boostedByRelay &&
|
||||
note.uri &&
|
||||
(await redisClient.exists(`publishedNote:${note.uri}`)) === 0
|
||||
) {
|
||||
// Publish if the post came directly from a remote server, or from a
|
||||
// relay that doesn't boost the post (e.g, YUKIMOCHI Activity-Relay),
|
||||
// and not yet published.
|
||||
const key = `publishedNote:${note.uri}`;
|
||||
publishNotesStream(note);
|
||||
await redisClient.set(key, 1, "EX", 30);
|
||||
}
|
||||
publishNotesStream(note);
|
||||
}
|
||||
if (note.replyId != null) {
|
||||
// Only provide the reply note id here as the recipient may not be authorized to see the note.
|
||||
|
@ -556,6 +524,7 @@ export default async (
|
|||
nm.push(data.renote.userId, type);
|
||||
}
|
||||
}
|
||||
|
||||
// Fetch watchers
|
||||
nmRelatedPromises.push(
|
||||
notifyToWatchersOfRenotee(data.renote, user, nm, type),
|
||||
|
@ -568,9 +537,8 @@ export default async (
|
|||
});
|
||||
publishMainStream(data.renote.userId, "renote", packedRenote);
|
||||
|
||||
const renote = data.renote;
|
||||
const webhooks = (await getActiveWebhooks()).filter(
|
||||
(x) => x.userId === renote.userId && x.on.includes("renote"),
|
||||
(x) => x.userId === data.renote!.userId && x.on.includes("renote"),
|
||||
);
|
||||
for (const webhook of webhooks) {
|
||||
webhookDeliver(webhook, "renote", {
|
||||
|
@ -750,23 +718,14 @@ async function insertNote(
|
|||
if (insert.hasPoll) {
|
||||
// Start transaction
|
||||
await db.transaction(async (transactionalEntityManager) => {
|
||||
if (!data.poll) throw new Error("Empty poll data");
|
||||
|
||||
await transactionalEntityManager.insert(Note, insert);
|
||||
|
||||
let expiresAt: Date | null;
|
||||
if (!data.poll.expiresAt || isNaN(data.poll.expiresAt.getTime())) {
|
||||
expiresAt = null;
|
||||
} else {
|
||||
expiresAt = data.poll.expiresAt;
|
||||
}
|
||||
|
||||
const poll = new Poll({
|
||||
noteId: insert.id,
|
||||
choices: data.poll.choices,
|
||||
expiresAt,
|
||||
multiple: data.poll.multiple,
|
||||
votes: new Array(data.poll.choices.length).fill(0),
|
||||
choices: data.poll!.choices,
|
||||
expiresAt: data.poll!.expiresAt,
|
||||
multiple: data.poll!.multiple,
|
||||
votes: new Array(data.poll!.choices.length).fill(0),
|
||||
noteVisibility: insert.visibility,
|
||||
userId: user.id,
|
||||
userHost: user.host,
|
||||
|
|
|
@ -37,7 +37,7 @@ export async function addRelay(inbox: string) {
|
|||
}).then((x) => Relays.findOneByOrFail(x.identifiers[0]));
|
||||
|
||||
const relayActor = await getRelayActor();
|
||||
const follow = renderFollowRelay(relay, relayActor);
|
||||
const follow = await renderFollowRelay(relay, relayActor);
|
||||
const activity = renderActivity(follow);
|
||||
deliver(relayActor, activity, relay.inbox);
|
||||
|
||||
|
@ -60,7 +60,6 @@ export async function removeRelay(inbox: string) {
|
|||
deliver(relayActor, activity, relay.inbox);
|
||||
|
||||
await Relays.delete(relay.id);
|
||||
await updateRelaysCache();
|
||||
}
|
||||
|
||||
export async function listRelay() {
|
||||
|
@ -68,31 +67,14 @@ export async function listRelay() {
|
|||
return relays;
|
||||
}
|
||||
|
||||
export async function getCachedRelays(): Promise<Relay[]> {
|
||||
return await relaysCache.fetch(null, () =>
|
||||
Relays.findBy({
|
||||
status: "accepted",
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
export async function relayAccepted(id: string) {
|
||||
const result = await Relays.update(id, {
|
||||
status: "accepted",
|
||||
});
|
||||
|
||||
await updateRelaysCache();
|
||||
|
||||
return JSON.stringify(result);
|
||||
}
|
||||
|
||||
async function updateRelaysCache() {
|
||||
const relays = await Relays.findBy({
|
||||
status: "accepted",
|
||||
});
|
||||
relaysCache.set(null, relays);
|
||||
}
|
||||
|
||||
export async function relayRejected(id: string) {
|
||||
const result = await Relays.update(id, {
|
||||
status: "rejected",
|
||||
|
@ -107,7 +89,11 @@ export async function deliverToRelays(
|
|||
) {
|
||||
if (activity == null) return;
|
||||
|
||||
const relays = await getCachedRelays();
|
||||
const relays = await relaysCache.fetch(null, () =>
|
||||
Relays.findBy({
|
||||
status: "accepted",
|
||||
}),
|
||||
);
|
||||
if (relays.length === 0) return;
|
||||
|
||||
// TODO
|
||||
|
|
|
@ -43,7 +43,13 @@ describe("ユーザー", () => {
|
|||
roles: any[];
|
||||
};
|
||||
|
||||
type MeDetailed = UserDetailedNotMe & misskey.entities.MeDetailed;
|
||||
type MeDetailed = UserDetailedNotMe &
|
||||
misskey.entities.MeDetailed & {
|
||||
showTimelineReplies: boolean;
|
||||
achievements: object[];
|
||||
loggedInDays: number;
|
||||
policies: object;
|
||||
};
|
||||
|
||||
type User = MeDetailed & { token: string };
|
||||
|
||||
|
@ -166,6 +172,9 @@ describe("ユーザー", () => {
|
|||
mutedInstances: user.mutedInstances,
|
||||
mutingNotificationTypes: user.mutingNotificationTypes,
|
||||
emailNotificationTypes: user.emailNotificationTypes,
|
||||
showTimelineReplies: user.showTimelineReplies,
|
||||
achievements: user.achievements,
|
||||
loggedInDays: user.loggedInDays,
|
||||
policies: user.policies,
|
||||
...(security
|
||||
? {
|
||||
|
@ -470,6 +479,13 @@ describe("ユーザー", () => {
|
|||
"follow",
|
||||
"receiveFollowRequest",
|
||||
]);
|
||||
assert.strictEqual(response.showTimelineReplies, false);
|
||||
assert.deepStrictEqual(response.achievements, []);
|
||||
assert.deepStrictEqual(response.loggedInDays, 0);
|
||||
assert.deepStrictEqual(response.policies, DEFAULT_POLICIES);
|
||||
assert.notStrictEqual(response.email, undefined);
|
||||
assert.strictEqual(response.emailVerified, false);
|
||||
assert.deepStrictEqual(response.securityKeysList, []);
|
||||
});
|
||||
|
||||
//#endregion
|
||||
|
@ -535,6 +551,8 @@ describe("ユーザー", () => {
|
|||
{ parameters: (): object => ({ isBot: false }) },
|
||||
{ parameters: (): object => ({ isCat: true }) },
|
||||
{ parameters: (): object => ({ isCat: false }) },
|
||||
{ parameters: (): object => ({ showTimelineReplies: true }) },
|
||||
{ parameters: (): object => ({ showTimelineReplies: false }) },
|
||||
{ parameters: (): object => ({ injectFeaturedNote: true }) },
|
||||
{ parameters: (): object => ({ injectFeaturedNote: false }) },
|
||||
{ parameters: (): object => ({ receiveAnnouncementEmail: true }) },
|
||||
|
|
|
@ -725,7 +725,6 @@ export type Endpoints = {
|
|||
"i/2fa/password-less": { req: TODO; res: TODO };
|
||||
"i/2fa/register-key": { req: TODO; res: TODO };
|
||||
"i/2fa/register": { req: TODO; res: TODO };
|
||||
"i/2fa/update-key": { req: TODO; res: TODO };
|
||||
"i/2fa/remove-key": { req: TODO; res: TODO };
|
||||
"i/2fa/unregister": { req: TODO; res: TODO };
|
||||
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
"@rollup/plugin-alias": "3.1.9",
|
||||
"@rollup/plugin-json": "4.1.0",
|
||||
"@rollup/pluginutils": "^4.2.1",
|
||||
"@syuilo/aiscript": "0.11.1",
|
||||
"@syuilo/aiscript": "^0.13.3",
|
||||
"@types/escape-regexp": "0.0.1",
|
||||
"@types/glob": "8.1.0",
|
||||
"@types/gulp": "4.0.11",
|
||||
|
@ -87,7 +87,6 @@
|
|||
"vue-isyourpasswordsafe": "^2.0.0",
|
||||
"vue-plyr": "^7.0.0",
|
||||
"vue-prism-editor": "2.0.0-alpha.2",
|
||||
"vue3-otp-input": "^0.4.1",
|
||||
"vuedraggable": "4.1.0"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import { defineAsyncComponent, reactive } from "vue";
|
||||
import * as misskey from "calckey-js";
|
||||
import { showSuspendedDialog } from "./scripts/show-suspended-dialog";
|
||||
import { i18n } from "./i18n";
|
||||
import { del, get, set } from "@/scripts/idb-proxy";
|
||||
import { apiUrl } from "@/config";
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
<button
|
||||
v-if="!link"
|
||||
class="bghgjjyj _button"
|
||||
:class="{ inline, primary, gradate, danger, rounded, full, mini, chip }"
|
||||
:class="{ inline, primary, gradate, danger, rounded, full, mini }"
|
||||
:type="type"
|
||||
@click="emit('click', $event)"
|
||||
@mousedown="onMousedown"
|
||||
|
@ -41,8 +41,7 @@ const props = defineProps<{
|
|||
wait?: boolean;
|
||||
danger?: boolean;
|
||||
full?: boolean;
|
||||
mini?: boolean;
|
||||
chip?: boolean;
|
||||
mini: boolean;
|
||||
}>();
|
||||
|
||||
const emit = defineEmits<{
|
||||
|
@ -199,13 +198,6 @@ function onMousedown(evt: MouseEvent): void {
|
|||
border-radius: 100px;
|
||||
}
|
||||
|
||||
&.chip {
|
||||
padding: 4px 12px;
|
||||
font-size: max(12px, 0.9em);
|
||||
min-width: unset;
|
||||
border-radius: 100px;
|
||||
}
|
||||
|
||||
&:disabled {
|
||||
opacity: 0.7;
|
||||
}
|
||||
|
|
|
@ -102,7 +102,7 @@ function isMe(message): boolean {
|
|||
opacity: 0.8;
|
||||
}
|
||||
|
||||
&:not(.isRead) {
|
||||
&:not(.isMe):not(.isRead) {
|
||||
background-color: var(--accentedBg);
|
||||
}
|
||||
|
||||
|
@ -175,6 +175,13 @@ function isMe(message): boolean {
|
|||
|
||||
&.max-width_400px {
|
||||
> .message {
|
||||
&:not(.isMe):not(.isRead) {
|
||||
> div {
|
||||
background-image: none;
|
||||
border-left: solid 4px #3aa2dc;
|
||||
}
|
||||
}
|
||||
|
||||
> div {
|
||||
padding: 16px;
|
||||
font-size: 0.9em;
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
<MkModal
|
||||
ref="modal"
|
||||
:prefer-type="'dialog'"
|
||||
:z-priority="'high'"
|
||||
@click="done(true)"
|
||||
@closed="emit('closed')"
|
||||
>
|
||||
|
@ -53,50 +54,18 @@
|
|||
>
|
||||
<Mfm :text="i18n.ts.password" />
|
||||
</header>
|
||||
<div v-if="text" :class="$style.text">
|
||||
<Mfm :text="text" />
|
||||
</div>
|
||||
<div v-if="text" :class="$style.text"><Mfm :text="text" /></div>
|
||||
<MkInput
|
||||
ref="inputEl"
|
||||
v-if="input && input.type !== 'paragraph'"
|
||||
v-model="inputValue"
|
||||
autofocus
|
||||
:autocomplete="input.autocomplete"
|
||||
:type="input.type == 'search' ? 'search' : input.type || 'text'"
|
||||
:type="input.type || 'text'"
|
||||
:placeholder="input.placeholder || undefined"
|
||||
@keydown="onInputKeydown"
|
||||
:style="{
|
||||
width: input.type === 'search' ? '300px' : null,
|
||||
}"
|
||||
>
|
||||
<template v-if="input.type === 'password'" #prefix
|
||||
><i class="ph-password ph-bold ph-lg"></i
|
||||
></template>
|
||||
<template #caption>
|
||||
<span
|
||||
v-if="
|
||||
okButtonDisabled &&
|
||||
disabledReason === 'charactersExceeded'
|
||||
"
|
||||
v-text="i18n.t('_dialog.charactersExceeded', { current: (inputValue as string).length, max: input.maxLength ?? 'NaN' })"
|
||||
/>
|
||||
<span
|
||||
v-else-if="
|
||||
okButtonDisabled &&
|
||||
disabledReason === 'charactersBelow'
|
||||
"
|
||||
v-text="i18n.t('_dialog.charactersBelow', { current: (inputValue as string).length, min: input.minLength ?? 'NaN' })"
|
||||
/>
|
||||
</template>
|
||||
<template v-if="input.type === 'search'" #suffix>
|
||||
<button
|
||||
class="_buttonIcon"
|
||||
@click.stop="openSearchFilters"
|
||||
v-tooltip.noDelay="i18n.ts.filter"
|
||||
>
|
||||
<i class="ph-funnel ph-bold"></i>
|
||||
</button>
|
||||
</template>
|
||||
</MkInput>
|
||||
<MkTextarea
|
||||
v-if="input && input.type === 'paragraph'"
|
||||
|
@ -126,7 +95,6 @@
|
|||
</optgroup>
|
||||
</template>
|
||||
</MkSelect>
|
||||
|
||||
<div
|
||||
v-if="(showOkButton || showCancelButton) && !actions"
|
||||
:class="$style.buttons"
|
||||
|
@ -137,7 +105,6 @@
|
|||
inline
|
||||
primary
|
||||
:autofocus="!input && !select"
|
||||
:disabled="okButtonDisabled"
|
||||
@click="ok"
|
||||
>{{
|
||||
showCancelButton || input || select
|
||||
|
@ -159,8 +126,8 @@
|
|||
primary
|
||||
:autofocus="!input && !select"
|
||||
@click="ok"
|
||||
>{{ i18n.ts.yes }}
|
||||
</MkButton>
|
||||
>{{ i18n.ts.yes }}</MkButton
|
||||
>
|
||||
<MkButton
|
||||
v-if="showCancelButton || input || select"
|
||||
inline
|
||||
|
@ -195,17 +162,12 @@ import MkButton from "@/components/MkButton.vue";
|
|||
import MkInput from "@/components/form/input.vue";
|
||||
import MkTextarea from "@/components/form/textarea.vue";
|
||||
import MkSelect from "@/components/form/select.vue";
|
||||
import * as os from "@/os";
|
||||
import { i18n } from "@/i18n";
|
||||
import * as Acct from "calckey-js/built/acct";
|
||||
|
||||
type Input = {
|
||||
type: HTMLInputElement["type"];
|
||||
placeholder?: string | null;
|
||||
autocomplete?: string;
|
||||
default: string | number | null;
|
||||
minLength?: number;
|
||||
maxLength?: number;
|
||||
default: any | null;
|
||||
};
|
||||
|
||||
type Select = {
|
||||
|
@ -231,8 +193,7 @@ const props = withDefaults(
|
|||
| "warning"
|
||||
| "info"
|
||||
| "question"
|
||||
| "waiting"
|
||||
| "search";
|
||||
| "waiting";
|
||||
title: string;
|
||||
text?: string;
|
||||
input?: Input;
|
||||
|
@ -268,37 +229,8 @@ const emit = defineEmits<{
|
|||
|
||||
const modal = shallowRef<InstanceType<typeof MkModal>>();
|
||||
|
||||
const inputValue = ref<string | number | null>(props.input?.default ?? null);
|
||||
const selectedValue = ref(props.select?.default ?? null);
|
||||
|
||||
let disabledReason = $ref<null | "charactersExceeded" | "charactersBelow">(
|
||||
null
|
||||
);
|
||||
const okButtonDisabled = $computed<boolean>(() => {
|
||||
if (props.input) {
|
||||
if (props.input.minLength) {
|
||||
if (
|
||||
(inputValue.value || inputValue.value === "") &&
|
||||
(inputValue.value as string).length < props.input.minLength
|
||||
) {
|
||||
disabledReason = "charactersBelow";
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if (props.input.maxLength) {
|
||||
if (
|
||||
inputValue.value &&
|
||||
(inputValue.value as string).length > props.input.maxLength
|
||||
) {
|
||||
disabledReason = "charactersExceeded";
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
});
|
||||
|
||||
const inputEl = ref<typeof MkInput>();
|
||||
const inputValue = ref(props.input?.default || null);
|
||||
const selectedValue = ref(props.select?.default || null);
|
||||
|
||||
function done(canceled: boolean, result?) {
|
||||
emit("done", { canceled, result });
|
||||
|
@ -336,115 +268,6 @@ function onInputKeydown(evt: KeyboardEvent) {
|
|||
}
|
||||
}
|
||||
|
||||
function formatDateToYYYYMMDD(date) {
|
||||
const year = date.getFullYear();
|
||||
const month = ("0" + (date.getMonth() + 1)).slice(-2);
|
||||
const day = ("0" + (date.getDate() + 1)).slice(-2);
|
||||
return `${year}-${month}-${day}`;
|
||||
}
|
||||
|
||||
async function openSearchFilters(ev) {
|
||||
await os.popupMenu(
|
||||
[
|
||||
{
|
||||
icon: "ph-user ph-bold ph-lg",
|
||||
text: i18n.ts._filters.fromUser,
|
||||
action: () => {
|
||||
os.selectUser().then((user) => {
|
||||
inputValue.value += " from:@" + Acct.toString(user);
|
||||
});
|
||||
},
|
||||
},
|
||||
{
|
||||
type: "parent",
|
||||
text: i18n.ts._filters.withFile,
|
||||
icon: "ph-paperclip ph-bold ph-lg",
|
||||
children: [
|
||||
{
|
||||
text: i18n.ts.image,
|
||||
icon: "ph-image-square ph-bold ph-lg",
|
||||
action: () => {
|
||||
inputValue.value += " has:image";
|
||||
},
|
||||
},
|
||||
{
|
||||
text: i18n.ts.video,
|
||||
icon: "ph-video-camera ph-bold ph-lg",
|
||||
action: () => {
|
||||
inputValue.value += " has:video";
|
||||
},
|
||||
},
|
||||
{
|
||||
text: i18n.ts.audio,
|
||||
icon: "ph-music-note ph-bold ph-lg",
|
||||
action: () => {
|
||||
inputValue.value += " has:audio";
|
||||
},
|
||||
},
|
||||
{
|
||||
text: i18n.ts.file,
|
||||
icon: "ph-file ph-bold ph-lg",
|
||||
action: () => {
|
||||
inputValue.value += " has:file";
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
icon: "ph-link ph-bold ph-lg",
|
||||
text: i18n.ts._filters.fromDomain,
|
||||
action: () => {
|
||||
inputValue.value += " domain:";
|
||||
},
|
||||
},
|
||||
{
|
||||
icon: "ph-calendar-blank ph-bold ph-lg",
|
||||
text: i18n.ts._filters.notesBefore,
|
||||
action: () => {
|
||||
os.inputDate({
|
||||
title: i18n.ts._filters.notesBefore,
|
||||
}).then((res) => {
|
||||
if (res.canceled) return;
|
||||
inputValue.value +=
|
||||
" before:" + formatDateToYYYYMMDD(res.result);
|
||||
});
|
||||
},
|
||||
},
|
||||
{
|
||||
icon: "ph-calendar-blank ph-bold ph-lg",
|
||||
text: i18n.ts._filters.notesAfter,
|
||||
action: () => {
|
||||
os.inputDate({
|
||||
title: i18n.ts._filters.notesAfter,
|
||||
}).then((res) => {
|
||||
if (res.canceled) return;
|
||||
inputValue.value +=
|
||||
" after:" + formatDateToYYYYMMDD(res.result);
|
||||
});
|
||||
},
|
||||
},
|
||||
{
|
||||
icon: "ph-eye ph-bold ph-lg",
|
||||
text: i18n.ts._filters.followingOnly,
|
||||
action: () => {
|
||||
inputValue.value += " filter:following ";
|
||||
},
|
||||
},
|
||||
{
|
||||
icon: "ph-users-three ph-bold ph-lg",
|
||||
text: i18n.ts._filters.followersOnly,
|
||||
action: () => {
|
||||
inputValue.value += " filter:followers ";
|
||||
},
|
||||
},
|
||||
],
|
||||
ev.target,
|
||||
{ noReturnFocus: true }
|
||||
);
|
||||
inputEl.value.focus();
|
||||
inputEl.value.selectRange(inputValue.value.length, inputValue.value.length); // cursor at end
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
document.addEventListener("keydown", onKeydown);
|
||||
});
|
||||
|
|
|
@ -1,12 +1,4 @@
|
|||
<template>
|
||||
<button
|
||||
v-if="!hideMenu"
|
||||
class="menu _button"
|
||||
@click.stop="menu"
|
||||
v-tooltip="i18n.ts.menu"
|
||||
>
|
||||
<i class="ph-dots-three-outline ph-bold ph-lg"></i>
|
||||
</button>
|
||||
<button
|
||||
v-if="$i != null && $i.id != user.id"
|
||||
class="kpoogebi _button follow-button"
|
||||
|
@ -18,43 +10,44 @@
|
|||
blocking: isBlocking,
|
||||
}"
|
||||
:disabled="wait"
|
||||
@click.stop="onClick"
|
||||
@click="onClick"
|
||||
:aria-label="`${state} ${user.name || user.username}`"
|
||||
v-tooltip="full ? null : `${state} ${user.name || user.username}`"
|
||||
>
|
||||
<template v-if="!wait">
|
||||
<template v-if="isBlocking">
|
||||
<span>{{ (state = i18n.ts.blocked) }}</span
|
||||
<span v-if="full">{{ (state = i18n.ts.blocked) }}</span
|
||||
><i class="ph-prohibit ph-bold ph-lg"></i>
|
||||
</template>
|
||||
<template
|
||||
v-else-if="hasPendingFollowRequestFromYou && user.isLocked"
|
||||
>
|
||||
<span>{{ (state = i18n.ts.followRequestPending) }}</span
|
||||
<span v-if="full">{{
|
||||
(state = i18n.ts.followRequestPending)
|
||||
}}</span
|
||||
><i class="ph-hourglass-medium ph-bold ph-lg"></i>
|
||||
</template>
|
||||
<template
|
||||
v-else-if="hasPendingFollowRequestFromYou && !user.isLocked"
|
||||
>
|
||||
<!-- つまりリモートフォローの場合。 -->
|
||||
<span>{{ (state = i18n.ts.processing) }}</span
|
||||
<span v-if="full">{{ (state = i18n.ts.processing) }}</span
|
||||
><i class="ph-circle-notch ph-bold ph-lg fa-pulse"></i>
|
||||
</template>
|
||||
<template v-else-if="isFollowing">
|
||||
<span>{{ (state = i18n.ts.unfollow) }}</span
|
||||
<span v-if="full">{{ (state = i18n.ts.unfollow) }}</span
|
||||
><i class="ph-minus ph-bold ph-lg"></i>
|
||||
</template>
|
||||
<template v-else-if="!isFollowing && user.isLocked">
|
||||
<span>{{ (state = i18n.ts.followRequest) }}</span
|
||||
<span v-if="full">{{ (state = i18n.ts.followRequest) }}</span
|
||||
><i class="ph-plus ph-bold ph-lg"></i>
|
||||
</template>
|
||||
<template v-else-if="!isFollowing && !user.isLocked">
|
||||
<span>{{ (state = i18n.ts.follow) }}</span
|
||||
<span v-if="full">{{ (state = i18n.ts.follow) }}</span
|
||||
><i class="ph-plus ph-bold ph-lg"></i>
|
||||
</template>
|
||||
</template>
|
||||
<template v-else>
|
||||
<span>{{ (state = i18n.ts.processing) }}</span
|
||||
<span v-if="full">{{ (state = i18n.ts.processing) }}</span
|
||||
><i class="ph-circle-notch ph-bold ph-lg fa-pulse ph-fw ph-lg"></i>
|
||||
</template>
|
||||
</button>
|
||||
|
@ -67,10 +60,6 @@ import * as os from "@/os";
|
|||
import { stream } from "@/stream";
|
||||
import { i18n } from "@/i18n";
|
||||
import { $i } from "@/account";
|
||||
import { getUserMenu } from "@/scripts/get-user-menu";
|
||||
import { useRouter } from "@/router";
|
||||
|
||||
const router = useRouter();
|
||||
|
||||
const emit = defineEmits(["refresh"]);
|
||||
const props = withDefaults(
|
||||
|
@ -78,7 +67,6 @@ const props = withDefaults(
|
|||
user: Misskey.entities.UserDetailed;
|
||||
full?: boolean;
|
||||
large?: boolean;
|
||||
hideMenu?: boolean;
|
||||
}>(),
|
||||
{
|
||||
full: false,
|
||||
|
@ -163,13 +151,6 @@ async function onClick() {
|
|||
}
|
||||
}
|
||||
|
||||
function menu(ev) {
|
||||
os.popupMenu(
|
||||
getUserMenu(props.user, router),
|
||||
ev.currentTarget ?? ev.target
|
||||
);
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
connection.on("follow", onFollowChange);
|
||||
connection.on("unfollow", onFollowChange);
|
||||
|
@ -181,11 +162,6 @@ onBeforeUnmount(() => {
|
|||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.menu {
|
||||
width: 3em;
|
||||
height: 2em;
|
||||
vertical-align: middle;
|
||||
}
|
||||
.follow-button {
|
||||
position: relative;
|
||||
display: inline-flex;
|
||||
|
@ -200,7 +176,6 @@ onBeforeUnmount(() => {
|
|||
height: 2em;
|
||||
border-radius: 100px;
|
||||
background: var(--bg);
|
||||
vertical-align: middle;
|
||||
|
||||
&.full {
|
||||
padding: 0.2em 0.7em;
|
||||
|
@ -216,9 +191,6 @@ onBeforeUnmount(() => {
|
|||
|
||||
&:not(.full) {
|
||||
width: 31px;
|
||||
span {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
&:focus-visible {
|
||||
|
|
|
@ -1,12 +1,6 @@
|
|||
<template>
|
||||
<FocusTrap
|
||||
ref="focusTrap"
|
||||
v-model:active="isActive"
|
||||
:return-focus-on-deactivate="!noReturnFocus"
|
||||
:initial-focus="() => itemsEl.children[0]"
|
||||
@deactivate="emit('close')"
|
||||
>
|
||||
<div>
|
||||
<FocusTrap :active="false" ref="focusTrap">
|
||||
<div tabindex="-1">
|
||||
<div
|
||||
ref="itemsEl"
|
||||
class="rrevdjwt _popup _shadow"
|
||||
|
@ -16,7 +10,6 @@
|
|||
maxHeight: maxHeight ? maxHeight + 'px' : '',
|
||||
}"
|
||||
@contextmenu.self="(e) => e.preventDefault()"
|
||||
tabindex="-1"
|
||||
>
|
||||
<template v-for="(item, i) in items2">
|
||||
<div v-if="item === null" class="divider"></div>
|
||||
|
@ -135,11 +128,7 @@
|
|||
<button
|
||||
v-else-if="!item.hidden"
|
||||
class="_button item"
|
||||
:class="{
|
||||
danger: item.danger,
|
||||
accent: item.accent,
|
||||
active: item.active,
|
||||
}"
|
||||
:class="{ danger: item.danger, active: item.active }"
|
||||
:disabled="item.active"
|
||||
@click="clicked(item.action, $event)"
|
||||
@mouseenter.passive="onItemMouseEnter(item)"
|
||||
|
@ -176,7 +165,6 @@
|
|||
:root-element="itemsEl"
|
||||
showing
|
||||
@actioned="childActioned"
|
||||
@closed="closeChild"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -213,7 +201,6 @@ const props = defineProps<{
|
|||
align?: "center" | string;
|
||||
width?: number;
|
||||
maxHeight?: number;
|
||||
noReturnFocus?: boolean;
|
||||
}>();
|
||||
|
||||
const emit = defineEmits<{
|
||||
|
@ -307,7 +294,23 @@ function close(actioned = false) {
|
|||
emit("close", actioned);
|
||||
}
|
||||
|
||||
function focusUp() {
|
||||
focusPrev(document.activeElement);
|
||||
}
|
||||
|
||||
function focusDown() {
|
||||
focusNext(document.activeElement);
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
focusTrap.value.activate();
|
||||
|
||||
if (props.viaKeyboard) {
|
||||
nextTick(() => {
|
||||
focusNext(itemsEl.children[0], true, false);
|
||||
});
|
||||
}
|
||||
|
||||
document.addEventListener("mousedown", onGlobalMousedown, {
|
||||
passive: true,
|
||||
});
|
||||
|
@ -395,26 +398,6 @@ onBeforeUnmount(() => {
|
|||
}
|
||||
}
|
||||
|
||||
&.accent {
|
||||
color: var(--accent);
|
||||
|
||||
&:hover {
|
||||
color: var(--accent);
|
||||
|
||||
&:before {
|
||||
background: var(--accentedBg);
|
||||
}
|
||||
}
|
||||
|
||||
&:active {
|
||||
color: var(--fgOnAccent);
|
||||
|
||||
&:before {
|
||||
background: var(--accent);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&.active {
|
||||
color: var(--fgOnAccent);
|
||||
opacity: 1;
|
||||
|
|
|
@ -14,17 +14,14 @@
|
|||
:duration="transitionDuration"
|
||||
appear
|
||||
@after-leave="emit('closed')"
|
||||
@keyup.esc="emit('click')"
|
||||
@enter="emit('opening')"
|
||||
@after-enter="onOpened"
|
||||
>
|
||||
<FocusTrap
|
||||
v-model:active="isActive"
|
||||
:initial-focus="() => $refs.content"
|
||||
:return-focus-on-deactivate="!noReturnFocus"
|
||||
@deactivate="close"
|
||||
>
|
||||
<FocusTrap v-model:active="isActive">
|
||||
<div
|
||||
v-show="manualShowing != null ? manualShowing : showing"
|
||||
v-hotkey.global="keymap"
|
||||
:class="[
|
||||
$style.root,
|
||||
{
|
||||
|
@ -44,6 +41,7 @@
|
|||
'--transformOrigin': transformOrigin,
|
||||
}"
|
||||
tabindex="-1"
|
||||
v-focus
|
||||
>
|
||||
<div
|
||||
class="_modalBg data-cy-bg"
|
||||
|
@ -104,7 +102,6 @@ const props = withDefaults(
|
|||
zPriority?: "low" | "middle" | "high";
|
||||
noOverlap?: boolean;
|
||||
transparentBg?: boolean;
|
||||
noReturnFocus?: boolean;
|
||||
}>(),
|
||||
{
|
||||
manualShowing: null,
|
||||
|
@ -114,7 +111,6 @@ const props = withDefaults(
|
|||
zPriority: "low",
|
||||
noOverlap: true,
|
||||
transparentBg: false,
|
||||
noReturnFocus: false,
|
||||
}
|
||||
);
|
||||
|
||||
|
@ -179,6 +175,7 @@ let transitionDuration = $computed(() =>
|
|||
|
||||
let contentClicking = false;
|
||||
|
||||
const focusedElement = document.activeElement;
|
||||
function close(ev, opts: { useSendAnimation?: boolean } = {}) {
|
||||
// removeEventListener("popstate", close);
|
||||
// if (props.preferType == "dialog") {
|
||||
|
@ -192,10 +189,12 @@ function close(ev, opts: { useSendAnimation?: boolean } = {}) {
|
|||
if (props.src) props.src.style.pointerEvents = "auto";
|
||||
showing = false;
|
||||
emit("close");
|
||||
focusedElement.focus();
|
||||
}
|
||||
|
||||
function onBgClick() {
|
||||
if (contentClicking) return;
|
||||
focusedElement.focus();
|
||||
emit("click");
|
||||
}
|
||||
|
||||
|
@ -203,6 +202,10 @@ if (type === "drawer") {
|
|||
maxHeight = window.innerHeight / 1.5;
|
||||
}
|
||||
|
||||
const keymap = {
|
||||
esc: () => emit("esc"),
|
||||
};
|
||||
|
||||
const MARGIN = 16;
|
||||
|
||||
const align = () => {
|
||||
|
|
|
@ -6,56 +6,58 @@
|
|||
@keyup.esc="$emit('close')"
|
||||
@closed="$emit('closed')"
|
||||
>
|
||||
<div
|
||||
ref="rootEl"
|
||||
class="ebkgoccj"
|
||||
:style="{
|
||||
width: `${width}px`,
|
||||
height: scroll
|
||||
? height
|
||||
? `${height}px`
|
||||
: null
|
||||
: height
|
||||
? `min(${height}px, 100%)`
|
||||
: '100%',
|
||||
}"
|
||||
tabindex="-1"
|
||||
>
|
||||
<div ref="headerEl" class="header">
|
||||
<button
|
||||
v-if="withOkButton"
|
||||
:aria-label="i18n.t('close')"
|
||||
class="_button"
|
||||
@click="$emit('close')"
|
||||
v-tooltip="i18n.ts.close"
|
||||
>
|
||||
<i class="ph-x ph-bold ph-lg"></i>
|
||||
</button>
|
||||
<span class="title">
|
||||
<slot name="header"></slot>
|
||||
</span>
|
||||
<button
|
||||
v-if="!withOkButton"
|
||||
:aria-label="i18n.t('close')"
|
||||
class="_button"
|
||||
@click="$emit('close')"
|
||||
>
|
||||
<i class="ph-x ph-bold ph-lg"></i>
|
||||
</button>
|
||||
<button
|
||||
v-if="withOkButton"
|
||||
:aria-label="i18n.t('ok')"
|
||||
class="_button"
|
||||
:disabled="okButtonDisabled"
|
||||
@click="$emit('ok')"
|
||||
>
|
||||
<i class="ph-check ph-bold ph-lg"></i>
|
||||
</button>
|
||||
<FocusTrap v-model:active="isActive">
|
||||
<div
|
||||
ref="rootEl"
|
||||
class="ebkgoccj"
|
||||
:style="{
|
||||
width: `${width}px`,
|
||||
height: scroll
|
||||
? height
|
||||
? `${height}px`
|
||||
: null
|
||||
: height
|
||||
? `min(${height}px, 100%)`
|
||||
: '100%',
|
||||
}"
|
||||
@keydown="onKeydown"
|
||||
tabindex="-1"
|
||||
>
|
||||
<div ref="headerEl" class="header">
|
||||
<button
|
||||
v-if="withOkButton"
|
||||
:aria-label="i18n.t('close')"
|
||||
class="_button"
|
||||
@click="$emit('close')"
|
||||
>
|
||||
<i class="ph-x ph-bold ph-lg"></i>
|
||||
</button>
|
||||
<span class="title">
|
||||
<slot name="header"></slot>
|
||||
</span>
|
||||
<button
|
||||
v-if="!withOkButton"
|
||||
:aria-label="i18n.t('close')"
|
||||
class="_button"
|
||||
@click="$emit('close')"
|
||||
>
|
||||
<i class="ph-x ph-bold ph-lg"></i>
|
||||
</button>
|
||||
<button
|
||||
v-if="withOkButton"
|
||||
:aria-label="i18n.t('ok')"
|
||||
class="_button"
|
||||
:disabled="okButtonDisabled"
|
||||
@click="$emit('ok')"
|
||||
>
|
||||
<i class="ph-check ph-bold ph-lg"></i>
|
||||
</button>
|
||||
</div>
|
||||
<div class="body">
|
||||
<slot></slot>
|
||||
</div>
|
||||
</div>
|
||||
<div class="body">
|
||||
<slot></slot>
|
||||
</div>
|
||||
</div>
|
||||
</FocusTrap>
|
||||
</MkModal>
|
||||
</template>
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
v-show="!isDeleted"
|
||||
ref="el"
|
||||
v-hotkey="keymap"
|
||||
v-size="{ max: [500, 350] }"
|
||||
v-size="{ max: [500, 450, 350] }"
|
||||
class="tkcbzcuz note-container"
|
||||
:tabindex="!isDeleted ? '-1' : null"
|
||||
:class="{ renote: isRenote }"
|
||||
|
@ -190,7 +190,6 @@
|
|||
ref="reactButton"
|
||||
class="button _button reacted"
|
||||
@click="undoReact(appearNote)"
|
||||
v-tooltip.noDelay.bottom="i18n.ts.removeReaction"
|
||||
>
|
||||
<i class="ph-minus ph-bold ph-lg"></i>
|
||||
</button>
|
||||
|
@ -619,11 +618,10 @@ defineExpose({
|
|||
.line::before {
|
||||
content: "";
|
||||
display: block;
|
||||
margin-bottom: -4px;
|
||||
margin-bottom: -10px;
|
||||
margin-top: 16px;
|
||||
border-left: 2px solid currentColor;
|
||||
border-left: 2px solid var(--X13);
|
||||
margin-left: calc((var(--avatarSize) / 2) - 1px);
|
||||
opacity: 0.25;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -846,7 +844,10 @@ defineExpose({
|
|||
}
|
||||
|
||||
&.max-width_500px {
|
||||
font-size: 0.975em;
|
||||
font-size: 0.9em;
|
||||
}
|
||||
|
||||
&.max-width_450px {
|
||||
--avatarSize: 46px;
|
||||
padding-top: 6px;
|
||||
> .note-context {
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
v-show="!isDeleted"
|
||||
ref="el"
|
||||
v-hotkey="keymap"
|
||||
v-size="{ max: [500, 350, 300] }"
|
||||
v-size="{ max: [500, 450, 350, 300] }"
|
||||
class="lxwezrsl _block"
|
||||
:tabindex="!isDeleted ? '-1' : null"
|
||||
:class="{ renote: isRenote }"
|
||||
|
@ -558,7 +558,7 @@ onUnmounted(() => {
|
|||
&::before {
|
||||
inset: 0px 8px;
|
||||
}
|
||||
&:not(.max-width_500px)::before {
|
||||
&:not(.max-width_450px)::before {
|
||||
bottom: 16px;
|
||||
}
|
||||
&:first-of-type::before {
|
||||
|
@ -609,8 +609,11 @@ onUnmounted(() => {
|
|||
background: none;
|
||||
}
|
||||
}
|
||||
|
||||
&.max-width_500px {
|
||||
font-size: 0.975em;
|
||||
font-size: 0.9em;
|
||||
}
|
||||
&.max-width_450px {
|
||||
> .reply-to {
|
||||
&::before {
|
||||
inset-inline: -24px;
|
||||
|
@ -625,7 +628,6 @@ onUnmounted(() => {
|
|||
|
||||
> :deep(.note-container) {
|
||||
padding: 12px 0 0 0;
|
||||
font-size: 1.05rem;
|
||||
> .header > .body {
|
||||
padding-left: 10px;
|
||||
}
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Reference in a new issue