1
0
Fork 1
mirror of https://example.com synced 2024-11-22 12:56:39 +09:00

Firefish v1.0.5-dev18

This commit is contained in:
naskya 2023-10-10 23:28:06 +09:00
parent 56c64d5860
commit dee4497e69
Signed by: naskya
GPG key ID: 164DFF24E2D40139
259 changed files with 1526 additions and 12180 deletions

3
.gitignore vendored
View file

@ -57,9 +57,6 @@ packages/backend/assets/LICENSE
!/packages/backend/src/db !/packages/backend/src/db
!/packages/backend/src/server/api/endpoints/drive/files !/packages/backend/src/server/api/endpoints/drive/files
packages/megalodon/lib
packages/megalodon/.idea
# blender backups # blender backups
*.blend1 *.blend1
*.blend2 *.blend2

View file

@ -26,7 +26,6 @@ COPY packages/backend/package.json packages/backend/package.json
COPY packages/client/package.json packages/client/package.json COPY packages/client/package.json packages/client/package.json
COPY packages/sw/package.json packages/sw/package.json COPY packages/sw/package.json packages/sw/package.json
COPY packages/firefish-js/package.json packages/firefish-js/package.json COPY packages/firefish-js/package.json packages/firefish-js/package.json
COPY packages/megalodon/package.json packages/megalodon/package.json
COPY packages/backend/native-utils/package.json packages/backend/native-utils/package.json COPY packages/backend/native-utils/package.json packages/backend/native-utils/package.json
COPY packages/backend/native-utils/npm/linux-x64-musl/package.json packages/backend/native-utils/npm/linux-x64-musl/package.json COPY packages/backend/native-utils/npm/linux-x64-musl/package.json packages/backend/native-utils/npm/linux-x64-musl/package.json
COPY packages/backend/native-utils/npm/linux-arm64-musl/package.json packages/backend/native-utils/npm/linux-arm64-musl/package.json COPY packages/backend/native-utils/npm/linux-arm64-musl/package.json packages/backend/native-utils/npm/linux-arm64-musl/package.json
@ -56,8 +55,6 @@ RUN apt-get update && apt-get install -y libvips-dev zip unzip tini ffmpeg
COPY . ./ COPY . ./
COPY --from=build /firefish/packages/megalodon /firefish/packages/megalodon
# Copy node modules # Copy node modules
COPY --from=build /firefish/node_modules /firefish/node_modules COPY --from=build /firefish/node_modules /firefish/node_modules
COPY --from=build /firefish/packages/backend/node_modules /firefish/packages/backend/node_modules COPY --from=build /firefish/packages/backend/node_modules /firefish/packages/backend/node_modules

View file

@ -1441,7 +1441,8 @@ _accountDelete:
requestAccountDelete: Sol·licitar la supressió del compte requestAccountDelete: Sol·licitar la supressió del compte
_ad: _ad:
back: Enrera back: Enrera
reduceFrequencyOfThisAd: Mostrar aquest anunci menys reduceFrequencyOfThisAd: Mostrar menys aquest anunci
adsBy: Anunci comunitari per {by}
_gallery: _gallery:
my: La meva Galeria my: La meva Galeria
liked: Publicacions que m'han agradat liked: Publicacions que m'han agradat
@ -1539,8 +1540,8 @@ low: Baixa
emailNotConfiguredWarning: L'adreça de correu electrònic no està definida. emailNotConfiguredWarning: L'adreça de correu electrònic no està definida.
instanceSecurity: Seguretat del servidor instanceSecurity: Seguretat del servidor
privateMode: Mode Privat privateMode: Mode Privat
allowedInstances: Servidors a la llista blanca allowedInstances: Servidors permesos
allowedInstancesDescription: Llista blanca de Hosts amb qui federar, cadascún separat allowedInstancesDescription: Llista permesa de Hosts amb qui federar, cadascún separat
per una línia nova (només s'aplica en mode privat). per una línia nova (només s'aplica en mode privat).
previewNoteText: Mostra la vista prèvia previewNoteText: Mostra la vista prèvia
customCss: CSS personalitzat customCss: CSS personalitzat
@ -1552,7 +1553,7 @@ troubleshooting: Resolució de problemes
learnMore: Més informació learnMore: Més informació
misskeyUpdated: Firefish s'ha actualitzat! misskeyUpdated: Firefish s'ha actualitzat!
translate: Tradueix translate: Tradueix
translatedFrom: Traduït per {x} translatedFrom: Traduït desde {x}
aiChanMode: Ai-chan a la interfície d'usuari clàssica aiChanMode: Ai-chan a la interfície d'usuari clàssica
keepCw: Mantenir els avisos de contingut keepCw: Mantenir els avisos de contingut
pubSub: Comptes Pub/Sub pubSub: Comptes Pub/Sub
@ -1646,8 +1647,8 @@ customCssWarn: Aquesta configuració només s'ha d'utilitzar si sabeu què fa. L
squareAvatars: Mostra avatars quadrats squareAvatars: Mostra avatars quadrats
secureModeInfo: Quan es faci una solicitut d'altres servidors no contestar sense una secureModeInfo: Quan es faci una solicitut d'altres servidors no contestar sense una
prova. prova.
privateModeInfo: Quan està activat, només els servidors a la llista blanca es poden privateModeInfo: Quan està activat, només els servidors a la llista es poden federar
federar amb el vostre servidor. Totes les publicacions s'amagaran al públic. amb el vostre servidor. Totes les publicacions s'amagaran al públic.
useBlurEffect: Utilitzeu efectes de desenfocament a la interfície d'usuari useBlurEffect: Utilitzeu efectes de desenfocament a la interfície d'usuari
accountDeletionInProgress: La supressió del compte està en curs accountDeletionInProgress: La supressió del compte està en curs
unmuteThread: Desfés el silenci al fil unmuteThread: Desfés el silenci al fil
@ -2200,3 +2201,4 @@ languageForTranslation: Idioma de traducció d'articles
openServerInfo: Mostra la informació del servidor fent clic al símbol del servidor openServerInfo: Mostra la informació del servidor fent clic al símbol del servidor
en un missatge en un missatge
vibrate: Activar vibracions vibrate: Activar vibracions
clickToShowPatterns: Fes clic per veure patrons de mòduls

View file

@ -83,7 +83,8 @@ exportRequested: "You've requested an export. This may take a while. It will be
to your Drive once completed." to your Drive once completed."
importRequested: "You've requested an import. This may take a while." importRequested: "You've requested an import. This may take a while."
lists: "Lists" lists: "Lists"
listsDesc: "Lists let you create timelines with specified users. They can be accessed from the timelines page." listsDesc: "Lists let you create timelines with specified users. They can be accessed
from the timelines page."
noLists: "You don't have any lists" noLists: "You don't have any lists"
note: "Post" note: "Post"
notes: "Posts" notes: "Posts"
@ -408,7 +409,8 @@ avoidMultiCaptchaConfirm: "Using multiple Captcha systems may cause interference
them. Would you like to disable the other Captcha systems currently active? If you them. Would you like to disable the other Captcha systems currently active? If you
would like them to stay enabled, press cancel." would like them to stay enabled, press cancel."
antennas: "Antennas" antennas: "Antennas"
antennasDesc: "Antennas display new posts matching the criteria you set!\n They can be accessed from the timelines page." antennasDesc: "Antennas display new posts matching the criteria you set!\n They can
be accessed from the timelines page."
manageAntennas: "Manage Antennas" manageAntennas: "Manage Antennas"
name: "Name" name: "Name"
antennaSource: "Antenna source" antennaSource: "Antenna source"
@ -603,7 +605,8 @@ output: "Output"
script: "Script" script: "Script"
disablePagesScript: "Disable AiScript on Pages" disablePagesScript: "Disable AiScript on Pages"
expandOnNoteClick: "Open post on click" expandOnNoteClick: "Open post on click"
expandOnNoteClickDesc: "If disabled, you can still open posts in the right-click menu or by clicking the timestamp." expandOnNoteClickDesc: "If disabled, you can still open posts in the right-click menu
or by clicking the timestamp."
updateRemoteUser: "Update remote user information" updateRemoteUser: "Update remote user information"
deleteAllFiles: "Delete all files" deleteAllFiles: "Delete all files"
deleteAllFilesConfirm: "Are you sure that you want to delete all files?" deleteAllFilesConfirm: "Are you sure that you want to delete all files?"
@ -743,8 +746,8 @@ unclip: "Unclip"
confirmToUnclipAlreadyClippedNote: "This post is already part of the \"{name}\" clip. confirmToUnclipAlreadyClippedNote: "This post is already part of the \"{name}\" clip.
Do you want to remove it from this clip instead?" Do you want to remove it from this clip instead?"
public: "Public" public: "Public"
i18nInfo: "Firefish is being translated into various languages by volunteers. You can i18nInfo: "Firefish is being translated into various languages by volunteers. You
help at {link}." can help at {link}."
manageAccessTokens: "Manage access tokens" manageAccessTokens: "Manage access tokens"
accountInfo: "Account Info" accountInfo: "Account Info"
notesCount: "Number of posts" notesCount: "Number of posts"
@ -779,7 +782,8 @@ pageLikedCount: "Number of received Page likes"
contact: "Contact" contact: "Contact"
useSystemFont: "Use the system's default font" useSystemFont: "Use the system's default font"
clips: "Clips" clips: "Clips"
clipsDesc: "Clips are like share-able categorized bookmarks. You can create clips from the menu of individual posts." clipsDesc: "Clips are like share-able categorized bookmarks. You can create clips
from the menu of individual posts."
experimentalFeatures: "Experimental features" experimentalFeatures: "Experimental features"
developer: "Developer" developer: "Developer"
makeExplorable: "Make account visible in \"Explore\"" makeExplorable: "Make account visible in \"Explore\""
@ -888,10 +892,10 @@ secureMode: "Secure Mode (Authorized Fetch)"
instanceSecurity: "Server Security" instanceSecurity: "Server Security"
secureModeInfo: "When requesting from other servers, do not send back without proof." secureModeInfo: "When requesting from other servers, do not send back without proof."
privateMode: "Private Mode" privateMode: "Private Mode"
privateModeInfo: "When enabled, only whitelisted servers can federate with your server. privateModeInfo: "When enabled, only allowlisted servers can federate with your server.
All posts will be hidden from the public." All posts will be hidden from the public."
allowedInstances: "Whitelisted Servers" allowedInstances: "Allowlisted Servers"
allowedInstancesDescription: "Hosts of servers to be whitelisted for federation, each allowedInstancesDescription: "Hosts of servers to be allowlisted for federation, each
separated by a new line (only applies in private mode)." separated by a new line (only applies in private mode)."
previewNoteText: "Show preview" previewNoteText: "Show preview"
customCss: "Custom CSS" customCss: "Custom CSS"
@ -1083,8 +1087,8 @@ license: "License"
indexPosts: "Index Posts" indexPosts: "Index Posts"
indexFrom: "Index from Post ID onwards" indexFrom: "Index from Post ID onwards"
indexFromDescription: "Leave blank to index every post" indexFromDescription: "Leave blank to index every post"
indexNotice: "Now indexing. This will probably take a while, please don't restart\ indexNotice: "Now indexing. This will probably take a while, please don't restart
\ your server for at least an hour." your server for at least an hour."
customKaTeXMacro: "Custom KaTeX macros" customKaTeXMacro: "Custom KaTeX macros"
customKaTeXMacroDescription: "Set up macros to write mathematical expressions easily! customKaTeXMacroDescription: "Set up macros to write mathematical expressions easily!
The notation conforms to the LaTeX command definitions and is written as \\newcommand{\\ The notation conforms to the LaTeX command definitions and is written as \\newcommand{\\
@ -1139,10 +1143,12 @@ origin: "Origin"
delete2fa: "Disable 2FA" delete2fa: "Disable 2FA"
deletePasskeys: "Delete passkeys" deletePasskeys: "Delete passkeys"
delete2faConfirm: "This will irreversibly delete 2FA on this account. Proceed?" delete2faConfirm: "This will irreversibly delete 2FA on this account. Proceed?"
deletePasskeysConfirm: "This will irreversibly delete all passkeys and security keys on this account. Proceed?" deletePasskeysConfirm: "This will irreversibly delete all passkeys and security keys
on this account. Proceed?"
inputNotMatch: "Input does not match" inputNotMatch: "Input does not match"
addRe: "Add \"re:\" at the beginning of comment in reply to a post with a content warning"
showBigPostButton: "Show a bigger post button in the posting form" showBigPostButton: "Show a bigger post button in the posting form"
addRe: "Add \"re:\" at the beginning of comment in reply to a post with a content
warning"
confirm: "Confirm" confirm: "Confirm"
emphasizeFollowed: "Highlight the \"Follows you\" sign on your follower info" emphasizeFollowed: "Highlight the \"Follows you\" sign on your follower info"
importZip: "Import ZIP" importZip: "Import ZIP"
@ -1151,7 +1157,8 @@ emojiPackCreator: "Emoji pack creator"
indexable: "Indexable" indexable: "Indexable"
indexableDescription: "Allow built-in search to show your public posts" indexableDescription: "Allow built-in search to show your public posts"
languageForTranslation: "Post translation language" languageForTranslation: "Post translation language"
detectPostLanguage: "Automatically detect the language and show a translate button for posts in foreign languages" detectPostLanguage: "Automatically detect the language and show a translate button
for posts in foreign languages"
vibrate: "Play vibrations" vibrate: "Play vibrations"
openServerInfo: "Show server information by clicking the server ticker on a post" openServerInfo: "Show server information by clicking the server ticker on a post"
@ -1195,7 +1202,8 @@ _accountDelete:
inProgress: "Deletion is currently in progress" inProgress: "Deletion is currently in progress"
_ad: _ad:
back: "Back" back: "Back"
reduceFrequencyOfThisAd: "Show this ad less" adsBy: "Community banner by {by}"
reduceFrequencyOfThisAd: "Show this banner less"
_forgotPassword: _forgotPassword:
enterEmail: "Enter the email address you used to register. A link with which you enterEmail: "Enter the email address you used to register. A link with which you
can reset your password will then be sent to it." can reset your password will then be sent to it."
@ -1245,8 +1253,8 @@ _registry:
domain: "Domain" domain: "Domain"
createKey: "Create key" createKey: "Create key"
_aboutFirefish: _aboutFirefish:
about: "Firefish is a fork of Misskey made by ThatOneCalculator, which has been in about: "Firefish is a fork of Misskey made by ThatOneCalculator, which has been
development since 2022." in development since 2022."
contributors: "Main contributors" contributors: "Main contributors"
allContributors: "All contributors" allContributors: "All contributors"
misskeyContributors: "Misskey main contributors" misskeyContributors: "Misskey main contributors"
@ -1255,13 +1263,15 @@ _aboutFirefish:
donate: "Donate to Firefish" donate: "Donate to Firefish"
donateTitle: "Enjoying Firefish?" donateTitle: "Enjoying Firefish?"
pleaseDonateToFirefish: "Please consider donating to Firefish to support its development." pleaseDonateToFirefish: "Please consider donating to Firefish to support its development."
pleaseDonateToHost: "Please also consider donating to your home server, {host}, to help support its operation costs." pleaseDonateToHost: "Please also consider donating to your home server, {host},
to help support its operation costs."
donateHost: "Donate to {host}" donateHost: "Donate to {host}"
morePatrons: "We also appreciate the support of many other helpers not listed here. morePatrons: "We also appreciate the support of many other helpers not listed here.
Thank you! 🥰" Thank you! 🥰"
sponsors: "Firefish sponsors" sponsors: "Firefish sponsors"
patrons: "Firefish patrons" patrons: "Firefish patrons"
patronsList: "Listed chronologically, not by donation size. Donate with the link above to get your name on here!" patronsList: "Listed chronologically, not by donation size. Donate with the link
above to get your name on here!"
_nsfw: _nsfw:
respect: "Hide NSFW media" respect: "Hide NSFW media"
ignore: "Don't hide NSFW media" ignore: "Don't hide NSFW media"
@ -1276,7 +1286,8 @@ _mfm:
can be used in many places. Here you can view a list of all available MFM syntax." can be used in many places. Here you can view a list of all available MFM syntax."
dummy: "Firefish expands the world of the Fediverse" dummy: "Firefish expands the world of the Fediverse"
advanced: "Advanced MFM" advanced: "Advanced MFM"
advancedDescription: "If disabled, only allows for basic markup unless animated MFM is playing" advancedDescription: "If disabled, only allows for basic markup unless animated
MFM is playing"
mention: "Mention" mention: "Mention"
mentionDescription: "You can specify a user by using an At-Symbol and a username." mentionDescription: "You can specify a user by using an At-Symbol and a username."
hashtag: "Hashtag" hashtag: "Hashtag"
@ -1532,10 +1543,10 @@ _tutorial:
step5_4: "The Local {icon} timeline is where you can see posts from everyone else step5_4: "The Local {icon} timeline is where you can see posts from everyone else
on this server." on this server."
step5_5: "The Social {icon} timeline is a combination of the Home and Local timelines." step5_5: "The Social {icon} timeline is a combination of the Home and Local timelines."
step5_6: "The Recommended {icon} timeline is where you can see posts from servers\ step5_6: "The Recommended {icon} timeline is where you can see posts from servers
\ the admins recommend." the admins recommend."
step5_7: "The Global {icon} timeline is where you can see posts from every other\ step5_7: "The Global {icon} timeline is where you can see posts from every other
\ connected server." connected server."
step6_1: "So, what is this place?" step6_1: "So, what is this place?"
step6_2: "Well, you didn't just join Firefish. You joined a portal to the Fediverse, step6_2: "Well, you didn't just join Firefish. You joined a portal to the Fediverse,
an interconnected network of thousands of servers." an interconnected network of thousands of servers."
@ -1548,23 +1559,29 @@ _2fa:
registerTOTP: "Register authenticator app" registerTOTP: "Register authenticator app"
step1: "First, install an authentication app (such as {a} or {b}) on your device." step1: "First, install an authentication app (such as {a} or {b}) on your device."
step2: "Then, scan the QR code displayed on this screen." step2: "Then, scan the QR code displayed on this screen."
step2Click: "Clicking on this QR code will allow you to register 2FA to your security key or phone authenticator app." step2Click: "Clicking on this QR code will allow you to register 2FA to your security
key or phone authenticator app."
step2Url: "You can also enter this URL if you're using a desktop program:" step2Url: "You can also enter this URL if you're using a desktop program:"
step3Title: "Enter an authentication code" step3Title: "Enter an authentication code"
step3: "Enter the token provided by your app to finish setup." step3: "Enter the token provided by your app to finish setup."
step4: "From now on, any future login attempts will ask for such a login token." step4: "From now on, any future login attempts will ask for such a login token."
securityKeyNotSupported: "Your browser does not support security keys." securityKeyNotSupported: "Your browser does not support security keys."
registerTOTPBeforeKey: "Please set up an authenticator app to register a security or pass key." registerTOTPBeforeKey: "Please set up an authenticator app to register a security
securityKeyInfo: "Besides fingerprint or PIN authentication, you can also setup authentication via hardware security keys that support FIDO2 to further secure your account." or pass key."
securityKeyInfo: "Besides fingerprint or PIN authentication, you can also setup
authentication via hardware security keys that support FIDO2 to further secure
your account."
chromePasskeyNotSupported: "Chrome passkeys are currently not supported." chromePasskeyNotSupported: "Chrome passkeys are currently not supported."
registerSecurityKey: "Register a security or pass key" registerSecurityKey: "Register a security or pass key"
securityKeyName: "Enter a key name" securityKeyName: "Enter a key name"
tapSecurityKey: "Please follow your browser to register the security or pass key" tapSecurityKey: "Please follow your browser to register the security or pass key"
removeKey: "Remove security key" removeKey: "Remove security key"
removeKeyConfirm: "Really delete the {name} key?" removeKeyConfirm: "Really delete the {name} key?"
whyTOTPOnlyRenew: "The authenticator app cannot be removed as long as a security key is registered." whyTOTPOnlyRenew: "The authenticator app cannot be removed as long as a security
key is registered."
renewTOTP: "Reconfigure authenticator app" renewTOTP: "Reconfigure authenticator app"
renewTOTPConfirm: "This will cause verification codes from your previous app to stop working" renewTOTPConfirm: "This will cause verification codes from your previous app to
stop working"
renewTOTPOk: "Reconfigure" renewTOTPOk: "Reconfigure"
renewTOTPCancel: "Cancel" renewTOTPCancel: "Cancel"
token: "2FA Token" token: "2FA Token"
@ -1713,10 +1730,9 @@ _profile:
youCanIncludeHashtags: "You can also include hashtags in your bio." youCanIncludeHashtags: "You can also include hashtags in your bio."
metadata: "Additional Information" metadata: "Additional Information"
metadataEdit: "Edit additional Information" metadataEdit: "Edit additional Information"
metadataDescription: metadataDescription: "Using these, you can display additional information fields
"Using these, you can display additional information fields in your profile. You can add an {a} tag or {l} tag with {rel} to verify the link
in your profile. You can add an {a} tag or {l} tag with {rel} on your profile!"
to verify the link on your profile!"
metadataLabel: "Label" metadataLabel: "Label"
metadataContent: "Content" metadataContent: "Content"
changeAvatar: "Change avatar" changeAvatar: "Change avatar"
@ -2127,9 +2143,9 @@ _deck:
_experiments: _experiments:
title: "Experiments" title: "Experiments"
enablePostImports: "Enable post imports" enablePostImports: "Enable post imports"
postImportsCaption: "Allows users to import their posts from past Firefish,\ postImportsCaption: "Allows users to import their posts from past Firefish, Misskey,
\ Misskey, Mastodon, Akkoma, and Pleroma accounts. It may cause slowdowns during\ Mastodon, Akkoma, and Pleroma accounts. It may cause slowdowns during load if
\ load if your queue is bottlenecked." your queue is bottlenecked."
_dialog: _dialog:
charactersExceeded: "Max characters exceeded! Current: {current}/Limit: {max}" charactersExceeded: "Max characters exceeded! Current: {current}/Limit: {max}"
charactersBelow: "Not enough characters! Current: {current}/Limit: {min}" charactersBelow: "Not enough characters! Current: {current}/Limit: {min}"

View file

@ -1988,7 +1988,7 @@ migration: Migración
silenced: Silenciado silenced: Silenciado
deleted: Eliminado deleted: Eliminado
edited: 'Editado a las {date} {time}' edited: 'Editado a las {date} {time}'
editNote: Editar nota editNote: Editar publicación
silenceThisInstance: Silenciar este servidor silenceThisInstance: Silenciar este servidor
findOtherInstance: Buscar otro servidor findOtherInstance: Buscar otro servidor
userSaysSomethingReasonRenote: '{name} impulsó una publicación que contiene {reason]' userSaysSomethingReasonRenote: '{name} impulsó una publicación que contiene {reason]'
@ -2164,3 +2164,4 @@ noGraze: Por favor desactiva la extensión de navegador "Graze for Mastodon" ya
silencedWarning: Esta página se muestra debido a que estos usuarios son de servidores silencedWarning: Esta página se muestra debido a que estos usuarios son de servidores
que tu administrador ha silenciado, ya que son presumiblemente fuente de spam. que tu administrador ha silenciado, ya que son presumiblemente fuente de spam.
isBot: Esta cuenta es un bot isBot: Esta cuenta es un bot
clickToShowPatterns: Haz clic para mostrar patrones de módulos

View file

@ -646,7 +646,7 @@ emptyToDisableSmtpAuth: "Laisser le nom dutilisateur et le mot de passe vides
smtpSecure: "Utiliser SSL/TLS implicitement dans les connexions SMTP" smtpSecure: "Utiliser SSL/TLS implicitement dans les connexions SMTP"
smtpSecureInfo: "Désactiver cette option lorsque STARTTLS est utilisé" smtpSecureInfo: "Désactiver cette option lorsque STARTTLS est utilisé"
testEmail: "Tester la distribution de courriel" testEmail: "Tester la distribution de courriel"
wordMute: "Filtre de mots" wordMute: "Filtre de mots et langages"
regexpError: "Erreur dexpression régulière" regexpError: "Erreur dexpression régulière"
instanceMute: "Serveur masqué" instanceMute: "Serveur masqué"
userSaysSomething: "{name} a dit quelque chose" userSaysSomething: "{name} a dit quelque chose"
@ -960,7 +960,8 @@ _accountDelete:
inProgress: "Suppression en cours" inProgress: "Suppression en cours"
_ad: _ad:
back: "Retour" back: "Retour"
reduceFrequencyOfThisAd: "Voir cette publicité moins souvent" reduceFrequencyOfThisAd: "Voir cette bannière moins souvent"
adsBy: Bannière communautaire par {by}
_forgotPassword: _forgotPassword:
enterEmail: "Entrez ici l'adresse e-mail que vous avez enregistrée pour votre compte. enterEmail: "Entrez ici l'adresse e-mail que vous avez enregistrée pour votre compte.
Un lien vous permettant de réinitialiser votre mot de passe sera envoyé à cette Un lien vous permettant de réinitialiser votre mot de passe sera envoyé à cette
@ -1145,6 +1146,13 @@ _wordMute:
soft: "Doux" soft: "Doux"
hard: "Strict" hard: "Strict"
mutedNotes: "Publications masquées" mutedNotes: "Publications masquées"
muteLangsDescription2: Utiliser les code de langage (i.e en, fr, ja, zh).
lang: Langage
langDescription: Cacher du fil de publication les publications qui correspondent
à ces langues.
muteLangs: Langages filtrés
muteLangsDescription: Séparer avec des espaces or des retours à la ligne pour une
condition OU (OR).
_instanceMute: _instanceMute:
instanceMuteDescription2: "Séparer avec des sauts de lignes" instanceMuteDescription2: "Séparer avec des sauts de lignes"
title: "Masque les publications provenant des serveurs listés." title: "Masque les publications provenant des serveurs listés."
@ -2218,3 +2226,5 @@ openServerInfo: Afficher les informations du serveur en cliquant sur le bandeau
serveur dune publication serveur dune publication
indexable: Indexable indexable: Indexable
languageForTranslation: Langage post-traduction languageForTranslation: Langage post-traduction
vibrate: Jouer les vibrations
clickToShowPatterns: Cliquer pour montrer les patrons de modules

1
locales/hi.yml Normal file
View file

@ -0,0 +1 @@
_lang_: "हिन्दी"

View file

@ -953,7 +953,8 @@ _accountDelete:
inProgress: "Penghapusan sedang dalam proses" inProgress: "Penghapusan sedang dalam proses"
_ad: _ad:
back: "Kembali" back: "Kembali"
reduceFrequencyOfThisAd: "Tampilkan iklan ini lebih sedikit" reduceFrequencyOfThisAd: "Tampilkan banner ini lebih sedikit"
adsBy: Banner komunitas oleh {by}
_forgotPassword: _forgotPassword:
enterEmail: "Masukkan alamat surel yang kamu gunakan pada saat mendaftar. Sebuah enterEmail: "Masukkan alamat surel yang kamu gunakan pada saat mendaftar. Sebuah
tautan untuk mengatur ulang kata sandi kamu akan dikirimkan ke alamat surel tersebut." tautan untuk mengatur ulang kata sandi kamu akan dikirimkan ke alamat surel tersebut."
@ -1268,8 +1269,8 @@ _tutorial:
{introduction} atau \"Halo dunia!\" yang sederhana." {introduction} atau \"Halo dunia!\" yang sederhana."
step5_1: "Linimasa, linimasa di mana-mana!" step5_1: "Linimasa, linimasa di mana-mana!"
step5_2: "Servermu memiliki {timelines} lini masa berbeda yang diaktifkan." step5_2: "Servermu memiliki {timelines} lini masa berbeda yang diaktifkan."
step5_3: "Lini masa Beranda {icon} adalah tempat di mana kamu bisa melihat postingan step5_3: "Lini masa Beranda {icon} adalah tempat kamu bisa melihat postingan dari
dari akun yang kamu ikuti." akun yang kamu ikuti."
step5_4: "Linimasa Lokal {icon} adalah tempat kamu dapat melihat postingan dari step5_4: "Linimasa Lokal {icon} adalah tempat kamu dapat melihat postingan dari
siapa pun di server ini." siapa pun di server ini."
step6_1: "Jadi, tempat apa ini?" step6_1: "Jadi, tempat apa ini?"
@ -1923,9 +1924,9 @@ moderation: Moderasi
userSaysSomethingReason: '{name} mengatakan {reason}' userSaysSomethingReason: '{name} mengatakan {reason}'
secureMode: Mode Aman (Pengambilan Terotorisasi) secureMode: Mode Aman (Pengambilan Terotorisasi)
secureModeInfo: Saat meminta dari server lain, jangan kirim kembali tanpa bukti. secureModeInfo: Saat meminta dari server lain, jangan kirim kembali tanpa bukti.
privateModeInfo: Saat aktif, hanya server yang masuk daftar putih dapat terfederasi privateModeInfo: Saat aktif, hanya server yang masuk daftar yang diizinkan yang dapat
dengan servermu. Semua postingan akan disembunyikan dari publik. terfederasi dengan servermu. Semua postingan akan disembunyikan dari publik.
allowedInstances: Server Masuk Daftar Putih allowedInstances: Daftar Server Diizinkan
newer: lebih baru newer: lebih baru
userSaysSomethingReasonReply: '{name} membalas postingan berisi {reason}' userSaysSomethingReasonReply: '{name} membalas postingan berisi {reason}'
userSaysSomethingReasonRenote: '{name} memposting ulang postingan berisi {reason}' userSaysSomethingReasonRenote: '{name} memposting ulang postingan berisi {reason}'
@ -1935,8 +1936,8 @@ jumpToPrevious: Lompat ke sebelumnya
flagSpeakAsCatDescription: Postinganmu akan nyampak dalam mode kucing flagSpeakAsCatDescription: Postinganmu akan nyampak dalam mode kucing
cw: Peringatan konten cw: Peringatan konten
flagSpeakAsCat: Bicara sebagai kucing flagSpeakAsCat: Bicara sebagai kucing
allowedInstancesDescription: Host server akan masuk daftar putih untuk federasi, mereka allowedInstancesDescription: Server host akan masuk daftar yang diizinkan untuk federasi,
dipisahkan dengan baris baru (hanya diterapkan pada mode pribadi). mereka dipisahkan dengan baris baru (hanya diterapkan pada mode pribadi).
xl: XL xl: XL
privateMode: Mode Pribadi privateMode: Mode Pribadi
seperateRenoteQuote: Tombol posting ulang dan kutip terpisah seperateRenoteQuote: Tombol posting ulang dan kutip terpisah
@ -2182,3 +2183,4 @@ languageForTranslation: Bahasa terjemahan kiriman
openServerInfo: Tampilkan informasi server dengan mengeklik ticker server di sebuah openServerInfo: Tampilkan informasi server dengan mengeklik ticker server di sebuah
kiriman kiriman
vibrate: Putar getaran vibrate: Putar getaran
clickToShowPatterns: Klik untuk menampilkan pola modul

View file

@ -626,7 +626,7 @@ emptyToDisableSmtpAuth: "Lasciare username e password vuoti per disabilitare la
smtpSecure: "Usa la porta SSL/TLS predefinita per le connessioni SMTP" smtpSecure: "Usa la porta SSL/TLS predefinita per le connessioni SMTP"
smtpSecureInfo: "Disabilita quando è attivo STARTTLS" smtpSecureInfo: "Disabilita quando è attivo STARTTLS"
testEmail: "Test di consegna email" testEmail: "Test di consegna email"
wordMute: "Filtro parole" wordMute: "Filtro parole e lingua"
instanceMute: "Server silenziati" instanceMute: "Server silenziati"
userSaysSomething: "{name} ha detto qualcosa" userSaysSomething: "{name} ha detto qualcosa"
makeActive: "Attiva" makeActive: "Attiva"
@ -901,7 +901,8 @@ _accountDelete:
caricato. caricato.
_ad: _ad:
back: "Indietro" back: "Indietro"
reduceFrequencyOfThisAd: "Mostra meno spesso questa pubblicità" reduceFrequencyOfThisAd: "Mostra meno spesso questo banner"
adsBy: Banner della comunità da {by}
_forgotPassword: _forgotPassword:
enterEmail: "Inserisci l'e-mail che hai registrato nel tuo profilo. Il link di ripristino enterEmail: "Inserisci l'e-mail che hai registrato nel tuo profilo. Il link di ripristino
della password verrà inviato a questo indirizzo." della password verrà inviato a questo indirizzo."
@ -1084,6 +1085,11 @@ _wordMute:
soft: "Moderato" soft: "Moderato"
hard: "Severo" hard: "Severo"
mutedNotes: "Post silenziati" mutedNotes: "Post silenziati"
muteLangsDescription2: 'Usa il codice lingua, esempio: en, fr, ja, zh.'
lang: Lingua
langDescription: Nascondi dalla timeline i post in quest'insieme di lingue.
muteLangs: Lingue da non mostrare
muteLangsDescription: Separa andando a capo o con spazi per la condizione OR.
_theme: _theme:
explore: "Esplora temi" explore: "Esplora temi"
install: "Installa un tema" install: "Installa un tema"
@ -1992,11 +1998,11 @@ secureMode: Modalità sicura (Acquisizione autorizzata)
secureModeInfo: Le richieste dai server remoti non ricevono risposta senza prima una secureModeInfo: Le richieste dai server remoti non ricevono risposta senza prima una
verifica. verifica.
privateMode: Modalità privata privateMode: Modalità privata
allowedInstancesDescription: Gli host dei server che saranno federati in esclusiva, allowedInstancesDescription: Gli host dei server con cui sarà permessa la federazione,
uno per riga (funziona solo in modalità privata). uno per riga (funziona solo in modalità privata).
privateModeInfo: Se abilitata, solo i server in una whitelist potranno essere federati privateModeInfo: Se abilitata, solo i server nell'elenco potranno essere federati
con questo server. Tutti i post saranno nascosti al pubblico. con questo server. Tutti i post saranno nascosti al pubblico.
allowedInstances: Whitelist dei server allowedInstances: Elenco server permessi
customCssWarn: Questa impostazione dovrebbe essere usata solo se sai cosa stai facendo. customCssWarn: Questa impostazione dovrebbe essere usata solo se sai cosa stai facendo.
Inserire valori errati potrebbe bloccare il funzionamento del client. Inserire valori errati potrebbe bloccare il funzionamento del client.
lastCommunication: Ultima comunicazione lastCommunication: Ultima comunicazione
@ -2164,3 +2170,5 @@ indexable: Indicizzabile
languageForTranslation: Linguaggio di traduzione dei post languageForTranslation: Linguaggio di traduzione dei post
openServerInfo: Mostra informazioni sul server cliccando sul riquadro del server in openServerInfo: Mostra informazioni sul server cliccando sul riquadro del server in
un post un post
vibrate: Abilita la vibrazione
clickToShowPatterns: Clicca per vedere i pattern del modulo

View file

@ -833,7 +833,7 @@ translatedFrom: "{x}から翻訳"
accountDeletionInProgress: "アカウントの削除が進行中です" accountDeletionInProgress: "アカウントの削除が進行中です"
usernameInfo: "サーバー上であなたのアカウントを一意に識別するための名前です。アルファベット(a~z, A~Z)、数字(0~9)、およびアンダーバー(_)が使用できます。ユーザー名は後から変更できません。" usernameInfo: "サーバー上であなたのアカウントを一意に識別するための名前です。アルファベット(a~z, A~Z)、数字(0~9)、およびアンダーバー(_)が使用できます。ユーザー名は後から変更できません。"
aiChanMode: "藍モードクラシックUI" aiChanMode: "藍モードクラシックUI"
enterSendsMessage: "メッセージングでReturnキーを押すと、メッセージが送信されますデフォルトはCtrl + Returnです)" enterSendsMessage: "チャットでEnterキー(Returnキー)を押すと、メッセージが送信されますオフの場合はCtrl + Enterで送信します)"
keepCw: "CWを維持する" keepCw: "CWを維持する"
pubSub: "Pub/Subのアカウント" pubSub: "Pub/Subのアカウント"
lastCommunication: "直近の通信" lastCommunication: "直近の通信"
@ -1031,7 +1031,8 @@ _accountDelete:
inProgress: "削除が進行中" inProgress: "削除が進行中"
_ad: _ad:
back: "戻る" back: "戻る"
reduceFrequencyOfThisAd: "この広告の表示頻度を下げる" adsBy: "バナーで{by}"
reduceFrequencyOfThisAd: "このバナーの表示頻度を下げる"
_forgotPassword: _forgotPassword:
enterEmail: "アカウントに登録したメールアドレスを入力してください。そのアドレス宛てに、パスワードリセット用のリンクが送信されます。" enterEmail: "アカウントに登録したメールアドレスを入力してください。そのアドレス宛てに、パスワードリセット用のリンクが送信されます。"
ifNoEmail: "メールアドレスを登録していない場合は、管理者までお問い合わせください。" ifNoEmail: "メールアドレスを登録していない場合は、管理者までお問い合わせください。"
@ -1513,7 +1514,7 @@ _profile:
youCanIncludeHashtags: "ハッシュタグを含められます。" youCanIncludeHashtags: "ハッシュタグを含められます。"
metadata: "追加情報" metadata: "追加情報"
metadataEdit: "追加情報を編集" metadataEdit: "追加情報を編集"
metadataDescription: "プロフィールに表として追加情報を表示できます。{a}タグまたは{l}タグを{rel}とともに追加すると、プロフィールのリンクを確認できます。" metadataDescription: "プロフィールに追加情報を表示できます。{a}タグまたは{l}タグを{rel}とともに追加すると、プロフィールのリンクを本人認証できます。"
metadataLabel: "ラベル" metadataLabel: "ラベル"
metadataContent: "内容" metadataContent: "内容"
changeAvatar: "アバター画像を変更" changeAvatar: "アバター画像を変更"
@ -2011,3 +2012,4 @@ hideMyName: "自分の名前とIDを表示しない"
openServerInfo: "投稿内のサーバー名をクリックでサーバー情報を開く" openServerInfo: "投稿内のサーバー名をクリックでサーバー情報を開く"
searchEngine: "検索の MFM で使用する検索エンジン" searchEngine: "検索の MFM で使用する検索エンジン"
postSearch: "このサーバーの投稿検索" postSearch: "このサーバーの投稿検索"
indexableDescription: MastodonやFirefishなどの検索機能に、あなたの投稿が表示されるのを許可します。

View file

@ -64,7 +64,7 @@ import: "インポート"
export: "エクスポート" export: "エクスポート"
files: "ファイル" files: "ファイル"
download: "ダウンロード" download: "ダウンロード"
driveFileDeleteConfirm: "ファイル「{name}」を消してしもうてええか?このファイルを添付した投稿も消えてまうで。" driveFileDeleteConfirm: "ファイル「{name}」を消してええんか?添付した全部の投稿から、きれいさっぱり消えてなくなるで。"
unfollowConfirm: "{name}のフォローを解除してもええんか?" unfollowConfirm: "{name}のフォローを解除してもええんか?"
exportRequested: "エクスポートしてな、ってリクエストしたけど、これ多分めっちゃ時間かかるで。エクスポート終わったら「ドライブ」に突っ込んどくで。" exportRequested: "エクスポートしてな、ってリクエストしたけど、これ多分めっちゃ時間かかるで。エクスポート終わったら「ドライブ」に突っ込んどくで。"
importRequested: "インポートしてな、ってリクエストしたけど、これ多分めっちゃ時間かかるで。" importRequested: "インポートしてな、ってリクエストしたけど、これ多分めっちゃ時間かかるで。"
@ -86,7 +86,7 @@ serverIsDead: "サーバーの応答がおまへん。ちーとの間待って
youShouldUpgradeClient: "このページを表示するには、リロードして新しいバージョンのクライアントを使うてや。" youShouldUpgradeClient: "このページを表示するには、リロードして新しいバージョンのクライアントを使うてや。"
enterListName: "リスト名を入れてや" enterListName: "リスト名を入れてや"
privacy: "プライバシー" privacy: "プライバシー"
makeFollowManuallyApprove: "自分が認めた人だけがこのアカウントをフォローできるようにする" makeFollowManuallyApprove: "ワイが認めた奴だけがワイをフォローできるようにする"
defaultNoteVisibility: "もとからの公開範囲" defaultNoteVisibility: "もとからの公開範囲"
follow: "フォロー" follow: "フォロー"
followRequest: "フォローを頼む" followRequest: "フォローを頼む"
@ -138,9 +138,9 @@ addEmoji: "絵文字を追加"
settingGuide: "ええ感じの設定" settingGuide: "ええ感じの設定"
cacheRemoteFiles: "リモートのファイルをキャッシュする" cacheRemoteFiles: "リモートのファイルをキャッシュする"
cacheRemoteFilesDescription: "この設定を切っとくと、リモートファイルをキャッシュせず直リンクするようになるで。サーバーの容量は節約できるけど、サムネイルが作られんくなるから通信量が増えるで。" cacheRemoteFilesDescription: "この設定を切っとくと、リモートファイルをキャッシュせず直リンクするようになるで。サーバーの容量は節約できるけど、サムネイルが作られんくなるから通信量が増えるで。"
flagAsBot: "ワイはBotや 🤖" flagAsBot: "ワイはBotや🤖"
flagAsBotDescription: "もしこのアカウントがプログラムによって運用されるんやったら、このフラグをオンにしてたのむで。オンにすると、反応の連鎖を防ぐためのフラグとして他の開発者に役立ったり、Firefishのシステム上での扱いがBotに合ったもんになったりするんやで。" flagAsBotDescription: "もしこのアカウントがプログラムによって運用されるんやったら、このフラグをオンにしてたのむで。オンにすると、反応の連鎖を防ぐためのフラグとして他の開発者に役立ったり、Firefishのシステム上での扱いがBotに合ったもんになったりするんやで。"
flagAsCat: "ワイはCatや 🐯" flagAsCat: "ワイはCatや🐯"
flagAsCatDescription: "自分、猫ちゃんならこのフラグつけてみ?" flagAsCatDescription: "自分、猫ちゃんならこのフラグつけてみ?"
flagShowTimelineReplies: "タイムラインに返信を表示させたる" flagShowTimelineReplies: "タイムラインに返信を表示させたる"
flagShowTimelineRepliesDescription: "有効にすると、タイムラインに他のユーザー宛ての投稿も表示したるで。" flagShowTimelineRepliesDescription: "有効にすると、タイムラインに他のユーザー宛ての投稿も表示したるで。"
@ -246,8 +246,8 @@ uploadFromUrl: "URLアップロード"
uploadFromUrlDescription: "このURLのファイルをアップロードしたいねん" uploadFromUrlDescription: "このURLのファイルをアップロードしたいねん"
uploadFromUrlRequested: "アップロードしたい言うといたで" uploadFromUrlRequested: "アップロードしたい言うといたで"
uploadFromUrlMayTakeTime: "アップロード終わるんにちょい時間かかるかもしれへんわ。" uploadFromUrlMayTakeTime: "アップロード終わるんにちょい時間かかるかもしれへんわ。"
explore: "みける" explore: "みける"
messageRead: "もう読んだ" messageRead: "もう読まはった"
noMoreHistory: "これより過去の履歴はあらへんで" noMoreHistory: "これより過去の履歴はあらへんで"
startMessaging: "チャットやるで" startMessaging: "チャットやるで"
nUsersRead: "{n}人が読んでもうた" nUsersRead: "{n}人が読んでもうた"
@ -334,7 +334,7 @@ bannerUrl: "バナー画像のURL"
backgroundImageUrl: "背景画像のURL" backgroundImageUrl: "背景画像のURL"
basicInfo: "基本情報" basicInfo: "基本情報"
pinnedUsers: "ピン留めしたユーザー" pinnedUsers: "ピン留めしたユーザー"
pinnedUsersDescription: "「みつける」ページとかにピン留めしたいユーザーをここに書けばええんやで。他ん人との名前は改行で区切ればええんやで。" pinnedUsersDescription: "「みっける」ページとかにピン留めしときたい兄ちゃんらをここに書いといたらええわ。名前は改行で区切ればええで。"
pinnedPages: "ピン留めページ" pinnedPages: "ピン留めページ"
pinnedPagesDescription: "サーバーのいっちゃん上にピン留めしたいページのパスを、改行で区切って記述してな。" pinnedPagesDescription: "サーバーのいっちゃん上にピン留めしたいページのパスを、改行で区切って記述してな。"
pinnedClipId: "ピン留めするクリップのID" pinnedClipId: "ピン留めするクリップのID"
@ -363,7 +363,7 @@ caseSensitive: "大文字と小文字は別もんや"
withReplies: "返信も入れたって" withReplies: "返信も入れたって"
connectedTo: "次のアカウントに繋がっとるで" connectedTo: "次のアカウントに繋がっとるで"
notesAndReplies: "投稿と返信" notesAndReplies: "投稿と返信"
withFiles: "ファイル付いとる" withFiles: "ファイル付いとるやつ"
silence: "サイレンス" silence: "サイレンス"
silenceConfirm: "サイレンスしよか?" silenceConfirm: "サイレンスしよか?"
unsilence: "サイレンスやめるで" unsilence: "サイレンスやめるで"
@ -389,7 +389,7 @@ securityKeyName: "キーの名前"
registerSecurityKey: "セキュリティキーを登録するで" registerSecurityKey: "セキュリティキーを登録するで"
lastUsed: "最後につこうた日" lastUsed: "最後につこうた日"
unregister: "登録やめる" unregister: "登録やめる"
passwordLessLogin: "パスワード無くてもログインできるようにする" passwordLessLogin: "パスワードなんか無うてもログインでけるようにする"
resetPassword: "パスワードをリセット" resetPassword: "パスワードをリセット"
newPasswordIs: "今度のパスワードは「{password}」や" newPasswordIs: "今度のパスワードは「{password}」や"
reduceUiAnimation: "UIの動きやアニメーションを減らす" reduceUiAnimation: "UIの動きやアニメーションを減らす"
@ -398,8 +398,8 @@ notFound: "見つからへんね"
notFoundDescription: "指定されたURLに該当するページはあらへんやった。" notFoundDescription: "指定されたURLに該当するページはあらへんやった。"
uploadFolder: "とりあえずアップロードしたやつ置いとく所" uploadFolder: "とりあえずアップロードしたやつ置いとく所"
cacheClear: "キャッシュをほかす" cacheClear: "キャッシュをほかす"
markAsReadAllNotifications: "通知はもう全て読んだわっ" markAsReadAllNotifications: "通知はもうぜんぶ読んだわっ"
markAsReadAllUnreadNotes: "投稿は全て読んだわっ" markAsReadAllUnreadNotes: "投稿はぜんぶ読んだわっ"
markAsReadAllTalkMessages: "チャットはもうぜんぶ読んだわっ" markAsReadAllTalkMessages: "チャットはもうぜんぶ読んだわっ"
help: "ヘルプ" help: "ヘルプ"
inputMessageHere: "ここにメッセージ書いてや" inputMessageHere: "ここにメッセージ書いてや"
@ -507,8 +507,8 @@ listen: "聴く"
none: "なし" none: "なし"
showInPage: "ページで表示" showInPage: "ページで表示"
popout: "ポップアウト" popout: "ポップアウト"
volume: "音量" volume: "やかましさ"
masterVolume: "全体の音量" masterVolume: "全体的なやかましさ"
details: "もっと" details: "もっと"
chooseEmoji: "絵文字を選ぶ" chooseEmoji: "絵文字を選ぶ"
unableToProcess: "なんか作業が止まってしまったようやね" unableToProcess: "なんか作業が止まってしまったようやね"
@ -527,7 +527,7 @@ scratchpad: "スクラッチパッド"
scratchpadDescription: "スクラッチパッドではAiScriptを色々試すことができるんや。Firefishに対して色々できるコードを書いて動かしてみたり、結果を見たりできるで。" scratchpadDescription: "スクラッチパッドではAiScriptを色々試すことができるんや。Firefishに対して色々できるコードを書いて動かしてみたり、結果を見たりできるで。"
output: "出力" output: "出力"
script: "スクリプト" script: "スクリプト"
disablePagesScript: "Pagesのスクリプトを無効にしてや" disablePagesScript: "ページ機能のスクリプトを無効にしてや"
updateRemoteUser: "リモートユーザー情報の更新してくれん?" updateRemoteUser: "リモートユーザー情報の更新してくれん?"
deleteAllFiles: "すべてのファイルを削除" deleteAllFiles: "すべてのファイルを削除"
deleteAllFilesConfirm: "ホンマにすべてのファイルを削除するん?消したもんはもう戻ってこんのやで?" deleteAllFilesConfirm: "ホンマにすべてのファイルを削除するん?消したもんはもう戻ってこんのやで?"
@ -684,7 +684,7 @@ clips: "クリップ"
experimentalFeatures: "実験的機能やで" experimentalFeatures: "実験的機能やで"
developer: "開発者やで" developer: "開発者やで"
makeExplorable: "アカウントを見つけやすくするで" makeExplorable: "アカウントを見つけやすくするで"
makeExplorableDescription: "オフにすると、「みつける」にアカウントが載らんくなるで。" makeExplorableDescription: "オフにすると、「みっける」ページに名前が載らんくなるで。"
showGapBetweenNotesInTimeline: "タイムライン上の投稿を離して表示するで" showGapBetweenNotesInTimeline: "タイムライン上の投稿を離して表示するで"
duplicate: "複製" duplicate: "複製"
left: "左" left: "左"
@ -714,7 +714,7 @@ saveConfirm: "保存するで?"
deleteConfirm: "ホンマに削除するで?" deleteConfirm: "ホンマに削除するで?"
invalidValue: "有効な値じゃないみたいやで。" invalidValue: "有効な値じゃないみたいやで。"
registry: "レジストリ" registry: "レジストリ"
closeAccount: "アカウントを閉鎖する" closeAccount: "このアカウントにさいならする"
currentVersion: "現在のバージョン" currentVersion: "現在のバージョン"
latestVersion: "最新のバージョン" latestVersion: "最新のバージョン"
youAreRunningUpToDateClient: "今使ってるクライアントが最新やで!" youAreRunningUpToDateClient: "今使ってるクライアントが最新やで!"
@ -872,8 +872,8 @@ _registry:
domain: "ドメイン" domain: "ドメイン"
createKey: "キーを作る" createKey: "キーを作る"
_aboutFirefish: _aboutFirefish:
about: "Firefishは、ThatOneCalculatorが2022年にMisskeyをいじって作った、オープンなソースのソフトウェアや。" about: "Firefishは、ThatOneCalculatorが2022年にMisskeyをいじって作った、オープンなソースのソフトウエアーや。"
contributors: "主な貢献者" contributors: "ごっつい貢献者"
allContributors: "全ての貢献者" allContributors: "全ての貢献者"
source: "ソースコード" source: "ソースコード"
translation: "Firefishを翻訳" translation: "Firefishを翻訳"
@ -1082,8 +1082,9 @@ _visibility:
public: 公開 public: 公開
homeDescription: ローカルTLやグローバルTLには流さへん homeDescription: ローカルTLやグローバルTLには流さへん
_profile: _profile:
name: "名前" name: "名前"
username: "ユーザー名" username: "ユーザー名"
youCanIncludeHashtags: ハッシュタグを書いてもええよ。
_exportOrImport: _exportOrImport:
allNotes: "すべての投稿" allNotes: "すべての投稿"
followingList: "フォロー" followingList: "フォロー"
@ -1441,6 +1442,12 @@ _tutorial:
step1_2: 使い始める前に、いくつか設定を済ませまひょ。すぐできますえ。 step1_2: 使い始める前に、いくつか設定を済ませまひょ。すぐできますえ。
step2_1: 最初に、あんさんのプロフィールを作りまひょ step2_1: 最初に、あんさんのプロフィールを作りまひょ
step2_2: プロフィールを設定しはることで、他ん人があんさんの投稿を見たり、フォローしたりするときの助けになってます。 step2_2: プロフィールを設定しはることで、他ん人があんさんの投稿を見たり、フォローしたりするときの助けになってます。
step3_2: "あんさんのホームとソーシャルタイムラインは、どなたはんをフォローしはるかで決まります。ほな、いくつかアカウントをフォローしてみまひょ。\n\
プロフィールの右上にある、まあるい+ボタンをクリックしはるとフォローできますえ。"
step4_1: 投稿しとーみ
step5_1: タイムライン! 文字と写真の宝石箱や~
step5_2: うちのサーバーでは{timelines}種類のタイムラインをご用意しとります。
step4_2: 最初は{introduction}に投稿したり、シンプルに「ここは賑やかどすなぁ。うちはそこまで喋れまへんが、どうぞよろしゅうに」などと投稿しはる方もいてます。
_postForm: _postForm:
_placeholders: _placeholders:
b: なんかおましたか? b: なんかおましたか?
@ -1449,7 +1456,7 @@ _postForm:
d: なんや言いたいんちゃいますか? d: なんや言いたいんちゃいますか?
f: あんさん書くんを待っとるんどす... f: あんさん書くんを待っとるんどす...
a: いまなにしとん? a: いまなにしとん?
flagSpeakAsCat: 猫弁で話す flagSpeakAsCat: 猫弁で喋る
flagSpeakAsCatDescription: オンにすると、ワレの投稿の「な」を「にゃ」に変換したるで。 flagSpeakAsCatDescription: オンにすると、ワレの投稿の「な」を「にゃ」に変換したるで。
welcomeBackWithName: おおきに、{name}はん welcomeBackWithName: おおきに、{name}はん
migration: アカウントの引っ越し migration: アカウントの引っ越し

View file

@ -36,11 +36,11 @@ save: "Opslaan"
users: "Gebruikers" users: "Gebruikers"
addUser: "Toevoegen gebruiker" addUser: "Toevoegen gebruiker"
favorite: "Favorieten" favorite: "Favorieten"
favorites: "Toevoegen aan favorieten" favorites: "Favorieten"
unfavorite: "Verwijderen uit favorieten" unfavorite: "Verwijderen uit favorieten"
favorited: "Toegevoegd aan favorieten." favorited: "Toegevoegd aan favorieten."
alreadyFavorited: "Al toegevoegd aan favorieten" alreadyFavorited: "Al toegevoegd aan favorieten"
cantFavorite: "Kon niet toevoegen aan favorieten" cantFavorite: "Kon niet toevoegen aan favorieten."
pin: "Vastmaken aan profielpagina" pin: "Vastmaken aan profielpagina"
unpin: "Losmaken van profielpagina" unpin: "Losmaken van profielpagina"
copyContent: "Kopiëren inhoud" copyContent: "Kopiëren inhoud"
@ -302,7 +302,7 @@ nsfw: "NSFW"
whenServerDisconnected: "Wanneer de verbinding met de server wordt onderbroken" whenServerDisconnected: "Wanneer de verbinding met de server wordt onderbroken"
disconnectedFromServer: "Verbinding met de server onderbroken." disconnectedFromServer: "Verbinding met de server onderbroken."
inMb: "in megabytes" inMb: "in megabytes"
pinnedNotes: "Vastgemaakte notitie" pinnedNotes: "Vastgemaakte posts"
userList: "Lijsten" userList: "Lijsten"
aboutFirefish: "Over Firefish" aboutFirefish: "Over Firefish"
administrator: "Beheerder" administrator: "Beheerder"
@ -412,7 +412,7 @@ emoji: Emoji
selectList: Selecteer een lijst selectList: Selecteer een lijst
selectAntenna: Selecteer een antenne selectAntenna: Selecteer een antenne
deleted: Verwijderd deleted: Verwijderd
editNote: Bewerk notitie editNote: Bewerk post
edited: 'Bewerkt om {date} {time}' edited: 'Bewerkt om {date} {time}'
emojis: Emojis emojis: Emojis
emojiName: Emoji naam emojiName: Emoji naam
@ -682,3 +682,27 @@ serverLogs: Server logboek
deleteAll: Verwijder alles deleteAll: Verwijder alles
showFixedPostForm: Toon het post formulier bovenaan de tijdlijn showFixedPostForm: Toon het post formulier bovenaan de tijdlijn
newNoteRecived: Er zijn nieuwe posts newNoteRecived: Er zijn nieuwe posts
pinnedUsersDescription: Lijst gebruikersnamen gescheiden door regeleinden om vast
te pinnen in het tabblad "Verkennen".
silencedInstancesDescription: Geef de hostnames op van de servers die je het zwijgen
wilt opleggen. Accounts op de vermelde servers worden als "Stil" behandeld, kunnen
alleen volgverzoeken doen en kunnen geen lokale accounts vermelden als ze niet worden
gevolgd. Dit heeft geen invloed op de geblokkeerde servers.
searchPlaceholder: Doorzoek Firefish
pinnedPagesDescription: Voer de paden in van de pagina's die je aan de bovenste pagina
van deze server wilt vastmaken, gescheiden door regeleinden.
_permissions:
"read:favorites": Lijst van uw favorieten
"write:favorites": Beheer uw favorieten
clipsDesc: Paperclips zijn deelbare gebundelde favorieten. Je kunt paperclips maken
vanuit het menu van individuele posts.
selectChannel: Selecteer een kanaal
removeReaction: Uw reactie verwijderen
antennasDesc: "Antennes geven nieuwe berichten weer die voldoen aan de criteria die
je hebt ingesteld!\nZe zijn toegankelijk via de pagina Tijdlijnen."
pinnedClipId: ID van de paperclip om vast te pinnen
hiddenTagsDescription: 'Vermeld de hashtags (zonder #) van de hashtags die je wilt
verbergen voor trending en verkennen. Verborgen hashtags zijn nog steeds op andere
manieren te ontdekken.'
listsDesc: Met lijsten kun je tijdlijnen aanmaken met gespecificeerde gebruikers.
Ze zijn toegankelijk via de pagina Tijdlijnen.

View file

@ -16,10 +16,10 @@ noNotifications: "Bildirim bulunmuyor"
settings: "Ayarlar" settings: "Ayarlar"
basicSettings: "Temel Ayarlar" basicSettings: "Temel Ayarlar"
otherSettings: "Diğer Ayarlar" otherSettings: "Diğer Ayarlar"
openInWindow: "Bir pencere ile aç" openInWindow: "ılır pencerede aç"
profile: "Profil" profile: "Profil"
timeline: "Zaman çizelgesi" timeline: "Akış"
noAccountDescription: "Bu kullanıcı henüz kendi hakkında kısmını yazmadı." noAccountDescription: "Bu kullanıcı henüz \"hakkında\" kısmını yazmadı."
login: "Giriş Yap" login: "Giriş Yap"
logout: ıkış Yap" logout: ıkış Yap"
signup: "Kayıt Ol" signup: "Kayıt Ol"
@ -29,7 +29,7 @@ addUser: "Kullanıcı Ekle"
favorite: "Favorilere ekle" favorite: "Favorilere ekle"
favorites: "Favoriler" favorites: "Favoriler"
unfavorite: "Favorilerden Kaldır" unfavorite: "Favorilerden Kaldır"
favorited: "Favorilerime eklendi." favorited: "Favorilere eklendi."
alreadyFavorited: "Zaten favorilerinizde kayıtlı." alreadyFavorited: "Zaten favorilerinizde kayıtlı."
pin: "Sabitlenmiş" pin: "Sabitlenmiş"
unpin: "Sabitlemeyi kaldır" unpin: "Sabitlemeyi kaldır"
@ -41,9 +41,9 @@ deleteAndEditConfirm: "Bu gönderiyi silip yeniden düzenlemek istiyor musunuz?
ilişkin tüm tepkiler, destekler ve yanıtlar silinecektir." ilişkin tüm tepkiler, destekler ve yanıtlar silinecektir."
addToList: "Listeye ekle" addToList: "Listeye ekle"
sendMessage: "Mesaj Gönder" sendMessage: "Mesaj Gönder"
copyUsername: "Kullanıcı Adını Kopyala" copyUsername: "Kullanıcı Adını kopyala"
searchUser: "Kullanıcıları ara" searchUser: "Kullanıcıları ara"
pinned: "Sabitlenmiş" pinned: "Profile sabitle"
remove: "Sil" remove: "Sil"
smtpUser: "Kullanıcı Adı" smtpUser: "Kullanıcı Adı"
smtpPass: "Şifre" smtpPass: "Şifre"
@ -240,7 +240,7 @@ instance: Sunucu
fetchingAsApObject: Fediverse'den çekiliyor fetchingAsApObject: Fediverse'den çekiliyor
removeReaction: Tepkini sil removeReaction: Tepkini sil
rememberNoteVisibility: Gönderi görünürlüğü ayarlarını hatırla rememberNoteVisibility: Gönderi görünürlüğü ayarlarını hatırla
attachCancel: Eklentiyi kaldır attachCancel: Ek'i kaldır
suspend: Askıya Al suspend: Askıya Al
unsuspend: Askıya Almayı Kaldır unsuspend: Askıya Almayı Kaldır
unmute: Susturmayı Kaldır unmute: Susturmayı Kaldır
@ -248,13 +248,13 @@ blockConfirm: Bu hesabı engellemek istediğinize emin misiniz?
unblockConfirm: Bu hesabın engelini kaldırmak istediğinize emin misiniz? unblockConfirm: Bu hesabın engelini kaldırmak istediğinize emin misiniz?
settingGuide: Tavsiye edilen ayarlar settingGuide: Tavsiye edilen ayarlar
cacheRemoteFilesDescription: Bu ayar devre dışı bırakıldığında, uzak dosyalar doğrudan cacheRemoteFilesDescription: Bu ayar devre dışı bırakıldığında, uzak dosyalar doğrudan
uzak sunucudan yüklenir. Bunun devre dışı bırakılması depolama kullanımını azaltacak, dosyanın bulunduğu sunucudan yüklenir. Bunun devre dışı bırakılması depolama kullanımını
ancak küçük resimler oluşturulmayacağından trafiği artıracaktır. azaltacak, ancak küçük resimler oluşturulmayacağından trafiği artıracaktır.
flagAsCatDescription: Kedi kulaklarına sahip olacak ve bir kedi gibi konuşacaksın! flagAsCatDescription: Kedi kulaklarına sahip olacak ve bir kedi gibi konuşacaksın!
flagSpeakAsCat: Kedi gibi konuş flagSpeakAsCat: Kedi gibi konuş
setWallpaper: Arkaplanı ayarla setWallpaper: Arkaplanı ayarla
removeWallpaper: Arkaplanı sil removeWallpaper: Arkaplanı sil
operations: Operasyonlar operations: İşlemler
clearCachedFiles: Ön belleği temizle clearCachedFiles: Ön belleği temizle
clearCachedFilesConfirm: Önbelleğe alınan tüm uzak dosyaları silmek istediğinizden clearCachedFilesConfirm: Önbelleğe alınan tüm uzak dosyaları silmek istediğinizden
emin misiniz? emin misiniz?
@ -357,13 +357,13 @@ whatIsNew: Değişiklikleri göster
translate: Çevir translate: Çevir
breakFollow: Takipçiyi sil breakFollow: Takipçiyi sil
breakFollowConfirm: Takipçiyi kaldırmak istediğinizden emin misiniz? breakFollowConfirm: Takipçiyi kaldırmak istediğinizden emin misiniz?
unfollowConfirm: "{name}'i takibi bırakmak istediğinizden emin misiniz?" unfollowConfirm: "{name} kullanıcısını takip etmeyi bırakmak istediğinizden emin misiniz?"
importRequested: Bir içe aktarma isteğinde bulundunuz. Bu biraz zaman alabilir. importRequested: Bir içe aktarma isteğinde bulundunuz. Bu biraz zaman alabilir.
somethingHappened: Bir hata ile karşılaşıldı somethingHappened: Bir hata ile karşılaşıldı
retry: Tekrar Dene retry: Tekrar Dene
youShouldUpgradeClient: Bu sayfayı görüntülemek için, lütfen istemcinizi yenileyin. youShouldUpgradeClient: Bu sayfayı görüntülemek için, lütfen istemcinizi yenileyin.
reactionSetting: Tepki seçicide gösterilecek tepkiler reactionSetting: Tepki seçicide gösterilecek tepkiler
unmarkAsSensitive: NSFW işaretini kaldır unmarkAsSensitive: NSFW (Müstehcen İçerik) işaretini kaldır
enterFileName: Dosya adı gir enterFileName: Dosya adı gir
noJobs: Hiçbir iş yok noJobs: Hiçbir iş yok
instanceFollowing: Sunucuda takip ediliyor instanceFollowing: Sunucuda takip ediliyor
@ -481,8 +481,8 @@ mention: Bahset
download: İndir download: İndir
lists: Listeler lists: Listeler
noLists: Hiç listen yok noLists: Hiç listen yok
cantRenote: Bu gönderi yükseltilemez. cantRenote: Bu gönderi desteklenemez.
cantReRenote: Bir yükseltme tekrar yükseltilemez. cantReRenote: Bir destek tekrardan desteklenemez.
mute: Sustur mute: Sustur
block: Engelle block: Engelle
editWidgetsExit: Tamamlandı editWidgetsExit: Tamamlandı
@ -636,10 +636,10 @@ reactionSettingDescription2: Yeniden sıralamak için sürükleyin, silmek için
eklemek için "+"ya basın. eklemek için "+"ya basın.
you: Sen you: Sen
clickToShow: Görmek için tıkla clickToShow: Görmek için tıkla
sensitive: NSFW sensitive: NSFW (Müstehcen İçerik)
add: Ekle add: Ekle
reaction: Tepkiler reaction: Tepkiler
markAsSensitive: NSFW olarak işaretle markAsSensitive: NSFW (Müstehcen İçerik) olarak işaretle
unblock: Engeli Kaldır unblock: Engeli Kaldır
addAccount: Hesap ekle addAccount: Hesap ekle
network: İnternet network: İnternet
@ -722,11 +722,11 @@ moveAccountDescription: Bu süreç geri döndürülemez. Taşımadan önce yeni
şeklinde biçimlendirilmiş hesabın etiketini girin şeklinde biçimlendirilmiş hesabın etiketini girin
emojis: Emoji emojis: Emoji
flagAsCat: Kedi misin? 😺 flagAsCat: Kedi misin? 😺
selectChannel: Kanal seç selectChannel: Bir kanal seç
emojiName: Emoji adı emojiName: Emoji adı
showOnRemote: Orijinal sayfayı showOnRemote: Orijinal sayfayı
flagSpeakAsCatDescription: Gönderileriniz kedi modundayken miyavdirilecektir flagSpeakAsCatDescription: Gönderileriniz kedi modundayken miyavdirilecektir
flagShowTimelineReplies: Yanıtları zaman çizelgesinde göster flagShowTimelineReplies: Yanıtları akışta göster
silenceThisInstance: Bu sunucuyu sustur silenceThisInstance: Bu sunucuyu sustur
proxyAccountDescription: Vekil hesabı, belirli koşullar altında kullanıcılar için proxyAccountDescription: Vekil hesabı, belirli koşullar altında kullanıcılar için
uzaktan takipçi işlevi gören bir hesaptır. Örneğin, bir kullanıcı listeye bir uzak uzaktan takipçi işlevi gören bir hesaptır. Örneğin, bir kullanıcı listeye bir uzak
@ -845,8 +845,8 @@ pageLoadErrorDescription: Bu problem genelde ağ hataları veya tarayıcının
kaynaklanır. Önbelleği temizlemeyi deneyin ve biraz bekledikten sonra tekrar deneyin. kaynaklanır. Önbelleği temizlemeyi deneyin ve biraz bekledikten sonra tekrar deneyin.
quote: Alıntıla quote: Alıntıla
pinnedNote: Sabitlenmiş gönderi pinnedNote: Sabitlenmiş gönderi
renote: Yükselt renote: Destekle
unrenote: Yükseltmeyi geri al unrenote: Desteklemeyi geri al
emojiUrl: Emoji URL'si emojiUrl: Emoji URL'si
suspendConfirm: Bu hesabı askıya almak istediğinize emin misiniz? suspendConfirm: Bu hesabı askıya almak istediğinize emin misiniz?
addEmoji: Ekle addEmoji: Ekle
@ -858,7 +858,7 @@ wallpaper: Arkaplan
searchWith: 'Arat: {q}' searchWith: 'Arat: {q}'
youHaveNoLists: Hiçbir listen yok youHaveNoLists: Hiçbir listen yok
followConfirm: '{name} kullanıcısını takip etmek istediğine emin misin?' followConfirm: '{name} kullanıcısını takip etmek istediğine emin misin?'
metadata: Metadata metadata: Üstveri
monitor: Monitör monitor: Monitör
jobQueue: İş Sırası jobQueue: İş Sırası
noUsers: Kullanıcılar bulunamadı noUsers: Kullanıcılar bulunamadı
@ -1013,7 +1013,7 @@ incorrectPassword: Yanlış şifre.
voteConfirm: '"{choice}" için oyunuzu onaylıyor musunuz?' voteConfirm: '"{choice}" için oyunuzu onaylıyor musunuz?'
failedToFetchAccountInformation: Hesap bilgileri getirilemedi failedToFetchAccountInformation: Hesap bilgileri getirilemedi
rateLimitExceeded: Hız limiti aşıldı rateLimitExceeded: Hız limiti aşıldı
renotedBy: '{user} Yükseltti' renotedBy: '{user} destekledi'
host: Host host: Host
objectStorage: Nesne Depolaması objectStorage: Nesne Depolaması
objectStorageUseSSLDesc: API bağlantıları için HTTPS kullanmayacaksanız bunu kapatın objectStorageUseSSLDesc: API bağlantıları için HTTPS kullanmayacaksanız bunu kapatın
@ -1026,8 +1026,8 @@ verificationEmailSent: Bir doğrulama maili gönderildi. Doğrulamayı tamamlama
lütfen verilen bağlantıyı takip edin. lütfen verilen bağlantıyı takip edin.
hashtags: Etiketler hashtags: Etiketler
resolved: Çözüldü resolved: Çözüldü
flagShowTimelineRepliesDescription: ıksa, kullanıcıların zaman çizelgesindeki diğer flagShowTimelineRepliesDescription: ıksa, kullanıcıların akıştaki diğer kullanıcıların
kullanıcıların gönderilerine verdiği yanıtları gösterir. gönderilerine verdiği yanıtları gösterir.
clearQueueConfirmText: Kuyrukta kalan teslim edilmemiş gönderiler birleştirilmeyecektir. clearQueueConfirmText: Kuyrukta kalan teslim edilmemiş gönderiler birleştirilmeyecektir.
Genellikle bu işleme gerek yoktur. Genellikle bu işleme gerek yoktur.
image: Resim image: Resim
@ -1040,8 +1040,8 @@ unsuspendConfirm: Bu hesabın askıya almasını kaldırmak istediğinize emin m
selectList: Liste seç selectList: Liste seç
editWidgets: Widget'ları düzenle editWidgets: Widget'ları düzenle
showEmojisInReactionNotifications: Tepki bildirimlerinde emojileri göster showEmojisInReactionNotifications: Tepki bildirimlerinde emojileri göster
renoteMute: Yükseltmeleri sustur renoteMute: Desteklemeleri sustur
renoteUnmute: Yükseltmeleri susturmayı kaldır renoteUnmute: Desteklemelerde ki susturmayı kaldır
loginFailed: Giriş yapılamadı loginFailed: Giriş yapılamadı
proxyAccount: Vekil Hesap proxyAccount: Vekil Hesap
selectUser: Kullanıcı seç selectUser: Kullanıcı seç
@ -1068,7 +1068,7 @@ hideThisNote: Bu gönderiyi gizle
file: Dosya file: Dosya
enableEmojiReactions: Emoji tepkilerini aç enableEmojiReactions: Emoji tepkilerini aç
cw: İçerik uyarısı cw: İçerik uyarısı
makeFollowManuallyApprove: Onay gerektiren takip istekleri makeFollowManuallyApprove: Onayınızı gerektiren takip istekleri
today: Bugün today: Bugün
enableRecommendedTimeline: Tavsiye edilen zaman çizgisini aktive et enableRecommendedTimeline: Tavsiye edilen zaman çizgisini aktive et
state: Durum state: Durum
@ -1165,7 +1165,7 @@ indexFromDescription: Her gönderiyi dizine eklemek için boş bırakın
indexNotice: Şimdi indeksleniyor. Bu muhtemelen biraz zaman alacaktır, lütfen sunucunuzu indexNotice: Şimdi indeksleniyor. Bu muhtemelen biraz zaman alacaktır, lütfen sunucunuzu
en az bir saat yeniden başlatmayın. en az bir saat yeniden başlatmayın.
customKaTeXMacro: Özel KaTeX makroları customKaTeXMacro: Özel KaTeX makroları
directNotes: Direkt Mesajlar directNotes: Özel Mesajlar
import: İçeri Aktar import: İçeri Aktar
export: Dışarı Aktar export: Dışarı Aktar
mentions: Bahsetmeler mentions: Bahsetmeler
@ -1173,8 +1173,8 @@ files: Dosyalar
driveFileDeleteConfirm: '"{name}" dosyasını silmek istediğinizden emin misiniz? Dosyayı driveFileDeleteConfirm: '"{name}" dosyasını silmek istediğinizden emin misiniz? Dosyayı
"Ek" olarak içeren tüm gönderilerden kaldırılacaktır.' "Ek" olarak içeren tüm gönderilerden kaldırılacaktır.'
createList: Liste oluştur createList: Liste oluştur
listsDesc: Listeler, belirtilen kullanıcılarla zaman çizelgesi oluşturmanıza olanak listsDesc: Listeler, belirtilen kullanıcıların içeriklerini içeren akışlar oluşturmanıza
tanır. Zaman Çizelgesi sayfasından erişilebilirler. olanak tanır. Akış sayfasından erişilebilirler.
note: Gönder note: Gönder
enterListName: Liste için isim gir enterListName: Liste için isim gir
unfollow: Takipten Çık unfollow: Takipten Çık
@ -1183,14 +1183,14 @@ followRequestPending: Takip isteği bekleniyor
enterEmoji: Bir emoji gir enterEmoji: Bir emoji gir
followRequest: Takip İsteği followRequest: Takip İsteği
followRequests: Takip istekleri followRequests: Takip istekleri
renoted: Yükseldi. renoted: Desteklendi.
emoji: Emoji emoji: Emoji
cacheRemoteFiles: Uzak dosyaları önbelleğe al cacheRemoteFiles: Uzak dosyaları önbelleğe al
flagAsBot: Bu hesabı robot olarak işaretle flagAsBot: Bu hesabı robot olarak işaretle
flagAsBotDescription: Bu hesap bir program tarafından kontrol ediliyorsa bu seçeneği flagAsBotDescription: Bu hesap bir program tarafından kontrol ediliyorsa bu seçeneği
etkinleştirin. Etkinleştirilirse, diğer geliştiricilerin botlarıyla sonsuz etkileşim etkinleştirin. Etkinleştirilirse, diğer geliştiricilerin botlarıyla sonsuz etkileşim
zincirlerinin önlemesi ve Firefish'in dahili sistemlerinin bu hesabı bir bot olarak zincirlerinin önlemesi ve Firefish'in dahili sistemlerinin bu hesabı bir bot olarak
ele alacak şekilde ayarlaması için bir bayrak görevi görür. ele alacak şekilde ayarlaması için bir işaret görevi görür.
clearQueue: Sırayı Temizle clearQueue: Sırayı Temizle
hiddenTags: Gizlenmiş Etiketler hiddenTags: Gizlenmiş Etiketler
done: Tamamlandı done: Tamamlandı
@ -2156,3 +2156,4 @@ importZip: ZIP içe aktar
indexable: Endekslenebilir indexable: Endekslenebilir
languageForTranslation: Çeviri sonrası dili languageForTranslation: Çeviri sonrası dili
confirm: Onayla confirm: Onayla
clickToShowPatterns: Modülün örüntülerini göstermek için tıklayın

View file

@ -12,7 +12,7 @@ ok: "好"
gotIt: "知道了!" gotIt: "知道了!"
cancel: "取消" cancel: "取消"
enterUsername: "输入用户名" enterUsername: "输入用户名"
renotedBy: "转发自 {user}" renotedBy: "{user} 转发了"
noNotes: "没有帖子" noNotes: "没有帖子"
noNotifications: "没有通知" noNotifications: "没有通知"
instance: "服务器" instance: "服务器"
@ -58,7 +58,7 @@ followRequestAccepted: "关注请求已通过"
mention: "提及" mention: "提及"
mentions: "提及" mentions: "提及"
directNotes: "私信" directNotes: "私信"
importAndExport: "导入/导出数据" importAndExport: "导入 / 导出数据"
import: "导入" import: "导入"
export: "导出" export: "导出"
files: "文件" files: "文件"
@ -69,7 +69,7 @@ exportRequested: "导出请求已提交,这可能需要花一些时间,导
importRequested: "导入请求已提交,这可能需要花一点时间。" importRequested: "导入请求已提交,这可能需要花一点时间。"
lists: "列表" lists: "列表"
noLists: "列表为空" noLists: "列表为空"
note: "" note: "帖"
notes: "帖子" notes: "帖子"
following: "关注中" following: "关注中"
followers: "关注者" followers: "关注者"
@ -243,7 +243,7 @@ saved: "已保存"
messaging: "聊天" messaging: "聊天"
upload: "本地上传" upload: "本地上传"
keepOriginalUploading: "保留原图" keepOriginalUploading: "保留原图"
keepOriginalUploadingDescription: "上传图片时保留原始图片。如果关闭,会在上传时生成一张用于 web 发布的图片。" keepOriginalUploadingDescription: "上传图片时保留原始图片。如果关闭,会在上传时生成一张用于 Web 发布的图片。"
fromDrive: "从网盘中" fromDrive: "从网盘中"
fromUrl: "从 URL" fromUrl: "从 URL"
uploadFromUrl: "从 URL 上传" uploadFromUrl: "从 URL 上传"
@ -675,7 +675,7 @@ driveFilesCount: "网盘的文件数"
driveUsage: "网盘的空间用量" driveUsage: "网盘的空间用量"
noCrawle: "要求搜索引擎不索引该用户" noCrawle: "要求搜索引擎不索引该用户"
noCrawleDescription: "要求外部搜索引擎不收录(索引)您的内容。" noCrawleDescription: "要求外部搜索引擎不收录(索引)您的内容。"
lockedAccountInfo: "即使通过了关注请求,只要您不将帖子可见范围设置成“关注者”,任何人都可以看到您的帖子。" lockedAccountInfo: "即使通过了关注请求,只要您不将帖子可见范围设置成「关注者」,任何人都可以看到您的帖子。"
alwaysMarkSensitive: "默认将媒体文件标记为敏感内容" alwaysMarkSensitive: "默认将媒体文件标记为敏感内容"
loadRawImages: "加载原始图像而不是显示缩略图" loadRawImages: "加载原始图像而不是显示缩略图"
disableShowingAnimatedImages: "不播放动画" disableShowingAnimatedImages: "不播放动画"
@ -690,8 +690,8 @@ useSystemFont: "使用系统默认字体"
clips: "便签" clips: "便签"
experimentalFeatures: "实验性功能" experimentalFeatures: "实验性功能"
developer: "开发者" developer: "开发者"
makeExplorable: "使账号在“发现”中可见" makeExplorable: "使账号在「发现」中可见"
makeExplorableDescription: "关闭时,账号不会显示在\"发现\"中。" makeExplorableDescription: "关闭时,账号不会显示在「发现」中。"
showGapBetweenNotesInTimeline: "时间线上的帖子分开显示" showGapBetweenNotesInTimeline: "时间线上的帖子分开显示"
duplicate: "复制" duplicate: "复制"
left: "左" left: "左"
@ -823,8 +823,8 @@ makeReactionsPublicDescription: "将您发表过的回应设置成公开可见
classic: "居中" classic: "居中"
muteThread: "静音帖子串" muteThread: "静音帖子串"
unmuteThread: "取消静音帖子串" unmuteThread: "取消静音帖子串"
ffVisibility: "关注/关注者 可见性" ffVisibility: "关注 / 关注者可见性"
ffVisibilityDescription: "您可以设置谁可以看到您的关注/关注者信息。" ffVisibilityDescription: "您可以设置谁可以看到您的关注 / 关注者信息。"
continueThread: "查看更多帖子" continueThread: "查看更多帖子"
deleteAccountConfirm: "这将不可逆转地删除账号,是否继续?" deleteAccountConfirm: "这将不可逆转地删除账号,是否继续?"
incorrectPassword: "密码错误。" incorrectPassword: "密码错误。"
@ -922,7 +922,7 @@ _emailUnavailable:
_ffVisibility: _ffVisibility:
public: "公开" public: "公开"
followers: "仅对关注者可见" followers: "仅对关注者可见"
private: "私" private: "私"
_signup: _signup:
almostThere: "即将完成" almostThere: "即将完成"
emailAddressInfo: "请输入您所使用的电子邮件地址,它不会公开显示。" emailAddressInfo: "请输入您所使用的电子邮件地址,它不会公开显示。"
@ -1238,15 +1238,15 @@ _tutorial:
step4_2: "对于第一条帖子,可以做一个 {introduction} 或一个简单的 \"hello world!\"" step4_2: "对于第一条帖子,可以做一个 {introduction} 或一个简单的 \"hello world!\""
step5_1: "时间线,无处不在的时间线!" step5_1: "时间线,无处不在的时间线!"
step5_2: "您的服务器已启用 {timelines} 种不同的时间线。" step5_2: "您的服务器已启用 {timelines} 种不同的时间线。"
step5_3: "主页 {icon} 时间线是您可以看到您关注账号的帖子的时间线。" step5_3: "首页{icon}时间线是您可以看到您关注账号的帖子的时间线。"
step5_4: "本地{icon}时间线是您可以看到此服务器上其它用户的帖子的时间线。" step5_4: "本地{icon}时间线是您可以看到此服务器上其它用户的帖子的时间线。"
step5_5: "社交{icon}时间线是主页和本地时间线的结合。" step5_5: "社交{icon}时间线是主页和本地时间线的结合。"
step5_6: "推荐{icon}时间线是您可以看到管理员推荐服务器的帖子的时间线。" step5_6: "推荐{icon}时间线是您可以看到管理员推荐服务器的帖子的时间线。"
step5_7: "全{icon}时间线是您可以看到来自其它所有互联服务器的帖子的时间线。" step5_7: "全{icon}时间线是您可以看到来自其它所有互联服务器的帖子的时间线。"
step6_1: "那么,这里是什么地方?" step6_1: "那么,这里是什么地方?"
step6_2: "好吧,您不只是加入 Firefish。您已经加入了 Fediverse 的一个门户,这是一个由成千上万台服务器组成的互联网络。" step6_2: "好吧,您不只是加入 Firefish。您已经加入了 Fediverse 的一个门户,这是一个由成千上万台服务器组成的互联网络。"
step6_3: "每个服务器的工作方式不同,并不是所有的服务器都运行 Firefish。但这个服务器是的! 这有点复杂,但您很快就会明白的。" step6_3: "每个服务器的工作方式不同,并不是所有的服务器都运行 Firefish。但这个服务器是的! 这有点复杂,但您很快就会明白的。"
step6_4: "现在,去吧,去探索,去享受乐趣吧!" step6_4: "现在,去吧,去探索,去享受乐趣吧"
_2fa: _2fa:
alreadyRegistered: "您已经注册了两步验证设备。" alreadyRegistered: "您已经注册了两步验证设备。"
registerTOTP: "注册身份验证器应用" registerTOTP: "注册身份验证器应用"
@ -1918,7 +1918,7 @@ _skinTones:
isModerator: 监察员 isModerator: 监察员
isAdmin: 管理员 isAdmin: 管理员
findOtherInstance: 寻找其它服务器 findOtherInstance: 寻找其它服务器
moveFromDescription: 这将为您的旧账号设置一个别名,以便您可以从该旧账号迁移到当前账号。在从旧账号迁移之前执行此操作。请输入格式如@person@server.com moveFromDescription: 这将为您的旧账号设置一个别名,以便您可以从该旧账号迁移到当前账号。在从旧账号迁移之前执行此操作。请输入格式如 @person@server.com
的账号标签 的账号标签
indexPosts: 索引帖子 indexPosts: 索引帖子
signupsDisabled: 该服务器目前关闭注册,但您随时可以在另一台服务器上注册!如果您有该服务器的邀请码,请在下面输入。 signupsDisabled: 该服务器目前关闭注册,但您随时可以在另一台服务器上注册!如果您有该服务器的邀请码,请在下面输入。

View file

@ -458,7 +458,7 @@ youHaveNoGroups: "找不到群組"
joinOrCreateGroup: "請加入現有群組,或創建新群組。" joinOrCreateGroup: "請加入現有群組,或創建新群組。"
noHistory: "沒有歷史紀錄" noHistory: "沒有歷史紀錄"
signinHistory: "登入歷史" signinHistory: "登入歷史"
disableAnimatedMfm: "用MFM動畫" disableAnimatedMfm: "用MFM動畫"
doing: "正在處理..." doing: "正在處理..."
category: "類別" category: "類別"
tags: "標籤" tags: "標籤"
@ -596,7 +596,7 @@ emptyToDisableSmtpAuth: "留空使用者名稱及密碼以關閉SMTP驗證"
smtpSecure: "在 SMTP 連接中使用隱式 SSL/TLS" smtpSecure: "在 SMTP 連接中使用隱式 SSL/TLS"
smtpSecureInfo: "如使用STARTTLS請關閉" smtpSecureInfo: "如使用STARTTLS請關閉"
testEmail: "測試郵件發送" testEmail: "測試郵件發送"
wordMute: "被靜音的文字" wordMute: "被靜音的文字及語言"
regexpError: "正規表達式錯誤" regexpError: "正規表達式錯誤"
regexpErrorDescription: "{tab} 靜音文字的第 {line} 行的正規表達式有錯誤:" regexpErrorDescription: "{tab} 靜音文字的第 {line} 行的正規表達式有錯誤:"
instanceMute: "伺服器的靜音" instanceMute: "伺服器的靜音"
@ -765,7 +765,7 @@ user: "使用者"
administration: "管理" administration: "管理"
accounts: "帳戶" accounts: "帳戶"
switch: "切換" switch: "切換"
noMaintainerInformationWarning: "尚未設定管理員信息。" noMaintainerInformationWarning: "尚未設定管理員資訊。"
noBotProtectionWarning: "尚未設定Bot防護。" noBotProtectionWarning: "尚未設定Bot防護。"
configure: "設定" configure: "設定"
postToGallery: "發佈到相簿" postToGallery: "發佈到相簿"
@ -899,7 +899,7 @@ customKaTeXMacro: "自訂KaTeX巨集"
customKaTeXMacroDescription: "使用巨集來輕鬆輸入數學表達式吧!巨集的用法與 LaTeX 中的命令定義相同。你可以使用 \\newcommand{\\ customKaTeXMacroDescription: "使用巨集來輕鬆輸入數學表達式吧!巨集的用法與 LaTeX 中的命令定義相同。你可以使用 \\newcommand{\\
name}{content} 或 \\newcommand{\\name}[number of arguments]{content} 來輸入數學表達式。舉例來說,\\ name}{content} 或 \\newcommand{\\name}[number of arguments]{content} 來輸入數學表達式。舉例來說,\\
newcommand{\\add}[2]{#1 + #2} 會將 \\add{3}{foo} 展開為 3 + foo。巨集名稱除了可用大括號 {} 括起來之外,也可使用小括號 newcommand{\\add}[2]{#1 + #2} 會將 \\add{3}{foo} 展開為 3 + foo。巨集名稱除了可用大括號 {} 括起來之外,也可使用小括號
() 和中括號 [],但使用於巨集參數的括號會有所變更。每行只能夠定義一個巨集,巨集中間無法間換。無效的行將被忽略。只支援簡單字串的替換功能,不支援條件分歧的高級語法。" () 和中括號 [],但使用於巨集參數的括號會有所變更。每行只能夠定義一個巨集,巨集中間無法間換。無效的行將被忽略。只支援簡單字串的替換功能,不支援條件分歧的進階語法。"
enableCustomKaTeXMacro: "啟用自定義 KaTeX 宏" enableCustomKaTeXMacro: "啟用自定義 KaTeX 宏"
_sensitiveMediaDetection: _sensitiveMediaDetection:
description: "您可以使用機器學習自動檢測敏感媒體並將其用於審核。 伺服器的負荷會稍微增加。" description: "您可以使用機器學習自動檢測敏感媒體並將其用於審核。 伺服器的負荷會稍微增加。"
@ -932,7 +932,7 @@ _accountDelete:
inProgress: "正在刪除" inProgress: "正在刪除"
_ad: _ad:
back: "返回" back: "返回"
reduceFrequencyOfThisAd: "降低此廣告的頻率" reduceFrequencyOfThisAd: "降低此橫幅的頻率"
_forgotPassword: _forgotPassword:
enterEmail: "請輸入您的帳戶註冊的電子郵件地址。 密碼重置連結將被發送到該電子郵件地址。" enterEmail: "請輸入您的帳戶註冊的電子郵件地址。 密碼重置連結將被發送到該電子郵件地址。"
ifNoEmail: "如果您還沒有註冊您的電子郵件地址,請聯繫管理員。" ifNoEmail: "如果您還沒有註冊您的電子郵件地址,請聯繫管理員。"
@ -1027,7 +1027,7 @@ _mfm:
emoji: "自訂表情符號" emoji: "自訂表情符號"
emojiDescription: "您可以通過將自定義表情符號名稱括在冒號中來顯示自定義表情符號。" emojiDescription: "您可以通過將自定義表情符號名稱括在冒號中來顯示自定義表情符號。"
search: "搜尋" search: "搜尋"
searchDescription: "您可以顯示所輸入的搜索框。" searchDescription: "顯示含有指定文字的搜尋欄。"
flip: "翻轉" flip: "翻轉"
flipDescription: "將內容上下或左右翻轉。" flipDescription: "將內容上下或左右翻轉。"
jelly: "動畫(果凍)" jelly: "動畫(果凍)"
@ -1069,7 +1069,7 @@ _mfm:
alwaysPlay: 自動播放所有MFM動畫 alwaysPlay: 自動播放所有MFM動畫
positionDescription: 按指定數量移動內容。 positionDescription: 按指定數量移動內容。
advancedDescription: 如果停用僅顯示基礎MFM及正在播放的MFM動畫 advancedDescription: 如果停用僅顯示基礎MFM及正在播放的MFM動畫
advanced: 高級MFM advanced: 進階MFM
fade: 淡出 fade: 淡出
foreground: 文字顏色 foreground: 文字顏色
crop: 裁切 crop: 裁切
@ -1231,7 +1231,7 @@ _tutorial:
step3_1: "現在是時候追隨一些人了!" step3_1: "現在是時候追隨一些人了!"
step3_2: "你的主頁和社交時間線是基於你所追蹤的人,所以試著先追蹤幾個帳戶。\n點擊個人資料右上角的加號圈就可以關注它。" step3_2: "你的主頁和社交時間線是基於你所追蹤的人,所以試著先追蹤幾個帳戶。\n點擊個人資料右上角的加號圈就可以關注它。"
step4_1: "讓我們出去找你。" step4_1: "讓我們出去找你。"
step4_2: "對於他們的第一條信息,有些人喜歡做 {introduction} 或一個簡單的 \"hello world!\"" step4_2: "作為第一則貼文,有些人喜歡發 {introduction} 或單純發一個 \"hello world!\""
step5_1: "時間線,到處都是時間線!" step5_1: "時間線,到處都是時間線!"
step5_2: "您的伺服器已啟用了{timelines}個時間線。" step5_2: "您的伺服器已啟用了{timelines}個時間線。"
step5_3: "首頁 {icon} 時間線是顯示你追蹤的帳號的貼文。" step5_3: "首頁 {icon} 時間線是顯示你追蹤的帳號的貼文。"
@ -1816,7 +1816,7 @@ _deck:
secureMode: 安全模式(授權獲取) secureMode: 安全模式(授權獲取)
instanceSecurity: 伺服器安全性 instanceSecurity: 伺服器安全性
privateMode: 私人模式 privateMode: 私人模式
allowedInstances: 列入名單的伺服器 allowedInstances: 列入允許名單的伺服器
secureModeInfo: 當從其他伺服器請求時,不要在沒有證據的情況下發回。 secureModeInfo: 當從其他伺服器請求時,不要在沒有證據的情況下發回。
_messaging: _messaging:
dms: 私訊 dms: 私訊
@ -1824,8 +1824,8 @@ _messaging:
manageGroups: 管理群組 manageGroups: 管理群組
replayTutorial: 重新播放教程 replayTutorial: 重新播放教程
moveFromLabel: '您想遷移的舊帳戶:' moveFromLabel: '您想遷移的舊帳戶:'
customMOTDDescription: 每次用戶加載/重新加載頁面時,由換行符號分隔的 MOTD啟動畫面的自定信息將隨機顯示。 customMOTDDescription: 自訂MOTD(啟動畫面)訊息,一行一個。每次用戶載入/重新整理頁面時將會隨機顯示。
privateModeInfo: 啟用後,只有列入名單的伺服器才能與你的伺服器聯合。所有貼文都將對公眾隱藏。 privateModeInfo: 啟用後,只有列入允許名單的伺服器才能與你的伺服器聯合。所有貼文都將對公眾隱藏。
adminCustomCssWarn: 除非你知道它的作用,否則請不要使用此設定。 輸入不正確的值可能會導致每個人的客戶端無法正常運行。你可在你的的用戶設定中測試,確保你的 adminCustomCssWarn: 除非你知道它的作用,否則請不要使用此設定。 輸入不正確的值可能會導致每個人的客戶端無法正常運行。你可在你的的用戶設定中測試,確保你的
CSS 正常工作。 CSS 正常工作。
showUpdates: Firefish 更新時顯示彈出視窗 showUpdates: Firefish 更新時顯示彈出視窗
@ -1853,7 +1853,7 @@ enableEmojiReactions: 啟用表情符號反應
breakFollowConfirm: 您確定要移除該關注者嗎? breakFollowConfirm: 您確定要移除該關注者嗎?
socialTimeline: 社交時間軸 socialTimeline: 社交時間軸
cannotUploadBecauseExceedsFileSizeLimit: 因檔案太大而無法上傳。 cannotUploadBecauseExceedsFileSizeLimit: 因檔案太大而無法上傳。
customMOTD: 自定義MOTD (網頁載入時顯示的息) customMOTD: 自定義MOTD (網頁載入時顯示的息)
customSplashIcons: 啟動畫面圖標 (網址) customSplashIcons: 啟動畫面圖標 (網址)
splash: 啟動畫面 splash: 啟動畫面
updateAvailable: 可能有可用的更新! updateAvailable: 可能有可用的更新!
@ -1872,7 +1872,7 @@ _experiments:
title: 試驗功能 title: 試驗功能
enablePostImports: 啟用匯入貼文的功能 enablePostImports: 啟用匯入貼文的功能
findOtherInstance: 找找另一個伺服器 findOtherInstance: 找找另一個伺服器
noGraze: 瀏覽器擴展 "Graze for Mastodon" 會與Firefish發生衝突請停用該擴展 noGraze: 瀏覽器擴充元件 "Graze for Mastodon" 會與Firefish發生衝突請停用該擴充元件
userSaysSomethingReasonRenote: '{name} 轉發了包含 {reason} 的貼文' userSaysSomethingReasonRenote: '{name} 轉發了包含 {reason} 的貼文'
pushNotificationNotSupported: 你的瀏覽器或伺服器不支援推送通知 pushNotificationNotSupported: 你的瀏覽器或伺服器不支援推送通知
accessibility: 輔助功能 accessibility: 輔助功能
@ -1884,13 +1884,13 @@ deleted: 已刪除
editNote: 編輯貼文 editNote: 編輯貼文
edited: '於 {date} {time} 編輯' edited: '於 {date} {time} 編輯'
userSaysSomethingReason: '{name} 說了 {reason}' userSaysSomethingReason: '{name} 說了 {reason}'
allowedInstancesDescription: 要加入聯邦白名單的服務器,每台伺服器用新行分隔(僅適用於私有模式)。 allowedInstancesDescription: 允許聯邦的伺服器名單,一行一個(僅適用於私人模式)。
defaultReaction: 默認的表情符號反應 defaultReaction: 默認的表情符號反應
license: 授權 license: 授權
apps: 應用 apps: 應用
pushNotification: 推送通知 pushNotification: 推送通知
subscribePushNotification: 啟用推送通知 subscribePushNotification: 啟用推送通知
unsubscribePushNotification: 用推送通知 unsubscribePushNotification: 用推送通知
pushNotificationAlreadySubscribed: 推送通知已經啟用 pushNotificationAlreadySubscribed: 推送通知已經啟用
recommendedInstancesDescription: 以每行分隔的推薦伺服器出現在推薦的時間線中。 recommendedInstancesDescription: 以每行分隔的推薦伺服器出現在推薦的時間線中。
searchPlaceholder: 在 Firefish 上搜尋 searchPlaceholder: 在 Firefish 上搜尋
@ -1933,7 +1933,7 @@ isModerator: 板主
isAdmin: 管理員 isAdmin: 管理員
isPatron: Firefish 項目贊助者 isPatron: Firefish 項目贊助者
silencedWarning: 顯示此頁面是因為這些使用者來自您伺服器管理員已靜音的伺服器,因此他們可能是垃圾訊息。 silencedWarning: 顯示此頁面是因為這些使用者來自您伺服器管理員已靜音的伺服器,因此他們可能是垃圾訊息。
signupsDisabled: 該伺服器上的註冊當前已被禁用,但您隨時可以在另一台伺服器上註冊!或是您有該伺服器的邀請碼,請在下面輸入。 signupsDisabled: 此伺服器目前停止註冊,但您隨時可以在另一台伺服器上註冊!如果您有此伺服器的邀請碼,請在下面輸入。
showPopup: 通過彈出式視窗通知用戶 showPopup: 通過彈出式視窗通知用戶
showWithSparkles: 讓標題閃閃發光 showWithSparkles: 讓標題閃閃發光
youHaveUnreadAnnouncements: 您有未讀的公告 youHaveUnreadAnnouncements: 您有未讀的公告

View file

@ -1 +1 @@
2cd036b102edbf63fadb68e3841e4c912032f993 696d3c6255b3608a8de59fcac5aea3d08b2eeebe

View file

@ -1,18 +1,17 @@
{ {
"name": "firefish", "name": "firefish",
"version": "1.0.5-dev17", "version": "1.0.5-dev18",
"codename": "aqua", "codename": "aqua",
"repository": { "repository": {
"type": "git", "type": "git",
"url": "https://code.naskya.net/naskya/firefish" "url": "https://code.naskya.net/naskya/firefish"
}, },
"packageManager": "pnpm@8.7.6", "packageManager": "pnpm@8.8.0",
"private": true, "private": true,
"scripts": { "scripts": {
"rebuild": "pnpm run clean && ./scripts/build-greet.sh && pnpm --filter !sw -r --parallel run build && pnpm --filter sw run build && pnpm run gulp", "rebuild": "pnpm run clean && pnpm run build",
"build": "./scripts/build-greet.sh && pnpm --filter !sw -r --parallel run build && pnpm --filter sw run build && pnpm run gulp", "build": "./scripts/build-greet.sh && pnpm --filter firefish-js run build && pnpm --filter !firefish-js -r --parallel run build && pnpm run gulp",
"start": "pnpm --filter backend run start", "start": "pnpm --filter backend run start",
"start:test": "pnpm --filter backend run start:test",
"init": "pnpm run migrate", "init": "pnpm run migrate",
"migrate": "pnpm --filter backend run migrate", "migrate": "pnpm --filter backend run migrate",
"revertmigration": "pnpm --filter backend run revertmigration", "revertmigration": "pnpm --filter backend run revertmigration",
@ -58,7 +57,7 @@
"gulp-replace": "1.1.4", "gulp-replace": "1.1.4",
"gulp-terser": "2.1.0", "gulp-terser": "2.1.0",
"install-peers": "^1.0.4", "install-peers": "^1.0.4",
"pnpm": "8.7.1", "pnpm": "8.8.0",
"typescript": "5.2.2" "typescript": "5.2.2"
} }
} }

View file

@ -7,4 +7,3 @@ This directory contains all of the packages Firefish uses.
- `client`: Web interface written in Vue3 and TypeScript - `client`: Web interface written in Vue3 and TypeScript
- `sw`: Web [Service Worker](https://developer.mozilla.org/en-US/docs/Web/API/Service_Worker_API) written in TypeScript - `sw`: Web [Service Worker](https://developer.mozilla.org/en-US/docs/Web/API/Service_Worker_API) written in TypeScript
- `firefish-js`: TypeScript SDK for both backend and client, also published on [NPM](https://www.npmjs.com/package/firefish-js) for public use - `firefish-js`: TypeScript SDK for both backend and client, also published on [NPM](https://www.npmjs.com/package/firefish-js) for public use
- `megalodon`: TypeScript library used for partial Mastodon API compatibility

Binary file not shown.

Before

Width:  |  Height:  |  Size: 40 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 41 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 35 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

View file

@ -41,7 +41,7 @@
"prepublishOnly": "napi prepublish -t npm", "prepublishOnly": "napi prepublish -t npm",
"universal": "napi universal", "universal": "napi universal",
"version": "napi version", "version": "napi version",
"format": "cargo fmt --all -- --check", "format": "cargo fmt --all --",
"lint": "cargo clippy --fix --allow-dirty --allow-staged && cargo fmt --all -- --check" "lint": "cargo clippy --fix --allow-dirty --allow-staged && cargo fmt --all --"
} }
} }

View file

@ -85,7 +85,7 @@
"koa-send": "5.0.1", "koa-send": "5.0.1",
"koa-slow": "2.1.0", "koa-slow": "2.1.0",
"koa-views": "7.0.2", "koa-views": "7.0.2",
"megalodon": "workspace:*", "megalodon": "8.1.1",
"meilisearch": "0.34.1", "meilisearch": "0.34.1",
"mfm-js": "0.23.3", "mfm-js": "0.23.3",
"mime-types": "2.1.35", "mime-types": "2.1.35",

View file

@ -0,0 +1,11 @@
import { detect } from "tinyld";
import * as mfm from "mfm-js";
export default function detectLanguage(text: string): string {
const nodes = mfm.parse(text);
const filtered = mfm.extract(nodes, (node) => {
return node.type === "text" || node.type === "quote";
});
const purified = mfm.toString(filtered);
return detect(purified);
}

View file

@ -1,28 +1,31 @@
export function nyaize(text: string): string { export function nyaize(text: string, lang?: string): string {
return ( text = text
text // ja-JP
// ja-JP .replaceAll("な", "にゃ")
.replaceAll("な", "にゃ") .replaceAll("ナ", "ニャ")
.replaceAll("ナ", "ニャ") .replaceAll("ナ", "ニャ")
.replaceAll("ナ", "ニャ") // en-US
// en-US .replace(/(?<=n)a/gi, (x) => (x === "A" ? "YA" : "ya"))
.replace(/(?<=n)a/gi, (x) => (x === "A" ? "YA" : "ya")) .replace(/(?<=morn)ing/gi, (x) => (x === "ING" ? "YAN" : "yan"))
.replace(/(?<=morn)ing/gi, (x) => (x === "ING" ? "YAN" : "yan")) .replace(/(?<=every)one/gi, (x) => (x === "ONE" ? "NYAN" : "nyan"))
.replace(/(?<=every)one/gi, (x) => (x === "ONE" ? "NYAN" : "nyan")) .replace(/non(?=[bcdfghjklmnpqrstvwxyz])/gi, (x) =>
.replace(/non(?=[bcdfghjklmnpqrstvwxyz])/gi, (x) => x === "NON" ? "NYAN" : "nyan",
x === "NON" ? "NYAN" : "nyan", )
) // ko-KR
// ko-KR .replace(/[나-낳]/g, (match) =>
.replace(/[나-낳]/g, (match) => String.fromCharCode(
String.fromCharCode( match.charCodeAt(0)! + "냐".charCodeAt(0) - "나".charCodeAt(0),
match.charCodeAt(0)! + "냐".charCodeAt(0) - "나".charCodeAt(0), ),
), )
) .replace(/(다$)|(다(?=\.))|(다(?= ))|(다(?=!))|(다(?=\?))/gm, "다냥")
.replace(/(다$)|(다(?=\.))|(다(?= ))|(다(?=!))|(다(?=\?))/gm, "다냥") .replace(/(야(?=\?))|(야$)|(야(?= ))/gm, "냥")
.replace(/(야(?=\?))|(야$)|(야(?= ))/gm, "냥") // el-GR
// el-GR .replaceAll("να", "νια")
.replaceAll("να", "νια") .replaceAll("ΝΑ", "ΝΙΑ")
.replaceAll("ΝΑ", "ΝΙΑ") .replaceAll("Να", "Νια");
.replaceAll("Να", "Νια")
); // zh-CN, zh-TW
if (lang === "zh") text = text.replace(/(妙|庙|描|渺|瞄|秒|苗|藐|廟)/g, "喵");
return text;
} }

View file

@ -4,11 +4,6 @@ import { Emojis } from "@/models/index.js";
import { toPunyNullable } from "./convert-host.js"; import { toPunyNullable } from "./convert-host.js";
import { IsNull } from "typeorm"; import { IsNull } from "typeorm";
export async function getFallbackReaction() {
const meta = await fetchMeta();
return meta.defaultReaction;
}
export function convertReactions(reactions: Record<string, number>) { export function convertReactions(reactions: Record<string, number>) {
const result = new Map(); const result = new Map();
@ -26,11 +21,11 @@ export async function toDbReaction(
reaction?: string | null, reaction?: string | null,
reacterHost?: string | null, reacterHost?: string | null,
): Promise<string> { ): Promise<string> {
if (!reaction) return await getFallbackReaction(); if (!reaction) return (await fetchMeta()).defaultReaction;
reacterHost = toPunyNullable(reacterHost); reacterHost = toPunyNullable(reacterHost);
if (reaction === "♥️") return "❤️"; if (reaction.includes("❤") || reaction.includes("♥️")) return "❤️";
// Allow unicode reactions // Allow unicode reactions
const match = emojiRegex.exec(reaction); const match = emojiRegex.exec(reaction);
@ -50,7 +45,7 @@ export async function toDbReaction(
if (emoji) return reacterHost ? `:${name}@${reacterHost}:` : `:${name}:`; if (emoji) return reacterHost ? `:${name}@${reacterHost}:` : `:${name}:`;
} }
return await getFallbackReaction(); return (await fetchMeta()).defaultReaction;
} }
type DecodedReaction = { type DecodedReaction = {

View file

@ -162,7 +162,7 @@ export class Meta {
@Column("varchar", { @Column("varchar", {
length: 512, length: 512,
nullable: true, nullable: true,
default: "/static-assets/badges/info.png", default: "/static-assets/badges/info.webp",
}) })
public mascotImageUrl: string | null; public mascotImageUrl: string | null;
@ -187,7 +187,7 @@ export class Meta {
@Column("varchar", { @Column("varchar", {
length: 512, length: 512,
nullable: true, nullable: true,
default: "/static-assets/badges/error.png", default: "/static-assets/badges/error.webp",
}) })
public errorImageUrl: string | null; public errorImageUrl: string | null;

View file

@ -23,7 +23,6 @@ import {
} from "@/misc/populate-emojis.js"; } from "@/misc/populate-emojis.js";
import { db } from "@/db/postgre.js"; import { db } from "@/db/postgre.js";
import { IdentifiableError } from "@/misc/identifiable-error.js"; import { IdentifiableError } from "@/misc/identifiable-error.js";
import { detect as detectLanguage } from "tinyld";
export async function populatePoll(note: Note, meId: User["id"] | null) { export async function populatePoll(note: Note, meId: User["id"] | null) {
const poll = await Polls.findOneByOrFail({ noteId: note.id }); const poll = await Polls.findOneByOrFail({ noteId: note.id });
@ -265,7 +264,8 @@ export const NoteRepository = db.getRepository(Note).extend({
const tokens = packed.text ? mfm.parse(packed.text) : []; const tokens = packed.text ? mfm.parse(packed.text) : [];
function nyaizeNode(node: mfm.MfmNode) { function nyaizeNode(node: mfm.MfmNode) {
if (node.type === "quote") return; if (node.type === "quote") return;
if (node.type === "text") node.props.text = nyaize(node.props.text); if (node.type === "text")
node.props.text = nyaize(node.props.text, packed.lang);
if (node.children) { if (node.children) {
for (const child of node.children) { for (const child of node.children) {

View file

@ -24,7 +24,7 @@ export const packedUserLiteSchema = {
type: "string", type: "string",
nullable: true, nullable: true,
optional: false, optional: false,
example: "misskey.example.com", example: "firefish.example.com",
description: "The local host is represented with `null`.", description: "The local host is represented with `null`.",
}, },
avatarUrl: { avatarUrl: {

View file

@ -1,12 +1,12 @@
import { In, IsNull } from "typeorm"; import { In, IsNull } from "typeorm";
import { detect as detectLanguage } from "tinyld";
import config from "@/config/index.js"; import config from "@/config/index.js";
import type { Note, IMentionedRemoteUsers } from "@/models/entities/note.js"; import type { Note, IMentionedRemoteUsers } from "@/models/entities/note.js";
import type { DriveFile } from "@/models/entities/drive-file.js"; import type { DriveFile } from "@/models/entities/drive-file.js";
import { DriveFiles, Notes, Users, Emojis, Polls } from "@/models/index.js"; import { DriveFiles, Notes, Users, Emojis, Polls } from "@/models/index.js";
import type { Emoji } from "@/models/entities/emoji.js"; import type { Emoji } from "@/models/entities/emoji.js";
import type { Poll } from "@/models/entities/poll.js"; import type { Poll } from "@/models/entities/poll.js";
import toHtml from "../misc/get-note-html.js"; import toHtml from "@/remote/activitypub/misc/get-note-html.js";
import detectLanguage from "@/misc/detect-language.js";
import renderEmoji from "./emoji.js"; import renderEmoji from "./emoji.js";
import renderMention from "./mention.js"; import renderMention from "./mention.js";
import renderHashtag from "./hashtag.js"; import renderHashtag from "./hashtag.js";

View file

@ -64,7 +64,7 @@ export const meta = {
type: "string", type: "string",
optional: false, optional: false,
nullable: false, nullable: false,
default: "/static-assets/badges/info.png", default: "/static-assets/badges/info.webp",
}, },
bannerUrl: { bannerUrl: {
type: "string", type: "string",
@ -75,7 +75,7 @@ export const meta = {
type: "string", type: "string",
optional: false, optional: false,
nullable: false, nullable: false,
default: "/static-assets/badges/error.png", default: "/static-assets/badges/error.webp",
}, },
iconUrl: { iconUrl: {
type: "string", type: "string",

View file

@ -49,7 +49,7 @@ export default define(meta, paramDef, async (ps) => {
createNotification(user.id, "app", { createNotification(user.id, "app", {
customBody: ps.comment, customBody: ps.comment,
customHeader: "Moderation Notice", customHeader: "Moderation Notice",
customIcon: "/static-assets/badges/info.png", customIcon: "/static-assets/badges/info.webp",
}); });
setImmediate(async () => { setImmediate(async () => {

View file

@ -155,7 +155,7 @@ export const meta = {
type: "string", type: "string",
optional: false, optional: false,
nullable: false, nullable: false,
default: "/static-assets/badges/info.png", default: "/static-assets/badges/info.webp",
}, },
bannerUrl: { bannerUrl: {
type: "string", type: "string",
@ -166,7 +166,7 @@ export const meta = {
type: "string", type: "string",
optional: false, optional: false,
nullable: false, nullable: false,
default: "/static-assets/badges/error.png", default: "/static-assets/badges/error.webp",
}, },
iconUrl: { iconUrl: {
type: "string", type: "string",

View file

@ -35,8 +35,8 @@ import renderUpdate from "@/remote/activitypub/renderer/update.js";
import { deliverToRelays } from "@/services/relay.js"; import { deliverToRelays } from "@/services/relay.js";
// import { deliverQuestionUpdate } from "@/services/note/polls/update.js"; // import { deliverQuestionUpdate } from "@/services/note/polls/update.js";
import { fetchMeta } from "@/misc/fetch-meta.js"; import { fetchMeta } from "@/misc/fetch-meta.js";
import { detect as detectLanguage } from "tinyld";
import { langmap } from "@/misc/langmap.js"; import { langmap } from "@/misc/langmap.js";
import detectLanguage from "@/misc/detect-language.js";
export const meta = { export const meta = {
tags: ["notes"], tags: ["notes"],

View file

@ -62,6 +62,7 @@ export const paramDef = {
type: "string", type: "string",
default: "chronological", default: "chronological",
nullable: true, nullable: true,
description: "Either 'chronological' or 'relevancy'",
}, },
}, },
required: ["query"], required: ["query"],
@ -75,9 +76,11 @@ export default define(meta, paramDef, async (ps, me) => {
ps.untilId, ps.untilId,
); );
if (ps.userId) { if (ps.userId != null) {
query.andWhere("note.userId = :userId", { userId: ps.userId }); query.andWhere("note.userId = :userId", { userId: ps.userId });
} else if (ps.channelId) { }
if (ps.channelId != null) {
query.andWhere("note.channelId = :channelId", { query.andWhere("note.channelId = :channelId", {
channelId: ps.channelId, channelId: ps.channelId,
}); });

View file

@ -24,7 +24,11 @@ export function getClient(
const accessTokenArr = authorization?.split(" ") ?? [null]; const accessTokenArr = authorization?.split(" ") ?? [null];
const accessToken = accessTokenArr[accessTokenArr.length - 1]; const accessToken = accessTokenArr[accessTokenArr.length - 1];
const generator = (megalodon as any).default; const generator = (megalodon as any).default;
const client = generator(BASE_URL, accessToken) as MegalodonInterface; const client = generator(
"firefish",
BASE_URL,
accessToken,
) as MegalodonInterface;
return client; return client;
} }

View file

@ -68,7 +68,7 @@ export function apiAuthMastodon(router: Router): void {
website: body.website, website: body.website,
redirect_uri: red, redirect_uri: red,
client_id: Buffer.from(appData.url || "").toString("base64"), client_id: Buffer.from(appData.url || "").toString("base64"),
client_secret: appData.clientSecret, client_secret: appData.client_secret,
}; };
console.log(returns); console.log(returns);
ctx.body = returns; ctx.body = returns;

View file

@ -1,8 +1,7 @@
import megalodon, { MegalodonInterface } from "megalodon";
import Router from "@koa/router"; import Router from "@koa/router";
import { getClient } from "../ApiMastodonCompatibleService.js"; import { getClient } from "../ApiMastodonCompatibleService.js";
import axios from "axios"; import axios from "axios";
import { Converter } from "megalodon"; import Converter from "megalodon";
import { convertTimelinesArgsId, limitToInt } from "./timeline.js"; import { convertTimelinesArgsId, limitToInt } from "./timeline.js";
import { convertAccount, convertStatus } from "../converters.js"; import { convertAccount, convertStatus } from "../converters.js";

View file

@ -12,6 +12,7 @@ import {
convertPoll, convertPoll,
convertStatus, convertStatus,
} from "../converters.js"; } from "../converters.js";
import { fetchMeta } from "@/misc/fetch-meta.js";
function normalizeQuery(data: any) { function normalizeQuery(data: any) {
const str = querystring.stringify(data); const str = querystring.stringify(data);
@ -216,10 +217,11 @@ export function apiStatusMastodon(router: Router): void {
router.post<{ Params: { id: string } }>( router.post<{ Params: { id: string } }>(
"/v1/statuses/:id/favourite", "/v1/statuses/:id/favourite",
async (ctx) => { async (ctx) => {
const meta = await fetchMeta();
const BASE_URL = `${ctx.protocol}://${ctx.hostname}`; const BASE_URL = `${ctx.protocol}://${ctx.hostname}`;
const accessTokens = ctx.headers.authorization; const accessTokens = ctx.headers.authorization;
const client = getClient(BASE_URL, accessTokens); const client = getClient(BASE_URL, accessTokens);
const react = await getFirstReaction(BASE_URL, accessTokens); const react = meta.defaultReaction;
try { try {
const a = (await client.createEmojiReaction( const a = (await client.createEmojiReaction(
convertId(ctx.params.id, IdType.FirefishId), convertId(ctx.params.id, IdType.FirefishId),
@ -238,10 +240,11 @@ export function apiStatusMastodon(router: Router): void {
router.post<{ Params: { id: string } }>( router.post<{ Params: { id: string } }>(
"/v1/statuses/:id/unfavourite", "/v1/statuses/:id/unfavourite",
async (ctx) => { async (ctx) => {
const meta = await fetchMeta();
const BASE_URL = `${ctx.protocol}://${ctx.hostname}`; const BASE_URL = `${ctx.protocol}://${ctx.hostname}`;
const accessTokens = ctx.headers.authorization; const accessTokens = ctx.headers.authorization;
const client = getClient(BASE_URL, accessTokens); const client = getClient(BASE_URL, accessTokens);
const react = await getFirstReaction(BASE_URL, accessTokens); const react = meta.defaultReaction;
try { try {
const data = await client.deleteEmojiReaction( const data = await client.deleteEmojiReaction(
convertId(ctx.params.id, IdType.FirefishId), convertId(ctx.params.id, IdType.FirefishId),
@ -377,7 +380,7 @@ export function apiStatusMastodon(router: Router): void {
const accessTokens = ctx.headers.authorization; const accessTokens = ctx.headers.authorization;
const client = getClient(BASE_URL, accessTokens); const client = getClient(BASE_URL, accessTokens);
try { try {
const data = await client.reactStatus( const data = await client.createEmojiReaction(
convertId(ctx.params.id, IdType.FirefishId), convertId(ctx.params.id, IdType.FirefishId),
ctx.params.name, ctx.params.name,
); );
@ -397,7 +400,7 @@ export function apiStatusMastodon(router: Router): void {
const accessTokens = ctx.headers.authorization; const accessTokens = ctx.headers.authorization;
const client = getClient(BASE_URL, accessTokens); const client = getClient(BASE_URL, accessTokens);
try { try {
const data = await client.unreactStatus( const data = await client.deleteEmojiReaction(
convertId(ctx.params.id, IdType.FirefishId), convertId(ctx.params.id, IdType.FirefishId),
ctx.params.name, ctx.params.name,
); );
@ -476,25 +479,3 @@ export function apiStatusMastodon(router: Router): void {
}, },
); );
} }
async function getFirstReaction(
BASE_URL: string,
accessTokens: string | undefined,
) {
const accessTokenArr = accessTokens?.split(" ") ?? [null];
const accessToken = accessTokenArr[accessTokenArr.length - 1];
let react = "⭐";
try {
const api = await axios.post(`${BASE_URL}/api/i/registry/get-unsecure`, {
scope: ["client", "base"],
key: "reactions",
i: accessToken,
});
const reactRaw = api.data;
react = Array.isArray(reactRaw) ? api.data[0] : "⭐";
console.log(api.data);
return react;
} catch (e) {
return react;
}
}

View file

@ -25,7 +25,7 @@ import { readNotification } from "../common/read-notification.js";
import channels from "./channels/index.js"; import channels from "./channels/index.js";
import type Channel from "./channel.js"; import type Channel from "./channel.js";
import type { StreamEventEmitter, StreamMessages } from "./types.js"; import type { StreamEventEmitter, StreamMessages } from "./types.js";
import { Converter } from "megalodon"; import Converter from "megalodon";
import { getClient } from "../mastodon/ApiMastodonCompatibleService.js"; import { getClient } from "../mastodon/ApiMastodonCompatibleService.js";
/** /**

View file

@ -163,11 +163,10 @@ mastoRouter.post("/oauth/token", async (ctx) => {
ctx.body = ret; ctx.body = ret;
return; return;
} }
let client_id: any = body.client_id; let client_id: Array<string> | string | null = body.client_id;
const BASE_URL = `${ctx.request.protocol}://${ctx.request.hostname}`; const BASE_URL = `${ctx.request.protocol}://${ctx.request.hostname}`;
const generator = (megalodon as any).default; const generator = (megalodon as any).default;
const client = generator(BASE_URL, null) as MegalodonInterface; const client = generator("firefish", BASE_URL, null) as MegalodonInterface;
let m = null;
let token = null; let token = null;
if (body.code) { if (body.code) {
//m = body.code.match(/^([a-zA-Z0-9]{8})([a-zA-Z0-9]{4})([a-zA-Z0-9]{4})([a-zA-Z0-9]{4})([a-zA-Z0-9]{12})/); //m = body.code.match(/^([a-zA-Z0-9]{8})([a-zA-Z0-9]{4})([a-zA-Z0-9]{4})([a-zA-Z0-9]{4})([a-zA-Z0-9]{12})/);
@ -191,7 +190,7 @@ mastoRouter.post("/oauth/token", async (ctx) => {
token ? token : "", token ? token : "",
); );
const ret = { const ret = {
access_token: atData.accessToken, access_token: atData.access_token,
token_type: "Bearer", token_type: "Bearer",
scope: body.scope || "read write follow push", scope: body.scope || "read write follow push",
created_at: Math.floor(new Date().getTime() / 1000), created_at: Math.floor(new Date().getTime() / 1000),

View file

@ -1,7 +1,18 @@
/* atkinson-hyperlegible-regular - latin_latin-ext */
@font-face {
font-display: swap; /* Check https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-display for other options. */
font-family: "Atkinson Hyperlegible";
font-style: normal;
font-weight: 400;
src: url("/static-assets/fonts/atkinson-hyperlegible-v11-latin_latin-ext-regular.woff2")
format("woff2"); /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */
}
html { html {
background-color: var(--bg); background-color: var(--bg);
color: var(--fg); color: var(--fg);
} }
@media (prefers-color-scheme: dark) { @media (prefers-color-scheme: dark) {
html { html {
--bg: rgb(17, 17, 27); --bg: rgb(17, 17, 27);
@ -104,7 +115,7 @@ html {
} }
} }
@media(prefers-reduced-motion) { @media (prefers-reduced-motion) {
#splashSpinner { #splashSpinner {
display: block; display: block;
} }
@ -122,5 +133,5 @@ html {
height: 0; height: 0;
text-align: center; text-align: center;
padding-top: 100px; padding-top: 100px;
font-family: sans-serif; font-family: "Atkinson Hyperlegible", sans-serif;
} }

View file

@ -36,9 +36,9 @@ html
link(rel='icon' href= icon || `/favicon.ico?${ timestamp }`) link(rel='icon' href= icon || `/favicon.ico?${ timestamp }`)
link(rel='apple-touch-icon' href= icon || `/apple-touch-icon.png?${ timestamp }`) link(rel='apple-touch-icon' href= icon || `/apple-touch-icon.png?${ timestamp }`)
link(rel='manifest' href='/manifest.json') link(rel='manifest' href='/manifest.json')
link(rel='prefetch' href=`/static-assets/badges/info.png?${ timestamp }`) link(rel='prefetch' href=`/static-assets/badges/info.webp?${ timestamp }`)
link(rel='prefetch' href=`/static-assets/badges/not-found.png?${ timestamp }`) link(rel='prefetch' href=`/static-assets/badges/not-found.webp?${ timestamp }`)
link(rel='prefetch' href=`/static-assets/badges/error.png?${ timestamp }`) link(rel='prefetch' href=`/static-assets/badges/error.webp?${ timestamp }`)
link(rel='stylesheet' href=`/static-assets/instance.css?${ timestamp }`) link(rel='stylesheet' href=`/static-assets/instance.css?${ timestamp }`)
link(rel='modulepreload' href=`/assets/${clientEntry.file}`) link(rel='modulepreload' href=`/assets/${clientEntry.file}`)

View file

@ -88,7 +88,7 @@ async function save(
if (type === "image/png") ext = ".png"; if (type === "image/png") ext = ".png";
if (type === "image/webp") ext = ".webp"; if (type === "image/webp") ext = ".webp";
if (type === "image/apng") ext = ".apng"; if (type === "image/apng") ext = ".apng";
if (type === "image/avif") ext = ".avif"; if (type === "image/avif") ext = ".webp";
if (type === "image/vnd.mozilla.apng") ext = ".apng"; if (type === "image/vnd.mozilla.apng") ext = ".apng";
} }

View file

@ -59,11 +59,11 @@ import type { UserProfile } from "@/models/entities/user-profile.js";
import { db } from "@/db/postgre.js"; import { db } from "@/db/postgre.js";
import { getActiveWebhooks } from "@/misc/webhook-cache.js"; import { getActiveWebhooks } from "@/misc/webhook-cache.js";
import { shouldSilenceInstance } from "@/misc/should-block-instance.js"; import { shouldSilenceInstance } from "@/misc/should-block-instance.js";
import meilisearch from "../../db/meilisearch.js"; import meilisearch from "@/db/meilisearch.js";
import { redisClient } from "@/db/redis.js"; import { redisClient } from "@/db/redis.js";
import { Mutex } from "redis-semaphore"; import { Mutex } from "redis-semaphore";
import { detect as detectLanguage } from "tinyld";
import { langmap } from "@/misc/langmap.js"; import { langmap } from "@/misc/langmap.js";
import detectLanguage from "@/misc/detect-language.js";
const mutedWordsCache = new Cache< const mutedWordsCache = new Cache<
{ userId: UserProfile["userId"]; mutedWords: UserProfile["mutedWords"] }[] { userId: UserProfile["userId"]; mutedWords: UserProfile["mutedWords"] }[]

View file

@ -43,10 +43,10 @@
"chartjs-plugin-zoom": "2.0.1", "chartjs-plugin-zoom": "2.0.1",
"city-timezones": "^1.2.1", "city-timezones": "^1.2.1",
"compare-versions": "6.1.0", "compare-versions": "6.1.0",
"cropperjs": "2.0.0-beta.2", "cropperjs": "2.0.0-beta.4",
"cross-env": "7.0.3", "cross-env": "7.0.3",
"date-fns": "2.30.0", "date-fns": "2.30.0",
"emojilib": "github:thatonecalculator/emojilib", "emojilib": "^3.0.11",
"escape-regexp": "0.0.1", "escape-regexp": "0.0.1",
"eslint-config-prettier": "9.0.0", "eslint-config-prettier": "9.0.0",
"eslint-plugin-file-progress": "^1.3.0", "eslint-plugin-file-progress": "^1.3.0",

View file

@ -1,5 +1,5 @@
import { defineAsyncComponent, reactive } from "vue"; import { defineAsyncComponent, reactive } from "vue";
import type * as misskey from "firefish-js"; import type * as firefish from "firefish-js";
import { i18n } from "./i18n"; import { i18n } from "./i18n";
import { del, get, set } from "@/scripts/idb-proxy"; import { del, get, set } from "@/scripts/idb-proxy";
import { apiUrl } from "@/config"; import { apiUrl } from "@/config";
@ -8,7 +8,7 @@ import { reloadChannel, unisonReload } from "@/scripts/unison-reload";
// TODO: 他のタブと永続化されたstateを同期 // TODO: 他のタブと永続化されたstateを同期
type Account = misskey.entities.MeDetailed; type Account = firefish.entities.MeDetailed;
const accountData = localStorage.getItem("account"); const accountData = localStorage.getItem("account");
@ -98,9 +98,9 @@ function fetchAccount(token: string): Promise<Account> {
.then((res) => { .then((res) => {
if (res.error) { if (res.error) {
if (res.error.id === "a8c724b3-6e9c-4b46-b1a8-bc3ed6258370") { if (res.error.id === "a8c724b3-6e9c-4b46-b1a8-bc3ed6258370") {
showSuspendedDialog().then(() => { showSuspendedDialog();
signout(); signout();
}); return;
} else { } else {
alert({ alert({
type: "error", type: "error",
@ -117,6 +117,14 @@ function fetchAccount(token: string): Promise<Account> {
}); });
} }
function showSuspendedDialog() {
alert({
type: "error",
title: i18n.ts.yourAccountSuspendedTitle,
text: i18n.ts.yourAccountSuspendedDescription,
});
}
export function updateAccount(accountData) { export function updateAccount(accountData) {
for (const [key, value] of Object.entries(accountData)) { for (const [key, value] of Object.entries(accountData)) {
$i[key] = value; $i[key] = value;
@ -151,8 +159,8 @@ export async function openAccountMenu(
opts: { opts: {
includeCurrentAccount?: boolean; includeCurrentAccount?: boolean;
withExtraOperation: boolean; withExtraOperation: boolean;
active?: misskey.entities.UserDetailed["id"]; active?: firefish.entities.UserDetailed["id"];
onChoose?: (account: misskey.entities.UserDetailed) => void; onChoose?: (account: firefish.entities.UserDetailed) => void;
}, },
ev: MouseEvent, ev: MouseEvent,
isMobile?: boolean, isMobile?: boolean,
@ -185,7 +193,7 @@ export async function openAccountMenu(
); );
} }
async function switchAccount(account: misskey.entities.UserDetailed) { async function switchAccount(account: firefish.entities.UserDetailed) {
const storedAccounts = await getAccounts(); const storedAccounts = await getAccounts();
const token = storedAccounts.find((x) => x.id === account.id).token; const token = storedAccounts.find((x) => x.id === account.id).token;
switchAccountWithToken(token); switchAccountWithToken(token);
@ -202,7 +210,7 @@ export async function openAccountMenu(
userIds: storedAccounts.map((x) => x.id), userIds: storedAccounts.map((x) => x.id),
}); });
function createItem(account: misskey.entities.UserDetailed) { function createItem(account: firefish.entities.UserDetailed) {
return { return {
type: "user", type: "user",
user: account, user: account,

View file

@ -41,7 +41,7 @@
<script setup lang="ts"> <script setup lang="ts">
import { ref } from "vue"; import { ref } from "vue";
import type * as Misskey from "firefish-js"; import type * as firefish from "firefish-js";
import XWindow from "@/components/MkWindow.vue"; import XWindow from "@/components/MkWindow.vue";
import MkTextarea from "@/components/form/textarea.vue"; import MkTextarea from "@/components/form/textarea.vue";
import MkButton from "@/components/MkButton.vue"; import MkButton from "@/components/MkButton.vue";
@ -49,7 +49,7 @@ import * as os from "@/os";
import { i18n } from "@/i18n"; import { i18n } from "@/i18n";
const props = defineProps<{ const props = defineProps<{
user: Misskey.entities.User; user: firefish.entities.User;
initialComment?: string; initialComment?: string;
}>(); }>();

View file

@ -3,7 +3,7 @@
<template #empty> <template #empty>
<div class="_fullinfo"> <div class="_fullinfo">
<img <img
src="/static-assets/badges/not-found.png" src="/static-assets/badges/not-found.webp"
class="_ghost" class="_ghost"
:alt="i18n.ts.notFound" :alt="i18n.ts.notFound"
/> />

View file

@ -131,7 +131,12 @@ export default defineComponent({
this.$el.style.setProperty("--maxHeight", this.maxHeight + "px"); this.$el.style.setProperty("--maxHeight", this.maxHeight + "px");
const calcOmit = () => { const calcOmit = () => {
if (this.omitted || this.ignoreOmit || this.maxHeight == null) if (
this.omitted ||
this.ignoreOmit ||
this.maxHeight == null ||
this.$refs.content == null
)
return; return;
const height = this.$refs.content.offsetHeight; const height = this.$refs.content.offsetHeight;
this.omitted = height > this.maxHeight; this.omitted = height > this.maxHeight;

View file

@ -37,7 +37,7 @@
<script lang="ts" setup> <script lang="ts" setup>
import { onMounted, ref } from "vue"; import { onMounted, ref } from "vue";
import type * as misskey from "firefish-js"; import type * as firefish from "firefish-js";
import Cropper from "cropperjs"; import Cropper from "cropperjs";
import tinycolor from "tinycolor2"; import tinycolor from "tinycolor2";
import XModalWindow from "@/components/MkModalWindow.vue"; import XModalWindow from "@/components/MkModalWindow.vue";
@ -49,13 +49,13 @@ import { query } from "@/scripts/url";
import { i18n } from "@/i18n"; import { i18n } from "@/i18n";
const emit = defineEmits<{ const emit = defineEmits<{
(ev: "ok", cropped: misskey.entities.DriveFile): void; (ev: "ok", cropped: firefish.entities.DriveFile): void;
(ev: "cancel"): void; (ev: "cancel"): void;
(ev: "closed"): void; (ev: "closed"): void;
}>(); }>();
const props = defineProps<{ const props = defineProps<{
file: misskey.entities.DriveFile; file: firefish.entities.DriveFile;
aspectRatio: number; aspectRatio: number;
}>(); }>();
@ -68,7 +68,7 @@ let cropper: Cropper | null = null,
loading = ref(true); loading = ref(true);
const ok = async () => { const ok = async () => {
const promise = new Promise<misskey.entities.DriveFile>(async (res) => { const promise = new Promise<firefish.entities.DriveFile>(async (res) => {
const croppedCanvas = await cropper?.getCropperSelection()?.$toCanvas(); const croppedCanvas = await cropper?.getCropperSelection()?.$toCanvas();
croppedCanvas.toBlob((blob) => { croppedCanvas.toBlob((blob) => {
const formData = new FormData(); const formData = new FormData();

View file

@ -15,13 +15,13 @@
<script lang="ts" setup> <script lang="ts" setup>
import { computed, ref } from "vue"; import { computed, ref } from "vue";
import { length } from "stringz"; import { length } from "stringz";
import type * as misskey from "firefish-js"; import type * as firefish from "firefish-js";
import { concat } from "@/scripts/array"; import { concat } from "@/scripts/array";
import { i18n } from "@/i18n"; import { i18n } from "@/i18n";
const props = defineProps<{ const props = defineProps<{
modelValue: boolean; modelValue: boolean;
note: misskey.entities.Note; note: firefish.entities.Note;
}>(); }>();
const emit = defineEmits<{ const emit = defineEmits<{

View file

@ -54,7 +54,12 @@
<Mfm :text="i18n.ts.password" /> <Mfm :text="i18n.ts.password" />
</header> </header>
<div v-if="text" :class="$style.text"> <div v-if="text" :class="$style.text">
<Mfm :text="text" /> <span
v-if="isPlaintext === true"
style="white-space: pre-line"
>{{ text }}</span
>
<Mfm v-else :text="text" />
</div> </div>
<MkInput <MkInput
v-if="input && input.type !== 'paragraph'" v-if="input && input.type !== 'paragraph'"
@ -245,6 +250,7 @@ const props = withDefaults(
| "search"; | "search";
title: string; title: string;
text?: string; text?: string;
isPlaintext?: boolean;
input?: Input; input?: Input;
select?: Select; select?: Select;
icon?: string; icon?: string;
@ -268,6 +274,7 @@ const props = withDefaults(
isYesNo: false, isYesNo: false,
cancelableByBgClick: true, cancelableByBgClick: true,
isPlaintext: false,
}, },
); );

View file

@ -39,7 +39,7 @@
<script lang="ts" setup> <script lang="ts" setup>
import { computed, defineAsyncComponent, ref } from "vue"; import { computed, defineAsyncComponent, ref } from "vue";
import type * as Misskey from "firefish-js"; import type * as firefish from "firefish-js";
import copyToClipboard from "@/scripts/copy-to-clipboard"; import copyToClipboard from "@/scripts/copy-to-clipboard";
import MkDriveFileThumbnail from "@/components/MkDriveFileThumbnail.vue"; import MkDriveFileThumbnail from "@/components/MkDriveFileThumbnail.vue";
import bytes from "@/filters/bytes"; import bytes from "@/filters/bytes";
@ -49,7 +49,7 @@ import { $i } from "@/account";
const props = withDefaults( const props = withDefaults(
defineProps<{ defineProps<{
file: Misskey.entities.DriveFile; file: firefish.entities.DriveFile;
isSelected?: boolean; isSelected?: boolean;
selectMode?: boolean; selectMode?: boolean;
}>(), }>(),
@ -60,7 +60,7 @@ const props = withDefaults(
); );
const emit = defineEmits<{ const emit = defineEmits<{
(ev: "chosen", r: Misskey.entities.DriveFile): void; (ev: "chosen", r: firefish.entities.DriveFile): void;
(ev: "dragstart"): void; (ev: "dragstart"): void;
(ev: "dragend"): void; (ev: "dragend"): void;
}>(); }>();

View file

@ -38,14 +38,14 @@
<script lang="ts" setup> <script lang="ts" setup>
import { computed, defineAsyncComponent, ref } from "vue"; import { computed, defineAsyncComponent, ref } from "vue";
import type * as Misskey from "firefish-js"; import type * as firefish from "firefish-js";
import * as os from "@/os"; import * as os from "@/os";
import { i18n } from "@/i18n"; import { i18n } from "@/i18n";
import { defaultStore } from "@/store"; import { defaultStore } from "@/store";
const props = withDefaults( const props = withDefaults(
defineProps<{ defineProps<{
folder: Misskey.entities.DriveFolder; folder: firefish.entities.DriveFolder;
isSelected?: boolean; isSelected?: boolean;
selectMode?: boolean; selectMode?: boolean;
}>(), }>(),
@ -56,11 +56,11 @@ const props = withDefaults(
); );
const emit = defineEmits<{ const emit = defineEmits<{
(ev: "chosen", v: Misskey.entities.DriveFolder): void; (ev: "chosen", v: firefish.entities.DriveFolder): void;
(ev: "move", v: Misskey.entities.DriveFolder): void; (ev: "move", v: firefish.entities.DriveFolder): void;
(ev: "upload", file: File, folder: Misskey.entities.DriveFolder); (ev: "upload", file: File, folder: firefish.entities.DriveFolder);
(ev: "removeFile", v: Misskey.entities.DriveFile["id"]): void; (ev: "removeFile", v: firefish.entities.DriveFile["id"]): void;
(ev: "removeFolder", v: Misskey.entities.DriveFolder["id"]): void; (ev: "removeFolder", v: firefish.entities.DriveFolder["id"]): void;
(ev: "dragstart"): void; (ev: "dragstart"): void;
(ev: "dragend"): void; (ev: "dragend"): void;
}>(); }>();

View file

@ -15,24 +15,24 @@
<script lang="ts" setup> <script lang="ts" setup>
import { ref } from "vue"; import { ref } from "vue";
import type * as Misskey from "firefish-js"; import type * as firefish from "firefish-js";
import * as os from "@/os"; import * as os from "@/os";
import { i18n } from "@/i18n"; import { i18n } from "@/i18n";
const props = defineProps<{ const props = defineProps<{
folder?: Misskey.entities.DriveFolder; folder?: firefish.entities.DriveFolder;
parentFolder: Misskey.entities.DriveFolder | null; parentFolder: firefish.entities.DriveFolder | null;
}>(); }>();
const emit = defineEmits<{ const emit = defineEmits<{
(ev: "move", v?: Misskey.entities.DriveFolder): void; (ev: "move", v?: firefish.entities.DriveFolder): void;
( (
ev: "upload", ev: "upload",
file: File, file: File,
folder?: Misskey.entities.DriveFolder | null, folder?: firefish.entities.DriveFolder | null,
): void; ): void;
(ev: "removeFile", v: Misskey.entities.DriveFile["id"]): void; (ev: "removeFile", v: firefish.entities.DriveFile["id"]): void;
(ev: "removeFolder", v: Misskey.entities.DriveFolder["id"]): void; (ev: "removeFolder", v: firefish.entities.DriveFolder["id"]): void;
}>(); }>();
const hover = ref(false); const hover = ref(false);

View file

@ -139,7 +139,7 @@ import {
ref, ref,
watch, watch,
} from "vue"; } from "vue";
import type * as Misskey from "firefish-js"; import type * as firefish from "firefish-js";
import MkButton from "./MkButton.vue"; import MkButton from "./MkButton.vue";
import XNavFolder from "@/components/MkDrive.navFolder.vue"; import XNavFolder from "@/components/MkDrive.navFolder.vue";
import XFolder from "@/components/MkDrive.folder.vue"; import XFolder from "@/components/MkDrive.folder.vue";
@ -152,7 +152,7 @@ import { uploadFile, uploads } from "@/scripts/upload";
const props = withDefaults( const props = withDefaults(
defineProps<{ defineProps<{
initialFolder?: Misskey.entities.DriveFolder; initialFolder?: firefish.entities.DriveFolder;
type?: string; type?: string;
multiple?: boolean; multiple?: boolean;
select?: "file" | "folder" | null; select?: "file" | "folder" | null;
@ -166,28 +166,28 @@ const props = withDefaults(
const emit = defineEmits<{ const emit = defineEmits<{
( (
ev: "selected", ev: "selected",
v: Misskey.entities.DriveFile | Misskey.entities.DriveFolder, v: firefish.entities.DriveFile | firefish.entities.DriveFolder,
): void; ): void;
( (
ev: "change-selection", ev: "change-selection",
v: Misskey.entities.DriveFile[] | Misskey.entities.DriveFolder[], v: firefish.entities.DriveFile[] | firefish.entities.DriveFolder[],
): void; ): void;
(ev: "move-root"): void; (ev: "move-root"): void;
(ev: "cd", v: Misskey.entities.DriveFolder | null): void; (ev: "cd", v: firefish.entities.DriveFolder | null): void;
(ev: "open-folder", v: Misskey.entities.DriveFolder): void; (ev: "open-folder", v: firefish.entities.DriveFolder): void;
}>(); }>();
const loadMoreFiles = ref<InstanceType<typeof MkButton>>(); const loadMoreFiles = ref<InstanceType<typeof MkButton>>();
const fileInput = ref<HTMLInputElement>(); const fileInput = ref<HTMLInputElement>();
const folder = ref<Misskey.entities.DriveFolder | null>(null); const folder = ref<firefish.entities.DriveFolder | null>(null);
const files = ref<Misskey.entities.DriveFile[]>([]); const files = ref<firefish.entities.DriveFile[]>([]);
const folders = ref<Misskey.entities.DriveFolder[]>([]); const folders = ref<firefish.entities.DriveFolder[]>([]);
const moreFiles = ref(false); const moreFiles = ref(false);
const moreFolders = ref(false); const moreFolders = ref(false);
const hierarchyFolders = ref<Misskey.entities.DriveFolder[]>([]); const hierarchyFolders = ref<firefish.entities.DriveFolder[]>([]);
const selectedFiles = ref<Misskey.entities.DriveFile[]>([]); const selectedFiles = ref<firefish.entities.DriveFile[]>([]);
const selectedFolders = ref<Misskey.entities.DriveFolder[]>([]); const selectedFolders = ref<firefish.entities.DriveFolder[]>([]);
const uploadings = uploads; const uploadings = uploads;
const connection = stream.useChannel("drive"); const connection = stream.useChannel("drive");
const keepOriginal = ref<boolean>(defaultStore.state.keepOriginalUploading); // $ref使 const keepOriginal = ref<boolean>(defaultStore.state.keepOriginalUploading); // $ref使
@ -211,11 +211,11 @@ const ilFilesObserver = new IntersectionObserver(
watch(folder, () => emit("cd", folder.value)); watch(folder, () => emit("cd", folder.value));
function onStreamDriveFileCreated(file: Misskey.entities.DriveFile) { function onStreamDriveFileCreated(file: firefish.entities.DriveFile) {
addFile(file, true); addFile(file, true);
} }
function onStreamDriveFileUpdated(file: Misskey.entities.DriveFile) { function onStreamDriveFileUpdated(file: firefish.entities.DriveFile) {
const current = folder.value ? folder.value.id : null; const current = folder.value ? folder.value.id : null;
if (current !== file.folderId) { if (current !== file.folderId) {
removeFile(file); removeFile(file);
@ -229,13 +229,13 @@ function onStreamDriveFileDeleted(fileId: string) {
} }
function onStreamDriveFolderCreated( function onStreamDriveFolderCreated(
createdFolder: Misskey.entities.DriveFolder, createdFolder: firefish.entities.DriveFolder,
) { ) {
addFolder(createdFolder, true); addFolder(createdFolder, true);
} }
function onStreamDriveFolderUpdated( function onStreamDriveFolderUpdated(
updatedFolder: Misskey.entities.DriveFolder, updatedFolder: firefish.entities.DriveFolder,
) { ) {
const current = folder.value ? folder.value.id : null; const current = folder.value ? folder.value.id : null;
if (current !== updatedFolder.parentId) { if (current !== updatedFolder.parentId) {
@ -380,7 +380,7 @@ function createFolder() {
}); });
} }
function renameFolder(folderToRename: Misskey.entities.DriveFolder) { function renameFolder(folderToRename: firefish.entities.DriveFolder) {
os.inputText({ os.inputText({
title: i18n.ts.renameFolder, title: i18n.ts.renameFolder,
placeholder: i18n.ts.inputNewFolderName, placeholder: i18n.ts.inputNewFolderName,
@ -397,7 +397,7 @@ function renameFolder(folderToRename: Misskey.entities.DriveFolder) {
}); });
} }
function deleteFolder(folderToDelete: Misskey.entities.DriveFolder) { function deleteFolder(folderToDelete: firefish.entities.DriveFolder) {
os.api("drive/folders/delete", { os.api("drive/folders/delete", {
folderId: folderToDelete.id, folderId: folderToDelete.id,
}) })
@ -432,7 +432,7 @@ function onChangeFileInput() {
function upload( function upload(
file: File, file: File,
folderToUpload?: Misskey.entities.DriveFolder | null, folderToUpload?: firefish.entities.DriveFolder | null,
) { ) {
uploadFile( uploadFile(
file, file,
@ -446,7 +446,7 @@ function upload(
}); });
} }
function chooseFile(file: Misskey.entities.DriveFile) { function chooseFile(file: firefish.entities.DriveFile) {
const isAlreadySelected = selectedFiles.value.some((f) => f.id === file.id); const isAlreadySelected = selectedFiles.value.some((f) => f.id === file.id);
if (props.multiple) { if (props.multiple) {
if (isAlreadySelected) { if (isAlreadySelected) {
@ -467,7 +467,7 @@ function chooseFile(file: Misskey.entities.DriveFile) {
} }
} }
function chooseFolder(folderToChoose: Misskey.entities.DriveFolder) { function chooseFolder(folderToChoose: firefish.entities.DriveFolder) {
const isAlreadySelected = selectedFolders.value.some( const isAlreadySelected = selectedFolders.value.some(
(f) => f.id === folderToChoose.id, (f) => f.id === folderToChoose.id,
); );
@ -490,7 +490,7 @@ function chooseFolder(folderToChoose: Misskey.entities.DriveFolder) {
} }
} }
function move(target?: Misskey.entities.DriveFolder) { function move(target?: firefish.entities.DriveFolder) {
if (!target) { if (!target) {
goRoot(); goRoot();
return; return;
@ -518,7 +518,10 @@ function move(target?: Misskey.entities.DriveFolder) {
}); });
} }
function addFolder(folderToAdd: Misskey.entities.DriveFolder, unshift = false) { function addFolder(
folderToAdd: firefish.entities.DriveFolder,
unshift = false,
) {
const current = folder.value ? folder.value.id : null; const current = folder.value ? folder.value.id : null;
if (current !== folderToAdd.parentId) return; if (current !== folderToAdd.parentId) return;
@ -535,7 +538,7 @@ function addFolder(folderToAdd: Misskey.entities.DriveFolder, unshift = false) {
} }
} }
function addFile(fileToAdd: Misskey.entities.DriveFile, unshift = false) { function addFile(fileToAdd: firefish.entities.DriveFile, unshift = false) {
const current = folder.value ? folder.value.id : null; const current = folder.value ? folder.value.id : null;
if (current !== fileToAdd.folderId) return; if (current !== fileToAdd.folderId) return;
@ -552,30 +555,30 @@ function addFile(fileToAdd: Misskey.entities.DriveFile, unshift = false) {
} }
} }
function removeFolder(folderToRemove: Misskey.entities.DriveFolder | string) { function removeFolder(folderToRemove: firefish.entities.DriveFolder | string) {
const folderIdToRemove = const folderIdToRemove =
typeof folderToRemove === "object" ? folderToRemove.id : folderToRemove; typeof folderToRemove === "object" ? folderToRemove.id : folderToRemove;
folders.value = folders.value.filter((f) => f.id !== folderIdToRemove); folders.value = folders.value.filter((f) => f.id !== folderIdToRemove);
} }
function removeFile(file: Misskey.entities.DriveFile | string) { function removeFile(file: firefish.entities.DriveFile | string) {
const fileId = typeof file === "object" ? file.id : file; const fileId = typeof file === "object" ? file.id : file;
files.value = files.value.filter((f) => f.id !== fileId); files.value = files.value.filter((f) => f.id !== fileId);
} }
function appendFile(file: Misskey.entities.DriveFile) { function appendFile(file: firefish.entities.DriveFile) {
addFile(file); addFile(file);
} }
function appendFolder(folderToAppend: Misskey.entities.DriveFolder) { function appendFolder(folderToAppend: firefish.entities.DriveFolder) {
addFolder(folderToAppend); addFolder(folderToAppend);
} }
/* /*
function prependFile(file: Misskey.entities.DriveFile) { function prependFile(file: firefish.entities.DriveFile) {
addFile(file, true); addFile(file, true);
} }
function prependFolder(folderToPrepend: Misskey.entities.DriveFolder) { function prependFolder(folderToPrepend: firefish.entities.DriveFolder) {
addFolder(folderToPrepend, true); addFolder(folderToPrepend, true);
} }
*/ */
@ -706,7 +709,7 @@ function getMenu() {
icon: "ph-trash ph-bold ph-lg", icon: "ph-trash ph-bold ph-lg",
action: () => { action: () => {
deleteFolder( deleteFolder(
folder.value as Misskey.entities.DriveFolder, folder.value as firefish.entities.DriveFolder,
); );
}, },
} }

View file

@ -41,11 +41,11 @@
<script lang="ts" setup> <script lang="ts" setup>
import { computed } from "vue"; import { computed } from "vue";
import type * as Misskey from "firefish-js"; import type * as firefish from "firefish-js";
import ImgWithBlurhash from "@/components/MkImgWithBlurhash.vue"; import ImgWithBlurhash from "@/components/MkImgWithBlurhash.vue";
const props = defineProps<{ const props = defineProps<{
file: Misskey.entities.DriveFile; file: firefish.entities.DriveFile;
fit: string; fit: string;
}>(); }>();

View file

@ -37,7 +37,7 @@
<script lang="ts" setup> <script lang="ts" setup>
import { ref } from "vue"; import { ref } from "vue";
import type * as Misskey from "firefish-js"; import type * as firefish from "firefish-js";
import XDrive from "@/components/MkDrive.vue"; import XDrive from "@/components/MkDrive.vue";
import XModalWindow from "@/components/MkModalWindow.vue"; import XModalWindow from "@/components/MkModalWindow.vue";
import number from "@/filters/number"; import number from "@/filters/number";
@ -54,13 +54,13 @@ withDefaults(
); );
const emit = defineEmits<{ const emit = defineEmits<{
(ev: "done", r?: Misskey.entities.DriveFile[]): void; (ev: "done", r?: firefish.entities.DriveFile[]): void;
(ev: "closed"): void; (ev: "closed"): void;
}>(); }>();
const dialog = ref<InstanceType<typeof XModalWindow>>(); const dialog = ref<InstanceType<typeof XModalWindow>>();
const selected = ref<Misskey.entities.DriveFile[]>([]); const selected = ref<firefish.entities.DriveFile[]>([]);
function ok() { function ok() {
emit("done", selected.value); emit("done", selected.value);
@ -72,7 +72,7 @@ function cancel() {
dialog.value?.close(); dialog.value?.close();
} }
function onChangeSelection(files: Misskey.entities.DriveFile[]) { function onChangeSelection(files: firefish.entities.DriveFile[]) {
selected.value = files; selected.value = files;
} }
</script> </script>

View file

@ -15,13 +15,13 @@
<script lang="ts" setup> <script lang="ts" setup>
import {} from "vue"; import {} from "vue";
import type * as Misskey from "firefish-js"; import type * as firefish from "firefish-js";
import XDrive from "@/components/MkDrive.vue"; import XDrive from "@/components/MkDrive.vue";
import XWindow from "@/components/MkWindow.vue"; import XWindow from "@/components/MkWindow.vue";
import { i18n } from "@/i18n"; import { i18n } from "@/i18n";
defineProps<{ defineProps<{
initialFolder?: Misskey.entities.DriveFolder; initialFolder?: firefish.entities.DriveFolder;
}>(); }>();
const emit = defineEmits<{ const emit = defineEmits<{

View file

@ -165,7 +165,7 @@
<script lang="ts" setup> <script lang="ts" setup>
import { computed, onMounted, ref, watch } from "vue"; import { computed, onMounted, ref, watch } from "vue";
import type * as Misskey from "firefish-js"; import type * as firefish from "firefish-js";
import { FocusTrap } from "focus-trap-vue"; import { FocusTrap } from "focus-trap-vue";
import XSection from "@/components/MkEmojiPicker.section.vue"; import XSection from "@/components/MkEmojiPicker.section.vue";
import type { UnicodeEmojiDef } from "@/scripts/emojilist"; import type { UnicodeEmojiDef } from "@/scripts/emojilist";
@ -241,7 +241,7 @@ const height = computed(() =>
const customEmojiCategories = emojiCategories; const customEmojiCategories = emojiCategories;
const customEmojis = instance.emojis; const customEmojis = instance.emojis;
const q = ref<string | null>(null); const q = ref<string | null>(null);
const searchResultCustom = ref<Misskey.entities.CustomEmoji[]>([]); const searchResultCustom = ref<firefish.entities.CustomEmoji[]>([]);
const searchResultUnicode = ref<UnicodeEmojiDef[]>([]); const searchResultUnicode = ref<UnicodeEmojiDef[]>([]);
const tab = ref<"index" | "custom" | "unicode" | "tags">("index"); const tab = ref<"index" | "custom" | "unicode" | "tags">("index");
@ -259,7 +259,7 @@ watch(q, () => {
const searchCustom = () => { const searchCustom = () => {
const max = 16; const max = 16;
const emojis = customEmojis; const emojis = customEmojis;
const matches = new Set<Misskey.entities.CustomEmoji>(); const matches = new Set<firefish.entities.CustomEmoji>();
const exactMatch = emojis.find((emoji) => emoji.name === newQ); const exactMatch = emojis.find((emoji) => emoji.name === newQ);
if (exactMatch) matches.add(exactMatch); if (exactMatch) matches.add(exactMatch);
@ -420,7 +420,7 @@ function reset() {
} }
function getKey( function getKey(
emoji: string | Misskey.entities.CustomEmoji | UnicodeEmojiDef, emoji: string | firefish.entities.CustomEmoji | UnicodeEmojiDef,
): string { ): string {
return typeof emoji === "string" ? emoji : emoji.emoji || `:${emoji.name}:`; return typeof emoji === "string" ? emoji : emoji.emoji || `:${emoji.name}:`;
} }

View file

@ -8,10 +8,10 @@
<script lang="ts" setup> <script lang="ts" setup>
import { ref } from "vue"; import { ref } from "vue";
import type * as Misskey from "firefish-js"; import type * as firefish from "firefish-js";
import * as os from "@/os"; import * as os from "@/os";
const meta = ref<Misskey.entities.DetailedInstanceMetadata>(); const meta = ref<firefish.entities.DetailedInstanceMetadata>();
os.api("meta", { detail: true }).then((gotMeta) => { os.api("meta", { detail: true }).then((gotMeta) => {
meta.value = gotMeta; meta.value = gotMeta;

View file

@ -62,7 +62,7 @@
<script lang="ts" setup> <script lang="ts" setup>
import { computed, onBeforeUnmount, onMounted, ref } from "vue"; import { computed, onBeforeUnmount, onMounted, ref } from "vue";
import type * as Misskey from "firefish-js"; import type * as firefish from "firefish-js";
import * as os from "@/os"; import * as os from "@/os";
import { stream } from "@/stream"; import { stream } from "@/stream";
import { i18n } from "@/i18n"; import { i18n } from "@/i18n";
@ -76,7 +76,7 @@ const router = useRouter();
const emit = defineEmits(["refresh"]); const emit = defineEmits(["refresh"]);
const props = withDefaults( const props = withDefaults(
defineProps<{ defineProps<{
user: Misskey.entities.UserDetailed; user: firefish.entities.UserDetailed;
full?: boolean; full?: boolean;
large?: boolean; large?: boolean;
hideMenu?: boolean; hideMenu?: boolean;
@ -107,7 +107,7 @@ if (props.user.isFollowing == null) {
}).then(onFollowChange); }).then(onFollowChange);
} }
function onFollowChange(user: Misskey.entities.UserDetailed) { function onFollowChange(user: firefish.entities.UserDetailed) {
if (user.id === props.user.id) { if (user.id === props.user.id) {
isFollowing.value = user.isFollowing; isFollowing.value = user.isFollowing;
hasPendingFollowRequestFromYou.value = hasPendingFollowRequestFromYou.value =

View file

@ -28,14 +28,14 @@
<script lang="ts" setup> <script lang="ts" setup>
import { ref } from "vue"; import { ref } from "vue";
import type * as misskey from "firefish-js"; import type * as firefish from "firefish-js";
import bytes from "@/filters/bytes"; import bytes from "@/filters/bytes";
import number from "@/filters/number"; import number from "@/filters/number";
import MkModal from "@/components/MkModal.vue"; import MkModal from "@/components/MkModal.vue";
const props = withDefaults( const props = withDefaults(
defineProps<{ defineProps<{
image: misskey.entities.DriveFile; image: firefish.entities.DriveFile;
}>(), }>(),
{}, {},
); );

View file

@ -52,6 +52,7 @@ function close() {
display: flex; display: flex;
align-items: center; align-items: center;
gap: 0.4em; gap: 0.4em;
white-space: pre-line;
&.warn { &.warn {
background: var(--infoWarnBg); background: var(--infoWarnBg);

View file

@ -92,7 +92,7 @@
import { computed, ref, watch } from "vue"; import { computed, ref, watch } from "vue";
import VuePlyr from "vue-plyr"; import VuePlyr from "vue-plyr";
import "vue-plyr/dist/vue-plyr.css"; import "vue-plyr/dist/vue-plyr.css";
import type * as misskey from "firefish-js"; import type * as firefish from "firefish-js";
import { getStaticImageUrl } from "@/scripts/get-static-image-url"; import { getStaticImageUrl } from "@/scripts/get-static-image-url";
import ImgWithBlurhash from "@/components/MkImgWithBlurhash.vue"; import ImgWithBlurhash from "@/components/MkImgWithBlurhash.vue";
import { defaultStore } from "@/store"; import { defaultStore } from "@/store";
@ -100,7 +100,7 @@ import { i18n } from "@/i18n";
import * as os from "@/os"; import * as os from "@/os";
const props = defineProps<{ const props = defineProps<{
media: misskey.entities.DriveFile; media: firefish.entities.DriveFile;
raw?: boolean; raw?: boolean;
}>(); }>();
@ -138,6 +138,7 @@ function captionPopup() {
os.alert({ os.alert({
type: "info", type: "info",
text: props.media.comment, text: props.media.comment,
isPlaintext: true,
}); });
} }

View file

@ -58,14 +58,14 @@
<script lang="ts" setup> <script lang="ts" setup>
import { onMounted, ref } from "vue"; import { onMounted, ref } from "vue";
import VuePlyr from "vue-plyr"; import VuePlyr from "vue-plyr";
import type * as misskey from "firefish-js"; import type * as firefish from "firefish-js";
import { ColdDeviceStorage } from "@/store"; import { ColdDeviceStorage } from "@/store";
import "vue-plyr/dist/vue-plyr.css"; import "vue-plyr/dist/vue-plyr.css";
import { i18n } from "@/i18n"; import { i18n } from "@/i18n";
const props = withDefaults( const props = withDefaults(
defineProps<{ defineProps<{
media: misskey.entities.DriveFile; media: firefish.entities.DriveFile;
}>(), }>(),
{}, {},
); );

View file

@ -41,7 +41,7 @@
<script lang="ts" setup> <script lang="ts" setup>
import { onMounted, ref } from "vue"; import { onMounted, ref } from "vue";
import type * as misskey from "firefish-js"; import type * as firefish from "firefish-js";
import PhotoSwipeLightbox from "photoswipe/lightbox"; import PhotoSwipeLightbox from "photoswipe/lightbox";
import PhotoSwipe from "photoswipe"; import PhotoSwipe from "photoswipe";
import "photoswipe/style.css"; import "photoswipe/style.css";
@ -56,7 +56,7 @@ import {
} from "@/const"; } from "@/const";
const props = defineProps<{ const props = defineProps<{
mediaList: misskey.entities.DriveFile[]; mediaList: firefish.entities.DriveFile[];
raw?: boolean; raw?: boolean;
inDm?: boolean; inDm?: boolean;
}>(); }>();
@ -184,7 +184,7 @@ onMounted(() => {
} }
}); });
const previewable = (file: misskey.entities.DriveFile): boolean => { const previewable = (file: firefish.entities.DriveFile): boolean => {
if (file.type === "image/svg+xml") return true; // svgwebpublic/thumbnailpngtrue if (file.type === "image/svg+xml") return true; // svgwebpublic/thumbnailpngtrue
// FILE_TYPE_BROWSERSAFE // FILE_TYPE_BROWSERSAFE
if (isModule(file)) return true; if (isModule(file)) return true;
@ -194,7 +194,7 @@ const previewable = (file: misskey.entities.DriveFile): boolean => {
); );
}; };
const isModule = (file: misskey.entities.DriveFile): boolean => { const isModule = (file: firefish.entities.DriveFile): boolean => {
return ( return (
FILE_TYPE_TRACKER_MODULES.some((type) => { FILE_TYPE_TRACKER_MODULES.some((type) => {
return file.type === type; return file.type === type;
@ -332,6 +332,7 @@ const previewableCount = props.mediaList.filter((media) =>
overflow-x: clip; overflow-x: clip;
overflow-y: auto; overflow-y: auto;
overscroll-behavior: contain; overscroll-behavior: contain;
white-space: pre-line;
} }
.pwsp__alt-text:empty { .pwsp__alt-text:empty {

View file

@ -418,8 +418,8 @@ onDeactivated(() => {
width: 100%; width: 100%;
height: 100%; height: 100%;
overflow: hidden; overflow: hidden;
color: #ffffff; color: var(--fg);
background-color: black; background-color: var(--panelHighlight);
text-align: center; text-align: center;
font: 12px monospace; font: 12px monospace;
white-space: pre; white-space: pre;
@ -441,17 +441,17 @@ onDeactivated(() => {
opacity: 0.5; opacity: 0.5;
> .modColQuarter { > .modColQuarter {
color: #ffff00; color: var(--badge);
} }
> .mod-row-inner { > .mod-row-inner {
background: repeating-linear-gradient( background: repeating-linear-gradient(
to right, to right,
white 0 4ch, var(--fg) 0 4ch,
#80e0ff 4ch 6ch, var(--codeBoolean) 4ch 6ch,
#80ff80 6ch 9ch, var(--codeNumber) 6ch 9ch,
#ff80e0 9ch 10ch, var(--codeString) 9ch 10ch,
#ffe080 10ch 12ch var(--error) 10ch 12ch
); );
background-clip: text; background-clip: text;
-webkit-background-clip: text; -webkit-background-clip: text;
@ -500,8 +500,8 @@ onDeactivated(() => {
display: flex; display: flex;
justify-content: center; justify-content: center;
align-items: center; align-items: center;
background: #111; background: var(--infoWarnBg);
color: #fff; color: var(--infoWarnFg);
> div { > div {
display: table-cell; display: table-cell;

View file

@ -43,7 +43,7 @@
>{{ i18n.ts.pinnedNote }} >{{ i18n.ts.pinnedNote }}
</div> </div>
<div v-if="isRenote" class="renote"> <div v-if="isRenote" class="renote">
<i class="ph-repeat ph-bold ph-lg"></i> <i class="ph-rocket-launch ph-bold ph-lg"></i>
<I18n :src="i18n.ts.renotedBy" tag="span"> <I18n :src="i18n.ts.renotedBy" tag="span">
<template #user> <template #user>
<MkA <MkA
@ -275,8 +275,7 @@
import { computed, inject, onMounted, ref } from "vue"; import { computed, inject, onMounted, ref } from "vue";
import * as mfm from "mfm-js"; import * as mfm from "mfm-js";
import type { Ref } from "vue"; import type { Ref } from "vue";
import type * as misskey from "firefish-js"; import type * as firefish from "firefish-js";
import { detect as detectLanguage_ } from "tinyld";
import MkSubNoteContent from "./MkSubNoteContent.vue"; import MkSubNoteContent from "./MkSubNoteContent.vue";
import MkNoteSub from "@/components/MkNoteSub.vue"; import MkNoteSub from "@/components/MkNoteSub.vue";
import XNoteHeader from "@/components/MkNoteHeader.vue"; import XNoteHeader from "@/components/MkNoteHeader.vue";
@ -287,6 +286,7 @@ import XStarButtonNoEmoji from "@/components/MkStarButtonNoEmoji.vue";
import XQuoteButton from "@/components/MkQuoteButton.vue"; import XQuoteButton from "@/components/MkQuoteButton.vue";
import MkVisibility from "@/components/MkVisibility.vue"; import MkVisibility from "@/components/MkVisibility.vue";
import copyToClipboard from "@/scripts/copy-to-clipboard"; import copyToClipboard from "@/scripts/copy-to-clipboard";
import detectLanguage from "@/scripts/detect-language";
import { url } from "@/config"; import { url } from "@/config";
import { pleaseLogin } from "@/scripts/please-login"; import { pleaseLogin } from "@/scripts/please-login";
import { focusNext, focusPrev } from "@/scripts/focus"; import { focusNext, focusPrev } from "@/scripts/focus";
@ -307,7 +307,7 @@ import { getNoteSummary } from "@/scripts/get-note-summary";
const router = useRouter(); const router = useRouter();
const props = defineProps<{ const props = defineProps<{
note: misskey.entities.Note; note: firefish.entities.Note;
pinned?: boolean; pinned?: boolean;
detailedView?: boolean; detailedView?: boolean;
collapsedReply?: boolean; collapsedReply?: boolean;
@ -352,7 +352,7 @@ const renoteButton = ref<InstanceType<typeof XRenoteButton>>();
const renoteTime = ref<HTMLElement>(); const renoteTime = ref<HTMLElement>();
const reactButton = ref<HTMLElement>(); const reactButton = ref<HTMLElement>();
const appearNote = computed(() => const appearNote = computed(() =>
isRenote ? (note.value.renote as misskey.entities.Note) : note.value, isRenote ? (note.value.renote as firefish.entities.Note) : note.value,
); );
const isMyRenote = $i && $i.id === note.value.userId; const isMyRenote = $i && $i.id === note.value.userId;
const showContent = ref(false); const showContent = ref(false);
@ -372,15 +372,6 @@ const expandOnNoteClick = defaultStore.state.expandOnNoteClick;
const lang = localStorage.getItem("lang"); const lang = localStorage.getItem("lang");
const translateLang = localStorage.getItem("translateLang"); const translateLang = localStorage.getItem("translateLang");
function detectLanguage(text: string) {
const nodes = mfm.parse(text);
const filtered = mfm.extract(nodes, (node) => {
return node.type === "text" || node.type === "quote";
});
const purified = mfm.toString(filtered);
return detectLanguage_(purified);
}
const isForeignLanguage: boolean = const isForeignLanguage: boolean =
defaultStore.state.detectPostLanguage && defaultStore.state.detectPostLanguage &&
appearNote.value.text != null && appearNote.value.text != null &&
@ -476,7 +467,7 @@ function undoReact(note): void {
}); });
} }
const currentClipPage = inject<Ref<misskey.entities.Clip> | null>( const currentClipPage = inject<Ref<firefish.entities.Clip> | null>(
"currentClipPage", "currentClipPage",
null, null,
); );
@ -948,7 +939,7 @@ defineExpose({
padding: 8px; padding: 8px;
opacity: 0.7; opacity: 0.7;
&:disabled { &:disabled {
opacity: 0.5 !important; opacity: 0.3 !important;
} }
flex-grow: 1; flex-grow: 1;
max-width: 3.5em; max-width: 3.5em;

View file

@ -42,7 +42,7 @@
{{ i18n.ts._notification._types.reply }} {{ i18n.ts._notification._types.reply }}
</option> </option>
<option v-if="note.renoteCount > 0" value="renotes"> <option v-if="note.renoteCount > 0" value="renotes">
<!-- <i class="ph-repeat ph-bold ph-lg"></i> --> <!-- <i class="ph-rocket-launch ph-bold ph-lg"></i> -->
<span class="count">{{ note.renoteCount }}</span> <span class="count">{{ note.renoteCount }}</span>
{{ i18n.ts._notification._types.renote }} {{ i18n.ts._notification._types.renote }}
</option> </option>
@ -150,7 +150,7 @@
<script lang="ts" setup> <script lang="ts" setup>
import { onMounted, onUnmounted, onUpdated, ref } from "vue"; import { onMounted, onUnmounted, onUpdated, ref } from "vue";
import type * as misskey from "firefish-js"; import type * as firefish from "firefish-js";
import type { NoteUpdatedEvent } from "firefish-js/built/streaming.types"; import type { NoteUpdatedEvent } from "firefish-js/built/streaming.types";
import MkTab from "@/components/MkTab.vue"; import MkTab from "@/components/MkTab.vue";
import MkNote from "@/components/MkNote.vue"; import MkNote from "@/components/MkNote.vue";
@ -172,7 +172,7 @@ import { deepClone } from "@/scripts/clone";
import { stream } from "@/stream"; import { stream } from "@/stream";
const props = defineProps<{ const props = defineProps<{
note: misskey.entities.Note; note: firefish.entities.Note;
pinned?: boolean; pinned?: boolean;
}>(); }>();
@ -218,10 +218,10 @@ const muted = ref(
); );
const translation = ref(null); const translation = ref(null);
const translating = ref(false); const translating = ref(false);
const conversation = ref<null | misskey.entities.Note[]>([]); const conversation = ref<null | firefish.entities.Note[]>([]);
const replies = ref<misskey.entities.Note[]>([]); const replies = ref<firefish.entities.Note[]>([]);
const directReplies = ref<null | misskey.entities.Note[]>([]); const directReplies = ref<null | firefish.entities.Note[]>([]);
const directQuotes = ref<null | misskey.entities.Note[]>([]); const directQuotes = ref<null | firefish.entities.Note[]>([]);
const clips = ref(); const clips = ref();
const renotes = ref(); const renotes = ref();
let isScrolling; let isScrolling;

View file

@ -50,7 +50,7 @@
<script lang="ts" setup> <script lang="ts" setup>
import { ref } from "vue"; import { ref } from "vue";
import type * as misskey from "firefish-js"; import type * as firefish from "firefish-js";
import { defaultStore } from "@/store"; import { defaultStore } from "@/store";
import MkVisibility from "@/components/MkVisibility.vue"; import MkVisibility from "@/components/MkVisibility.vue";
import MkInstanceTicker from "@/components/MkInstanceTicker.vue"; import MkInstanceTicker from "@/components/MkInstanceTicker.vue";
@ -60,7 +60,7 @@ import { i18n } from "@/i18n";
import { pageWindow } from "@/os"; import { pageWindow } from "@/os";
const props = defineProps<{ const props = defineProps<{
note: misskey.entities.Note; note: firefish.entities.Note;
pinned?: boolean; pinned?: boolean;
canOpenServerInfo?: boolean; canOpenServerInfo?: boolean;
}>(); }>();

View file

@ -20,8 +20,7 @@
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import {} from "vue"; import preprocess from "@/scripts/preprocess";
import { preprocess } from "@/scripts/preprocess";
const props = defineProps<{ const props = defineProps<{
text: string; text: string;

View file

@ -11,12 +11,12 @@
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import type * as misskey from "firefish-js"; import type * as firefish from "firefish-js";
import XNoteHeader from "@/components/MkNoteHeader.vue"; import XNoteHeader from "@/components/MkNoteHeader.vue";
import MkSubNoteContent from "@/components/MkSubNoteContent.vue"; import MkSubNoteContent from "@/components/MkSubNoteContent.vue";
const props = defineProps<{ const props = defineProps<{
note: misskey.entities.Note; note: firefish.entities.Note;
pinned?: boolean; pinned?: boolean;
}>(); }>();
</script> </script>

View file

@ -191,9 +191,8 @@
<script lang="ts" setup> <script lang="ts" setup>
import { computed, inject, ref } from "vue"; import { computed, inject, ref } from "vue";
import type { Ref } from "vue"; import type { Ref } from "vue";
import type * as misskey from "firefish-js"; import type * as firefish from "firefish-js";
import * as mfm from "mfm-js"; import * as mfm from "mfm-js";
import { detect as detectLanguage_ } from "tinyld";
import XNoteHeader from "@/components/MkNoteHeader.vue"; import XNoteHeader from "@/components/MkNoteHeader.vue";
import MkSubNoteContent from "@/components/MkSubNoteContent.vue"; import MkSubNoteContent from "@/components/MkSubNoteContent.vue";
import XReactionsViewer from "@/components/MkReactionsViewer.vue"; import XReactionsViewer from "@/components/MkReactionsViewer.vue";
@ -202,6 +201,7 @@ import XStarButtonNoEmoji from "@/components/MkStarButtonNoEmoji.vue";
import XRenoteButton from "@/components/MkRenoteButton.vue"; import XRenoteButton from "@/components/MkRenoteButton.vue";
import XQuoteButton from "@/components/MkQuoteButton.vue"; import XQuoteButton from "@/components/MkQuoteButton.vue";
import copyToClipboard from "@/scripts/copy-to-clipboard"; import copyToClipboard from "@/scripts/copy-to-clipboard";
import detectLanguage from "@/scripts/detect-language";
import { url } from "@/config"; import { url } from "@/config";
import { pleaseLogin } from "@/scripts/please-login"; import { pleaseLogin } from "@/scripts/please-login";
import { getNoteMenu } from "@/scripts/get-note-menu"; import { getNoteMenu } from "@/scripts/get-note-menu";
@ -221,8 +221,8 @@ const router = useRouter();
const props = withDefaults( const props = withDefaults(
defineProps<{ defineProps<{
note: misskey.entities.Note; note: firefish.entities.Note;
conversation?: misskey.entities.Note[]; conversation?: firefish.entities.Note[];
parentId?; parentId?;
detailedView?; detailedView?;
@ -262,7 +262,7 @@ const starButton = ref<InstanceType<typeof XStarButton>>();
const renoteButton = ref<InstanceType<typeof XRenoteButton>>(); const renoteButton = ref<InstanceType<typeof XRenoteButton>>();
const reactButton = ref<HTMLElement>(); const reactButton = ref<HTMLElement>();
const appearNote = computed(() => const appearNote = computed(() =>
isRenote ? (note.value.renote as misskey.entities.Note) : note.value, isRenote ? (note.value.renote as firefish.entities.Note) : note.value,
); );
const isDeleted = ref(false); const isDeleted = ref(false);
const muted = ref( const muted = ref(
@ -275,7 +275,7 @@ const muted = ref(
); );
const translation = ref(null); const translation = ref(null);
const translating = ref(false); const translating = ref(false);
const replies: misskey.entities.Note[] = const replies: firefish.entities.Note[] =
props.conversation props.conversation
?.filter( ?.filter(
(item) => (item) =>
@ -288,15 +288,6 @@ const expandOnNoteClick = defaultStore.state.expandOnNoteClick;
const lang = localStorage.getItem("lang"); const lang = localStorage.getItem("lang");
const translateLang = localStorage.getItem("translateLang"); const translateLang = localStorage.getItem("translateLang");
function detectLanguage(text: string) {
const nodes = mfm.parse(text);
const filtered = mfm.extract(nodes, (node) => {
return node.type === "text" || node.type === "quote";
});
const purified = mfm.toString(filtered);
return detectLanguage_(purified);
}
const isForeignLanguage: boolean = const isForeignLanguage: boolean =
defaultStore.state.detectPostLanguage && defaultStore.state.detectPostLanguage &&
appearNote.value.text != null && appearNote.value.text != null &&
@ -378,7 +369,7 @@ function undoReact(note): void {
}); });
} }
const currentClipPage = inject<Ref<misskey.entities.Clip> | null>( const currentClipPage = inject<Ref<firefish.entities.Clip> | null>(
"currentClipPage", "currentClipPage",
null, null,
); );
@ -552,7 +543,7 @@ function noteClick(e) {
padding: 8px; padding: 8px;
opacity: 0.7; opacity: 0.7;
&:disabled { &:disabled {
opacity: 0.5 !important; opacity: 0.3 !important;
} }
flex-grow: 1; flex-grow: 1;
max-width: 3.5em; max-width: 3.5em;

View file

@ -3,7 +3,7 @@
<template #empty> <template #empty>
<div class="_fullinfo"> <div class="_fullinfo">
<img <img
src="/static-assets/badges/info.png" src="/static-assets/badges/info.webp"
class="_ghost" class="_ghost"
alt="Info" alt="Info"
/> />

View file

@ -41,7 +41,7 @@
></i> ></i>
<i <i
v-else-if="notification.type === 'renote'" v-else-if="notification.type === 'renote'"
class="ph-repeat ph-bold" class="ph-rocket-launch ph-bold"
></i> ></i>
<i <i
v-else-if="notification.type === 'reply'" v-else-if="notification.type === 'reply'"
@ -263,7 +263,7 @@
<script lang="ts" setup> <script lang="ts" setup>
import { onMounted, onUnmounted, ref, watch } from "vue"; import { onMounted, onUnmounted, ref, watch } from "vue";
import type * as misskey from "firefish-js"; import type * as firefish from "firefish-js";
import XReactionIcon from "@/components/MkReactionIcon.vue"; import XReactionIcon from "@/components/MkReactionIcon.vue";
import MkFollowButton from "@/components/MkFollowButton.vue"; import MkFollowButton from "@/components/MkFollowButton.vue";
import XReactionTooltip from "@/components/MkReactionTooltip.vue"; import XReactionTooltip from "@/components/MkReactionTooltip.vue";
@ -279,7 +279,7 @@ import { instance } from "@/instance";
const props = withDefaults( const props = withDefaults(
defineProps<{ defineProps<{
notification: misskey.entities.Notification; notification: firefish.entities.Notification;
withTime?: boolean; withTime?: boolean;
full?: boolean; full?: boolean;
}>(), }>(),

View file

@ -3,7 +3,7 @@
<template #empty> <template #empty>
<div class="_fullinfo"> <div class="_fullinfo">
<img <img
src="/static-assets/badges/info.png" src="/static-assets/badges/info.webp"
class="_ghost" class="_ghost"
alt="Info" alt="Info"
/> />

View file

@ -8,7 +8,7 @@
<slot name="empty"> <slot name="empty">
<div class="_fullinfo"> <div class="_fullinfo">
<img <img
src="/static-assets/badges/info.png" src="/static-assets/badges/info.webp"
class="_ghost" class="_ghost"
alt="Error" alt="Error"
/> />
@ -65,7 +65,7 @@
<script lang="ts" setup> <script lang="ts" setup>
import type { ComputedRef } from "vue"; import type { ComputedRef } from "vue";
import { computed, isRef, onActivated, onDeactivated, ref, watch } from "vue"; import { computed, isRef, onActivated, onDeactivated, ref, watch } from "vue";
import type * as misskey from "firefish-js"; import type * as firefish from "firefish-js";
import * as os from "@/os"; import * as os from "@/os";
import { import {
getScrollContainer, getScrollContainer,
@ -77,13 +77,13 @@ import MkButton from "@/components/MkButton.vue";
import { i18n } from "@/i18n"; import { i18n } from "@/i18n";
export interface Paging< export interface Paging<
E extends keyof misskey.Endpoints = keyof misskey.Endpoints, E extends keyof firefish.Endpoints = keyof firefish.Endpoints,
> { > {
endpoint: E; endpoint: E;
limit: number; limit: number;
params?: params?:
| misskey.Endpoints[E]["req"] | firefish.Endpoints[E]["req"]
| ComputedRef<misskey.Endpoints[E]["req"]>; | ComputedRef<firefish.Endpoints[E]["req"]>;
/** /**
* 検索APIのようなページング不可なエンドポイントを利用する場合 * 検索APIのようなページング不可なエンドポイントを利用する場合

View file

@ -53,7 +53,7 @@
<script lang="ts" setup> <script lang="ts" setup>
import { computed, ref } from "vue"; import { computed, ref } from "vue";
import type * as misskey from "firefish-js"; import type * as firefish from "firefish-js";
import { sum } from "@/scripts/array"; import { sum } from "@/scripts/array";
import { pleaseLogin } from "@/scripts/please-login"; import { pleaseLogin } from "@/scripts/please-login";
import * as os from "@/os"; import * as os from "@/os";
@ -61,7 +61,7 @@ import { i18n } from "@/i18n";
import { useInterval } from "@/scripts/use-interval"; import { useInterval } from "@/scripts/use-interval";
const props = defineProps<{ const props = defineProps<{
note: misskey.entities.Note; note: firefish.entities.Note;
readOnly?: boolean; readOnly?: boolean;
}>(); }>();

View file

@ -255,7 +255,7 @@ import {
watch, watch,
} from "vue"; } from "vue";
import * as mfm from "mfm-js"; import * as mfm from "mfm-js";
import type * as misskey from "firefish-js"; import type * as firefish from "firefish-js";
import autosize from "autosize"; import autosize from "autosize";
import insertTextAtCursor from "insert-text-at-cursor"; import insertTextAtCursor from "insert-text-at-cursor";
import { length } from "stringz"; import { length } from "stringz";
@ -285,28 +285,28 @@ import {
} from "@/account"; } from "@/account";
import { uploadFile } from "@/scripts/upload"; import { uploadFile } from "@/scripts/upload";
import { deepClone } from "@/scripts/clone"; import { deepClone } from "@/scripts/clone";
import { preprocess } from "@/scripts/preprocess"; import preprocess from "@/scripts/preprocess";
import { vibrate } from "@/scripts/vibrate"; import { vibrate } from "@/scripts/vibrate";
const modal = inject("modal"); const modal = inject("modal");
const props = withDefaults( const props = withDefaults(
defineProps<{ defineProps<{
reply?: misskey.entities.Note; reply?: firefish.entities.Note;
renote?: misskey.entities.Note; renote?: firefish.entities.Note;
channel?: any; // TODO channel?: any; // TODO
mention?: misskey.entities.User; mention?: firefish.entities.User;
specified?: misskey.entities.User; specified?: firefish.entities.User;
initialText?: string; initialText?: string;
initialVisibility?: typeof misskey.noteVisibilities; initialVisibility?: typeof firefish.noteVisibilities;
initialFiles?: misskey.entities.DriveFile[]; initialFiles?: firefish.entities.DriveFile[];
initialLocalOnly?: boolean; initialLocalOnly?: boolean;
initialVisibleUsers?: misskey.entities.User[]; initialVisibleUsers?: firefish.entities.User[];
initialNote?: misskey.entities.Note; initialNote?: firefish.entities.Note;
instant?: boolean; instant?: boolean;
fixed?: boolean; fixed?: boolean;
autofocus?: boolean; autofocus?: boolean;
editId?: misskey.entities.Note["id"]; editId?: firefish.entities.Note["id"];
}>(), }>(),
{ {
initialVisibleUsers: () => [], initialVisibleUsers: () => [],
@ -349,7 +349,7 @@ const visibility = ref(
((defaultStore.state.rememberNoteVisibility ((defaultStore.state.rememberNoteVisibility
? defaultStore.state.visibility ? defaultStore.state.visibility
: defaultStore.state : defaultStore.state
.defaultNoteVisibility) as (typeof misskey.noteVisibilities)[number]), .defaultNoteVisibility) as (typeof firefish.noteVisibilities)[number]),
); );
const visibleUsers = ref([]); const visibleUsers = ref([]);
if (props.initialVisibleUsers) { if (props.initialVisibleUsers) {
@ -987,7 +987,7 @@ function showActions(ev) {
); );
} }
const postAccount = ref<misskey.entities.UserDetailed | null>(null); const postAccount = ref<firefish.entities.UserDetailed | null>(null);
function openAccountMenu(ev: MouseEvent) { function openAccountMenu(ev: MouseEvent) {
openAccountMenu_( openAccountMenu_(

View file

@ -3,9 +3,9 @@
<VueDraggable <VueDraggable
v-model="_files" v-model="_files"
class="files" class="files"
animation="150" :animation="150"
delay="100" :delay="100"
delay-on-touch-only="true" :delay-on-touch-only="true"
> >
<div <div
v-for="element in _files" v-for="element in _files"

View file

@ -21,26 +21,26 @@
<script lang="ts" setup> <script lang="ts" setup>
import { shallowRef } from "vue"; import { shallowRef } from "vue";
import type * as misskey from "firefish-js"; import type * as firefish from "firefish-js";
import MkModal from "@/components/MkModal.vue"; import MkModal from "@/components/MkModal.vue";
import MkPostForm from "@/components/MkPostForm.vue"; import MkPostForm from "@/components/MkPostForm.vue";
const props = defineProps<{ const props = defineProps<{
reply?: misskey.entities.Note; reply?: firefish.entities.Note;
renote?: misskey.entities.Note; renote?: firefish.entities.Note;
channel?: any; // TODO channel?: any; // TODO
mention?: misskey.entities.User; mention?: firefish.entities.User;
specified?: misskey.entities.User; specified?: firefish.entities.User;
initialText?: string; initialText?: string;
initialVisibility?: typeof misskey.noteVisibilities; initialVisibility?: typeof firefish.noteVisibilities;
initialFiles?: misskey.entities.DriveFile[]; initialFiles?: firefish.entities.DriveFile[];
initialLocalOnly?: boolean; initialLocalOnly?: boolean;
initialVisibleUsers?: misskey.entities.User[]; initialVisibleUsers?: firefish.entities.User[];
initialNote?: misskey.entities.Note; initialNote?: firefish.entities.Note;
instant?: boolean; instant?: boolean;
fixed?: boolean; fixed?: boolean;
autofocus?: boolean; autofocus?: boolean;
editId?: misskey.entities.Note["id"]; editId?: firefish.entities.Note["id"];
}>(); }>();
const emit = defineEmits<{ const emit = defineEmits<{

View file

@ -32,16 +32,16 @@
<script lang="ts" setup> <script lang="ts" setup>
import { onMounted, ref, watch } from "vue"; import { onMounted, ref, watch } from "vue";
import type * as misskey from "firefish-js"; import type * as firefish from "firefish-js";
import MkReactionIcon from "@/components/MkReactionIcon.vue"; import MkReactionIcon from "@/components/MkReactionIcon.vue";
import MkUserCardMini from "@/components/MkUserCardMini.vue"; import MkUserCardMini from "@/components/MkUserCardMini.vue";
import * as os from "@/os"; import * as os from "@/os";
const props = defineProps<{ const props = defineProps<{
noteId: misskey.entities.Note["id"]; noteId: firefish.entities.Note["id"];
}>(); }>();
const note = ref<misskey.entities.Note>(); const note = ref<firefish.entities.Note>();
const tab = ref<string>(); const tab = ref<string>();
const reactions = ref<string[]>(); const reactions = ref<string[]>();
const users = ref(); const users = ref();

View file

@ -23,7 +23,7 @@
<script lang="ts" setup> <script lang="ts" setup>
import { computed, ref } from "vue"; import { computed, ref } from "vue";
import type * as misskey from "firefish-js"; import type * as firefish from "firefish-js";
import XDetails from "@/components/MkReactionsViewer.details.vue"; import XDetails from "@/components/MkReactionsViewer.details.vue";
import XReactionIcon from "@/components/MkReactionIcon.vue"; import XReactionIcon from "@/components/MkReactionIcon.vue";
import * as os from "@/os"; import * as os from "@/os";
@ -34,7 +34,7 @@ const props = defineProps<{
reaction: string; reaction: string;
count: number; count: number;
isInitial: boolean; isInitial: boolean;
note: misskey.entities.Note; note: firefish.entities.Note;
}>(); }>();
const emit = defineEmits<{ const emit = defineEmits<{

View file

@ -18,12 +18,12 @@
<script lang="ts" setup> <script lang="ts" setup>
import { computed, ref } from "vue"; import { computed, ref } from "vue";
import type * as misskey from "firefish-js"; import type * as firefish from "firefish-js";
import { $i } from "@/account"; import { $i } from "@/account";
import XReaction from "@/components/MkReactionsViewer.reaction.vue"; import XReaction from "@/components/MkReactionsViewer.reaction.vue";
const props = defineProps<{ const props = defineProps<{
note: misskey.entities.Note; note: firefish.entities.Note;
}>(); }>();
const reactionsEl = ref<HTMLElement>(); const reactionsEl = ref<HTMLElement>();

View file

@ -3,26 +3,26 @@
v-if="canRenote" v-if="canRenote"
ref="buttonRef" ref="buttonRef"
v-tooltip.noDelay.bottom="i18n.ts.renote" v-tooltip.noDelay.bottom="i18n.ts.renote"
class="button _button canRenote" class="button _button"
:class="{ renoted: hasRenotedBefore }" :class="{ renoted: hasRenotedBefore }"
@click.stop="renote(false, $event)" @click.stop="renote(false, $event)"
> >
<i class="ph-repeat ph-bold ph-lg"></i> <i class="ph-rocket-launch ph-bold ph-lg"></i>
<p v-if="count > 0 && !detailedView" class="count">{{ count }}</p> <p v-if="count > 0 && !detailedView" class="count">{{ count }}</p>
</button> </button>
<button <button
v-else v-else
v-tooltip.noDelay.bottom="i18n.ts.disabled" v-tooltip.noDelay.bottom="i18n.ts.disabled"
class="eddddedb _button" class="_button"
disabled="true" disabled="true"
> >
<i class="ph-repeat ph-bold ph-lg"></i> <i class="ph-rocket-launch ph-bold ph-lg"></i>
</button> </button>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { computed, ref } from "vue"; import { computed, ref } from "vue";
import type * as misskey from "firefish-js"; import type * as firefish from "firefish-js";
import Ripple from "@/components/MkRipple.vue"; import Ripple from "@/components/MkRipple.vue";
import XDetails from "@/components/MkUsersTooltip.vue"; import XDetails from "@/components/MkUsersTooltip.vue";
import { pleaseLogin } from "@/scripts/please-login"; import { pleaseLogin } from "@/scripts/please-login";
@ -35,7 +35,7 @@ import type { MenuItem } from "@/types/menu";
import { vibrate } from "@/scripts/vibrate"; import { vibrate } from "@/scripts/vibrate";
const props = defineProps<{ const props = defineProps<{
note: misskey.entities.Note; note: firefish.entities.Note;
count: number; count: number;
detailedView?; detailedView?;
}>(); }>();
@ -88,7 +88,7 @@ const renote = (viaKeyboard = false, ev?: MouseEvent) => {
if (props.note.visibility === "public") { if (props.note.visibility === "public") {
buttonActions.push({ buttonActions.push({
text: i18n.ts.renote, text: i18n.ts.renote,
icon: "ph-repeat ph-bold ph-lg", icon: "ph-rocket-launch ph-bold ph-lg",
danger: false, danger: false,
action: () => { action: () => {
os.api("notes/create", { os.api("notes/create", {
@ -266,7 +266,7 @@ const renote = (viaKeyboard = false, ev?: MouseEvent) => {
<style lang="scss" scoped> <style lang="scss" scoped>
.button { .button {
&:not(.canRenote) { &:not(.button) {
cursor: default; cursor: default;
} }
&.renoted { &.renoted {

View file

@ -177,7 +177,7 @@
<script lang="ts" setup> <script lang="ts" setup>
import { ref } from "vue"; import { ref } from "vue";
import type * as misskey from "firefish-js"; import type * as firefish from "firefish-js";
import * as mfm from "mfm-js"; import * as mfm from "mfm-js";
import * as os from "@/os"; import * as os from "@/os";
import XNoteSimple from "@/components/MkNoteSimple.vue"; import XNoteSimple from "@/components/MkNoteSimple.vue";
@ -194,7 +194,7 @@ import { i18n } from "@/i18n";
import { defaultStore } from "@/store"; import { defaultStore } from "@/store";
const props = defineProps<{ const props = defineProps<{
note: misskey.entities.Note; note: firefish.entities.Note;
parentId?; parentId?;
conversation?; conversation?;
detailed?: boolean; detailed?: boolean;

View file

@ -25,12 +25,12 @@
<script lang="ts" setup> <script lang="ts" setup>
import { ref } from "vue"; import { ref } from "vue";
import type * as misskey from "firefish-js"; import type * as firefish from "firefish-js";
import { acct, userPage } from "@/filters/user"; import { acct, userPage } from "@/filters/user";
const props = withDefaults( const props = withDefaults(
defineProps<{ defineProps<{
user: misskey.entities.User; user: firefish.entities.User;
showAboutPage?: boolean; showAboutPage?: boolean;
}>(), }>(),
{ {

View file

@ -89,7 +89,7 @@
<script lang="ts" setup> <script lang="ts" setup>
import { ref } from "vue"; import { ref } from "vue";
import type * as misskey from "firefish-js"; import type * as firefish from "firefish-js";
import MkFollowButton from "@/components/MkFollowButton.vue"; import MkFollowButton from "@/components/MkFollowButton.vue";
import XShowMoreButton from "@/components/MkShowMoreButton.vue"; import XShowMoreButton from "@/components/MkShowMoreButton.vue";
import MkNumber from "@/components/MkNumber.vue"; import MkNumber from "@/components/MkNumber.vue";
@ -98,7 +98,7 @@ import { i18n } from "@/i18n";
import { defaultStore } from "@/store"; import { defaultStore } from "@/store";
const props = defineProps<{ const props = defineProps<{
user: misskey.entities.UserDetailed; user: firefish.entities.UserDetailed;
detailed?: boolean; detailed?: boolean;
}>(); }>();

View file

@ -3,7 +3,7 @@
<template #empty> <template #empty>
<div class="_fullinfo"> <div class="_fullinfo">
<img <img
src="/static-assets/badges/info.png" src="/static-assets/badges/info.webp"
class="_ghost" class="_ghost"
alt="Info" alt="Info"
/> />

View file

@ -10,11 +10,11 @@
<script lang="ts" setup> <script lang="ts" setup>
import { computed } from "vue"; import { computed } from "vue";
import type * as misskey from "firefish-js"; import type * as firefish from "firefish-js";
import { i18n } from "@/i18n"; import { i18n } from "@/i18n";
const props = defineProps<{ const props = defineProps<{
user: misskey.entities.User; user: firefish.entities.User;
}>(); }>();
const text = computed(() => { const text = computed(() => {

View file

@ -30,7 +30,7 @@
<script lang="ts" setup> <script lang="ts" setup>
import { onMounted, ref } from "vue"; import { onMounted, ref } from "vue";
import * as Acct from "firefish-js/built/acct"; import * as Acct from "firefish-js/built/acct";
import type * as misskey from "firefish-js"; import type * as firefish from "firefish-js";
import MkUserInfo from "@/components/MkUserInfo.vue"; import MkUserInfo from "@/components/MkUserInfo.vue";
import * as os from "@/os"; import * as os from "@/os";
@ -47,7 +47,7 @@ const emit = defineEmits<{
}>(); }>();
const zIndex = os.claimZIndex("middle"); const zIndex = os.claimZIndex("middle");
const user = ref<misskey.entities.UserDetailed | null>(null); const user = ref<firefish.entities.UserDetailed | null>(null);
const top = ref(0); const top = ref(0);
const left = ref(0); const left = ref(0);

Some files were not shown because too many files have changed in this diff Show more