Firefish v1.0.4-beta
This commit is contained in:
parent
f58683e142
commit
52e3595da2
49 changed files with 2329 additions and 853 deletions
|
@ -34,7 +34,7 @@ port: 3000
|
|||
#───┘ PostgreSQL configuration └────────────────────────────────
|
||||
|
||||
db:
|
||||
host: database
|
||||
host: postgres
|
||||
port: 5432
|
||||
|
||||
# Database name
|
||||
|
|
|
@ -29,7 +29,7 @@ url: https://example.com/
|
|||
# The port that your Firefish server should listen on.
|
||||
port: 3000
|
||||
|
||||
# The bind host your Calckey server should listen on.
|
||||
# The bind host your Firefish server should listen on.
|
||||
# If unspecified, the wildcard address will be used.
|
||||
#bind: 127.0.0.1
|
||||
|
||||
|
|
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -1,6 +1,7 @@
|
|||
# Visual Studio Code
|
||||
/.vscode
|
||||
!/.vscode/extensions.json
|
||||
!/.vscode/launch.json
|
||||
|
||||
# Intelij-IDEA
|
||||
/.idea
|
||||
|
|
1952
CHANGELOG.md
1952
CHANGELOG.md
File diff suppressed because it is too large
Load diff
|
@ -12,9 +12,6 @@ You can contribute without knowing how to code by helping translate here:
|
|||
|
||||
[![Translation bars](https://hosted.weblate.org/widgets/firefish/-/multi-auto.svg)](https://hosted.weblate.org/engage/firefish/)
|
||||
|
||||
## Roadmap
|
||||
See [FIREFISH.md](./FIREFISH.md)
|
||||
|
||||
## Issues
|
||||
Before creating an issue, please check the following:
|
||||
- To avoid duplication, please search for similar issues before creating a new issue.
|
||||
|
|
|
@ -2177,5 +2177,5 @@ deletePasskeys: Suprimeix les contrasenyes
|
|||
deletePasskeysConfirm: Això suprimirà de manera irreversible totes les contrasenyes
|
||||
i claus de seguretat d'aquest compte. Procedir?
|
||||
inputNotMatch: L'entrada no coincideix
|
||||
delete2fa: Suprimeix 2FA
|
||||
delete2fa: Desactivar 2FA
|
||||
delete2faConfirm: Això suprimirà irreversiblement 2FA en aquest compte. Procedir?
|
||||
|
|
|
@ -853,7 +853,7 @@ gallery: "Bilder-Galerie"
|
|||
recentPosts: "Neue Beiträge"
|
||||
popularPosts: "Beliebte Beiträge"
|
||||
shareWithNote: "Mit Beitrag teilen"
|
||||
ads: "Werbeanzeigen"
|
||||
ads: "Community-Banner"
|
||||
expiration: "Frist"
|
||||
memo: "Merkzettel"
|
||||
priority: "Priorität"
|
||||
|
@ -953,9 +953,9 @@ driveCapOverrideCaption: "Gib einen Wert von 0 oder weniger ein, um die Kapazit
|
|||
auf den Standard zurückzusetzen."
|
||||
requireAdminForView: "Du musst dich mit einem Administratorkonto anmelden um dies
|
||||
zu sehen."
|
||||
isSystemAccount: "Dieses Konto wird vom System erstellt und automatisch verwaltet.
|
||||
Bitte moderieren, bearbeiten, löschen oder manipulieren Sie dieses Konto nicht,
|
||||
da es sonst zu einem Server-Absturz kommen könnte."
|
||||
isSystemAccount: "Ein Nutzerkonto, dass durch das System erstellt und automatisch
|
||||
kontrolliert wird. Jede Anpassung, Veränderung oder Löschung dieses Nutzerkontos,
|
||||
kann zu schwerwiegenden Fehlern auf diesem Server führen."
|
||||
typeToConfirm: "Bitte gib zur Bestätigung {x} ein"
|
||||
deleteAccount: "Nutzerkonto löschen"
|
||||
document: "Dokumentation"
|
||||
|
@ -966,7 +966,7 @@ logoutConfirm: "Wirklich abmelden?"
|
|||
lastActiveDate: "Zuletzt verwendet am"
|
||||
statusbar: "Statusleiste"
|
||||
pleaseSelect: "Wähle eine Option"
|
||||
reverse: "Umkehren"
|
||||
reverse: "Rückgängig machen"
|
||||
colored: "Farbig"
|
||||
refreshInterval: "Aktualisierungsintervall "
|
||||
label: "Beschriftung"
|
||||
|
@ -1128,7 +1128,7 @@ _mfm:
|
|||
bold: "Fett"
|
||||
boldDescription: "Zeichen zur Betonung dicker erscheinen lassen."
|
||||
small: "Klein"
|
||||
smallDescription: "Inhalt klein und dünn erscheinen lassen."
|
||||
smallDescription: "Inhalt klein und dünn anzeigen."
|
||||
center: "Zentrieren"
|
||||
centerDescription: "Inhalt zentriert anzeigen."
|
||||
inlineCode: "Code (Eingebettet)"
|
||||
|
@ -2053,7 +2053,7 @@ userSaysSomethingReasonReply: '{name} hat auf einen Beitrag geantwortet der {rea
|
|||
userSaysSomethingReasonRenote: '{name} hat einen Beitrag geteilt der {reason} beinhaltet'
|
||||
userSaysSomethingReasonQuote: '{name} hat einen Beitrag zitiert der {reason} beinhaltet'
|
||||
seperateRenoteQuote: Getrennte Boost- und Zitat-Schaltflächen
|
||||
showAds: Anzeigen anzeigen
|
||||
showAds: Community-Banner anzeigen
|
||||
splash: Begrüßungsbildschirm
|
||||
customSplashIconsDescription: URLs für benutzerdefinierte Splash-Screen-Symbole, die
|
||||
durch Zeilenumbrüche getrennt sind und nach dem Zufallsprinzip jedes Mal angezeigt
|
||||
|
@ -2191,3 +2191,13 @@ _skinTones:
|
|||
showPopup: Benutzer mit Popup benachrichtigen
|
||||
showWithSparkles: Mit Glitzer anzeigen
|
||||
removeQuote: Zitat entfernen
|
||||
objectStorageS3ForcePathStyle: Verwende pfadbasierte Endpunkt-URLs
|
||||
objectStorageS3ForcePathStyleDesc: Wenn aktiviert, werden Endpunkt-URLs im Format
|
||||
's3.amazonaws.com/<bucket>/' statt '<bucket>.s3.amazonaws.com' erstellt.
|
||||
origin: Herkunft
|
||||
delete2fa: 2FA deaktivieren
|
||||
deletePasskeys: Passkeys löschen
|
||||
delete2faConfirm: Passkeys werden unwiderruflich von diesem Account gelöscht. Fortfahren?
|
||||
deletePasskeysConfirm: Alle Passkeys und Security-Keys werden unwiderruflich von diesem
|
||||
Account gelöscht. Fortfahren?
|
||||
inputNotMatch: Eingabe stimmt nicht überein
|
||||
|
|
|
@ -1135,7 +1135,6 @@ hideFollowButtons: "Hide follow buttons in notifications and user pages"
|
|||
forMobile: "Mobile"
|
||||
replaceChatButtonWithAccountButton: "Replace chat button at the bottom with account switch button"
|
||||
replaceWidgetsButtonWithReloadButton: "Replace widgets button at the bottom with reload button"
|
||||
addRe: "Add \"re:\" at the beginning of comment in reply to CW'd post"
|
||||
origin: "Origin"
|
||||
delete2fa: "Disable 2FA"
|
||||
deletePasskeys: "Delete passkeys"
|
||||
|
@ -1144,6 +1143,7 @@ deletePasskeysConfirm: "This will irreversibly delete all passkeys and security
|
|||
inputNotMatch: "Input does not match"
|
||||
detectPostLanguage: "Automatically detect the language and show a translate button for non-English posts"
|
||||
languageForTranslation: "Language used for post translation"
|
||||
addRe: "Add \"re:\" at the beginning of comment in reply to a post with a content warning"
|
||||
|
||||
_sensitiveMediaDetection:
|
||||
description: "Reduces the effort of server moderation through automatically recognizing
|
||||
|
@ -1239,7 +1239,7 @@ _aboutFirefish:
|
|||
development since 2022."
|
||||
contributors: "Main contributors"
|
||||
allContributors: "All contributors"
|
||||
originalMisskeyContributors: "Original Misskey main contributors"
|
||||
misskeyContributors: "Misskey main contributors"
|
||||
source: "Source code"
|
||||
translation: "Translate Firefish"
|
||||
donate: "Donate to Firefish"
|
||||
|
|
|
@ -161,7 +161,7 @@ autoAcceptFollowed: "Aceptar automáticamente las solicitudes de seguimiento de
|
|||
usuarios que sigues"
|
||||
addAccount: "Agregar Cuenta"
|
||||
loginFailed: "Error al iniciar sesión"
|
||||
showOnRemote: "Ver en servidor remoto"
|
||||
showOnRemote: "Abrir página original"
|
||||
general: "General"
|
||||
wallpaper: "Fondo de pantalla"
|
||||
setWallpaper: "Establecer fondo de pantalla"
|
||||
|
@ -540,7 +540,7 @@ objectStorageSetPublicRead: "Seleccionar \"public-read\" al subir "
|
|||
serverLogs: "Registros del servidor"
|
||||
deleteAll: "Eliminar todos"
|
||||
showFixedPostForm: "Mostrar el formulario de las entradas encima de la línea de tiempo"
|
||||
newNoteRecived: "Tienes unas publicaciones nuevas"
|
||||
newNoteRecived: "Hay publicaciones nuevas"
|
||||
sounds: "Sonidos"
|
||||
listen: "Escuchar"
|
||||
none: "Ninguna"
|
||||
|
@ -690,7 +690,7 @@ instanceTicker: "Información de publicaciones de el servidor"
|
|||
waitingFor: "Esperando a {x}"
|
||||
random: "Aleatorio"
|
||||
system: "Sistema"
|
||||
switchUi: "Cambiar interfaz de usuario"
|
||||
switchUi: "Interfaz"
|
||||
desktop: "Escritorio"
|
||||
clip: "Clip"
|
||||
createNew: "Crear"
|
||||
|
@ -700,15 +700,15 @@ unclip: "Quitar clip"
|
|||
confirmToUnclipAlreadyClippedNote: "Esta publicación ya está incluida en el clip \"\
|
||||
{name}\". ¿Quiere quitar la nota del clip?"
|
||||
public: "Público"
|
||||
i18nInfo: "Firefish está siendo traducido a varios idiomas gracias a voluntarios. Se
|
||||
puede colaborar traduciendo en {link}"
|
||||
i18nInfo: "Firefish está siendo traducido a varios idiomas gracias a voluntarios.
|
||||
Se puede colaborar traduciendo en {link}"
|
||||
manageAccessTokens: "Administrar tokens de acceso"
|
||||
accountInfo: "Información de la Cuenta"
|
||||
notesCount: "Cantidad de publicaciones"
|
||||
repliesCount: "Cantidad de respuestas hechas"
|
||||
renotesCount: "Cantidad de renotas hechas"
|
||||
renotesCount: "Número de impulsos enviados"
|
||||
repliedCount: "Cantidad de respuestas recibidas"
|
||||
renotedCount: "Cantidad de renotas recibidas"
|
||||
renotedCount: "Cantidad de impulsos recibidos"
|
||||
followingCount: "Cantidad de seguidos"
|
||||
followersCount: "Cantidad de seguidores"
|
||||
sentReactionsCount: "Cantidad de reacciones hechas"
|
||||
|
@ -722,9 +722,9 @@ driveUsage: "Uso del drive"
|
|||
noCrawle: "Rechazar indexación del crawler"
|
||||
noCrawleDescription: "Pedir a los motores de búsqueda que no indexen tu perfil, publicaciones,
|
||||
páginas, etc."
|
||||
lockedAccountInfo: "A menos que configures la visibilidad de tus notas como \"Sólo
|
||||
seguidores\", tus notas serán visibles para cualquiera, incluso si requieres que
|
||||
los seguidores sean aprobados manualmente."
|
||||
lockedAccountInfo: "A menos que configures la visibilidad de tus publicaciones como
|
||||
\"Sólo seguidores\", tus publicaciones serán visibles para cualquiera, incluso si
|
||||
requieres que los seguidores sean aprobados manualmente."
|
||||
alwaysMarkSensitive: "Marcar los medios de comunicación como contenido sensible por
|
||||
defecto"
|
||||
loadRawImages: "Cargar las imágenes originales en lugar de mostrar las miniaturas"
|
||||
|
@ -758,7 +758,7 @@ showTitlebar: "Mostrar la barra de título"
|
|||
clearCache: "Limpiar caché"
|
||||
onlineUsersCount: "{n} usuarios en línea"
|
||||
nUsers: "{n} Usuarios"
|
||||
nNotes: "{n} Notas"
|
||||
nNotes: "{n} Publicaciones"
|
||||
sendErrorReports: "Envíar informe de errores"
|
||||
sendErrorReportsDescription: "Si habilita esta opción, los detalles de los errores
|
||||
serán compartidos con Firefish cuando ocurra un problema, lo que ayudará a mejorar
|
||||
|
@ -788,7 +788,7 @@ capacity: "Capacidad"
|
|||
inUse: "Usado"
|
||||
editCode: "Editar código"
|
||||
apply: "Aplicar"
|
||||
receiveAnnouncementFromInstance: "Recibir notificaciones de la instancia"
|
||||
receiveAnnouncementFromInstance: "Recibir notificaciones de este servidor"
|
||||
emailNotification: "Notificaciones por correo electrónico"
|
||||
publish: "Publicar"
|
||||
inChannelSearch: "Buscar en el canal"
|
||||
|
@ -804,9 +804,10 @@ unlikeConfirm: "¿Quitar como favorito?"
|
|||
fullView: "Vista completa"
|
||||
quitFullView: "quitar vista completa"
|
||||
addDescription: "Agregar descripción"
|
||||
userPagePinTip: "Puede mantener sus notas visibles aquí seleccionando Pin en el menú
|
||||
de notas individuales"
|
||||
notSpecifiedMentionWarning: "Algunas menciones no están incluidas en el destino"
|
||||
userPagePinTip: "Puede mantener tus publicaciones visibles aquí seleccionando Pin
|
||||
en el menú de notas individuales."
|
||||
notSpecifiedMentionWarning: "Esta publicacion contiene menciones a usuarios no incluídos
|
||||
como destinatarios"
|
||||
info: "Información"
|
||||
userInfo: "Información del usuario"
|
||||
unknown: "Desconocido"
|
||||
|
@ -819,7 +820,7 @@ active: "Activo"
|
|||
offline: "Sin conexión"
|
||||
notRecommended: "obsoleto"
|
||||
botProtection: "Protección contra bots"
|
||||
instanceBlocking: "Instancias bloqueadas"
|
||||
instanceBlocking: "Gestión de la Federación"
|
||||
selectAccount: "Elija una cuenta"
|
||||
switchAccount: "Cambiar de cuenta"
|
||||
enabled: "Activado"
|
||||
|
@ -836,8 +837,8 @@ postToGallery: "Crear una nueva publicación en la galería"
|
|||
gallery: "Galería"
|
||||
recentPosts: "Posts recientes"
|
||||
popularPosts: "Más vistos"
|
||||
shareWithNote: "Compartir con una nota"
|
||||
ads: "Anuncios"
|
||||
shareWithNote: "Compartir con una publicación"
|
||||
ads: "Banners"
|
||||
expiration: "Termina el"
|
||||
memo: "Notas"
|
||||
priority: "Prioridad"
|
||||
|
@ -885,14 +886,14 @@ manageAccounts: "Administrar cuenta"
|
|||
makeReactionsPublic: "Hacer el historial de reacciones público"
|
||||
makeReactionsPublicDescription: "Todas las reacciones que hayas hecho serán públicamente
|
||||
visibles."
|
||||
classic: "Clásico"
|
||||
classic: "Centrado"
|
||||
muteThread: "Ocultar hilo"
|
||||
unmuteThread: "Mostrar hilo"
|
||||
ffVisibility: "Visibilidad de seguidores y seguidos"
|
||||
ffVisibilityDescription: "Puedes configurar quien puede ver a quienes sigues y quienes
|
||||
te siguen"
|
||||
continueThread: "Ver la continuación del hilo"
|
||||
deleteAccountConfirm: "La cuenta será borrada. ¿Está seguro?"
|
||||
deleteAccountConfirm: "La cuenta será borrada irreversiblemente. ¿Está seguro?"
|
||||
incorrectPassword: "La contraseña es incorrecta"
|
||||
voteConfirm: "¿Confirma su voto a {choice}?"
|
||||
hide: "Ocultar"
|
||||
|
@ -934,7 +935,9 @@ driveCapOverrideLabel: "Cambiar la capacidad de la unidad para este usuario"
|
|||
driveCapOverrideCaption: "Restablecer la capacidad a su predeterminado ingresando
|
||||
un valor de 0 o menos"
|
||||
requireAdminForView: "Necesitas iniciar sesión como administrador para ver esto."
|
||||
isSystemAccount: "Cuenta creada y operada automáticamente por el sistema"
|
||||
isSystemAccount: "Esta cuenta es creada y operada automaticamente por el sistema.
|
||||
Porfavor no moderar, editar, borrar o manipular de ninguna forma esta cuenta, o
|
||||
podría romper tu servidor."
|
||||
typeToConfirm: "Ingrese {x} para confirmar"
|
||||
deleteAccount: "Borrar cuenta"
|
||||
document: "Documento"
|
||||
|
@ -1019,8 +1022,9 @@ _forgotPassword:
|
|||
enterEmail: "Ingrese el correo usado para registrar la cuenta. Se enviará un link
|
||||
para resetear la contraseña."
|
||||
ifNoEmail: "Si no utilizó un correo para crear la cuenta, contáctese con el administrador."
|
||||
contactAdmin: "Esta instancia no admite el uso de direcciones de correo electrónico,
|
||||
póngase en contacto con el administrador de la instancia para restablecer su contraseña"
|
||||
contactAdmin: "Este servidor no admite el uso de direcciones de correo electrónico,
|
||||
póngase en contacto con la persona que administra el servidor para restablecer
|
||||
su contraseña."
|
||||
_gallery:
|
||||
my: "Mi galería"
|
||||
liked: "Publicaciones que me gustan"
|
||||
|
@ -1073,6 +1077,14 @@ _aboutFirefish:
|
|||
morePatrons: "También apreciamos el apoyo de muchos más que no están enlistados
|
||||
aquí. ¡Gracias! 🥰"
|
||||
patrons: "Mecenas de Firefish"
|
||||
pleaseDonateToFirefish: Por favor considera donar a Firefish para apollar su desarrollo.
|
||||
donateHost: Dona a {host}
|
||||
patronsList: Listados cronológicamente no por monto de la donación. ¡Dona con el
|
||||
vínculo de arriba para que tu nombre aparezca aquí!
|
||||
donateTitle: ¿Te gusta Firefish?
|
||||
pleaseDonateToHost: También considera donar a tu propio servidor , {host}, para
|
||||
ayudar con los costos de operación.
|
||||
sponsors: Patrocinadores de Firefish
|
||||
_nsfw:
|
||||
respect: "Ocultar medios NSFW"
|
||||
ignore: "No esconder medios NSFW "
|
||||
|
@ -1080,8 +1092,8 @@ _nsfw:
|
|||
_mfm:
|
||||
cheatSheet: "Hoja de referencia de MFM"
|
||||
intro: "MFM es un lenguaje de marcado dedicado que se puede usar en varios lugares
|
||||
dentro de Misskey, Firefish, Akkoma, y mucho más. Aquí puede ver una lista de sintaxis
|
||||
disponibles en MFM."
|
||||
dentro de Misskey, Firefish, Akkoma, y mucho más. Aquí puede ver una lista de
|
||||
sintaxis disponibles en MFM."
|
||||
dummy: "Firefish expande el mundo de la Fediverso"
|
||||
mention: "Menciones"
|
||||
mentionDescription: "El signo @ seguido de un nombre de usuario se puede utilizar
|
||||
|
@ -1106,7 +1118,7 @@ _mfm:
|
|||
inlineMath: "Fórmula (insertado)"
|
||||
inlineMathDescription: "Muestra fórmulas (KaTeX) insertadas"
|
||||
blockMath: "Fórmula (bloque)"
|
||||
blockMathDescription: "Muestra fórmulas (KaTeX) de varias líneas en un bloque"
|
||||
blockMathDescription: "Muestra fórmulas matemáticas (KaTeX) en un bloque"
|
||||
quote: "Citar"
|
||||
quoteDescription: "Muestra el contenido como una cita"
|
||||
emoji: "Emojis personalizados"
|
||||
|
@ -1151,6 +1163,22 @@ _mfm:
|
|||
plainDescription: "Desactiva los efectos de todo el contenido MFM con este efecto
|
||||
MFM."
|
||||
position: Posición
|
||||
warn: MFM podría contener movimientos rápidos o animaciones destellantes
|
||||
advancedDescription: Si está desactivado, solo permitir markup básico, excepto cuando
|
||||
un MFM animado se reproduce
|
||||
scale: Escalar
|
||||
foreground: Color en primer plano
|
||||
scaleDescription: Ajustar el contenido según un valor especificado.
|
||||
stop: Detener MFM
|
||||
crop: Recortar
|
||||
cropDescription: Recortar contenido.
|
||||
backgroundDescription: Cambiar el color de fondo del texto.
|
||||
alwaysPlay: Siempre reproducir todos los MFM animados
|
||||
fade: Fundido
|
||||
advanced: MFM avanzado
|
||||
play: Reproducir MFM
|
||||
foregroundDescription: Cambiar el color en primer plano del texto.
|
||||
background: Color de fondo
|
||||
_instanceTicker:
|
||||
none: "No mostrar"
|
||||
remote: "Mostrar a usuarios remotos"
|
||||
|
@ -1169,7 +1197,7 @@ _channel:
|
|||
owned: "Dueño"
|
||||
following: "Siguiendo"
|
||||
usersCount: "{n} participantes"
|
||||
notesCount: "{n} notas"
|
||||
notesCount: "{n} publicaciones"
|
||||
nameOnly: Nombre solamente
|
||||
nameAndDescription: Nombre y descripción
|
||||
_menuDisplay:
|
||||
|
@ -1183,18 +1211,20 @@ _wordMute:
|
|||
con lineas nuevas indica una declaracion Or。"
|
||||
muteWordsDescription2: "Encerrar las palabras clave entre numerales para usar expresiones
|
||||
regulares"
|
||||
softDescription: "Ocultar en la linea de tiempo las notas que cumplen las condiciones"
|
||||
hardDescription: "Evitar que se agreguen a la linea de tiempo las notas que cumplen
|
||||
las condiciones. Las notas no agregadas seguirán quitadas aunque cambien las condiciones."
|
||||
softDescription: "Ocultar en la linea de tiempo las publicaciones que cumplen las
|
||||
condiciones"
|
||||
hardDescription: "Evitar que se agreguen a la linea de tiempo las publicaciones
|
||||
que cumplen las condiciones, estas no serán agregadas a la linea de tiempo incluso
|
||||
si cambian las condiciones."
|
||||
soft: "Suave"
|
||||
hard: "Duro"
|
||||
mutedNotes: "Notas silenciadas"
|
||||
mutedNotes: "Publicaciones silenciadas"
|
||||
_instanceMute:
|
||||
instanceMuteDescription: "Silencia todas las notas y reposts de la instancias seleccionadas,
|
||||
incluyendo respuestas a los usuarios de las mismas"
|
||||
instanceMuteDescription: "Silencia todas las publicaciones e impusos de los servidores
|
||||
seleccionados, incluyendo respuestas a los usuarios de las mismas."
|
||||
instanceMuteDescription2: "Separar por líneas"
|
||||
title: "Oculta las notas de las instancias listadas."
|
||||
heading: "Instancias a silenciar"
|
||||
title: "Oculta las publicaciones de los servidores listados."
|
||||
heading: "Servidores a silenciar"
|
||||
_theme:
|
||||
explore: "Explorar temas"
|
||||
install: "Instalar tema"
|
||||
|
@ -1243,7 +1273,7 @@ _theme:
|
|||
hashtag: "Hashtag"
|
||||
mention: "Menciones"
|
||||
mentionMe: "Menciones (yo)"
|
||||
renote: "Renotar"
|
||||
renote: "Impulsar"
|
||||
modalBg: "Fondo modal"
|
||||
divider: "Divisor"
|
||||
scrollbarHandle: "Cuadro de la barra de desplazamiento"
|
||||
|
@ -1270,23 +1300,23 @@ _theme:
|
|||
accentLighten: "Acento (claro)"
|
||||
fgHighlighted: "Texto resaltado"
|
||||
_sfx:
|
||||
note: "Notas"
|
||||
note: "Nueva publicación"
|
||||
noteMy: "Nota (a mí mismo)"
|
||||
notification: "Notificaciones"
|
||||
chat: "Chat"
|
||||
chatBg: "Chat (Fondo)"
|
||||
antenna: "Antena receptora"
|
||||
antenna: "Antenas"
|
||||
channel: "Notificaciones del canal"
|
||||
_ago:
|
||||
future: "Futuro"
|
||||
justNow: "Recién ahora"
|
||||
secondsAgo: "Hace {n} segundos"
|
||||
minutesAgo: "Hace {n} minutos"
|
||||
hoursAgo: "Hace {n} horas"
|
||||
daysAgo: "Hace {n} días"
|
||||
weeksAgo: "Hace {n} semanas"
|
||||
monthsAgo: "Hace {n} meses"
|
||||
yearsAgo: "Hace {n} años"
|
||||
secondsAgo: "Hace {n} segundo(s)"
|
||||
minutesAgo: "Hace {n} minuto(s)"
|
||||
hoursAgo: "Hace {n} hora(s)"
|
||||
daysAgo: "Hace {n} día(s)"
|
||||
weeksAgo: "Hace {n} semana(s)"
|
||||
monthsAgo: "Hace {n} mes(es)"
|
||||
yearsAgo: "Hace {n} año(s)"
|
||||
_time:
|
||||
second: "Segundos"
|
||||
minute: "Minutos"
|
||||
|
@ -1298,16 +1328,16 @@ _tutorial:
|
|||
step1_2: "Vamos a configurarte. ¡Estarás listo y funcionando en poco tiempo!"
|
||||
step2_1: "En primer lugar, rellena tu perfil"
|
||||
step2_2: "Proporcionar algo de información sobre quién eres hará que sea más fácil
|
||||
para los demás saber si quieren ver tus notas o seguirte."
|
||||
para los demás saber si quieren ver tus publicaciones o seguirte."
|
||||
step3_1: "¡Ahora es el momento de seguir a algunas personas!"
|
||||
step3_2: "Tu página de inicio y tus líneas de tiempo sociales se basan en quién
|
||||
sigues, así que intenta seguir un par de cuentas para empezar.\nHaz clic en el
|
||||
círculo más en la parte superior derecha de un perfil para seguirlos."
|
||||
step4_1: "Vamos a salir a la calle"
|
||||
step4_2: "Para tu primer post, a algunas personas les gusta hacer un post de {introduction}
|
||||
o un simple \"¡Hola mundo!\""
|
||||
step4_2: "Para tu primer publicación, a algunas personas les gusta escribir una
|
||||
{introduction} o un simple \"¡Hola mundo!\""
|
||||
step5_1: "¡Líneas de tiempo, líneas de tiempo por todas partes!"
|
||||
step5_2: "Su instancia tiene {timelines} diferentes líneas de tiempo habilitadas"
|
||||
step5_2: "Tu servidor tiene {timelines} diferentes líneas de tiempo habilitadas."
|
||||
step5_3: "La línea de tiempo Inicio {icon} es donde puedes ver las publicaciones
|
||||
de tus seguidores."
|
||||
step5_4: "La línea de tiempo Local {icon} es donde puedes ver las publicaciones
|
||||
|
@ -1475,7 +1505,8 @@ _profile:
|
|||
youCanIncludeHashtags: "Puedes añadir hashtags"
|
||||
metadata: "información adicional"
|
||||
metadataEdit: "Editar información adicional"
|
||||
metadataDescription: "Muestra la información adicional en el perfil. ¡Puede agregar una etiqueta {a} o una etiqueta {l} con {rel} para verificar el enlace en su perfil!"
|
||||
metadataDescription: "Muestra la información adicional en el perfil. ¡Puede agregar
|
||||
una etiqueta {a} o una etiqueta {l} con {rel} para verificar el enlace en su perfil!"
|
||||
metadataLabel: "Etiqueta"
|
||||
metadataContent: "Contenido"
|
||||
changeAvatar: "Cambiar avatar"
|
||||
|
@ -1887,7 +1918,7 @@ renoteUnmute: Dejar de silenciar impulsos
|
|||
flagSpeakAsCat: Habla como un gato
|
||||
selectInstance: Selecciona un servidor
|
||||
flagSpeakAsCatDescription: Tu publicación se "nyanified" cuando esté en modo gato
|
||||
allowedInstances: Instancias en la lista blanca
|
||||
allowedInstances: Servidores autorizados
|
||||
breakFollowConfirm: ¿Estás seguro de que quieres eliminar el seguidor?
|
||||
subscribePushNotification: Habilitar notificaciones
|
||||
unsubscribePushNotification: Desactivar notificaciones
|
||||
|
@ -1904,12 +1935,12 @@ hiddenTags: Etiquetas Ocultas
|
|||
noInstances: No hay servidores
|
||||
accountMoved: 'Usuario ha movido a una cuenta nueva:'
|
||||
caption: Auto Subtítulos
|
||||
showAds: Mostrar Anuncios
|
||||
showAds: Mostrar banners
|
||||
enterSendsMessage: Presione "RETORNO" en los mensajes para enviar el mensaje (para
|
||||
apagarlo es Ctrl + RETORNO)
|
||||
recommendedInstances: Instancias Recomendadas
|
||||
instanceSecurity: Seguridad de la instancia
|
||||
seperateRenoteQuote: Separar impulsados y Citar botones
|
||||
instanceSecurity: Seguridad del servidor
|
||||
seperateRenoteQuote: Separar botones de Impulsar y Citar
|
||||
_messaging:
|
||||
groups: Grupos
|
||||
dms: Privado
|
||||
|
@ -1941,3 +1972,53 @@ hiddenTagsDescription: 'Escriba los hashtags (sin el #) que desea ocultar de las
|
|||
jumpToPrevious: Ver anterior
|
||||
enableEmojiReactions: Habilitar reacciones de emoji
|
||||
cw: Aviso de contenido
|
||||
sendPushNotificationReadMessage: Eliminar notificaciones una vez que la notificación
|
||||
o mensaje ha sido leído
|
||||
sendPushNotificationReadMessageCaption: Una notificación con el texto "{emptyPushNotificationMessage}"
|
||||
será mostrada por un breve período. Esto podría aumentar el uso de batería de tu
|
||||
dispositivo.
|
||||
enableServerMachineStats: Permitir estadísticas del hardware del servidor
|
||||
customMOTD: Mensaje del día personalizado (mensajes de la pantalla de presentación)
|
||||
antennasDesc: "Las Antennas muestran nuevas publicaciones que conciden con los criterios
|
||||
que estableciste.\nPueden ser accedidas desde la sección de Lineas de tiempo."
|
||||
antennaInstancesDescription: Escribe un servidor por cada linea
|
||||
expandOnNoteClickDesc: Si está desactivado, puedes abrir publicaciones usando el menú
|
||||
del botón derecho del ratón o presionando sobre la fecha.
|
||||
channelFederationWarn: Los Canales aún no federan con otras instancias
|
||||
clipsDesc: Los clips como marcadores categorizados que pueden ser compartidos. Puedes
|
||||
crear clips desde el menú de publicaciones.
|
||||
verifiedLink: Vínculo verificado
|
||||
cannotUploadBecauseExceedsFileSizeLimit: Este archivo no pudo ser cargado porque excede
|
||||
el tamaño máximo permitido.
|
||||
accessibility: Accesibilidad
|
||||
_filters:
|
||||
fromUser: Del usuario
|
||||
fromDomain: Desde el dominio
|
||||
notesAfter: Publicaciones posteriores
|
||||
userSaysSomethingReasonReply: '{name} respondió a una publicación que contiene {reason}'
|
||||
userSaysSomethingReasonQuote: '{name} citó una publicación que contiene {reason}'
|
||||
privateModeInfo: Al activar, solo servidores autorizados podrán federar con tu servidor.
|
||||
Todas las publicaiones estáran ocultas del público.
|
||||
customMOTDDescription: Mensajes del día personalizados (MOTD) de la pantalla de presentación,
|
||||
separados cada salto de linea. Para ser mostrados aleatoriamente cada vez que un
|
||||
usuario carga/recarga una página.
|
||||
customSplashIcons: Icono personalizado de la pantalla de presentación (url)
|
||||
donationLink: Vinculo a página de donación
|
||||
delete2fa: Desactivar autentificación en dos pasos
|
||||
delete2faConfirm: Esto eliminara irreversiblemente la autentificación en dos pasos
|
||||
de esta cuenta. ¿Quieres continuar?
|
||||
allowedInstancesDescription: Host de los servidores autorizados para federar, cada
|
||||
uno separado por una nueva linea (solo aplica en modo pivado).
|
||||
adminCustomCssWarn: Está configuración solo debería ser utilizado si sabes lo que
|
||||
hace. Ingresar valores erroneos podría causar que TODOS los clientes dejaran de
|
||||
funcionar normalmente. Porfavor asegurate que tus CSS funcionan adecuadamente al
|
||||
probar los en tus configuraciones de usuario.
|
||||
image: Imagen
|
||||
showPopup: Notificar a los usuarios con una ventana emergente
|
||||
showWithSparkles: Mostrar con destellos
|
||||
youHaveUnreadAnnouncements: Tienes anuncios sin leer
|
||||
neverShow: No mostrar nuevamente
|
||||
remindMeLater: Recordar nuevamente
|
||||
removeQuote: Eliminar cita
|
||||
removeRecipient: Eliminar destinatario
|
||||
removeMember: Eliminar miembro
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
_lang_: "Français"
|
||||
headlineFirefish: "Réseau relié par des notes"
|
||||
headlineFirefish: "Une plateforme de réseaux sociaux décentralisé, open source qui
|
||||
est gratuit pour toujours ! 🚀"
|
||||
introFirefish: "Bienvenue ! Firefish est une plateforme de réseau social décentralisé
|
||||
et open source qui est gratuite pour toujours ! 🚀"
|
||||
monthAndDay: "{day}/{month}"
|
||||
|
@ -13,8 +14,8 @@ ok: "OK"
|
|||
gotIt: "J’ai compris !"
|
||||
cancel: "Annuler"
|
||||
enterUsername: "Entrer un nom d’utilisateur·rice"
|
||||
renotedBy: "Renoté par {user}"
|
||||
noNotes: "Aucune note"
|
||||
renotedBy: "Boosté par {user}"
|
||||
noNotes: "Aucun post"
|
||||
noNotifications: "Aucune notification"
|
||||
instance: "Serveur"
|
||||
settings: "Paramètres"
|
||||
|
@ -45,8 +46,8 @@ copyContent: "Copier le contenu"
|
|||
copyLink: "Copier le lien"
|
||||
delete: "Supprimer"
|
||||
deleteAndEdit: "Supprimer et réécrire"
|
||||
deleteAndEditConfirm: "Êtes-vous sûr·e de vouloir supprimer cette note et la reformuler
|
||||
? Vous perdrez toutes les réactions, renotes et réponses y afférentes."
|
||||
deleteAndEditConfirm: "Êtes-vous sûr·e de vouloir supprimer ce post et le reformuler
|
||||
? Vous perdrez toutes les réactions, boosts et réponses liées."
|
||||
addToList: "Ajouter à une liste"
|
||||
sendMessage: "Envoyer un message"
|
||||
copyUsername: "Copier le nom d’utilisateur·rice"
|
||||
|
@ -60,14 +61,14 @@ receiveFollowRequest: "Demande d’abonnement reçue"
|
|||
followRequestAccepted: "La demande d’abonnement a été acceptée"
|
||||
mention: "Mentionner"
|
||||
mentions: "Mentions"
|
||||
directNotes: "Notes directes"
|
||||
directNotes: "Messages directs"
|
||||
importAndExport: "Import et export"
|
||||
import: "Importer"
|
||||
export: "Exporter"
|
||||
files: "Fichiers"
|
||||
download: "Télécharger"
|
||||
driveFileDeleteConfirm: "Êtes-vous sûr·e de vouloir supprimer le fichier \"{name}\"\
|
||||
\ ? Il sera retiré de toutes ses notes liées."
|
||||
\ ? Il sera retiré de tous ses posts liées."
|
||||
unfollowConfirm: "Désirez-vous vous désabonner de {name} ?"
|
||||
exportRequested: "Vous avez demandé une exportation. L’opération pourrait prendre
|
||||
un peu de temps. Une terminée, le fichier résultant sera ajouté au Drive."
|
||||
|
@ -94,18 +95,18 @@ youShouldUpgradeClient: "Si la page ne s'affiche pas correctement, rechargez-la
|
|||
enterListName: "Nom de la liste"
|
||||
privacy: "Confidentialité"
|
||||
makeFollowManuallyApprove: "Accepter manuellement les demandes d’abonnement"
|
||||
defaultNoteVisibility: "Visibilité des notes par défaut"
|
||||
defaultNoteVisibility: "Visibilité des posts par défaut"
|
||||
follow: "S’abonner"
|
||||
followRequest: "Demande d’abonnement"
|
||||
followRequests: "Demandes d’abonnement"
|
||||
unfollow: "Se désabonner"
|
||||
followRequestPending: "Demande d'abonnement en attente de confirmation"
|
||||
enterEmoji: "Insérer un émoji"
|
||||
renote: "Renoter"
|
||||
unrenote: "Annuler la Renote"
|
||||
renoted: "Renoté."
|
||||
cantRenote: "Ce message ne peut pas être renoté."
|
||||
cantReRenote: "Impossible de renoter une Renote."
|
||||
renote: "Booster"
|
||||
unrenote: "Annuler le boost"
|
||||
renoted: "Boosté."
|
||||
cantRenote: "Ce message ne peut pas être boosté."
|
||||
cantReRenote: "Impossible de partager ce boost."
|
||||
quote: "Citer"
|
||||
pinnedNote: "Note épinglée"
|
||||
pinned: "Épingler sur le profil"
|
||||
|
@ -117,9 +118,9 @@ reaction: "Réactions"
|
|||
reactionSetting: "Réactions à afficher dans le sélecteur de réactions"
|
||||
reactionSettingDescription2: "Déplacer pour réorganiser, cliquer pour effacer, utiliser
|
||||
« + » pour ajouter."
|
||||
rememberNoteVisibility: "Activer l'option \" se souvenir de la visibilité des notes
|
||||
rememberNoteVisibility: "Activer l'option \" se souvenir de la visibilité des posts
|
||||
\" vous permet de réutiliser automatiquement la visibilité utilisée lors de la publication
|
||||
de votre note précédente."
|
||||
de votre post précédent."
|
||||
attachCancel: "Supprimer le fichier attaché"
|
||||
markAsSensitive: "Marquer comme sensible"
|
||||
unmarkAsSensitive: "Supprimer le marquage comme sensible"
|
||||
|
@ -175,9 +176,9 @@ proxyAccount: "Compte proxy"
|
|||
proxyAccountDescription: "Un compte proxy se comporte, dans certaines conditions,
|
||||
comme un·e abonné·e distant·e pour les utilisateur·rice·s d'autres serveurs. Par
|
||||
exemple, quand un·e utilisateur·rice local ajoute un·e utilisateur·rice distant·e
|
||||
à une liste, ses notes ne seront pas visibles sur le serveur si personne ne suit
|
||||
à une liste, ses posts ne seront pas visibles sur le serveur si personne ne suit
|
||||
cet·te utilisateur·rice. Le compte proxy va donc suivre cet·te utilisateur·rice
|
||||
pour que ses notes soient acheminées."
|
||||
pour que ses posts soient acheminées."
|
||||
host: "Serveur distant"
|
||||
selectUser: "Sélectionner un·e utilisateur·rice"
|
||||
recipient: "Destinataire"
|
||||
|
@ -207,7 +208,7 @@ instanceInfo: "Informations du serveur"
|
|||
statistics: "Statistiques"
|
||||
clearQueue: "Vider la file d’attente"
|
||||
clearQueueConfirmTitle: "Êtes-vous sûr·e de vouloir vider la file d’attente ?"
|
||||
clearQueueConfirmText: "Les notes non distribuées ne seront pas délivrées. Normalement,
|
||||
clearQueueConfirmText: "Les posts non distribués ne seront pas délivrés. Normalement,
|
||||
vous n'avez pas besoin d'effectuer cette opération."
|
||||
clearCachedFiles: "Vider le cache"
|
||||
clearCachedFilesConfirm: "Êtes-vous sûr·e de vouloir vider tout le cache de fichiers
|
||||
|
@ -220,8 +221,8 @@ mutedUsers: "Utilisateur·rice·s en sourdine"
|
|||
blockedUsers: "Utilisateur·rice·s bloqué·e·s"
|
||||
noUsers: "Il n’y a pas d’utilisateur·rice·s"
|
||||
editProfile: "Modifier votre profil"
|
||||
noteDeleteConfirm: "Êtes-vous sûr·e de vouloir supprimer cette note ?"
|
||||
pinLimitExceeded: "Vous ne pouvez pas épingler plus de notes"
|
||||
noteDeleteConfirm: "Êtes-vous sûr·e de vouloir supprimer ce post ?"
|
||||
pinLimitExceeded: "Vous ne pouvez pas épingler plus de posts"
|
||||
intro: "L’installation de Firefish est terminée ! Veuillez créer un compte administrateur."
|
||||
done: "Terminé"
|
||||
processing: "Traitement en cours"
|
||||
|
@ -366,7 +367,7 @@ pinnedPages: "Pages épinglées"
|
|||
pinnedPagesDescription: "Inscrivez le chemin des Pages que vous souhaitez épingler
|
||||
en haut de la page du serveur. Séparez les d'un retour à la ligne."
|
||||
pinnedClipId: "Identifiant du clip épinglé"
|
||||
pinnedNotes: "Note épinglée"
|
||||
pinnedNotes: "Posts épinglée"
|
||||
hcaptcha: "hCaptcha"
|
||||
enableHcaptcha: "Activer hCaptcha"
|
||||
hcaptchaSiteKey: "Clé du site"
|
||||
|
@ -386,14 +387,14 @@ antennaKeywords: "Mots clés à recevoir"
|
|||
antennaExcludeKeywords: "Mots clés à exclure"
|
||||
antennaKeywordsDescription: "Séparer avec des espaces pour la condition AND. Séparer
|
||||
avec un saut de ligne pour une condition OR."
|
||||
notifyAntenna: "Je souhaite recevoir les notifications des nouvelles notes"
|
||||
withFileAntenna: "Notes ayant des attachements uniquement"
|
||||
notifyAntenna: "Je souhaite recevoir les notifications des nouveaux posts"
|
||||
withFileAntenna: "Posts ayant des attachements uniquement"
|
||||
enableServiceworker: "Activer ServiceWorker"
|
||||
antennaUsersDescription: "Saisissez un seul nom d’utilisateur·rice par ligne"
|
||||
caseSensitive: "Sensible à la casse"
|
||||
withReplies: "Inclure les réponses"
|
||||
connectedTo: "Vous êtes connectés aux services suivants"
|
||||
notesAndReplies: "Notes et Réponses"
|
||||
notesAndReplies: "Posts et Réponses"
|
||||
withFiles: "Avec fichiers joints"
|
||||
silence: "Mettre en sourdine"
|
||||
silenceConfirm: "Êtes-vous sûr·e de vouloir mettre l’utilisateur·rice en sourdine
|
||||
|
@ -431,7 +432,7 @@ notFoundDescription: "Aucune page ne correspond à l’URL spécifiée."
|
|||
uploadFolder: "Emplacement de téléversement par défaut"
|
||||
cacheClear: "Vider le cache"
|
||||
markAsReadAllNotifications: "Marquer toutes les notifications comme lues"
|
||||
markAsReadAllUnreadNotes: "Marquer toutes les notes comme lues"
|
||||
markAsReadAllUnreadNotes: "Marquer tous les posts comme lus"
|
||||
markAsReadAllTalkMessages: "Marquer toutes les discussions comme lues"
|
||||
help: "Aide"
|
||||
inputMessageHere: "Écrivez votre message ici"
|
||||
|
@ -452,7 +453,7 @@ text: "Texte"
|
|||
enable: "Activer"
|
||||
next: "Suivant"
|
||||
retype: "Confirmation"
|
||||
noteOf: "Notes de {user}"
|
||||
noteOf: "Posts de {user}"
|
||||
inviteToGroup: "Inviter dans un groupe"
|
||||
quoteAttached: "Avec citation"
|
||||
quoteQuestion: "Souhaitez-vous ajouter une citation ?"
|
||||
|
@ -512,8 +513,8 @@ accountSettings: "Paramètres du compte"
|
|||
promotion: "Promu"
|
||||
promote: "Promouvoir"
|
||||
numberOfDays: "Nombre de jours"
|
||||
hideThisNote: "Masquer cette note"
|
||||
showFeaturedNotesInTimeline: "Afficher les notes des Tendances dans le fil d'actualité"
|
||||
hideThisNote: "Masquer ce post"
|
||||
showFeaturedNotesInTimeline: "Afficher les posts des Tendances dans le fil d'actualité"
|
||||
objectStorage: "Stockage d'objets"
|
||||
useObjectStorage: "Utiliser le stockage d'objets"
|
||||
objectStorageBaseUrl: "Base URL"
|
||||
|
@ -544,7 +545,7 @@ objectStorageSetPublicRead: "Régler sur « public » lors de l'envoi"
|
|||
serverLogs: "Journal du serveur"
|
||||
deleteAll: "Supprimer tout"
|
||||
showFixedPostForm: "Afficher le formulaire de publication en haut du fil d'actualité"
|
||||
newNoteRecived: "Voir les nouvelles notes"
|
||||
newNoteRecived: "Voir les nouveaux posts"
|
||||
sounds: "Sons"
|
||||
listen: "Écouter"
|
||||
none: "Rien"
|
||||
|
@ -594,8 +595,8 @@ addRelay: "Ajouter un relais"
|
|||
inboxUrl: "Inbox URL"
|
||||
addedRelays: "Relais ajoutés"
|
||||
serviceworkerInfo: "Devrait être activé pour les notifications push."
|
||||
deletedNote: "Note supprimée"
|
||||
invisibleNote: "Note invisible"
|
||||
deletedNote: "Post supprimé"
|
||||
invisibleNote: "Post invisible"
|
||||
enableInfiniteScroll: "Activer le défilement infini"
|
||||
visibility: "Visibilité"
|
||||
poll: "Sondage"
|
||||
|
@ -680,7 +681,7 @@ abuseReports: "Signalements"
|
|||
reportAbuse: "Signaler"
|
||||
reportAbuseOf: "Signaler {name}"
|
||||
fillAbuseReportDescription: "Veuillez expliquer les raisons du signalement. S'il s'agit
|
||||
d'une note particulière, veuillez inclure le lien."
|
||||
d'un post particulier, veuillez inclure le lien."
|
||||
abuseReported: "Le rapport est envoyé. Merci."
|
||||
reporter: "Signalé par"
|
||||
reporteeOrigin: "Origine du signalement"
|
||||
|
@ -693,7 +694,7 @@ openInSideView: "Ouvrir en vue latérale"
|
|||
defaultNavigationBehaviour: "Navigation par défaut"
|
||||
editTheseSettingsMayBreakAccount: "La modification de ces paramètres peut endommager
|
||||
votre compte."
|
||||
instanceTicker: "Nom du serveur d'origine des notes"
|
||||
instanceTicker: "Nom du serveur d'origine des posts"
|
||||
waitingFor: "En attente de {x}"
|
||||
random: "Aléatoire"
|
||||
system: "Système"
|
||||
|
@ -708,11 +709,11 @@ i18nInfo: "Firefish est traduit dans différentes langues par des bénévoles. V
|
|||
contribuer à {link}."
|
||||
manageAccessTokens: "Gérer les jetons d'accès"
|
||||
accountInfo: " Informations du compte "
|
||||
notesCount: "Nombre de notes"
|
||||
notesCount: "Nombre de posts"
|
||||
repliesCount: "Nombre de réponses envoyées"
|
||||
renotesCount: "Nombre de notes que vous avez renotées"
|
||||
renotesCount: "Nombre de boosts que vous avez envoyé"
|
||||
repliedCount: "Nombre de réponses reçues"
|
||||
renotedCount: "Nombre de vos notes renotées"
|
||||
renotedCount: "Nombre de vos posts boostés"
|
||||
followingCount: "Nombre de comptes suivis"
|
||||
followersCount: "Nombre d'abonnés"
|
||||
sentReactionsCount: "Nombre de réactions envoyées"
|
||||
|
@ -725,9 +726,9 @@ driveFilesCount: "Nombre de fichiers dans le Drive"
|
|||
driveUsage: "Utilisation du Drive"
|
||||
noCrawle: "Refuser l'indexation par les robots"
|
||||
noCrawleDescription: "Demandez aux moteurs de recherche de ne pas indexer votre page
|
||||
de profil, vos notes, vos pages, etc."
|
||||
lockedAccountInfo: "À moins que vous ne définissiez la visibilité de votre note sur
|
||||
\"Abonné-e-s\", vos notes sont visibles par tous, même si vous exigez que les demandes
|
||||
de profil, vos posts, vos pages, etc."
|
||||
lockedAccountInfo: "À moins que vous ne définissiez la visibilité de votre post sur
|
||||
\"Abonné-e-s\", vos posts sont visibles par tous, même si vous exigez que les demandes
|
||||
d'abonnement soient approuvées manuellement."
|
||||
alwaysMarkSensitive: "Marquer les médias comme contenu sensible par défaut"
|
||||
loadRawImages: "Affichage complet des images jointes au lieu des vignettes"
|
||||
|
@ -736,7 +737,7 @@ verificationEmailSent: "Un e-mail de vérification a été envoyé. Veuillez acc
|
|||
lien pour compléter la vérification."
|
||||
notSet: "Non défini"
|
||||
emailVerified: "Votre adresse e-mail a été vérifiée."
|
||||
noteFavoritesCount: "Nombre de notes dans les favoris"
|
||||
noteFavoritesCount: "Nombre de posts dans les favoris"
|
||||
pageLikesCount: "Nombre de pages aimées"
|
||||
pageLikedCount: "Nombre de vos pages aimées"
|
||||
contact: "Contact"
|
||||
|
@ -747,7 +748,7 @@ developer: "Développeur"
|
|||
makeExplorable: "Rendre le compte visible sur la page \"Découvrir\"."
|
||||
makeExplorableDescription: "Si vous désactivez cette option, votre compte n'apparaîtra
|
||||
pas sur la page \"Découvrir\"."
|
||||
showGapBetweenNotesInTimeline: "Afficher un écart entre les notes du fil d’actualité"
|
||||
showGapBetweenNotesInTimeline: "Afficher un écart entre les posts du fil d’actualité"
|
||||
duplicate: "Duliquer"
|
||||
left: "Gauche"
|
||||
center: "Centrer"
|
||||
|
@ -760,7 +761,7 @@ showTitlebar: "Afficher la barre de titre"
|
|||
clearCache: "Vider le cache"
|
||||
onlineUsersCount: "{n} utilisateur(s) en ligne"
|
||||
nUsers: "{n} utilisateur·rice·s"
|
||||
nNotes: "{n} Notes"
|
||||
nNotes: "{n} Posts"
|
||||
sendErrorReports: "Envoyer les rapports d’erreur"
|
||||
sendErrorReportsDescription: "Si vous activez l'envoi des rapports d'erreur, vous
|
||||
contribuerez à améliorer la qualité de Firefish grâce au partage d'informations
|
||||
|
@ -805,8 +806,8 @@ unlikeConfirm: "Êtes-vous sûr·e de ne plus vouloir aimer cette publication ?"
|
|||
fullView: "Plein écran"
|
||||
quitFullView: "Quitter le plein écran"
|
||||
addDescription: "Ajouter une description"
|
||||
userPagePinTip: "Vous pouvez afficher des notes ici en sélectionnant l'option « Épingler
|
||||
au profil » dans le menu de chaque note."
|
||||
userPagePinTip: "Vous pouvez afficher des posts ici en sélectionnant l'option « Épingler
|
||||
au profil » dans le menu de chaque post."
|
||||
notSpecifiedMentionWarning: "Vous avez mentionné des utilisateur·rice·s qui ne font
|
||||
pas partie de la liste des destinataires"
|
||||
info: "Informations"
|
||||
|
@ -838,7 +839,7 @@ postToGallery: "Publier dans la galerie"
|
|||
gallery: "Galerie"
|
||||
recentPosts: "Les plus récentes"
|
||||
popularPosts: "Les plus consultées"
|
||||
shareWithNote: "Partager dans une note"
|
||||
shareWithNote: "Partager dans un post"
|
||||
ads: "Bannière communautaire"
|
||||
expiration: "Échéance"
|
||||
memo: "Pense-bête"
|
||||
|
@ -1121,7 +1122,7 @@ _channel:
|
|||
owned: "Mes canaux"
|
||||
following: "Abonné·e"
|
||||
usersCount: "{n} Participant·e·s"
|
||||
notesCount: "{n} Notes"
|
||||
notesCount: "{n} Posts"
|
||||
nameAndDescription: Nom et description
|
||||
nameOnly: Nom uniquement
|
||||
_menuDisplay:
|
||||
|
@ -1135,20 +1136,20 @@ _wordMute:
|
|||
un saut de ligne pour une condition OR."
|
||||
muteWordsDescription2: "Pour utiliser des expressions régulières (regex), mettez
|
||||
les mots-clés entre barres obliques."
|
||||
softDescription: "Masquez de votre fil d’actualité les notes qui répondent aux conditions
|
||||
softDescription: "Masquez de votre fil d’actualité les posts qui répondent aux conditions
|
||||
définies."
|
||||
hardDescription: "Empêche les notes qui remplissent les conditions définies d'être
|
||||
hardDescription: "Empêche les posts qui remplissent les conditions définies d'être
|
||||
ajoutées au fil d'actualité. Cette action est irréversible : si vous modifiez
|
||||
ces conditions plus tard, les notes précédemment filtrées ne seront pas récupérées."
|
||||
ces conditions plus tard, les posts précédemment filtrées ne seront pas récupérées."
|
||||
soft: "Doux"
|
||||
hard: "Strict"
|
||||
mutedNotes: "Notes filtrées"
|
||||
mutedNotes: "Posts filtrés"
|
||||
_instanceMute:
|
||||
instanceMuteDescription2: "Séparer avec des sauts de lignes"
|
||||
title: "Masque les notes venant des serveurs listés."
|
||||
title: "Masque les posts provenant des serveurs listés."
|
||||
heading: "Serveurs à mettre en sourdine/masquer"
|
||||
instanceMuteDescription: Ceci va masquer toute publication ou partage de serveurs
|
||||
listés, incluant celles des personnes répondant à des personnes des serveurs masqués.
|
||||
instanceMuteDescription: Ceci va masquer toute posts ou boosts de serveurs listés,
|
||||
incluant celles des personnes répondant à des personnes des serveurs masqués.
|
||||
_theme:
|
||||
explore: "Explorer les thèmes"
|
||||
install: "Installer un thème"
|
||||
|
@ -1199,7 +1200,7 @@ _theme:
|
|||
hashtag: "Hashtags"
|
||||
mention: "Mentionner"
|
||||
mentionMe: "Mentions (Moi)"
|
||||
renote: "Renoter"
|
||||
renote: "Booster"
|
||||
modalBg: "Modal d'arrière-plan"
|
||||
divider: "Séparateur"
|
||||
scrollbarHandle: "Poignée de la barre de navigation"
|
||||
|
@ -1226,8 +1227,8 @@ _theme:
|
|||
accentLighten: "Plus clair"
|
||||
fgHighlighted: "Texte mis en évidence"
|
||||
_sfx:
|
||||
note: "Nouvelle note"
|
||||
noteMy: "Ma note"
|
||||
note: "Nouveau post"
|
||||
noteMy: "Mon post"
|
||||
notification: "Notifications"
|
||||
chat: "Discuter"
|
||||
chatBg: "Discussion (arrière-plan)"
|
||||
|
@ -1254,14 +1255,14 @@ _tutorial:
|
|||
step1_2: "On va vous installer. Vous serez opérationnel en un rien de temps"
|
||||
step2_1: "Tout d'abord, remplissez votre profil"
|
||||
step2_2: "En fournissant quelques informations sur qui vous êtes, il sera plus facile
|
||||
pour les autres de savoir s'ils veulent voir vos notes ou vous suivre."
|
||||
pour les autres de savoir s'ils veulent voir vos posts ou vous suivre."
|
||||
step3_1: "Maintenant il est temps de suivre des gens !"
|
||||
step3_2: "Vos fil d’actualité Principal et Social sont basés sur les personnes que
|
||||
vous suivez, alors essayez de suivre quelques comptes pour commencer.\nCliquez
|
||||
sur le cercle plus en haut à droite d'un profil pour le suivre."
|
||||
step4_1: "On y va."
|
||||
step4_2: "Pour votre première note, certaines personnes aiment faire une note {introduction}
|
||||
ou une simple note 'Bonjours tout le monde !'."
|
||||
step4_2: "Pour votre premier post, certaines personnes aiment faire un post {introduction}
|
||||
ou un simple 'Bonjours tout le monde !'"
|
||||
step5_1: "Des fils, des fils d’actualité partout !"
|
||||
step5_2: "Votre serveur a {timelines} fils différents disponibles !"
|
||||
step5_3: "Le fil {icon} Principal est l'endroit où vous pouvez voir les publications
|
||||
|
@ -1334,7 +1335,7 @@ _permissions:
|
|||
"write:messaging": "Gérer les discussions"
|
||||
"read:mutes": "Voir les comptes masqués"
|
||||
"write:mutes": "Gérer les comptes masqués"
|
||||
"write:notes": "Créer / supprimer des notes"
|
||||
"write:notes": "Créer / supprimer des posts"
|
||||
"read:notifications": "Afficher les notifications"
|
||||
"write:notifications": "Gérer vos notifications"
|
||||
"read:reactions": "Lire les réactions"
|
||||
|
@ -1363,12 +1364,12 @@ _auth:
|
|||
copyAsk: "Veuillez coller le code d’autorisation suivant dans l'application :"
|
||||
allPermissions: Accès complet au compte
|
||||
_antennaSources:
|
||||
all: "Toutes les notes"
|
||||
homeTimeline: "Notes provenant des utilisateur·rice·s auxquel·les je suis abonné"
|
||||
users: "Notes venant de la part d’utilisateur·rice·s précis"
|
||||
userList: "Notes venant d’une liste spécifique"
|
||||
userGroup: "Notes venant d’utilisateur·rice·s du groupe spécifié"
|
||||
instances: Notes de tous les utilisateurs d'un serveur
|
||||
all: "Tous les posts"
|
||||
homeTimeline: "Posts provenant des utilisateur·rice·s auxquel·les je suis abonné"
|
||||
users: "Posts venant de la part d’utilisateur·rice·s précis"
|
||||
userList: "Posts venant d’une liste spécifique"
|
||||
userGroup: "Posts venant d’utilisateur·rice·s du groupe spécifié"
|
||||
instances: Posts de tous les utilisateurs d'un serveur
|
||||
_weekday:
|
||||
sunday: "Dimanche"
|
||||
monday: "Lundi"
|
||||
|
@ -1401,7 +1402,7 @@ _widgets:
|
|||
_userList:
|
||||
chooseList: Sélectionner une liste
|
||||
unixClock: Horloge UNIX
|
||||
meiliIndexCount: Notes indexées
|
||||
meiliIndexCount: Posts indexés
|
||||
serverInfo: Info serveur
|
||||
meiliStatus: État du serveur
|
||||
meiliSize: Taille de l’index
|
||||
|
@ -1446,8 +1447,8 @@ _visibility:
|
|||
localOnly: "Local seulement"
|
||||
localOnlyDescription: "Caché pour les utilisateur·rice·s distant"
|
||||
_postForm:
|
||||
replyPlaceholder: "Répondre à cette note ..."
|
||||
quotePlaceholder: "Citez cette note ..."
|
||||
replyPlaceholder: "Répondre à ce post ..."
|
||||
quotePlaceholder: "Citez ce post ..."
|
||||
channelPlaceholder: "Publier sur une chaîne…"
|
||||
_placeholders:
|
||||
a: "Quoi de neuf ?"
|
||||
|
@ -1473,7 +1474,7 @@ _profile:
|
|||
locationDescription: Si vous entrez votre ville en premier, votre heure locale sera
|
||||
affichée aux autres utilisateur·rice·s.
|
||||
_exportOrImport:
|
||||
allNotes: "Toutes les notes"
|
||||
allNotes: "Tous les posts"
|
||||
followingList: "Abonnements"
|
||||
muteList: "Comptes masqués"
|
||||
blockingList: "Comptes bloqués"
|
||||
|
@ -1486,10 +1487,10 @@ _charts:
|
|||
usersIncDec: "Variation du nombre d'utilisateur·rice·s"
|
||||
usersTotal: "Nombre des utilisateur·rice·s au total"
|
||||
activeUsers: "Nombre d'utilisateurices actif·ve·s"
|
||||
notesIncDec: "Variation du nombre des notes"
|
||||
localNotesIncDec: "Variation du nombre de notes locales"
|
||||
remoteNotesIncDec: "Variation du nombre de notes distantes"
|
||||
notesTotal: "Nombre total des notes"
|
||||
notesIncDec: "Variation du nombre de publications"
|
||||
localNotesIncDec: "Variation du nombre de publications locales"
|
||||
remoteNotesIncDec: "Variation du nombre de publications distantes"
|
||||
notesTotal: "Nombre total des publications"
|
||||
filesIncDec: "Variation du nombre de fichiers"
|
||||
filesTotal: "Nombre total de fichiers"
|
||||
storageUsageIncDec: "Variation de l'utilisation du stockage"
|
||||
|
@ -1498,8 +1499,8 @@ _instanceCharts:
|
|||
requests: "Requêtes"
|
||||
users: "Variation du nombre d'utilisateur·rice·s"
|
||||
usersTotal: "Total cumulé du nombre d'utilisateur·rice·s"
|
||||
notes: "Variation du nombre de notes"
|
||||
notesTotal: "Nombre total cumulé des notes"
|
||||
notes: "Variation du nombre de publications"
|
||||
notesTotal: "Nombre total cumulé des publications"
|
||||
ff: "Variation des abonné·e·s / abonnements"
|
||||
ffTotal: "Total cumulé du nombre d'abonné·e·s / abonnements"
|
||||
cacheSize: "Variation de la taille du cache"
|
||||
|
@ -1587,10 +1588,10 @@ _pages:
|
|||
id: "Toile ID"
|
||||
width: "Largeur"
|
||||
height: "Hauteur"
|
||||
note: "Note intégrée"
|
||||
note: "Post intégré"
|
||||
_note:
|
||||
id: "Identifiant de la note"
|
||||
idDescription: "Vous pouvez aussi coller ici l'URL ici."
|
||||
id: "Identifiant du post"
|
||||
idDescription: "Vous pouvez aussi coller l'URL du post ici."
|
||||
detailed: "Afficher les détails"
|
||||
switch: "Interrupteur"
|
||||
_switch:
|
||||
|
@ -1813,7 +1814,7 @@ _notification:
|
|||
youGotMention: "{name} vous a mentionné"
|
||||
youGotReply: "Réponse de {name}"
|
||||
youGotQuote: "Cité·e par {name}"
|
||||
youRenoted: "{name} vous a Renoté"
|
||||
youRenoted: "{name} vous a boosté"
|
||||
youGotPoll: "{name} a participé à votre sondage"
|
||||
youGotMessagingMessageFromUser: "{name} vous envoyé un message"
|
||||
youGotMessagingMessageFromGroup: "Un message a été envoyé au groupe {name}"
|
||||
|
@ -1828,7 +1829,7 @@ _notification:
|
|||
follow: "Nouvel·le abonné·e"
|
||||
mention: "Mentions"
|
||||
reply: "Réponses"
|
||||
renote: "Renotes"
|
||||
renote: "Boosts"
|
||||
quote: "Citations"
|
||||
reaction: "Réactions"
|
||||
pollVote: "Votes dans des sondages"
|
||||
|
@ -1840,9 +1841,9 @@ _notification:
|
|||
_actions:
|
||||
followBack: "Suivre"
|
||||
reply: "Répondre"
|
||||
renote: "Renoter"
|
||||
renote: "Boosts"
|
||||
reacted: a réagit à votre Note
|
||||
renoted: a boosté votre Note
|
||||
renoted: a boosté votre post
|
||||
voted: a voté pour votre sondage
|
||||
_deck:
|
||||
alwaysShowMainColumn: "Toujours afficher la colonne principale"
|
||||
|
@ -1931,7 +1932,7 @@ moveAccountDescription: Ce processus est irréversible. Soyez sûr⋅e que vous
|
|||
un alias pour ce compte sur votre nouveau compte avant de migrer. Merci d'entrer
|
||||
la mention du compte formaté comme ceci @personne@server.com
|
||||
moveAccount: Déplacer le compte !
|
||||
seperateRenoteQuote: Séparer les renotes et les boutons de citation
|
||||
seperateRenoteQuote: Séparer les boutons de boosts et de citation
|
||||
failedToFetchAccountInformation: Impossible de récupérer les informations de compte
|
||||
noEmailServerWarning: Serveur mail non configuré.
|
||||
deleteAccount: Supprimer le compte
|
||||
|
@ -2002,7 +2003,7 @@ forwardReportIsAnonymous: À la place de votre compte, un compte système anonym
|
|||
affiché comme rapporteur au serveur distant.
|
||||
noThankYou: Non merci
|
||||
addInstance: Ajouter un serveur
|
||||
renoteMute: Mettre en silence les renotes
|
||||
renoteMute: Masquer les boosts
|
||||
flagSpeakAsCat: Parler comme un chat
|
||||
flagSpeakAsCatDescription: Vos messages seront nyanifiés en mode chat
|
||||
hiddenTags: Hashtags cachés
|
||||
|
@ -2059,14 +2060,14 @@ pushNotificationAlreadySubscribed: Notifications push déjà activées
|
|||
logoImageUrl: URL de l'image du logo
|
||||
moveToLabel: 'Compte vers lequel vous migrez :'
|
||||
moveFrom: Migrer vers ce compte depuis un ancien compte
|
||||
defaultReaction: Émoji de réaction par défaut pour les notes entrantes et sortantes
|
||||
defaultReaction: Émoji de réaction par défaut pour les posts entrants et sortants
|
||||
license: Licence
|
||||
indexPosts: Indexer les Notes
|
||||
indexPosts: Indexer les Posts
|
||||
indexNotice: Indexation en cours. Cela prendra certainement du temps, veuillez ne
|
||||
pas redémarrer votre serveur pour au moins une heure.
|
||||
customKaTeXMacro: Macros KaTeX personnalisées
|
||||
enableCustomKaTeXMacro: Activer les macros KaTeX personnalisées
|
||||
noteId: ID de Note
|
||||
noteId: ID des Posts
|
||||
customKaTeXMacroDescription: "Définissez des macros pour écrire des expressions mathématiques
|
||||
simplement ! La notation se conforme aux définitions de commandes LaTeX et s'écrit
|
||||
\\newcommand{\\·name}{content} ou \\newcommand{\\name}[number of arguments]{content}.
|
||||
|
@ -2085,7 +2086,7 @@ deleted: Effacé
|
|||
editNote: Modifier note
|
||||
edited: 'Modifié à {date} {time}'
|
||||
flagShowTimelineRepliesDescription: Si activé, affiche dans le fil les réponses des
|
||||
utilisatieur·rice·s aux notes des autres.
|
||||
utilisatieur·rice·s aux posts des autres.
|
||||
_experiments:
|
||||
alpha: Alpha
|
||||
beta: Beta
|
||||
|
@ -2096,21 +2097,21 @@ _experiments:
|
|||
peut entraîner des ralentissements lors du chargement si votre file d'attente
|
||||
est congestionnée.
|
||||
findOtherInstance: Trouver un autre serveur
|
||||
userSaysSomethingReasonQuote: '{name} a cité une note contenant {reason}'
|
||||
userSaysSomethingReasonQuote: '{name} a cité un post contenant {reason}'
|
||||
signupsDisabled: Les inscriptions sur ce serveur sont actuellement désactivés, mais
|
||||
vous pouvez toujours vous inscrire sur un autre serveur ! Si vous avez un code d'invitation
|
||||
pour ce serveur, entrez-le ci-dessous s'il vous plait.
|
||||
apps: Applications
|
||||
userSaysSomethingReasonReply: '{noms} a répondu à une note contenant {raison}'
|
||||
userSaysSomethingReasonReply: '{noms} a répondu à un post contenant {raison}'
|
||||
defaultValueIs: 'défaut : {valeur}'
|
||||
searchPlaceholder: Recherchez sur Firefish
|
||||
removeReaction: Retirer votre réaction
|
||||
selectChannel: Sélectionner une chaîne
|
||||
expandOnNoteClick: Ouvrir la note en cliquant
|
||||
expandOnNoteClick: Ouvrir le post en cliquant
|
||||
preventAiLearning: Empêcher le récupération de données par des IA
|
||||
listsDesc: Les listes vous laissent créer des fils personnalisés avec des utilisateur·rice·s
|
||||
spécifié·e·s. Elles sont accessibles depuis la page des fils.
|
||||
indexFromDescription: Laisser vide pour indexer toutes les Notes
|
||||
indexFromDescription: Laisser vide pour indexer toutes les Posts
|
||||
_feeds:
|
||||
jsonFeed: flux JSON
|
||||
atom: Atom
|
||||
|
@ -2118,9 +2119,9 @@ _feeds:
|
|||
rss: RSS
|
||||
alt: ALT
|
||||
swipeOnMobile: Permettre le balayage entre les pages
|
||||
expandOnNoteClickDesc: Si désactivé, vous pourrez toujours ouvrir les Notes dans le
|
||||
expandOnNoteClickDesc: Si désactivé, vous pourrez toujours ouvrir les posts dans le
|
||||
menu du clic droit et en cliquant sur l’horodatage.
|
||||
indexFrom: Indexer à partir de l’ID des Notes
|
||||
indexFrom: Indexer à partir de l’ID des Posts
|
||||
older: plus ancien
|
||||
newer: plus récent
|
||||
accessibility: Accessibilité
|
||||
|
@ -2128,7 +2129,7 @@ silencedInstancesDescription: Listez les noms de domaine de serveurs que vous vo
|
|||
masquer. Les comptes des serveurs listés seront traités comme "Masqués", ne pourront
|
||||
faire que des demandes d’abonnement, et ne pourront pas mentionner les comptes locaux
|
||||
si non-suivis. Cela n’affectera en rien les serveurs bloqués.
|
||||
antennasDesc: "Les Antennes affichent de nouvelles notes selon les critères que vous
|
||||
antennasDesc: "Les Antennes affichent de nouveaux posts selon les critères que vous
|
||||
indiqués.\nElles peuvent être consultées depuis la page des fils."
|
||||
image: Image
|
||||
video: Vidéo
|
||||
|
@ -2138,10 +2139,10 @@ cw: Avertissement de contenu
|
|||
xl: XL
|
||||
reflectMayTakeTime: Il pourra s’écouler un certain temps avant que les changements
|
||||
ne soient reflétés.
|
||||
userSaysSomethingReasonRenote: '{name} a boosté une note contenant {reason}'
|
||||
userSaysSomethingReasonRenote: '{name} a boosté un post contenant {reason}'
|
||||
sendModMail: Envoyer un avis à la modération
|
||||
clipsDesc: Les clips sont comme des favoris catégorisés pouvant être partagés. Vous
|
||||
pouvez créer des clips à partir du menu de chaque note.
|
||||
pouvez créer des clips à partir du menu de chaque post.
|
||||
unclip: Dé-clipper
|
||||
secureMode: Mode sécurisé (Authorized Fetch)
|
||||
secureModeInfo: Quand sollicité depuis d'autres serveurs, ne pas répondre sans preuve.
|
||||
|
@ -2174,8 +2175,8 @@ isPatron: Mécène Firefish
|
|||
_filters:
|
||||
fromUser: De l’utilisateur
|
||||
withFile: Avec fichier
|
||||
notesBefore: Notes avant
|
||||
notesAfter: Notes après
|
||||
notesBefore: Posts avant
|
||||
notesAfter: Posts après
|
||||
followersOnly: Abonnés uniquement
|
||||
followingOnly: Abonnements uniquement
|
||||
fromDomain: Du domaine
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
_lang_: "Bahasa Indonesia"
|
||||
headlineFirefish: "Jaringan terhubung melalui catatan"
|
||||
headlineFirefish: "Platform media sosial sumber terbuka dan terdesentralisasi yang
|
||||
merdeka sepenuhnya! 🚀"
|
||||
introFirefish: "Selamat datang! Firefish adalah media sosial sumber terbuka dan terdesentralisasi
|
||||
yang selamanya bebas! 🚀"
|
||||
monthAndDay: "{day} {month}"
|
||||
|
@ -93,7 +94,7 @@ youShouldUpgradeClient: "Untuk melihat halaman ini, mohon muat ulang untuk memut
|
|||
enterListName: "Masukkan nama daftar"
|
||||
privacy: "Privasi"
|
||||
makeFollowManuallyApprove: "Permintaan mengikuti membutuhkan persetujuan"
|
||||
defaultNoteVisibility: "Privasi bawaan catatan"
|
||||
defaultNoteVisibility: "Visibilitas bawaan"
|
||||
follow: "Ikuti"
|
||||
followRequest: "Permintaan Mengikuti"
|
||||
followRequests: "Permintaan mengikuti"
|
||||
|
@ -743,7 +744,7 @@ developer: "Pengembang"
|
|||
makeExplorable: "Buat akun tampil di \"Jelajahi\""
|
||||
makeExplorableDescription: "Jika kamu menonaktifkan ini, akun kamu tidak akan muncul
|
||||
di bagian \"Jelajahi\"."
|
||||
showGapBetweenNotesInTimeline: "Tampilkan jarak diantara catatan pada linimasa"
|
||||
showGapBetweenNotesInTimeline: "Tampilkan jarak diantara postingan pada linimasa"
|
||||
duplicate: "Duplikat"
|
||||
left: "Kiri"
|
||||
center: "Tengah"
|
||||
|
@ -834,7 +835,7 @@ gallery: "Galeri"
|
|||
recentPosts: "Postingan terbaru"
|
||||
popularPosts: "Postingan populer"
|
||||
shareWithNote: "Bagikan dengan postingan"
|
||||
ads: "Iklan"
|
||||
ads: "Spanduk komunitas"
|
||||
expiration: "Batas akhir"
|
||||
memo: "Memo"
|
||||
priority: "Prioritas"
|
||||
|
@ -1245,8 +1246,7 @@ _tutorial:
|
|||
step1_2: "Ayo siapkan. Lekas mulai tanpa basa-basi!"
|
||||
step1_3: "Linimasa kamu kosong, karena kamu belum mencatat catatan apapun atau mengikuti
|
||||
siapapun."
|
||||
step2_1: "Selesaikan menyetel profilmu sebelum menulis sebuah catatan atau mengikuti
|
||||
seseorang."
|
||||
step2_1: "Pertama, isi profilmu lebih dahulu."
|
||||
step2_2: "Menyediakan beberapa informasi tentang siapa kamu akan membuatnya lebih
|
||||
mudah bagi orang lain untuk menentukan jika mereka ingin postinganmu atau mengikutimu."
|
||||
step3_1: "Sekarang saatnya mengikuti beberapa orang!"
|
||||
|
@ -1558,7 +1558,7 @@ _pages:
|
|||
if: "Jika"
|
||||
_if:
|
||||
variable: "Variabel"
|
||||
post: "Buat catatan"
|
||||
post: "Formulir posting"
|
||||
_post:
|
||||
text: "Isi"
|
||||
attachCanvasImage: "Posting dengan kanvas sebagai gambar"
|
||||
|
@ -2011,7 +2011,7 @@ pushNotificationAlreadySubscribed: Pemberitahuan dorong sudah aktif
|
|||
pushNotificationNotSupported: Peramban atau servermu tidak mendukung pemberitahuan
|
||||
dorong
|
||||
apps: Aplikasi
|
||||
showAds: Tampilkan iklan
|
||||
showAds: Tampilkan spanduk komunitas
|
||||
enterSendsMessage: Tekan Enter pada Pesan untuk mengirim pesan (matikan dengan Ctrl
|
||||
+ Enter)
|
||||
showAdminUpdates: Indikasi versi Firefish baru tersedia (hanya admin)
|
||||
|
@ -2157,3 +2157,9 @@ origin: Asal
|
|||
objectStorageS3ForcePathStyle: Gunakan URL titik akhir berbasis lokasi
|
||||
objectStorageS3ForcePathStyleDesc: Aktifkan ini untuk membuat URL titik akhir dalam
|
||||
format 's3.amazonaws.com/<bucket>/' di atas '<bucket>.s3.amazonaws.com'.
|
||||
deletePasskeys: Hapus passkeys
|
||||
inputNotMatch: Masukan tidak cocok
|
||||
delete2fa: Nonaktifkan 2FA
|
||||
delete2faConfirm: Ini akan menghapus 2FA secara permanen pada akun ini. Lanjutkan?
|
||||
deletePasskeysConfirm: Ini akan menghapus semua passkeys dan kunci keamanan pada akun
|
||||
ini secara permanen. Lanjutkan?
|
||||
|
|
|
@ -1076,7 +1076,7 @@ _aboutFirefish:
|
|||
about: "Firefishは、2022年に生まれたThatOneCalculatorによるMisskeyのforkです。"
|
||||
contributors: "主なコントリビューター"
|
||||
allContributors: "全てのコントリビューター"
|
||||
originalMisskeyContributors: "フォーク元のMisskeyの主なコントリビューター"
|
||||
misskeyContributors: "フォーク元のMisskeyの主なコントリビューター"
|
||||
source: "ソースコード"
|
||||
translation: "Firefishを翻訳"
|
||||
donate: "Firefishに寄付"
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "firefish",
|
||||
"version": "1.0.4-dev6",
|
||||
"version": "1.0.4-beta",
|
||||
"codename": "aqua",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
|
@ -22,6 +22,8 @@
|
|||
"dev": "pnpm node ./scripts/dev.js",
|
||||
"dev:staging": "NODE_OPTIONS=--max_old_space_size=3072 NODE_ENV=development pnpm run build && pnpm run start",
|
||||
"lint": "pnpm -r --parallel run lint",
|
||||
"debug": "pnpm run build:debug && pnpm run start",
|
||||
"build:debug": "pnpm -r --parallel run build:debug && pnpm run gulp",
|
||||
"cy:open": "cypress open --browser --e2e --config-file=cypress.config.ts",
|
||||
"cy:run": "cypress run",
|
||||
"e2e": "start-server-and-test start:test http://localhost:61812 cy:run",
|
||||
|
|
|
@ -42,13 +42,15 @@ async fn main() {
|
|||
None => "redis",
|
||||
Some(_) => "rediss",
|
||||
};
|
||||
let redis_uri_userpass = match redis_conf.user {
|
||||
None => "".to_string(),
|
||||
Some(user) => format!("{}:{}@", user, encode(&redis_conf.pass.unwrap_or_default())),
|
||||
};
|
||||
let redis_user = redis_conf.user.unwrap_or("default".to_string());
|
||||
let redis_uri_userpass = format!(
|
||||
"{}:{}",
|
||||
redis_user,
|
||||
encode(&redis_conf.pass.unwrap_or_default())
|
||||
);
|
||||
let redis_uri_hostport = format!("{}:{}", redis_conf.host, redis_conf.port);
|
||||
let redis_uri = format!(
|
||||
"{}://{}{}/{}",
|
||||
"{}://{}@{}/{}",
|
||||
redis_proto, redis_uri_userpass, redis_uri_hostport, redis_conf.db
|
||||
);
|
||||
env::set_var(CACHE_URL_ENV, redis_uri);
|
||||
|
|
|
@ -36,8 +36,8 @@
|
|||
"artifacts": "napi artifacts",
|
||||
"build": "pnpm run build:napi && pnpm run build:migration",
|
||||
"build:napi": "napi build --features napi --platform --release ./built/",
|
||||
"build:migration": "cargo build --locked --release --manifest-path ./migration/Cargo.toml && cp ./target/release/migration ./built/migration",
|
||||
"build:debug": "napi build --platform ./built/ && cargo build --manifest-path ./migration/Cargo.toml",
|
||||
"build:migration": "cargo build --locked --release --manifest-path ./migration/Cargo.toml && cp -v ./target/release/migration ./built/migration",
|
||||
"build:debug": "napi build --features napi --platform ./built/ && cargo build --locked --manifest-path ./migration/Cargo.toml && cp -v ./target/debug/migration ./built/migration",
|
||||
"prepublishOnly": "napi prepublish -t npm",
|
||||
"test": "pnpm run cargo:test && pnpm run build:napi && ava",
|
||||
"universal": "napi universal",
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
"revertmigration:cargo": "./native-utils/built/migration down",
|
||||
"check:connect": "node ./check_connect.js",
|
||||
"build": "pnpm swc src -d built -D",
|
||||
"build:debug": "pnpm swc src -d built -s -D",
|
||||
"watch": "pnpm swc src -d built -D -w",
|
||||
"lint": "pnpm rome check --apply *",
|
||||
"mocha": "cross-env NODE_ENV=test TS_NODE_FILES=true TS_NODE_TRANSPILE_ONLY=true TS_NODE_PROJECT=\"./test/tsconfig.json\" mocha",
|
||||
|
|
|
@ -156,7 +156,7 @@ export function toHtml(
|
|||
|
||||
search(node) {
|
||||
const a = doc.createElement("a");
|
||||
a.href = `https://search.annoyingorange.xyz/search?q=${node.props.query}`;
|
||||
a.href = `/search/${node.props.query}`;
|
||||
a.textContent = node.props.content;
|
||||
return a;
|
||||
},
|
||||
|
|
|
@ -1,16 +1,18 @@
|
|||
export type Post = {
|
||||
text: string | null;
|
||||
text: string | undefined;
|
||||
cw: string | null;
|
||||
localOnly: boolean;
|
||||
createdAt: Date;
|
||||
visibility: string;
|
||||
};
|
||||
|
||||
export function parse(acct: any): Post {
|
||||
return {
|
||||
text: acct.text,
|
||||
text: acct.text || undefined,
|
||||
cw: acct.cw,
|
||||
localOnly: acct.localOnly,
|
||||
createdAt: new Date(acct.createdAt),
|
||||
visibility: "hidden" + (acct.visibility || ""),
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -28,6 +28,7 @@ import {
|
|||
backgroundQueue,
|
||||
} from "./queues.js";
|
||||
import type { ThinUser } from "./types.js";
|
||||
import { Note } from "@/models/entities/note.js";
|
||||
|
||||
function renderError(e: Error): any {
|
||||
return {
|
||||
|
@ -358,6 +359,7 @@ export function createImportCkPostJob(
|
|||
user: ThinUser,
|
||||
post: any,
|
||||
signatureCheck: boolean,
|
||||
parent: Note | null = null,
|
||||
) {
|
||||
return dbQueue.add(
|
||||
"importCkPost",
|
||||
|
@ -365,6 +367,7 @@ export function createImportCkPostJob(
|
|||
user: user,
|
||||
post: post,
|
||||
signatureCheck: signatureCheck,
|
||||
parent: parent,
|
||||
},
|
||||
{
|
||||
removeOnComplete: true,
|
||||
|
|
|
@ -3,7 +3,13 @@ import create from "@/services/note/create.js";
|
|||
import { Users } from "@/models/index.js";
|
||||
import type { DbUserImportMastoPostJobData } from "@/queue/types.js";
|
||||
import { queueLogger } from "../../logger.js";
|
||||
import { uploadFromUrl } from "@/services/drive/upload-from-url.js";
|
||||
import type { DriveFile } from "@/models/entities/drive-file.js";
|
||||
import type Bull from "bull";
|
||||
import { createImportCkPostJob } from "@/queue/index.js";
|
||||
import { Notes, NoteEdits } from "@/models/index.js";
|
||||
import type { Note } from "@/models/entities/note.js";
|
||||
import { genId } from "@/misc/gen-id.js";
|
||||
|
||||
const logger = queueLogger.createSubLogger("import-firefish-post");
|
||||
|
||||
|
@ -17,6 +23,7 @@ export async function importCkPost(
|
|||
return;
|
||||
}
|
||||
const post = job.data.post;
|
||||
/*
|
||||
if (post.replyId != null) {
|
||||
done();
|
||||
return;
|
||||
|
@ -29,23 +36,74 @@ export async function importCkPost(
|
|||
done();
|
||||
return;
|
||||
}
|
||||
const { text, cw, localOnly, createdAt } = Post.parse(post);
|
||||
const note = await create(user, {
|
||||
*/
|
||||
const urls = (post.files || [])
|
||||
.map((x: any) => x.url)
|
||||
.filter((x: String) => x.startsWith("http"));
|
||||
const files: DriveFile[] = [];
|
||||
for (const url of urls) {
|
||||
try {
|
||||
const file = await uploadFromUrl({
|
||||
url: url,
|
||||
user: user,
|
||||
});
|
||||
files.push(file);
|
||||
} catch (e) {
|
||||
logger.error(`Skipped adding file to drive: ${url}`);
|
||||
}
|
||||
}
|
||||
const { text, cw, localOnly, createdAt, visibility } = Post.parse(post);
|
||||
let note = await Notes.findOneBy({
|
||||
createdAt: createdAt,
|
||||
files: undefined,
|
||||
poll: undefined,
|
||||
text: text || undefined,
|
||||
reply: null,
|
||||
renote: null,
|
||||
cw: cw,
|
||||
localOnly,
|
||||
visibility: "hidden",
|
||||
visibleUsers: [],
|
||||
channel: null,
|
||||
apMentions: new Array(0),
|
||||
apHashtags: undefined,
|
||||
apEmojis: undefined,
|
||||
text: text,
|
||||
userId: user.id,
|
||||
});
|
||||
|
||||
if (note && (note?.fileIds?.length || 0) < files.length) {
|
||||
const update: Partial<Note> = {};
|
||||
update.fileIds = files.map((x) => x.id);
|
||||
await Notes.update(note.id, update);
|
||||
await NoteEdits.insert({
|
||||
id: genId(),
|
||||
noteId: note.id,
|
||||
text: note.text || undefined,
|
||||
cw: note.cw,
|
||||
fileIds: note.fileIds,
|
||||
updatedAt: new Date(),
|
||||
});
|
||||
logger.info(`Note file updated`);
|
||||
}
|
||||
if (!note) {
|
||||
note = await create(user, {
|
||||
createdAt: createdAt,
|
||||
files: files.length == 0 ? undefined : files,
|
||||
poll: undefined,
|
||||
text: text || undefined,
|
||||
reply: post.replyId ? job.data.parent : null,
|
||||
renote: post.renoteId ? job.data.parent : null,
|
||||
cw: cw,
|
||||
localOnly,
|
||||
visibility: visibility,
|
||||
visibleUsers: [],
|
||||
channel: null,
|
||||
apMentions: new Array(0),
|
||||
apHashtags: undefined,
|
||||
apEmojis: undefined,
|
||||
});
|
||||
logger.info(`Create new note`);
|
||||
} else {
|
||||
logger.info(`Note exist`);
|
||||
}
|
||||
logger.succ("Imported");
|
||||
if (post.childNotes) {
|
||||
for (const child of post.childNotes) {
|
||||
createImportCkPostJob(
|
||||
job.data.user,
|
||||
child,
|
||||
job.data.signatureCheck,
|
||||
note,
|
||||
);
|
||||
}
|
||||
}
|
||||
done();
|
||||
}
|
||||
|
|
|
@ -8,6 +8,9 @@ import { resolveNote } from "@/remote/activitypub/models/note.js";
|
|||
import { Note } from "@/models/entities/note.js";
|
||||
import { uploadFromUrl } from "@/services/drive/upload-from-url.js";
|
||||
import type { DriveFile } from "@/models/entities/drive-file.js";
|
||||
import { Notes, NoteEdits } from "@/models/index.js";
|
||||
import type { Note } from "@/models/entities/note.js";
|
||||
import { genId } from "@/misc/gen-id.js";
|
||||
|
||||
const logger = queueLogger.createSubLogger("import-masto-post");
|
||||
|
||||
|
@ -67,23 +70,47 @@ export async function importMastoPost(
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
const note = await create(user, {
|
||||
let note = await Notes.findOneBy({
|
||||
createdAt: new Date(post.object.published),
|
||||
files: files.length == 0 ? undefined : files,
|
||||
poll: undefined,
|
||||
text: text || undefined,
|
||||
reply,
|
||||
renote: null,
|
||||
cw: post.object.sensitive ? post.object.summary : undefined,
|
||||
localOnly: false,
|
||||
visibility: "hidden",
|
||||
visibleUsers: [],
|
||||
channel: null,
|
||||
apMentions: new Array(0),
|
||||
apHashtags: undefined,
|
||||
apEmojis: undefined,
|
||||
text: text,
|
||||
userId: user.id,
|
||||
});
|
||||
|
||||
if (note && (note?.fileIds?.length || 0) < files.length) {
|
||||
const update: Partial<Note> = {};
|
||||
update.fileIds = files.map((x) => x.id);
|
||||
await Notes.update(note.id, update);
|
||||
await NoteEdits.insert({
|
||||
id: genId(),
|
||||
noteId: note.id,
|
||||
text: note.text || undefined,
|
||||
cw: note.cw,
|
||||
fileIds: note.fileIds,
|
||||
updatedAt: new Date(),
|
||||
});
|
||||
logger.info(`Note file updated`);
|
||||
}
|
||||
if (!note) {
|
||||
note = await create(user, {
|
||||
createdAt: new Date(post.object.published),
|
||||
files: files.length == 0 ? undefined : files,
|
||||
poll: undefined,
|
||||
text: text || undefined,
|
||||
reply,
|
||||
renote: null,
|
||||
cw: post.object.sensitive ? post.object.summary : undefined,
|
||||
localOnly: false,
|
||||
visibility: "hiddenpublic",
|
||||
visibleUsers: [],
|
||||
channel: null,
|
||||
apMentions: new Array(0),
|
||||
apHashtags: undefined,
|
||||
apEmojis: undefined,
|
||||
});
|
||||
logger.info(`Create new note`);
|
||||
} else {
|
||||
logger.info(`Note exist`);
|
||||
}
|
||||
job.progress(100);
|
||||
done();
|
||||
|
||||
|
|
|
@ -57,7 +57,8 @@ export async function importPosts(
|
|||
const parsed = JSON.parse(json);
|
||||
if (parsed instanceof Array) {
|
||||
logger.info("Parsing key style posts");
|
||||
for (const post of JSON.parse(json)) {
|
||||
const arr = recreateChain(parsed);
|
||||
for (const post of arr) {
|
||||
createImportCkPostJob(job.data.user, post, job.data.signatureCheck);
|
||||
}
|
||||
} else if (parsed instanceof Object) {
|
||||
|
@ -74,3 +75,32 @@ export async function importPosts(
|
|||
logger.succ("Imported");
|
||||
done();
|
||||
}
|
||||
|
||||
function recreateChain(arr: any[]): any {
|
||||
type NotesMap = {
|
||||
[id: string]: any;
|
||||
};
|
||||
const notesTree: any[] = [];
|
||||
const lookup: NotesMap = {};
|
||||
for (const note of arr) {
|
||||
lookup[`${note.id}`] = note;
|
||||
note.childNotes = [];
|
||||
if (note.replyId == null && note.renoteId == null) {
|
||||
notesTree.push(note);
|
||||
}
|
||||
}
|
||||
for (const note of arr) {
|
||||
let parent = null;
|
||||
if (note.replyId != null) {
|
||||
parent = lookup[`${note.replyId}`];
|
||||
}
|
||||
if (note.renoteId != null) {
|
||||
parent = lookup[`${note.renoteId}`];
|
||||
}
|
||||
|
||||
if (parent) {
|
||||
parent.childNotes.push(note);
|
||||
}
|
||||
}
|
||||
return notesTree;
|
||||
}
|
||||
|
|
|
@ -52,6 +52,7 @@ export type DbUserImportMastoPostJobData = {
|
|||
user: ThinUser;
|
||||
post: any;
|
||||
signatureCheck: boolean;
|
||||
parent: Note | null;
|
||||
};
|
||||
|
||||
export type ObjectStorageJobData =
|
||||
|
|
|
@ -27,6 +27,8 @@ export function apiStatusMastodon(router: Router): void {
|
|||
let body: any = ctx.request.body;
|
||||
if (body.in_reply_to_id)
|
||||
body.in_reply_to_id = convertId(body.in_reply_to_id, IdType.FirefishId);
|
||||
if (body.quote_id)
|
||||
body.quote_id = convertId(body.quote_id, IdType.FirefishId);
|
||||
if (
|
||||
(!body.poll && body["poll[options][]"]) ||
|
||||
(!body.media_ids && body["media_ids[]"])
|
||||
|
|
|
@ -18,6 +18,10 @@ export function argsToBools(q: ParsedUrlQuery) {
|
|||
const toBoolean = (value: string) =>
|
||||
!["0", "f", "F", "false", "FALSE", "off", "OFF"].includes(value);
|
||||
|
||||
// Keys taken from:
|
||||
// - https://docs.joinmastodon.org/methods/accounts/#statuses
|
||||
// - https://docs.joinmastodon.org/methods/timelines/#public
|
||||
// - https://docs.joinmastodon.org/methods/timelines/#tag
|
||||
let object: any = q;
|
||||
if (q.only_media)
|
||||
if (typeof q.only_media === "string")
|
||||
|
@ -25,6 +29,13 @@ export function argsToBools(q: ParsedUrlQuery) {
|
|||
if (q.exclude_replies)
|
||||
if (typeof q.exclude_replies === "string")
|
||||
object.exclude_replies = toBoolean(q.exclude_replies);
|
||||
if (q.exclude_reblogs)
|
||||
if (typeof q.exclude_reblogs === "string")
|
||||
object.exclude_reblogs = toBoolean(q.exclude_reblogs);
|
||||
if (q.pinned)
|
||||
if (typeof q.pinned === "string") object.pinned = toBoolean(q.pinned);
|
||||
if (q.local)
|
||||
if (typeof q.local === "string") object.local = toBoolean(q.local);
|
||||
return q;
|
||||
}
|
||||
|
||||
|
|
221
packages/backend/src/server/file/byte-range-readable.ts
Normal file
221
packages/backend/src/server/file/byte-range-readable.ts
Normal file
|
@ -0,0 +1,221 @@
|
|||
import { Readable, ReadableOptions } from "node:stream";
|
||||
import { Buffer, constants as BufferConstants } from "node:buffer";
|
||||
import * as fs from "node:fs";
|
||||
|
||||
interface ByteRange {
|
||||
start: bigint;
|
||||
end: bigint;
|
||||
size: bigint;
|
||||
}
|
||||
|
||||
const BOUNDARY_CHARS =
|
||||
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
|
||||
const BYTERANGE_SPEC_REGEX = /^bytes=(.+)$/;
|
||||
const BYTERANGE_REGEX = /(\d*)-(\d*)/;
|
||||
|
||||
const BIGINT_0 = BigInt(0);
|
||||
const BIGINT_1 = BigInt(1);
|
||||
const BOUNDARY_SIZE = 40;
|
||||
|
||||
function extractRanges(
|
||||
fileSize: bigint,
|
||||
maxByteRanges: number,
|
||||
rangeHeaderValue: string,
|
||||
): ByteRange[] {
|
||||
const ranges: ByteRange[] = [];
|
||||
|
||||
if (!rangeHeaderValue) return ranges;
|
||||
|
||||
const rangeSpecMatch = rangeHeaderValue.match(BYTERANGE_SPEC_REGEX);
|
||||
if (!rangeSpecMatch) return [];
|
||||
|
||||
const rangeSpecs = rangeSpecMatch[1].split(",");
|
||||
for (let i = 0; i < rangeSpecs.length; i = i + 1) {
|
||||
const byteRange = rangeSpecs[i].match(BYTERANGE_REGEX);
|
||||
if (!byteRange) return [];
|
||||
|
||||
let start: bigint;
|
||||
let end: bigint;
|
||||
let size: bigint;
|
||||
|
||||
if (byteRange[1]) {
|
||||
start = BigInt(byteRange[1]);
|
||||
}
|
||||
|
||||
if (byteRange[2]) {
|
||||
end = BigInt(byteRange[2]);
|
||||
}
|
||||
|
||||
if (start === undefined && end === undefined) {
|
||||
/* some invalid range like bytes=- */
|
||||
return [];
|
||||
}
|
||||
|
||||
if (start === undefined) {
|
||||
/* end-of-file range like -500 */
|
||||
start = fileSize - end;
|
||||
end = fileSize - BIGINT_1;
|
||||
if (start < BIGINT_0) return []; /* range larger than file, return */
|
||||
}
|
||||
|
||||
if (end === undefined) {
|
||||
/* range like 0- */
|
||||
end = fileSize - BIGINT_1;
|
||||
}
|
||||
|
||||
if (start > end || end >= fileSize) {
|
||||
/* return empty range to issue regular 200 */
|
||||
return [];
|
||||
}
|
||||
size = end - start + BIGINT_1;
|
||||
|
||||
if (1 > maxByteRanges - ranges.length) return [];
|
||||
|
||||
ranges.push({
|
||||
start: start,
|
||||
end: end,
|
||||
size: size,
|
||||
});
|
||||
}
|
||||
|
||||
return ranges;
|
||||
}
|
||||
|
||||
function createBoundary(len: number): string {
|
||||
let chars = [];
|
||||
for (let i = 0; i < len; i = i + 1) {
|
||||
chars[i] = BOUNDARY_CHARS.charAt(
|
||||
Math.floor(Math.random() * BOUNDARY_CHARS.length),
|
||||
);
|
||||
}
|
||||
return chars.join("");
|
||||
}
|
||||
|
||||
class ByteRangeReadable extends Readable {
|
||||
size: bigint; /* the total size in bytes */
|
||||
boundary: string; /* boundary marker to use in multipart headers */
|
||||
|
||||
private fd: number;
|
||||
private ranges: ByteRange[];
|
||||
private index: number; /* index within ranges */
|
||||
private position: bigint;
|
||||
private end: bigint;
|
||||
private contentType: string;
|
||||
private fileSize: bigint;
|
||||
private headers: Buffer[];
|
||||
private trailer: Buffer;
|
||||
|
||||
static parseByteRanges(
|
||||
fileSize: bigint,
|
||||
maxByteRanges: number,
|
||||
rangeHeaderValue?: string,
|
||||
): ByteRange[] {
|
||||
return extractRanges(fileSize, maxByteRanges, rangeHeaderValue);
|
||||
}
|
||||
|
||||
private createPartHeader(range: ByteRange): Buffer {
|
||||
return Buffer.from(
|
||||
[
|
||||
"",
|
||||
`--${this.boundary}`,
|
||||
`Content-Type: ${this.contentType}`,
|
||||
`Content-Range: bytes ${range.start}-${range.end}/${this.fileSize}`,
|
||||
"",
|
||||
"",
|
||||
].join("\r\n"),
|
||||
);
|
||||
}
|
||||
|
||||
constructor(
|
||||
fd: number,
|
||||
fileSize: bigint,
|
||||
ranges: ByteRange[],
|
||||
contentType: string,
|
||||
opts?: ReadableOptions,
|
||||
) {
|
||||
super(opts);
|
||||
|
||||
if (ranges.length === 0) {
|
||||
throw Error("this requires at least 1 byte range");
|
||||
}
|
||||
|
||||
this.fd = fd;
|
||||
this.ranges = ranges;
|
||||
this.fileSize = fileSize;
|
||||
this.contentType = contentType;
|
||||
|
||||
this.position = BIGINT_1;
|
||||
this.end = BIGINT_0;
|
||||
this.index = -1;
|
||||
this.headers = [];
|
||||
|
||||
this.size = BIGINT_0;
|
||||
|
||||
if (this.ranges.length === 1) {
|
||||
this.size = this.ranges[0].size;
|
||||
} else {
|
||||
this.boundary = createBoundary(BOUNDARY_SIZE);
|
||||
this.ranges.forEach((r) => {
|
||||
const header = this.createPartHeader(r);
|
||||
this.headers.push(header);
|
||||
|
||||
this.size += BigInt(header.length) + r.size;
|
||||
});
|
||||
this.trailer = Buffer.from(`\r\n--${this.boundary}--\r\n`);
|
||||
this.size += BigInt(this.trailer.length);
|
||||
}
|
||||
}
|
||||
|
||||
_read(n) {
|
||||
if (this.index == this.ranges.length) {
|
||||
this.push(null);
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.position > this.end) {
|
||||
/* move ahead to the next index */
|
||||
this.index++;
|
||||
|
||||
if (this.index === this.ranges.length) {
|
||||
if (this.trailer) {
|
||||
this.push(this.trailer);
|
||||
return;
|
||||
}
|
||||
this.push(null);
|
||||
return;
|
||||
}
|
||||
|
||||
this.position = this.ranges[this.index].start;
|
||||
this.end = this.ranges[this.index].end;
|
||||
|
||||
if (this.ranges.length > 1) {
|
||||
this.push(this.headers[this.index]);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
const max = this.end - this.position + BIGINT_1;
|
||||
|
||||
if (n > max) n = Number(max);
|
||||
const buf = Buffer.alloc(n);
|
||||
|
||||
fs.read(this.fd, buf, 0, n, this.position, (err, bytesRead) => {
|
||||
if (err) {
|
||||
this.destroy(err);
|
||||
return;
|
||||
}
|
||||
if (bytesRead == 0) {
|
||||
/* something seems to have gone wrong? */
|
||||
this.push(null);
|
||||
return;
|
||||
}
|
||||
|
||||
if (bytesRead > n) bytesRead = n;
|
||||
|
||||
this.position += BigInt(bytesRead);
|
||||
this.push(buf.slice(0, bytesRead));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export { ByteRange, ByteRangeReadable };
|
|
@ -14,6 +14,7 @@ import { detectType } from "@/misc/get-file-info.js";
|
|||
import { convertToWebp } from "@/services/drive/image-processor.js";
|
||||
import { GenerateVideoThumbnail } from "@/services/drive/generate-video-thumbnail.js";
|
||||
import { StatusError } from "@/misc/fetch.js";
|
||||
import { ByteRangeReadable } from "./byte-range-readable.js";
|
||||
import { FILE_TYPE_BROWSERSAFE } from "@/const.js";
|
||||
|
||||
const _filename = fileURLToPath(import.meta.url);
|
||||
|
@ -21,6 +22,8 @@ const _dirname = dirname(_filename);
|
|||
|
||||
const assets = `${_dirname}/../../server/file/assets/`;
|
||||
|
||||
const MAX_BYTE_RANGES = 10;
|
||||
|
||||
const commonReadableHandlerGenerator =
|
||||
(ctx: Koa.Context) => (e: Error): void => {
|
||||
serverLogger.error(e);
|
||||
|
@ -122,31 +125,88 @@ export default async function (ctx: Koa.Context) {
|
|||
return;
|
||||
}
|
||||
|
||||
let contentType;
|
||||
let filename;
|
||||
let fileHandle;
|
||||
|
||||
if (isThumbnail || isWebpublic) {
|
||||
const { mime, ext } = await detectType(InternalStorage.resolvePath(key));
|
||||
const filename = rename(file.name, {
|
||||
suffix: isThumbnail ? "-thumb" : "-web",
|
||||
extname: ext ? `.${ext}` : undefined,
|
||||
}).toString();
|
||||
(contentType = FILE_TYPE_BROWSERSAFE.includes(mime)
|
||||
? mime
|
||||
: "application/octet-stream"),
|
||||
(filename = rename(file.name, {
|
||||
suffix: isThumbnail ? "-thumb" : "-web",
|
||||
extname: ext ? `.${ext}` : undefined,
|
||||
}).toString());
|
||||
|
||||
ctx.body = InternalStorage.read(key);
|
||||
ctx.set(
|
||||
"Content-Type",
|
||||
FILE_TYPE_BROWSERSAFE.includes(mime) ? mime : "application/octet-stream",
|
||||
);
|
||||
ctx.set("Cache-Control", "max-age=31536000, immutable");
|
||||
ctx.set("Content-Disposition", contentDisposition("inline", filename));
|
||||
fileHandle = await InternalStorage.open(key, "r");
|
||||
} else {
|
||||
const readable = InternalStorage.read(file.accessKey!);
|
||||
readable.on("error", commonReadableHandlerGenerator(ctx));
|
||||
ctx.body = readable;
|
||||
ctx.set(
|
||||
"Content-Type",
|
||||
FILE_TYPE_BROWSERSAFE.includes(file.type)
|
||||
? file.type
|
||||
: "application/octet-stream",
|
||||
);
|
||||
ctx.set("Cache-Control", "max-age=31536000, immutable");
|
||||
ctx.set("Content-Disposition", contentDisposition("inline", file.name));
|
||||
(contentType = FILE_TYPE_BROWSERSAFE.includes(file.type)
|
||||
? file.type
|
||||
: "application/octet-stream"),
|
||||
(filename = file.name);
|
||||
fileHandle = await InternalStorage.open(file.accessKey!, "r");
|
||||
}
|
||||
|
||||
// We can let Koa evaluate conditionals by setting
|
||||
// the status to 200, along with the lastModified
|
||||
// and etag properties, then checking ctx.fresh.
|
||||
// Additionally, Range is ignored if a conditional GET would
|
||||
// result in a 304 response, so we can return early here.
|
||||
|
||||
ctx.status = 200;
|
||||
ctx.etag = file.md5;
|
||||
ctx.lastModified = file.createdAt;
|
||||
|
||||
// When doing a conditional request, we MUST return a "Cache-Control" header
|
||||
// if a normal 200 response would have included.
|
||||
ctx.set("Cache-Control", "max-age=31536000, immutable");
|
||||
|
||||
if (ctx.fresh) {
|
||||
ctx.status = 304;
|
||||
return;
|
||||
}
|
||||
|
||||
ctx.length = file.size;
|
||||
ctx.set("Content-Disposition", contentDisposition("inline", filename));
|
||||
ctx.set("Content-Type", contentType);
|
||||
|
||||
const ranges = ByteRangeReadable.parseByteRanges(
|
||||
BigInt(file.size),
|
||||
MAX_BYTE_RANGES,
|
||||
ctx.headers["range"],
|
||||
);
|
||||
const readable =
|
||||
ranges.length === 0
|
||||
? fileHandle.createReadStream()
|
||||
: new ByteRangeReadable(
|
||||
fileHandle.fd,
|
||||
BigInt(file.size),
|
||||
ranges,
|
||||
contentType,
|
||||
);
|
||||
readable.on("error", commonReadableHandlerGenerator(ctx));
|
||||
ctx.body = readable;
|
||||
|
||||
if (ranges.length === 0) {
|
||||
ctx.set("Accept-Ranges", "bytes");
|
||||
} else {
|
||||
ctx.status = 206;
|
||||
ctx.length = readable.size;
|
||||
readable.on("close", async () => {
|
||||
await fileHandle.close();
|
||||
});
|
||||
|
||||
if (ranges.length === 1) {
|
||||
ctx.set(
|
||||
"Content-Range",
|
||||
`bytes ${ranges[0].start}-${ranges[0].end}/${file.size}`,
|
||||
);
|
||||
} else {
|
||||
ctx.set(
|
||||
"Content-Type",
|
||||
`multipart/byteranges; boundary=${readable.boundary}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import * as fs from "node:fs";
|
||||
import * as fsPromises from "node:fs/promises";
|
||||
import * as Path from "node:path";
|
||||
import { fileURLToPath } from "node:url";
|
||||
import { dirname } from "node:path";
|
||||
|
@ -13,6 +14,10 @@ export class InternalStorage {
|
|||
public static resolvePath = (key: string) =>
|
||||
Path.resolve(InternalStorage.path, key);
|
||||
|
||||
public static open(key: string, flags: string) {
|
||||
return fsPromises.open(InternalStorage.resolvePath(key), flags);
|
||||
}
|
||||
|
||||
public static read(key: string) {
|
||||
return fs.createReadStream(InternalStorage.resolvePath(key));
|
||||
}
|
||||
|
|
|
@ -6,10 +6,13 @@ async function getRelMeLinks(url: string): Promise<string[]> {
|
|||
try {
|
||||
const html = await getHtml(url);
|
||||
const dom = new JSDOM(html);
|
||||
const relMeLinks = [
|
||||
...dom.window.document.querySelectorAll("a[rel='me']"),
|
||||
...dom.window.document.querySelectorAll("link[rel='me']"),
|
||||
].map((a) => (a as HTMLAnchorElement | HTMLLinkElement).href);
|
||||
const allLinks = [...dom.window.document.querySelectorAll("a, link")];
|
||||
const relMeLinks = allLinks
|
||||
.filter((a) => {
|
||||
const relAttribute = a.getAttribute("rel");
|
||||
return relAttribute ? relAttribute.split(" ").includes("me") : false;
|
||||
})
|
||||
.map((a) => (a as HTMLAnchorElement | HTMLLinkElement).href);
|
||||
return relMeLinks;
|
||||
} catch {
|
||||
return [];
|
||||
|
|
|
@ -172,7 +172,7 @@ export default async (
|
|||
// rome-ignore lint/suspicious/noAsyncPromiseExecutor: FIXME
|
||||
new Promise<Note>(async (res, rej) => {
|
||||
const dontFederateInitially =
|
||||
data.localOnly || data.visibility === "hidden";
|
||||
data.localOnly || data.visibility?.startsWith("hidden");
|
||||
|
||||
// If you reply outside the channel, match the scope of the target.
|
||||
// TODO (I think it's a process that could be done on the client side, but it's server side for now.)
|
||||
|
@ -206,7 +206,8 @@ export default async (
|
|||
if (data.channel != null) data.visibility = "public";
|
||||
if (data.channel != null) data.visibleUsers = [];
|
||||
if (data.channel != null) data.localOnly = true;
|
||||
if (data.visibility === "hidden") data.visibility = "public";
|
||||
if (data.visibility.startsWith("hidden"))
|
||||
data.visibility = data.visibility.slice(6);
|
||||
|
||||
// enforce silent clients on server
|
||||
if (
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
"scripts": {
|
||||
"watch": "pnpm vite build --watch --mode development",
|
||||
"build": "pnpm vite build",
|
||||
"build:debug": "pnpm run build",
|
||||
"lint": "pnpm rome check **/*.ts --apply && pnpm run lint:vue",
|
||||
"lint:vue": "pnpm paralint --ext .vue --fix '**/*.vue' --cache",
|
||||
"format": "pnpm rome format * --write && pnpm prettier --write '**/*.{scss,vue}' --cache --cache-strategy metadata"
|
||||
|
|
|
@ -132,7 +132,7 @@ export default defineComponent({
|
|||
display: none;
|
||||
}
|
||||
|
||||
> *:not(:last-child) {
|
||||
&:not(.date-separated-list-nogap) > *:not(:last-child) {
|
||||
margin-bottom: var(--margin);
|
||||
}
|
||||
|
||||
|
|
|
@ -11,6 +11,9 @@
|
|||
<script lang="ts" setup>
|
||||
import { ref } from "vue";
|
||||
import { i18n } from "@/i18n";
|
||||
import { useRouter } from "@/router";
|
||||
|
||||
const router = useRouter();
|
||||
|
||||
const props = defineProps<{
|
||||
q: string;
|
||||
|
@ -19,10 +22,7 @@ const props = defineProps<{
|
|||
const query = ref(props.q);
|
||||
|
||||
const search = () => {
|
||||
window.open(
|
||||
`https://search.annoyingorange.xyz/search?q=${query.value}`,
|
||||
"_blank",
|
||||
);
|
||||
router.push(`/search/${query.value}`);
|
||||
};
|
||||
</script>
|
||||
|
||||
|
|
|
@ -45,14 +45,17 @@ const instance = props.instance ?? {
|
|||
const commonNames = new Map<string, string>([
|
||||
["birdsitelive", "BirdsiteLIVE"],
|
||||
["bookwyrm", "BookWyrm"],
|
||||
["bridgy-fed", "Bridgy Fed"],
|
||||
["foundkey", "FoundKey"],
|
||||
["gnusocial", "GNU social"],
|
||||
["gnusocial", "GNU Social"],
|
||||
["gotosocial", "GoToSocial"],
|
||||
["microblogpub", "microblog.pub"],
|
||||
["nextcloud social", "Nextcloud Social"],
|
||||
["peertube", "PeerTube"],
|
||||
["snac", "snac"],
|
||||
["snac2", "snac2"],
|
||||
["takahe", "Takahē"],
|
||||
["wafrn", "WAFRN"],
|
||||
["wordpress", "WordPress"],
|
||||
["writefreely", "WriteFreely"],
|
||||
["wxwclub", "wxwClub"],
|
||||
|
|
|
@ -53,6 +53,7 @@
|
|||
:aria-label="media.comment"
|
||||
preload="none"
|
||||
controls
|
||||
playsinline
|
||||
@contextmenu.stop
|
||||
>
|
||||
<source :src="media.url" :type="mediaType" />
|
||||
|
|
|
@ -106,31 +106,26 @@
|
|||
:text="'@namekuji@firefish.social (Backend)'"
|
||||
/></FormLink>
|
||||
<FormLink to="/@dev@post.naskya.net"
|
||||
><Mfm :text="'@dev@post.naskya.net (Backend)'"
|
||||
><Mfm :text="'@dev@post.naskya.net (Fullstack)'"
|
||||
/></FormLink>
|
||||
<FormLink to="/@panos@firefish.social"
|
||||
><Mfm
|
||||
:text="'@panos@firefish.social (Project Coordinator)'"
|
||||
/></FormLink>
|
||||
<FormLink
|
||||
to="https://www.youtube.com/c/Henkiwashere"
|
||||
external
|
||||
>Henki (error images artist)</FormLink
|
||||
>
|
||||
<FormLink to="/@blackspike@mastodon.cloud"
|
||||
><Mfm
|
||||
:text="'@blackspike@mastodon.cloud (Logo Design)'"
|
||||
/></FormLink>
|
||||
</div>
|
||||
<template #caption
|
||||
><MkLink
|
||||
url="https://git.joinfirefish.org/firefish/firefish/activity"
|
||||
>{{
|
||||
i18n.ts._aboutFirefish.allContributors
|
||||
}}</MkLink
|
||||
></template
|
||||
<h3
|
||||
style="
|
||||
font-weight: 700;
|
||||
margin: 1.5em 0 16px;
|
||||
font-size: 1em;
|
||||
"
|
||||
>
|
||||
</FormSection>
|
||||
<FormSection>
|
||||
<template #label>{{
|
||||
i18n.ts._aboutFirefish.originalMisskeyContributors
|
||||
}}</template>
|
||||
{{ i18n.ts._aboutFirefish.misskeyContributors }}
|
||||
</h3>
|
||||
<div class="_formLinks">
|
||||
<FormLink to="/@syuilo@misskey.io"
|
||||
><Mfm :text="'@syuilo@misskey.io'"
|
||||
|
@ -151,6 +146,12 @@
|
|||
><Mfm :text="'@robflop@misskey.io'"
|
||||
/></FormLink>
|
||||
</div>
|
||||
<h3>
|
||||
<MkLink
|
||||
url="https://git.joinfirefish.org/firefish/firefish/activity"
|
||||
>{{ i18n.ts._aboutFirefish.allContributors }}
|
||||
</MkLink>
|
||||
</h3>
|
||||
</FormSection>
|
||||
<FormSection>
|
||||
<template #label
|
||||
|
|
|
@ -218,6 +218,7 @@ definePageMetadata(
|
|||
> .users {
|
||||
> .inputs {
|
||||
display: flex;
|
||||
gap: 0.4rem;
|
||||
margin-bottom: 16px;
|
||||
|
||||
> * {
|
||||
|
|
|
@ -5,14 +5,15 @@
|
|||
/></template>
|
||||
<MkSpacer :content-max="800">
|
||||
<MkPagination
|
||||
ref="paginationEl"
|
||||
v-slot="{ items }"
|
||||
:pagination="pagination"
|
||||
class="ruryvtyk _content"
|
||||
class="ruryvtyk _gaps_m"
|
||||
>
|
||||
<section
|
||||
v-for="(announcement, i) in items"
|
||||
v-for="announcement in items"
|
||||
:key="announcement.id"
|
||||
class="_card announcement"
|
||||
class="announcement _panel"
|
||||
>
|
||||
<div class="_title">
|
||||
<span v-if="$i && !announcement.isRead">🆕 </span>
|
||||
|
@ -31,7 +32,7 @@
|
|||
/>
|
||||
</div>
|
||||
<div v-if="$i && !announcement.isRead" class="_footer">
|
||||
<MkButton primary @click="read(items, announcement, i)"
|
||||
<MkButton primary @click="read(announcement.id)"
|
||||
><i class="ph-check ph-bold ph-lg"></i>
|
||||
{{ i18n.ts.gotIt }}</MkButton
|
||||
>
|
||||
|
@ -43,7 +44,7 @@
|
|||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import {} from "vue";
|
||||
import { ref } from "vue";
|
||||
import MkPagination from "@/components/MkPagination.vue";
|
||||
import MkButton from "@/components/MkButton.vue";
|
||||
import * as os from "@/os";
|
||||
|
@ -55,13 +56,14 @@ const pagination = {
|
|||
limit: 10,
|
||||
};
|
||||
|
||||
// TODO: これは実質的に親コンポーネントから子コンポーネントのプロパティを変更してるのでなんとかしたい
|
||||
function read(items, announcement, i) {
|
||||
items[i] = {
|
||||
...announcement,
|
||||
isRead: true,
|
||||
};
|
||||
os.api("i/read-announcement", { announcementId: announcement.id });
|
||||
const paginationEl = ref<InstanceType<typeof MkPagination>>();
|
||||
function read(id: string) {
|
||||
if (!paginationEl.value) return;
|
||||
paginationEl.value.updateItem(id, (announcement) => {
|
||||
announcement.isRead = true;
|
||||
return announcement;
|
||||
});
|
||||
os.api("i/read-announcement", { announcementId: id });
|
||||
}
|
||||
|
||||
const headerActions = $computed(() => []);
|
||||
|
|
|
@ -19,21 +19,21 @@ import { i18n } from "@/i18n";
|
|||
|
||||
const paginationForLocal = {
|
||||
endpoint: "notes/featured" as const,
|
||||
limit: 10,
|
||||
limit: 15,
|
||||
origin: "local",
|
||||
offsetMode: true,
|
||||
params: {
|
||||
days: 14,
|
||||
days: 5,
|
||||
},
|
||||
};
|
||||
|
||||
const paginationForRemote = {
|
||||
endpoint: "notes/featured" as const,
|
||||
limit: 20,
|
||||
limit: 15,
|
||||
offsetMode: true,
|
||||
params: {
|
||||
origin: "remote",
|
||||
days: 7,
|
||||
days: 5,
|
||||
},
|
||||
};
|
||||
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
:threshold="10"
|
||||
:centeredSlides="true"
|
||||
:modules="[Virtual]"
|
||||
:space-between="20"
|
||||
:space-between="30"
|
||||
:virtual="true"
|
||||
:allow-touch-move="
|
||||
defaultStore.state.swipeOnMobile &&
|
||||
|
|
|
@ -130,6 +130,12 @@
|
|||
@update:modelValue="save()"
|
||||
>{{ i18n.ts.keepCw }}</FormSwitch
|
||||
>
|
||||
<FormSwitch
|
||||
v-model="addRe"
|
||||
class="_formBlock"
|
||||
@update:modelValue="save()"
|
||||
>{{ i18n.ts.addRe }}
|
||||
</FormSwitch>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
@ -164,6 +170,7 @@ let rememberNoteVisibility = $computed(
|
|||
defaultStore.makeGetterSetter("rememberNoteVisibility"),
|
||||
);
|
||||
let keepCw = $computed(defaultStore.makeGetterSetter("keepCw"));
|
||||
let addRe = $computed(defaultStore.makeGetterSetter("addRe"));
|
||||
|
||||
function save() {
|
||||
os.api("i/update", {
|
||||
|
|
|
@ -127,8 +127,8 @@
|
|||
</FormFolder>
|
||||
<template #caption>{{
|
||||
i18n.t("_profile.metadataDescription", {
|
||||
a: "\<code\>\<a\>\</code\>",
|
||||
l: "\<code\>\<a\>\</code\>",
|
||||
a: "\<a\>",
|
||||
l: "\<a\>",
|
||||
rel: `rel="me" href="https://${host}/@${$i.username}"`,
|
||||
})
|
||||
}}</template>
|
||||
|
|
|
@ -219,7 +219,7 @@
|
|||
{{ i18n.ts.sendModMail }}</FormButton
|
||||
>
|
||||
<FormButton
|
||||
v-if="$i.isAdmin"
|
||||
v-if="user.host == null && $i.isAdmin"
|
||||
inline
|
||||
danger
|
||||
@click="delete2fa"
|
||||
|
@ -227,7 +227,7 @@
|
|||
{{ i18n.ts.delete2fa }}</FormButton
|
||||
>
|
||||
<FormButton
|
||||
v-if="$i.isAdmin"
|
||||
v-if="user.host == null && $i.isAdmin"
|
||||
inline
|
||||
danger
|
||||
@click="deletePasskeys"
|
||||
|
|
|
@ -87,17 +87,13 @@
|
|||
v-if="user.isAdmin"
|
||||
v-tooltip.noDelay="i18n.ts.isAdmin"
|
||||
style="color: var(--badge)"
|
||||
><i
|
||||
class="ph-bookmark-simple ph-fill ph-lg"
|
||||
></i
|
||||
><i class="ph-crown ph-bold ph-lg"></i
|
||||
></span>
|
||||
<span
|
||||
v-if="!user.isAdmin && user.isModerator"
|
||||
v-tooltip.noDelay="i18n.ts.isModerator"
|
||||
style="color: var(--badge)"
|
||||
><i
|
||||
class="ph-bookmark-simple ph-bold ph-lg"
|
||||
></i
|
||||
><i class="ph-gavel ph-bold ph-lg"></i
|
||||
></span>
|
||||
<span
|
||||
v-if="user.isLocked"
|
||||
|
@ -176,9 +172,7 @@
|
|||
v-if="user.isAdmin"
|
||||
v-tooltip.noDelay="i18n.ts.isAdmin"
|
||||
style="color: var(--badge)"
|
||||
><i
|
||||
class="ph-bookmark-simple ph-fill ph-lg"
|
||||
></i
|
||||
><i class="ph-crown ph-bold ph-lg"></i
|
||||
></span>
|
||||
<span
|
||||
v-if="!user.isAdmin && user.isModerator"
|
||||
|
@ -187,9 +181,7 @@
|
|||
color: var(--badge);
|
||||
margin-left: 0.5rem;
|
||||
"
|
||||
><i
|
||||
class="ph-bookmark-simple ph-bold ph-lg"
|
||||
></i
|
||||
><i class="ph-gavel ph-bold ph-lg"></i
|
||||
></span>
|
||||
<span
|
||||
v-if="user.isLocked"
|
||||
|
|
|
@ -46,6 +46,8 @@ html {
|
|||
tab-size: 2;
|
||||
scroll-padding: 60px;
|
||||
overflow-x: clip;
|
||||
text-size-adjust: none;
|
||||
-webkit-text-size-adjust: none;
|
||||
|
||||
&.useCJKFont {
|
||||
font-family: "Hiragino Maru Gothic Pro", "BIZ UDGothic", Roboto,
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
"types": "./built/index.d.ts",
|
||||
"scripts": {
|
||||
"build": "pnpm swc src -d built -D",
|
||||
"build:debug": "pnpm swc src -d built -s -D",
|
||||
"render": "pnpm run build && pnpm run api && pnpm run api-prod && cp temp/firefish-js.api.json etc/ && pnpm run api-doc",
|
||||
"tsd": "tsc && tsd",
|
||||
"api": "pnpm api-extractor run --local --verbose",
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
"typings": "./lib/src/index.d.ts",
|
||||
"scripts": {
|
||||
"build": "tsc -p ./",
|
||||
"build:debug": "pnpm run build",
|
||||
"lint": "pnpm rome check **/*.ts --apply",
|
||||
"format": "pnpm rome format --write src/**/*.ts",
|
||||
"doc": "typedoc --out ../docs ./src",
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
"private": true,
|
||||
"scripts": {
|
||||
"build": "webpack",
|
||||
"build:debug": "pnpm run build",
|
||||
"watch": "pnpm swc src -d built -D -w",
|
||||
"lint": "pnpm rome check **/*.ts --apply",
|
||||
"format": "pnpm rome format * --write"
|
||||
|
|
82
patrons.json
82
patrons.json
|
@ -1,13 +1,13 @@
|
|||
{
|
||||
"patrons": [
|
||||
"@atomicpoet@calckey.social",
|
||||
"@atomicpoet@firefish.social",
|
||||
"@shoq@mastodon.social",
|
||||
"@pikadude@erisly.social",
|
||||
"@sage@stop.voring.me",
|
||||
"@sky@therian.club",
|
||||
"@panos@electricrequiem.com",
|
||||
"@redhunt07@www.foxyhole.io",
|
||||
"@griff@calckey.social",
|
||||
"@griff@firefish.social",
|
||||
"@cafkafk@ck.cafkafk.com",
|
||||
"@privateger@plasmatrap.com",
|
||||
"@effye@toot.thoughtworks.com",
|
||||
|
@ -17,56 +17,56 @@
|
|||
"@topher@mastodon.online",
|
||||
"@hanicef@stop.voring.me",
|
||||
"@nmkj@calckey.jp",
|
||||
"@unattributed@calckey.social",
|
||||
"@unattributed@firefish.social",
|
||||
"@cody@misskey.codingneko.com",
|
||||
"@kate@blahaj.zone",
|
||||
"@emtk@mkkey.net",
|
||||
"@jovikowi@calckey.social",
|
||||
"@padraig@calckey.social",
|
||||
"@jovikowi@firefish.social",
|
||||
"@padraig@firefish.social",
|
||||
"@pancakes@cats.city",
|
||||
"@theresmiling@calckey.social",
|
||||
"@kristian@calckey.social",
|
||||
"@theresmiling@firefish.social",
|
||||
"@kristian@firefish.social",
|
||||
"@jo@blahaj.zone",
|
||||
"@narF@calckey.social",
|
||||
"@narF@firefish.social",
|
||||
"@AlderForrest@raining.anvil.top",
|
||||
"@box464@calckey.social",
|
||||
"@MariaTheMartian@calckey.social",
|
||||
"@nisemikol@calckey.social",
|
||||
"@box464@firefish.social",
|
||||
"@MariaTheMartian@firefish.social",
|
||||
"@nisemikol@firefish.social",
|
||||
"@smallpatatas@blahaj.zone",
|
||||
"@bayra@stop.voring.me",
|
||||
"@frost@wolfdo.gg",
|
||||
"@joebiden@fuckgov.org",
|
||||
"@nyaa@calckey.social",
|
||||
"@Dan@calckey.social",
|
||||
"@dana@calckey.social",
|
||||
"@Jdreben@calckey.social",
|
||||
"@nyaa@firefish.social",
|
||||
"@Dan@firefish.social",
|
||||
"@dana@firefish.social",
|
||||
"@Jdreben@firefish.social",
|
||||
"@natalie@prismst.one",
|
||||
"@KelsonV@wandering.shop",
|
||||
"@breakfastmtn@calckey.social",
|
||||
"@breakfastmtn@firefish.social",
|
||||
"@richardazia@mastodon.social",
|
||||
"@joestone@calckey.social",
|
||||
"@aj@calckey.social",
|
||||
"@joestone@firefish.social",
|
||||
"@aj@firefish.social",
|
||||
"@zepfanman@ramblingreaders.org",
|
||||
"@kimby@stop.voring.me",
|
||||
"@fyrfli@fyrfli.social",
|
||||
"@riversidebryan@firefish.lgbt",
|
||||
"@aRubes@sloth.run",
|
||||
"@andreasdotorg@calckey.social",
|
||||
"@andreasdotorg@firefish.social",
|
||||
"@ozzy@calckey.online",
|
||||
"@leni@windycity.style",
|
||||
"@mhzmodels@calckey.art",
|
||||
"@ReflexVE@calckey.social",
|
||||
"@mark@calckey.social",
|
||||
"@ReflexVE@firefish.social",
|
||||
"@mark@firefish.social",
|
||||
"@skyizwhite@himagine.club",
|
||||
"@Uwu@calckey.social",
|
||||
"@jGoose@calckey.social",
|
||||
"@Uwu@firefish.social",
|
||||
"@jGoose@firefish.social",
|
||||
"@kunev@blewsky.social",
|
||||
"@Simoto@electricrequiem.com",
|
||||
"@Evoterra@calckey.social",
|
||||
"@Evoterra@firefish.social",
|
||||
"@LauraLangdon@procial.tchncs.de",
|
||||
"@mho@social.heise.de",
|
||||
"@richardazia@calckey.social",
|
||||
"@blues653@calckey.social",
|
||||
"@richardazia@firefish.social",
|
||||
"@blues653@firefish.social",
|
||||
"@rafale_blue@calc.04.si",
|
||||
"@esm@lethallava.land",
|
||||
"@vmstan@vmst.io",
|
||||
|
@ -74,33 +74,33 @@
|
|||
"@renere@distance.blue",
|
||||
"@theking@kitsunes.club",
|
||||
"@toof@fedi.toofie.net",
|
||||
"@Punko@calckey.social",
|
||||
"@joesbrat67@calckey.social",
|
||||
"@arth@calckey.social",
|
||||
"@Punko@firefish.social",
|
||||
"@joesbrat67@firefish.social",
|
||||
"@arth@firefish.social",
|
||||
"@octofloofy@ck.octofloofy.ink",
|
||||
"@pauliehedron@infosec.town",
|
||||
"@soulthunk@lethallava.land",
|
||||
"@bumble@ibe.social",
|
||||
"@DarrenNevares@calckey.social",
|
||||
"@irfan@calckey.social",
|
||||
"@DarrenNevares@firefish.social",
|
||||
"@irfan@firefish.social",
|
||||
"@dvd@dvd.chat",
|
||||
"@charlie2alpha@electricrequiem.com",
|
||||
"@arndot@layer8.space",
|
||||
"@ryan@c.ryanccn.dev",
|
||||
"@lapastora_deprova@calckey.social",
|
||||
"@rameez@calckey.social",
|
||||
"@lapastora_deprova@firefish.social",
|
||||
"@rameez@firefish.social",
|
||||
"@dracoling@firetribe.org",
|
||||
"@Space6host@calckey.social",
|
||||
"@Space6host@firefish.social",
|
||||
"@zakalwe@plasmatrap.com",
|
||||
"@seasicksailor@calckey.social",
|
||||
"@geerue@calckey.social",
|
||||
"@seasicksailor@firefish.social",
|
||||
"@geerue@firefish.social",
|
||||
"@WXFanatic@m.ai6yr.org",
|
||||
"@Hunkabilly@calckey.world",
|
||||
"@samleegray@calckey.social",
|
||||
"@samleegray@firefish.social",
|
||||
"@schwarzewald@kodow.net",
|
||||
"@Conatusprinciple@calckey.social",
|
||||
"@Conatusprinciple@firefish.social",
|
||||
"@183231bcb@firefish.lgbt",
|
||||
"@wiase@calckey.social",
|
||||
"@wiase@firefish.social",
|
||||
"@leonieke@vitaulium.nl",
|
||||
"@soulfire@wackywolf.xyz",
|
||||
"@elbullazul@pub.elbullazul.com",
|
||||
|
@ -110,8 +110,8 @@
|
|||
"@hryggrbyr@ibe.social"
|
||||
],
|
||||
"sponsors": [
|
||||
"@atomicpoet@calckey.social",
|
||||
"@unattributed@calckey.social",
|
||||
"@atomicpoet@firefish.social",
|
||||
"@unattributed@firefish.social",
|
||||
"@jtbennett@noc.social",
|
||||
"\nInterkosmos Link"
|
||||
]
|
||||
|
|
Loading…
Reference in a new issue