Merge remote-tracking branch 'parent/main' into upstream-20231021

This commit is contained in:
KMY 2023-10-23 18:48:26 +09:00
commit 46a1e62dc4
37 changed files with 154 additions and 157 deletions

View file

@ -1,7 +1,7 @@
import { render, fireEvent, screen } from '@testing-library/react';
import renderer from 'react-test-renderer';
import Button from '../button';
import { Button } from '../button';
describe('<Button />', () => {
it('renders a button element', () => {

View file

@ -15,7 +15,7 @@ import { VerifiedBadge } from 'mastodon/components/verified_badge';
import { me } from '../initial_state';
import { Avatar } from './avatar';
import Button from './button';
import { Button } from './button';
import { FollowersCounter } from './counters';
import { DisplayName } from './display_name';
import { IconButton } from './icon_button';

View file

@ -1,58 +0,0 @@
import PropTypes from 'prop-types';
import { PureComponent } from 'react';
import classNames from 'classnames';
export default class Button extends PureComponent {
static propTypes = {
text: PropTypes.node,
type: PropTypes.string,
onClick: PropTypes.func,
disabled: PropTypes.bool,
block: PropTypes.bool,
secondary: PropTypes.bool,
className: PropTypes.string,
title: PropTypes.string,
children: PropTypes.node,
};
static defaultProps = {
type: 'button',
};
handleClick = (e) => {
if (!this.props.disabled && this.props.onClick) {
this.props.onClick(e);
}
};
setRef = (c) => {
this.node = c;
};
focus() {
this.node.focus();
}
render () {
const className = classNames('button', this.props.className, {
'button-secondary': this.props.secondary,
'button--block': this.props.block,
});
return (
<button
className={className}
disabled={this.props.disabled}
onClick={this.handleClick}
ref={this.setRef}
title={this.props.title}
type={this.props.type}
>
{this.props.text || this.props.children}
</button>
);
}
}

View file

@ -0,0 +1,58 @@
import { useCallback } from 'react';
import classNames from 'classnames';
interface BaseProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {
block?: boolean;
secondary?: boolean;
text?: JSX.Element;
}
interface PropsWithChildren extends BaseProps {
text?: never;
}
interface PropsWithText extends BaseProps {
text: JSX.Element;
children: never;
}
type Props = PropsWithText | PropsWithChildren;
export const Button: React.FC<Props> = ({
text,
type = 'button',
onClick,
disabled,
block,
secondary,
className,
title,
children,
...props
}) => {
const handleClick = useCallback<React.MouseEventHandler<HTMLButtonElement>>(
(e) => {
if (!disabled && onClick) {
onClick(e);
}
},
[disabled, onClick],
);
return (
<button
className={classNames('button', className, {
'button-secondary': secondary,
'button--block': block,
})}
disabled={disabled}
onClick={handleClick}
title={title}
type={type}
{...props}
>
{text ?? children}
</button>
);
};

View file

@ -12,7 +12,7 @@ import { HotKeys } from 'react-hotkeys';
import AttachmentList from 'mastodon/components/attachment_list';
import { Icon } from 'mastodon/components/icon';
import PictureInPicturePlaceholder from 'mastodon/components/picture_in_picture_placeholder';
import { withOptionalRouter, WithRouterPropTypes } from 'mastodon/utils/react_router';
import { withOptionalRouter, WithOptionalRouterPropTypes } from 'mastodon/utils/react_router';
import CompactedStatusContainer from '../containers/compacted_status_container';
import Card from '../features/status/components/card';
@ -127,7 +127,7 @@ class Status extends ImmutablePureComponent {
available: PropTypes.bool,
}),
withoutEmojiReactions: PropTypes.bool,
...WithRouterPropTypes,
...WithOptionalRouterPropTypes,
};
// Avoid checking props that are functions (and whose equality will always

View file

@ -11,7 +11,7 @@ import ImmutablePureComponent from 'react-immutable-pure-component';
import { Avatar } from 'mastodon/components/avatar';
import { Badge, AutomatedBadge, GroupBadge } from 'mastodon/components/badge';
import Button from 'mastodon/components/button';
import { Button } from 'mastodon/components/button';
import { FollowersCounter, FollowingCounter, StatusesCounter } from 'mastodon/components/counters';
import { Icon } from 'mastodon/components/icon';
import { IconButton } from 'mastodon/components/icon_button';

View file

@ -6,7 +6,7 @@ import { FormattedMessage } from 'react-intl';
import { connect } from 'react-redux';
import { revealAccount } from 'mastodon/actions/accounts';
import Button from 'mastodon/components/button';
import { Button } from 'mastodon/components/button';
import { domain } from 'mastodon/initial_state';
const mapDispatchToProps = (dispatch, { accountId }) => ({

View file

@ -14,7 +14,7 @@ import { WithOptionalRouterPropTypes, withOptionalRouter } from 'mastodon/utils/
import AutosuggestInput from '../../../components/autosuggest_input';
import AutosuggestTextarea from '../../../components/autosuggest_textarea';
import Button from '../../../components/button';
import { Button } from '../../../components/button';
import CircleSelectContainer from '../containers/circle_select_container';
import EmojiPickerDropdown from '../containers/emoji_picker_dropdown_container';
import ExpirationDropdownContainer from '../containers/expiration_dropdown_container';

View file

@ -17,7 +17,7 @@ import {
} from 'mastodon/actions/accounts';
import { openModal } from 'mastodon/actions/modal';
import { Avatar } from 'mastodon/components/avatar';
import Button from 'mastodon/components/button';
import { Button } from 'mastodon/components/button';
import { DisplayName } from 'mastodon/components/display_name';
import { ShortNumber } from 'mastodon/components/short_number';
import { autoPlayGif, me, unfollowModal } from 'mastodon/initial_state';

View file

@ -6,7 +6,7 @@ import { FormattedMessage } from 'react-intl';
import ImmutablePropTypes from 'react-immutable-proptypes';
import { connect } from 'react-redux';
import Button from 'mastodon/components/button';
import { Button } from 'mastodon/components/button';
import { toServerSideType } from 'mastodon/utils/filters';
const mapStateToProps = (state, { filterId }) => ({

View file

@ -4,7 +4,7 @@ import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
import ImmutablePropTypes from 'react-immutable-proptypes';
import Button from 'mastodon/components/button';
import { Button } from 'mastodon/components/button';
import { ShortNumber } from 'mastodon/components/short_number';
const messages = defineMessages({

View file

@ -11,7 +11,7 @@ import { throttle, escapeRegExp } from 'lodash';
import { openModal, closeModal } from 'mastodon/actions/modal';
import api from 'mastodon/api';
import Button from 'mastodon/components/button';
import { Button } from 'mastodon/components/button';
import { Icon } from 'mastodon/components/icon';
import { registrationsOpen, sso_redirect } from 'mastodon/initial_state';

View file

@ -6,7 +6,7 @@ import { defineMessages, injectIntl } from 'react-intl';
import { connect } from 'react-redux';
import { changeListEditorTitle, submitListEditor } from 'mastodon/actions/lists';
import Button from 'mastodon/components/button';
import { Button } from 'mastodon/components/button';
const messages = defineMessages({
label: { id: 'lists.new.title_placeholder', defaultMessage: 'New list title' },

View file

@ -7,7 +7,7 @@ import { connect } from 'react-redux';
import { requestBrowserPermission } from 'mastodon/actions/notifications';
import { changeSetting } from 'mastodon/actions/settings';
import Button from 'mastodon/components/button';
import { Button } from 'mastodon/components/button';
import { Icon } from 'mastodon/components/icon';
import { IconButton } from 'mastodon/components/icon_button';

View file

@ -7,7 +7,7 @@ import { List as ImmutableList } from 'immutable';
import ImmutablePropTypes from 'react-immutable-proptypes';
import { connect } from 'react-redux';
import Button from 'mastodon/components/button';
import { Button } from 'mastodon/components/button';
import Option from './components/option';

View file

@ -11,7 +11,7 @@ import { createSelector } from 'reselect';
import Toggle from 'react-toggle';
import { fetchAccount } from 'mastodon/actions/accounts';
import Button from 'mastodon/components/button';
import { Button } from 'mastodon/components/button';
import { useAppDispatch, useAppSelector } from 'mastodon/store';
const messages = defineMessages({

View file

@ -6,7 +6,7 @@ import { FormattedMessage } from 'react-intl';
import ImmutablePropTypes from 'react-immutable-proptypes';
import { connect } from 'react-redux';
import Button from 'mastodon/components/button';
import { Button } from 'mastodon/components/button';
import Option from './components/option';

View file

@ -7,7 +7,7 @@ import { OrderedSet } from 'immutable';
import ImmutablePropTypes from 'react-immutable-proptypes';
import { connect } from 'react-redux';
import Button from 'mastodon/components/button';
import { Button } from 'mastodon/components/button';
import { LoadingIndicator } from 'mastodon/components/loading_indicator';
import StatusCheckBox from 'mastodon/features/report/containers/status_check_box_container';

View file

@ -11,7 +11,7 @@ import {
muteAccount,
blockAccount,
} from 'mastodon/actions/accounts';
import Button from 'mastodon/components/button';
import { Button } from 'mastodon/components/button';
const mapStateToProps = () => ({});

View file

@ -9,7 +9,7 @@ import { connect } from 'react-redux';
import { createSelector } from 'reselect';
import { followAccount } from 'mastodon/actions/accounts';
import Button from 'mastodon/components/button';
import { Button } from 'mastodon/components/button';
import { IconButton } from 'mastodon/components/icon_button';
import Option from 'mastodon/features/report/components/option';
import { languages as preloadedLanguages } from 'mastodon/initial_state';

View file

@ -8,7 +8,7 @@ import { connect } from 'react-redux';
import { blockAccount } from '../../../actions/accounts';
import { closeModal } from '../../../actions/modal';
import { initReport } from '../../../actions/reports';
import Button from '../../../components/button';
import { Button } from '../../../components/button';
import { makeGetAccount } from '../../../selectors';
const makeMapStateToProps = () => {
@ -51,10 +51,6 @@ class BlockModal extends PureComponent {
intl: PropTypes.object.isRequired,
};
componentDidMount() {
this.button.focus();
}
handleClick = () => {
this.props.onClose();
this.props.onConfirm(this.props.account);
@ -69,10 +65,6 @@ class BlockModal extends PureComponent {
this.props.onClose();
};
setRef = (c) => {
this.button = c;
};
render () {
const { account } = this.props;
@ -95,7 +87,7 @@ class BlockModal extends PureComponent {
<Button onClick={this.handleSecondary} className='confirmation-modal__secondary-button'>
<FormattedMessage id='confirmations.block.block_and_report' defaultMessage='Block & Report' />
</Button>
<Button onClick={this.handleClick} ref={this.setRef}>
<Button onClick={this.handleClick} autoFocus>
<FormattedMessage id='confirmations.block.confirm' defaultMessage='Block' />
</Button>
</div>

View file

@ -16,7 +16,7 @@ import PrivacyDropdown from 'mastodon/features/compose/components/privacy_dropdo
import { WithRouterPropTypes } from 'mastodon/utils/react_router';
import { Avatar } from '../../../components/avatar';
import Button from '../../../components/button';
import { Button } from '../../../components/button';
import { DisplayName } from '../../../components/display_name';
import { RelativeTimestamp } from '../../../components/relative_timestamp';
import StatusContent from '../../../components/status_content';
@ -61,10 +61,6 @@ class BoostModal extends ImmutablePureComponent {
...WithRouterPropTypes,
};
componentDidMount() {
this.button.focus();
}
handleReblog = () => {
this.props.onReblog(this.props.status, this.props.privacy);
this.props.onClose();
@ -82,10 +78,6 @@ class BoostModal extends ImmutablePureComponent {
return document.getElementsByClassName('modal-root__container')[0];
};
setRef = (c) => {
this.button = c;
};
render () {
const { status, privacy, intl } = this.props;
const buttonText = status.get('reblogged') ? messages.cancel_reblog : messages.reblog;
@ -145,7 +137,7 @@ class BoostModal extends ImmutablePureComponent {
onChange={this.props.onChangeBoostPrivacy}
/>
)}
<Button text={intl.formatMessage(buttonText)} onClick={this.handleReblog} ref={this.setRef} />
<Button text={intl.formatMessage(buttonText)} onClick={this.handleReblog} autoFocus />
</div>
</div>
);

View file

@ -7,7 +7,7 @@ import classNames from 'classnames';
import { Helmet } from 'react-helmet';
import { Link } from 'react-router-dom';
import Button from 'mastodon/components/button';
import { Button } from 'mastodon/components/button';
import Column from 'mastodon/components/column';
import { autoPlayGif } from 'mastodon/initial_state';

View file

@ -3,7 +3,7 @@ import { PureComponent } from 'react';
import { injectIntl, FormattedMessage } from 'react-intl';
import Button from '../../../components/button';
import { Button } from '../../../components/button';
class ConfirmationModal extends PureComponent {
@ -22,10 +22,6 @@ class ConfirmationModal extends PureComponent {
closeWhenConfirm: true,
};
componentDidMount() {
this.button.focus();
}
handleClick = () => {
if (this.props.closeWhenConfirm) {
this.props.onClose();
@ -42,10 +38,6 @@ class ConfirmationModal extends PureComponent {
this.props.onClose();
};
setRef = (c) => {
this.button = c;
};
render () {
const { message, confirm, secondary } = this.props;
@ -62,7 +54,7 @@ class ConfirmationModal extends PureComponent {
{secondary !== undefined && (
<Button text={secondary} onClick={this.handleSecondary} className='confirmation-modal__secondary-button' />
)}
<Button text={confirm} onClick={this.handleClick} ref={this.setRef} />
<Button text={confirm} onClick={this.handleClick} autoFocus />
</div>
</div>
);

View file

@ -16,7 +16,7 @@ import tesseractWorkerPath from 'tesseract.js/dist/worker.min.js';
// eslint-disable-next-line import/no-extraneous-dependencies
import tesseractCorePath from 'tesseract.js-core/tesseract-core.wasm.js';
import Button from 'mastodon/components/button';
import { Button } from 'mastodon/components/button';
import { GIFV } from 'mastodon/components/gifv';
import { IconButton } from 'mastodon/components/icon_button';
import Audio from 'mastodon/features/audio';

View file

@ -10,7 +10,7 @@ import Toggle from 'react-toggle';
import { muteAccount } from '../../../actions/accounts';
import { closeModal } from '../../../actions/modal';
import { toggleHideNotifications, changeMuteDuration } from '../../../actions/mutes';
import Button from '../../../components/button';
import { Button } from '../../../components/button';
const messages = defineMessages({
minutes: { id: 'intervals.full.minutes', defaultMessage: '{number, plural, one {# minute} other {# minutes}}' },
@ -63,10 +63,6 @@ class MuteModal extends PureComponent {
onChangeMuteDuration: PropTypes.func.isRequired,
};
componentDidMount() {
this.button.focus();
}
handleClick = () => {
this.props.onClose();
this.props.onConfirm(this.props.account, this.props.notifications, this.props.muteDuration);
@ -76,10 +72,6 @@ class MuteModal extends PureComponent {
this.props.onClose();
};
setRef = (c) => {
this.button = c;
};
toggleNotifications = () => {
this.props.onToggleNotifications();
};
@ -134,7 +126,7 @@ class MuteModal extends PureComponent {
<Button onClick={this.handleCancel} className='mute-modal__cancel-button'>
<FormattedMessage id='confirmation_modal.cancel' defaultMessage='Cancel' />
</Button>
<Button onClick={this.handleClick} ref={this.setRef}>
<Button onClick={this.handleClick} autoFocus>
<FormattedMessage id='confirmations.mute.confirm' defaultMessage='Mute' />
</Button>
</div>

View file

@ -163,13 +163,13 @@
"confirmation_modal.cancel": "Annulearje",
"confirmations.block.block_and_report": "Blokkearje en rapportearje",
"confirmations.block.confirm": "Blokkearje",
"confirmations.block.message": "Bisto wis datsto {name} blokkearje wolst?",
"confirmations.block.message": "Binne jo wis dat jo {name} blokkearje wolle?",
"confirmations.cancel_follow_request.confirm": "Fersyk annulearje",
"confirmations.cancel_follow_request.message": "Binne jo wis dat jo jo fersyk om {name} te folgjen annulearje wolle?",
"confirmations.delete.confirm": "Fuortsmite",
"confirmations.delete.message": "Binne jo wis dat jo dit berjocht fuortsmite wolle?",
"confirmations.delete_list.confirm": "Fuortsmite",
"confirmations.delete_list.message": "Bisto wis datsto dizze list foar permanint fuortsmite wolst?",
"confirmations.delete_list.message": "Binne jo wis dat jo dizze list foar permanint fuortsmite wolle?",
"confirmations.discard_edit_media.confirm": "Fuortsmite",
"confirmations.discard_edit_media.message": "Jo hawwe net-bewarre wizigingen yn de mediabeskriuwing of foarfertoaning, wolle jo dizze dochs fuortsmite?",
"confirmations.domain_block.confirm": "Alles fan dit domein blokkearje",
@ -177,16 +177,16 @@
"confirmations.edit.confirm": "Bewurkje",
"confirmations.edit.message": "Troch no te bewurkjen sil it berjocht dat jo no oan it skriuwen binne oerskreaun wurde. Wolle jo trochgean?",
"confirmations.logout.confirm": "Ofmelde",
"confirmations.logout.message": "Bisto wis datsto ôfmelde wolst?",
"confirmations.logout.message": "Binne jo wis dat jo ôfmelde wolle?",
"confirmations.mute.confirm": "Negearje",
"confirmations.mute.explanation": "Dit sil berjochten fan harren en berjochten dêrt se yn fermeld wurde ûnsichtber meitsje, mar se sille berjochten noch hieltyd sjen kinne en jo folgje kinne.",
"confirmations.mute.explanation": "Dit sil berjochten fan harren en berjochten dêrt se yn fermeld wurde ûnsichtber meitsje, mar se sille jo berjochten noch hieltyd sjen kinne en jo folgje kinne.",
"confirmations.mute.message": "Binne jo wis dat jo {name} negearje wolle?",
"confirmations.redraft.confirm": "Fuortsmite en opnij opstelle",
"confirmations.redraft.message": "Binne jo wis dat jo dit berjocht fuortsmite en opnij opstelle wolle? Favoriten en boosts geane dan ferlern en reaksjes op it oarspronklike berjocht reitsje jo kwyt.",
"confirmations.reply.confirm": "Reagearje",
"confirmations.reply.message": "Troch no te reagearjen sil it berjocht dat jo no oan it skriuwen binne oerskreaun wurde. Wolle jo trochgean?",
"confirmations.unfollow.confirm": "Net mear folgje",
"confirmations.unfollow.message": "Bisto wis datsto {name} net mear folgje wolst?",
"confirmations.unfollow.message": "Binne jo wis dat jo {name} net mear folgje wolle?",
"conversation.delete": "Petear fuortsmite",
"conversation.mark_as_read": "As lêzen markearje",
"conversation.open": "Petear toane",
@ -351,7 +351,7 @@
"keyboard_shortcuts.local": "to open local timeline",
"keyboard_shortcuts.mention": "Skriuwer fermelde",
"keyboard_shortcuts.muted": "to open muted users list",
"keyboard_shortcuts.my_profile": "Dyn profyl iepenje",
"keyboard_shortcuts.my_profile": "Jo profyl iepenje",
"keyboard_shortcuts.notifications": "Meldingen toane",
"keyboard_shortcuts.open_media": "Media iepenje",
"keyboard_shortcuts.pinned": "Fêstsette berjochten toane",
@ -421,20 +421,20 @@
"navigation_bar.public_timeline": "Globale tiidline",
"navigation_bar.search": "Sykje",
"navigation_bar.security": "Befeiliging",
"not_signed_in_indicator.not_signed_in": "Do moatst oanmelde om tagong ta dizze ynformaasje te krijen.",
"not_signed_in_indicator.not_signed_in": "Jo moatte oanmelde om tagong ta dizze ynformaasje te krijen.",
"notification.admin.report": "{name} hat {target} rapportearre",
"notification.admin.sign_up": "{name} hat harren registrearre",
"notification.favourite": "{name} hat jo berjocht as favoryt markearre",
"notification.follow": "{name} folget dy",
"notification.follow_request": "{name} hat dy in folchfersyk stjoerd",
"notification.mention": "{name} hat dy fermeld",
"notification.own_poll": "Dyn poll is beëinige",
"notification.own_poll": "Jo poll is beëinige",
"notification.poll": "In enkête dêrt jo yn stimd hawwe is beëinige",
"notification.reblog": "{name} hat jo berjocht boost",
"notification.status": "{name} hat in berjocht pleatst",
"notification.update": "{name} hat in berjocht bewurke",
"notifications.clear": "Meldingen wiskje",
"notifications.clear_confirmation": "Bisto wis datsto al dyn meldingen permanint fuortsmite wolst?",
"notifications.clear_confirmation": "Binne jo wis dat jo al jo meldingen permanint fuortsmite wolle?",
"notifications.column_settings.admin.report": "Nije rapportaazjes:",
"notifications.column_settings.admin.sign_up": "Nije registraasjes:",
"notifications.column_settings.alert": "Desktopmeldingen",

View file

@ -114,7 +114,7 @@
"column.directory": "瀏覽個人檔案",
"column.domain_blocks": "已封鎖網域",
"column.favourites": "最愛",
"column.firehose": "即時河道",
"column.firehose": "即時內容",
"column.follow_requests": "跟隨請求",
"column.home": "首頁",
"column.lists": "列表",
@ -629,7 +629,7 @@
"status.edit": "編輯",
"status.edited": "編輯於 {date}",
"status.edited_x_times": "已編輯 {count, plural, one {{count} 次} other {{count} 次}}",
"status.embed": "內嵌",
"status.embed": "內嵌嘟文",
"status.favourite": "最愛",
"status.filter": "過濾此嘟文",
"status.filtered": "已過濾",

View file

@ -49,6 +49,7 @@ export function withOptionalRouter(Component) {
C.displayName = displayName;
C.WrappedComponent = Component;
C.propTypes = {
...Component.propTypes,
wrappedComponentRef: PropTypes.oneOfType([
PropTypes.string,
PropTypes.func,

View file

@ -55,7 +55,7 @@ class PreviewCard < ApplicationRecord
has_attached_file :image, processors: [:thumbnail, :blurhash_transcoder], styles: ->(f) { image_styles(f) }, convert_options: { all: '-quality 90 +profile "!icc,*" +set date:modify +set date:create +set date:timestamp' }, validate_media_type: false
validates :url, presence: true, uniqueness: true
validates :url, presence: true, uniqueness: true, url: true
validates_attachment_content_type :image, content_type: IMAGE_MIME_TYPES
validates_attachment_size :image, less_than: LIMIT
remotable_attachment :image, LIMIT

View file

@ -36,7 +36,7 @@ zh-CN:
status:
attributes:
reblog:
taken: 被转嘟过
taken: 被转嘟过
user:
attributes:
email:

View file

@ -13,7 +13,7 @@ fy:
locked: Jo account is blokkearre.
not_found_in_database: "%{authentication_keys} of wachtwurd ûnjildich."
pending: Jo account moat noch hieltyd beoardiele wurde.
timeout: Dyn sesje is ferrûn, meld dy opnij oan.
timeout: Jo sesje is ferrûn. Meld jo opnij oan om troch te gean.
unauthenticated: Jo moatte oanmelde of registrearje.
unconfirmed: Jo moatte earst jo account befêstigje.
mailer:

View file

@ -9,7 +9,7 @@ zh-CN:
already_authenticated: 你已登录。
inactive: 你还没有激活账户。
invalid: "%{authentication_keys} 无效或密码错误。"
last_attempt: 你只有最后一次尝试机会,若未通过,号将被锁定。
last_attempt: 你只有最后一次尝试机会,若未通过,号将被锁定。
locked: 你的账户已被锁定。
not_found_in_database: "%{authentication_keys}或密码错误。"
pending: 你的账号仍在审核中。
@ -85,7 +85,7 @@ zh-CN:
send_instructions: 如果你的电子邮件地址存在于我们的数据库中,你将在几分钟后收到一个密码恢复链接。如果你没有收到这封邮件,请检查你邮箱的垃圾箱。
send_paranoid_instructions: 如果你的电子邮件地址存在于我们的数据库中,你将在几分钟后收到一个密码恢复链接。如果你没有收到这封邮件,请检查你邮箱的垃圾箱。
updated: 你的密码已成功修改,现在你已登录。
updated_not_active: 你的密码已成功修改。
updated_not_active: 你的密码已修改成功
registrations:
destroyed: 再见!你的账户已成功注销。我们希望很快可以再见到你。
signed_up: 欢迎!你已成功注册。

View file

@ -43,7 +43,7 @@ fy:
new: Nije tapassing
scopes: Tastimmingen
show: Toane
title: Dyn tapassingen
title: Jo tapassingen
new:
title: Nije tapassing
show:
@ -60,7 +60,7 @@ fy:
error:
title: Der is in flater bard
new:
prompt_html: "%{client_name} hat tastimming nedich om tagong te krijen ta dyn account. It giet om in tapassing fan in tredde partij.<strong>Asto dit net fertroust, moatsto gjin tastimming jaan.</strong>"
prompt_html: "%{client_name} hat tastimming nedich om tagong te krijen ta jo account. It giet om in tapassing fan in tredde partij.<strong>As jo dit net fertrouwe, moatte jo gjin tastimming jaan.</strong>"
review_permissions: Tastimmingen beoardiele
title: Autorisaasje fereaske
show:
@ -69,15 +69,15 @@ fy:
buttons:
revoke: Ynlûke
confirmations:
revoke: Bisto wis?
revoke: Binne jo wis?
index:
authorized_at: Autorisearre op %{date}
description_html: Dit binne tapassingen dyt tagong hawwe ta dyn account fia de API. As der tapassingen tusken steane dytsto net werkenst of in tapassing harren misdraacht, kinsto de tagongsrjochten fan de tapassing ynlûke.
description_html: Dit binne tapassingen dyt fia de API tagong hawwe ta jo account. As der tapassingen tusken steane dyt jo net werkenne of in tapassing harren misdraacht, kinne jo de tagongsrjochten fan de tapassing ynlûke.
last_used_at: Lêst brûkt op %{date}
never_used: Nea brûkt
scopes: Tastimmingen
superapp: Yntern
title: Dyn autorisearre tapassingen
title: Jo autorisearre tapassingen
errors:
messages:
access_denied: De boarne-eigener of autorisaasjeserver hat it fersyk wegere.
@ -165,22 +165,22 @@ fy:
admin:write:reports: moderaasjemaatregelen nimme yn rapportaazjes
crypto: ein-ta-ein-fersifering brûke
follow: relaasjes tusken accounts bewurkje
push: dyn pushmeldingen ûntfange
read: alle gegevens fan dyn account lêze
push: jo pushmeldingen ûntfange
read: alle gegevens fan jo account lêze
read:accounts: accountynformaasje besjen
read:blocks: dyn blokkearre brûkers besjen
read:bookmarks: dyn blêdwizers besjen
read:blocks: jo blokkearre brûkers besjen
read:bookmarks: jo blêdwizers besjen
read:favourites: jo favoriten besjen
read:filters: dyn filters besjen
read:filters: jo filters besjen
read:follows: de accounts dytsto folgest besjen
read:lists: dyn listen besjen
read:mutes: dyn negearre brûkers besjen
read:notifications: dyn meldingen besjen
read:reports: dyn rapportearre berjochten besjen
read:search: út dyn namme sykje
read:lists: jo listen besjen
read:mutes: jo negearre brûkers besjen
read:notifications: jo meldingen besjen
read:reports: jo rapportearre berjochten besjen
read:search: út jo namme sykje
read:statuses: alle berjochten besjen
write: alle gegevens fan dyn account bewurkje
write:accounts: dyn profyl bewurkje
write: alle gegevens fan jo account bewurkje
write:accounts: jo profyl bewurkje
write:blocks: accounts en domeinen blokkearje
write:bookmarks: berjochten oan blêdwizers tafoegje
write:conversations: petearen negearre en fuortsmite

View file

@ -86,7 +86,7 @@ fy:
media_cache_retention_period: Mediabestannen dyt fan oare servers download binne wurde nei it opjûne oantal dagen fuortsmiten en wurde op fersyk opnij download.
peers_api_enabled: In list mei domeinnammen, dêrt dizze server yn fediverse kontakt hân mei hat. Hjir wurdt gjin data dield, oft jo mei in bepaalde server federearrest, mar alinnich, dat jo server dat wit. Dit wurdt foar tsjinsten brûkt, dyt statistiken oer federaasje yn algemiene sin sammelet.
profile_directory: De brûkersgids befettet in list fan alle brûkers dy¥t derfoar keazen hawwe om ûntdekt wurde te kinnen.
require_invite_text: Meitsje it ynfoljen fan "Wêrom wolle jo jo hjir registrearje?" ferplicht yn stee fan opsjoneel, wanneart registraasjes hânmjittich goedkard wurde moatte
require_invite_text: Meitsje it ynfoljen fan Wêrom wolle jo jo hjir registrearje? ferplicht yn stee fan opsjoneel, wanneart registraasjes hânmjittich goedkard wurde moatte
site_contact_email: Hoe minsken jo berikke kinne foar juridyske fragen of stipe.
site_contact_username: Hoe minsken jo op Mastodon berikke kinne.
site_extended_description: Alle oanfoljende ynformaasje dyt nuttich wêze kin foar besikers en jo brûkers. Kin opmakke wurde mei Markdown.

View file

@ -40,7 +40,7 @@ zh-CN:
current_email: 当前的电子邮箱
label: 更改电子邮箱
new_email: 新的电子邮箱
submit: 更改电子邮件地址
submit: 更改电子邮
title: 更改 %{username} 的电子邮箱
change_role:
changed_msg: 已成功更改角色!
@ -68,8 +68,8 @@ zh-CN:
enable_sign_in_token_auth: 启用电子邮件令牌认证
enabled: 已启用
enabled_msg: 成功解冻 %{username} 的账号
followers: 关注者
follows: 正在关注
followers: 粉丝
follows: 关注
header: 个人资料页横幅图片
inbox_url: 收件箱InboxURL
invite_request_text: 加入理由

View file

@ -0,0 +1,28 @@
# frozen_string_literal: true
require 'rails_helper'
describe PreviewCard do
describe 'validations' do
describe 'urls' do
it 'allows http schemes' do
record = described_class.new(url: 'http://example.host/path')
expect(record).to be_valid
end
it 'allows https schemes' do
record = described_class.new(url: 'https://example.host/path')
expect(record).to be_valid
end
it 'does not allow javascript: schemes' do
record = described_class.new(url: 'javascript:alert()')
expect(record).to_not be_valid
expect(record).to model_have_error_on_field(:url)
end
end
end
end