diff --git a/app/helpers/languages_helper.rb b/app/helpers/languages_helper.rb index ce88ebb5a3c..dbf56f45a04 100644 --- a/app/helpers/languages_helper.rb +++ b/app/helpers/languages_helper.rb @@ -100,7 +100,7 @@ module LanguagesHelper lo: ['Lao', 'ລາວ'].freeze, lt: ['Lithuanian', 'lietuvių kalba'].freeze, lu: ['Luba-Katanga', 'Tshiluba'].freeze, - lv: ['Latvian', 'latviešu valoda'].freeze, + lv: ['Latvian', 'Latviski'].freeze, mg: ['Malagasy', 'fiteny malagasy'].freeze, mh: ['Marshallese', 'Kajin M̧ajeļ'].freeze, mi: ['Māori', 'te reo Māori'].freeze, diff --git a/app/javascript/mastodon/features/compose/components/privacy_dropdown.jsx b/app/javascript/mastodon/features/compose/components/privacy_dropdown.jsx deleted file mode 100644 index 1c9434502c0..00000000000 --- a/app/javascript/mastodon/features/compose/components/privacy_dropdown.jsx +++ /dev/null @@ -1,158 +0,0 @@ -import PropTypes from 'prop-types'; -import { PureComponent } from 'react'; - -import { injectIntl, defineMessages } from 'react-intl'; - -import classNames from 'classnames'; - -import Overlay from 'react-overlays/Overlay'; - -import AlternateEmailIcon from '@/material-icons/400-24px/alternate_email.svg?react'; -import LockIcon from '@/material-icons/400-24px/lock.svg?react'; -import PublicIcon from '@/material-icons/400-24px/public.svg?react'; -import QuietTimeIcon from '@/material-icons/400-24px/quiet_time.svg?react'; -import { DropdownSelector } from 'mastodon/components/dropdown_selector'; -import { Icon } from 'mastodon/components/icon'; - -export const messages = defineMessages({ - public_short: { id: 'privacy.public.short', defaultMessage: 'Public' }, - public_long: { id: 'privacy.public.long', defaultMessage: 'Anyone on and off Mastodon' }, - unlisted_short: { id: 'privacy.unlisted.short', defaultMessage: 'Quiet public' }, - unlisted_long: { id: 'privacy.unlisted.long', defaultMessage: 'Hidden from Mastodon search results, trending, and public timelines' }, - private_short: { id: 'privacy.private.short', defaultMessage: 'Followers' }, - private_long: { id: 'privacy.private.long', defaultMessage: 'Only your followers' }, - direct_short: { id: 'privacy.direct.short', defaultMessage: 'Specific people' }, - direct_long: { id: 'privacy.direct.long', defaultMessage: 'Everyone mentioned in the post' }, - change_privacy: { id: 'privacy.change', defaultMessage: 'Change post privacy' }, - unlisted_extra: { id: 'privacy.unlisted.additional', defaultMessage: 'This behaves exactly like public, except the post will not appear in live feeds or hashtags, explore, or Mastodon search, even if you are opted-in account-wide.' }, -}); - -class PrivacyDropdown extends PureComponent { - - static propTypes = { - value: PropTypes.string.isRequired, - onChange: PropTypes.func.isRequired, - noDirect: PropTypes.bool, - container: PropTypes.func, - disabled: PropTypes.bool, - intl: PropTypes.object.isRequired, - }; - - state = { - open: false, - placement: 'bottom', - }; - - handleToggle = () => { - if (this.state.open && this.activeElement) { - this.activeElement.focus({ preventScroll: true }); - } - - this.setState({ open: !this.state.open }); - }; - - handleKeyDown = e => { - switch(e.key) { - case 'Escape': - this.handleClose(); - break; - } - }; - - handleMouseDown = () => { - if (!this.state.open) { - this.activeElement = document.activeElement; - } - }; - - handleButtonKeyDown = (e) => { - switch(e.key) { - case ' ': - case 'Enter': - this.handleMouseDown(); - break; - } - }; - - handleClose = () => { - if (this.state.open && this.activeElement) { - this.activeElement.focus({ preventScroll: true }); - } - this.setState({ open: false }); - }; - - handleChange = value => { - this.props.onChange(value); - }; - - UNSAFE_componentWillMount () { - const { intl: { formatMessage } } = this.props; - - this.options = [ - { icon: 'globe', iconComponent: PublicIcon, value: 'public', text: formatMessage(messages.public_short), meta: formatMessage(messages.public_long) }, - { icon: 'unlock', iconComponent: QuietTimeIcon, value: 'unlisted', text: formatMessage(messages.unlisted_short), meta: formatMessage(messages.unlisted_long), extra: formatMessage(messages.unlisted_extra) }, - { icon: 'lock', iconComponent: LockIcon, value: 'private', text: formatMessage(messages.private_short), meta: formatMessage(messages.private_long) }, - ]; - - if (!this.props.noDirect) { - this.options.push( - { icon: 'at', iconComponent: AlternateEmailIcon, value: 'direct', text: formatMessage(messages.direct_short), meta: formatMessage(messages.direct_long) }, - ); - } - } - - setTargetRef = c => { - this.target = c; - }; - - findTarget = () => { - return this.target; - }; - - handleOverlayEnter = (state) => { - this.setState({ placement: state.placement }); - }; - - render () { - const { value, container, disabled, intl } = this.props; - const { open, placement } = this.state; - - const valueOption = this.options.find(item => item.value === value); - - return ( -
- - - - {({ props, placement }) => ( -
-
- -
-
- )} -
-
- ); - } - -} - -export default injectIntl(PrivacyDropdown); diff --git a/app/javascript/mastodon/features/compose/components/privacy_dropdown.tsx b/app/javascript/mastodon/features/compose/components/privacy_dropdown.tsx new file mode 100644 index 00000000000..5a463d86e79 --- /dev/null +++ b/app/javascript/mastodon/features/compose/components/privacy_dropdown.tsx @@ -0,0 +1,199 @@ +import { useCallback, useRef, useState } from 'react'; + +import { defineMessages, useIntl } from 'react-intl'; + +import classNames from 'classnames'; + +import type { OverlayProps } from 'react-overlays/Overlay'; +import Overlay from 'react-overlays/Overlay'; + +import type { StatusVisibility } from '@/mastodon/api_types/statuses'; +import AlternateEmailIcon from '@/material-icons/400-24px/alternate_email.svg?react'; +import LockIcon from '@/material-icons/400-24px/lock.svg?react'; +import PublicIcon from '@/material-icons/400-24px/public.svg?react'; +import QuietTimeIcon from '@/material-icons/400-24px/quiet_time.svg?react'; +import { DropdownSelector } from 'mastodon/components/dropdown_selector'; +import { Icon } from 'mastodon/components/icon'; + +export const messages = defineMessages({ + public_short: { id: 'privacy.public.short', defaultMessage: 'Public' }, + public_long: { + id: 'privacy.public.long', + defaultMessage: 'Anyone on and off Mastodon', + }, + unlisted_short: { + id: 'privacy.unlisted.short', + defaultMessage: 'Quiet public', + }, + unlisted_long: { + id: 'privacy.unlisted.long', + defaultMessage: + 'Hidden from Mastodon search results, trending, and public timelines', + }, + private_short: { id: 'privacy.private.short', defaultMessage: 'Followers' }, + private_long: { + id: 'privacy.private.long', + defaultMessage: 'Only your followers', + }, + direct_short: { + id: 'privacy.direct.short', + defaultMessage: 'Specific people', + }, + direct_long: { + id: 'privacy.direct.long', + defaultMessage: 'Everyone mentioned in the post', + }, + change_privacy: { + id: 'privacy.change', + defaultMessage: 'Change post privacy', + }, + unlisted_extra: { + id: 'privacy.unlisted.additional', + defaultMessage: + 'This behaves exactly like public, except the post will not appear in live feeds or hashtags, explore, or Mastodon search, even if you are opted-in account-wide.', + }, +}); + +interface PrivacyDropdownProps { + value: StatusVisibility; + onChange: (value: StatusVisibility) => void; + noDirect?: boolean; + container?: OverlayProps['container']; + disabled?: boolean; +} + +const PrivacyDropdown: React.FC = ({ + value, + onChange, + noDirect, + container, + disabled, +}) => { + const intl = useIntl(); + const overlayTargetRef = useRef(null); + const previousFocusTargetRef = useRef(null); + const [isOpen, setIsOpen] = useState(false); + + const handleClose = useCallback(() => { + if (isOpen && previousFocusTargetRef.current) { + previousFocusTargetRef.current.focus({ preventScroll: true }); + } + setIsOpen(false); + }, [isOpen]); + + const handleToggle = useCallback(() => { + if (isOpen) { + handleClose(); + } + setIsOpen((prev) => !prev); + }, [handleClose, isOpen]); + + const registerPreviousFocusTarget = useCallback(() => { + if (!isOpen) { + previousFocusTargetRef.current = document.activeElement as HTMLElement; + } + }, [isOpen]); + + const handleButtonKeyDown = useCallback( + (e: React.KeyboardEvent) => { + if ([' ', 'Enter'].includes(e.key)) { + registerPreviousFocusTarget(); + } + }, + [registerPreviousFocusTarget], + ); + + const options = [ + { + icon: 'globe', + iconComponent: PublicIcon, + value: 'public', + text: intl.formatMessage(messages.public_short), + meta: intl.formatMessage(messages.public_long), + }, + { + icon: 'unlock', + iconComponent: QuietTimeIcon, + value: 'unlisted', + text: intl.formatMessage(messages.unlisted_short), + meta: intl.formatMessage(messages.unlisted_long), + extra: intl.formatMessage(messages.unlisted_extra), + }, + { + icon: 'lock', + iconComponent: LockIcon, + value: 'private', + text: intl.formatMessage(messages.private_short), + meta: intl.formatMessage(messages.private_long), + }, + ]; + + if (!noDirect) { + options.push({ + icon: 'at', + iconComponent: AlternateEmailIcon, + value: 'direct', + text: intl.formatMessage(messages.direct_short), + meta: intl.formatMessage(messages.direct_long), + }); + } + + const selectedOption = + options.find((item) => item.value === value) ?? options.at(0); + + return ( +
+ + + + {({ props, placement }) => ( +
+
+ +
+
+ )} +
+
+ ); +}; + +// eslint-disable-next-line import/no-default-export +export default PrivacyDropdown; diff --git a/app/javascript/mastodon/features/compose/containers/privacy_dropdown_container.js b/app/javascript/mastodon/features/compose/containers/privacy_dropdown_container.js deleted file mode 100644 index 803dcb1a4a0..00000000000 --- a/app/javascript/mastodon/features/compose/containers/privacy_dropdown_container.js +++ /dev/null @@ -1,19 +0,0 @@ -import { connect } from 'react-redux'; - -import { changeComposeVisibility } from '@/mastodon/actions/compose_typed'; - -import PrivacyDropdown from '../components/privacy_dropdown'; - -const mapStateToProps = state => ({ - value: state.getIn(['compose', 'privacy']), -}); - -const mapDispatchToProps = dispatch => ({ - - onChange (value) { - dispatch(changeComposeVisibility(value)); - }, - -}); - -export default connect(mapStateToProps, mapDispatchToProps)(PrivacyDropdown); diff --git a/app/javascript/mastodon/features/ui/components/boost_modal.tsx b/app/javascript/mastodon/features/ui/components/boost_modal.tsx index a55141167b0..7e45f574917 100644 --- a/app/javascript/mastodon/features/ui/components/boost_modal.tsx +++ b/app/javascript/mastodon/features/ui/components/boost_modal.tsx @@ -52,7 +52,10 @@ export const BoostModal: React.FC<{ }, [onClose]); const findContainer = useCallback( - () => document.getElementsByClassName('modal-root__container')[0], + () => + document.getElementsByClassName( + 'modal-root__container', + )[0] as HTMLDivElement, [], ); diff --git a/app/javascript/mastodon/locales/ca.json b/app/javascript/mastodon/locales/ca.json index 636c6f34dd8..81f89f962cf 100644 --- a/app/javascript/mastodon/locales/ca.json +++ b/app/javascript/mastodon/locales/ca.json @@ -250,6 +250,8 @@ "confirmations.missing_alt_text.title": "Hi voleu afegir text alternatiu?", "confirmations.mute.confirm": "Silencia", "confirmations.private_quote_notify.cancel": "Torna a l'edició", + "confirmations.private_quote_notify.confirm": "Publica la publicació", + "confirmations.private_quote_notify.do_not_show_again": "No tornis a mostrar-me aquest missatge", "confirmations.private_quote_notify.message": "La persona que citeu i altres mencionades rebran una notificació i podran veure la vostra publicació, encara que no us segueixen.", "confirmations.private_quote_notify.title": "Voleu compartir amb seguidors i usuaris mencionats?", "confirmations.quiet_post_quote_info.dismiss": "No m'ho tornis a recordar", @@ -341,7 +343,7 @@ "empty_column.bookmarked_statuses": "Encara no has marcat cap tut. Quan en marquis un, apareixerà aquí.", "empty_column.community": "La línia de temps local és buida. Escriu alguna cosa públicament per posar-ho tot en marxa!", "empty_column.direct": "Encara no tens mencions privades. Quan n'enviïs o en rebis una, et sortirà aquí.", - "empty_column.disabled_feed": "Aquest canal ha estat desactivat per l'administració del vostre servidor.", + "empty_column.disabled_feed": "L'administració del vostre servidor ha desactivat aquest canal.", "empty_column.domain_blocks": "Encara no hi ha dominis blocats.", "empty_column.explore_statuses": "No hi ha res en tendència ara mateix. Revisa-ho més tard!", "empty_column.favourited_statuses": "Encara no has afavorit cap tut. Quan ho facis, apareixerà aquí.", @@ -366,6 +368,7 @@ "explore.trending_links": "Notícies", "explore.trending_statuses": "Tuts", "explore.trending_tags": "Etiquetes", + "featured_carousel.current": "Publicació {current, number} / {max, number}", "featured_carousel.header": "{count, plural, one {Publicació fixada} other {Publicacions fixades}}", "featured_carousel.slide": "Publicació {current, number} de {max, number}", "filter_modal.added.context_mismatch_explanation": "Aquesta categoria de filtre no s'aplica al context en què has accedit a aquest tut. Si també vols que el tut es filtri en aquest context, hauràs d'editar el filtre.", diff --git a/app/javascript/mastodon/locales/cs.json b/app/javascript/mastodon/locales/cs.json index 4aa5ddccf99..6f32e5359ea 100644 --- a/app/javascript/mastodon/locales/cs.json +++ b/app/javascript/mastodon/locales/cs.json @@ -357,6 +357,7 @@ "empty_column.notification_requests": "Vyčištěno! Nic tu není. Jakmile obdržíš nové notifikace, objeví se zde podle tvého nastavení.", "empty_column.notifications": "Zatím nemáte žádná oznámení. Až s vámi někdo bude interagovat, uvidíte to zde.", "empty_column.public": "Tady nic není! Napište něco veřejně, nebo začněte ručně sledovat uživatele z jiných serverů, aby tu něco přibylo", + "error.no_hashtag_feed_access": "Zaregistrujte se nebo se přihlaste k zobrazení a sledování tohoto hashtagu.", "error.unexpected_crash.explanation": "Kvůli chybě v našem kódu nebo problému s kompatibilitou prohlížeče nemohla být tato stránka správně zobrazena.", "error.unexpected_crash.explanation_addons": "Tuto stránku nelze správně zobrazit. Takovou chybu obvykle způsobuje doplněk prohlížeče nebo nástroje pro automatický překlad.", "error.unexpected_crash.next_steps": "Zkuste stránku načíst znovu. Pokud to nepomůže, zkuste Mastodon používat pomocí jiného prohlížeče nebo nativní aplikace.", diff --git a/app/javascript/mastodon/locales/cy.json b/app/javascript/mastodon/locales/cy.json index 9f3631a0fe4..fcf33e4635d 100644 --- a/app/javascript/mastodon/locales/cy.json +++ b/app/javascript/mastodon/locales/cy.json @@ -357,6 +357,7 @@ "empty_column.notification_requests": "Dim i boeni amdano! Does dim byd yma. Pan fyddwch yn derbyn hysbysiadau newydd, byddan nhw'n ymddangos yma yn ôl eich gosodiadau.", "empty_column.notifications": "Does gennych chi ddim hysbysiadau eto. Pan fyddwch chi'n rhyngweithio ag eraill, byddwch yn ei weld yma.", "empty_column.public": "Does dim byd yma! Ysgrifennwch rywbeth cyhoeddus, neu dilynwch ddefnyddwyr o weinyddion eraill i'w lanw", + "error.no_hashtag_feed_access": "Ymunwch neu mewngofnodwch i weld a dilyn yr hashnod hwn.", "error.unexpected_crash.explanation": "Oherwydd gwall yn ein cod neu oherwydd problem cysondeb porwr, nid oedd y dudalen hon gallu cael ei dangos yn gywir.", "error.unexpected_crash.explanation_addons": "Does dim modd dangos y dudalen hon yn gywir. Mae'r gwall hwn yn debygol o gael ei achosi gan ategyn porwr neu offer cyfieithu awtomatig.", "error.unexpected_crash.next_steps": "Ceisiwch ail-lwytho'r dudalen. Os nad yw hyn yn eich helpu, efallai gallwch ddefnyddio Mastodon trwy borwr neu ap brodorol gwahanol.", diff --git a/app/javascript/mastodon/locales/da.json b/app/javascript/mastodon/locales/da.json index b480c2062c8..8bd2fdc8f9a 100644 --- a/app/javascript/mastodon/locales/da.json +++ b/app/javascript/mastodon/locales/da.json @@ -357,6 +357,7 @@ "empty_column.notification_requests": "Alt er klar! Der er intet her. Når der modtages nye notifikationer, fremgår de her jævnfør dine indstillinger.", "empty_column.notifications": "Du har endnu ingen notifikationer. Når andre interagerer med dig, vil det fremgå her.", "empty_column.public": "Der er ikke noget her! Skriv noget offentligt, eller følg manuelt brugere fra andre servere for at se indhold", + "error.no_hashtag_feed_access": "Tilmeld dig eller log ind for at se og følge dette hashtag.", "error.unexpected_crash.explanation": "Grundet en fejl i vores kode, eller en netlæser-kompatibilitetsfejl, kunne siden ikke vises korrekt.", "error.unexpected_crash.explanation_addons": "Denne side kunne ikke vises korrekt. Fejlen skyldes sandsynligvis en browsertilføjelse eller automatiske oversættelsesværktøjer.", "error.unexpected_crash.next_steps": "Prøv at opfriske siden. Hjælper dette ikke, kan Mastodon muligvis stadig bruges via en anden netlæser eller app.", diff --git a/app/javascript/mastodon/locales/de.json b/app/javascript/mastodon/locales/de.json index 40cd74f23fa..d7328b6d612 100644 --- a/app/javascript/mastodon/locales/de.json +++ b/app/javascript/mastodon/locales/de.json @@ -357,6 +357,7 @@ "empty_column.notification_requests": "Alles klar! Hier gibt es nichts. Wenn Sie neue Mitteilungen erhalten, werden diese entsprechend Ihren Einstellungen hier angezeigt.", "empty_column.notifications": "Du hast noch keine Benachrichtigungen. Sobald andere Personen mit dir interagieren, wirst du hier darüber informiert.", "empty_column.public": "Hier ist nichts zu sehen! Schreibe etwas öffentlich oder folge Profilen von anderen Servern, um die Timeline aufzufüllen", + "error.no_hashtag_feed_access": "Registriere dich oder melde dich an, um den Hashtag anzusehen und ihm zu folgen.", "error.unexpected_crash.explanation": "Wegen eines Fehlers in unserem Code oder aufgrund einer Browser-Inkompatibilität kann diese Seite nicht korrekt angezeigt werden.", "error.unexpected_crash.explanation_addons": "Diese Seite konnte nicht korrekt angezeigt werden. Dieser Fehler wird wahrscheinlich durch ein Browser-Add-on oder automatische Übersetzungswerkzeuge verursacht.", "error.unexpected_crash.next_steps": "Versuche, die Seite neu zu laden. Wenn das nicht helfen sollte, kannst du das Webinterface von Mastodon vermutlich über einen anderen Browser erreichen – oder du verwendest eine mobile (native) App.", @@ -759,7 +760,7 @@ "privacy.quote.disabled": "{visibility} – niemand darf zitieren", "privacy.quote.limited": "{visibility} – eingeschränktes Zitieren", "privacy.unlisted.additional": "Das Verhalten ist wie bei „Öffentlich“, jedoch gibt es einige Einschränkungen. Der Beitrag wird nicht in „Live-Feeds“, „Erkunden“, Hashtags oder über die Mastodon-Suchfunktion auffindbar sein – selbst wenn die zugehörige Einstellung aktiviert wurde.", - "privacy.unlisted.long": "Verborgen vor Suchergebnissen, Trends und öffentlichen Timelines auf Mastodon", + "privacy.unlisted.long": "Verborgen vor Suchergebnissen, Trends und öffentlichen Timelines", "privacy.unlisted.short": "Öffentlich (still)", "privacy_policy.last_updated": "Stand: {date}", "privacy_policy.title": "Datenschutzerklärung", diff --git a/app/javascript/mastodon/locales/el.json b/app/javascript/mastodon/locales/el.json index 244c69dd029..ffe2eceacb0 100644 --- a/app/javascript/mastodon/locales/el.json +++ b/app/javascript/mastodon/locales/el.json @@ -357,6 +357,7 @@ "empty_column.notification_requests": "Όλα καθαρά! Δεν υπάρχει τίποτα εδώ. Όταν λαμβάνεις νέες ειδοποιήσεις, αυτές θα εμφανίζονται εδώ σύμφωνα με τις ρυθμίσεις σου.", "empty_column.notifications": "Δεν έχεις ειδοποιήσεις ακόμα. Όταν άλλα άτομα αλληλεπιδράσουν μαζί σου, θα το δεις εδώ.", "empty_column.public": "Δεν υπάρχει τίποτα εδώ! Γράψε κάτι δημόσιο ή ακολούθησε χειροκίνητα χρήστες από άλλους διακομιστές για να τη γεμίσεις", + "error.no_hashtag_feed_access": "Γίνετε μέλος ή συνδεθείτε για να δείτε και να ακολουθήσετε αυτήν την ετικέτα.", "error.unexpected_crash.explanation": "Είτε λόγω σφάλματος στον κώδικά μας ή λόγω ασυμβατότητας με τον περιηγητή, η σελίδα δε μπόρεσε να εμφανιστεί σωστά.", "error.unexpected_crash.explanation_addons": "Η σελίδα δεν μπόρεσε να εμφανιστεί σωστά. Το πρόβλημα οφείλεται πιθανόν σε κάποια επέκταση του φυλλομετρητή ή σε κάποιο αυτόματο εργαλείο μετάφρασης.", "error.unexpected_crash.next_steps": "Δοκίμασε να ανανεώσεις τη σελίδα. Αν αυτό δε βοηθήσει, ίσως να μπορέσεις να χρησιμοποιήσεις το Mastodon μέσω διαφορετικού περιηγητή ή κάποιας εφαρμογής.", diff --git a/app/javascript/mastodon/locales/es-AR.json b/app/javascript/mastodon/locales/es-AR.json index 596ad83af07..b470c1d523e 100644 --- a/app/javascript/mastodon/locales/es-AR.json +++ b/app/javascript/mastodon/locales/es-AR.json @@ -357,6 +357,7 @@ "empty_column.notification_requests": "¡Todo limpio! No hay nada acá. Cuando recibás nuevas notificaciones, aparecerán acá, acorde a tu configuración.", "empty_column.notifications": "Todavía no tenés ninguna notificación. Cuando otras cuentas interactúen con vos, vas a ver la notificación acá.", "empty_column.public": "¡Naranja! Escribí algo públicamente, o seguí usuarios manualmente de otros servidores para ir llenando esta línea temporal", + "error.no_hashtag_feed_access": "Únete o inicia sesión para ver y seguir esta etiqueta.", "error.unexpected_crash.explanation": "Debido a un error en nuestro código o a un problema de compatibilidad con el navegador web, esta página no se pudo mostrar correctamente.", "error.unexpected_crash.explanation_addons": "No se pudo mostrar correctamente esta página. Este error probablemente es causado por un complemento del navegador web o por herramientas de traducción automática.", "error.unexpected_crash.next_steps": "Intentá recargar la página. Si eso no ayuda, podés usar Mastodon a través de un navegador web diferente o aplicación nativa.", diff --git a/app/javascript/mastodon/locales/es-MX.json b/app/javascript/mastodon/locales/es-MX.json index f7494d34450..69dcde9181e 100644 --- a/app/javascript/mastodon/locales/es-MX.json +++ b/app/javascript/mastodon/locales/es-MX.json @@ -357,6 +357,7 @@ "empty_column.notification_requests": "¡Todo limpio! No hay nada aquí. Cuando recibas nuevas notificaciones, aparecerán aquí conforme a tu configuración.", "empty_column.notifications": "No tienes ninguna notificación aún. Interactúa con otros para empezar una conversación.", "empty_column.public": "¡Aquí no hay nada! Escribe algo públicamente o sigue manualmente a usuarios de otros servidores para llenarlo", + "error.no_hashtag_feed_access": "Únete o inicia sesión para ver y seguir esta etiqueta.", "error.unexpected_crash.explanation": "Debido a un error en nuestro código o a un problema de compatibilidad con el navegador, esta página no se ha podido mostrar correctamente.", "error.unexpected_crash.explanation_addons": "No se pudo mostrar correctamente esta página. Este error probablemente fue causado por un complemento del navegador web o por herramientas de traducción automática.", "error.unexpected_crash.next_steps": "Intenta actualizar la página. Si eso no ayuda, es posible que puedas usar Mastodon a través de otro navegador o aplicación nativa.", diff --git a/app/javascript/mastodon/locales/es.json b/app/javascript/mastodon/locales/es.json index 87bb231f6ec..1501531fc3c 100644 --- a/app/javascript/mastodon/locales/es.json +++ b/app/javascript/mastodon/locales/es.json @@ -357,6 +357,7 @@ "empty_column.notification_requests": "¡Todo limpio! No hay nada aquí. Cuando recibas nuevas notificaciones, aparecerán aquí conforme a tu configuración.", "empty_column.notifications": "Aún no tienes ninguna notificación. Cuando otras personas interactúen contigo, aparecerán aquí.", "empty_column.public": "¡No hay nada aquí! Escribe algo públicamente, o sigue usuarios de otras instancias manualmente para llenarlo", + "error.no_hashtag_feed_access": "Únete o inicia sesión para ver y seguir esta etiqueta.", "error.unexpected_crash.explanation": "Debido a un error en nuestro código o a un problema de compatibilidad con el navegador, esta página no se ha podido mostrar correctamente.", "error.unexpected_crash.explanation_addons": "No se pudo mostrar correctamente esta página. Este error probablemente fue causado por un complemento del navegador web o por herramientas de traducción automática.", "error.unexpected_crash.next_steps": "Intenta actualizar la página. Si eso no ayuda, quizás puedas usar Mastodon desde otro navegador o aplicación nativa.", diff --git a/app/javascript/mastodon/locales/et.json b/app/javascript/mastodon/locales/et.json index c645e774285..c19aa7d6b9c 100644 --- a/app/javascript/mastodon/locales/et.json +++ b/app/javascript/mastodon/locales/et.json @@ -36,7 +36,7 @@ "account.familiar_followers_two": "Jälgijateks {name1} ja {name2}", "account.featured": "Esiletõstetud", "account.featured.accounts": "Profiilid", - "account.featured.hashtags": "Sildid", + "account.featured.hashtags": "Teemaviited", "account.featured_tags.last_status_at": "Viimane postitus {date}", "account.featured_tags.last_status_never": "Postitusi pole", "account.follow": "Jälgi", @@ -126,8 +126,8 @@ "annual_report.summary.highlighted_post.by_replies": "kõige vastatum postitus", "annual_report.summary.highlighted_post.possessive": "omanik {name}", "annual_report.summary.most_used_app.most_used_app": "enim kasutatud äpp", - "annual_report.summary.most_used_hashtag.most_used_hashtag": "enim kasutatud silt", - "annual_report.summary.most_used_hashtag.none": "Pole", + "annual_report.summary.most_used_hashtag.most_used_hashtag": "enim kasutatud teemaviide", + "annual_report.summary.most_used_hashtag.none": "Puudub", "annual_report.summary.new_posts.new_posts": "uus postitus", "annual_report.summary.percentile.text": "See paneb su top {domain} kasutajate hulka.", "annual_report.summary.percentile.we_wont_tell_bernie": "Vägev.", @@ -204,7 +204,7 @@ "compose.saved.body": "Postitus salvestatud.", "compose_form.direct_message_warning_learn_more": "Vaata lisa", "compose_form.encryption_warning": "Postitused Mastodonis ei ole otsast-otsani krüpteeritud. Ära jaga mingeid delikaatseid andmeid Mastodoni kaudu.", - "compose_form.hashtag_warning": "See postitus ei ilmu ühegi märksõna all, kuna pole avalik. Vaid avalikud postitused on märksõnade kaudu leitavad.", + "compose_form.hashtag_warning": "See postitus ei ilmu ühegi teemaviite all, kuna pole avalik. Vaid avalikud postitused on teemaviidete kaudu leitavad.", "compose_form.lock_disclaimer": "Su konto ei ole {locked}. Igaüks saab sind jälgida, et näha su ainult-jälgijatele postitusi.", "compose_form.lock_disclaimer.lock": "lukus", "compose_form.placeholder": "Millest mõtled?", @@ -332,8 +332,8 @@ "emoji_button.search_results": "Otsitulemused", "emoji_button.symbols": "Sümbolid", "emoji_button.travel": "Reisimine & kohad", - "empty_column.account_featured.me": "Sa pole veel midagi esile tõstnud. Kas sa teadsid, et oma profiilis saad esile tõsta enamkasutatavaid silte või või sõbra kasutajakontot?", - "empty_column.account_featured.other": "{acct} pole veel midagi esile tõstnud. Kas sa teadsid, et oma profiilis saad esile tõsta enamkasutatavaid silte või või sõbra kasutajakontot?", + "empty_column.account_featured.me": "Sa pole veel midagi esile tõstnud. Kas sa teadsid, et oma profiilis saad esile tõsta enamkasutatavaid teemaviiteid või sõbra kasutajakontot?", + "empty_column.account_featured.other": "{acct} pole veel midagi esile tõstnud. Kas sa teadsid, et oma profiilis saad esile tõsta enamkasutatavaid teemaviiteid või sõbra kasutajakontot?", "empty_column.account_featured_other.unknown": "See kasutajakonto pole veel midagi esile tõstnud.", "empty_column.account_hides_collections": "See kasutaja otsustas mitte teha seda infot saadavaks", "empty_column.account_suspended": "Konto kustutatud", @@ -349,14 +349,15 @@ "empty_column.favourited_statuses": "Pole veel lemmikpostitusi. Kui märgid mõne, näed neid siin.", "empty_column.favourites": "Keegi pole veel seda postitust lemmikuks märkinud. Kui keegi seda teeb, siis on ta nähtav siin.", "empty_column.follow_requests": "Pole hetkel ühtegi jälgimistaotlust. Kui saad mõne, näed neid siin.", - "empty_column.followed_tags": "Sa ei jälgi veel ühtegi märksõna. Kui jälgid, ilmuvad need siia.", - "empty_column.hashtag": "Selle sildi all ei ole ühtegi postitust.", + "empty_column.followed_tags": "Sa ei jälgi veel ühtegi teemaviidet. Kui jälgid, ilmuvad need siia.", + "empty_column.hashtag": "Selle teemaviite all ei ole ühtegi postitust.", "empty_column.home": "Su koduajajoon on tühi. Jälgi rohkemaid inimesi, et seda täita {suggestions}", "empty_column.list": "Siin loetelus pole veel midagi. Kui loetelu liikmed teevad uusi postitusi, näed neid siin.", "empty_column.mutes": "Sa pole veel ühtegi kasutajat summutanud.", "empty_column.notification_requests": "Kõik tühi! Siin pole mitte midagi. Kui saad uusi teavitusi, ilmuvad need siin vastavalt sinu seadistustele.", "empty_column.notifications": "Ei ole veel teateid. Kui keegi suhtleb sinuga, näed seda siin.", "empty_column.public": "Siin pole midagi! Kirjuta midagi avalikku või jälgi ise kasutajaid täitmaks seda ruumi", + "error.no_hashtag_feed_access": "Selle teemaviite jälgimiseks liitu teenusega või logi sisse oma kasutajakontoga.", "error.unexpected_crash.explanation": "Meie poolse probleemi või veebilehitseja ühilduvusprobleemi tõttu ei suutnud me seda lehekülge korrektselt näidata.", "error.unexpected_crash.explanation_addons": "Seda lehte ei suudetud õigesti kuvada. Selle vea põhjustas arvatavasti mõni lehitseja lisand või automaattõlke tööriist.", "error.unexpected_crash.next_steps": "Proovi lehekülge uuesti avada. Kui see ei aita, võib proovida kasutada Mastodoni mõne muu veebilehitseja või äpi kaudu.", @@ -367,7 +368,7 @@ "explore.title": "Populaarsust koguv", "explore.trending_links": "Uudised", "explore.trending_statuses": "Postitused", - "explore.trending_tags": "Sildid", + "explore.trending_tags": "Teemaviited", "featured_carousel.current": "Postitus {current, number} / {max, number}", "featured_carousel.header": "{count, plural, one {Esiletõstetud postitus} other {Esiletõstetud postitust}}", "featured_carousel.slide": "Postitus {current, number} / {max, number}", @@ -411,7 +412,7 @@ "follow_suggestions.similar_to_recently_followed_longer": "Sarnane profiilile, mida hiljuti jälgima hakkasid", "follow_suggestions.view_all": "Vaata kõiki", "follow_suggestions.who_to_follow": "Keda jälgida", - "followed_tags": "Jälgitavad märksõnad", + "followed_tags": "Jälgitavad teemaviited", "footer.about": "Teave", "footer.about_this_server": "Serveri teave", "footer.directory": "Profiilikataloog", @@ -424,17 +425,17 @@ "generic.saved": "Salvestatud", "getting_started.heading": "Alustamine", "hashtag.admin_moderation": "Ava modereerimisliides #{name} jaoks", - "hashtag.browse": "Sirvi #{hashtag} sildiga postitusi", - "hashtag.browse_from_account": "Sirvi @{name} kasutaja #{hashtag} sildiga postitusi", + "hashtag.browse": "Sirvi #{hashtag} teemaviitega postitusi", + "hashtag.browse_from_account": "Sirvi @{name} kasutaja #{hashtag} teemaviitega postitusi", "hashtag.column_header.tag_mode.all": "ja {additional}", - "hashtag.column_header.tag_mode.any": "või {additional}", - "hashtag.column_header.tag_mode.none": "ilma {additional}", + "hashtag.column_header.tag_mode.any": "või teemaviide {additional}", + "hashtag.column_header.tag_mode.none": "ilma teemaviiteta {additional}", "hashtag.column_settings.select.no_options_message": "Soovitusi ei leitud", "hashtag.column_settings.select.placeholder": "Sisesta sildid…", "hashtag.column_settings.tag_mode.all": "Kõik need", "hashtag.column_settings.tag_mode.any": "Mõni neist", "hashtag.column_settings.tag_mode.none": "Mitte ükski neist", - "hashtag.column_settings.tag_toggle": "Kaasa lisamärked selle tulba jaoks", + "hashtag.column_settings.tag_toggle": "Kaasa lisasildid selle veeru jaoks", "hashtag.counter_by_accounts": "{count, plural, one {{counter} osalejaga} other {{counter} osalejaga}}", "hashtag.counter_by_uses": "{count, plural, one {{counter} postitusega} other {{counter} postitusega}}", "hashtag.counter_by_uses_today": "{count, plural, one {{counter} postitust} other {{counter} postitust}} täna", @@ -580,7 +581,7 @@ "navigation_bar.favourites": "Lemmikud", "navigation_bar.filters": "Summutatud sõnad", "navigation_bar.follow_requests": "Jälgimistaotlused", - "navigation_bar.followed_tags": "Jälgitavad märksõnad", + "navigation_bar.followed_tags": "Jälgitavad teemaviited", "navigation_bar.follows_and_followers": "Jälgitavad ja jälgijad", "navigation_bar.import_export": "Import ja eksport", "navigation_bar.lists": "Loetelud", @@ -730,7 +731,7 @@ "onboarding.profile.display_name": "Näidatav nimi", "onboarding.profile.display_name_hint": "Su täisnimi või naljanimi…", "onboarding.profile.note": "Elulugu", - "onboarding.profile.note_hint": "Saad @mainida teisi kasutajaid või #sildistada…", + "onboarding.profile.note_hint": "Saad @mainida teisi kasutajaid või lisada #teemaviidet…", "onboarding.profile.save_and_continue": "Salvesta ja jätka", "onboarding.profile.title": "Profiili seadistamine", "onboarding.profile.upload_avatar": "Laadi üles profiilipilt", @@ -758,7 +759,7 @@ "privacy.quote.anyone": "{visibility}, kõik võivad tsiteerida", "privacy.quote.disabled": "{visibility}, tsiteerimine pole lubatud", "privacy.quote.limited": "{visibility}, tsiteerimine on piiratud", - "privacy.unlisted.additional": "See on olemuselt küll avalik, aga postitus ei ilmu voogudes ega märksõnades, lehitsedes ega Mastodoni otsingus, isegi kui konto on seadistustes avalik.", + "privacy.unlisted.additional": "See on olemuselt küll avalik, aga postitus ei ilmu voogudes ega teemaviidetes, lehitsedes ega Mastodoni otsingus, isegi kui konto on seadistustes avalik.", "privacy.unlisted.long": "Peidetud Mastodoni otsingutulemustest, pupulaarsust koguva sisu voost ja avalikult ajajoonelt", "privacy.unlisted.short": "Vaikselt avalik", "privacy_policy.last_updated": "Viimati uuendatud {date}", @@ -845,7 +846,7 @@ "search.placeholder": "Otsi", "search.quick_action.account_search": "Sobivaid profiile {x}", "search.quick_action.go_to_account": "Mine profiili {x}", - "search.quick_action.go_to_hashtag": "Ava silt {x}", + "search.quick_action.go_to_hashtag": "Ava teemaviide {x}", "search.quick_action.open_url": "Ava URL Mastodonis", "search.quick_action.status_search": "Sobivad postitused {x}", "search.search_or_paste": "Otsi või kleebi URL", @@ -861,7 +862,7 @@ "search_results.all": "Kõik", "search_results.hashtags": "Sildid", "search_results.no_results": "Tulemusi pole.", - "search_results.no_search_yet": "Proovi otsida postitusi, profiile või silte.", + "search_results.no_search_yet": "Proovi otsida postitusi, profiile või teemaviiteid.", "search_results.see_all": "Vaata kõiki", "search_results.statuses": "Postitused", "search_results.title": "Otsi märksõna: {q}", diff --git a/app/javascript/mastodon/locales/fi.json b/app/javascript/mastodon/locales/fi.json index 4aa6c425b20..9b3aacb9b4a 100644 --- a/app/javascript/mastodon/locales/fi.json +++ b/app/javascript/mastodon/locales/fi.json @@ -357,6 +357,7 @@ "empty_column.notification_requests": "Olet ajan tasalla! Täällä ei ole mitään uutta kerrottavaa. Kun saat uusia ilmoituksia, ne näkyvät täällä asetustesi mukaisesti.", "empty_column.notifications": "Sinulla ei ole vielä ilmoituksia. Kun muut ovat vuorovaikutuksessa kanssasi, näet sen täällä.", "empty_column.public": "Täällä ei ole mitään! Kirjoita jotain julkisesti tai seuraa muiden palvelinten käyttäjiä, niin saat sisältöä", + "error.no_hashtag_feed_access": "Liity tai kirjaudu sisään, niin voit tarkastella ja seurata tätä aihetunnistetta.", "error.unexpected_crash.explanation": "Sivua ei voida näyttää oikein ohjelmointivirheen tai selaimen yhteensopivuusvajeen vuoksi.", "error.unexpected_crash.explanation_addons": "Sivua ei voitu näyttää oikein. Tämä virhe johtuu todennäköisesti selaimen lisäosasta tai automaattisista käännöstyökaluista.", "error.unexpected_crash.next_steps": "Kokeile päivittää sivu. Jos se ei auta, voi Mastodonin käyttö ehkä onnistua eri selaimella tai natiivisovelluksella.", diff --git a/app/javascript/mastodon/locales/fil.json b/app/javascript/mastodon/locales/fil.json index 37db5a1b159..82c1616ddf2 100644 --- a/app/javascript/mastodon/locales/fil.json +++ b/app/javascript/mastodon/locales/fil.json @@ -1,6 +1,7 @@ { "about.blocks": "Mga pinatimping server", "about.contact": "Kontak:", + "about.default_locale": "Default", "about.disclaimer": "Ang Mastodon ay software na malaya at bukas-na-pinagmulan, at isang tatak-pangkalakal ng Mastodon gGmbH.", "about.domain_blocks.no_reason_available": "Hindi makuha ang dahilan", "about.domain_blocks.preamble": "Sa kadalasan, hinahayaan ka ng Mastodon na makita ang mga content sa, at makipag-interact sa users ng, ibang servers sa fediverse. Narito ang exceptions na ginawa sa partikular na server na ito.", @@ -8,6 +9,7 @@ "about.domain_blocks.silenced.title": "Limitado", "about.domain_blocks.suspended.explanation": "Walang data mula sa server na ito ang mapoproseso, maiimbak o maipagpapaplitan. Sa gayon. imposibleng magawa ang interaksiyon o komunikasyon sa ibang users sa server na ito.", "about.domain_blocks.suspended.title": "Suspendido", + "about.language_label": "Wika", "about.not_available": "Hindi available ang impormasyong ito.", "about.powered_by": "Decentralisadong social media na pinapagana ng {mastodon}", "about.rules": "Mga alituntunin ng server", @@ -19,21 +21,31 @@ "account.block_domain": "Hadlangan ang domain na {domain}", "account.block_short": "Hadlangan", "account.blocked": "Hinadlangan", + "account.blocking": "Pagharang", "account.cancel_follow_request": "I-kansela ang pagsunod", "account.copy": "I-sipi ang kawing sa profile", "account.direct": "Palihim banggitin si @{name}", "account.disable_notifications": "I-tigil ang pagpapaalam sa akin tuwing nagpopost si @{name}", + "account.domain_blocking": "Pag-block ng domain", "account.edit_profile": "Baguhin ang profile", + "account.edit_profile_short": "I-edit", "account.enable_notifications": "Ipaalam sa akin kapag nag-post si @{name}", "account.endorse": "I-tampok sa profile", "account.familiar_followers_many": "Sinusundan nina {name1}, {name2}, at {othersCount, plural, one {# iba pa na kilala mo} other {# na iba pa na kilala mo}}", "account.familiar_followers_one": "Sinusindan ni/ng {name1}", "account.familiar_followers_two": "Sinusindan nina {name1} at {name2}", "account.featured": "Itinatampok", + "account.featured.accounts": "Mga Profile", + "account.featured.hashtags": "Mga Hashtag", "account.featured_tags.last_status_at": "Huling post noong {date}", "account.featured_tags.last_status_never": "Walang mga post", "account.follow": "Sundan", "account.follow_back": "Sundan pabalik", + "account.follow_back_short": "I-follow back", + "account.follow_request": "Humiling na mag-follow", + "account.follow_request_cancel": "I-cancel ang request", + "account.follow_request_cancel_short": "Cancel", + "account.follow_request_short": "Request", "account.followers": "Mga tagasunod", "account.followers.empty": "Wala pang sumusunod sa tagagamit na ito.", "account.followers_counter": "{count, plural, one {{counter} tagasunod} other {{counter} tagasunod}}", @@ -56,15 +68,29 @@ "account.mute_notifications_short": "I-mute ang mga abiso", "account.mute_short": "I-mute", "account.muted": "Naka-mute", + "account.muting": "Pag-mute", + "account.mutual": "Pina-follow nyo ang isa't-isa", "account.no_bio": "Walang nakalaan na paglalarawan.", "account.open_original_page": "Buksan ang pinagmulang pahina", "account.posts": "Mga post", + "account.posts_with_replies": "Mga Post at Reply", + "account.remove_from_followers": "Alisin si {name} sa mga follower", "account.report": "I-ulat si/ang @{name}", "account.requested_follow": "Hinihiling ni {name} na sundan ka", + "account.requests_to_follow_you": "Mga Request para i-fillow ka", "account.share": "Ibahagi ang profile ni @{name}", "account.show_reblogs": "Ipakita ang mga pagpapalakas mula sa/kay {name}", + "account.statuses_counter": "{count,plural,one {{counter} i-post} other {{counter} mga post}}", + "account.unblock": "I-unblock si @{name}", + "account.unblock_domain": "I-unblock ang domain {domain}", + "account.unblock_domain_short": "I-unblock", + "account.unblock_short": "I-unblock", "account.unendorse": "Huwag itampok sa profile", "account.unfollow": "Huwag nang sundan", + "account.unmute": "I-unmute si @{name}", + "account.unmute_notifications_short": "I-unmute ang mga notification", + "account.unmute_short": "I-unmute", + "account_note.placeholder": "I-click para magdagdag ng note", "admin.dashboard.retention.cohort_size": "Mga bagong tagagamit", "alert.rate_limited.message": "Mangyaring subukan muli pagkatapos ng {retry_time, time, medium}.", "audio.hide": "Itago ang tunog", diff --git a/app/javascript/mastodon/locales/ga.json b/app/javascript/mastodon/locales/ga.json index 5cafc8f61bf..ed866f32ce6 100644 --- a/app/javascript/mastodon/locales/ga.json +++ b/app/javascript/mastodon/locales/ga.json @@ -357,6 +357,7 @@ "empty_column.notification_requests": "Gach soiléir! Níl aon rud anseo. Nuair a gheobhaidh tú fógraí nua, beidh siad le feiceáil anseo de réir do shocruithe.", "empty_column.notifications": "Níl aon fógraí agat fós. Nuair a dhéanann daoine eile idirghníomhú leat, feicfear anseo é.", "empty_column.public": "Faic anseo! Scríobh rud éigin go poiblí, nó lean úsáideoirí ar fhreastalaithe eile chun é a líonadh", + "error.no_hashtag_feed_access": "Bí linn nó logáil isteach chun an haischlib seo a fheiceáil agus a leanúint.", "error.unexpected_crash.explanation": "De bharr fabht inár gcód, nó fadhb le chomhoiriúnacht brabhsálaí, níorbh fhéadfadh an leathanach seo a léiriú i gceart.", "error.unexpected_crash.explanation_addons": "Ní taispeántar an leathanach seo mar is ceart. Is dócha go gcruthaíonn breiseán brabhsálaí nó uirlisí uathaistriúcháin an fhadhb seo.", "error.unexpected_crash.next_steps": "Bain triail as an leathanach a athnuachan. Mura gcabhraíonn sé sin, seans go mbeidh tú fós in ann Mastodon a úsáid trí bhrabhsálaí nó aip dhúchais eile.", diff --git a/app/javascript/mastodon/locales/gl.json b/app/javascript/mastodon/locales/gl.json index f8a1c39f6ae..b9142bcd18d 100644 --- a/app/javascript/mastodon/locales/gl.json +++ b/app/javascript/mastodon/locales/gl.json @@ -357,6 +357,7 @@ "empty_column.notification_requests": "Todo ben! Nada por aquí. Cando recibas novas notificacións aparecerán aquí seguindo o criterio dos teus axustes.", "empty_column.notifications": "Aínda non tes notificacións. Aparecerán cando outras persoas interactúen contigo.", "empty_column.public": "Nada por aquí! Escribe algo de xeito público, ou segue de xeito manual usuarias doutros servidores para ir enchéndoo", + "error.no_hashtag_feed_access": "Crea unha conta ou accede para ver e seguir este cancelo.", "error.unexpected_crash.explanation": "Debido a un erro no noso código ou a unha compatilidade co teu navegador, esta páxina non pode ser amosada correctamente.", "error.unexpected_crash.explanation_addons": "Non se puido mostrar correctamente a páxina. Habitualmente este erro está causado por algún engadido do navegador ou ferramentas de tradución automática.", "error.unexpected_crash.next_steps": "Tenta actualizar a páxina. Se isto non axuda podes tamén empregar Mastodon noutro navegador ou aplicación nativa.", diff --git a/app/javascript/mastodon/locales/he.json b/app/javascript/mastodon/locales/he.json index b16e4b95146..cdd041df413 100644 --- a/app/javascript/mastodon/locales/he.json +++ b/app/javascript/mastodon/locales/he.json @@ -357,6 +357,7 @@ "empty_column.notification_requests": "בום! אין פה כלום. כשיווצרו עוד התראות, הן יופיעו כאן על בסיס ההעדפות שלך.", "empty_column.notifications": "אין התראות עדיין. יאללה, הגיע הזמן להתחיל להתערבב.", "empty_column.public": "אין פה כלום! כדי למלא את הטור הזה אפשר לכתוב משהו, או להתחיל לעקוב אחרי אנשים מקהילות אחרות", + "error.no_hashtag_feed_access": "הצטרפו או התחברו כדי לעקוב אחרי תגית זו.", "error.unexpected_crash.explanation": "עקב תקלה בקוד שלנו או בעיית תאימות דפדפן, לא ניתן להציג דף זה כראוי.", "error.unexpected_crash.explanation_addons": "לא ניתן להציג דף זה כראוי. הבעיה נגרמת כנראה עקב תוסף דפדפן או כלי תרגום אוטומטי.", "error.unexpected_crash.next_steps": "נסה/י לרענן את הדף. אם זה לא עוזר, אולי אפשר עדיין להשתמש במסטודון דרך דפדפן אחר או באמצעות אפליקציה ילידית.", diff --git a/app/javascript/mastodon/locales/hu.json b/app/javascript/mastodon/locales/hu.json index 85330bfadc4..08082b53ba5 100644 --- a/app/javascript/mastodon/locales/hu.json +++ b/app/javascript/mastodon/locales/hu.json @@ -357,6 +357,7 @@ "empty_column.notification_requests": "Minden tiszta! Itt nincs semmi. Ha új értesítéseket kapsz, azok itt jelennek meg a beállításoknak megfelelően.", "empty_column.notifications": "Jelenleg még nincsenek értesítéseid. Ha mások kapcsolatba lépnek veled, ezek itt lesznek láthatóak.", "empty_column.public": "Jelenleg itt nincs semmi! Írj valamit nyilvánosan vagy kövess más kiszolgálón levő felhasználókat, hogy megtöltsd.", + "error.no_hashtag_feed_access": "Csatlakozz vagy jelentkezz be, hogy megtekintsd és kövesd ezt a hashtaget.", "error.unexpected_crash.explanation": "Egy kód- vagy böngészőkompatibilitási hiba miatt ez az oldal nem jeleníthető meg helyesen.", "error.unexpected_crash.explanation_addons": "Ezt az oldalt nem lehet helyesen megjeleníteni. Ezt a hibát valószínűleg egy böngésző kiegészítő vagy egy automatikus fordító okozza.", "error.unexpected_crash.next_steps": "Próbáld frissíteni az oldalt. Ha ez nem segít, egy másik böngészőn vagy appon keresztül még mindig használhatod a Mastodont.", diff --git a/app/javascript/mastodon/locales/is.json b/app/javascript/mastodon/locales/is.json index e18cdd05c70..5af1f32ed52 100644 --- a/app/javascript/mastodon/locales/is.json +++ b/app/javascript/mastodon/locales/is.json @@ -357,6 +357,7 @@ "empty_column.notification_requests": "Allt hreint! Það er ekkert hér. Þegar þú færð nýjar tilkynningar, munu þær birtast hér í samræmi við stillingarnar þínar.", "empty_column.notifications": "Þú ert ekki ennþá með neinar tilkynningar. Vertu í samskiptum við aðra til að umræður fari af stað.", "empty_column.public": "Það er ekkert hér! Skrifaðu eitthvað opinberlega, eða fylgstu með notendum á öðrum netþjónum til að fylla upp í þetta", + "error.no_hashtag_feed_access": "Skráðu þig inn eða stofnaðu aðgang til að skoða og fylgjast með þessu myllumerki.", "error.unexpected_crash.explanation": "Vegna villu í kóðanum okkar eða samhæfnivandamála í vafra er ekki hægt að birta þessa síðu svo vel sé.", "error.unexpected_crash.explanation_addons": "Ekki er hægt að birta þessa síðu rétt. Þetta er líklega af völdum forritsviðbótar í vafranum eða sjálfvirkra þýðainaverkfæra.", "error.unexpected_crash.next_steps": "Prófaðu að endurlesa síðuna. Ef það hjálpar ekki til, má samt vera að þú getir notað Mastodon í gegnum annan vafra eða forrit.", diff --git a/app/javascript/mastodon/locales/it.json b/app/javascript/mastodon/locales/it.json index e5c4c22f3cf..9fc0be45315 100644 --- a/app/javascript/mastodon/locales/it.json +++ b/app/javascript/mastodon/locales/it.json @@ -357,6 +357,7 @@ "empty_column.notification_requests": "Tutto chiaro! Non c'è niente qui. Quando ricevi nuove notifiche, verranno visualizzate qui in base alle tue impostazioni.", "empty_column.notifications": "Non hai ancora nessuna notifica. Quando altre persone interagiranno con te, le vedrai qui.", "empty_column.public": "Non c'è nulla qui! Scrivi qualcosa pubblicamente o segui manualmente gli utenti dagli altri server per riempire questo spazio", + "error.no_hashtag_feed_access": "Iscriviti o accedi per visualizzare e seguire questo hashtag.", "error.unexpected_crash.explanation": "A causa di un bug nel nostro codice o di un problema di compatibilità del browser, non è stato possibile visualizzare correttamente questa pagina.", "error.unexpected_crash.explanation_addons": "Impossibile mostrare correttamente questa pagina. Questo errore è probabilmente causato da un addon del browser o da strumenti di traduzione automatica.", "error.unexpected_crash.next_steps": "Prova a ricaricare la pagina. Se non aiuta, potresti comunque utilizzare Mastodon tramite un browser differente o un'app nativa.", diff --git a/app/javascript/mastodon/locales/pt-BR.json b/app/javascript/mastodon/locales/pt-BR.json index 6251b4c7190..d60d1561524 100644 --- a/app/javascript/mastodon/locales/pt-BR.json +++ b/app/javascript/mastodon/locales/pt-BR.json @@ -357,6 +357,7 @@ "empty_column.notification_requests": "Tudo limpo! Não há nada aqui. Quando você receber novas notificações, elas aparecerão aqui de acordo com suas configurações.", "empty_column.notifications": "Interaja com outros usuários para começar a conversar.", "empty_column.public": "Publique algo ou siga manualmente usuários de outros servidores", + "error.no_hashtag_feed_access": "Se cadastre ou faça login para ver e seguir esta hashtag.", "error.unexpected_crash.explanation": "Esta página não pôde ser mostrada corretamente. Este erro provavelmente é devido a um bug em nosso código ou um problema de compatibilidade de navegador.", "error.unexpected_crash.explanation_addons": "Esta página não pôde ser mostrada corretamente. Este erro provavelmente é causado por um complemento do navegador ou ferramentas de tradução automática.", "error.unexpected_crash.next_steps": "Tente atualizar a página. Se isso não ajudar, você ainda poderá usar o Mastodon por meio de um navegador diferente ou de um aplicativo nativo.", diff --git a/app/javascript/mastodon/locales/pt-PT.json b/app/javascript/mastodon/locales/pt-PT.json index e8b8de206fc..101a4bbd78b 100644 --- a/app/javascript/mastodon/locales/pt-PT.json +++ b/app/javascript/mastodon/locales/pt-PT.json @@ -357,6 +357,7 @@ "empty_column.notification_requests": "Tudo limpo! Não há nada aqui. Quando receberes novas notificações, elas aparecerão aqui conforme as tuas configurações.", "empty_column.notifications": "Ainda não tens quaisquer notificações. Quando outras pessoas interagirem contigo, verás isso aqui.", "empty_column.public": "Não há nada aqui! Escreve algo publicamente ou segue outros utilizadores para veres aqui os conteúdos públicos", + "error.no_hashtag_feed_access": "Inscreva-se ou inicie sessão para ver e seguir esta etiqueta.", "error.unexpected_crash.explanation": "Devido a um erro no nosso código ou a um problema de compatibilidade do navegador, esta página não pode ser apresentada corretamente.", "error.unexpected_crash.explanation_addons": "Esta página não pode ser mostrada corretamente. Este erro provavelmente é causado por um complemento do navegador ou ferramentas de tradução automática.", "error.unexpected_crash.next_steps": "Tenta atualizar a página. Se isso não ajudar, podes usar o Mastodon através de um navegador diferente ou uma aplicação nativa.", diff --git a/app/javascript/mastodon/locales/sl.json b/app/javascript/mastodon/locales/sl.json index a93a9569ab7..3b246c5b291 100644 --- a/app/javascript/mastodon/locales/sl.json +++ b/app/javascript/mastodon/locales/sl.json @@ -1,6 +1,7 @@ { "about.blocks": "Moderirani strežniki", "about.contact": "Stik:", + "about.default_locale": "Privzeto", "about.disclaimer": "Mastodon je prosto, odprtokodno programje in blagovna znamka podjetja Mastodon gGmbH.", "about.domain_blocks.no_reason_available": "Razlog ni na voljo", "about.domain_blocks.preamble": "Mastodon vam na splošno omogoča ogled vsebin in interakcijo z uporabniki z vseh drugih strežnikov v fediverzumu. Tu so navedene izjeme, ki jih postavlja ta strežnik.", @@ -8,6 +9,7 @@ "about.domain_blocks.silenced.title": "Omejeno", "about.domain_blocks.suspended.explanation": "Nobeni podatki s tega strežnika ne bodo obdelani, shranjeni ali izmenjani, zaradi česar je nemogoča kakršna koli interakcija ali komunikacija z uporabniki s tega strežnika.", "about.domain_blocks.suspended.title": "Suspendiran", + "about.language_label": "Jezik", "about.not_available": "Ti podatki še niso na voljo na tem strežniku.", "about.powered_by": "Decentraliziran družabni medij, ki ga poganja {mastodon}", "about.rules": "Pravila strežnika", @@ -24,12 +26,16 @@ "account.direct": "Zasebno omeni @{name}", "account.disable_notifications": "Ne obveščaj me več, ko ima @{name} novo objavo", "account.edit_profile": "Uredi profil", + "account.edit_profile_short": "Uredi", "account.enable_notifications": "Obvesti me, ko ima @{name} novo objavo", "account.endorse": "Izpostavi v profilu", + "account.featured.accounts": "Profili", + "account.featured.hashtags": "Ključniki", "account.featured_tags.last_status_at": "Zadnja objava {date}", "account.featured_tags.last_status_never": "Ni objav", "account.follow": "Sledi", "account.follow_back": "Sledi nazaj", + "account.follow_request_cancel_short": "Prekliči", "account.followers": "Sledilci", "account.followers.empty": "Nihče še ne sledi temu uporabniku.", "account.followers_counter": "{count, plural, one {{counter} sledilec} two {{counter} sledilca} few {{counter} sledilci} other {{counter} sledilcev}}", @@ -214,9 +220,15 @@ "confirmations.missing_alt_text.secondary": "Vseeno objavi", "confirmations.missing_alt_text.title": "Dodam nadomestno besedilo?", "confirmations.mute.confirm": "Utišaj", + "confirmations.quiet_post_quote_info.got_it": "Razumem", "confirmations.redraft.confirm": "Izbriši in preoblikuj", "confirmations.redraft.message": "Ali ste prepričani, da želite izbrisati to objavo in jo preoblikovati? Izkazi priljubljenosti in izpostavitve bodo izgubljeni, odgovori na izvirno objavo pa bodo osiroteli.", "confirmations.redraft.title": "Želite izbrisati in preoblikovati objavo?", + "confirmations.remove_from_followers.confirm": "Odstrani sledilca", + "confirmations.remove_from_followers.title": "Ali želite odstraniti sledilca?", + "confirmations.revoke_quote.confirm": "Odstrani objavo", + "confirmations.revoke_quote.message": "Tega dejanja ni možno povrniti.", + "confirmations.revoke_quote.title": "Ali želite odstraniti objavo?", "confirmations.unfollow.confirm": "Ne sledi več", "content_warning.hide": "Skrij objavo", "content_warning.show": "Vseeno pokaži", @@ -682,6 +694,7 @@ "relative_time.minutes": "{number} m", "relative_time.seconds": "{number} s", "relative_time.today": "danes", + "remove_quote_hint.button_label": "Razumem", "reply_indicator.attachments": "{count, plural, one {# priloga} two {# prilogi} few {# priloge} other {# prilog}}", "reply_indicator.cancel": "Prekliči", "reply_indicator.poll": "Anketa", @@ -735,6 +748,7 @@ "report_notification.categories.violation": "Kršitev pravila", "report_notification.categories.violation_sentence": "kršitev pravila", "report_notification.open": "Odpri prijavo", + "search.clear": "Počisti iskanje", "search.no_recent_searches": "Ni nedavnih iskanj", "search.placeholder": "Iskanje", "search.quick_action.account_search": "Profili, ki se ujemajo z {x}", diff --git a/app/javascript/mastodon/locales/tok.json b/app/javascript/mastodon/locales/tok.json index 221c2158876..2f560424624 100644 --- a/app/javascript/mastodon/locales/tok.json +++ b/app/javascript/mastodon/locales/tok.json @@ -28,6 +28,7 @@ "account.disable_notifications": "@{name} li toki la o mu ala e mi", "account.domain_blocking": "mi len e ma ni", "account.edit_profile": "o ante e lipu mi", + "account.edit_profile_short": "o ante", "account.enable_notifications": "@{name} li toki la o toki e toki ona tawa mi", "account.endorse": "lipu jan la o suli e ni", "account.familiar_followers_many": "{name1} en {name2} en {othersCount, plural, other {jan ante #}} li kute e jan ni", @@ -40,6 +41,10 @@ "account.featured_tags.last_status_never": "toki ala li lon", "account.follow": "o kute", "account.follow_back": "jan ni li kute e sina. o kute", + "account.follow_back_short": "jan ni li kute e sina. o kute", + "account.follow_request": "toki e wile kute", + "account.follow_request_cancel": "toki ala e wile kute", + "account.follow_request_cancel_short": "ala", "account.followers": "jan kute", "account.followers.empty": "jan ala li kute e jan ni", "account.followers_counter": "{count, plural, other {jan {counter} li kute e ona}}", @@ -151,6 +156,8 @@ "bundle_modal_error.close": "o pini", "bundle_modal_error.message": "ilo li wile kama e ijo ni, taso pakala li lon.", "bundle_modal_error.retry": "o alasa sin", + "carousel.current": "lipu {current, number} / {max, number}", + "carousel.slide": "lipu {current, number} lon {max, number}", "closed_registrations.other_server_instructions": "kulupu Mastodon la lawa mute li lon. sina ken pali e sijelo lon ma ante la sina awen ken lukin e ijo pi ma ni.", "closed_registrations_modal.description": "tenpo ni la, sina ken ala pali e jan lon ma {domain}. taso sina wile kepeken ilo Mastodon la, sina ken pali e jan lon ma ante lon ala ma {domain}.", "closed_registrations_modal.find_another_server": "o alasa e ma ante", @@ -167,6 +174,8 @@ "column.edit_list": "o ante e kulupu", "column.favourites": "ijo pona", "column.firehose": "toki pi tenpo ni", + "column.firehose_local": "toki pi tenpo ni pi ma ni", + "column.firehose_singular": "toki pi tenpo ni", "column.follow_requests": "wile alasa pi jan ante", "column.home": "lipu open", "column.list_members": "o ante e kulupu jan", @@ -186,6 +195,7 @@ "community.column_settings.local_only": "toki tan ni taso", "community.column_settings.media_only": "sitelen taso", "community.column_settings.remote_only": "toki tan ante taso", + "compose.error.blank_post": "toki ken ala jo e ala.", "compose.language.change": "o ante e nasin toki", "compose.language.search": "o alasa e nasin toki...", "compose.published.body": "toki li pana.", @@ -237,6 +247,9 @@ "confirmations.missing_alt_text.secondary": "o pana a", "confirmations.missing_alt_text.title": "o pana ala pana e toki pi sona lukin?", "confirmations.mute.confirm": "o len", + "confirmations.private_quote_notify.confirm": "o pana e toki ni tawa ale", + "confirmations.private_quote_notify.do_not_show_again": "o toki ala e toki ni", + "confirmations.quiet_post_quote_info.dismiss": "o toki ala e ni tawa mi", "confirmations.quiet_post_quote_info.got_it": "sona", "confirmations.redraft.confirm": "o weka o pali sin e toki", "confirmations.redraft.message": "pali sin e toki ni la sina wile ala wile weka e ona? sina ni la suli pi toki ni en wawa pi toki ni li weka. kin la toki lon toki ni li jo e mama ala.", @@ -246,7 +259,10 @@ "confirmations.remove_from_followers.title": "o kama ala kama kute ala e jan?", "confirmations.revoke_quote.confirm": "o weka e toki tan lipu Mastodon", "confirmations.revoke_quote.title": "sina wile weka ala weka e toki?", + "confirmations.unblock.confirm": "o len ala", + "confirmations.unblock.title": "o len ala e {name}?", "confirmations.unfollow.confirm": "o kute ala", + "confirmations.unfollow.title": "o kute ala e {name}?", "content_warning.hide": "o len", "content_warning.show": "o lukin a", "content_warning.show_more": "o lukin", @@ -287,10 +303,12 @@ "domain_pill.your_handle": "nimi sina:", "domain_pill.your_server": "ni li ma sina lon ilo. toki ale sina li lon ma ni. ma li ike tawa sina la, sina ken tawa ma ante. ni la jan kute sina li tawa sama.", "domain_pill.your_username": "ni li nimi sina. ma sina la, sina taso li jo e ona. jan mute li lon ma ante la, ona li ken jo e nimi sama.", + "dropdown.empty": "o wile e ijo wan", "embed.instructions": "o pana e toki ni la, toki li lon lipu ante. ", "embed.preview": "ni li jo e sitelen ni:", "emoji_button.activity": "musi", "emoji_button.clear": "o weka", + "emoji_button.custom": "pali sin", "emoji_button.flags": "len ma", "emoji_button.food": "moku", "emoji_button.label": "o pana e sitelen pilin", @@ -326,7 +344,10 @@ "explore.trending_links": "sin", "explore.trending_statuses": "toki", "explore.trending_tags": "kulupu pi lipu suli", + "featured_carousel.current": "toki{current, number} / {max, number}", "featured_carousel.header": "{count, plural, other {toki sewi}}", + "featured_carousel.slide": "toki {current, number} lon {max, number}", + "filter_modal.added.review_and_configure_title": "o alasa e lawa", "filter_modal.added.settings_link": "lipu lawa", "filter_modal.select_filter.expired": "tenpo pini", "filter_modal.select_filter.search": "o alasa anu pali", @@ -367,8 +388,10 @@ "hashtag.counter_by_accounts": "{count, plural, other {jan {counter}}}", "hashtag.counter_by_uses": "{count, plural, other {toki {counter}}}", "hashtag.counter_by_uses_today": "{count, plural, other {toki poka {counter}}}", + "hashtag.feature": "lipu jan la o suli e ni", "hashtag.follow": "o kute e kulupu lipu", "hashtag.mute": "o kute ala e kulupu #{hashtag}", + "hashtag.unfeature": "lipu jan la o suli ala e ni", "hashtag.unfollow": "o kute ala e kulupu lipu", "hints.profiles.followers_may_be_missing": "jan kute li ken weka.", "hints.profiles.see_more_followers": "o lukin e jan ni lon ma {domain}: ona li kute e jan ni.", diff --git a/app/javascript/mastodon/locales/vi.json b/app/javascript/mastodon/locales/vi.json index 3ae73d0fd5e..d6437549fe9 100644 --- a/app/javascript/mastodon/locales/vi.json +++ b/app/javascript/mastodon/locales/vi.json @@ -357,6 +357,7 @@ "empty_column.notification_requests": "Sạch sẽ! Không còn gì ở đây. Khi bạn nhận được thông báo mới, chúng sẽ xuất hiện ở đây theo cài đặt của bạn.", "empty_column.notifications": "Bạn chưa có thông báo nào. Hãy thử theo dõi hoặc nhắn riêng cho ai đó.", "empty_column.public": "Trống trơn! Bạn hãy viết gì đó hoặc bắt đầu theo dõi những người khác", + "error.no_hashtag_feed_access": "Tham gia hoặc đăng nhập để xem và theo dõi hashtag này.", "error.unexpected_crash.explanation": "Trang này có thể không hiển thị chính xác do lỗi lập trình Mastodon hoặc vấn đề tương thích trình duyệt.", "error.unexpected_crash.explanation_addons": "Trang này không thể hiển thị do xung khắc với add-on của trình duyệt hoặc công cụ tự động dịch ngôn ngữ.", "error.unexpected_crash.next_steps": "Hãy thử làm mới trang. Nếu vẫn không được, bạn hãy vào Mastodon bằng một ứng dụng di động hoặc trình duyệt khác.", diff --git a/app/javascript/mastodon/locales/zh-TW.json b/app/javascript/mastodon/locales/zh-TW.json index 16089b41065..cbe6a1e56fb 100644 --- a/app/javascript/mastodon/locales/zh-TW.json +++ b/app/javascript/mastodon/locales/zh-TW.json @@ -357,6 +357,7 @@ "empty_column.notification_requests": "清空啦!已經沒有任何推播通知。當您收到新推播通知時,它們將依照您的設定於此顯示。", "empty_column.notifications": "您還沒有收到任何推播通知,當您與別人開始互動時,它將於此顯示。", "empty_column.public": "這裡什麼都沒有!嘗試寫些公開的嘟文,或者跟隨其他伺服器的使用者後,就會有嘟文出現了", + "error.no_hashtag_feed_access": "加入或登入 Mastodon 以檢視與跟隨此主題標籤。", "error.unexpected_crash.explanation": "由於發生系統故障或瀏覽器相容性問題,無法正常顯示此頁面。", "error.unexpected_crash.explanation_addons": "此頁面無法被正常顯示,這可能是由瀏覽器附加元件或網頁自動翻譯工具造成的。", "error.unexpected_crash.next_steps": "請嘗試重新整理頁面。如果狀況沒有改善,您可以使用不同的瀏覽器或應用程式以檢視來使用 Mastodon。", diff --git a/app/lib/attachment_batch.rb b/app/lib/attachment_batch.rb index 374abfac490..cf08fdcf528 100644 --- a/app/lib/attachment_batch.rb +++ b/app/lib/attachment_batch.rb @@ -112,10 +112,17 @@ class AttachmentBatch keys.each_slice(LIMIT) do |keys_slice| logger.debug { "Deleting #{keys_slice.size} objects" } - bucket.delete_objects(delete: { - objects: keys_slice.map { |key| { key: key } }, - quiet: true, - }) + bucket.delete_objects( + { + delete: { + objects: keys_slice.map { |key| { key: key } }, + quiet: true, + }, + }, + { + http_read_timeout: [Paperclip::Attachment.default_options[:s3_options][:http_read_timeout], 120].max, + } + ) rescue => e retries += 1 diff --git a/app/models/collection.rb b/app/models/collection.rb new file mode 100644 index 00000000000..320933ea606 --- /dev/null +++ b/app/models/collection.rb @@ -0,0 +1,53 @@ +# frozen_string_literal: true + +# == Schema Information +# +# Table name: collections +# +# id :bigint(8) not null, primary key +# description :text not null +# discoverable :boolean not null +# local :boolean not null +# name :string not null +# original_number_of_items :integer +# sensitive :boolean not null +# uri :string +# created_at :datetime not null +# updated_at :datetime not null +# account_id :bigint(8) not null +# tag_id :bigint(8) +# +class Collection < ApplicationRecord + MAX_ITEMS = 25 + + belongs_to :account + belongs_to :tag, optional: true + + has_many :collection_items, dependent: :delete_all + + validates :name, presence: true + validates :description, presence: true + validates :uri, presence: true, if: :remote? + validates :original_number_of_items, + presence: true, + numericality: { greater_than_or_equal: 0 }, + if: :remote? + validate :tag_is_usable + validate :items_do_not_exceed_limit + + def remote? + !local? + end + + private + + def tag_is_usable + return if tag.blank? + + errors.add(:tag, :unusable) unless tag.usable? + end + + def items_do_not_exceed_limit + errors.add(:collection_items, :too_many, count: MAX_ITEMS) if collection_items.size > MAX_ITEMS + end +end diff --git a/app/models/collection_item.rb b/app/models/collection_item.rb new file mode 100644 index 00000000000..0ea50e69142 --- /dev/null +++ b/app/models/collection_item.rb @@ -0,0 +1,40 @@ +# frozen_string_literal: true + +# == Schema Information +# +# Table name: collection_items +# +# id :bigint(8) not null, primary key +# activity_uri :string +# approval_last_verified_at :datetime +# approval_uri :string +# object_uri :string +# position :integer default(1), not null +# state :integer default("pending"), not null +# created_at :datetime not null +# updated_at :datetime not null +# account_id :bigint(8) +# collection_id :bigint(8) not null +# +class CollectionItem < ApplicationRecord + belongs_to :collection + belongs_to :account, optional: true + + enum :state, + { pending: 0, accepted: 1, rejected: 2, revoked: 3 }, + validate: true + + delegate :local?, :remote?, to: :collection + + validates :position, numericality: { only_integer: true, greater_than: 0 } + validates :activity_uri, presence: true, if: :local_item_with_remote_account? + validates :approval_uri, absence: true, unless: :local? + validates :account, presence: true, if: :accepted? + validates :object_uri, presence: true, if: -> { account.nil? } + + scope :ordered, -> { order(position: :asc) } + + def local_item_with_remote_account? + local? && account&.remote? + end +end diff --git a/app/models/concerns/account/associations.rb b/app/models/concerns/account/associations.rb index 62c55da5de1..e1684d25607 100644 --- a/app/models/concerns/account/associations.rb +++ b/app/models/concerns/account/associations.rb @@ -13,6 +13,8 @@ module Account::Associations has_many :account_warnings has_many :aliases, class_name: 'AccountAlias' has_many :bookmarks + has_many :collections + has_many :collection_items has_many :conversations, class_name: 'AccountConversation' has_many :custom_filters has_many :favourites diff --git a/app/models/media_attachment.rb b/app/models/media_attachment.rb index 13ca0d7e3ab..2615eed4e39 100644 --- a/app/models/media_attachment.rb +++ b/app/models/media_attachment.rb @@ -4,29 +4,30 @@ # # Table name: media_attachments # -# id :bigint(8) not null, primary key -# status_id :bigint(8) -# file_file_name :string -# file_content_type :string -# file_file_size :integer -# file_updated_at :datetime -# remote_url :string default(""), not null -# created_at :datetime not null -# updated_at :datetime not null -# shortcode :string -# type :integer default("image"), not null -# file_meta :json -# account_id :bigint(8) -# description :text -# scheduled_status_id :bigint(8) -# blurhash :string -# processing :integer -# file_storage_schema_version :integer -# thumbnail_file_name :string -# thumbnail_content_type :string -# thumbnail_file_size :integer -# thumbnail_updated_at :datetime -# thumbnail_remote_url :string +# id :bigint(8) not null, primary key +# blurhash :string +# description :text +# file_content_type :string +# file_file_name :string +# file_file_size :integer +# file_meta :json +# file_storage_schema_version :integer +# file_updated_at :datetime +# processing :integer +# remote_url :string default(""), not null +# shortcode :string +# thumbnail_content_type :string +# thumbnail_file_name :string +# thumbnail_file_size :integer +# thumbnail_remote_url :string +# thumbnail_storage_schema_version :integer +# thumbnail_updated_at :datetime +# type :integer default("image"), not null +# created_at :datetime not null +# updated_at :datetime not null +# account_id :bigint(8) +# scheduled_status_id :bigint(8) +# status_id :bigint(8) # class MediaAttachment < ApplicationRecord diff --git a/app/views/statuses/_og_image.html.haml b/app/views/statuses/_og_image.html.haml index 1ae97adff67..1f7f57f1562 100644 --- a/app/views/statuses/_og_image.html.haml +++ b/app/views/statuses/_og_image.html.haml @@ -1,6 +1,6 @@ -- if activity.is_a?(Status) && (activity.non_sensitive_with_media? || (activity.with_media? && Setting.preview_sensitive_media)) +- if status.non_sensitive_with_media? || (status.with_media? && Setting.preview_sensitive_media) - player_card = false - - activity.ordered_media_attachments.each do |media| + - status.ordered_media_attachments.each do |media| - if media.image? = opengraph 'og:image', full_asset_url(media.file.url(:original)) = opengraph 'og:image:type', media.file_content_type diff --git a/app/views/statuses/show.html.haml b/app/views/statuses/show.html.haml index ca2628bbcda..7478562ea2e 100644 --- a/app/views/statuses/show.html.haml +++ b/app/views/statuses/show.html.haml @@ -20,6 +20,6 @@ = opengraph 'profile:username', acct(@account)[1..] = render 'og_description', activity: @status - = render 'og_image', activity: @status, account: @account + = render 'og_image', status: @status, account: @account = render 'shared/web_app' diff --git a/config/locales/activerecord.en.yml b/config/locales/activerecord.en.yml index 6940d589cab..fb5ccce89e2 100644 --- a/config/locales/activerecord.en.yml +++ b/config/locales/activerecord.en.yml @@ -32,6 +32,12 @@ en: attributes: url: invalid: is not a valid URL + collection: + attributes: + collection_items: + too_many: are too many, no more than %{count} are allowed + tag: + unusable: may not be used doorkeeper/application: attributes: website: diff --git a/config/locales/da.yml b/config/locales/da.yml index e8053aaf63f..b26de6ab2c7 100644 --- a/config/locales/da.yml +++ b/config/locales/da.yml @@ -1901,7 +1901,7 @@ da: user_domain_block: "%{target_name} blev blokeret" lost_followers: Tabte følgere lost_follows: Mistet følger - preamble: Der kan mistes fulgte objekter og følgere, når et domæne blokeres eller moderatorerne beslutter at suspendere en ekstern server. Når det sker, kan der downloades lister over afbrudte relationer til inspektion og mulig import på anden server. + preamble: Du kan miste fulgte og følgere, når du blokerer et domæne, eller når dine moderatorer beslutter at suspendere en fjernserver. Når det sker, kan du downloade lister over afbrudte forhold til inspektion og eventuelt import til en anden server. purged: Oplysninger om denne server er blevet renset af serveradministratoreren. type: Begivenhed statuses: diff --git a/config/locales/de.yml b/config/locales/de.yml index b085fc4f019..df3e5b8887f 100644 --- a/config/locales/de.yml +++ b/config/locales/de.yml @@ -364,7 +364,7 @@ de: overwrite: Überschreiben shortcode: Shortcode shortcode_hint: Mindestens 2 Zeichen, nur Buchstaben, Ziffern und Unterstriche - title: Eigene Emojis + title: Emojis uncategorized: Unkategorisiert unlist: Nicht anzeigen unlisted: Nicht sichtbar @@ -2150,7 +2150,7 @@ de: follow_limit_reached: Du kannst nicht mehr als %{limit} Profilen folgen go_to_sso_account_settings: Kontoeinstellungen des Identitätsanbieters aufrufen invalid_otp_token: Ungültiger Code der Zwei-Faktor-Authentisierung - otp_lost_help_html: Wenn du beides nicht mehr weißt, melde dich bitte bei uns unter der E-Mail-Adresse %{email} + otp_lost_help_html: Wenn du sowohl die E-Mail-Adresse als auch das Passwort nicht mehr weißt, melde dich bitte bei uns unter %{email} rate_limited: Zu viele Authentisierungsversuche. Bitte versuche es später noch einmal. seamless_external_login: Du bist über einen externen Dienst angemeldet, daher sind Passwort- und E-Mail-Einstellungen nicht verfügbar. signed_in_as: 'Angemeldet als:' diff --git a/config/locales/et.yml b/config/locales/et.yml index 99643e60859..0bb6f5acc4d 100644 --- a/config/locales/et.yml +++ b/config/locales/et.yml @@ -384,8 +384,8 @@ et: one: "%{count} ootel raport" other: "%{count} ootel raportit" pending_tags_html: - one: "%{count} ootel silt" - other: "%{count} ootel silti" + one: "%{count} ootel teemaviide" + other: "%{count} ootel teemaviidet" pending_users_html: one: "%{count} ootel kasutaja" other: "%{count} ootel kasutajat" @@ -783,7 +783,7 @@ et: manage_settings: Halda sätteid manage_settings_description: Lubab kasutajatel muuta lehekülje sätteid manage_taxonomies: Halda taksonoomiaid - manage_taxonomies_description: Luba kasutajatel populaarset sisu üle vaadata ning uuendada siltide sätteid + manage_taxonomies_description: Luba kasutajatel populaarset sisu üle vaadata ning uuendada teemaviidete seadistusi manage_user_access: Halda kasutajate ligipääsu manage_user_access_description: Võimaldab kasutajatel keelata teiste kasutajate kaheastmelise autentimise, muuta oma e-posti aadressi ja lähtestada oma parooli manage_users: Kasutajate haldamine @@ -998,8 +998,8 @@ et: reset: Lähtesta review: Vaata olek üle search: Otsi - title: Märksõnad - updated_msg: Sildi sätted edukalt uuendatud + title: Teemaviited + updated_msg: Teemaviite seadistused on uuendatud terms_of_service: back: Tagasi teenuse tingimustesse changelog: Mis on muutunud @@ -1088,14 +1088,14 @@ et: tag_servers_dimension: Populaarseimad serverid tag_servers_measure: erinevat serverit tag_uses_measure: kasutajaid kokku - description_html: Need sildid ilmuvad praegu paljudes postitutes mida su server näeb. See võib aidata su kasutajatel leida seda millest kõige rohkem parajasti räägitakse. Ühtegi silti ei näidata avalikult, enne nende heaks kiitmist. + description_html: Need teemaviited ilmuvad praegu paljudes postitutes, mida su server näeb. See võib aidata su kasutajatel leida seda millest kõige rohkem parajasti räägitakse. Ühtegi teemaviidet ei näidata enne nende heaks kiitmist avalikult. listable: Võib olla soovitatud no_tag_selected: Silte ei muudetud, kuna ühtegi polnud valitud not_listable: Ei soovitata not_trendable: Ei ilmu trendides not_usable: Ei saa kasutada peaked_on_and_decaying: Populaarseim %{date}, nüüd langemas - title: Trendikad sildid + title: Trendikad teemaviited trendable: Võib ilmuda trendides trending_rank: 'Trendides #%{rank}' usable: Kasutatav @@ -1186,7 +1186,7 @@ et: new_trending_statuses: title: Trendikad postitused new_trending_tags: - title: Trendikad sildid + title: Trendikad teemaviited subject: Uued %{instance} trendid ülevaatuseks aliases: add_new: Pane kolimiseks valmis @@ -1428,8 +1428,8 @@ et: featured_tags: add_new: Lisa uus errors: - limit: Oled jõudnud siltide lubatud maksimumarvuni - hint_html: "Mis on esiletõstetud sildid? Neid silte näidatakse su avalikul profiilil esiletõstetult ning need aitavad teistel leida postitusi, millel on selline silt. See on hea viis, kuidas hoida järge loovtöödel või pikaajalistel projektidel." + limit: Oled jõudnud teemaviidete lubatud maksimumarvuni + hint_html: "Mis on esiletõstetud teemaviited? Neid teemaviiteid näidatakse su avalikul profiilil esiletõstetult ning need aitavad teistel leida postitusi, millel on selline teemaviide. See on hea viis, kuidas hoida järge loovtöödel või pikaajalistel projektidel." filters: contexts: account: Profiilid @@ -1815,7 +1815,7 @@ et: content_warning: 'Sisuhoiatus:' descriptions: account: "@%{acct} avalikud postitused" - tag: 'Avalikud postitused sildiga #%{hashtag}' + tag: 'Avalikud postitused teemaviitega #%{hashtag}' scheduled_statuses: over_daily_limit: Lubatud ajastatud postituste arv %{limit} päevas on tänaseks ületatud over_total_limit: Oled jõudnud ajastatud postituste lubatud maksimumarvuni %{limit} @@ -1880,7 +1880,7 @@ et: development: Arendus edit_profile: Muuda profiili export: Eksport - featured_tags: Esile toodud sildid + featured_tags: Esile toodud teemaviited import: Impordi import_and_export: Import / eksport migrate: Konto kolimine @@ -1923,8 +1923,8 @@ et: show: Näita rohkem default_language: Kasutajaliidese keelega sama disallowed_hashtags: - one: 'sisaldab ebasobivat silti: %{tags}' - other: 'sisaldab ebasobivaid silte: %{tags}' + one: 'sisaldab ebasobivat teemaviidet: %{tags}' + other: 'sisaldab ebasobivaid teemaviiteid: %{tags}' edited_at_html: Muudetud %{date} errors: in_reply_not_found: Postitus, millele üritad vastata, ei näi enam eksisteerivat. @@ -2139,7 +2139,7 @@ et: other: "%{people} inimest viimase 2 päeva jooksul" hashtags_subtitle: Avasta, mis viimase 2 päeva jooksul on toimunud hashtags_title: Populaarsed märksõnad - hashtags_view_more: Vaata teisi trendikaid märksõnu + hashtags_view_more: Vaata teisi trendikaid teemaviiteid post_action: Postita post_step: Tervita maailma teksti, fotode, videote või küsitlustega. post_title: Tee oma esimene postitus diff --git a/config/locales/simple_form.ca.yml b/config/locales/simple_form.ca.yml index d1daf27e55c..d7ced9c6f58 100644 --- a/config/locales/simple_form.ca.yml +++ b/config/locales/simple_form.ca.yml @@ -353,7 +353,9 @@ ca: jurisdiction: Jurisdicció min_age: Edat mínima user: + date_of_birth_1i: Any date_of_birth_2i: Mes + date_of_birth_3i: Dia role: Rol time_zone: Zona horària user_role: diff --git a/config/locales/simple_form.da.yml b/config/locales/simple_form.da.yml index 952b228b879..b442e5add0c 100644 --- a/config/locales/simple_form.da.yml +++ b/config/locales/simple_form.da.yml @@ -5,7 +5,7 @@ da: account: attribution_domains: Ét pr. linje. Beskytter mod falske tilskrivninger. discoverable: Dine offentlige indlæg og profil kan blive fremhævet eller anbefalet i forskellige områder af Mastodon, og profilen kan blive foreslået til andre brugere. - display_name: Dit fulde navn eller dit sjove navn. + display_name: Dit fulde navn eller et kaldenavn. fields: Din hjemmeside, dine pronominer, din alder, eller hvad du har lyst til. indexable: Dine offentlige indlæg vil kunne vises i Mastodon-søgeresultater. Folk, som har interageret med dem, vil kunne finde dem uanset. note: 'Du kan @omtale andre personer eller #hashtags.' diff --git a/config/locales/simple_form.et.yml b/config/locales/simple_form.et.yml index 1a56c1e1a6e..92efc6dbadf 100644 --- a/config/locales/simple_form.et.yml +++ b/config/locales/simple_form.et.yml @@ -8,7 +8,7 @@ et: display_name: Su täisnimi või naljanimi. fields: Su koduleht, sugu, vanus. Mistahes, mida soovid. indexable: Sinu avalikud postitused võivad ilmuda Mastodoni otsingutulemustes. Inimesed, kes on sinu postitustele reageerinud, saavad neid otsida nii või naa. - note: 'Saad @mainida teisi inimesi või #silte.' + note: 'Saad @mainida teisi inimesi või #teemaviiteid.' show_collections: Inimesed saavad sirvida su jälgijaid ja jälgitavaid. Inimesed, keda sa jälgid, näevad seda sõltumata häälestuse valikust. unlocked: Teised kasutajad saavad sind jälgima hakata nõusolekut küsimata. Eemalda märge, kui soovid jälgimistaotlusi üle vaadata ja valida, kas nõustuda või keelduda uute jälgijatega. account_alias: @@ -16,7 +16,7 @@ et: account_migration: acct: Sisesta kasutajanimi@domeen, kuhu soovid konto siit kolida account_warning_preset: - text: Saab kasutada postituse süntaksi, näiteks URLe, silte ja mainimisi + text: Saad kasutada postituse süntaksi, näiteks võrguaadresse, teemaviiteid ja mainimisi title: Valikuline. Ei ole nähtav saajale admin_account_action: include_statuses: Kasutaja näeb, millised postitused on põhjustanud moderaatori otsuse või hoiatuse @@ -77,7 +77,7 @@ et: domain: See võib olla e-postiaadressis näha olev domeen või MX-kirje, mida aadress kasutab. Kontroll toimub liitumise käigus. with_dns_records: Püütakse lahendada selle domeeni DNS-kirjed ja ühtlasi blokeerida ka selle tulemused featured_tag: - name: 'Siin on mõned nendest siltidest, mida oled viimati kasutanud:' + name: 'Siin on mõned nendest teemaviiteid, mida oled viimati kasutanud:' filters: action: Vali tegevus, kui postitus vastab filtrile actions: @@ -110,7 +110,7 @@ et: theme: Teema, mida näevad sisenemata ning uued kasutajad. thumbnail: Umbes 2:1 mõõdus pilt serveri informatsiooni kõrval. trendable_by_default: Populaarse sisu ülevaatuse vahele jätmine. Pärast seda on siiski võimalik üksikuid üksusi trendidest eemaldada. - trends: Trendid näitavad, millised postitused, sildid ja uudislood koguvad sinu serveris tähelepanu. + trends: Trendid näitavad, millised postitused, teemaviited ja uudislood koguvad sinu serveris tähelepanu. form_challenge: current_password: Turvalisse alasse sisenemine imports: @@ -272,7 +272,7 @@ et: email_domain_block: with_dns_records: Kaasa domeeni MX-kirjed ning IP-aadressid featured_tag: - name: Silt + name: Teemaviide filters: actions: blur: Peida hoiatusega meedia @@ -353,10 +353,10 @@ et: indexable: Kaasa profiilileht otsimootoritesse show_application: Näita, millisest äpist postituse saatsid tag: - listable: Luba sellel sildil ilmuda profiilide kataloogis - name: Silt - trendable: Luba sellel sildil trendida - usable: Luba seda märksõna postitustes kasutada lokaalselt + listable: Luba sellel teemaviitel ilmuda profiilide kataloogis + name: Teemaviide + trendable: Luba sellel teemaviitel olla nähtav viimaste trendide all + usable: Luba seda teemaviidet postitustes kasutada lokaalselt terms_of_service: changelog: Mis on muutunud? effective_date: Jõustumise kuupäev diff --git a/config/locales/simple_form.pt-BR.yml b/config/locales/simple_form.pt-BR.yml index 0677399d38b..8de2c8b04aa 100644 --- a/config/locales/simple_form.pt-BR.yml +++ b/config/locales/simple_form.pt-BR.yml @@ -253,7 +253,7 @@ pt-BR: setting_expand_spoilers: Sempre expandir toots com Aviso de Conteúdo setting_hide_network: Ocultar suas relações setting_missing_alt_text_modal: Avise-me antes de publicar mídia sem texto alternado - setting_quick_boosting: Ativar aceleração rápida + setting_quick_boosting: Ativar impulsionamento rápido setting_reduce_motion: Reduzir animações setting_system_font_ui: Usar fonte padrão do sistema setting_system_scrollbars_ui: Usar barra de rolagem padrão do sistema diff --git a/config/locales/simple_form.sl.yml b/config/locales/simple_form.sl.yml index ee86870244b..7dc825d526e 100644 --- a/config/locales/simple_form.sl.yml +++ b/config/locales/simple_form.sl.yml @@ -220,7 +220,9 @@ sl: setting_always_send_emails: Vedno pošlji e-obvestila setting_auto_play_gif: Samodejno predvajanje animiranih GIF-ov setting_default_language: Jezik objavljanja + setting_default_quote_policy: Kdo lahko citira setting_default_sensitive: Vedno označi medije kot občutljive + setting_delete_modal: Pred brisanjem objave me opozori setting_disable_hover_cards: Onemogoči predogled profila pod kazalcem setting_disable_swiping: Onemogoči poteze drsanja setting_display_media: Prikaz medijev @@ -305,6 +307,7 @@ sl: follow_request: Pošlji e-pošto, ko vam nekdo želi slediti mention: Pošlji e-pošto, ko vas nekdo omeni pending_account: Pošlji e-pošto, ko je potreben pregled novega računa + quote: Nekdo vas je citiral reblog: Pošlji e-sporočilo, ko nekdo izpostavi vašo objavo report: Novo poročilo je oddano software_updates: @@ -340,7 +343,9 @@ sl: jurisdiction: Pravna pristojnost min_age: Najmanjša starost user: + date_of_birth_1i: Leto date_of_birth_2i: Mesec + date_of_birth_3i: Dan role: Vloga time_zone: Časovni pas user_role: @@ -349,6 +354,9 @@ sl: name: Ime permissions_as_keys: Pravice position: Prioriteta + username_block: + allow_with_approval: Dovoli registracije z odobritvijo + comparison: Metoda primerjave webhook: events: Omogočeni dogodki template: Predloga obremenitev diff --git a/db/migrate/20251117023614_add_thumbnail_storage_schema_version.rb b/db/migrate/20251117023614_add_thumbnail_storage_schema_version.rb new file mode 100644 index 00000000000..0a8119642d4 --- /dev/null +++ b/db/migrate/20251117023614_add_thumbnail_storage_schema_version.rb @@ -0,0 +1,7 @@ +# frozen_string_literal: true + +class AddThumbnailStorageSchemaVersion < ActiveRecord::Migration[8.0] + def change + add_column :media_attachments, :thumbnail_storage_schema_version, :integer + end +end diff --git a/db/migrate/20251118115657_create_collections.rb b/db/migrate/20251118115657_create_collections.rb new file mode 100644 index 00000000000..299cc7aade6 --- /dev/null +++ b/db/migrate/20251118115657_create_collections.rb @@ -0,0 +1,19 @@ +# frozen_string_literal: true + +class CreateCollections < ActiveRecord::Migration[8.0] + def change + create_table :collections do |t| + t.references :account, null: false, foreign_key: true + t.string :name, null: false + t.text :description, null: false + t.string :uri + t.boolean :local, null: false # rubocop:disable Rails/ThreeStateBooleanColumn + t.boolean :sensitive, null: false # rubocop:disable Rails/ThreeStateBooleanColumn + t.boolean :discoverable, null: false # rubocop:disable Rails/ThreeStateBooleanColumn + t.references :tag, foreign_key: true + t.integer :original_number_of_items + + t.timestamps + end + end +end diff --git a/db/migrate/20251119093332_create_collection_items.rb b/db/migrate/20251119093332_create_collection_items.rb new file mode 100644 index 00000000000..9fc5d99df53 --- /dev/null +++ b/db/migrate/20251119093332_create_collection_items.rb @@ -0,0 +1,18 @@ +# frozen_string_literal: true + +class CreateCollectionItems < ActiveRecord::Migration[8.0] + def change + create_table :collection_items do |t| + t.references :collection, null: false, foreign_key: { on_delete: :cascade } + t.references :account, foreign_key: true + t.integer :position, null: false, default: 1 + t.string :object_uri, index: { unique: true, where: 'activity_uri IS NOT NULL' } + t.string :approval_uri, index: { unique: true, where: 'approval_uri IS NOT NULL' } + t.string :activity_uri + t.datetime :approval_last_verified_at + t.integer :state, null: false, default: 0 + + t.timestamps + end + end +end diff --git a/db/schema.rb b/db/schema.rb index 7bdd6c0ce40..e4e7db3868c 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -10,7 +10,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema[8.0].define(version: 2025_10_23_210145) do +ActiveRecord::Schema[8.0].define(version: 2025_11_19_093332) do # These are extensions that must be enabled in order to support this database enable_extension "pg_catalog.plpgsql" @@ -351,6 +351,39 @@ ActiveRecord::Schema[8.0].define(version: 2025_10_23_210145) do t.index ["reference_account_id"], name: "index_canonical_email_blocks_on_reference_account_id" end + create_table "collection_items", force: :cascade do |t| + t.bigint "collection_id", null: false + t.bigint "account_id" + t.integer "position", default: 1, null: false + t.string "object_uri" + t.string "approval_uri" + t.string "activity_uri" + t.datetime "approval_last_verified_at" + t.integer "state", default: 0, null: false + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + t.index ["account_id"], name: "index_collection_items_on_account_id" + t.index ["approval_uri"], name: "index_collection_items_on_approval_uri", unique: true, where: "(approval_uri IS NOT NULL)" + t.index ["collection_id"], name: "index_collection_items_on_collection_id" + t.index ["object_uri"], name: "index_collection_items_on_object_uri", unique: true, where: "(activity_uri IS NOT NULL)" + end + + create_table "collections", force: :cascade do |t| + t.bigint "account_id", null: false + t.string "name", null: false + t.text "description", null: false + t.string "uri" + t.boolean "local", null: false + t.boolean "sensitive", null: false + t.boolean "discoverable", null: false + t.bigint "tag_id" + t.integer "original_number_of_items" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + t.index ["account_id"], name: "index_collections_on_account_id" + t.index ["tag_id"], name: "index_collections_on_tag_id" + end + create_table "conversation_mutes", force: :cascade do |t| t.bigint "conversation_id", null: false t.bigint "account_id", null: false @@ -694,6 +727,7 @@ ActiveRecord::Schema[8.0].define(version: 2025_10_23_210145) do t.integer "thumbnail_file_size" t.datetime "thumbnail_updated_at", precision: nil t.string "thumbnail_remote_url" + t.integer "thumbnail_storage_schema_version" t.index ["account_id", "status_id"], name: "index_media_attachments_on_account_id_and_status_id", order: { status_id: :desc } t.index ["scheduled_status_id"], name: "index_media_attachments_on_scheduled_status_id", where: "(scheduled_status_id IS NOT NULL)" t.index ["shortcode"], name: "index_media_attachments_on_shortcode", unique: true, opclass: :text_pattern_ops, where: "(shortcode IS NOT NULL)" @@ -1386,6 +1420,10 @@ ActiveRecord::Schema[8.0].define(version: 2025_10_23_210145) do add_foreign_key "bulk_import_rows", "bulk_imports", on_delete: :cascade add_foreign_key "bulk_imports", "accounts", on_delete: :cascade add_foreign_key "canonical_email_blocks", "accounts", column: "reference_account_id", on_delete: :cascade + add_foreign_key "collection_items", "accounts" + add_foreign_key "collection_items", "collections", on_delete: :cascade + add_foreign_key "collections", "accounts" + add_foreign_key "collections", "tags" add_foreign_key "conversation_mutes", "accounts", name: "fk_225b4212bb", on_delete: :cascade add_foreign_key "conversation_mutes", "conversations", on_delete: :cascade add_foreign_key "custom_filter_keywords", "custom_filters", on_delete: :cascade diff --git a/spec/fabricators/account_fabricator.rb b/spec/fabricators/account_fabricator.rb index 6ec89a1cb65..bce8803be75 100644 --- a/spec/fabricators/account_fabricator.rb +++ b/spec/fabricators/account_fabricator.rb @@ -17,3 +17,7 @@ Fabricator(:account) do discoverable true indexable true end + +Fabricator(:remote_account, from: :account) do + domain 'example.com' +end diff --git a/spec/fabricators/collection_fabricator.rb b/spec/fabricators/collection_fabricator.rb new file mode 100644 index 00000000000..a6a8411ba00 --- /dev/null +++ b/spec/fabricators/collection_fabricator.rb @@ -0,0 +1,10 @@ +# frozen_string_literal: true + +Fabricator(:collection) do + account { Fabricate.build(:account) } + name { sequence(:name) { |i| "Collection ##{i}" } } + description 'People to follow' + local true + sensitive false + discoverable true +end diff --git a/spec/fabricators/collection_item_fabricator.rb b/spec/fabricators/collection_item_fabricator.rb new file mode 100644 index 00000000000..011f9ba5b5e --- /dev/null +++ b/spec/fabricators/collection_item_fabricator.rb @@ -0,0 +1,15 @@ +# frozen_string_literal: true + +Fabricator(:collection_item) do + collection { Fabricate.build(:collection) } + account { Fabricate.build(:account) } + position 1 + state :accepted +end + +Fabricator(:unverified_remote_collection_item, from: :collection_item) do + account nil + state :pending + object_uri { Fabricate.build(:remote_account).uri } + approval_uri { sequence(:uri) { |i| "https://example.com/authorizations/#{i}" } } +end diff --git a/spec/models/collection_item_spec.rb b/spec/models/collection_item_spec.rb new file mode 100644 index 00000000000..39464b7a340 --- /dev/null +++ b/spec/models/collection_item_spec.rb @@ -0,0 +1,41 @@ +# frozen_string_literal: true + +require 'rails_helper' + +RSpec.describe CollectionItem do + describe 'Validations' do + subject { Fabricate.build(:collection_item) } + + it { is_expected.to define_enum_for(:state) } + + it { is_expected.to validate_numericality_of(:position).only_integer.is_greater_than(0) } + + context 'when account inclusion is accepted' do + subject { Fabricate.build(:collection_item, state: :accepted) } + + it { is_expected.to validate_presence_of(:account) } + end + + context 'when item is local and account is remote' do + subject { Fabricate.build(:collection_item, account: remote_account) } + + let(:remote_account) { Fabricate.build(:remote_account) } + + it { is_expected.to validate_presence_of(:activity_uri) } + end + + context 'when item is not local' do + subject { Fabricate.build(:collection_item, collection: remote_collection) } + + let(:remote_collection) { Fabricate.build(:collection, local: false) } + + it { is_expected.to validate_absence_of(:approval_uri) } + end + + context 'when account is not present' do + subject { Fabricate.build(:unverified_remote_collection_item) } + + it { is_expected.to validate_presence_of(:object_uri) } + end + end +end diff --git a/spec/models/collection_spec.rb b/spec/models/collection_spec.rb new file mode 100644 index 00000000000..c6a500210f6 --- /dev/null +++ b/spec/models/collection_spec.rb @@ -0,0 +1,45 @@ +# frozen_string_literal: true + +require 'rails_helper' + +RSpec.describe Collection do + describe 'Validations' do + subject { Fabricate.build :collection } + + it { is_expected.to validate_presence_of(:name) } + + it { is_expected.to validate_presence_of(:description) } + + context 'when collection is remote' do + subject { Fabricate.build :collection, local: false } + + it { is_expected.to validate_presence_of(:uri) } + + it { is_expected.to validate_presence_of(:original_number_of_items) } + end + + context 'when using a hashtag as category' do + subject { Fabricate.build(:collection, tag:) } + + context 'when hashtag is usable' do + let(:tag) { Fabricate.build(:tag) } + + it { is_expected.to be_valid } + end + + context 'when hashtag is not usable' do + let(:tag) { Fabricate.build(:tag, usable: false) } + + it { is_expected.to_not be_valid } + end + end + + context 'when there are more items than allowed' do + subject { Fabricate.build(:collection, collection_items:) } + + let(:collection_items) { Fabricate.build_times(described_class::MAX_ITEMS + 1, :collection_item, collection: nil) } + + it { is_expected.to_not be_valid } + end + end +end diff --git a/spec/requests/media_spec.rb b/spec/requests/media_spec.rb index a448a87492e..523c4689d6a 100644 --- a/spec/requests/media_spec.rb +++ b/spec/requests/media_spec.rb @@ -87,4 +87,17 @@ RSpec.describe 'Media' do end end end + + describe 'GET /media/:medium_id/player' do + context 'when media type is not large format type' do + let(:media) { Fabricate :media_attachment } + + it 'responds with not found' do + get medium_player_path(media) + + expect(response) + .to have_http_status(404) + end + end + end end diff --git a/spec/system/media_spec.rb b/spec/system/media_spec.rb index d014c7e88ef..ec069cdcaa9 100644 --- a/spec/system/media_spec.rb +++ b/spec/system/media_spec.rb @@ -4,19 +4,47 @@ require 'rails_helper' RSpec.describe 'Media' do describe 'Player page' do + let(:status) { Fabricate :status } + + before { status.media_attachments << media } + context 'when signed in' do before { sign_in Fabricate(:user) } - it 'visits the media player page and renders the media' do - status = Fabricate :status - media = Fabricate :media_attachment, type: :video - status.media_attachments << media + context 'when media type is video' do + let(:media) { Fabricate :media_attachment, type: :video } - visit medium_player_path(media) + it 'visits the player page and renders media' do + visit medium_player_path(media) - expect(page) - .to have_css('body', class: 'player') - .and have_css('div[data-component="Video"]') + expect(page) + .to have_css('body', class: 'player') + .and have_css('div[data-component="Video"] video[controls="controls"] source') + end + end + + context 'when media type is gifv' do + let(:media) { Fabricate :media_attachment, type: :gifv } + + it 'visits the player page and renders media' do + visit medium_player_path(media) + + expect(page) + .to have_css('body', class: 'player') + .and have_css('div[data-component="MediaGallery"] video[loop="loop"] source') + end + end + + context 'when media type is audio' do + let(:media) { Fabricate :media_attachment, type: :audio } + + it 'visits the player page and renders media' do + visit medium_player_path(media) + + expect(page) + .to have_css('body', class: 'player') + .and have_css('div[data-component="Audio"] audio source') + end end end end diff --git a/yarn.lock b/yarn.lock index a56fc1f72e7..a7a34cd7cfa 100644 --- a/yarn.lock +++ b/yarn.lock @@ -6062,9 +6062,9 @@ __metadata: linkType: hard "core-js@npm:^3.30.2, core-js@npm:^3.45.0": - version: 3.46.0 - resolution: "core-js@npm:3.46.0" - checksum: 10c0/12d559d39a58227881bc6c86c36d24dcfbe2d56e52dac42e35e8643278172596ab67f57ede98baf40b153ca1b830f37420ea32c3f7417c0c5a1fed46438ae187 + version: 3.47.0 + resolution: "core-js@npm:3.47.0" + checksum: 10c0/9b1a7088b7c660c7b8f1d4c90bb1816a8d5352ebdcb7bc742e3a0e4eb803316b5aa17bacb8769522342196351a5430178f46914644f2bfdb94ce0ced3c7fd523 languageName: node linkType: hard @@ -13988,8 +13988,8 @@ __metadata: linkType: hard "vite@npm:^6.0.0 || ^7.0.0, vite@npm:^7.1.1": - version: 7.2.2 - resolution: "vite@npm:7.2.2" + version: 7.2.4 + resolution: "vite@npm:7.2.4" dependencies: esbuild: "npm:^0.25.0" fdir: "npm:^6.5.0" @@ -14038,7 +14038,7 @@ __metadata: optional: true bin: vite: bin/vite.js - checksum: 10c0/9c76ee441f8dbec645ddaecc28d1f9cf35670ffa91cff69af7b1d5081545331603f0b1289d437b2fa8dc43cdc77b4d96b5bd9c9aed66310f490cb1a06f9c814c + checksum: 10c0/26aa0cad01d6e00f17c837b2a0587ab52f6bd0d0e64606b4220cfc58fa5fa76a4095ef3ea27c886bea542a346363912c4fad9f9462ef1e6757262fedfd5196b2 languageName: node linkType: hard