From db146046c4eaea8e980f3e7ab5f2254f93f4feae Mon Sep 17 00:00:00 2001 From: Claire Date: Thu, 23 Jan 2025 13:54:23 +0100 Subject: [PATCH 01/42] Convert `LanguageDropdown` to a functional component (#33701) --- .../compose/components/compose_form.jsx | 2 +- .../compose/components/language_dropdown.jsx | 185 +++++++++--------- .../language_detection.js} | 60 +----- 3 files changed, 104 insertions(+), 143 deletions(-) rename app/javascript/mastodon/features/compose/{containers/language_dropdown_container.js => util/language_detection.js} (51%) diff --git a/app/javascript/mastodon/features/compose/components/compose_form.jsx b/app/javascript/mastodon/features/compose/components/compose_form.jsx index ca67c3f63e264c..468125afb08d2e 100644 --- a/app/javascript/mastodon/features/compose/components/compose_form.jsx +++ b/app/javascript/mastodon/features/compose/components/compose_form.jsx @@ -14,7 +14,6 @@ import AutosuggestInput from '../../../components/autosuggest_input'; import AutosuggestTextarea from '../../../components/autosuggest_textarea'; import { Button } from '../../../components/button'; import EmojiPickerDropdown from '../containers/emoji_picker_dropdown_container'; -import LanguageDropdown from '../containers/language_dropdown_container'; import PollButtonContainer from '../containers/poll_button_container'; import PrivacyDropdownContainer from '../containers/privacy_dropdown_container'; import SpoilerButtonContainer from '../containers/spoiler_button_container'; @@ -24,6 +23,7 @@ import { countableText } from '../util/counter'; import { CharacterCounter } from './character_counter'; import { EditIndicator } from './edit_indicator'; +import { LanguageDropdown } from './language_dropdown'; import { NavigationBar } from './navigation_bar'; import { PollForm } from "./poll_form"; import { ReplyIndicator } from './reply_indicator'; diff --git a/app/javascript/mastodon/features/compose/components/language_dropdown.jsx b/app/javascript/mastodon/features/compose/components/language_dropdown.jsx index 20fba29ecba884..c80aa27e46a6ef 100644 --- a/app/javascript/mastodon/features/compose/components/language_dropdown.jsx +++ b/app/javascript/mastodon/features/compose/components/language_dropdown.jsx @@ -1,10 +1,13 @@ import PropTypes from 'prop-types'; -import { PureComponent } from 'react'; +import { useCallback, useRef, useState, useEffect, PureComponent } from 'react'; -import { injectIntl, defineMessages } from 'react-intl'; +import { useIntl, defineMessages } from 'react-intl'; import classNames from 'classnames'; +import { createSelector } from '@reduxjs/toolkit'; +import { Map as ImmutableMap } from 'immutable'; + import { supportsPassiveEvents } from 'detect-passive-events'; import fuzzysort from 'fuzzysort'; import Overlay from 'react-overlays/Overlay'; @@ -12,8 +15,12 @@ import Overlay from 'react-overlays/Overlay'; import CancelIcon from '@/material-icons/400-24px/cancel-fill.svg?react'; import SearchIcon from '@/material-icons/400-24px/search.svg?react'; import TranslateIcon from '@/material-icons/400-24px/translate.svg?react'; +import { changeComposeLanguage } from 'mastodon/actions/compose'; import { Icon } from 'mastodon/components/icon'; import { languages as preloadedLanguages } from 'mastodon/initial_state'; +import { useAppSelector, useAppDispatch } from 'mastodon/store'; + +import { debouncedGuess } from '../util/language_detection'; const messages = defineMessages({ changeLanguage: { id: 'compose.language.change', defaultMessage: 'Change language' }, @@ -237,94 +244,90 @@ class LanguageDropdownMenu extends PureComponent { } -class LanguageDropdown extends PureComponent { - - static propTypes = { - value: PropTypes.string, - frequentlyUsedLanguages: PropTypes.arrayOf(PropTypes.string), - guess: PropTypes.string, - intl: PropTypes.object.isRequired, - onChange: PropTypes.func, - }; - - state = { - open: false, - placement: 'bottom', - }; - - handleToggle = () => { - if (this.state.open && this.activeElement) { - this.activeElement.focus({ preventScroll: true }); - } - - this.setState({ open: !this.state.open }); - }; - - handleClose = () => { - if (this.state.open && this.activeElement) { - this.activeElement.focus({ preventScroll: true }); +const getFrequentlyUsedLanguages = createSelector([ + state => state.getIn(['settings', 'frequentlyUsedLanguages'], ImmutableMap()), +], languageCounters => ( + languageCounters.keySeq() + .sort((a, b) => languageCounters.get(a) - languageCounters.get(b)) + .reverse() + .toArray() +)); + +export const LanguageDropdown = () => { + const [open, setOpen] = useState(false); + const [placement, setPlacement] = useState('bottom'); + const [guess, setGuess] = useState(''); + const activeElementRef = useRef(null); + const targetRef = useRef(null); + + const intl = useIntl(); + + const dispatch = useAppDispatch(); + const frequentlyUsedLanguages = useAppSelector(getFrequentlyUsedLanguages); + const value = useAppSelector((state) => state.compose.get('language')); + const text = useAppSelector((state) => state.compose.get('text')); + + const current = preloadedLanguages.find(lang => lang[0] === value) ?? []; + + const handleToggle = useCallback(() => { + if (open && activeElementRef.current) + activeElementRef.current.focus({ preventScroll: true }); + + setOpen(!open); + }, [open, setOpen]); + + const handleClose = useCallback(() => { + if (open && activeElementRef.current) + activeElementRef.current.focus({ preventScroll: true }); + + setOpen(false); + }, [open, setOpen]); + + const handleChange = useCallback((value) => { + dispatch(changeComposeLanguage(value)); + }, [dispatch]); + + const handleOverlayEnter = useCallback(({ placement }) => { + setPlacement(placement); + }, [setPlacement]); + + useEffect(() => { + if (text.length > 20) { + debouncedGuess(text, setGuess); + } else { + setGuess(''); } - - this.setState({ open: false }); - }; - - handleChange = value => { - const { onChange } = this.props; - onChange(value); - }; - - setTargetRef = c => { - this.target = c; - }; - - findTarget = () => { - return this.target; - }; - - handleOverlayEnter = (state) => { - this.setState({ placement: state.placement }); - }; - - render () { - const { value, guess, intl, frequentlyUsedLanguages } = this.props; - const { open, placement } = this.state; - const current = preloadedLanguages.find(lang => lang[0] === value) ?? []; - - return ( -
- - - - {({ props, placement }) => ( -
-
- -
+ }, [text, setGuess]); + + return ( +
+ + + + {({ props, placement }) => ( +
+
+
- )} - -
- ); - } - -} - -export default injectIntl(LanguageDropdown); +
+ )} + +
+ ); +}; diff --git a/app/javascript/mastodon/features/compose/containers/language_dropdown_container.js b/app/javascript/mastodon/features/compose/util/language_detection.js similarity index 51% rename from app/javascript/mastodon/features/compose/containers/language_dropdown_container.js rename to app/javascript/mastodon/features/compose/util/language_detection.js index 64d6516a18cb0e..b3be07d516ff2d 100644 --- a/app/javascript/mastodon/features/compose/containers/language_dropdown_container.js +++ b/app/javascript/mastodon/features/compose/util/language_detection.js @@ -1,23 +1,7 @@ -import { createSelector } from '@reduxjs/toolkit'; -import { Map as ImmutableMap } from 'immutable'; -import { connect } from 'react-redux'; - import lande from 'lande'; import { debounce } from 'lodash'; -import { changeComposeLanguage } from 'mastodon/actions/compose'; - -import LanguageDropdown from '../components/language_dropdown'; -import { urlRegex } from '../util/url_regex'; - -const getFrequentlyUsedLanguages = createSelector([ - state => state.getIn(['settings', 'frequentlyUsedLanguages'], ImmutableMap()), -], languageCounters => ( - languageCounters.keySeq() - .sort((a, b) => languageCounters.get(a) - languageCounters.get(b)) - .reverse() - .toArray() -)); +import { urlRegex } from './url_regex'; const ISO_639_MAP = { afr: 'af', // Afrikaans @@ -72,47 +56,21 @@ const ISO_639_MAP = { vie: 'vi', // Vietnamese }; -const debouncedLande = debounce((text) => { +const guessLanguage = (text) => { text = text .replace(urlRegex, '') .replace(/(^|[^/\w])@(([a-z0-9_]+)@[a-z0-9.-]+[a-z0-9]+)/ig, ''); - if (text.length <= 20) - return undefined; - - return lande(text); -}, 500, { trailing: true }); - -const detectedLanguage = createSelector([ - state => state.getIn(['compose', 'text']), -], text => { if (text.length > 20) { - const guesses = debouncedLande(text); - if (!guesses) - return ''; - - const [lang, confidence] = guesses[0]; - - if (confidence > 0.8) { + const [lang, confidence] = lande(text)[0]; + + if (confidence > 0.8) return ISO_639_MAP[lang]; - } } return ''; -}); - -const mapStateToProps = state => ({ - frequentlyUsedLanguages: getFrequentlyUsedLanguages(state), - value: state.getIn(['compose', 'language']), - guess: detectedLanguage(state), -}); - -const mapDispatchToProps = dispatch => ({ - - onChange (value) { - dispatch(changeComposeLanguage(value)); - }, - -}); +}; -export default connect(mapStateToProps, mapDispatchToProps)(LanguageDropdown); +export const debouncedGuess = debounce((text, setGuess) => { + setGuess(guessLanguage(text)); +}, 500, { leading: true, trailing: true }); \ No newline at end of file From 0885c316331cf4d314fb6dc3f2e057a6d2ccdfaf Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Thu, 23 Jan 2025 14:01:11 +0100 Subject: [PATCH 02/42] Add information about alt text to alt text modal in web UI (#33702) --- .../alt_text_modal/components/info_button.tsx | 81 +++++++++++++++++++ .../features/alt_text_modal/index.tsx | 14 +++- app/javascript/mastodon/locales/en.json | 2 + .../400-24px/question_mark-fill.svg | 1 + .../material-icons/400-24px/question_mark.svg | 1 + .../styles/mastodon/components.scss | 42 ++++++++++ app/javascript/styles/mastodon/forms.scss | 7 +- 7 files changed, 142 insertions(+), 6 deletions(-) create mode 100644 app/javascript/mastodon/features/alt_text_modal/components/info_button.tsx create mode 100644 app/javascript/material-icons/400-24px/question_mark-fill.svg create mode 100644 app/javascript/material-icons/400-24px/question_mark.svg diff --git a/app/javascript/mastodon/features/alt_text_modal/components/info_button.tsx b/app/javascript/mastodon/features/alt_text_modal/components/info_button.tsx new file mode 100644 index 00000000000000..701af2d98c976b --- /dev/null +++ b/app/javascript/mastodon/features/alt_text_modal/components/info_button.tsx @@ -0,0 +1,81 @@ +import { useState, useRef, useCallback, useId } from 'react'; + +import { FormattedMessage, useIntl, defineMessages } from 'react-intl'; + +import classNames from 'classnames'; + +import Overlay from 'react-overlays/Overlay'; + +import QuestionMarkIcon from '@/material-icons/400-24px/question_mark.svg?react'; +import { Icon } from 'mastodon/components/icon'; + +const messages = defineMessages({ + help: { id: 'info_button.label', defaultMessage: 'Help' }, +}); + +export const InfoButton: React.FC = () => { + const intl = useIntl(); + const [open, setOpen] = useState(false); + const triggerRef = useRef(null); + const accessibilityId = useId(); + + const handleClick = useCallback(() => { + setOpen(!open); + }, [open, setOpen]); + + return ( + <> + + + + {({ props }) => ( +
+

{node}

, + p: (node) =>

{node}

, + ul: (node) =>
    {node}
, + li: (node) =>
  • {node}
  • , + }} + /> +
    + )} +
    + + ); +}; diff --git a/app/javascript/mastodon/features/alt_text_modal/index.tsx b/app/javascript/mastodon/features/alt_text_modal/index.tsx index 88ffb7c477fa13..80c4f36105e5ad 100644 --- a/app/javascript/mastodon/features/alt_text_modal/index.tsx +++ b/app/javascript/mastodon/features/alt_text_modal/index.tsx @@ -36,6 +36,8 @@ import type { MediaAttachment } from 'mastodon/models/media_attachment'; import { useAppSelector, useAppDispatch } from 'mastodon/store'; import { assetHost } from 'mastodon/utils/config'; +import { InfoButton } from './components/info_button'; + const messages = defineMessages({ placeholderVisual: { id: 'alt_text_modal.describe_for_people_with_visual_impairments', @@ -504,6 +506,13 @@ export const AltTextModal = forwardRef>(
    + + +
    + - +
    diff --git a/app/javascript/mastodon/locales/en.json b/app/javascript/mastodon/locales/en.json index ac05c0f53eecde..a2dedd22d5a8be 100644 --- a/app/javascript/mastodon/locales/en.json +++ b/app/javascript/mastodon/locales/en.json @@ -414,6 +414,8 @@ "ignore_notifications_modal.not_followers_title": "Ignore notifications from people not following you?", "ignore_notifications_modal.not_following_title": "Ignore notifications from people you don't follow?", "ignore_notifications_modal.private_mentions_title": "Ignore notifications from unsolicited Private Mentions?", + "info_button.label": "Help", + "info_button.what_is_alt_text": "

    What is alt text?

    Alt text provides image descriptions for people with vision impairments, low-bandwidth connections, or those seeking extra context.

    You can improve accessibility and understanding for everyone by writing clear, concise, and objective alt text.

    ", "interaction_modal.action.favourite": "To continue, you need to favorite from your account.", "interaction_modal.action.follow": "To continue, you need to follow from your account.", "interaction_modal.action.reblog": "To continue, you need to reblog from your account.", diff --git a/app/javascript/material-icons/400-24px/question_mark-fill.svg b/app/javascript/material-icons/400-24px/question_mark-fill.svg new file mode 100644 index 00000000000000..9b02086c4d8756 --- /dev/null +++ b/app/javascript/material-icons/400-24px/question_mark-fill.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/javascript/material-icons/400-24px/question_mark.svg b/app/javascript/material-icons/400-24px/question_mark.svg new file mode 100644 index 00000000000000..9b02086c4d8756 --- /dev/null +++ b/app/javascript/material-icons/400-24px/question_mark.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/javascript/styles/mastodon/components.scss b/app/javascript/styles/mastodon/components.scss index ff7f1b75a4a421..ed23a88d4137c8 100644 --- a/app/javascript/styles/mastodon/components.scss +++ b/app/javascript/styles/mastodon/components.scss @@ -50,6 +50,34 @@ } } +.help-button { + background: $ui-button-background-color; + border: 0; + color: $ui-button-color; + border-radius: 20px; + cursor: pointer; + width: 24px; + height: 24px; + display: flex; + align-items: center; + justify-content: center; + + &:active, + &:focus, + &:hover { + background-color: $ui-button-focus-background-color; + } + + &:focus-visible { + outline: $ui-button-icon-focus-outline; + } + + .icon { + width: 14px; + height: 14px; + } +} + .button { background-color: $ui-button-background-color; border: 10px none; @@ -6091,6 +6119,20 @@ a.status-card { } } + &__popout { + background: var(--dropdown-background-color); + backdrop-filter: var(--background-filter); + border: 1px solid var(--dropdown-border-color); + box-shadow: var(--dropdown-shadow); + max-width: 320px; + padding: 16px; + border-radius: 8px; + z-index: 9999 !important; + font-size: 14px; + line-height: 20px; + color: $darker-text-color; + } + .copy-paste-text { margin-bottom: 0; } diff --git a/app/javascript/styles/mastodon/forms.scss b/app/javascript/styles/mastodon/forms.scss index a8949b7100ef6f..b9f86f82a217f9 100644 --- a/app/javascript/styles/mastodon/forms.scss +++ b/app/javascript/styles/mastodon/forms.scss @@ -83,9 +83,12 @@ code { &__toolbar { margin-top: 16px; display: flex; - justify-content: space-between; align-items: center; gap: 16px; + + .character-counter { + flex: 0 0 auto; + } } &.hidden { @@ -565,7 +568,7 @@ code { margin-bottom: 15px; } - button:not(.button, .link-button) { + button:not(.button, .link-button, .help-button) { display: block; width: 100%; border: 0; From 51ecc7326f8e1d7a88dab0503205aa80715566ce Mon Sep 17 00:00:00 2001 From: Matt Jankowski Date: Thu, 23 Jan 2025 08:35:19 -0500 Subject: [PATCH 03/42] Fix intermittent services/ap/process_status_update tags failure (#33695) --- spec/services/activitypub/process_status_update_service_spec.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/services/activitypub/process_status_update_service_spec.rb b/spec/services/activitypub/process_status_update_service_spec.rb index 1a8ea2d1709694..caaca2fe7c6600 100644 --- a/spec/services/activitypub/process_status_update_service_spec.rb +++ b/spec/services/activitypub/process_status_update_service_spec.rb @@ -268,7 +268,7 @@ it 'updates tags and featured tags' do expect { subject.call(status, json, json) } - .to change { status.tags.reload.pluck(:name) }.from(%w(test foo)).to(%w(foo bar)) + .to change { status.tags.reload.pluck(:name) }.from(contain_exactly('test', 'foo')).to(contain_exactly('foo', 'bar')) .and change { status.account.featured_tags.find_by(name: 'test').statuses_count }.by(-1) .and change { status.account.featured_tags.find_by(name: 'bar').statuses_count }.by(1) .and change { status.account.featured_tags.find_by(name: 'bar').last_status_at }.from(nil).to(be_present) From 1b2c9524712cd974a4db32c1e21678432dc76f21 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 23 Jan 2025 13:36:03 +0000 Subject: [PATCH 04/42] New Crowdin Translations (automated) (#33697) Co-authored-by: GitHub Actions --- app/javascript/mastodon/locales/ca.json | 4 +- app/javascript/mastodon/locales/de.json | 38 ++++----- app/javascript/mastodon/locales/fi.json | 7 ++ app/javascript/mastodon/locales/hu.json | 7 ++ app/javascript/mastodon/locales/ia.json | 1 + app/javascript/mastodon/locales/is.json | 7 ++ app/javascript/mastodon/locales/kab.json | 20 +++++ app/javascript/mastodon/locales/ko.json | 15 ++++ app/javascript/mastodon/locales/lt.json | 7 ++ app/javascript/mastodon/locales/pl.json | 15 ++++ config/locales/activerecord.ko.yml | 2 + config/locales/activerecord.pl.yml | 2 + config/locales/kab.yml | 5 ++ config/locales/ko.yml | 3 + config/locales/pl.yml | 101 +++++++++++++++++++++++ config/locales/simple_form.ko.yml | 6 ++ config/locales/simple_form.pl.yml | 12 +++ 17 files changed, 231 insertions(+), 21 deletions(-) diff --git a/app/javascript/mastodon/locales/ca.json b/app/javascript/mastodon/locales/ca.json index bd264ece96088e..3cbc556e09c286 100644 --- a/app/javascript/mastodon/locales/ca.json +++ b/app/javascript/mastodon/locales/ca.json @@ -90,8 +90,8 @@ "alt_text_modal.add_text_from_image": "Afegiu text d'una imatge", "alt_text_modal.cancel": "Cancel·la", "alt_text_modal.change_thumbnail": "Canvia la miniatura", - "alt_text_modal.describe_for_people_with_hearing_impairments": "Descriu això per a persones amb problemes d'audició…", - "alt_text_modal.describe_for_people_with_visual_impairments": "Descriu això per a persones amb problemes visuals…", + "alt_text_modal.describe_for_people_with_hearing_impairments": "Descriviu això per a persones amb problemes d'audició…", + "alt_text_modal.describe_for_people_with_visual_impairments": "Descriviu això per a persones amb problemes visuals…", "alt_text_modal.done": "Fet", "announcement.announcement": "Anunci", "annual_report.summary.archetype.booster": "Sempre a la moda", diff --git a/app/javascript/mastodon/locales/de.json b/app/javascript/mastodon/locales/de.json index 7a7d5d614c0672..a90843fa146619 100644 --- a/app/javascript/mastodon/locales/de.json +++ b/app/javascript/mastodon/locales/de.json @@ -3,7 +3,7 @@ "about.contact": "Kontakt:", "about.disclaimer": "Mastodon ist eine freie, quelloffene Software und eine Marke der Mastodon gGmbH.", "about.domain_blocks.no_reason_available": "Grund unbekannt", - "about.domain_blocks.preamble": "Mastodon erlaubt es dir grundsätzlich, alle Inhalte von allen Nutzer*innen auf allen Servern im Fediverse zu sehen und mit ihnen zu interagieren. Für diesen Server gibt es aber ein paar Ausnahmen.", + "about.domain_blocks.preamble": "Mastodon erlaubt es dir grundsätzlich, Inhalte von allen Nutzer*innen auf allen Servern im Fediversum zu sehen und mit ihnen zu interagieren. Für diesen Server gibt es aber ein paar Ausnahmen.", "about.domain_blocks.silenced.explanation": "Alle Inhalte und Profile dieses Servers werden zunächst nicht angezeigt. Du kannst die Profile und Inhalte aber dennoch sehen, wenn du explizit nach diesen suchst oder diesen folgst.", "about.domain_blocks.silenced.title": "Stummgeschaltet", "about.domain_blocks.suspended.explanation": "Es werden keine Daten von diesem Server verarbeitet, gespeichert oder ausgetauscht, sodass eine Interaktion oder Kommunikation mit Nutzer*innen dieses Servers nicht möglich ist.", @@ -19,7 +19,7 @@ "account.block_domain": "{domain} sperren", "account.block_short": "Blockieren", "account.blocked": "Blockiert", - "account.cancel_follow_request": "Follower-Anfrage zurückziehen", + "account.cancel_follow_request": "Abo-Anfrage verwerfen", "account.copy": "Link zum Profil kopieren", "account.direct": "@{name} privat erwähnen", "account.disable_notifications": "Höre auf mich zu benachrichtigen wenn @{name} etwas postet", @@ -42,8 +42,8 @@ "account.hide_reblogs": "Geteilte Beiträge von @{name} ausblenden", "account.in_memoriam": "Zum Andenken.", "account.joined_short": "Mitglied seit", - "account.languages": "Ausgewählte Sprachen ändern", - "account.link_verified_on": "Das Profil mit dieser E-Mail-Adresse wurde bereits am {date} bestätigt", + "account.languages": "Sprache ändern.", + "account.link_verified_on": "Das Profil mit dieser E-Mail-Adresse wurde bereits am {date} verifiziert", "account.locked_info": "Die Privatsphäre dieses Kontos wurde auf „geschützt“ gesetzt. Die Person bestimmt manuell, wer ihrem Profil folgen darf.", "account.media": "Medien", "account.mention": "@{name} erwähnen", @@ -63,7 +63,7 @@ "account.share": "Profil von @{name} teilen", "account.show_reblogs": "Geteilte Beiträge von @{name} anzeigen", "account.statuses_counter": "{count, plural, one {{counter} Beitrag} other {{counter} Beiträge}}", - "account.unblock": "Blockierung von @{name} aufheben", + "account.unblock": "{name} nicht mehr blockieren", "account.unblock_domain": "Blockierung von {domain} aufheben", "account.unblock_short": "Blockierung aufheben", "account.unendorse": "Im Profil nicht mehr empfehlen", @@ -72,8 +72,8 @@ "account.unmute_notifications_short": "Stummschaltung der Benachrichtigungen aufheben", "account.unmute_short": "Stummschaltung aufheben", "account_note.placeholder": "Klicken, um Notiz hinzuzufügen", - "admin.dashboard.daily_retention": "Verweildauer der Benutzer*innen pro Tag nach der Registrierung", - "admin.dashboard.monthly_retention": "Verweildauer der Benutzer*innen pro Monat nach der Registrierung", + "admin.dashboard.daily_retention": "Verweildauer der Nutzer im Tagesdurchschnitt seit Registrierung", + "admin.dashboard.monthly_retention": "Verweildauer der Nutzer im Monatsdurchschnitt seit Registrierung", "admin.dashboard.retention.average": "Durchschnitt", "admin.dashboard.retention.cohort": "Monat der Registrierung", "admin.dashboard.retention.cohort_size": "Neue Konten", @@ -89,30 +89,30 @@ "alt_text_modal.add_alt_text": "Bildbeschreibung hinzufügen", "alt_text_modal.add_text_from_image": "Text aus Bild hinzufügen", "alt_text_modal.cancel": "Abbrechen", - "alt_text_modal.change_thumbnail": "Vorschaubild ändern", - "alt_text_modal.describe_for_people_with_hearing_impairments": "Beschreibe den Inhalt für Menschen mit Schwerhörigkeit …", - "alt_text_modal.describe_for_people_with_visual_impairments": "Beschreibe den Inhalt für Menschen mit Sehschwäche …", + "alt_text_modal.change_thumbnail": "Titelbild ändern", + "alt_text_modal.describe_for_people_with_hearing_impairments": "Beschreibung für Blinde und Sehbehinderte...", + "alt_text_modal.describe_for_people_with_visual_impairments": "Beschreibung für Blinde und Sehbehinderte", "alt_text_modal.done": "Fertig", "announcement.announcement": "Ankündigung", "annual_report.summary.archetype.booster": "Trendjäger*in", "annual_report.summary.archetype.lurker": "Beobachter*in", - "annual_report.summary.archetype.oracle": "Universaltalent", + "annual_report.summary.archetype.oracle": "Wandelndes Lexikon", "annual_report.summary.archetype.pollster": "Meinungsforscher*in", - "annual_report.summary.archetype.replier": "Sozialer Schmetterling", - "annual_report.summary.followers.followers": "Follower", + "annual_report.summary.archetype.replier": "Sozialakrobat", + "annual_report.summary.followers.followers": "Abonnenten", "annual_report.summary.followers.total": "{count} insgesamt", "annual_report.summary.here_it_is": "Dein Jahresrückblick für {year}:", - "annual_report.summary.highlighted_post.by_favourites": "am häufigsten favorisierter Beitrag", - "annual_report.summary.highlighted_post.by_reblogs": "am häufigsten geteilter Beitrag", + "annual_report.summary.highlighted_post.by_favourites": "Am häufigsten favorisierter Beitrag", + "annual_report.summary.highlighted_post.by_reblogs": "Am häufigsten geteilter Beitrag", "annual_report.summary.highlighted_post.by_replies": "Beitrag mit den meisten Antworten", "annual_report.summary.highlighted_post.possessive": "{name}", - "annual_report.summary.most_used_app.most_used_app": "am häufigsten verwendete App", - "annual_report.summary.most_used_hashtag.most_used_hashtag": "am häufigsten verwendeter Hashtag", + "annual_report.summary.most_used_app.most_used_app": "Am häufigsten verwendete App", + "annual_report.summary.most_used_hashtag.most_used_hashtag": "Am häufigsten verwendeter Hashtag", "annual_report.summary.most_used_hashtag.none": "Keiner", - "annual_report.summary.new_posts.new_posts": "neue Beiträge", + "annual_report.summary.new_posts.new_posts": "Neue Beiträge", "annual_report.summary.percentile.text": "Damit gehörst du zu den oberstender Nutzer*innen auf {domain}.", "annual_report.summary.percentile.we_wont_tell_bernie": "Wir werden Bernie nichts verraten.", - "annual_report.summary.thanks": "Danke, dass du Teil von Mastodon bist!", + "annual_report.summary.thanks": "Vielen Dank, dass du Teil von Mastodon bist!", "attachments_list.unprocessed": "(ausstehend)", "audio.hide": "Audio ausblenden", "block_modal.remote_users_caveat": "Wir werden den Server {domain} bitten, deine Entscheidung zu respektieren. Allerdings kann nicht garantiert werden, dass sie eingehalten wird, weil einige Server Blockierungen unterschiedlich handhaben können. Öffentliche Beiträge können für nicht angemeldete Nutzer*innen weiterhin sichtbar sein.", diff --git a/app/javascript/mastodon/locales/fi.json b/app/javascript/mastodon/locales/fi.json index 2d6598c20de5a1..36954e4c541c79 100644 --- a/app/javascript/mastodon/locales/fi.json +++ b/app/javascript/mastodon/locales/fi.json @@ -86,6 +86,13 @@ "alert.unexpected.message": "Tapahtui odottamaton virhe.", "alert.unexpected.title": "Hups!", "alt_text_badge.title": "Vaihtoehtoinen teksti", + "alt_text_modal.add_alt_text": "Lisää vaihtoehtoinen teksti", + "alt_text_modal.add_text_from_image": "Lisää teksti kuvasta", + "alt_text_modal.cancel": "Peruuta", + "alt_text_modal.change_thumbnail": "Vaihda pikkukuva", + "alt_text_modal.describe_for_people_with_hearing_impairments": "Kuvaile tätä kuulovammallisille ihmisille…", + "alt_text_modal.describe_for_people_with_visual_impairments": "Kuvaile tätä näkövammallisille ihmisille…", + "alt_text_modal.done": "Valmis", "announcement.announcement": "Tiedote", "annual_report.summary.archetype.booster": "Tehostaja", "annual_report.summary.archetype.lurker": "Lymyilijä", diff --git a/app/javascript/mastodon/locales/hu.json b/app/javascript/mastodon/locales/hu.json index 664c0c58db8e24..537eb797b873e7 100644 --- a/app/javascript/mastodon/locales/hu.json +++ b/app/javascript/mastodon/locales/hu.json @@ -86,6 +86,13 @@ "alert.unexpected.message": "Váratlan hiba történt.", "alert.unexpected.title": "Hoppá!", "alt_text_badge.title": "Helyettesítő szöveg", + "alt_text_modal.add_alt_text": "Helyettesítő szöveg hozzáadása", + "alt_text_modal.add_text_from_image": "Szöveg hozzáadása a képből", + "alt_text_modal.cancel": "Mégse", + "alt_text_modal.change_thumbnail": "Bélyegkép megváltoztatása", + "alt_text_modal.describe_for_people_with_hearing_impairments": "Írd le a hallássérültek számára…", + "alt_text_modal.describe_for_people_with_visual_impairments": "Írd le a látássérültek számára…", + "alt_text_modal.done": "Kész", "announcement.announcement": "Közlemény", "annual_report.summary.archetype.booster": "A cool-vadász", "annual_report.summary.archetype.lurker": "A settenkedő", diff --git a/app/javascript/mastodon/locales/ia.json b/app/javascript/mastodon/locales/ia.json index a39f4939577793..fc3194e4dda8df 100644 --- a/app/javascript/mastodon/locales/ia.json +++ b/app/javascript/mastodon/locales/ia.json @@ -89,6 +89,7 @@ "alt_text_modal.add_text_from_image": "Adder texto ab imagine", "alt_text_modal.cancel": "Cancellar", "alt_text_modal.change_thumbnail": "Cambiar le miniatura", + "alt_text_modal.done": "Preste", "announcement.announcement": "Annuncio", "annual_report.summary.archetype.booster": "Le impulsator", "annual_report.summary.archetype.lurker": "Le lector", diff --git a/app/javascript/mastodon/locales/is.json b/app/javascript/mastodon/locales/is.json index ee0e38140bdbe6..148b6237e22662 100644 --- a/app/javascript/mastodon/locales/is.json +++ b/app/javascript/mastodon/locales/is.json @@ -86,6 +86,13 @@ "alert.unexpected.message": "Upp kom óvænt villa.", "alert.unexpected.title": "Úbbs!", "alt_text_badge.title": "Hjálpartexti mynda", + "alt_text_modal.add_alt_text": "Bæta við hjálpartexta", + "alt_text_modal.add_text_from_image": "Bæta við texta úr mynd", + "alt_text_modal.cancel": "Hætta við", + "alt_text_modal.change_thumbnail": "Skipta um smámynd", + "alt_text_modal.describe_for_people_with_hearing_impairments": "Lýstu þessu fyrir fólk með skerta heyrn…", + "alt_text_modal.describe_for_people_with_visual_impairments": "Lýstu þessu fyrir fólk með skerta sjón…", + "alt_text_modal.done": "Lokið", "announcement.announcement": "Auglýsing", "annual_report.summary.archetype.booster": "Svali gaurinn", "annual_report.summary.archetype.lurker": "Lurkurinn", diff --git a/app/javascript/mastodon/locales/kab.json b/app/javascript/mastodon/locales/kab.json index 02ecec2a70e621..8cdfe6df193456 100644 --- a/app/javascript/mastodon/locales/kab.json +++ b/app/javascript/mastodon/locales/kab.json @@ -74,7 +74,10 @@ "alert.unexpected.message": "Yeḍra-d unezri ur netturaǧu ara.", "alert.unexpected.title": "Ayhuh!", "alt_text_badge.title": "Aḍris asegzan", + "alt_text_modal.cancel": "Semmet", + "alt_text_modal.done": "Immed", "announcement.announcement": "Ulɣu", + "annual_report.summary.most_used_hashtag.none": "Ula yiwen", "audio.hide": "Ffer amesli", "block_modal.show_less": "Ssken-d drus", "block_modal.show_more": "Ssken-d ugar", @@ -100,9 +103,11 @@ "column.blocks": "Imiḍanen yettusḥebsen", "column.bookmarks": "Ticraḍ", "column.community": "Tasuddemt tadigant", + "column.create_list": "Snulfu-d tabdart", "column.direct": "Tabdarin tusligin", "column.directory": "Inig deg imeɣna", "column.domain_blocks": "Taɣulin yeffren", + "column.edit_list": "Ẓreg tabdart", "column.favourites": "Imenyafen", "column.follow_requests": "Isuturen n teḍfeṛt", "column.home": "Agejdan", @@ -165,6 +170,7 @@ "confirmations.unfollow.message": "Tetḥeqqeḍ belli tebɣiḍ ur teṭafaṛeḍ ara {name}?", "content_warning.hide": "Ffer tasuffeɣt", "content_warning.show": "Ssken-d akken tebɣu tili", + "content_warning.show_more": "Sken-d ugar", "conversation.delete": "Kkes adiwenni", "conversation.mark_as_read": "Creḍ yettwaɣṛa", "conversation.open": "Ssken adiwenni", @@ -325,11 +331,20 @@ "link_preview.author": "S-ɣur {name}", "link_preview.more_from_author": "Ugar sɣur {name}", "link_preview.shares": "{count, plural, one {{counter} n tsuffeɣt} other {{counter} n tsuffaɣ}}", + "lists.add_member": "Rnu", + "lists.add_to_list": "Rnu ɣer tebdart", + "lists.add_to_lists": "Rnu {name} ɣer tebdarin", + "lists.create": "Snulfu-d", "lists.delete": "Kkes tabdart", "lists.edit": "Ẓreg tabdart", + "lists.list_name": "Isem n tebdart", + "lists.new_list_name": "Isem n tebdart tamaynut", + "lists.remove_member": "Kkes", "lists.replies_policy.followed": "Kra n useqdac i yettwaḍefren", "lists.replies_policy.list": "Iɛeggalen n tebdart", "lists.replies_policy.none": "Ula yiwen·t", + "lists.save": "Sekles", + "lists.search": "Nadi", "load_pending": "{count, plural, one {# n uferdis amaynut} other {# n yiferdisen imaynuten}}", "loading_indicator.label": "Yessalay-d …", "media_gallery.hide": "Seggelmes", @@ -399,6 +414,7 @@ "notifications.column_settings.filter_bar.category": "Iri n usizdeg uzrib", "notifications.column_settings.follow": "Imeḍfaṛen imaynuten:", "notifications.column_settings.follow_request": "Isuturen imaynuten n teḍfeṛt:", + "notifications.column_settings.group": "Agraw", "notifications.column_settings.mention": "Abdar:", "notifications.column_settings.poll": "Igemmaḍ n usenqed:", "notifications.column_settings.push": "Alɣuten yettudemmren", @@ -429,6 +445,9 @@ "notifications.policy.filter_private_mentions_title": "Abdar uslig ur yettwasferken ara", "notifications_permission_banner.enable": "Rmed alɣuten n tnarit", "notifications_permission_banner.title": "Ur zeggel acemma", + "onboarding.follows.back": "Uɣal", + "onboarding.follows.done": "Immed", + "onboarding.follows.search": "Nadi", "onboarding.profile.display_name": "Isem ara d-yettwaskanen", "onboarding.profile.display_name_hint": "Isem-ik·im ummid neɣ isem-ik·im n uqeṣṣer…", "onboarding.profile.note": "Tameddurt", @@ -524,6 +543,7 @@ "search_results.accounts": "Imeɣna", "search_results.all": "Akk", "search_results.hashtags": "Ihacṭagen", + "search_results.no_results": "Ulac igemmaḍ.", "search_results.see_all": "Wali-ten akk", "search_results.statuses": "Tisuffaɣ", "server_banner.active_users": "iseqdacen urmiden", diff --git a/app/javascript/mastodon/locales/ko.json b/app/javascript/mastodon/locales/ko.json index fd5e2b906d3c7a..d1ee08dcad2c0e 100644 --- a/app/javascript/mastodon/locales/ko.json +++ b/app/javascript/mastodon/locales/ko.json @@ -86,6 +86,13 @@ "alert.unexpected.message": "예상하지 못한 에러가 발생했습니다.", "alert.unexpected.title": "앗!", "alt_text_badge.title": "대체 문구", + "alt_text_modal.add_alt_text": "대체 텍스트 추가", + "alt_text_modal.add_text_from_image": "이미지에서 텍스트 추가", + "alt_text_modal.cancel": "취소", + "alt_text_modal.change_thumbnail": "썸네일 변경", + "alt_text_modal.describe_for_people_with_hearing_impairments": "청력 장애가 있는 사람들을 위한 설명을 작성하세요…", + "alt_text_modal.describe_for_people_with_visual_impairments": "시각 장애가 있는 사람들을 위한 설명을 작성하세요…", + "alt_text_modal.done": "완료", "announcement.announcement": "공지사항", "annual_report.summary.archetype.booster": "연쇄부스트마", "annual_report.summary.archetype.lurker": "은둔자", @@ -407,6 +414,13 @@ "ignore_notifications_modal.not_followers_title": "나를 팔로우하지 않는 사람들의 알림을 무시할까요?", "ignore_notifications_modal.not_following_title": "내가 팔로우하지 않는 사람들의 알림을 무시할까요?", "ignore_notifications_modal.private_mentions_title": "요청하지 않은 개인 멘션 알림을 무시할까요?", + "interaction_modal.action.favourite": "계속하려면 내 계정으로 즐겨찾기해야 합니다.", + "interaction_modal.action.follow": "계속하려면 내 계정으로 팔로우해야 합니다.", + "interaction_modal.action.reblog": "계속하려면 내 계정으로 리블로그해야 합니다.", + "interaction_modal.action.reply": "계속하려면 내 계정으로 답장해야 합니다.", + "interaction_modal.action.vote": "계속하려면 내 계정으로 투표해야 합니다.", + "interaction_modal.go": "이동", + "interaction_modal.no_account_yet": "아직 계정이 없나요?", "interaction_modal.on_another_server": "다른 서버에", "interaction_modal.on_this_server": "이 서버에서", "interaction_modal.title.favourite": "{name} 님의 게시물을 좋아하기", @@ -830,6 +844,7 @@ "status.reblogs.empty": "아직 아무도 이 게시물을 부스트하지 않았습니다. 부스트 한 사람들이 여기에 표시 됩니다.", "status.redraft": "지우고 다시 쓰기", "status.remove_bookmark": "북마크 삭제", + "status.remove_favourite": "즐겨찾기에서 제거", "status.replied_in_thread": "글타래에 답장", "status.replied_to": "{name} 님에게", "status.reply": "답장", diff --git a/app/javascript/mastodon/locales/lt.json b/app/javascript/mastodon/locales/lt.json index 9379620c7eb6bc..2c758b49768e26 100644 --- a/app/javascript/mastodon/locales/lt.json +++ b/app/javascript/mastodon/locales/lt.json @@ -86,6 +86,13 @@ "alert.unexpected.message": "Įvyko netikėta klaida.", "alert.unexpected.title": "Ups!", "alt_text_badge.title": "Alternatyvus tekstas", + "alt_text_modal.add_alt_text": "Pridėti alternatyvųjį tekstą", + "alt_text_modal.add_text_from_image": "Pridėti tekstą iš vaizdo", + "alt_text_modal.cancel": "Atšaukti", + "alt_text_modal.change_thumbnail": "Keisti miniatiūrą", + "alt_text_modal.describe_for_people_with_hearing_impairments": "Aprašykite tai klausos negalią turintiems asmenims…", + "alt_text_modal.describe_for_people_with_visual_impairments": "Aprašykite tai regos sutrikimų turintiems asmenims…", + "alt_text_modal.done": "Atlikta", "announcement.announcement": "Skelbimas", "annual_report.summary.archetype.booster": "Šaunus medžiotojas", "annual_report.summary.archetype.lurker": "Stebėtojas", diff --git a/app/javascript/mastodon/locales/pl.json b/app/javascript/mastodon/locales/pl.json index 079a128cf86347..8e3b8a26fac44e 100644 --- a/app/javascript/mastodon/locales/pl.json +++ b/app/javascript/mastodon/locales/pl.json @@ -86,6 +86,13 @@ "alert.unexpected.message": "Wystąpił nieoczekiwany błąd.", "alert.unexpected.title": "Ups!", "alt_text_badge.title": "Tekst alternatywny", + "alt_text_modal.add_alt_text": "Dodaj tekst alternatywny", + "alt_text_modal.add_text_from_image": "Dodaj tekst z obrazu", + "alt_text_modal.cancel": "Anuluj", + "alt_text_modal.change_thumbnail": "Zmień miniaturę", + "alt_text_modal.describe_for_people_with_hearing_impairments": "Opisz to dla osób z wadą słuchu…", + "alt_text_modal.describe_for_people_with_visual_impairments": "Opisz to dla osób z wadą wzroku…", + "alt_text_modal.done": "Gotowe", "announcement.announcement": "Ogłoszenie", "annual_report.summary.archetype.booster": "Łowca treści", "annual_report.summary.archetype.lurker": "Czyhający", @@ -103,6 +110,7 @@ "annual_report.summary.most_used_hashtag.most_used_hashtag": "najczęściej używany hashtag", "annual_report.summary.most_used_hashtag.none": "Brak", "annual_report.summary.new_posts.new_posts": "nowe wpisy", + "annual_report.summary.percentile.text": "Plasuje Cię w czołówce użytkowników {domain}.", "annual_report.summary.percentile.we_wont_tell_bernie": "Nie powiemy Berniemu.", "annual_report.summary.thanks": "Dziękujemy, że jesteś częścią Mastodona!", "attachments_list.unprocessed": "(nieprzetworzone)", @@ -408,6 +416,10 @@ "ignore_notifications_modal.private_mentions_title": "Ignoruj powiadomienia o nieproszonych wzmiankach prywatnych?", "interaction_modal.action.favourite": "Aby kontynuować, musisz dodać do ulubionych na swoim koncie.", "interaction_modal.action.follow": "Aby kontynuować, musisz obserwować ze swojego konta.", + "interaction_modal.action.reblog": "Aby kontynuować, musisz podać dalej ze swojego konta.", + "interaction_modal.action.reply": "Aby kontynuować, musisz odpowiedzieć ze swojego konta.", + "interaction_modal.action.vote": "Aby kontynuować, musisz zagłosować ze swojego konta.", + "interaction_modal.go": "Dalej", "interaction_modal.no_account_yet": "Nie masz jeszcze konta?", "interaction_modal.on_another_server": "Na innym serwerze", "interaction_modal.on_this_server": "Na tym serwerze", @@ -452,6 +464,7 @@ "keyboard_shortcuts.toggle_hidden": "aby wyświetlić lub ukryć wpis spod CW", "keyboard_shortcuts.toggle_sensitivity": "Pokaż/ukryj multimedia", "keyboard_shortcuts.toot": "Stwórz nowy post", + "keyboard_shortcuts.translate": "Aby przetłumaczyć post", "keyboard_shortcuts.unfocus": "aby opuścić pole wyszukiwania/pisania", "keyboard_shortcuts.up": "aby przejść na górę listy", "lightbox.close": "Zamknij", @@ -690,6 +703,8 @@ "privacy_policy.title": "Polityka prywatności", "recommended": "Zalecane", "refresh": "Odśwież", + "regeneration_indicator.please_stand_by": "Proszę czekać.", + "regeneration_indicator.preparing_your_home_feed": "Przygotowywanie Twojego kanału wiadomości...", "relative_time.days": "{number} dni", "relative_time.full.days": "{number, plural, one {# dzień} few {# dni} many {# dni} other {# dni}} temu", "relative_time.full.hours": "{number, plural, one {# godzinę} few {# godziny} many {# godzin} other {# godzin}} temu", diff --git a/config/locales/activerecord.ko.yml b/config/locales/activerecord.ko.yml index 5dbd2e3d78e41d..9442c3aae3d9ac 100644 --- a/config/locales/activerecord.ko.yml +++ b/config/locales/activerecord.ko.yml @@ -23,6 +23,8 @@ ko: models: account: attributes: + fields: + fields_with_values_missing_labels: 라벨 없는 값들이 존재합니다 username: invalid: 영문자와 숫자, 밑줄만 사용 가능합니다 reserved: 예약되어 있습니다 diff --git a/config/locales/activerecord.pl.yml b/config/locales/activerecord.pl.yml index 06b358700836dc..62edc03c0eafa5 100644 --- a/config/locales/activerecord.pl.yml +++ b/config/locales/activerecord.pl.yml @@ -23,6 +23,8 @@ pl: models: account: attributes: + fields: + fields_with_values_missing_labels: zawiera wartości z brakującymi etykietami username: invalid: może składać się tylko z liter, cyfr i podkreślników reserved: jest zarezerwowana diff --git a/config/locales/kab.yml b/config/locales/kab.yml index 314029a89ede52..11cc8b331835c9 100644 --- a/config/locales/kab.yml +++ b/config/locales/kab.yml @@ -413,6 +413,7 @@ kab: account: Ameskar application: Asnas back_to_account: Tuɣalin ɣer usebter n umiḍan + contents: Agbur deleted: Yettwakkes favourites: Imenyafen language: Tutlayt @@ -432,6 +433,9 @@ kab: tags: search: Anadi title: Ihacṭagen + terms_of_service: + draft: Arewway + publish: Asuffeɣ title: Tadbelt trends: allow: Sireg @@ -781,6 +785,7 @@ kab: delete: Tukksa n umiḍan development: Taneflit edit_profile: Ẓreg amaɣnu + export: Sifeḍ import: Kter import_and_export: Taktert d usifeḍ migrate: Tunigin n umiḍan diff --git a/config/locales/ko.yml b/config/locales/ko.yml index f7469ce25a1cc5..f29f7879c4bfc1 100644 --- a/config/locales/ko.yml +++ b/config/locales/ko.yml @@ -925,9 +925,12 @@ ko: generates: action: 생성 chance_to_review_html: "생성된 이용 약관은 자동으로 게시되지 않을 것입니다. 결과를 확인할 기회가 있습니다. 진행하려면 필요한 정보들을 입력하세요." + explanation_html: 제공되는 이용약관 틀은 정보 제공만을 목적으로 하며 법률 조언으로 해석하면 안 됩니다. 귀하의 상황에 맞는 법률 자문을 받아주시기 바랍니다. title: 이용 약관 설정 history: 역사 live: 활성 + no_history: 기록된 이용약관 변경이 아직 없습니다. + no_terms_of_service_html: 현재 설정된 이용약관이 없습니다. 이용약관은 명확성을 제공하고 귀하와 사용자간 분쟁에서 발생할 수 있는 책임으로부터 보호할 수 있습니다. notified_on_html: 사용자들이 %{date}에 알림을 받았습니다 notify_users: 사용자들에게 알리기 preview: diff --git a/config/locales/pl.yml b/config/locales/pl.yml index 83a9674f843623..e2e28600591a3c 100644 --- a/config/locales/pl.yml +++ b/config/locales/pl.yml @@ -285,6 +285,7 @@ pl: enable_user_html: "%{name} przywrócił(a) możliwość logowania użytkownikowi %{target}" memorialize_account_html: "%{name} nadał(a) kontu %{target} status in memoriam" promote_user_html: "%{name} podniósł(a) uprawnienia użytkownikowi %{target}" + publish_terms_of_service_html: "%{name} opublikował aktualizacje warunków korzystania z usługi" reject_appeal_html: "%{name} zatwierdził(-a) odwołanie decyzji moderacyjnej od %{target}" reject_user_html: "%{name} odrzucił rejestrację od %{target}" remove_avatar_user_html: "%{name} usunął(-ęła) awatar użytkownikowi %{target}" @@ -955,9 +956,36 @@ pl: title: Hashtagi updated_msg: Pomyślnie uaktualniono ustawienia hashtagów terms_of_service: + back: Powrót do warunków świadczenia usług + changelog: Co się zmieniło + create: Użyj własnego + current: Aktualna wersja draft: Szkic generate: Użyj szablonu + generates: + action: Wygeneruj + chance_to_review_html: "Wygenerowane warunki świadczenia usług nie zostaną automatycznie opublikowane. Będziesz miał szansę je sprawdzić raz jeszcze. Wypełnij wymagane pola, aby kontynuować." + explanation_html: Dostarczany wzór warunków świadczenia usług służy wyłącznie celom informacyjnym i nie powinien być interpretowany jako porada prawna w odniesieniu do żadnego przedmiotu. Proszę skonsultować się ze swoim doradcą prawnym w sprawie swojej sytuacji i konkretnych kwestii prawnych, które państwo posiadają. + title: Warunki korzystania z usługi + history: Historia + live: Rzeczywiste + no_history: Nie ma jeszcze zapisanych zmian w warunkach korzystania z usługi. + no_terms_of_service_html: Obecnie nie masz żadnych skonfigurowanych warunków korzystania z usługi. Warunki korzystania z usługi mają zapewnić jasność i ochronę przed potencjalnymi zobowiązaniami w sporach z użytkownikami. + notified_on_html: Użytkownicy powiadomieni o %{date} + notify_users: Powiadom użytkowników + preview: + explanation_html: 'E-mail zostanie wysłany do %{display_count} użytkowników, którzy zarejestrowali się przed %{date}. Otrzymają oni wiadomość o następującej treści:' + send_preview: Wyślij podgląd do %{email} + send_to_all: + few: Wyślij %{display_count} wiadomości e-mail + many: Wyślij %{display_count} wiadomości e-mail + one: Wyślij %{display_count} wiadomość e-mail + other: Wyślij %{display_count} wiadomości e-mail + title: Podgląd warunków powiadomienia o usłudze + publish: Publikuj + published_on_html: Opublikowano w dniu %{date} save_draft: Zapisz wersję roboczą + title: Warunki korzystania z usługi title: Administracja trends: allow: Zezwól @@ -1197,6 +1225,7 @@ pl: set_new_password: Ustaw nowe hasło setup: email_below_hint_html: Sprawdź folder ze spamem lub poproś o inny link potwierdzający. Możesz poprawić swój adres e-mail, jeśli jest niepoprawny. + email_settings_hint_html: Kliknij link, który wysłaliśmy do %{email} , aby rozpocząć korzystanie z Mastodon. Poczekamy tutaj. link_not_received: Nie otrzymano linku? new_confirmation_instructions_sent: Za kilka minut otrzymasz nowy e-mail z linkiem potwierdzającym! title: Sprawdź swoją skrzynkę odbiorczą @@ -1205,6 +1234,7 @@ pl: title: Zaloguj się do %{domain} sign_up: manual_review: Rejestracja na %{domain} przechodzi przez ręczne sprawdzanie przez naszych moderatorów. Aby pomóc nam usprawnić ten proces, napisz coś o sobie oraz dlaczego chcesz założyć konto na %{domain}. + preamble: Z kontem na tym serwerze Mastodon będziesz mógł obserwować każdą inną osobę w sieci, niezależnie od miejsca przechowywania ich konta. title: Skonfigurujmy Twoje konto na %{domain}. status: account_status: Stan konta @@ -1435,6 +1465,68 @@ pl: merge_long: Zachowaj obecne wpisy i dodaj nowe overwrite: Nadpisz overwrite_long: Zastąp obecne wpisy nowymi + overwrite_preambles: + blocking_html: + few: Zamierzasz zastąpić swoją listę bloków maksymalnie %{count} kontami z %{filename}. + many: Zamierzasz zastąpić swoją listę bloków maksymalnie %{count} kontami z %{filename}. + one: Zamierzasz zastąpić swoją listę bloków maksymalnie %{count} kontem z %{filename}. + other: Zamierzasz zastąpić swoją listę bloków maksymalnie %{count} kontami z %{filename}. + bookmarks_html: + few: Zamierzasz zastąpić swoje zakładki maksymalnie %{count} wpisami z %{filename}. + many: Zamierzasz zastąpić swoje zakładki maksymalnie %{count} wpisami z %{filename}. + one: Zamierzasz zastąpić swoje zakładki maksymalnie %{count} wpisem z %{filename}. + other: Zamierzasz zastąpić swoje zakładki maksymalnie %{count} wpisami z %{filename}. + domain_blocking_html: + few: Zamierzasz zastąpić swoją listę bloków domen maksymalnie %{count} domenami z %{filename}. + many: Zamierzasz zastąpić swoją listę bloków domen maksymalnie %{count} domenami z %{filename}. + one: Zamierzasz zastąpić swoją listę bloków domen maksymalnie %{count} domeną z %{filename}. + other: Zamierzasz zastąpić swoją listę bloków domen maksymalnie %{count} domenami z %{filename}. + following_html: + few: Zamierzasz zaobserwować maksymalnie %{count} konta z %{filename} i przestać obserwować kogokolwiek innego. + many: Zamierzasz zaobserwować maksymalnie %{count} kont z %{filename} i przestać obserwować kogokolwiek innego. + one: Zamierzasz zaobserwować maksymalnie %{count} konto z %{filename} i przestać obserwować kogokolwiek innego. + other: Zamierzasz zaobserwować maksymalnie %{count} kont z %{filename} i przestać obserwować kogokolwiek innego. + lists_html: + few: Zamierzasz zastąpić swoje listy maksymalnie %{count} kontami z %{filename}. + many: Zamierzasz zastąpić swoje listy maksymalnie %{count} kontami z %{filename}. + one: Zamierzasz zastąpić swoje listy maksymalnie %{count} kontem z %{filename}. + other: Zamierzasz zastąpić swoje listy maksymalnie %{count} kontami z %{filename}. + muting_html: + few: Zamierzasz zastąpić swoją listę wyciszonych maksymalnie %{count} kontami z %{filename}. + many: Zamierzasz zastąpić swoją listę wyciszonych maksymalnie %{count} kontami z %{filename}. + one: Zamierzasz zastąpić swoją listę wyciszonych maksymalnie %{count} kontem z %{filename}. + other: Zamierzasz zastąpić swoją listę wyciszonych maksymalnie %{count} kontami z %{filename}. + preambles: + blocking_html: + few: Zamierzasz zablokować maksymalnie %{count} konta z %{filename}. + many: Zamierzasz zablokować maksymalnie %{count} kont z %{filename}. + one: Zamierzasz zablokować maksymalnie %{count} konto z %{filename}. + other: Zamierzasz zablokować maksymalnie %{count} kont z %{filename}. + bookmarks_html: + few: Zamierzasz dodać maksymalnie %{count} wpisy do twoich zakładek z %{filename}. + many: Zamierzasz dodać maksymalnie %{count} wpisów do twoich zakładek z %{filename}. + one: Zamierzasz dodać maksymalnie %{count} wpis do twoich zakładek z %{filename}. + other: Zamierzasz dodać maksymalnie %{count} wpisów do twoich zakładek z %{filename}. + domain_blocking_html: + few: Zamierzasz zablokować maksymalnie %{count} domeny z %{filename}. + many: Zamierzasz zablokować maksymalnie %{count} domeny z %{filename}. + one: Zamierzasz zablokować maksymalnie %{count} domenę z %{filename}. + other: Zamierzasz zablokować maksymalnie %{count} domeny z %{filename}. + following_html: + few: Zamierzasz zaobserwować maksymalnie %{count} konta z %{filename}. + many: Zamierzasz zaobserwować maksymalnie %{count} kont z %{filename}. + one: Zamierzasz zaobserwować maksymalnie %{count} konto z %{filename}. + other: Zamierzasz zaobserwować maksymalnie %{count} kont z %{filename}. + lists_html: + few: Zamierzasz dodać maksymalnie %{count} konta do twoich list z %{filename}. Jeżeli nie ma list, nowe zostaną utworzone. + many: Zamierzasz dodać maksymalnie %{count} kont do twoich list z %{filename}. Jeżeli nie ma list, nowe zostaną utworzone. + one: Zamierzasz dodać maksymalnie %{count} konto do twoich list z %{filename}. Jeżeli nie ma list, nowe zostaną utworzone. + other: Zamierzasz dodać maksymalnie %{count} kont do twoich list z %{filename}. Jeżeli nie ma list, nowe zostaną utworzone. + muting_html: + few: Zamierzasz wyciszyć maksymalnie %{count} konta z %{filename}. + many: Zamierzasz wyciszyć maksymalnie %{count} kont z %{filename}. + one: Zamierzasz wyciszyć maksymalnie %{count} konto z %{filename}. + other: Zamierzasz wyciszyć maksymalnie %{count} kont z %{filename}. preface: Możesz zaimportować pewne dane (np. lista kont, które obserwujesz lub blokujesz) do swojego konta na tym serwerze, korzystając z danych wyeksportowanych z innego serwera. recent_imports: Ostatnie importy states: @@ -1926,6 +2018,15 @@ pl: further_actions_html: Jeśli to nie Ty, zalecamy %{action} natychmiastowo i włącz uwierzytelnianie dwuetapowe, aby Twoje konto było bezpieczne. subject: Uzyskano dostęp do twojego konta z nowego adresu IP title: Nowe logowanie + terms_of_service_changed: + agreement: Kontynuując używanie %{domain}, zgadzasz się na te warunki. Jeśli nie zgadzasz się ze zaktualizowanymi warunkami, możesz wypowiedzieć umowę z %{domain} w dowolnym momencie, usuwając swoje konto. + changelog: 'W skrócie oto co oznacza dla Ciebie ta aktualizacja:' + description: 'Otrzymujesz ten e-mail, ponieważ wprowadzamy pewne zmiany w naszym regulaminie usługi w %{domain}. Zachęcamy Cię do pełnego zapoznania się z aktualnymi warunkami:' + description_html: Otrzymujesz ten e-mail, ponieważ wprowadzamy pewne zmiany w naszym regulaminie usługi w %{domain}. Zachęcamy do zapoznania się z aktualnymi warunkami w całości tutaj. + sign_off: Zespół %{domain} + subject: Aktualizacja warunków korzystania z usług + subtitle: Warunki korzystania z %{domain} zmieniają się + title: Ważna aktualizacja warning: appeal: Złóż odwołanie appeal_description: Jeśli uważasz, że zaszło nieporozumienie, możesz złożyć odwołanie do zespołu %{instance}. diff --git a/config/locales/simple_form.ko.yml b/config/locales/simple_form.ko.yml index d40ca7ebf8fb09..92d306224ad0b9 100644 --- a/config/locales/simple_form.ko.yml +++ b/config/locales/simple_form.ko.yml @@ -3,6 +3,7 @@ ko: simple_form: hints: account: + attribution_domains: 한 줄에 하나씩. 가짜 기여로부터 보호합니다. discoverable: 내 공개 게시물과 프로필이 마스토돈의 다양한 추천 기능에 나타날 수 있고 프로필이 다른 사용자에게 제안될 수 있습니다 display_name: 진짜 이름 또는 재미난 이름. fields: 홈페이지, 호칭, 나이, 뭐든지 적고 싶은 것들. @@ -133,8 +134,12 @@ ko: changelog: 마크다운 문법을 사용할 수 있습니다. text: 마크다운 문법을 사용할 수 있습니다. terms_of_service_generator: + admin_email: 법적 고지에는 이의 제기, 법원 명령, 게시 중단 요청, 법 집행 요청이 포함됩니다. + arbitration_address: 위의 실제 주소와 같을 수 있으며, 이메일을 사용한다면 "N/A"로 두세요 arbitration_website: 웹 형태를 사용할 수 있습니다. 이메일을 사용한다면 "N/A"로 둘 수 있습니다 dmca_email: 상단의 "법적 통지를 위한 이메일 주소"와 같은 주소를 사용할 수 있습니다 + domain: 귀하가 제공하는 온라인 서비스의 고유 식별정보입니다. + jurisdiction: 요금을 지불하는 사람이 거주하는 국가를 기재하세요. 회사나 기타 법인인 경우 해당 법인이 설립된 국가와 도시, 지역, 영토 또는 주를 적절히 기재하세요. user: chosen_languages: 체크하면, 선택 된 언어로 작성된 게시물들만 공개 타임라인에 보여집니다 role: 역할은 사용자가 어떤 권한을 가지게 될 지 결정합니다. @@ -150,6 +155,7 @@ ko: url: 이벤트가 어디로 전송될 지 labels: account: + attribution_domains: 나를 기여자로 올릴 수 있도록 허용된 웹사이트들 discoverable: 발견하기 알고리즘에 프로필과 게시물을 추천하기 fields: name: 라벨 diff --git a/config/locales/simple_form.pl.yml b/config/locales/simple_form.pl.yml index d7f3829af2f2e9..efa17c1a9bd12d 100644 --- a/config/locales/simple_form.pl.yml +++ b/config/locales/simple_form.pl.yml @@ -3,6 +3,7 @@ pl: simple_form: hints: account: + attribution_domains: Jedna na linię. discoverable: Twój profil i publiczne wpisy mogą być promowane lub polecane na Mastodonie i twój profil może być sugerowany innym użytkownikom. display_name: Twoje imię lub pseudonim. fields: Co ci się tylko podoba – twoja strona domowa, zaimki, wiek… @@ -129,6 +130,13 @@ pl: show_application: Ty zawsze widzisz program użyty do zamieszczenia. tag: name: Możesz zmieniać tylko wielkość liter, np. aby były bardziej widoczne + terms_of_service: + changelog: Może być stworzony przy pomocy składni Markdown. + text: Może być stworzony przy pomocy składni Markdown. + terms_of_service_generator: + admin_email: Zawiadomienia prawne obejmują środki zapobiegawcze, nakazy sądowe, wnioski o popełnienie sprawy oraz wnioski organów ścigania. + arbitration_address: Może być taki sam jak adres fizyczny powyżej lub „N/A” jeśli używasz adresu e-mail + arbitration_website: Może być formularzem internetowym lub „N/A”, jeśli używasz adresu e-mail user: chosen_languages: Jeżeli zaznaczone, tylko wpisy w wybranych językach będą wyświetlane na publicznych osiach czasu role: Rola kontroluje uprawnienia użytkownika. @@ -321,6 +329,10 @@ pl: changelog: Co się zmieniło? text: Warunki korzystania z usługi terms_of_service_generator: + arbitration_address: Adres fizyczny powiadomień arbitrażowych + arbitration_website: Strona internetowa do składania zgłoszeń arbitrażowych + dmca_address: Adres fizyczny dla zgłoszeń naruszenia DMCA/praw autorskich + dmca_email: Adres e-mail dla zgłoszeń naruszenia DMCA/praw autorskich domain: Domena jurisdiction: Jurysdykcja user: From ffaf458f9938eabaa188743e187eaae21a1371b2 Mon Sep 17 00:00:00 2001 From: Claire Date: Thu, 23 Jan 2025 15:09:33 +0100 Subject: [PATCH 05/42] =?UTF-8?q?Change=20=E2=80=9CProhibited=20uses?= =?UTF-8?q?=E2=80=9D=20section=20of=20ToS=20template=20according=20to=20fe?= =?UTF-8?q?edback=20(#33703)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- config/templates/terms-of-service.md | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/config/templates/terms-of-service.md b/config/templates/terms-of-service.md index cb81a22e84327d..4b11a9897cfcc7 100644 --- a/config/templates/terms-of-service.md +++ b/config/templates/terms-of-service.md @@ -58,16 +58,18 @@ attempt to): or limit the functionality of the Instance, launch a denial of service attack, or in any other way attempt to interfere with the functioning and availability of the Instance; -- Except as may be the result of standard search engine or Internet browser - usage, use, launch, develop, or distribute any automated system, including - without limitation, any spider, robot, cheat utility, scraper, offline reader, - or any data mining or similar data gathering extraction tools to access the - Instance, or use or launch any unauthorized script or other software; +- Use, launch, develop, or distribute any automated system, including without + limitation, any spider, robot, cheat utility, scraper, offline reader, or any + data mining or similar data gathering extraction tools to access the Instance, + except in each case as may be the result of standard search engine or Internet + browser and local caching or for human review and interaction with Content on + the Instance; +- Use or launch any unauthorized script or other software; - Interfere with, disable, vandalize or disrupt the Instance or servers or networks connected to the Instance; - Hack into, penetrate, disable, or otherwise circumvent the security measures of the Instance or servers or networks connected to the Instance; -- or otherwise use the Instance in any way that violates any applicable +- Otherwise use the Instance in any way that violates any applicable national, federal, state, local or international law or regulation. ## Intellectual Property From 4b4de02feefb590f9e945a4bc712f574eb811b23 Mon Sep 17 00:00:00 2001 From: Claire Date: Thu, 23 Jan 2025 15:34:30 +0100 Subject: [PATCH 06/42] Remove broken link to Terms of Service when none are defined (#33699) --- app/views/auth/registrations/new.html.haml | 2 +- config/locales/en.yml | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/app/views/auth/registrations/new.html.haml b/app/views/auth/registrations/new.html.haml index afeeef0c6d5d66..5e9aa02d68331f 100644 --- a/app/views/auth/registrations/new.html.haml +++ b/app/views/auth/registrations/new.html.haml @@ -72,7 +72,7 @@ .fields-group = f.input :agreement, as: :boolean, - label: t('auth.user_agreement_html', privacy_policy_path: privacy_policy_path, terms_of_service_path: terms_of_service_path), + label: TermsOfService.live.exists? ? t('auth.user_agreement_html', privacy_policy_path: privacy_policy_path, terms_of_service_path: terms_of_service_path) : t('auth.user_privacy_agreement_html', privacy_policy_path: privacy_policy_path), required: false, wrapper: :with_label diff --git a/config/locales/en.yml b/config/locales/en.yml index ab76b462ee5fbb..fdf73bad9e247a 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -1209,6 +1209,7 @@ en: too_fast: Form submitted too fast, try again. use_security_key: Use security key user_agreement_html: I have read and agree to the terms of service and privacy policy + user_privacy_agreement_html: I have read and agree to the privacy policy author_attribution: example_title: Sample text hint_html: Are you writing news or blog articles outside of Mastodon? Control how you get credited when they are shared on Mastodon. From 72619517914fdfccbe7654c64923433245069f9a Mon Sep 17 00:00:00 2001 From: Claire Date: Thu, 23 Jan 2025 18:56:33 +0100 Subject: [PATCH 07/42] Fix LDSignature tests (#33705) --- .../activitypub/linked_data_signature_spec.rb | 53 ++++++++++++++++++- 1 file changed, 52 insertions(+), 1 deletion(-) diff --git a/spec/lib/activitypub/linked_data_signature_spec.rb b/spec/lib/activitypub/linked_data_signature_spec.rb index b1a8dc5c49c39b..8128fdd070b645 100644 --- a/spec/lib/activitypub/linked_data_signature_spec.rb +++ b/spec/lib/activitypub/linked_data_signature_spec.rb @@ -13,10 +13,13 @@ { '@context' => 'https://www.w3.org/ns/activitystreams', 'id' => 'http://example.com/hello-world', + 'type' => 'Note', + 'content' => 'Hello world', } end - let(:json) { raw_json.merge('signature' => signature) } + let(:signed_json) { raw_json.merge('signature' => signature) } + let(:json) { signed_json } describe '#verify_actor!' do context 'when signature matches' do @@ -90,6 +93,54 @@ expect(subject.verify_actor!).to be_nil end end + + context 'when an attribute has been removed from the document' do + let(:signature) { raw_signature.merge('type' => 'RsaSignature2017', 'signatureValue' => sign(sender, raw_signature, raw_json)) } + let(:json) { signed_json.without('content') } + + let(:raw_signature) do + { + 'creator' => 'http://example.com/alice', + 'created' => '2017-09-23T20:21:34Z', + } + end + + it 'returns nil' do + expect(subject.verify_actor!).to be_nil + end + end + + context 'when an attribute has been added to the document' do + let(:signature) { raw_signature.merge('type' => 'RsaSignature2017', 'signatureValue' => sign(sender, raw_signature, raw_json)) } + let(:json) { signed_json.merge('attributedTo' => 'http://example.com/bob') } + + let(:raw_signature) do + { + 'creator' => 'http://example.com/alice', + 'created' => '2017-09-23T20:21:34Z', + } + end + + it 'returns nil' do + expect(subject.verify_actor!).to be_nil + end + end + + context 'when an existing attribute has been changed' do + let(:signature) { raw_signature.merge('type' => 'RsaSignature2017', 'signatureValue' => sign(sender, raw_signature, raw_json)) } + let(:json) { signed_json.merge('content' => 'oops') } + + let(:raw_signature) do + { + 'creator' => 'http://example.com/alice', + 'created' => '2017-09-23T20:21:34Z', + } + end + + it 'returns nil' do + expect(subject.verify_actor!).to be_nil + end + end end describe '#sign!' do From 5c50d89a86f7f34b9a9c4e41901e4d3474710c58 Mon Sep 17 00:00:00 2001 From: Christian Schmidt Date: Fri, 24 Jan 2025 09:18:46 +0100 Subject: [PATCH 08/42] Store Bootsnap cache outside bind mounts (devcontainer only) (#33677) --- .devcontainer/compose.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/.devcontainer/compose.yaml b/.devcontainer/compose.yaml index 705d26e0ab28a0..4d5ed0f25fc5f3 100644 --- a/.devcontainer/compose.yaml +++ b/.devcontainer/compose.yaml @@ -10,6 +10,7 @@ services: RAILS_ENV: development NODE_ENV: development BIND: 0.0.0.0 + BOOTSNAP_CACHE_DIR: /tmp REDIS_HOST: redis REDIS_PORT: '6379' DB_HOST: db From e44b78413a4633bad3e9b2568e1ed01483904494 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 24 Jan 2025 10:06:25 +0100 Subject: [PATCH 09/42] New Crowdin Translations (automated) (#33711) Co-authored-by: GitHub Actions --- app/javascript/mastodon/locales/ca.json | 1 + app/javascript/mastodon/locales/da.json | 2 ++ app/javascript/mastodon/locales/de.json | 38 ++++++++++++---------- app/javascript/mastodon/locales/eo.json | 1 + app/javascript/mastodon/locales/es-AR.json | 2 ++ app/javascript/mastodon/locales/es-MX.json | 2 ++ app/javascript/mastodon/locales/es.json | 2 ++ app/javascript/mastodon/locales/eu.json | 7 ++++ app/javascript/mastodon/locales/fi.json | 2 ++ app/javascript/mastodon/locales/fo.json | 2 ++ app/javascript/mastodon/locales/fr-CA.json | 2 ++ app/javascript/mastodon/locales/fr.json | 4 ++- app/javascript/mastodon/locales/gl.json | 2 ++ app/javascript/mastodon/locales/he.json | 2 ++ app/javascript/mastodon/locales/is.json | 2 ++ app/javascript/mastodon/locales/ja.json | 7 ++++ app/javascript/mastodon/locales/nl.json | 2 ++ app/javascript/mastodon/locales/pt-PT.json | 4 ++- app/javascript/mastodon/locales/sq.json | 2 ++ app/javascript/mastodon/locales/sv.json | 2 +- app/javascript/mastodon/locales/tok.json | 24 +++++++------- app/javascript/mastodon/locales/tr.json | 2 ++ app/javascript/mastodon/locales/uk.json | 6 ++++ app/javascript/mastodon/locales/zh-TW.json | 2 ++ config/locales/ca.yml | 1 + config/locales/da.yml | 1 + config/locales/de.yml | 1 + config/locales/eo.yml | 1 + config/locales/es-AR.yml | 1 + config/locales/es-MX.yml | 1 + config/locales/es.yml | 1 + config/locales/eu.yml | 1 + config/locales/fi.yml | 1 + config/locales/fo.yml | 1 + config/locales/fr-CA.yml | 1 + config/locales/fr.yml | 1 + config/locales/gl.yml | 1 + config/locales/he.yml | 1 + config/locales/hu.yml | 1 + config/locales/is.yml | 1 + config/locales/ja.yml | 1 + config/locales/nl.yml | 1 + config/locales/pt-PT.yml | 3 +- config/locales/simple_form.pt-PT.yml | 2 +- config/locales/sq.yml | 1 + config/locales/uk.yml | 1 + config/locales/zh-TW.yml | 1 + 47 files changed, 113 insertions(+), 35 deletions(-) diff --git a/app/javascript/mastodon/locales/ca.json b/app/javascript/mastodon/locales/ca.json index 3cbc556e09c286..9ce2612b77d2f3 100644 --- a/app/javascript/mastodon/locales/ca.json +++ b/app/javascript/mastodon/locales/ca.json @@ -414,6 +414,7 @@ "ignore_notifications_modal.not_followers_title": "Voleu ignorar les notificacions de qui no us segueix?", "ignore_notifications_modal.not_following_title": "Voleu ignorar les notificacions de qui no seguiu?", "ignore_notifications_modal.private_mentions_title": "Voleu ignorar les notificacions de mencions privades no sol·licitades?", + "info_button.label": "Ajuda", "interaction_modal.action.favourite": "Per a continuar heu d'afavorir des del vostre compte.", "interaction_modal.action.follow": "Per a continuar heu de seguir des del vostre compte.", "interaction_modal.action.reblog": "Per a continuar heu d'impulsar des del vostre compte.", diff --git a/app/javascript/mastodon/locales/da.json b/app/javascript/mastodon/locales/da.json index 43539d366555ba..c40e230bfc5da4 100644 --- a/app/javascript/mastodon/locales/da.json +++ b/app/javascript/mastodon/locales/da.json @@ -414,6 +414,8 @@ "ignore_notifications_modal.not_followers_title": "Ignorér notifikationer fra folk, som ikke er følgere?", "ignore_notifications_modal.not_following_title": "Ignorér notifikationer fra folk, man ikke følger?", "ignore_notifications_modal.private_mentions_title": "Ignorér notifikationer fra uopfordrede Private omtaler?", + "info_button.label": "Hjælp", + "info_button.what_is_alt_text": "

    Hvad er alt-tekst?

    Alt-tekst leverer billedbeskrivelser til folk med synsnedsættelser, lav båndbredde-forbindelser eller med ønske om ekstra kontekst.

    Tilgængelighed og forståelse kan forbedres for alle ved at skrive klar, kortfattet og objektiv alt-tekst.

    • Fang vigtige elementer
    • Opsummér tekst i billeder
    • Brug almindelig sætningsstruktur
    • Undgå overflødig information
    • Fokusér på tendenser og centrale resultater i kompleks grafik (såsom diagrammer eller kort)
    ", "interaction_modal.action.favourite": "For at fortsætte, skal man vælge Gør til favorit fra sin konto.", "interaction_modal.action.follow": "For at fortsætte, skal man vælge Følg fra sin konto.", "interaction_modal.action.reblog": "For at fortsætte, skal man vælge Genblog fra sin konto.", diff --git a/app/javascript/mastodon/locales/de.json b/app/javascript/mastodon/locales/de.json index a90843fa146619..1032271fc92b31 100644 --- a/app/javascript/mastodon/locales/de.json +++ b/app/javascript/mastodon/locales/de.json @@ -3,8 +3,8 @@ "about.contact": "Kontakt:", "about.disclaimer": "Mastodon ist eine freie, quelloffene Software und eine Marke der Mastodon gGmbH.", "about.domain_blocks.no_reason_available": "Grund unbekannt", - "about.domain_blocks.preamble": "Mastodon erlaubt es dir grundsätzlich, Inhalte von allen Nutzer*innen auf allen Servern im Fediversum zu sehen und mit ihnen zu interagieren. Für diesen Server gibt es aber ein paar Ausnahmen.", - "about.domain_blocks.silenced.explanation": "Alle Inhalte und Profile dieses Servers werden zunächst nicht angezeigt. Du kannst die Profile und Inhalte aber dennoch sehen, wenn du explizit nach diesen suchst oder diesen folgst.", + "about.domain_blocks.preamble": "Mastodon erlaubt es dir grundsätzlich, alle Inhalte von allen Nutzer*innen auf allen Servern im Fediverse zu sehen und mit ihnen zu interagieren. Für diesen Server gibt es aber ein paar Ausnahmen.", + "about.domain_blocks.silenced.explanation": "Standardmäßig werden von diesem Server keine Inhalte oder Profile angezeigt. Du kannst die Profile und Inhalte aber dennoch sehen, wenn du explizit nach diesen suchst oder diesen folgst.", "about.domain_blocks.silenced.title": "Stummgeschaltet", "about.domain_blocks.suspended.explanation": "Es werden keine Daten von diesem Server verarbeitet, gespeichert oder ausgetauscht, sodass eine Interaktion oder Kommunikation mit Nutzer*innen dieses Servers nicht möglich ist.", "about.domain_blocks.suspended.title": "Gesperrt", @@ -19,7 +19,7 @@ "account.block_domain": "{domain} sperren", "account.block_short": "Blockieren", "account.blocked": "Blockiert", - "account.cancel_follow_request": "Abo-Anfrage verwerfen", + "account.cancel_follow_request": "Follower-Anfrage zurückziehen", "account.copy": "Link zum Profil kopieren", "account.direct": "@{name} privat erwähnen", "account.disable_notifications": "Höre auf mich zu benachrichtigen wenn @{name} etwas postet", @@ -72,12 +72,12 @@ "account.unmute_notifications_short": "Stummschaltung der Benachrichtigungen aufheben", "account.unmute_short": "Stummschaltung aufheben", "account_note.placeholder": "Klicken, um Notiz hinzuzufügen", - "admin.dashboard.daily_retention": "Verweildauer der Nutzer im Tagesdurchschnitt seit Registrierung", - "admin.dashboard.monthly_retention": "Verweildauer der Nutzer im Monatsdurchschnitt seit Registrierung", + "admin.dashboard.daily_retention": "Verweildauer der Nutzer*innen pro Tag nach der Registrierung", + "admin.dashboard.monthly_retention": "Verweildauer der Nutzer*innen pro Monat nach der Registrierung", "admin.dashboard.retention.average": "Durchschnitt", "admin.dashboard.retention.cohort": "Monat der Registrierung", "admin.dashboard.retention.cohort_size": "Neue Konten", - "admin.impact_report.instance_accounts": "Kontenprofile, die dadurch gelöscht würden", + "admin.impact_report.instance_accounts": "Profilkonten, die dadurch gelöscht würden", "admin.impact_report.instance_followers": "Follower, die unsere Nutzer*innen verlieren würden", "admin.impact_report.instance_follows": "Follower, die deren Nutzer*innen verlieren würden", "admin.impact_report.title": "Zusammenfassung der Auswirkung", @@ -89,30 +89,30 @@ "alt_text_modal.add_alt_text": "Bildbeschreibung hinzufügen", "alt_text_modal.add_text_from_image": "Text aus Bild hinzufügen", "alt_text_modal.cancel": "Abbrechen", - "alt_text_modal.change_thumbnail": "Titelbild ändern", - "alt_text_modal.describe_for_people_with_hearing_impairments": "Beschreibung für Blinde und Sehbehinderte...", - "alt_text_modal.describe_for_people_with_visual_impairments": "Beschreibung für Blinde und Sehbehinderte", + "alt_text_modal.change_thumbnail": "Vorschaubild ändern", + "alt_text_modal.describe_for_people_with_hearing_impairments": "Beschreibe den Inhalt für Menschen mit Schwerhörigkeit …", + "alt_text_modal.describe_for_people_with_visual_impairments": "Beschreibe den Inhalt für Menschen mit Sehschwäche …", "alt_text_modal.done": "Fertig", "announcement.announcement": "Ankündigung", "annual_report.summary.archetype.booster": "Trendjäger*in", "annual_report.summary.archetype.lurker": "Beobachter*in", - "annual_report.summary.archetype.oracle": "Wandelndes Lexikon", + "annual_report.summary.archetype.oracle": "Universaltalent", "annual_report.summary.archetype.pollster": "Meinungsforscher*in", - "annual_report.summary.archetype.replier": "Sozialakrobat", - "annual_report.summary.followers.followers": "Abonnenten", + "annual_report.summary.archetype.replier": "Sozialer Schmetterling", + "annual_report.summary.followers.followers": "Follower", "annual_report.summary.followers.total": "{count} insgesamt", "annual_report.summary.here_it_is": "Dein Jahresrückblick für {year}:", - "annual_report.summary.highlighted_post.by_favourites": "Am häufigsten favorisierter Beitrag", - "annual_report.summary.highlighted_post.by_reblogs": "Am häufigsten geteilter Beitrag", + "annual_report.summary.highlighted_post.by_favourites": "am häufigsten favorisierter Beitrag", + "annual_report.summary.highlighted_post.by_reblogs": "am häufigsten geteilter Beitrag", "annual_report.summary.highlighted_post.by_replies": "Beitrag mit den meisten Antworten", "annual_report.summary.highlighted_post.possessive": "{name}", - "annual_report.summary.most_used_app.most_used_app": "Am häufigsten verwendete App", - "annual_report.summary.most_used_hashtag.most_used_hashtag": "Am häufigsten verwendeter Hashtag", + "annual_report.summary.most_used_app.most_used_app": "am häufigsten verwendete App", + "annual_report.summary.most_used_hashtag.most_used_hashtag": "am häufigsten verwendeter Hashtag", "annual_report.summary.most_used_hashtag.none": "Keiner", - "annual_report.summary.new_posts.new_posts": "Neue Beiträge", + "annual_report.summary.new_posts.new_posts": "neue Beiträge", "annual_report.summary.percentile.text": "Damit gehörst du zu den oberstender Nutzer*innen auf {domain}.", "annual_report.summary.percentile.we_wont_tell_bernie": "Wir werden Bernie nichts verraten.", - "annual_report.summary.thanks": "Vielen Dank, dass du Teil von Mastodon bist!", + "annual_report.summary.thanks": "Danke, dass du Teil von Mastodon bist!", "attachments_list.unprocessed": "(ausstehend)", "audio.hide": "Audio ausblenden", "block_modal.remote_users_caveat": "Wir werden den Server {domain} bitten, deine Entscheidung zu respektieren. Allerdings kann nicht garantiert werden, dass sie eingehalten wird, weil einige Server Blockierungen unterschiedlich handhaben können. Öffentliche Beiträge können für nicht angemeldete Nutzer*innen weiterhin sichtbar sein.", @@ -414,6 +414,8 @@ "ignore_notifications_modal.not_followers_title": "Benachrichtigungen von Profilen ignorieren, die dir nicht folgen?", "ignore_notifications_modal.not_following_title": "Benachrichtigungen von Profilen ignorieren, denen du nicht folgst?", "ignore_notifications_modal.private_mentions_title": "Benachrichtigungen von unerwünschten privaten Erwähnungen ignorieren?", + "info_button.label": "Hilfe", + "info_button.what_is_alt_text": "

    Was ist Alt-Text?

    Alt-Text bietet Bildbeschreibungen für Personen mit einer Sehschwäche, einer schlechten Internetverbindung und für alle, die zusätzlichen Kontext möchten.

    Du kannst die Zugänglichkeit und die Verständlichkeit für alle verbessern, indem du eine klare, genaue und objektive Bildbeschreibung hinzufügst.

    • Erfasse wichtige Elemente
    • Fasse Text in Bildern zusammen
    • Verwende einen korrekten Satzbau
    • Vermeide unwichtige Informationen
    • Konzentriere dich bei komplexen Darstellungen (z. B. Diagramme oder Karten) auf Trends und wichtige Erkenntnisse
    ", "interaction_modal.action.favourite": "Du musst von deinem Konto aus favorisieren, um fortzufahren.", "interaction_modal.action.follow": "Du musst von deinem Konto aus folgen, um fortzufahren.", "interaction_modal.action.reblog": "Du musst von deinem Konto aus teilen, um fortzufahren.", diff --git a/app/javascript/mastodon/locales/eo.json b/app/javascript/mastodon/locales/eo.json index 9a38b6fc618f04..3133b0fa40b0a9 100644 --- a/app/javascript/mastodon/locales/eo.json +++ b/app/javascript/mastodon/locales/eo.json @@ -414,6 +414,7 @@ "ignore_notifications_modal.not_followers_title": "Ĉu ignori sciigojn de homoj, kiuj ne sekvas vin?", "ignore_notifications_modal.not_following_title": "Ĉu ignori sciigojn de homoj, kiujn vi ne sekvas?", "ignore_notifications_modal.private_mentions_title": "Ĉu ignori sciigojn de nepetitaj privataj mencioj?", + "info_button.label": "Helpo", "interaction_modal.action.favourite": "Por daŭrigi, vi devas stelumi el via konto.", "interaction_modal.action.follow": "Por daŭrigi, vi devas sekvi el via konto.", "interaction_modal.action.reblog": "Por daŭrigi, vi devas diskonigi el via konto.", diff --git a/app/javascript/mastodon/locales/es-AR.json b/app/javascript/mastodon/locales/es-AR.json index e56ca403d99b00..a399b91a6ff997 100644 --- a/app/javascript/mastodon/locales/es-AR.json +++ b/app/javascript/mastodon/locales/es-AR.json @@ -414,6 +414,8 @@ "ignore_notifications_modal.not_followers_title": "¿Ignorar notificaciones de cuentas que no te siguen?", "ignore_notifications_modal.not_following_title": "¿Ignorar notificaciones de cuentas a las que no seguís?", "ignore_notifications_modal.private_mentions_title": "¿Ignorar notificaciones de menciones privadas no solicitadas?", + "info_button.label": "Ayuda", + "info_button.what_is_alt_text": "

    ¿Qué es el texto alternativo?

    El texto alternativo proporciona descripciones de las imágenes para personas con problemas de visión, conexiones con poco ancho de banda o que buscan un contexto adicional.

    Puedes mejorar la accesibilidad y la comprensión para todos escribiendo un texto alternativo claro, conciso y objetivo.

    • Captura los elementos importantes.
    • Resume el texto en imágenes.
    • Usa una estructura de frases normal.
    • Evita la información redundante.
    • Céntrate en las tendencias y conclusiones clave de los elementos visuales complejos (como diagramas o mapas).
    ", "interaction_modal.action.favourite": "Para continuar, tenés que marcar como favorito desde tu cuenta.", "interaction_modal.action.follow": "Para continuar, tenés que seguir desde tu cuenta.", "interaction_modal.action.reblog": "Para continuar, tenés que adherir desde tu cuenta.", diff --git a/app/javascript/mastodon/locales/es-MX.json b/app/javascript/mastodon/locales/es-MX.json index 428153e5b148b7..27b5565992c1b3 100644 --- a/app/javascript/mastodon/locales/es-MX.json +++ b/app/javascript/mastodon/locales/es-MX.json @@ -414,6 +414,8 @@ "ignore_notifications_modal.not_followers_title": "¿Ignorar notificaciones de personas que no te siguen?", "ignore_notifications_modal.not_following_title": "¿Ignorar notificaciones de personas a las que no sigues?", "ignore_notifications_modal.private_mentions_title": "¿Ignorar notificaciones de menciones privadas no solicitadas?", + "info_button.label": "Ayuda", + "info_button.what_is_alt_text": "

    ¿Qué es el texto alternativo?

    El texto alternativo proporciona descripciones de las imágenes para personas con problemas de visión, conexiones con poco ancho de banda o que buscan un contexto adicional.

    Puedes mejorar la accesibilidad y la comprensión para todos escribiendo un texto alternativo claro, conciso y objetivo.

    • Captura los elementos importantes.
    • Resume el texto en imágenes.
    • Usa una estructura de frases normal.
    • Evita la información redundante.
    • Céntrate en las tendencias y conclusiones clave de los elementos visuales complejos (como diagramas o mapas).
    ", "interaction_modal.action.favourite": "Para continuar, debes marcar como favorito desde tu cuenta.", "interaction_modal.action.follow": "Para continuar, debes seguir desde tu cuenta.", "interaction_modal.action.reblog": "Para continuar, debes impulsar desde tu cuenta.", diff --git a/app/javascript/mastodon/locales/es.json b/app/javascript/mastodon/locales/es.json index e014f967903d37..ba903ceaa72421 100644 --- a/app/javascript/mastodon/locales/es.json +++ b/app/javascript/mastodon/locales/es.json @@ -414,6 +414,8 @@ "ignore_notifications_modal.not_followers_title": "¿Ignorar notificaciones de personas que no te siguen?", "ignore_notifications_modal.not_following_title": "¿Ignorar notificaciones de personas a las que no sigues?", "ignore_notifications_modal.private_mentions_title": "¿Ignorar notificaciones de menciones privadas no solicitadas?", + "info_button.label": "Ayuda", + "info_button.what_is_alt_text": "

    ¿Qué es el texto alternativo?

    El texto alternativo proporciona descripciones de las imágenes para personas con problemas de visión, conexiones con poco ancho de banda o que buscan un contexto adicional.

    Puedes mejorar la accesibilidad y la comprensión para todos escribiendo un texto alternativo claro, conciso y objetivo.

    • Captura los elementos importantes.
    • Resume el texto en imágenes.
    • Usa una estructura de frases normal.
    • Evita la información redundante.
    • Céntrate en las tendencias y conclusiones clave de los elementos visuales complejos (como diagramas o mapas).
    ", "interaction_modal.action.favourite": "Para continuar, tienes que marcar como favorito desde tu cuenta.", "interaction_modal.action.follow": "Para continuar, tienes que seguir desde tu cuenta.", "interaction_modal.action.reblog": "Para continuar, tienes que impulsar desde tu cuenta.", diff --git a/app/javascript/mastodon/locales/eu.json b/app/javascript/mastodon/locales/eu.json index f201baa2897cdd..1341bb17f3872d 100644 --- a/app/javascript/mastodon/locales/eu.json +++ b/app/javascript/mastodon/locales/eu.json @@ -86,12 +86,18 @@ "alert.unexpected.message": "Ustekabeko errore bat gertatu da.", "alert.unexpected.title": "Ene!", "alt_text_badge.title": "Testu alternatiboa", + "alt_text_modal.add_alt_text": "Gehitu ordezko testua", + "alt_text_modal.add_text_from_image": "Gehitu testua iruditik", + "alt_text_modal.cancel": "Utzi", + "alt_text_modal.change_thumbnail": "Aldatu koadro txikia", + "alt_text_modal.done": "Egina", "announcement.announcement": "Iragarpena", "annual_report.summary.followers.followers": "jarraitzaileak", "annual_report.summary.followers.total": "{count} guztira", "annual_report.summary.highlighted_post.by_favourites": "egindako bidalketa gogokoena", "annual_report.summary.highlighted_post.by_reblogs": "egindako bidalketa zabalduena", "annual_report.summary.highlighted_post.by_replies": "erantzun gehien izan dituen bidalketa", + "annual_report.summary.highlighted_post.possessive": "{name}-(r)ena", "annual_report.summary.most_used_app.most_used_app": "app erabiliena", "annual_report.summary.most_used_hashtag.most_used_hashtag": "traola erabiliena", "annual_report.summary.most_used_hashtag.none": "Bat ere ez", @@ -120,6 +126,7 @@ "bundle_column_error.routing.body": "Eskatutako orria ezin izan da aurkitu. Ziur helbide-barrako URLa zuzena dela?", "bundle_column_error.routing.title": "404", "bundle_modal_error.close": "Itxi", + "bundle_modal_error.message": "Zerbait okerra gertatu da pantaila hau kargatzean.", "bundle_modal_error.retry": "Saiatu berriro", "closed_registrations.other_server_instructions": "Mastodon deszentralizatua denez, beste kontu bat sortu dezakezu beste zerbitzari batean eta honekin komunikatu.", "closed_registrations_modal.description": "Une honetan ezin da konturik sortu {domain} zerbitzarian, baina kontuan izan Mastodon erabiltzeko ez duzula zertan konturik izan zehazki {domain} zerbitzarian.", diff --git a/app/javascript/mastodon/locales/fi.json b/app/javascript/mastodon/locales/fi.json index 36954e4c541c79..2b1929a3132665 100644 --- a/app/javascript/mastodon/locales/fi.json +++ b/app/javascript/mastodon/locales/fi.json @@ -414,6 +414,8 @@ "ignore_notifications_modal.not_followers_title": "Sivuutetaanko ilmoitukset käyttäjiltä, jotka eivät seuraa sinua?", "ignore_notifications_modal.not_following_title": "Sivuutetaanko ilmoitukset käyttäjiltä, joita et seuraa?", "ignore_notifications_modal.private_mentions_title": "Sivuutetaanko ilmoitukset pyytämättömistä yksityismaininnoista?", + "info_button.label": "Ohje", + "info_button.what_is_alt_text": "

    Mikä vaihtoehtoinen teksti on?

    Vaihtoehtoinen teksti tarjoaa kuvauksen kuvista ihmisille, joilla on näkövamma tai matalan kaistanleveyden yhteys tai jotka kaipaavat lisäkontekstia.

    Voit parantaa saavutettavuutta ja ymmärrettävyyttä kaikkien näkökulmasta kirjoittamalla selkeän, tiiviin ja objektiivisen vaihtoehtoisen tekstin.

    • Ota mukaan tärkeät elementit
    • Tiivistä kuvissa oleva teksti
    • Käytä tavallisia lauserakenteita
    • Vältä turhaa tietoa
    • Keskity trendeihin ja keskeisiin tuloksiin monimutkaisissa visuaalisissa esityksissä (kuten kaavioissa tai kartoissa)
    ", "interaction_modal.action.favourite": "Jotta voit jatkaa, sinun tulee lisätä julkaisu suosikiksesi omalta tililtäsi.", "interaction_modal.action.follow": "Jotta voit jatkaa, sinun tulee seurata käyttäjää omalta tililtäsi.", "interaction_modal.action.reblog": "Jotta voit jatkaa, sinun tulee uudelleenjulkaista omalta tililtäsi.", diff --git a/app/javascript/mastodon/locales/fo.json b/app/javascript/mastodon/locales/fo.json index 7530ffcc6d73d5..42677ebe56dd6b 100644 --- a/app/javascript/mastodon/locales/fo.json +++ b/app/javascript/mastodon/locales/fo.json @@ -414,6 +414,8 @@ "ignore_notifications_modal.not_followers_title": "Lat sum um tú ikki sær fráboðanir frá fólki, sum ikki fylgja tær?", "ignore_notifications_modal.not_following_title": "Lat sum um tú ikki sær fráboðanir frá fólki, sum tú ikki fylgir?", "ignore_notifications_modal.private_mentions_title": "Lat sum um tú ikki sær fráboðanir frá óbiðnum privatum umrøðum?", + "info_button.label": "Hjálp", + "info_button.what_is_alt_text": "

    Hvat er alt tekstur?

    Alt tekstur lýsir myndir fyri fólki, sum síggja illa, ella sum hava ringt net samband ella tey, sum vilja vita meira um samanhangin.

    Tú kanst bøta um atkomuna og fatanina hjá øllum við at skriva kláran, stuttan og objektivan alt tekst.

    • Fanga týdningarmikil element
    • Samanfata tekst í myndum
    • Brúka reglubundnan setningsbygnað
    • Lat vera við at siga ting upp í saman
    • Fokusera á rák og høvuðsúrslit í kompleksum myndum (sosum diagrammir og kort)
    ", "interaction_modal.action.favourite": "Fyri at halda fram, so mást tú yndismerkja frá tínari kontu.", "interaction_modal.action.follow": "Fyri at halda fram, mást tú fylgja frá tínari kontu.", "interaction_modal.action.reblog": "Fyri at halda fram, mást tú endurblogga frá tínari kontu.", diff --git a/app/javascript/mastodon/locales/fr-CA.json b/app/javascript/mastodon/locales/fr-CA.json index 3f72cc9e07cb66..2fddca9f1688b7 100644 --- a/app/javascript/mastodon/locales/fr-CA.json +++ b/app/javascript/mastodon/locales/fr-CA.json @@ -414,6 +414,8 @@ "ignore_notifications_modal.not_followers_title": "Ignorer les notifications provenant des personnes qui ne vous suivent pas ?", "ignore_notifications_modal.not_following_title": "Ignorer les notifications provenant des personnes que vous ne suivez pas ?", "ignore_notifications_modal.private_mentions_title": "Ignorer les notifications issues des mentions privées non sollicitées ?", + "info_button.label": "Aide", + "info_button.what_is_alt_text": "

    Qu'est-ce que le texte alternatif ?

    Un texte alternatif fournit une description de l'image aux personnes avec un handicap visuel ou une connexion limitée ou qui souhaitent avoir un contexte supplémentaire.

    Vous pouvez améliorer l'accessibilité et la compression de tout le monde en écrivant un texte alternatif clair, concis et objectif.

    • Identifiez les éléments importants
    • Résumez le texte présent à l'image
    • Utilisez une structure de phrase normale
    • Évitez les informations redondantes
    • Pour les visuels complexes (tels que les diagrammes ou les cartes), indiquez les tendances ou points-clés
    ", "interaction_modal.action.favourite": "Pour continuer, vous devez ajouter en favori depuis votre compte.", "interaction_modal.action.follow": "Pour continuer, vous devez suivre depuis votre compte.", "interaction_modal.action.reblog": "Pour continuer, vous devez booster depuis votre compte.", diff --git a/app/javascript/mastodon/locales/fr.json b/app/javascript/mastodon/locales/fr.json index 1de6672353766a..1660132fedb8b4 100644 --- a/app/javascript/mastodon/locales/fr.json +++ b/app/javascript/mastodon/locales/fr.json @@ -414,6 +414,8 @@ "ignore_notifications_modal.not_followers_title": "Ignorer les notifications provenant des personnes qui ne vous suivent pas ?", "ignore_notifications_modal.not_following_title": "Ignorer les notifications provenant des personnes que vous ne suivez pas ?", "ignore_notifications_modal.private_mentions_title": "Ignorer les notifications issues des mentions privées non sollicitées ?", + "info_button.label": "Aide", + "info_button.what_is_alt_text": "

    Qu'est-ce que le texte alternatif ?

    Un texte alternatif fournit une description de l'image aux personnes avec un handicap visuel ou une connexion limitée ou qui souhaitent avoir un contexte supplémentaire.

    Vous pouvez améliorer l'accessibilité et la compression de tout le monde en écrivant un texte alternatif clair, concis et objectif.

    • Identifiez les éléments importants
    • Résumez le texte présent à l'image
    • Utilisez une structure de phrase normale
    • Évitez les informations redondantes
    • Pour les visuels complexes (tels que les diagrammes ou les cartes), indiquez les tendances ou points-clés
    ", "interaction_modal.action.favourite": "Pour continuer, vous devez ajouter en favori depuis votre compte.", "interaction_modal.action.follow": "Pour continuer, vous devez suivre depuis votre compte.", "interaction_modal.action.reblog": "Pour continuer, vous devez booster depuis votre compte.", @@ -549,7 +551,7 @@ "notification.admin.report_account_other": "{name} a signalé {count, plural, one {un message} other {# messages}} depuis {target}", "notification.admin.report_statuses": "{name} a signalé {target} pour {category}", "notification.admin.report_statuses_other": "{name} a signalé {target}", - "notification.admin.sign_up": "{name} s'est inscrit", + "notification.admin.sign_up": "{name} s'est inscrit·e", "notification.admin.sign_up.name_and_others": "{name} et {count, plural, one {# autre} other {# autres}} se sont inscrit", "notification.annual_report.message": "Votre {year} #Wrapstodon attend ! Dévoilez les moments forts et mémorables de votre année sur Mastodon !", "notification.annual_report.view": "Voir #Wrapstodon", diff --git a/app/javascript/mastodon/locales/gl.json b/app/javascript/mastodon/locales/gl.json index 700815db49b244..87c8e939ee8125 100644 --- a/app/javascript/mastodon/locales/gl.json +++ b/app/javascript/mastodon/locales/gl.json @@ -414,6 +414,8 @@ "ignore_notifications_modal.not_followers_title": "Ignorar notificacións de persoas que non te seguen?", "ignore_notifications_modal.not_following_title": "Ignorar notificacións de persoas que non segues?", "ignore_notifications_modal.private_mentions_title": "Ignorar notificacións de Mencións Privadas non solicitadas?", + "info_button.label": "Axuda", + "info_button.what_is_alt_text": "

    Que é o Texto Alternativo?

    O Text Alt proporciona a descrición das imaxes para as persoas con deficiencias visuais, conexións a internet de baixa calidade ou para engadir contexto ás mesmas.

    Podes mellorar a accesibilidade e a comprensión da publicación ao escribir un texto alternativo claro, conciso e obxectivo.

    • Identifica os elementos importantes
    • Inclúe o texto que apareza nas imaxes
    • Utiliza sintaxe estándar nas frases
    • Evita información redundante
    • Céntrate nos elementos principais cando sexan imaxes complexas (como diagramas ou mapas)
    ", "interaction_modal.action.favourite": "Para continuar, debes favorecer desde a túa conta.", "interaction_modal.action.follow": "Para continuar, debes facer seguimento desde a túa conta.", "interaction_modal.action.reblog": "Para continuar, debes promover desde a túa conta.", diff --git a/app/javascript/mastodon/locales/he.json b/app/javascript/mastodon/locales/he.json index 5b43bd0b847827..22481cfe5bc7f4 100644 --- a/app/javascript/mastodon/locales/he.json +++ b/app/javascript/mastodon/locales/he.json @@ -414,6 +414,8 @@ "ignore_notifications_modal.not_followers_title": "להתעלם מהתראות מא.נשים שאינם עוקביך?", "ignore_notifications_modal.not_following_title": "להתעלם מהתראות מא.נשים שאינם נעקביך?", "ignore_notifications_modal.private_mentions_title": "להתעלם מהתראות מאיזכורים פרטיים?", + "info_button.label": "עזרה", + "info_button.what_is_alt_text": "

    מהו כיתוב חלופי?

    כיתוב חלופי משמש תיאור מילולי של תמונות לסובלים ממגבלות ראיה, חיבורי רשת איטיים, או אלו הצריכים הקשר יותר מפורט לתוכן המולטימדיה המצורף.

    ניתן לשפר את הנגישות והבנת התוכן לכולם ע\"י כתיבת תיאור ברור, תמציתי ונטול פניות.

    • כיסוי היסודות החשובים
    • סיכום המלל שבתמונות
    • שימוש במבנה משפטים רגיל
    • יש להמנע מחזרה על מידע
    • אם העזרים הויזואליים הם דיאגרמות או מפות, התמקדו במגמות וממצאים מרכזיים.
    ", "interaction_modal.action.favourite": "כדי להמשיך, עליך לחבב מחשבונך.", "interaction_modal.action.follow": "כדי להמשיך, עליך לעקוב מחשבונך.", "interaction_modal.action.reblog": "כדי להמשיך, עליך להדהד מחשבונך.", diff --git a/app/javascript/mastodon/locales/is.json b/app/javascript/mastodon/locales/is.json index 148b6237e22662..743c4cad828b43 100644 --- a/app/javascript/mastodon/locales/is.json +++ b/app/javascript/mastodon/locales/is.json @@ -414,6 +414,8 @@ "ignore_notifications_modal.not_followers_title": "Hunsa tilkynningar frá fólki sem fylgist ekki með þér?", "ignore_notifications_modal.not_following_title": "Hunsa tilkynningar frá fólki sem þú fylgist ekki með?", "ignore_notifications_modal.private_mentions_title": "Hunsa tilkynningar frá óumbeðnum tilvísunum í einkaspjalli?", + "info_button.label": "Hjálp", + "info_button.what_is_alt_text": "

    Hvað er alt-texti?

    Hjálpartexti eða ALT-myndatexti inniheldur lýsingu á myndefni fyrir fólk með ýmsar gerðir sjónskerðingar, fyrir tengingar með litla bandbreidd, eða til að gefa nánara samhengi fyrir myndefni.

    Þú getur með þessu bætt almennt aðgengi og aukið skilning á efni sem þú birtir með því að skrifa skýran, skorinortan og hlutlægan alt-texta til vara.

    • Lýstu mikilvægum atriðum
    • \\n
    • Hafðu yfirlit með þeim texta sem sést í myndum
    • Notaðu eðlilega setningaskipan
    • Forðastu óþarfar upplýsingar
    • Leggðu áherslu á aðalatriði í flóknu myndefni (eins og línuritum eða landakortum)
    ", "interaction_modal.action.favourite": "Til að halda áfram þarftu að setja eitthvað í eftirlæti, verandi inni á aðgangnum þínum.", "interaction_modal.action.follow": "Til að halda áfram þarftu að fylgjast með einhverjum, verandi inni á aðgangnum þínum.", "interaction_modal.action.reblog": "Til að halda áfram þarftu að endurbirta frá einhverjum, verandi inni á aðgangnum þínum.", diff --git a/app/javascript/mastodon/locales/ja.json b/app/javascript/mastodon/locales/ja.json index ff41d870479c56..0c9b4a6062b0e7 100644 --- a/app/javascript/mastodon/locales/ja.json +++ b/app/javascript/mastodon/locales/ja.json @@ -86,6 +86,10 @@ "alert.unexpected.message": "不明なエラーが発生しました。", "alert.unexpected.title": "エラー!", "alt_text_badge.title": "代替テキスト", + "alt_text_modal.add_alt_text": "代替テキストを追加", + "alt_text_modal.cancel": "キャンセル", + "alt_text_modal.change_thumbnail": "サムネイルを変更", + "alt_text_modal.done": "完了", "announcement.announcement": "お知らせ", "annual_report.summary.archetype.booster": "トレンドハンター", "annual_report.summary.archetype.lurker": "ROM専", @@ -407,6 +411,8 @@ "ignore_notifications_modal.not_followers_title": "本当に「フォローされていないアカウントからの通知」を無視するようにしますか?", "ignore_notifications_modal.not_following_title": "本当に「フォローしていないアカウントからの通知」を無視するようにしますか?", "ignore_notifications_modal.private_mentions_title": "本当に「外部からの非公開の返信」を無視するようにしますか?", + "info_button.label": "ヘルプ", + "info_button.what_is_alt_text": "

    代替テキストとは何ですか?

    代替テキストは、視覚障害、低速ネットワーク接続の人や追加コンテンツを求める人に役立つ画像説明です。

    明確、簡潔、客観的に記述することでアクセシビリティが向上し、より多くの人に理解されるようになります。

    • 要点をとらえる
    • 画像内のテキストを要約する
    • 平易な文章で説明する
    • 情報の重複を避ける
    • 複雑な内容 (図や地図など) では傾向やポイントを見つける
    ", "interaction_modal.action.favourite": "お気に入り登録はあなたのアカウントがあるサーバーで行う必要があります。", "interaction_modal.action.follow": "ユーザーをフォローするには、あなたのアカウントがあるサーバーからフォローする必要があります。", "interaction_modal.action.reblog": "投稿をブーストするには、あなたのアカウントがあるサーバーでブーストする必要があります。", @@ -836,6 +842,7 @@ "status.reblogs.empty": "まだ誰もブーストしていません。ブーストされるとここに表示されます。", "status.redraft": "削除して下書きに戻す", "status.remove_bookmark": "ブックマークを削除", + "status.remove_favourite": "お気に入りから削除", "status.replied_in_thread": "ほかのユーザーへ", "status.replied_to": "{name}さんへの返信", "status.reply": "返信", diff --git a/app/javascript/mastodon/locales/nl.json b/app/javascript/mastodon/locales/nl.json index d97ce0279857dc..817160a0322d74 100644 --- a/app/javascript/mastodon/locales/nl.json +++ b/app/javascript/mastodon/locales/nl.json @@ -414,6 +414,8 @@ "ignore_notifications_modal.not_followers_title": "Meldingen negeren van mensen die jou niet volgen?", "ignore_notifications_modal.not_following_title": "Meldingen negeren van mensen die je niet volgt?", "ignore_notifications_modal.private_mentions_title": "Meldingen negeren van ongevraagde privéberichten?", + "info_button.label": "Help", + "info_button.what_is_alt_text": "

    Wat is alt-tekst?

    Alt-tekst biedt beschrijvingen van afbeeldingen voor mensen met een visuele beperking, voor verbindingen met lage internetsnelheid of mensen die op zoek zijn naar extra context.

    Je kunt de toegankelijkheid en de begrijpelijkheid voor iedereen verbeteren door heldere, beknopte en objectieve alt-teksten te schrijven.

    • Leg belangrijke elementen vast
    • Tekst in afbeeldingen samenvatten
    • Een eenvoudige zinsbouw gebruiken
    • Overbodige informatie vermijden
    • Voor complexe diagrammen of kaarten alleen op trends en belangrijke bevindingen focussen
    ", "interaction_modal.action.favourite": "Om verder te gaan, moet je vanaf je eigen account als favoriet markeren.", "interaction_modal.action.follow": "Om verder te gaan, moet je vanaf je eigen account volgen.", "interaction_modal.action.reblog": "Om verder te gaan, moet je vanaf je eigen account boosten.", diff --git a/app/javascript/mastodon/locales/pt-PT.json b/app/javascript/mastodon/locales/pt-PT.json index f9cd9dfcc1fe1e..48ae395481f76e 100644 --- a/app/javascript/mastodon/locales/pt-PT.json +++ b/app/javascript/mastodon/locales/pt-PT.json @@ -414,9 +414,11 @@ "ignore_notifications_modal.not_followers_title": "Ignorar notificações de pessoas que não te seguem?", "ignore_notifications_modal.not_following_title": "Ignorar notificações de pessoas que não segues?", "ignore_notifications_modal.private_mentions_title": "Ignorar notificações de menções privadas não solicitadas?", + "info_button.label": "Ajuda", + "info_button.what_is_alt_text": "

    O que é texto alternativo?

    O texto alternativo fornece descrições de imagens para pessoas com deficiências visuais, conexões de baixa largura de banda ou pessoas que procuram um contexto adicional.

    Podes melhorar a acessibilidade e a compreensão para todos escrevendo um texto alternativo claro, conciso e objetivo.

    • Capta elementos importantes
    • Resume o texto que aparece nas imagens
    • Usa uma estrutura de frase regular
    • Evita informações redundantes
    • Centra-te nas tendências e nas principais conclusões em imagens complexas (como diagramas ou mapas)
    ", "interaction_modal.action.favourite": "Para continuar, tens de adicionar um favorito na tua conta.", "interaction_modal.action.follow": "Para continuar, tens de seguir alguém na tua conta.", - "interaction_modal.action.reblog": "Para continuar, tens de fazer uma republicação na tua conta.", + "interaction_modal.action.reblog": "Para continuar, tens de impulsionar desde a tua conta.", "interaction_modal.action.reply": "Para continuar, tens de fazer uma resposta na tua conta.", "interaction_modal.action.vote": "Para continuar é necessário votar a partir da tua conta.", "interaction_modal.go": "Ir", diff --git a/app/javascript/mastodon/locales/sq.json b/app/javascript/mastodon/locales/sq.json index 1148254a4dbfc8..68b774336e6751 100644 --- a/app/javascript/mastodon/locales/sq.json +++ b/app/javascript/mastodon/locales/sq.json @@ -409,6 +409,8 @@ "ignore_notifications_modal.not_followers_title": "Të shpërfillen njoftime nga persona që s’ju ndjekin?", "ignore_notifications_modal.not_following_title": "Të shpërfillen njoftime nga persona që s’i ndiqni?", "ignore_notifications_modal.private_mentions_title": "Të shpërfillen njoftime nga Përmendje Private të pakërkuara?", + "info_button.label": "Ndihmë", + "info_button.what_is_alt_text": "

    Ç’është teksti alternativ?

    Teksti alternativ jep përshkrime figurash për persona me mangësi në të parët, lidhje me gjerësi bande të ulët, ose për ata që duan kontekst shtesë.

    Mund të përmirësoni përdorimin nga persona me aftësi të kufizuara dhe kuptimin për këto, duke shkruar tekst alternativ të qartë, konciz dhe objektiv.

    • Rrokni elementët e rëndësishëm
    • Përmblidhni tekst në figura
    • Përdorni strukturë të rregullt fjalish
    • Shmangni përsëritje informacioni
    • Në aspekte pamore të ndërlikuara (fjala vjen, diagrame ose harta) përqendrohuni te prirje dhe gjetje gjërash kyçe
    ", "interaction_modal.action.favourite": "Që të vazhdoni, lypset t’i vini shenjë si i parapëlqyer që nga llogaria juaj.", "interaction_modal.action.follow": "Që të vazhdoni, lypset ta ndiqni që nga llogaria juaj.", "interaction_modal.action.reblog": "Që të vazhdoni, lypset ta riblogoni që nga llogaria juaj.", diff --git a/app/javascript/mastodon/locales/sv.json b/app/javascript/mastodon/locales/sv.json index 52993740c55abb..da6a49b75ad73e 100644 --- a/app/javascript/mastodon/locales/sv.json +++ b/app/javascript/mastodon/locales/sv.json @@ -523,7 +523,7 @@ "navigation_bar.favourites": "Favoriter", "navigation_bar.filters": "Tystade ord", "navigation_bar.follow_requests": "Följförfrågningar", - "navigation_bar.followed_tags": "Utvalda hashtags", + "navigation_bar.followed_tags": "Följda hashtaggar", "navigation_bar.follows_and_followers": "Följer och följare", "navigation_bar.lists": "Listor", "navigation_bar.logout": "Logga ut", diff --git a/app/javascript/mastodon/locales/tok.json b/app/javascript/mastodon/locales/tok.json index f60c2fe2896e8a..f95e71372c0cf7 100644 --- a/app/javascript/mastodon/locales/tok.json +++ b/app/javascript/mastodon/locales/tok.json @@ -1,11 +1,11 @@ { "about.blocks": "ma lawa", "about.contact": "toki:", - "about.disclaimer": "ilo Masoton la, jan ale li ken kama jo e ona kepeken mani ala, li ken ante e toki ilo ona. kulupu esun Mastodon li jo e nimi ona. kulupu esun Mastodon li nasin lawa gGmbH.", + "about.disclaimer": "ilo Masoton la jan ale li lawa e ona li pana e pona tawa ona. kulupu esun Mastodon gGmbH li lawa e nimi ona.", "about.domain_blocks.no_reason_available": "mi sona ala e tan", "about.domain_blocks.preamble": "ilo Masoton li ken e ni: sina lukin e toki jan pi ma ilo mute. sina ken toki tawa ona lon kulupu ma. taso, ma ni li ken ala e ni tawa ma ni:", "about.domain_blocks.silenced.explanation": "sina lukin ala e toki e jan tan ma ni. taso, sina wile la, sina ken ni.", - "about.domain_blocks.silenced.title": "ken lili lukin", + "about.domain_blocks.silenced.title": "ken lukin lili ", "about.domain_blocks.suspended.title": "weka", "about.not_available": "lon kulupu ni la sina ken alasa ala e sona ni.", "about.powered_by": "lipu kulupu pi jan lawa mute tan {mastodon}", @@ -18,7 +18,7 @@ "account.block_domain": "o weka e ma {domain}", "account.block_short": "o weka e jan tawa mi", "account.blocked": "jan li weka tawa mi", - "account.cancel_follow_request": "o pini kute", + "account.cancel_follow_request": "o kute ala", "account.copy": "o pali same e linja pi lipu jan", "account.direct": "len la o mu e @{name}", "account.disable_notifications": "@{name} li toki la o mu ala e mi", @@ -50,9 +50,9 @@ "account.mute": "o len e @{name}", "account.mute_notifications_short": "o kute ala e mu tan jan ni", "account.mute_short": "o kute ala", - "account.muted": "sina len e jan ni", + "account.muted": "sina kute ala e jan ni", "account.mutual": "jan pona sona", - "account.no_bio": "lipu li weka", + "account.no_bio": "lipu li weka.", "account.open_original_page": "o open e lipu open", "account.posts": "toki suli", "account.posts_with_replies": "toki ale", @@ -64,9 +64,9 @@ "account.statuses_counter": "{count, plural, other {toki {counter}}}", "account.unblock": "o weka ala e jan {name}", "account.unblock_domain": "o weka ala e ma {domain}", - "account.unblock_short": "o pini weka", + "account.unblock_short": "o weka ala", "account.unendorse": "lipu jan la o suli ala e ni", - "account.unfollow": "o pini kute", + "account.unfollow": "o kute ala", "account.unmute": "o len ala e @{name}", "account.unmute_notifications_short": "o kute e mu tan jan ni", "account.unmute_short": "o len ala", @@ -102,7 +102,7 @@ "block_modal.you_wont_see_mentions": "nimi ona li lon toki suli la sina lukin ala e toki ni.", "boost_modal.combo": "sina ken luka e nena {combo} tawa ni: sina wile ala luka e nena lon tenpo kama", "boost_modal.reblog": "o wawa ala wawa e toki?", - "boost_modal.undo_reblog": "o pini ala pini e wawa toki?", + "boost_modal.undo_reblog": "o weka ala weka e wawa toki?", "bundle_column_error.copy_stacktrace": "o awen e sona pakala lon ilo sina", "bundle_column_error.error.body": "ilo li ken ala pana e lipu ni. ni li ken tan pakala ilo.", "bundle_column_error.error.title": "ike a!", @@ -169,7 +169,7 @@ "compose_form.spoiler.marked": "o weka e toki pi ijo ike ken", "compose_form.spoiler.unmarked": "o pali e toki pi ijo ike ken", "compose_form.spoiler_placeholder": "toki pi ijo ike ken (sina ken ala e ni)", - "confirmation_modal.cancel": "o pini", + "confirmation_modal.cancel": "o weka", "confirmations.block.confirm": "o weka", "confirmations.delete.confirm": "o weka", "confirmations.delete.message": "sina wile ala wile weka e toki ni?", @@ -190,7 +190,7 @@ "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.", "confirmations.reply.confirm": "toki lon toki ni", "confirmations.reply.message": "sina toki lon toki ni la toki pali sina li weka. sina wile ala wile e ni?", - "confirmations.unfollow.confirm": "o pini kute", + "confirmations.unfollow.confirm": "o kute ala", "confirmations.unfollow.message": "sina o wile ala wile pini kute e jan {name}?", "content_warning.show": "o lukin", "conversation.delete": "o weka e toki ni", @@ -368,7 +368,7 @@ "report.category.title": "ike seme li lon {type} ni", "report.category.title_account": "lipu", "report.category.title_status": "toki", - "report.close": "o pini", + "report.close": "ale li pona", "report.mute": "o kute ala e ona", "report.mute_explanation": "sina kama ala lukin e ijo pana ona. ona li awen ken kute e sina li awen ken lukin e sina li sona ala e weka kute sina e weka lukin sina.", "report.next": "awen", @@ -377,7 +377,7 @@ "report.reasons.other": "ni li ike tan ante", "report.reasons.spam": "ni li ike tan toki mute", "report.thanks.title": "sina wile ala lukin e ni anu seme?", - "report.unfollow": "o pini kute e {name}", + "report.unfollow": "o kute ala e {name}", "report_notification.categories.legal": "ike tawa nasin lawa", "report_notification.categories.other": "ante", "search.no_recent_searches": "alasa ala li lon tenpo poka", diff --git a/app/javascript/mastodon/locales/tr.json b/app/javascript/mastodon/locales/tr.json index 4ee3f40e56c4e5..484e6c6b731002 100644 --- a/app/javascript/mastodon/locales/tr.json +++ b/app/javascript/mastodon/locales/tr.json @@ -414,6 +414,8 @@ "ignore_notifications_modal.not_followers_title": "Takip etmeyen kişilerin bildirimlerini yoksay?", "ignore_notifications_modal.not_following_title": "Takip etmediğin kişilerin bildirimlerini yoksay?", "ignore_notifications_modal.private_mentions_title": "İstenmeyen özel bahsetmelerden gelen bildirimleri yoksay?", + "info_button.label": "Yardım", + "info_button.what_is_alt_text": "

    Alternatif metin nedir?

    Alternatif metin, görme bozukluğu olan, düşük bant genişliğine sahip bağlantıları olan veya ekstra bağlam arayan kişiler için görsel açıklamaları sağlar.

    Net, sade ve nesnel alternatif metin yazarak herkes için erişilebilirliği ve anlaşılabilirliği iyileştirebilirsiniz.

    • Önemlileri yakalayın
    • Resimlerdeki metni özetleyin
    • Düzenli cümle yapısı kullanın
    • Gereksiz bilgilerden kaçının
    • Karmaşık görsellerde (şemalar veya haritalar gibi) trendlere ve temel bulgulara odaklanın
    ", "interaction_modal.action.favourite": "Devam etmek için, hesabınızı kullanarak beğenmelisiniz.", "interaction_modal.action.follow": "Devam etmek için, hesabınızı kullanarak takip etmelisiniz.", "interaction_modal.action.reblog": "Devam etmek için, hesabınızı kullanarak tekrar göndermelisiniz.", diff --git a/app/javascript/mastodon/locales/uk.json b/app/javascript/mastodon/locales/uk.json index aa1abff2865a48..277c7df4a7dcc3 100644 --- a/app/javascript/mastodon/locales/uk.json +++ b/app/javascript/mastodon/locales/uk.json @@ -87,7 +87,11 @@ "alert.unexpected.title": "Ой!", "alt_text_badge.title": "Альтернативний текст", "alt_text_modal.add_alt_text": "Додати альтернативний текст", + "alt_text_modal.add_text_from_image": "Додати текст із малюнку", "alt_text_modal.cancel": "Скасувати", + "alt_text_modal.change_thumbnail": "Змінити мініатюру", + "alt_text_modal.describe_for_people_with_hearing_impairments": "Опишіть цю ідею для людей із порушеннями слуху…", + "alt_text_modal.describe_for_people_with_visual_impairments": "Опишіть цю ідею для людей із порушеннями зору…", "alt_text_modal.done": "Готово", "announcement.announcement": "Оголошення", "annual_report.summary.archetype.booster": "Мисливець на дописи", @@ -410,6 +414,8 @@ "ignore_notifications_modal.not_followers_title": "Ігнорувати сповіщення від людей, які не підписані на вас?", "ignore_notifications_modal.not_following_title": "Ігнорувати сповіщення від людей, на яких ви не підписалися?", "ignore_notifications_modal.private_mentions_title": "Ігнорувати сповіщення від небажаних приватних згадок?", + "info_button.label": "Довідка", + "info_button.what_is_alt_text": "

    Що таке альтернативний текст?

    Альтернативний текст містить описи зображень для людей з вадами зору, низькошвидкісними з'єднаннями або тих, хто шукає додатковий контекст.

    Ви можете покращити доступність і розуміння для всіх, написавши чіткий та лаконічний альтернативний текст.

    • Позначайте важливі елементи
    • Охоплюйте текст у картинках
    • Використовуйте звичайну структуру речень
    • Уникайте надлишкової інформації
    • Зосередьтеся на тенденціях і ключових висновках у складних візуальних формах (наприклад, діаграмах або картах)
    ", "interaction_modal.action.favourite": "Щоб продовжити, потрібно додати улюблене з вашого облікового запису.", "interaction_modal.action.follow": "Щоб іти далі, потрібно підписатися з вашого облікового запису.", "interaction_modal.action.reblog": "Щоб іти далі, потрібно зробити реблог з вашого облікового запису.", diff --git a/app/javascript/mastodon/locales/zh-TW.json b/app/javascript/mastodon/locales/zh-TW.json index 9e27ae05350a6a..d8b8197730c3a0 100644 --- a/app/javascript/mastodon/locales/zh-TW.json +++ b/app/javascript/mastodon/locales/zh-TW.json @@ -414,6 +414,8 @@ "ignore_notifications_modal.not_followers_title": "忽略來自未跟隨您帳號之推播通知?", "ignore_notifications_modal.not_following_title": "忽略來自您未跟隨帳號之推播通知?", "ignore_notifications_modal.private_mentions_title": "忽略來自不請自來私訊之推播通知?", + "info_button.label": "幫助", + "info_button.what_is_alt_text": "

    何謂 ALT 說明文字?

    ALT 說明文字為視覺障礙者、低網路頻寬或尋求額外上下文語境的人們提供圖片描述。

    您可以透過撰寫清晰、簡潔及客觀的說明文字以替所有人改善無障礙特性與協助理解。

    • 掌握幾個重要元素
    • 替圖片提供文字摘要
    • 使用常規行文結構
    • 避免冗贅資訊
    • 聚焦於趨勢與複雜視覺中之關鍵(如圖表或地圖)
    ", "interaction_modal.action.favourite": "若欲繼續,您必須自您的帳號加入最愛。", "interaction_modal.action.follow": "若欲繼續,您必須自您的帳號跟隨。", "interaction_modal.action.reblog": "若欲繼續,您必須自您的帳號轉嘟。", diff --git a/config/locales/ca.yml b/config/locales/ca.yml index acd103a2507868..c602b36c8c3129 100644 --- a/config/locales/ca.yml +++ b/config/locales/ca.yml @@ -1206,6 +1206,7 @@ ca: too_fast: Formulari enviat massa ràpid, torna a provar-ho. use_security_key: Usa clau de seguretat user_agreement_html: He llegit i estic d'acord amb les condicions de servei i la política de privadesa + user_privacy_agreement_html: He llegit i estic d'acord amb la política de privacitat author_attribution: example_title: Text d'exemple hint_html: Escriviu notícies o un blog fora de Mastodon? Controleu quin crèdit rebeu quan es comparteixen aquí. diff --git a/config/locales/da.yml b/config/locales/da.yml index c571c0990290d8..b567fa016c8aff 100644 --- a/config/locales/da.yml +++ b/config/locales/da.yml @@ -1209,6 +1209,7 @@ da: too_fast: Formularen indsendt for hurtigt, forsøg igen. use_security_key: Brug sikkerhedsnøgle user_agreement_html: Jeg accepterer Tjenestevilkår og Fortrolighedspolitik + user_privacy_agreement_html: Jeg accepterer fortrolighedspolitikken author_attribution: example_title: Eksempeltekst hint_html: Skriver du nyheder eller blogartikler uden for Mastodon? Styr, hvordan man bliver krediteret, når disse deles på Mastodon. diff --git a/config/locales/de.yml b/config/locales/de.yml index d1d557432b668e..17c5098e2035bb 100644 --- a/config/locales/de.yml +++ b/config/locales/de.yml @@ -1209,6 +1209,7 @@ de: too_fast: Formular zu schnell übermittelt. Bitte versuche es erneut. use_security_key: Sicherheitsschlüssel verwenden user_agreement_html: Ich stimme den Nutzungsbedingungen sowie der Datenschutzerklärung zu + user_privacy_agreement_html: Ich stimme der Datenschutzerklärung zu author_attribution: example_title: Beispieltext hint_html: Schreibst du außerhalb von Mastodon journalistische Artikel oder andere Texte, beispielsweise in einem Blog? Lege hier fest, wann auf dein Profil verwiesen werden soll, wenn Links zu deinen Werken auf Mastodon geteilt werden. diff --git a/config/locales/eo.yml b/config/locales/eo.yml index 400b03958ef6e7..d56d67e28ea0b3 100644 --- a/config/locales/eo.yml +++ b/config/locales/eo.yml @@ -1209,6 +1209,7 @@ eo: too_fast: Formularo sendita tro rapide, klopodu denove. use_security_key: Uzi sekurecan ŝlosilon user_agreement_html: Mi legis kaj konsentas pri la servokondiĉoj kaj privateca politiko + user_privacy_agreement_html: Mi legis kaj konsentis pri privatpolitiko author_attribution: example_title: Ekzempla teksto hint_html: Ĉu vi skribas novaĵojn aŭ blogartikolojn ekster Mastodon? Kontrolu kiel vi estas kreditita kiam ili estas kunhavataj ĉe Mastodon. diff --git a/config/locales/es-AR.yml b/config/locales/es-AR.yml index e3bcc5e5b5ec6a..141e31a346c366 100644 --- a/config/locales/es-AR.yml +++ b/config/locales/es-AR.yml @@ -1209,6 +1209,7 @@ es-AR: too_fast: Formulario enviado demasiado rápido, probá de nuevo. use_security_key: Usar la llave de seguridad user_agreement_html: Leí y acepto los términos del servicio y la política de privacidad + user_privacy_agreement_html: He leído y acepto la política de privacidad author_attribution: example_title: Texto de ejemplo hint_html: "¿Escribís artículos de noticias o de blog fuera de Mastodon? Controlá cómo se te acredita cuando se comparten en Mastodon." diff --git a/config/locales/es-MX.yml b/config/locales/es-MX.yml index 6bdee869e7b841..dd0cf365a1befd 100644 --- a/config/locales/es-MX.yml +++ b/config/locales/es-MX.yml @@ -1209,6 +1209,7 @@ es-MX: too_fast: Formulario enviado demasiado rápido, inténtelo de nuevo. use_security_key: Usar la clave de seguridad user_agreement_html: He leído y acepto las condiciones del servicio y la política de privacidad + user_privacy_agreement_html: He leído y acepto la política de privacidad author_attribution: example_title: Texto de ejemplo hint_html: "¿Estás escribiendo artículos de noticias o blogs fuera de Mastodon? Controla cómo te acreditan cuando se comparten en Mastodon." diff --git a/config/locales/es.yml b/config/locales/es.yml index 5e3374ae8ccfa7..7f7473f18fd34d 100644 --- a/config/locales/es.yml +++ b/config/locales/es.yml @@ -1209,6 +1209,7 @@ es: too_fast: Formulario enviado demasiado rápido, inténtelo de nuevo. use_security_key: Usar la clave de seguridad user_agreement_html: He leído y acepto los términos del servicio y la política de privacidad + user_privacy_agreement_html: He leído y acepto la política de privacidad author_attribution: example_title: Texto de ejemplo hint_html: "¿Escribes noticias o artículos de blog fuera de Mastodon? Controla cómo se te acredita cuando se comparten en Mastodon." diff --git a/config/locales/eu.yml b/config/locales/eu.yml index 97a8da3704137e..97943a46bb9f97 100644 --- a/config/locales/eu.yml +++ b/config/locales/eu.yml @@ -25,6 +25,7 @@ eu: admin: account_actions: action: Burutu ekintza + already_silenced: Kontu hau dagoeneko mugatua izan da. already_suspended: Kontu hau dagoeneko kanporatua izan da. title: Burutu moderazio ekintza %{acct} kontuan account_moderation_notes: diff --git a/config/locales/fi.yml b/config/locales/fi.yml index 064ca67cbf430d..c7148772b80994 100644 --- a/config/locales/fi.yml +++ b/config/locales/fi.yml @@ -1209,6 +1209,7 @@ fi: too_fast: Lomake lähetettiin liian nopeasti, yritä uudelleen. use_security_key: Käytä suojausavainta user_agreement_html: Olen lukenut ja hyväksyn käyttöehdot ja tietosuojakäytännön + user_privacy_agreement_html: Olen lukenut ja hyväksyn tietosuojakäytännön author_attribution: example_title: Esimerkkiteksti hint_html: Kirjoitatko uutisia tai blogitekstejä Mastodonin ulkopuolella? Määrää, kuinka tulet tunnustetuksi, kun niitä jaetaan Mastodonissa. diff --git a/config/locales/fo.yml b/config/locales/fo.yml index 441217ec0ef833..df99926a4c46a9 100644 --- a/config/locales/fo.yml +++ b/config/locales/fo.yml @@ -1206,6 +1206,7 @@ fo: too_fast: Oyðublaðið innsent ov skjótt, royn aftur. use_security_key: Brúka trygdarlykil user_agreement_html: Eg havi lisið og taki undir við tænastutreytunum og privatlívspolitikkinum + user_privacy_agreement_html: I have lisið og taki undir við privatlívspolitikkinum author_attribution: example_title: Tekstadømi hint_html: Skrivar tú tíðindi ella greinar til bloggin uttanfyri Mastodon? Her kanst tú stýra, hvussu tú verður tilsipað/ur, tá ið títt tilfar verður deilt á Mastodon. diff --git a/config/locales/fr-CA.yml b/config/locales/fr-CA.yml index 4fefee7ae09a55..37c34b767848f2 100644 --- a/config/locales/fr-CA.yml +++ b/config/locales/fr-CA.yml @@ -1212,6 +1212,7 @@ fr-CA: too_fast: Formulaire envoyé trop rapidement, veuillez réessayer. use_security_key: Utiliser la clé de sécurité user_agreement_html: J'ai lu et j'accepte les conditions d'utilisation et la politique de confidentialité + user_privacy_agreement_html: J’ai lu et j’accepte la politique de confidentialité author_attribution: example_title: Exemple de texte hint_html: Vous écrivez des nouvelles ou des articles de blog en dehors de Mastodon ? Contrôlez la façon dont vous êtes crédité lorsqu'ils sont partagés sur Mastodon. diff --git a/config/locales/fr.yml b/config/locales/fr.yml index 3000f9a4a9130d..0c1e248467ac7c 100644 --- a/config/locales/fr.yml +++ b/config/locales/fr.yml @@ -1212,6 +1212,7 @@ fr: too_fast: Formulaire envoyé trop rapidement, veuillez réessayer. use_security_key: Utiliser la clé de sécurité user_agreement_html: J'ai lu et j'accepte les conditions d'utilisation et la politique de confidentialité + user_privacy_agreement_html: J’ai lu et j’accepte la politique de confidentialité author_attribution: example_title: Exemple de texte hint_html: Vous écrivez des nouvelles ou des articles de blog en dehors de Mastodon ? Contrôlez la façon dont vous êtes crédité lorsqu'ils sont partagés sur Mastodon. diff --git a/config/locales/gl.yml b/config/locales/gl.yml index 63a2b9b340ab86..fe0b00fec22ac9 100644 --- a/config/locales/gl.yml +++ b/config/locales/gl.yml @@ -1209,6 +1209,7 @@ gl: too_fast: Formulario enviado demasiado rápido, inténtao outra vez. use_security_key: Usa chave de seguridade user_agreement_html: Lin e acepto os termos do servizo e a política de privacidade + user_privacy_agreement_html: Lin e acepto a política de privacidade author_attribution: example_title: Texto de mostra hint_html: Escribes novas ou artigos nun blog alleos a Mastodon? Xestiona o xeito en que podes dar crédito da túa autoría cando os compartes en Mastodon. diff --git a/config/locales/he.yml b/config/locales/he.yml index eea4c631797589..0a68d338f0841c 100644 --- a/config/locales/he.yml +++ b/config/locales/he.yml @@ -1247,6 +1247,7 @@ he: too_fast: הטופס הוגש מהר מדי, נסה/י שוב. use_security_key: שימוש במפתח אבטחה user_agreement_html: קראתי וזו הסכמתי למסמך תנאי השירות ומדיניות הפרטיות + user_privacy_agreement_html: קראתי והסכמתי למדיניות הפרטיות author_attribution: example_title: טקסט לדוגמה hint_html: האם יש לך בלוג או טור חדשות שמתפרסם מחוץ למסטודון? ניתן לשלוט איך יוצג הקרדיט שלך כשמשתפים את הלינק במסטודון. diff --git a/config/locales/hu.yml b/config/locales/hu.yml index da51e3b5a90bcd..722c3617107ba2 100644 --- a/config/locales/hu.yml +++ b/config/locales/hu.yml @@ -1209,6 +1209,7 @@ hu: too_fast: Túl gyorsan küldted el az űrlapot, próbáld később. use_security_key: Biztonsági kulcs használata user_agreement_html: Elolvastam és egyetértek a felhasználási feltételekkel és az adatvédelmi nyilatkozattal + user_privacy_agreement_html: Elolvastam és egyetértek az adatvédemi nyilatkozattal author_attribution: example_title: Mintaszöveg hint_html: Mastodonon kívül írsz híreket vagy blogbejegyzéseket? Szabályozd, hogyan tüntethetnek fel szerzőként, amikor Mastodonon osztják meg őket. diff --git a/config/locales/is.yml b/config/locales/is.yml index 229cbb56bf03ef..c4172f238d4e34 100644 --- a/config/locales/is.yml +++ b/config/locales/is.yml @@ -1213,6 +1213,7 @@ is: too_fast: Innfyllingarform sent inn of hratt, prófaðu aftur. use_security_key: Nota öryggislykil user_agreement_html: Ég hef lesið og samþykkt þjónustuskilmálana og stefnuna um persónuvernd + user_privacy_agreement_html: Ég hef lesið og samþykkt persónuverndarstefnuna author_attribution: example_title: Sýnitexti hint_html: Ertu að skrifa fréttir eða bloggfærslur utan Mastodon? Stýrðu því hvernig vitnað er í þig þegar þeim er deilt á Mastodon. diff --git a/config/locales/ja.yml b/config/locales/ja.yml index 201bdc1a0888c9..77670f0ec30758 100644 --- a/config/locales/ja.yml +++ b/config/locales/ja.yml @@ -1190,6 +1190,7 @@ ja: too_fast: フォームの送信が速すぎます。もう一度やり直してください。 use_security_key: セキュリティキーを使用 user_agreement_html: 利用規約 および プライバシーポリシーを読み、同意します。 + user_privacy_agreement_html: プライバシーポリシーを読み、同意します author_attribution: example_title: サンプルテキスト hint_html: Mastodonの外でニュースやブログなどを執筆しているユーザーは、Mastodonで自分の記事が共有されたときに著者情報を表示させることができます。 diff --git a/config/locales/nl.yml b/config/locales/nl.yml index 9f71900040dbf6..9f05104153dac3 100644 --- a/config/locales/nl.yml +++ b/config/locales/nl.yml @@ -1209,6 +1209,7 @@ nl: too_fast: Formulier is te snel ingediend. Probeer het nogmaals. use_security_key: Beveiligingssleutel gebruiken user_agreement_html: Ik heb de gebruiksvoorwaarden en het privacybeleid gelezen en ga ermee akkoord + user_privacy_agreement_html: Ik heb het privacybeleid gelezen en ga ermee akkoord author_attribution: example_title: Voorbeeldtekst hint_html: Schrijf je nieuws- of blogartikelen buiten Mastodon? Bepaal hoe je geattribueerd wordt als deze gedeeld worden op Mastodon. diff --git a/config/locales/pt-PT.yml b/config/locales/pt-PT.yml index 7dcf0977f35f58..4015005b2d87b1 100644 --- a/config/locales/pt-PT.yml +++ b/config/locales/pt-PT.yml @@ -844,7 +844,7 @@ pt-PT: no_status_selected: Nenhum estado foi alterado porque nenhum foi selecionado open: Abrir publicação original_status: Publicação original - reblogs: Reblogues + reblogs: Impulsos replied_to_html: Respondeu a %{acct_link} status_changed: Publicação alterada status_title: Publicado por @%{name} @@ -1209,6 +1209,7 @@ pt-PT: too_fast: Formulário enviado demasiado rapidamente, tenta novamente. use_security_key: Usar chave de segurança user_agreement_html: Eu li e concordo com os termos do serviço e política de privacidade + user_privacy_agreement_html: Eu li e concordo com a política de privacidade author_attribution: example_title: Texto de exemplo hint_html: Estás a escrever notícias ou artigos de blogue fora do Mastodon? Controla a forma como és creditados quando estes são partilhados no Mastodon. diff --git a/config/locales/simple_form.pt-PT.yml b/config/locales/simple_form.pt-PT.yml index ebf16f839d8a23..1330878c48aa20 100644 --- a/config/locales/simple_form.pt-PT.yml +++ b/config/locales/simple_form.pt-PT.yml @@ -63,7 +63,7 @@ pt-PT: setting_system_scrollbars_ui: Aplica-se apenas a navegadores de desktop baseados no Safari e Chrome setting_use_blurhash: Os gradientes são baseados nas cores das imagens escondidas, mas ofuscam quaisquer pormenores setting_use_pending_items: Ocultar as atualizações da cronologia após um clique em vez de percorrer automaticamente a cronologia - username: Pode utilizar letras, números e traços inferiores (_) + username: Podes utilizar letras, números e traços inferiores (_) whole_word: Quando a palavra-chave ou expressão-chave é somente alfanumérica, ela só será aplicada se corresponder à palavra completa domain_allow: domain: Este domínio será capaz de obter dados desta instância e os dados dele recebidos serão processados e armazenados diff --git a/config/locales/sq.yml b/config/locales/sq.yml index 4ac12b67a49280..0697bb0a991c58 100644 --- a/config/locales/sq.yml +++ b/config/locales/sq.yml @@ -1203,6 +1203,7 @@ sq: too_fast: Formulari u parashtrua shumë shpejt, riprovoni. use_security_key: Përdor kyç sigurie user_agreement_html: I kam lexuar dhe pajtohen me kushtet e shërbimit dhe rregullat e privatësisë + user_privacy_agreement_html: I kam lexuar dhe pajtohem me rregullat e privatësisë author_attribution: example_title: Tekst shembull hint_html: Shkruani lajme, apo artikuj blogu jashtë Mastodon-it? Kontrolloni se si ju jepet hakë, kur ndahen me të tjerët në Mastodon. diff --git a/config/locales/uk.yml b/config/locales/uk.yml index c4abba8e111832..801d32b1aba3ee 100644 --- a/config/locales/uk.yml +++ b/config/locales/uk.yml @@ -1242,6 +1242,7 @@ uk: too_fast: Форму подано занадто швидко, спробуйте ще раз. use_security_key: Використовувати ключ безпеки user_agreement_html: Я прочитав і приймаю умови використання та політику конфіденційності< /a> + user_privacy_agreement_html: Мною прочитано і я погоджуюся з політикою приватності author_attribution: example_title: Зразок тексту hint_html: Ви пишете новини чи статті в блозі за межами Mastodon? Контролюйте, як вони підписуються, коли ними діляться на Mastodon. diff --git a/config/locales/zh-TW.yml b/config/locales/zh-TW.yml index cf215240e95634..4a3ab2ba238428 100644 --- a/config/locales/zh-TW.yml +++ b/config/locales/zh-TW.yml @@ -1192,6 +1192,7 @@ zh-TW: too_fast: 送出表單的速度太快跟不上,請稍後再試。 use_security_key: 使用安全金鑰 user_agreement_html: 我已閱讀並同意 服務條款隱私權政策 + user_privacy_agreement_html: 我已閱讀並同意 隱私權政策 author_attribution: example_title: 範例文字 hint_html: 您是否正於 Mastodon 之外撰寫新聞或部落格文章?控制當它們於 Mastodon 上分享時您如何獲得信譽。 From a1d9c3fb99f21135602d9bb742a98925bb27a660 Mon Sep 17 00:00:00 2001 From: Matt Jankowski Date: Fri, 24 Jan 2025 09:40:20 -0500 Subject: [PATCH 10/42] Use `expect` params wrapper for more "auth" and "2FA" "controllers" (#33717) --- app/controllers/auth/sessions_controller.rb | 2 +- .../settings/applications_controller.rb | 10 +++------- .../confirmations_controller.rb | 2 +- .../settings/verifications_controller.rb | 2 +- spec/requests/auth/sessions_spec.rb | 18 ++++++++++++++++++ spec/requests/settings/applications_spec.rb | 18 ++++++++++++++++++ .../confirmations_spec.rb | 19 +++++++++++++++++++ spec/requests/settings/verifications_spec.rb | 16 ++++++++++++++++ 8 files changed, 77 insertions(+), 10 deletions(-) create mode 100644 spec/requests/auth/sessions_spec.rb create mode 100644 spec/requests/settings/two_factor_authentication/confirmations_spec.rb create mode 100644 spec/requests/settings/verifications_spec.rb diff --git a/app/controllers/auth/sessions_controller.rb b/app/controllers/auth/sessions_controller.rb index ecac4c5ba8e517..250573fc7d51ff 100644 --- a/app/controllers/auth/sessions_controller.rb +++ b/app/controllers/auth/sessions_controller.rb @@ -73,7 +73,7 @@ def find_user_from_params end def user_params - params.require(:user).permit(:email, :password, :otp_attempt, credential: {}) + params.expect(user: [:email, :password, :otp_attempt, credential: {}]) end def after_sign_in_path_for(resource) diff --git a/app/controllers/settings/applications_controller.rb b/app/controllers/settings/applications_controller.rb index d6573f9b4949bf..9785a1b90fb2f7 100644 --- a/app/controllers/settings/applications_controller.rb +++ b/app/controllers/settings/applications_controller.rb @@ -60,16 +60,12 @@ def set_application end def application_params - params.require(:doorkeeper_application).permit( - :name, - :redirect_uri, - :scopes, - :website - ) + params + .expect(doorkeeper_application: [:name, :redirect_uri, :scopes, :website]) end def prepare_scopes - scopes = params.fetch(:doorkeeper_application, {}).fetch(:scopes, nil) + scopes = application_params.fetch(:doorkeeper_application, {}).fetch(:scopes, nil) params[:doorkeeper_application][:scopes] = scopes.join(' ') if scopes.is_a? Array end end diff --git a/app/controllers/settings/two_factor_authentication/confirmations_controller.rb b/app/controllers/settings/two_factor_authentication/confirmations_controller.rb index 1a0afe58b05490..eae990e79b2229 100644 --- a/app/controllers/settings/two_factor_authentication/confirmations_controller.rb +++ b/app/controllers/settings/two_factor_authentication/confirmations_controller.rb @@ -38,7 +38,7 @@ def create private def confirmation_params - params.require(:form_two_factor_confirmation).permit(:otp_attempt) + params.expect(form_two_factor_confirmation: [:otp_attempt]) end def prepare_two_factor_form diff --git a/app/controllers/settings/verifications_controller.rb b/app/controllers/settings/verifications_controller.rb index 9cc60ba2e88b13..bed29dbeec79be 100644 --- a/app/controllers/settings/verifications_controller.rb +++ b/app/controllers/settings/verifications_controller.rb @@ -18,7 +18,7 @@ def update private def account_params - params.require(:account).permit(:attribution_domains).tap do |params| + params.expect(account: [:attribution_domains]).tap do |params| params[:attribution_domains] = params[:attribution_domains].split if params[:attribution_domains] end end diff --git a/spec/requests/auth/sessions_spec.rb b/spec/requests/auth/sessions_spec.rb new file mode 100644 index 00000000000000..246c3794cc2362 --- /dev/null +++ b/spec/requests/auth/sessions_spec.rb @@ -0,0 +1,18 @@ +# frozen_string_literal: true + +require 'rails_helper' + +RSpec.describe 'Auth Sessions' do + describe 'POST /auth/sign_in' do + # The rack-attack check has issues with the non-nested invalid param used here + before { Rack::Attack.enabled = false } + after { Rack::Attack.enabled = true } + + it 'gracefully handles invalid nested params' do + post user_session_path(user: 'invalid') + + expect(response) + .to have_http_status(400) + end + end +end diff --git a/spec/requests/settings/applications_spec.rb b/spec/requests/settings/applications_spec.rb index 8a5b3de895b47f..d2d91f03b1e564 100644 --- a/spec/requests/settings/applications_spec.rb +++ b/spec/requests/settings/applications_spec.rb @@ -40,5 +40,23 @@ expect(response) .to redirect_to(settings_applications_path) end + + it 'gracefully handles invalid nested params' do + post settings_applications_path(doorkeeper_application: 'invalid') + + expect(response) + .to have_http_status(400) + end + end + + describe 'PUT /settings/applications/:id' do + let(:application) { Fabricate :application, owner: user } + + it 'gracefully handles invalid nested params' do + put settings_application_path(application.id, doorkeeper_application: 'invalid') + + expect(response) + .to have_http_status(400) + end end end diff --git a/spec/requests/settings/two_factor_authentication/confirmations_spec.rb b/spec/requests/settings/two_factor_authentication/confirmations_spec.rb new file mode 100644 index 00000000000000..bf443a5e62fe00 --- /dev/null +++ b/spec/requests/settings/two_factor_authentication/confirmations_spec.rb @@ -0,0 +1,19 @@ +# frozen_string_literal: true + +require 'rails_helper' + +RSpec.describe 'Settings 2FA Confirmations' do + describe 'POST /settings/two_factor_authentication/confirmations' do + before do + sign_in Fabricate(:user, encrypted_password: '') # Empty encrypted password avoids challengable flow + post settings_otp_authentication_path # Sets `session[:new_otp_secret]` which is needed for next step + end + + it 'gracefully handles invalid nested params' do + post settings_two_factor_authentication_confirmation_path(form_two_factor_confirmation: 'invalid') + + expect(response) + .to have_http_status(400) + end + end +end diff --git a/spec/requests/settings/verifications_spec.rb b/spec/requests/settings/verifications_spec.rb new file mode 100644 index 00000000000000..5acfe648367a8b --- /dev/null +++ b/spec/requests/settings/verifications_spec.rb @@ -0,0 +1,16 @@ +# frozen_string_literal: true + +require 'rails_helper' + +RSpec.describe 'Settings Verifications' do + describe 'PUT /settings/verification' do + before { sign_in Fabricate(:user) } + + it 'gracefully handles invalid nested params' do + put settings_verification_path(account: 'invalid') + + expect(response) + .to have_http_status(400) + end + end +end From 9a0166c3f30fdc0fa60d4be5e88ebc03ec69f4ed Mon Sep 17 00:00:00 2001 From: Claire Date: Fri, 24 Jan 2025 17:11:23 +0100 Subject: [PATCH 11/42] Convert `LanguageDropdownMenu` to functional component (#33704) --- .../compose/components/language_dropdown.jsx | 270 ++++++++---------- 1 file changed, 118 insertions(+), 152 deletions(-) diff --git a/app/javascript/mastodon/features/compose/components/language_dropdown.jsx b/app/javascript/mastodon/features/compose/components/language_dropdown.jsx index c80aa27e46a6ef..cc97d61415eecc 100644 --- a/app/javascript/mastodon/features/compose/components/language_dropdown.jsx +++ b/app/javascript/mastodon/features/compose/components/language_dropdown.jsx @@ -1,5 +1,5 @@ import PropTypes from 'prop-types'; -import { useCallback, useRef, useState, useEffect, PureComponent } from 'react'; +import { useCallback, useRef, useState, useEffect, useMemo } from 'react'; import { useIntl, defineMessages } from 'react-intl'; @@ -30,109 +30,37 @@ const messages = defineMessages({ const listenerOptions = supportsPassiveEvents ? { passive: true, capture: true } : true; -class LanguageDropdownMenu extends PureComponent { - - static propTypes = { - value: PropTypes.string.isRequired, - guess: PropTypes.string, - frequentlyUsedLanguages: PropTypes.arrayOf(PropTypes.string).isRequired, - onClose: PropTypes.func.isRequired, - onChange: PropTypes.func.isRequired, - languages: PropTypes.arrayOf(PropTypes.arrayOf(PropTypes.string)), - intl: PropTypes.object, - }; - - static defaultProps = { - languages: preloadedLanguages, - }; - - state = { - searchValue: '', - }; - - handleDocumentClick = e => { - if (this.node && !this.node.contains(e.target)) { - this.props.onClose(); - e.stopPropagation(); - } - }; - - componentDidMount () { - document.addEventListener('click', this.handleDocumentClick, { capture: true }); - document.addEventListener('touchend', this.handleDocumentClick, listenerOptions); - - // Because of https://github.com/react-bootstrap/react-bootstrap/issues/2614 we need - // to wait for a frame before focusing - requestAnimationFrame(() => { - if (this.node) { - const element = this.node.querySelector('input[type="search"]'); - if (element) element.focus(); - } - }); - } - - componentWillUnmount () { - document.removeEventListener('click', this.handleDocumentClick, { capture: true }); - document.removeEventListener('touchend', this.handleDocumentClick, listenerOptions); - } - - setRef = c => { - this.node = c; - }; - - setListRef = c => { - this.listNode = c; - }; - - handleSearchChange = ({ target }) => { - this.setState({ searchValue: target.value }); - }; - - search () { - const { languages, value, frequentlyUsedLanguages, guess } = this.props; - const { searchValue } = this.state; - - if (searchValue === '') { - return [...languages].sort((a, b) => { - - if (guess && a[0] === guess) { // Push guessed language higher than current selection - return -1; - } else if (guess && b[0] === guess) { - return 1; - } else if (a[0] === value) { // Push current selection to the top of the list - return -1; - } else if (b[0] === value) { - return 1; - } else { - // Sort according to frequently used languages +const getFrequentlyUsedLanguages = createSelector([ + state => state.getIn(['settings', 'frequentlyUsedLanguages'], ImmutableMap()), +], languageCounters => ( + languageCounters.keySeq() + .sort((a, b) => languageCounters.get(a) - languageCounters.get(b)) + .reverse() + .toArray() +)); - const indexOfA = frequentlyUsedLanguages.indexOf(a[0]); - const indexOfB = frequentlyUsedLanguages.indexOf(b[0]); +const LanguageDropdownMenu = ({ value, guess, onClose, onChange, languages = preloadedLanguages, intl }) => { + const [searchValue, setSearchValue] = useState(''); + const nodeRef = useRef(null); + const listNodeRef = useRef(null); - return ((indexOfA > -1 ? indexOfA : Infinity) - (indexOfB > -1 ? indexOfB : Infinity)); - } - }); - } + const frequentlyUsedLanguages = useAppSelector(getFrequentlyUsedLanguages); - return fuzzysort.go(searchValue, languages, { - keys: ['0', '1', '2'], - limit: 5, - threshold: -10000, - }).map(result => result.obj); - } + const handleSearchChange = useCallback(({ target }) => { + setSearchValue(target.value); + }, [setSearchValue]); - handleClick = e => { + const handleClick = useCallback((e) => { const value = e.currentTarget.getAttribute('data-index'); e.preventDefault(); - this.props.onClose(); - this.props.onChange(value); - }; + onClose(); + onChange(value); + }, [onClose, onChange]); - handleKeyDown = e => { - const { onClose } = this.props; - const index = Array.from(this.listNode.childNodes).findIndex(node => node === e.currentTarget); + const handleKeyDown = useCallback(e => { + const index = Array.from(listNodeRef.current.childNodes).findIndex(node => node === e.currentTarget); let element = null; @@ -142,26 +70,26 @@ class LanguageDropdownMenu extends PureComponent { break; case ' ': case 'Enter': - this.handleClick(e); + handleClick(e); break; case 'ArrowDown': - element = this.listNode.childNodes[index + 1] || this.listNode.firstChild; + element = listNodeRef.current.childNodes[index + 1] || listNodeRef.current.firstChild; break; case 'ArrowUp': - element = this.listNode.childNodes[index - 1] || this.listNode.lastChild; + element = listNodeRef.current.childNodes[index - 1] || listNodeRef.current.lastChild; break; case 'Tab': if (e.shiftKey) { - element = this.listNode.childNodes[index - 1] || this.listNode.lastChild; + element = listNodeRef.current.childNodes[index - 1] || listNodeRef.current.lastChild; } else { - element = this.listNode.childNodes[index + 1] || this.listNode.firstChild; + element = listNodeRef.current.childNodes[index + 1] || listNodeRef.current.firstChild; } break; case 'Home': - element = this.listNode.firstChild; + element = listNodeRef.current.firstChild; break; case 'End': - element = this.listNode.lastChild; + element = listNodeRef.current.lastChild; break; } @@ -170,18 +98,15 @@ class LanguageDropdownMenu extends PureComponent { e.preventDefault(); e.stopPropagation(); } - }; - - handleSearchKeyDown = e => { - const { onChange, onClose } = this.props; - const { searchValue } = this.state; + }, [onClose, handleClick]); + const handleSearchKeyDown = useCallback(e => { let element = null; switch(e.key) { case 'Tab': case 'ArrowDown': - element = this.listNode.firstChild; + element = listNodeRef.current.firstChild; if (element) { element.focus(); @@ -191,7 +116,7 @@ class LanguageDropdownMenu extends PureComponent { break; case 'Enter': - element = this.listNode.firstChild; + element = listNodeRef.current.firstChild; if (element) { onChange(element.getAttribute('data-index')); @@ -206,52 +131,96 @@ class LanguageDropdownMenu extends PureComponent { break; } - }; + }, [onChange, onClose, searchValue]); - handleClear = () => { - this.setState({ searchValue: '' }); - }; + const handleClear = useCallback(() => { + setSearchValue(''); + }, [setSearchValue]); - renderItem = lang => { - const { value } = this.props; + const isSearching = searchValue !== ''; - return ( -
    - {lang[2]} ({lang[1]}) -
    - ); - }; - - render () { - const { intl } = this.props; - const { searchValue } = this.state; - const isSearching = searchValue !== ''; - const results = this.search(); - - return ( -
    -
    - - -
    - -
    - {results.map(this.renderItem)} -
    + useEffect(() => { + const handleDocumentClick = (e) => { + if (nodeRef.current && !nodeRef.current.contains(e.target)) { + onClose(); + e.stopPropagation(); + } + }; + + document.addEventListener('click', handleDocumentClick, { capture: true }); + document.addEventListener('touchend', handleDocumentClick, listenerOptions); + + // Because of https://github.com/react-bootstrap/react-bootstrap/issues/2614 we need + // to wait for a frame before focusing + requestAnimationFrame(() => { + if (nodeRef.current) { + const element = nodeRef.current.querySelector('input[type="search"]'); + if (element) element.focus(); + } + }); + + return () => { + document.removeEventListener('click', handleDocumentClick, { capture: true }); + document.removeEventListener('touchend', handleDocumentClick, listenerOptions); + }; + }, [onClose]); + + const results = useMemo(() => { + if (searchValue === '') { + return [...languages].sort((a, b) => { + + if (guess && a[0] === guess) { // Push guessed language higher than current selection + return -1; + } else if (guess && b[0] === guess) { + return 1; + } else if (a[0] === value) { // Push current selection to the top of the list + return -1; + } else if (b[0] === value) { + return 1; + } else { + // Sort according to frequently used languages + + const indexOfA = frequentlyUsedLanguages.indexOf(a[0]); + const indexOfB = frequentlyUsedLanguages.indexOf(b[0]); + + return ((indexOfA > -1 ? indexOfA : Infinity) - (indexOfB > -1 ? indexOfB : Infinity)); + } + }); + } + + return fuzzysort.go(searchValue, languages, { + keys: ['0', '1', '2'], + limit: 5, + threshold: -10000, + }).map(result => result.obj); + }, [searchValue, languages, guess, frequentlyUsedLanguages, value]); + + return ( +
    +
    + +
    - ); - } -} +
    + {results.map((lang) => ( +
    + {lang[2]} ({lang[1]}) +
    + ))} +
    +
    + ); +}; -const getFrequentlyUsedLanguages = createSelector([ - state => state.getIn(['settings', 'frequentlyUsedLanguages'], ImmutableMap()), -], languageCounters => ( - languageCounters.keySeq() - .sort((a, b) => languageCounters.get(a) - languageCounters.get(b)) - .reverse() - .toArray() -)); +LanguageDropdownMenu.propTypes = { + value: PropTypes.string.isRequired, + guess: PropTypes.string, + onClose: PropTypes.func.isRequired, + onChange: PropTypes.func.isRequired, + languages: PropTypes.arrayOf(PropTypes.arrayOf(PropTypes.string)), + intl: PropTypes.object, +}; export const LanguageDropdown = () => { const [open, setOpen] = useState(false); @@ -263,7 +232,6 @@ export const LanguageDropdown = () => { const intl = useIntl(); const dispatch = useAppDispatch(); - const frequentlyUsedLanguages = useAppSelector(getFrequentlyUsedLanguages); const value = useAppSelector((state) => state.compose.get('language')); const text = useAppSelector((state) => state.compose.get('text')); @@ -319,10 +287,8 @@ export const LanguageDropdown = () => {
    From 469c8f8db16cc5fe48c1831364551129d53c9d0c Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 24 Jan 2025 17:49:48 +0100 Subject: [PATCH 12/42] Update babel monorepo to v7.26.7 (#33721) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- yarn.lock | 192 ++++++++++++++++++++++++------------------------------ 1 file changed, 85 insertions(+), 107 deletions(-) diff --git a/yarn.lock b/yarn.lock index da5fcb70f9732c..6b5d879be73645 100644 --- a/yarn.lock +++ b/yarn.lock @@ -55,57 +55,57 @@ __metadata: languageName: node linkType: hard -"@babel/code-frame@npm:^7.0.0, @babel/code-frame@npm:^7.10.4, @babel/code-frame@npm:^7.12.13, @babel/code-frame@npm:^7.25.9, @babel/code-frame@npm:^7.26.0": - version: 7.26.0 - resolution: "@babel/code-frame@npm:7.26.0" +"@babel/code-frame@npm:^7.0.0, @babel/code-frame@npm:^7.10.4, @babel/code-frame@npm:^7.12.13, @babel/code-frame@npm:^7.25.9, @babel/code-frame@npm:^7.26.2": + version: 7.26.2 + resolution: "@babel/code-frame@npm:7.26.2" dependencies: "@babel/helper-validator-identifier": "npm:^7.25.9" js-tokens: "npm:^4.0.0" picocolors: "npm:^1.0.0" - checksum: 10c0/46f7e367714be736b52ea3c01b24f47e2102e210fb83021d1c8237d8fc511b9538909e16e2fcdbb5cb6173e0794e28624309a59014e52fcfb7bde908f5284388 + checksum: 10c0/7d79621a6849183c415486af99b1a20b84737e8c11cd55b6544f688c51ce1fd710e6d869c3dd21232023da272a79b91efb3e83b5bc2dc65c1187c5fcd1b72ea8 languageName: node linkType: hard -"@babel/compat-data@npm:^7.22.6, @babel/compat-data@npm:^7.25.9, @babel/compat-data@npm:^7.26.0": - version: 7.26.0 - resolution: "@babel/compat-data@npm:7.26.0" - checksum: 10c0/6325c9151a3c9b0a3a807e854a26255ef66d989bff331475a935af9bb18f160e0fffe6aed550e4e96b63f91efcd874bfbaab2a1f4a2f8d25645d712a0de590fb +"@babel/compat-data@npm:^7.22.6, @babel/compat-data@npm:^7.26.5": + version: 7.26.5 + resolution: "@babel/compat-data@npm:7.26.5" + checksum: 10c0/9d2b41f0948c3dfc5de44d9f789d2208c2ea1fd7eb896dfbb297fe955e696728d6f363c600cd211e7f58ccbc2d834fe516bb1e4cf883bbabed8a32b038afc1a0 languageName: node linkType: hard "@babel/core@npm:^7.11.6, @babel/core@npm:^7.12.3, @babel/core@npm:^7.22.1, @babel/core@npm:^7.24.4, @babel/core@npm:^7.25.0": - version: 7.26.0 - resolution: "@babel/core@npm:7.26.0" + version: 7.26.7 + resolution: "@babel/core@npm:7.26.7" dependencies: "@ampproject/remapping": "npm:^2.2.0" - "@babel/code-frame": "npm:^7.26.0" - "@babel/generator": "npm:^7.26.0" - "@babel/helper-compilation-targets": "npm:^7.25.9" + "@babel/code-frame": "npm:^7.26.2" + "@babel/generator": "npm:^7.26.5" + "@babel/helper-compilation-targets": "npm:^7.26.5" "@babel/helper-module-transforms": "npm:^7.26.0" - "@babel/helpers": "npm:^7.26.0" - "@babel/parser": "npm:^7.26.0" + "@babel/helpers": "npm:^7.26.7" + "@babel/parser": "npm:^7.26.7" "@babel/template": "npm:^7.25.9" - "@babel/traverse": "npm:^7.25.9" - "@babel/types": "npm:^7.26.0" + "@babel/traverse": "npm:^7.26.7" + "@babel/types": "npm:^7.26.7" convert-source-map: "npm:^2.0.0" debug: "npm:^4.1.0" gensync: "npm:^1.0.0-beta.2" json5: "npm:^2.2.3" semver: "npm:^6.3.1" - checksum: 10c0/91de73a7ff5c4049fbc747930aa039300e4d2670c2a91f5aa622f1b4868600fc89b01b6278385fbcd46f9574186fa3d9b376a9e7538e50f8d118ec13cfbcb63e + checksum: 10c0/fbd2cd9fc23280bdcaca556e558f715c0a42d940b9913c52582e8e3d24e391d269cb8a9cd6589172593983569021c379e28bba6b19ea2ee08674f6068c210a9d languageName: node linkType: hard -"@babel/generator@npm:^7.25.9, @babel/generator@npm:^7.26.0, @babel/generator@npm:^7.7.2": - version: 7.26.0 - resolution: "@babel/generator@npm:7.26.0" +"@babel/generator@npm:^7.26.5, @babel/generator@npm:^7.7.2": + version: 7.26.5 + resolution: "@babel/generator@npm:7.26.5" dependencies: - "@babel/parser": "npm:^7.26.0" - "@babel/types": "npm:^7.26.0" + "@babel/parser": "npm:^7.26.5" + "@babel/types": "npm:^7.26.5" "@jridgewell/gen-mapping": "npm:^0.3.5" "@jridgewell/trace-mapping": "npm:^0.3.25" jsesc: "npm:^3.0.2" - checksum: 10c0/b6bb9185f19a97eaf58e04a6d39a13237076678e7ed16b6321dea914535d4bf6a8d7727c9dcb65539845aa0096b326eb67be4bab764bd74bcfd848e2eda68609 + checksum: 10c0/3be79e0aa03f38858a465d12ee2e468320b9122dc44fc85984713e32f16f4d77ce34a16a1a9505972782590e0b8d847b6f373621f9c6fafa1906d90f31416cb0 languageName: node linkType: hard @@ -118,16 +118,6 @@ __metadata: languageName: node linkType: hard -"@babel/helper-builder-binary-assignment-operator-visitor@npm:^7.25.9": - version: 7.25.9 - resolution: "@babel/helper-builder-binary-assignment-operator-visitor@npm:7.25.9" - dependencies: - "@babel/traverse": "npm:^7.25.9" - "@babel/types": "npm:^7.25.9" - checksum: 10c0/a6068bb813e7f72d12b72edeecb99167f60cd7964cacedfb60e01fff5e7bed4a5a7f4f7414de7cf352a1b71487df5f8dab8c2b5230de4ad5aea16adf32e14219 - languageName: node - linkType: hard - "@babel/helper-builder-react-jsx@npm:^7.25.9": version: 7.25.9 resolution: "@babel/helper-builder-react-jsx@npm:7.25.9" @@ -138,16 +128,16 @@ __metadata: languageName: node linkType: hard -"@babel/helper-compilation-targets@npm:^7.22.6, @babel/helper-compilation-targets@npm:^7.25.9": - version: 7.25.9 - resolution: "@babel/helper-compilation-targets@npm:7.25.9" +"@babel/helper-compilation-targets@npm:^7.22.6, @babel/helper-compilation-targets@npm:^7.25.9, @babel/helper-compilation-targets@npm:^7.26.5": + version: 7.26.5 + resolution: "@babel/helper-compilation-targets@npm:7.26.5" dependencies: - "@babel/compat-data": "npm:^7.25.9" + "@babel/compat-data": "npm:^7.26.5" "@babel/helper-validator-option": "npm:^7.25.9" browserslist: "npm:^4.24.0" lru-cache: "npm:^5.1.1" semver: "npm:^6.3.1" - checksum: 10c0/a6b26a1e4222e69ef8e62ee19374308f060b007828bc11c65025ecc9e814aba21ff2175d6d3f8bf53c863edd728ee8f94ba7870f8f90a37d39552ad9933a8aaa + checksum: 10c0/9da5c77e5722f1a2fcb3e893049a01d414124522bbf51323bb1a0c9dcd326f15279836450fc36f83c9e8a846f3c40e88be032ed939c5a9840922bed6073edfb4 languageName: node linkType: hard @@ -271,16 +261,6 @@ __metadata: languageName: node linkType: hard -"@babel/helper-simple-access@npm:^7.25.9": - version: 7.25.9 - resolution: "@babel/helper-simple-access@npm:7.25.9" - dependencies: - "@babel/traverse": "npm:^7.25.9" - "@babel/types": "npm:^7.25.9" - checksum: 10c0/3f1bcdb88ee3883ccf86959869a867f6bbf8c4737cd44fb9f799c38e54f67474590bc66802500ae9fe18161792875b2cfb7ec15673f48ed6c8663f6d09686ca8 - languageName: node - linkType: hard - "@babel/helper-skip-transparent-expression-wrappers@npm:^7.25.9": version: 7.25.9 resolution: "@babel/helper-skip-transparent-expression-wrappers@npm:7.25.9" @@ -323,24 +303,24 @@ __metadata: languageName: node linkType: hard -"@babel/helpers@npm:^7.26.0": - version: 7.26.0 - resolution: "@babel/helpers@npm:7.26.0" +"@babel/helpers@npm:^7.26.7": + version: 7.26.7 + resolution: "@babel/helpers@npm:7.26.7" dependencies: "@babel/template": "npm:^7.25.9" - "@babel/types": "npm:^7.26.0" - checksum: 10c0/343333cced6946fe46617690a1d0789346960910225ce359021a88a60a65bc0d791f0c5d240c0ed46cf8cc63b5fd7df52734ff14e43b9c32feae2b61b1647097 + "@babel/types": "npm:^7.26.7" + checksum: 10c0/37fec398e53a2dbbf24bc2a025c4d571b2556cef18d8116d05d04b153f13ef659cdfbaab96c8eed875e629d39bdf9b3ea5d099ccf80544537de224e2d94f9b11 languageName: node linkType: hard -"@babel/parser@npm:^7.1.0, @babel/parser@npm:^7.14.7, @babel/parser@npm:^7.20.7, @babel/parser@npm:^7.25.9, @babel/parser@npm:^7.26.0": - version: 7.26.1 - resolution: "@babel/parser@npm:7.26.1" +"@babel/parser@npm:^7.1.0, @babel/parser@npm:^7.14.7, @babel/parser@npm:^7.20.7, @babel/parser@npm:^7.25.9, @babel/parser@npm:^7.26.5, @babel/parser@npm:^7.26.7": + version: 7.26.7 + resolution: "@babel/parser@npm:7.26.7" dependencies: - "@babel/types": "npm:^7.26.0" + "@babel/types": "npm:^7.26.7" bin: parser: ./bin/babel-parser.js - checksum: 10c0/dc7d4e6b7eb667fa0784e7e2c3f6f92ca12ad72242f6d4311995310dae55093f02acdb595b69b0dbbf04cb61ad87156ac03186ff32eacfa35149c655bc22c14b + checksum: 10c0/dcb08a4f2878ece33caffefe43b71488d753324bae7ca58d64bca3bc4af34dcfa1b58abdf9972516d76af760fceb25bb9294ca33461d56b31c5059ccfe32001f languageName: node linkType: hard @@ -637,14 +617,14 @@ __metadata: languageName: node linkType: hard -"@babel/plugin-transform-block-scoped-functions@npm:^7.25.9": - version: 7.25.9 - resolution: "@babel/plugin-transform-block-scoped-functions@npm:7.25.9" +"@babel/plugin-transform-block-scoped-functions@npm:^7.26.5": + version: 7.26.5 + resolution: "@babel/plugin-transform-block-scoped-functions@npm:7.26.5" dependencies: - "@babel/helper-plugin-utils": "npm:^7.25.9" + "@babel/helper-plugin-utils": "npm:^7.26.5" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 10c0/e92ba0e3d72c038513844d8fca1cc8437dcb35cd42778e97fd03cb8303380b201468611e7ecfdcae3de33473b2679fe2de1552c5f925d112c5693425cf851f10 + checksum: 10c0/2f3060800ead46b09971dd7bf830d66383b7bc61ced9945633b4ef9bf87787956ea83fcf49b387cecb377812588c6b81681714c760f9cf89ecba45edcbab1192 languageName: node linkType: hard @@ -768,15 +748,14 @@ __metadata: languageName: node linkType: hard -"@babel/plugin-transform-exponentiation-operator@npm:^7.25.9": - version: 7.25.9 - resolution: "@babel/plugin-transform-exponentiation-operator@npm:7.25.9" +"@babel/plugin-transform-exponentiation-operator@npm:^7.26.3": + version: 7.26.3 + resolution: "@babel/plugin-transform-exponentiation-operator@npm:7.26.3" dependencies: - "@babel/helper-builder-binary-assignment-operator-visitor": "npm:^7.25.9" "@babel/helper-plugin-utils": "npm:^7.25.9" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 10c0/3b42f65bab3fee28c385115ce6bcb6ba544dff187012df408a432c9fb44c980afd898911020c723dc1c9257aaf3d7d0131ad83ba15102bf30ad9a86fc2a8a912 + checksum: 10c0/cac922e851c6a0831fdd2e3663564966916015aeff7f4485825fc33879cbc3a313ceb859814c9200248e2875d65bb13802a723e5d7d7b40a2e90da82a5a1e15c languageName: node linkType: hard @@ -872,16 +851,15 @@ __metadata: languageName: node linkType: hard -"@babel/plugin-transform-modules-commonjs@npm:^7.25.9": - version: 7.25.9 - resolution: "@babel/plugin-transform-modules-commonjs@npm:7.25.9" +"@babel/plugin-transform-modules-commonjs@npm:^7.25.9, @babel/plugin-transform-modules-commonjs@npm:^7.26.3": + version: 7.26.3 + resolution: "@babel/plugin-transform-modules-commonjs@npm:7.26.3" dependencies: - "@babel/helper-module-transforms": "npm:^7.25.9" + "@babel/helper-module-transforms": "npm:^7.26.0" "@babel/helper-plugin-utils": "npm:^7.25.9" - "@babel/helper-simple-access": "npm:^7.25.9" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 10c0/6ce771fb04d4810257fc8900374fece877dacaed74b05eaa16ad9224b390f43795c4d046cbe9ae304e1eb5aad035d37383895e3c64496d647c2128d183916e74 + checksum: 10c0/82e59708f19f36da29531a64a7a94eabbf6ff46a615e0f5d9b49f3f59e8ef10e2bac607d749091508d3fa655146c9e5647c3ffeca781060cdabedb4c7a33c6f2 languageName: node linkType: hard @@ -934,7 +912,7 @@ __metadata: languageName: node linkType: hard -"@babel/plugin-transform-nullish-coalescing-operator@npm:^7.22.3, @babel/plugin-transform-nullish-coalescing-operator@npm:^7.25.9": +"@babel/plugin-transform-nullish-coalescing-operator@npm:^7.22.3, @babel/plugin-transform-nullish-coalescing-operator@npm:^7.26.6": version: 7.26.6 resolution: "@babel/plugin-transform-nullish-coalescing-operator@npm:7.26.6" dependencies: @@ -1219,14 +1197,14 @@ __metadata: languageName: node linkType: hard -"@babel/plugin-transform-typeof-symbol@npm:^7.25.9": - version: 7.25.9 - resolution: "@babel/plugin-transform-typeof-symbol@npm:7.25.9" +"@babel/plugin-transform-typeof-symbol@npm:^7.26.7": + version: 7.26.7 + resolution: "@babel/plugin-transform-typeof-symbol@npm:7.26.7" dependencies: - "@babel/helper-plugin-utils": "npm:^7.25.9" + "@babel/helper-plugin-utils": "npm:^7.26.5" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 10c0/2b19fd88608589d9bc6b607ff17b06791d35c67ef3249f4659283454e6a9984241e3bd4c4eb72bb8b3d860a73223f3874558b861adb7314aa317c1c6a2f0cafb + checksum: 10c0/d5640e3457637e6eee1d7205d255602ccca124ed30e4de10ec75ba179d167e0a826ceeab424e119921f5c995dfddf39ef1f2c91efd2dcbf3f0dc1e7931dfd1d1 languageName: node linkType: hard @@ -1293,12 +1271,12 @@ __metadata: linkType: hard "@babel/preset-env@npm:^7.11.0, @babel/preset-env@npm:^7.12.1, @babel/preset-env@npm:^7.22.4": - version: 7.26.0 - resolution: "@babel/preset-env@npm:7.26.0" + version: 7.26.7 + resolution: "@babel/preset-env@npm:7.26.7" dependencies: - "@babel/compat-data": "npm:^7.26.0" - "@babel/helper-compilation-targets": "npm:^7.25.9" - "@babel/helper-plugin-utils": "npm:^7.25.9" + "@babel/compat-data": "npm:^7.26.5" + "@babel/helper-compilation-targets": "npm:^7.26.5" + "@babel/helper-plugin-utils": "npm:^7.26.5" "@babel/helper-validator-option": "npm:^7.25.9" "@babel/plugin-bugfix-firefox-class-in-computed-class-key": "npm:^7.25.9" "@babel/plugin-bugfix-safari-class-field-initializer-scope": "npm:^7.25.9" @@ -1312,7 +1290,7 @@ __metadata: "@babel/plugin-transform-arrow-functions": "npm:^7.25.9" "@babel/plugin-transform-async-generator-functions": "npm:^7.25.9" "@babel/plugin-transform-async-to-generator": "npm:^7.25.9" - "@babel/plugin-transform-block-scoped-functions": "npm:^7.25.9" + "@babel/plugin-transform-block-scoped-functions": "npm:^7.26.5" "@babel/plugin-transform-block-scoping": "npm:^7.25.9" "@babel/plugin-transform-class-properties": "npm:^7.25.9" "@babel/plugin-transform-class-static-block": "npm:^7.26.0" @@ -1323,7 +1301,7 @@ __metadata: "@babel/plugin-transform-duplicate-keys": "npm:^7.25.9" "@babel/plugin-transform-duplicate-named-capturing-groups-regex": "npm:^7.25.9" "@babel/plugin-transform-dynamic-import": "npm:^7.25.9" - "@babel/plugin-transform-exponentiation-operator": "npm:^7.25.9" + "@babel/plugin-transform-exponentiation-operator": "npm:^7.26.3" "@babel/plugin-transform-export-namespace-from": "npm:^7.25.9" "@babel/plugin-transform-for-of": "npm:^7.25.9" "@babel/plugin-transform-function-name": "npm:^7.25.9" @@ -1332,12 +1310,12 @@ __metadata: "@babel/plugin-transform-logical-assignment-operators": "npm:^7.25.9" "@babel/plugin-transform-member-expression-literals": "npm:^7.25.9" "@babel/plugin-transform-modules-amd": "npm:^7.25.9" - "@babel/plugin-transform-modules-commonjs": "npm:^7.25.9" + "@babel/plugin-transform-modules-commonjs": "npm:^7.26.3" "@babel/plugin-transform-modules-systemjs": "npm:^7.25.9" "@babel/plugin-transform-modules-umd": "npm:^7.25.9" "@babel/plugin-transform-named-capturing-groups-regex": "npm:^7.25.9" "@babel/plugin-transform-new-target": "npm:^7.25.9" - "@babel/plugin-transform-nullish-coalescing-operator": "npm:^7.25.9" + "@babel/plugin-transform-nullish-coalescing-operator": "npm:^7.26.6" "@babel/plugin-transform-numeric-separator": "npm:^7.25.9" "@babel/plugin-transform-object-rest-spread": "npm:^7.25.9" "@babel/plugin-transform-object-super": "npm:^7.25.9" @@ -1354,7 +1332,7 @@ __metadata: "@babel/plugin-transform-spread": "npm:^7.25.9" "@babel/plugin-transform-sticky-regex": "npm:^7.25.9" "@babel/plugin-transform-template-literals": "npm:^7.25.9" - "@babel/plugin-transform-typeof-symbol": "npm:^7.25.9" + "@babel/plugin-transform-typeof-symbol": "npm:^7.26.7" "@babel/plugin-transform-unicode-escapes": "npm:^7.25.9" "@babel/plugin-transform-unicode-property-regex": "npm:^7.25.9" "@babel/plugin-transform-unicode-regex": "npm:^7.25.9" @@ -1367,7 +1345,7 @@ __metadata: semver: "npm:^6.3.1" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 10c0/26e19dc407cfa1c5166be638b4c54239d084fe15d8d7e6306d8c6dc7bc1decc51070a8dcf28352c1a2feeefbe52a06d193a12e302327ad5f529583df75fb7a26 + checksum: 10c0/77d2e46a4f133768c5c8a6b3fec49a7c85c6baec601991e63458921e889ff93911f447723c3a99a6a471ca654ea6dc2aaa7ed690f3e518ee80cea7820ab80ce3 languageName: node linkType: hard @@ -1425,11 +1403,11 @@ __metadata: linkType: hard "@babel/runtime@npm:^7.0.0, @babel/runtime@npm:^7.1.2, @babel/runtime@npm:^7.11.2, @babel/runtime@npm:^7.12.0, @babel/runtime@npm:^7.12.13, @babel/runtime@npm:^7.12.5, @babel/runtime@npm:^7.13.8, @babel/runtime@npm:^7.18.3, @babel/runtime@npm:^7.2.0, @babel/runtime@npm:^7.20.13, @babel/runtime@npm:^7.22.3, @babel/runtime@npm:^7.3.1, @babel/runtime@npm:^7.5.5, @babel/runtime@npm:^7.6.3, @babel/runtime@npm:^7.8.4, @babel/runtime@npm:^7.8.7, @babel/runtime@npm:^7.9.2": - version: 7.26.0 - resolution: "@babel/runtime@npm:7.26.0" + version: 7.26.7 + resolution: "@babel/runtime@npm:7.26.7" dependencies: regenerator-runtime: "npm:^0.14.0" - checksum: 10c0/12c01357e0345f89f4f7e8c0e81921f2a3e3e101f06e8eaa18a382b517376520cd2fa8c237726eb094dab25532855df28a7baaf1c26342b52782f6936b07c287 + checksum: 10c0/60199c049f90e5e41c687687430052a370aca60bac7859ff4ee761c5c1739b8ba1604d391d01588c22dc0e93828cbadb8ada742578ad1b1df240746bce98729a languageName: node linkType: hard @@ -1444,28 +1422,28 @@ __metadata: languageName: node linkType: hard -"@babel/traverse@npm:^7.25.0, @babel/traverse@npm:^7.25.9": - version: 7.25.9 - resolution: "@babel/traverse@npm:7.25.9" +"@babel/traverse@npm:^7.25.0, @babel/traverse@npm:^7.25.9, @babel/traverse@npm:^7.26.7": + version: 7.26.7 + resolution: "@babel/traverse@npm:7.26.7" dependencies: - "@babel/code-frame": "npm:^7.25.9" - "@babel/generator": "npm:^7.25.9" - "@babel/parser": "npm:^7.25.9" + "@babel/code-frame": "npm:^7.26.2" + "@babel/generator": "npm:^7.26.5" + "@babel/parser": "npm:^7.26.7" "@babel/template": "npm:^7.25.9" - "@babel/types": "npm:^7.25.9" + "@babel/types": "npm:^7.26.7" debug: "npm:^4.3.1" globals: "npm:^11.1.0" - checksum: 10c0/e90be586a714da4adb80e6cb6a3c5cfcaa9b28148abdafb065e34cc109676fc3db22cf98cd2b2fff66ffb9b50c0ef882cab0f466b6844be0f6c637b82719bba1 + checksum: 10c0/b23a36ce40d2e4970741431c45d4f92e3f4c2895c0a421456516b2729bd9e17278846e01ee3d9039b0adf5fc5a071768061c17fcad040e74a5c3e39517449d5b languageName: node linkType: hard -"@babel/types@npm:^7.0.0, @babel/types@npm:^7.0.0-beta.49, @babel/types@npm:^7.12.6, @babel/types@npm:^7.20.7, @babel/types@npm:^7.25.0, @babel/types@npm:^7.25.9, @babel/types@npm:^7.26.0, @babel/types@npm:^7.3.3, @babel/types@npm:^7.4.4": - version: 7.26.0 - resolution: "@babel/types@npm:7.26.0" +"@babel/types@npm:^7.0.0, @babel/types@npm:^7.0.0-beta.49, @babel/types@npm:^7.12.6, @babel/types@npm:^7.20.7, @babel/types@npm:^7.25.0, @babel/types@npm:^7.25.9, @babel/types@npm:^7.26.5, @babel/types@npm:^7.26.7, @babel/types@npm:^7.3.3, @babel/types@npm:^7.4.4": + version: 7.26.7 + resolution: "@babel/types@npm:7.26.7" dependencies: "@babel/helper-string-parser": "npm:^7.25.9" "@babel/helper-validator-identifier": "npm:^7.25.9" - checksum: 10c0/b694f41ad1597127e16024d766c33a641508aad037abd08d0d1f73af753e1119fa03b4a107d04b5f92cc19c095a594660547ae9bead1db2299212d644b0a5cb8 + checksum: 10c0/7810a2bca97b13c253f07a0863a628d33dbe76ee3c163367f24be93bfaf4c8c0a325f73208abaaa050a6b36059efc2950c2e4b71fb109c0f07fa62221d8473d4 languageName: node linkType: hard From f73df1f2b058e782cb3ff3e4c4a08d2768db7c90 Mon Sep 17 00:00:00 2001 From: Matt Jankowski Date: Fri, 24 Jan 2025 11:57:55 -0500 Subject: [PATCH 13/42] Fix `Style/HashSlice` cop violations (#33720) --- app/lib/activitypub/adapter.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/lib/activitypub/adapter.rb b/app/lib/activitypub/adapter.rb index 5b9437eb8dad40..9122b07483e99f 100644 --- a/app/lib/activitypub/adapter.rb +++ b/app/lib/activitypub/adapter.rb @@ -17,7 +17,7 @@ def serializable_hash(options = nil) options = serialization_options(options) serialized_hash = serializer.serializable_hash(options.merge(named_contexts: named_contexts, context_extensions: context_extensions)) - serialized_hash = serialized_hash.select { |k, _| options[:fields].include?(k) } if options[:fields] + serialized_hash = serialized_hash.slice(*options[:fields]) if options[:fields] serialized_hash = self.class.transform_key_casing!(serialized_hash, instance_options) { '@context': serialized_context(named_contexts, context_extensions) }.merge(serialized_hash) From 79cbb6160d9e374c6274da7d44de0e663a978a37 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 24 Jan 2025 18:16:22 +0100 Subject: [PATCH 14/42] Update dependency react-select to v5.10.0 (#33722) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- yarn.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/yarn.lock b/yarn.lock index 6b5d879be73645..473300dd48d83a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -14768,8 +14768,8 @@ __metadata: linkType: hard "react-select@npm:^5.7.3": - version: 5.9.0 - resolution: "react-select@npm:5.9.0" + version: 5.10.0 + resolution: "react-select@npm:5.10.0" dependencies: "@babel/runtime": "npm:^7.12.0" "@emotion/cache": "npm:^11.4.0" @@ -14783,7 +14783,7 @@ __metadata: peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 - checksum: 10c0/f21f18ca41a8c866ab69f9c65253e86dcc5323477bbfc729bf6aa9d897e04e27cfffd13c07f10b70dc554e15ad1d238c1283e05e457bf4ead8526a1dd7fbc8b0 + checksum: 10c0/64cc73ef43556d0a199420d7d19f9f72e3c5e3a7f6828aef5421ec16cc0e4bc337061a8fa3c03afc5b929a087a4ca866f497e0ef865b03fe014c5cacde5e71dd languageName: node linkType: hard From 2df86d6413d14c269d630ac39f5f9da1e7f07417 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Fri, 24 Jan 2025 23:20:05 +0100 Subject: [PATCH 15/42] Fix wrong styles on rules and buttons in the sign-up form (#33725) --- app/javascript/styles/mastodon/forms.scss | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/app/javascript/styles/mastodon/forms.scss b/app/javascript/styles/mastodon/forms.scss index b9f86f82a217f9..09ec0e9e41dc39 100644 --- a/app/javascript/styles/mastodon/forms.scss +++ b/app/javascript/styles/mastodon/forms.scss @@ -564,11 +564,14 @@ code { } .stacked-actions { + display: flex; + flex-direction: column; + gap: 10px; margin-top: 30px; margin-bottom: 15px; } - button:not(.button, .link-button, .help-button) { + .btn { display: block; width: 100%; border: 0; @@ -585,8 +588,6 @@ code { cursor: pointer; font-weight: 500; outline: 0; - margin-bottom: 10px; - margin-inline-end: 10px; &:last-child { margin-inline-end: 0; From 52a5c8ae053120f08f91e0d5c594380cebff24ee Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Mon, 27 Jan 2025 09:06:33 +0100 Subject: [PATCH 16/42] Refactor `` into TypeScript (#33723) --- .../compose/components/language_dropdown.jsx | 299 ------------ .../compose/components/language_dropdown.tsx | 427 ++++++++++++++++++ 2 files changed, 427 insertions(+), 299 deletions(-) delete mode 100644 app/javascript/mastodon/features/compose/components/language_dropdown.jsx create mode 100644 app/javascript/mastodon/features/compose/components/language_dropdown.tsx diff --git a/app/javascript/mastodon/features/compose/components/language_dropdown.jsx b/app/javascript/mastodon/features/compose/components/language_dropdown.jsx deleted file mode 100644 index cc97d61415eecc..00000000000000 --- a/app/javascript/mastodon/features/compose/components/language_dropdown.jsx +++ /dev/null @@ -1,299 +0,0 @@ -import PropTypes from 'prop-types'; -import { useCallback, useRef, useState, useEffect, useMemo } from 'react'; - -import { useIntl, defineMessages } from 'react-intl'; - -import classNames from 'classnames'; - -import { createSelector } from '@reduxjs/toolkit'; -import { Map as ImmutableMap } from 'immutable'; - -import { supportsPassiveEvents } from 'detect-passive-events'; -import fuzzysort from 'fuzzysort'; -import Overlay from 'react-overlays/Overlay'; - -import CancelIcon from '@/material-icons/400-24px/cancel-fill.svg?react'; -import SearchIcon from '@/material-icons/400-24px/search.svg?react'; -import TranslateIcon from '@/material-icons/400-24px/translate.svg?react'; -import { changeComposeLanguage } from 'mastodon/actions/compose'; -import { Icon } from 'mastodon/components/icon'; -import { languages as preloadedLanguages } from 'mastodon/initial_state'; -import { useAppSelector, useAppDispatch } from 'mastodon/store'; - -import { debouncedGuess } from '../util/language_detection'; - -const messages = defineMessages({ - changeLanguage: { id: 'compose.language.change', defaultMessage: 'Change language' }, - search: { id: 'compose.language.search', defaultMessage: 'Search languages...' }, - clear: { id: 'emoji_button.clear', defaultMessage: 'Clear' }, -}); - -const listenerOptions = supportsPassiveEvents ? { passive: true, capture: true } : true; - -const getFrequentlyUsedLanguages = createSelector([ - state => state.getIn(['settings', 'frequentlyUsedLanguages'], ImmutableMap()), -], languageCounters => ( - languageCounters.keySeq() - .sort((a, b) => languageCounters.get(a) - languageCounters.get(b)) - .reverse() - .toArray() -)); - -const LanguageDropdownMenu = ({ value, guess, onClose, onChange, languages = preloadedLanguages, intl }) => { - const [searchValue, setSearchValue] = useState(''); - const nodeRef = useRef(null); - const listNodeRef = useRef(null); - - const frequentlyUsedLanguages = useAppSelector(getFrequentlyUsedLanguages); - - const handleSearchChange = useCallback(({ target }) => { - setSearchValue(target.value); - }, [setSearchValue]); - - const handleClick = useCallback((e) => { - const value = e.currentTarget.getAttribute('data-index'); - - e.preventDefault(); - - onClose(); - onChange(value); - }, [onClose, onChange]); - - const handleKeyDown = useCallback(e => { - const index = Array.from(listNodeRef.current.childNodes).findIndex(node => node === e.currentTarget); - - let element = null; - - switch(e.key) { - case 'Escape': - onClose(); - break; - case ' ': - case 'Enter': - handleClick(e); - break; - case 'ArrowDown': - element = listNodeRef.current.childNodes[index + 1] || listNodeRef.current.firstChild; - break; - case 'ArrowUp': - element = listNodeRef.current.childNodes[index - 1] || listNodeRef.current.lastChild; - break; - case 'Tab': - if (e.shiftKey) { - element = listNodeRef.current.childNodes[index - 1] || listNodeRef.current.lastChild; - } else { - element = listNodeRef.current.childNodes[index + 1] || listNodeRef.current.firstChild; - } - break; - case 'Home': - element = listNodeRef.current.firstChild; - break; - case 'End': - element = listNodeRef.current.lastChild; - break; - } - - if (element) { - element.focus(); - e.preventDefault(); - e.stopPropagation(); - } - }, [onClose, handleClick]); - - const handleSearchKeyDown = useCallback(e => { - let element = null; - - switch(e.key) { - case 'Tab': - case 'ArrowDown': - element = listNodeRef.current.firstChild; - - if (element) { - element.focus(); - e.preventDefault(); - e.stopPropagation(); - } - - break; - case 'Enter': - element = listNodeRef.current.firstChild; - - if (element) { - onChange(element.getAttribute('data-index')); - onClose(); - } - break; - case 'Escape': - if (searchValue !== '') { - e.preventDefault(); - this.handleClear(); - } - - break; - } - }, [onChange, onClose, searchValue]); - - const handleClear = useCallback(() => { - setSearchValue(''); - }, [setSearchValue]); - - const isSearching = searchValue !== ''; - - useEffect(() => { - const handleDocumentClick = (e) => { - if (nodeRef.current && !nodeRef.current.contains(e.target)) { - onClose(); - e.stopPropagation(); - } - }; - - document.addEventListener('click', handleDocumentClick, { capture: true }); - document.addEventListener('touchend', handleDocumentClick, listenerOptions); - - // Because of https://github.com/react-bootstrap/react-bootstrap/issues/2614 we need - // to wait for a frame before focusing - requestAnimationFrame(() => { - if (nodeRef.current) { - const element = nodeRef.current.querySelector('input[type="search"]'); - if (element) element.focus(); - } - }); - - return () => { - document.removeEventListener('click', handleDocumentClick, { capture: true }); - document.removeEventListener('touchend', handleDocumentClick, listenerOptions); - }; - }, [onClose]); - - const results = useMemo(() => { - if (searchValue === '') { - return [...languages].sort((a, b) => { - - if (guess && a[0] === guess) { // Push guessed language higher than current selection - return -1; - } else if (guess && b[0] === guess) { - return 1; - } else if (a[0] === value) { // Push current selection to the top of the list - return -1; - } else if (b[0] === value) { - return 1; - } else { - // Sort according to frequently used languages - - const indexOfA = frequentlyUsedLanguages.indexOf(a[0]); - const indexOfB = frequentlyUsedLanguages.indexOf(b[0]); - - return ((indexOfA > -1 ? indexOfA : Infinity) - (indexOfB > -1 ? indexOfB : Infinity)); - } - }); - } - - return fuzzysort.go(searchValue, languages, { - keys: ['0', '1', '2'], - limit: 5, - threshold: -10000, - }).map(result => result.obj); - }, [searchValue, languages, guess, frequentlyUsedLanguages, value]); - - return ( -
    -
    - - -
    - -
    - {results.map((lang) => ( -
    - {lang[2]} ({lang[1]}) -
    - ))} -
    -
    - ); -}; - -LanguageDropdownMenu.propTypes = { - value: PropTypes.string.isRequired, - guess: PropTypes.string, - onClose: PropTypes.func.isRequired, - onChange: PropTypes.func.isRequired, - languages: PropTypes.arrayOf(PropTypes.arrayOf(PropTypes.string)), - intl: PropTypes.object, -}; - -export const LanguageDropdown = () => { - const [open, setOpen] = useState(false); - const [placement, setPlacement] = useState('bottom'); - const [guess, setGuess] = useState(''); - const activeElementRef = useRef(null); - const targetRef = useRef(null); - - const intl = useIntl(); - - const dispatch = useAppDispatch(); - const value = useAppSelector((state) => state.compose.get('language')); - const text = useAppSelector((state) => state.compose.get('text')); - - const current = preloadedLanguages.find(lang => lang[0] === value) ?? []; - - const handleToggle = useCallback(() => { - if (open && activeElementRef.current) - activeElementRef.current.focus({ preventScroll: true }); - - setOpen(!open); - }, [open, setOpen]); - - const handleClose = useCallback(() => { - if (open && activeElementRef.current) - activeElementRef.current.focus({ preventScroll: true }); - - setOpen(false); - }, [open, setOpen]); - - const handleChange = useCallback((value) => { - dispatch(changeComposeLanguage(value)); - }, [dispatch]); - - const handleOverlayEnter = useCallback(({ placement }) => { - setPlacement(placement); - }, [setPlacement]); - - useEffect(() => { - if (text.length > 20) { - debouncedGuess(text, setGuess); - } else { - setGuess(''); - } - }, [text, setGuess]); - - return ( -
    - - - - {({ props, placement }) => ( -
    -
    - -
    -
    - )} -
    -
    - ); -}; diff --git a/app/javascript/mastodon/features/compose/components/language_dropdown.tsx b/app/javascript/mastodon/features/compose/components/language_dropdown.tsx new file mode 100644 index 00000000000000..21c43599816b95 --- /dev/null +++ b/app/javascript/mastodon/features/compose/components/language_dropdown.tsx @@ -0,0 +1,427 @@ +import { useCallback, useRef, useState, useEffect, useMemo } from 'react'; + +import { useIntl, defineMessages } from 'react-intl'; + +import classNames from 'classnames'; + +import { createSelector } from '@reduxjs/toolkit'; +import { Map as ImmutableMap } from 'immutable'; + +import fuzzysort from 'fuzzysort'; +import Overlay from 'react-overlays/Overlay'; +import type { State, Placement } from 'react-overlays/usePopper'; + +import CancelIcon from '@/material-icons/400-24px/cancel-fill.svg?react'; +import SearchIcon from '@/material-icons/400-24px/search.svg?react'; +import TranslateIcon from '@/material-icons/400-24px/translate.svg?react'; +import { changeComposeLanguage } from 'mastodon/actions/compose'; +import { Icon } from 'mastodon/components/icon'; +import { languages as preloadedLanguages } from 'mastodon/initial_state'; +import type { RootState } from 'mastodon/store'; +import { useAppSelector, useAppDispatch } from 'mastodon/store'; + +import { debouncedGuess } from '../util/language_detection'; + +const messages = defineMessages({ + changeLanguage: { + id: 'compose.language.change', + defaultMessage: 'Change language', + }, + search: { + id: 'compose.language.search', + defaultMessage: 'Search languages...', + }, + clear: { id: 'emoji_button.clear', defaultMessage: 'Clear' }, +}); + +type Language = [string, string, string]; + +const getFrequentlyUsedLanguages = createSelector( + [ + (state: RootState) => + (state.settings as ImmutableMap).get( + 'frequentlyUsedLanguages', + ImmutableMap(), + ) as ImmutableMap, + ], + (languageCounters) => + languageCounters + .keySeq() + .sort( + (a, b) => + (languageCounters.get(a) ?? 0) - (languageCounters.get(b) ?? 0), + ) + .reverse() + .toArray(), +); + +const LanguageDropdownMenu: React.FC<{ + value: string; + guess?: string; + onClose: () => void; + onChange: (arg0: string) => void; +}> = ({ value, guess, onClose, onChange }) => { + const languages = preloadedLanguages as Language[]; + const intl = useIntl(); + const [searchValue, setSearchValue] = useState(''); + const nodeRef = useRef(null); + const listNodeRef = useRef(null); + + const frequentlyUsedLanguages = useAppSelector(getFrequentlyUsedLanguages); + + const handleSearchChange = useCallback( + ({ target }: React.ChangeEvent) => { + setSearchValue(target.value); + }, + [setSearchValue], + ); + + const handleClick = useCallback( + (e: React.MouseEvent | React.KeyboardEvent) => { + const value = e.currentTarget.getAttribute('data-index'); + + if (!value) { + return; + } + + e.preventDefault(); + + onClose(); + onChange(value); + }, + [onClose, onChange], + ); + + const handleKeyDown = useCallback( + (e: React.KeyboardEvent) => { + if (!listNodeRef.current) { + return; + } + + const index = Array.from(listNodeRef.current.childNodes).findIndex( + (node) => node === e.currentTarget, + ); + + let element = null; + + switch (e.key) { + case 'Escape': + onClose(); + break; + case ' ': + case 'Enter': + handleClick(e); + break; + case 'ArrowDown': + element = + listNodeRef.current.childNodes[index + 1] ?? + listNodeRef.current.firstChild; + break; + case 'ArrowUp': + element = + listNodeRef.current.childNodes[index - 1] ?? + listNodeRef.current.lastChild; + break; + case 'Tab': + if (e.shiftKey) { + element = + listNodeRef.current.childNodes[index - 1] ?? + listNodeRef.current.lastChild; + } else { + element = + listNodeRef.current.childNodes[index + 1] ?? + listNodeRef.current.firstChild; + } + break; + case 'Home': + element = listNodeRef.current.firstChild; + break; + case 'End': + element = listNodeRef.current.lastChild; + break; + } + + if (element && element instanceof HTMLElement) { + element.focus(); + e.preventDefault(); + e.stopPropagation(); + } + }, + [onClose, handleClick], + ); + + const handleSearchKeyDown = useCallback( + (e: React.KeyboardEvent) => { + let element = null; + + if (!listNodeRef.current) { + return; + } + + switch (e.key) { + case 'Tab': + case 'ArrowDown': + element = listNodeRef.current.firstChild; + + if (element && element instanceof HTMLElement) { + element.focus(); + e.preventDefault(); + e.stopPropagation(); + } + + break; + case 'Enter': + element = listNodeRef.current.firstChild; + + if (element && element instanceof HTMLElement) { + const value = element.getAttribute('data-index'); + + if (value) { + onChange(value); + onClose(); + } + } + break; + case 'Escape': + if (searchValue !== '') { + e.preventDefault(); + setSearchValue(''); + } + + break; + } + }, + [setSearchValue, onChange, onClose, searchValue], + ); + + const handleClear = useCallback(() => { + setSearchValue(''); + }, [setSearchValue]); + + const isSearching = searchValue !== ''; + + useEffect(() => { + const handleDocumentClick = (e: MouseEvent) => { + if ( + nodeRef.current && + e.target instanceof HTMLElement && + !nodeRef.current.contains(e.target) + ) { + onClose(); + e.stopPropagation(); + } + }; + + document.addEventListener('click', handleDocumentClick, { capture: true }); + + // Because of https://github.com/react-bootstrap/react-bootstrap/issues/2614 we need + // to wait for a frame before focusing + requestAnimationFrame(() => { + if (nodeRef.current) { + const element = nodeRef.current.querySelector( + 'input[type="search"]', + ); + if (element) element.focus(); + } + }); + + return () => { + document.removeEventListener('click', handleDocumentClick); + }; + }, [onClose]); + + const results = useMemo(() => { + if (searchValue === '') { + return [...languages].sort((a, b) => { + if (guess && a[0] === guess) { + // Push guessed language higher than current selection + return -1; + } else if (guess && b[0] === guess) { + return 1; + } else if (a[0] === value) { + // Push current selection to the top of the list + return -1; + } else if (b[0] === value) { + return 1; + } else { + // Sort according to frequently used languages + + const indexOfA = frequentlyUsedLanguages.indexOf(a[0]); + const indexOfB = frequentlyUsedLanguages.indexOf(b[0]); + + return ( + (indexOfA > -1 ? indexOfA : Infinity) - + (indexOfB > -1 ? indexOfB : Infinity) + ); + } + }); + } + + return fuzzysort + .go(searchValue, languages, { + keys: ['0', '1', '2'], + limit: 5, + threshold: -10000, + }) + .map((result) => result.obj); + }, [searchValue, languages, guess, frequentlyUsedLanguages, value]); + + return ( +
    +
    + + +
    + +
    + {results.map((lang) => ( +
    + + {lang[2]} + {' '} + + ({lang[1]}) + +
    + ))} +
    +
    + ); +}; + +export const LanguageDropdown: React.FC = () => { + const [open, setOpen] = useState(false); + const [placement, setPlacement] = useState('bottom'); + const [guess, setGuess] = useState(''); + const activeElementRef = useRef(null); + const targetRef = useRef(null); + + const intl = useIntl(); + + const dispatch = useAppDispatch(); + const value = useAppSelector( + (state) => state.compose.get('language') as string, + ); + const text = useAppSelector((state) => state.compose.get('text') as string); + + const current = + (preloadedLanguages as Language[]).find((lang) => lang[0] === value) ?? []; + + const handleMouseDown = useCallback(() => { + if (!open && document.activeElement instanceof HTMLElement) { + activeElementRef.current = document.activeElement; + } + }, [open]); + + const handleToggle = useCallback(() => { + if (open && activeElementRef.current) + activeElementRef.current.focus({ preventScroll: true }); + + setOpen(!open); + }, [open, setOpen]); + + const handleClose = useCallback(() => { + if (open && activeElementRef.current) + activeElementRef.current.focus({ preventScroll: true }); + + setOpen(false); + }, [open, setOpen]); + + const handleChange = useCallback( + (value: string) => { + dispatch(changeComposeLanguage(value)); + }, + [dispatch], + ); + + const handleOverlayEnter = useCallback( + (state: Partial) => { + setPlacement(state.placement); + }, + [setPlacement], + ); + + useEffect(() => { + if (text.length > 20) { + debouncedGuess(text, setGuess); + } else { + setGuess(''); + } + }, [text, setGuess]); + + return ( +
    + + + + {({ props, placement }) => ( +
    +
    + +
    +
    + )} +
    +
    + ); +}; From 81271a18c596e940f01608739de749f4375b6e60 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Mon, 27 Jan 2025 09:08:31 +0100 Subject: [PATCH 17/42] Fix color of language indicator in light theme in web UI (#33724) --- app/javascript/styles/mastodon-light/diff.scss | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/app/javascript/styles/mastodon-light/diff.scss b/app/javascript/styles/mastodon-light/diff.scss index 2d2c0c2bcaa44f..d23d789e4664e7 100644 --- a/app/javascript/styles/mastodon-light/diff.scss +++ b/app/javascript/styles/mastodon-light/diff.scss @@ -451,6 +451,15 @@ background: darken($ui-base-color, 10%); } +.dropdown-button.warning { + border-color: #b3261e; + color: #b3261e; + + &.active { + background-color: #f9dedc; + } +} + .search__popout__menu__item { &:hover, &:active, From 956873362edb33e0089367b279f03bb42e0f1829 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Mon, 27 Jan 2025 09:17:59 +0100 Subject: [PATCH 18/42] Remove system tooltip for alt text in web UI (#33736) --- app/javascript/mastodon/components/media_gallery.jsx | 2 -- .../features/account_gallery/components/media_item.tsx | 3 --- 2 files changed, 5 deletions(-) diff --git a/app/javascript/mastodon/components/media_gallery.jsx b/app/javascript/mastodon/components/media_gallery.jsx index 95b06abc548466..51323166000815 100644 --- a/app/javascript/mastodon/components/media_gallery.jsx +++ b/app/javascript/mastodon/components/media_gallery.jsx @@ -145,7 +145,6 @@ class Item extends PureComponent { srcSet={srcSet} sizes={sizes} alt={description} - title={description} lang={lang} style={{ objectPosition: `${x}% ${y}%` }} onLoad={this.handleImageLoad} @@ -167,7 +166,6 @@ class Item extends PureComponent {