mirror of
https://github.com/glitch-soc/mastodon.git
synced 2024-11-30 03:50:13 -05:00
Merge commit '24ef8255b3f9b44cb54f49bc78fe3382a7070b1a' into glitch-soc/merge-upstream
Conflicts: - `app/helpers/accounts_helper.rb`: Upstream removed a helper, textually adjacent to a glitch-soc-only one. Not really a conflict. Removed the helper as upstream did. - `app/views/layouts/embedded.html.haml`: Conflicts due to theming system. Adapted upstream's change to our theming system. - `app/views/statuses/_simple_status.html.haml`: Removed upstream, but we had local changes. Removed as upstream did.
This commit is contained in:
commit
3465d39494
@ -19,14 +19,6 @@ module AccountsHelper
|
||||
end
|
||||
end
|
||||
|
||||
def account_action_button(account)
|
||||
return if account.memorial? || account.moved?
|
||||
|
||||
link_to ActivityPub::TagManager.instance.url_for(account), class: 'button logo-button', target: '_new' do
|
||||
safe_join([logo_as_symbol, t('accounts.follow')])
|
||||
end
|
||||
end
|
||||
|
||||
def hide_followers_count?(account)
|
||||
Setting.hide_followers_count || account.user&.settings&.[]('hide_followers_count')
|
||||
end
|
||||
|
@ -57,26 +57,6 @@ module MediaComponentHelper
|
||||
end
|
||||
end
|
||||
|
||||
def render_card_component(status, **options)
|
||||
component_params = {
|
||||
sensitive: sensitive_viewer?(status, current_account),
|
||||
card: serialize_status_card(status).as_json,
|
||||
}.merge(**options)
|
||||
|
||||
react_component :card, component_params
|
||||
end
|
||||
|
||||
def render_poll_component(status, **options)
|
||||
component_params = {
|
||||
disabled: true,
|
||||
poll: serialize_status_poll(status).as_json,
|
||||
}.merge(**options)
|
||||
|
||||
react_component :poll, component_params do
|
||||
render partial: 'statuses/poll', locals: { status: status, poll: status.preloadable_poll, autoplay: prefers_autoplay? }
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def serialize_media_attachment(attachment)
|
||||
@ -86,22 +66,6 @@ module MediaComponentHelper
|
||||
)
|
||||
end
|
||||
|
||||
def serialize_status_card(status)
|
||||
ActiveModelSerializers::SerializableResource.new(
|
||||
status.preview_card,
|
||||
serializer: REST::PreviewCardSerializer
|
||||
)
|
||||
end
|
||||
|
||||
def serialize_status_poll(status)
|
||||
ActiveModelSerializers::SerializableResource.new(
|
||||
status.preloadable_poll,
|
||||
serializer: REST::PollSerializer,
|
||||
scope: current_user,
|
||||
scope_name: :current_user
|
||||
)
|
||||
end
|
||||
|
||||
def sensitive_viewer?(status, account)
|
||||
if !account.nil? && account.id == status.account_id
|
||||
status.sensitive
|
||||
|
74
app/javascript/entrypoints/embed.tsx
Normal file
74
app/javascript/entrypoints/embed.tsx
Normal file
@ -0,0 +1,74 @@
|
||||
import './public-path';
|
||||
import { createRoot } from 'react-dom/client';
|
||||
|
||||
import { afterInitialRender } from 'mastodon/../hooks/useRenderSignal';
|
||||
|
||||
import { start } from '../mastodon/common';
|
||||
import { Status } from '../mastodon/features/standalone/status';
|
||||
import { loadPolyfills } from '../mastodon/polyfills';
|
||||
import ready from '../mastodon/ready';
|
||||
|
||||
start();
|
||||
|
||||
function loaded() {
|
||||
const mountNode = document.getElementById('mastodon-status');
|
||||
|
||||
if (mountNode) {
|
||||
const attr = mountNode.getAttribute('data-props');
|
||||
|
||||
if (!attr) return;
|
||||
|
||||
const props = JSON.parse(attr) as { id: string; locale: string };
|
||||
const root = createRoot(mountNode);
|
||||
|
||||
root.render(<Status {...props} />);
|
||||
}
|
||||
}
|
||||
|
||||
function main() {
|
||||
ready(loaded).catch((error: unknown) => {
|
||||
console.error(error);
|
||||
});
|
||||
}
|
||||
|
||||
loadPolyfills()
|
||||
.then(main)
|
||||
.catch((error: unknown) => {
|
||||
console.error(error);
|
||||
});
|
||||
|
||||
interface SetHeightMessage {
|
||||
type: 'setHeight';
|
||||
id: string;
|
||||
height: number;
|
||||
}
|
||||
|
||||
function isSetHeightMessage(data: unknown): data is SetHeightMessage {
|
||||
if (
|
||||
data &&
|
||||
typeof data === 'object' &&
|
||||
'type' in data &&
|
||||
data.type === 'setHeight'
|
||||
)
|
||||
return true;
|
||||
else return false;
|
||||
}
|
||||
|
||||
window.addEventListener('message', (e) => {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition -- typings are not correct, it can be null in very rare cases
|
||||
if (!e.data || !isSetHeightMessage(e.data) || !window.parent) return;
|
||||
|
||||
const data = e.data;
|
||||
|
||||
// We use a timeout to allow for the React page to render before calculating the height
|
||||
afterInitialRender(() => {
|
||||
window.parent.postMessage(
|
||||
{
|
||||
type: 'setHeight',
|
||||
id: data.id,
|
||||
height: document.getElementsByTagName('html')[0]?.scrollHeight,
|
||||
},
|
||||
'*',
|
||||
);
|
||||
});
|
||||
});
|
@ -37,43 +37,6 @@ const messages = defineMessages({
|
||||
},
|
||||
});
|
||||
|
||||
interface SetHeightMessage {
|
||||
type: 'setHeight';
|
||||
id: string;
|
||||
height: number;
|
||||
}
|
||||
|
||||
function isSetHeightMessage(data: unknown): data is SetHeightMessage {
|
||||
if (
|
||||
data &&
|
||||
typeof data === 'object' &&
|
||||
'type' in data &&
|
||||
data.type === 'setHeight'
|
||||
)
|
||||
return true;
|
||||
else return false;
|
||||
}
|
||||
|
||||
window.addEventListener('message', (e) => {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition -- typings are not correct, it can be null in very rare cases
|
||||
if (!e.data || !isSetHeightMessage(e.data) || !window.parent) return;
|
||||
|
||||
const data = e.data;
|
||||
|
||||
ready(() => {
|
||||
window.parent.postMessage(
|
||||
{
|
||||
type: 'setHeight',
|
||||
id: data.id,
|
||||
height: document.getElementsByTagName('html')[0]?.scrollHeight,
|
||||
},
|
||||
'*',
|
||||
);
|
||||
}).catch((e: unknown) => {
|
||||
console.error('Error in setHeightMessage postMessage', e);
|
||||
});
|
||||
});
|
||||
|
||||
function loaded() {
|
||||
const { messages: localeData } = getLocale();
|
||||
|
||||
|
32
app/javascript/hooks/useRenderSignal.ts
Normal file
32
app/javascript/hooks/useRenderSignal.ts
Normal file
@ -0,0 +1,32 @@
|
||||
// This hook allows a component to signal that it's done rendering in a way that
|
||||
// can be used by e.g. our embed code to determine correct iframe height
|
||||
|
||||
let renderSignalReceived = false;
|
||||
|
||||
type Callback = () => void;
|
||||
|
||||
let onInitialRender: Callback;
|
||||
|
||||
export const afterInitialRender = (callback: Callback) => {
|
||||
if (renderSignalReceived) {
|
||||
callback();
|
||||
} else {
|
||||
onInitialRender = callback;
|
||||
}
|
||||
};
|
||||
|
||||
export const useRenderSignal = () => {
|
||||
return () => {
|
||||
if (renderSignalReceived) {
|
||||
return;
|
||||
}
|
||||
|
||||
renderSignalReceived = true;
|
||||
|
||||
if (typeof onInitialRender !== 'undefined') {
|
||||
window.requestAnimationFrame(() => {
|
||||
onInitialRender();
|
||||
});
|
||||
}
|
||||
};
|
||||
};
|
@ -49,11 +49,13 @@ export function fetchStatusRequest(id, skipLoading) {
|
||||
};
|
||||
}
|
||||
|
||||
export function fetchStatus(id, forceFetch = false) {
|
||||
export function fetchStatus(id, forceFetch = false, alsoFetchContext = true) {
|
||||
return (dispatch, getState) => {
|
||||
const skipLoading = !forceFetch && getState().getIn(['statuses', id], null) !== null;
|
||||
|
||||
dispatch(fetchContext(id));
|
||||
if (alsoFetchContext) {
|
||||
dispatch(fetchContext(id));
|
||||
}
|
||||
|
||||
if (skipLoading) {
|
||||
return;
|
||||
|
90
app/javascript/mastodon/components/copy_paste_text.tsx
Normal file
90
app/javascript/mastodon/components/copy_paste_text.tsx
Normal file
@ -0,0 +1,90 @@
|
||||
import { useRef, useState, useCallback } from 'react';
|
||||
|
||||
import { FormattedMessage } from 'react-intl';
|
||||
|
||||
import classNames from 'classnames';
|
||||
|
||||
import ContentCopyIcon from '@/material-icons/400-24px/content_copy.svg?react';
|
||||
import { useTimeout } from 'mastodon/../hooks/useTimeout';
|
||||
import { Icon } from 'mastodon/components/icon';
|
||||
|
||||
export const CopyPasteText: React.FC<{ value: string }> = ({ value }) => {
|
||||
const inputRef = useRef<HTMLTextAreaElement>(null);
|
||||
const [copied, setCopied] = useState(false);
|
||||
const [focused, setFocused] = useState(false);
|
||||
const [setAnimationTimeout] = useTimeout();
|
||||
|
||||
const handleInputClick = useCallback(() => {
|
||||
setCopied(false);
|
||||
|
||||
if (inputRef.current) {
|
||||
inputRef.current.focus();
|
||||
inputRef.current.select();
|
||||
inputRef.current.setSelectionRange(0, value.length);
|
||||
}
|
||||
}, [setCopied, value]);
|
||||
|
||||
const handleButtonClick = useCallback(
|
||||
(e: React.MouseEvent) => {
|
||||
e.stopPropagation();
|
||||
void navigator.clipboard.writeText(value);
|
||||
inputRef.current?.blur();
|
||||
setCopied(true);
|
||||
setAnimationTimeout(() => {
|
||||
setCopied(false);
|
||||
}, 700);
|
||||
},
|
||||
[setCopied, setAnimationTimeout, value],
|
||||
);
|
||||
|
||||
const handleKeyUp = useCallback(
|
||||
(e: React.KeyboardEvent) => {
|
||||
if (e.key !== ' ') return;
|
||||
void navigator.clipboard.writeText(value);
|
||||
setCopied(true);
|
||||
setAnimationTimeout(() => {
|
||||
setCopied(false);
|
||||
}, 700);
|
||||
},
|
||||
[setCopied, setAnimationTimeout, value],
|
||||
);
|
||||
|
||||
const handleFocus = useCallback(() => {
|
||||
setFocused(true);
|
||||
}, [setFocused]);
|
||||
|
||||
const handleBlur = useCallback(() => {
|
||||
setFocused(false);
|
||||
}, [setFocused]);
|
||||
|
||||
return (
|
||||
<div
|
||||
className={classNames('copy-paste-text', { copied, focused })}
|
||||
tabIndex={0}
|
||||
role='button'
|
||||
onClick={handleInputClick}
|
||||
onKeyUp={handleKeyUp}
|
||||
>
|
||||
<textarea
|
||||
readOnly
|
||||
value={value}
|
||||
ref={inputRef}
|
||||
onClick={handleInputClick}
|
||||
onFocus={handleFocus}
|
||||
onBlur={handleBlur}
|
||||
/>
|
||||
|
||||
<button className='button' onClick={handleButtonClick}>
|
||||
<Icon id='copy' icon={ContentCopyIcon} />{' '}
|
||||
{copied ? (
|
||||
<FormattedMessage id='copypaste.copied' defaultMessage='Copied' />
|
||||
) : (
|
||||
<FormattedMessage
|
||||
id='copypaste.copy_to_clipboard'
|
||||
defaultMessage='Copy to clipboard'
|
||||
/>
|
||||
)}
|
||||
</button>
|
||||
</div>
|
||||
);
|
||||
};
|
@ -7,6 +7,13 @@ export const WordmarkLogo: React.FC = () => (
|
||||
</svg>
|
||||
);
|
||||
|
||||
export const IconLogo: React.FC = () => (
|
||||
<svg viewBox='0 0 79 79' className='logo logo--icon' role='img'>
|
||||
<title>Mastodon</title>
|
||||
<use xlinkHref='#logo-symbol-icon' />
|
||||
</svg>
|
||||
);
|
||||
|
||||
export const SymbolLogo: React.FC = () => (
|
||||
<img src={logo} alt='Mastodon' className='logo logo--icon' />
|
||||
);
|
||||
|
@ -2,14 +2,12 @@ import PropTypes from 'prop-types';
|
||||
|
||||
import { FormattedMessage } from 'react-intl';
|
||||
|
||||
import { IconLogo } from 'mastodon/components/logo';
|
||||
import { AuthorLink } from 'mastodon/features/explore/components/author_link';
|
||||
|
||||
export const MoreFromAuthor = ({ accountId }) => (
|
||||
<div className='more-from-author'>
|
||||
<svg viewBox='0 0 79 79' className='logo logo--icon' role='img'>
|
||||
<use xlinkHref='#logo-symbol-icon' />
|
||||
</svg>
|
||||
|
||||
<IconLogo />
|
||||
<FormattedMessage id='link_preview.more_from_author' defaultMessage='More from {name}' values={{ name: <AuthorLink accountId={accountId} /> }} />
|
||||
</div>
|
||||
);
|
||||
|
@ -55,7 +55,7 @@ const messages = defineMessages({
|
||||
unmuteConversation: { id: 'status.unmute_conversation', defaultMessage: 'Unmute conversation' },
|
||||
pin: { id: 'status.pin', defaultMessage: 'Pin on profile' },
|
||||
unpin: { id: 'status.unpin', defaultMessage: 'Unpin from profile' },
|
||||
embed: { id: 'status.embed', defaultMessage: 'Embed' },
|
||||
embed: { id: 'status.embed', defaultMessage: 'Get embed code' },
|
||||
admin_account: { id: 'status.admin_account', defaultMessage: 'Open moderation interface for @{name}' },
|
||||
admin_status: { id: 'status.admin_status', defaultMessage: 'Open this post in the moderation interface' },
|
||||
admin_domain: { id: 'status.admin_domain', defaultMessage: 'Open moderation interface for {domain}' },
|
||||
|
@ -6,7 +6,6 @@ import {
|
||||
unmuteAccount,
|
||||
unblockAccount,
|
||||
} from '../actions/accounts';
|
||||
import { showAlertForError } from '../actions/alerts';
|
||||
import { initBlockModal } from '../actions/blocks';
|
||||
import {
|
||||
replyCompose,
|
||||
@ -100,10 +99,7 @@ const mapDispatchToProps = (dispatch, { contextType }) => ({
|
||||
onEmbed (status) {
|
||||
dispatch(openModal({
|
||||
modalType: 'EMBED',
|
||||
modalProps: {
|
||||
id: status.get('id'),
|
||||
onError: error => dispatch(showAlertForError(error)),
|
||||
},
|
||||
modalProps: { id: status.get('id') },
|
||||
}));
|
||||
},
|
||||
|
||||
|
@ -10,8 +10,8 @@ import { Link } from 'react-router-dom';
|
||||
import SwipeableViews from 'react-swipeable-views';
|
||||
|
||||
import ArrowRightAltIcon from '@/material-icons/400-24px/arrow_right_alt.svg?react';
|
||||
import ContentCopyIcon from '@/material-icons/400-24px/content_copy.svg?react';
|
||||
import { ColumnBackButton } from 'mastodon/components/column_back_button';
|
||||
import { CopyPasteText } from 'mastodon/components/copy_paste_text';
|
||||
import { Icon } from 'mastodon/components/icon';
|
||||
import { me, domain } from 'mastodon/initial_state';
|
||||
import { useAppSelector } from 'mastodon/store';
|
||||
@ -20,67 +20,6 @@ const messages = defineMessages({
|
||||
shareableMessage: { id: 'onboarding.share.message', defaultMessage: 'I\'m {username} on #Mastodon! Come follow me at {url}' },
|
||||
});
|
||||
|
||||
class CopyPasteText extends PureComponent {
|
||||
|
||||
static propTypes = {
|
||||
value: PropTypes.string,
|
||||
};
|
||||
|
||||
state = {
|
||||
copied: false,
|
||||
focused: false,
|
||||
};
|
||||
|
||||
setRef = c => {
|
||||
this.input = c;
|
||||
};
|
||||
|
||||
handleInputClick = () => {
|
||||
this.setState({ copied: false });
|
||||
this.input.focus();
|
||||
this.input.select();
|
||||
this.input.setSelectionRange(0, this.props.value.length);
|
||||
};
|
||||
|
||||
handleButtonClick = e => {
|
||||
e.stopPropagation();
|
||||
|
||||
const { value } = this.props;
|
||||
navigator.clipboard.writeText(value);
|
||||
this.input.blur();
|
||||
this.setState({ copied: true });
|
||||
this.timeout = setTimeout(() => this.setState({ copied: false }), 700);
|
||||
};
|
||||
|
||||
handleFocus = () => {
|
||||
this.setState({ focused: true });
|
||||
};
|
||||
|
||||
handleBlur = () => {
|
||||
this.setState({ focused: false });
|
||||
};
|
||||
|
||||
componentWillUnmount () {
|
||||
if (this.timeout) clearTimeout(this.timeout);
|
||||
}
|
||||
|
||||
render () {
|
||||
const { value } = this.props;
|
||||
const { copied, focused } = this.state;
|
||||
|
||||
return (
|
||||
<div className={classNames('copy-paste-text', { copied, focused })} tabIndex='0' role='button' onClick={this.handleInputClick}>
|
||||
<textarea readOnly value={value} ref={this.setRef} onClick={this.handleInputClick} onFocus={this.handleFocus} onBlur={this.handleBlur} />
|
||||
|
||||
<button className='button' onClick={this.handleButtonClick}>
|
||||
<Icon id='copy' icon={ContentCopyIcon} /> {copied ? <FormattedMessage id='copypaste.copied' defaultMessage='Copied' /> : <FormattedMessage id='copypaste.copy_to_clipboard' defaultMessage='Copy to clipboard' />}
|
||||
</button>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class TipCarousel extends PureComponent {
|
||||
|
||||
static propTypes = {
|
||||
|
87
app/javascript/mastodon/features/standalone/status/index.tsx
Normal file
87
app/javascript/mastodon/features/standalone/status/index.tsx
Normal file
@ -0,0 +1,87 @@
|
||||
/* eslint-disable @typescript-eslint/no-unsafe-return,
|
||||
@typescript-eslint/no-explicit-any,
|
||||
@typescript-eslint/no-unsafe-assignment */
|
||||
|
||||
import { useEffect, useCallback } from 'react';
|
||||
|
||||
import { Provider } from 'react-redux';
|
||||
|
||||
import { useRenderSignal } from 'mastodon/../hooks/useRenderSignal';
|
||||
import { fetchStatus, toggleStatusSpoilers } from 'mastodon/actions/statuses';
|
||||
import { hydrateStore } from 'mastodon/actions/store';
|
||||
import { Router } from 'mastodon/components/router';
|
||||
import { DetailedStatus } from 'mastodon/features/status/components/detailed_status';
|
||||
import initialState from 'mastodon/initial_state';
|
||||
import { IntlProvider } from 'mastodon/locales';
|
||||
import { makeGetStatus, makeGetPictureInPicture } from 'mastodon/selectors';
|
||||
import { store, useAppSelector, useAppDispatch } from 'mastodon/store';
|
||||
|
||||
const getStatus = makeGetStatus() as unknown as (arg0: any, arg1: any) => any;
|
||||
const getPictureInPicture = makeGetPictureInPicture() as unknown as (
|
||||
arg0: any,
|
||||
arg1: any,
|
||||
) => any;
|
||||
|
||||
const Embed: React.FC<{ id: string }> = ({ id }) => {
|
||||
const status = useAppSelector((state) => getStatus(state, { id }));
|
||||
const pictureInPicture = useAppSelector((state) =>
|
||||
getPictureInPicture(state, { id }),
|
||||
);
|
||||
const domain = useAppSelector((state) => state.meta.get('domain'));
|
||||
const dispatch = useAppDispatch();
|
||||
const dispatchRenderSignal = useRenderSignal();
|
||||
|
||||
useEffect(() => {
|
||||
dispatch(fetchStatus(id, false, false));
|
||||
}, [dispatch, id]);
|
||||
|
||||
const handleToggleHidden = useCallback(() => {
|
||||
dispatch(toggleStatusSpoilers(id));
|
||||
}, [dispatch, id]);
|
||||
|
||||
// This allows us to calculate the correct page height for embeds
|
||||
if (status) {
|
||||
dispatchRenderSignal();
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-member-access
|
||||
const permalink = status?.get('url') as string;
|
||||
|
||||
return (
|
||||
<div className='embed'>
|
||||
<DetailedStatus
|
||||
status={status}
|
||||
domain={domain}
|
||||
pictureInPicture={pictureInPicture}
|
||||
onToggleHidden={handleToggleHidden}
|
||||
withLogo
|
||||
/>
|
||||
|
||||
<a
|
||||
className='embed__overlay'
|
||||
href={permalink}
|
||||
target='_blank'
|
||||
rel='noreferrer noopener'
|
||||
aria-label=''
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export const Status: React.FC<{ id: string }> = ({ id }) => {
|
||||
useEffect(() => {
|
||||
if (initialState) {
|
||||
store.dispatch(hydrateStore(initialState));
|
||||
}
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<IntlProvider>
|
||||
<Provider store={store}>
|
||||
<Router>
|
||||
<Embed id={id} />
|
||||
</Router>
|
||||
</Provider>
|
||||
</IntlProvider>
|
||||
);
|
||||
};
|
@ -49,7 +49,7 @@ const messages = defineMessages({
|
||||
share: { id: 'status.share', defaultMessage: 'Share' },
|
||||
pin: { id: 'status.pin', defaultMessage: 'Pin on profile' },
|
||||
unpin: { id: 'status.unpin', defaultMessage: 'Unpin from profile' },
|
||||
embed: { id: 'status.embed', defaultMessage: 'Embed' },
|
||||
embed: { id: 'status.embed', defaultMessage: 'Get embed code' },
|
||||
admin_account: { id: 'status.admin_account', defaultMessage: 'Open moderation interface for @{name}' },
|
||||
admin_status: { id: 'status.admin_status', defaultMessage: 'Open this post in the moderation interface' },
|
||||
admin_domain: { id: 'status.admin_domain', defaultMessage: 'Open moderation interface for {domain}' },
|
||||
|
@ -1,322 +0,0 @@
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
import { FormattedDate, FormattedMessage } from 'react-intl';
|
||||
|
||||
import classNames from 'classnames';
|
||||
import { Link, withRouter } from 'react-router-dom';
|
||||
|
||||
import ImmutablePropTypes from 'react-immutable-proptypes';
|
||||
import ImmutablePureComponent from 'react-immutable-pure-component';
|
||||
|
||||
import AlternateEmailIcon from '@/material-icons/400-24px/alternate_email.svg?react';
|
||||
import { AnimatedNumber } from 'mastodon/components/animated_number';
|
||||
import { ContentWarning } from 'mastodon/components/content_warning';
|
||||
import EditedTimestamp from 'mastodon/components/edited_timestamp';
|
||||
import { getHashtagBarForStatus } from 'mastodon/components/hashtag_bar';
|
||||
import { Icon } from 'mastodon/components/icon';
|
||||
import PictureInPicturePlaceholder from 'mastodon/components/picture_in_picture_placeholder';
|
||||
import { VisibilityIcon } from 'mastodon/components/visibility_icon';
|
||||
import { WithRouterPropTypes } from 'mastodon/utils/react_router';
|
||||
|
||||
import { Avatar } from '../../../components/avatar';
|
||||
import { DisplayName } from '../../../components/display_name';
|
||||
import MediaGallery from '../../../components/media_gallery';
|
||||
import StatusContent from '../../../components/status_content';
|
||||
import Audio from '../../audio';
|
||||
import scheduleIdleTask from '../../ui/util/schedule_idle_task';
|
||||
import Video from '../../video';
|
||||
|
||||
import Card from './card';
|
||||
|
||||
class DetailedStatus extends ImmutablePureComponent {
|
||||
|
||||
static propTypes = {
|
||||
status: ImmutablePropTypes.map,
|
||||
onOpenMedia: PropTypes.func.isRequired,
|
||||
onOpenVideo: PropTypes.func.isRequired,
|
||||
onToggleHidden: PropTypes.func.isRequired,
|
||||
onTranslate: PropTypes.func.isRequired,
|
||||
measureHeight: PropTypes.bool,
|
||||
onHeightChange: PropTypes.func,
|
||||
domain: PropTypes.string.isRequired,
|
||||
compact: PropTypes.bool,
|
||||
showMedia: PropTypes.bool,
|
||||
pictureInPicture: ImmutablePropTypes.contains({
|
||||
inUse: PropTypes.bool,
|
||||
available: PropTypes.bool,
|
||||
}),
|
||||
onToggleMediaVisibility: PropTypes.func,
|
||||
...WithRouterPropTypes,
|
||||
};
|
||||
|
||||
state = {
|
||||
height: null,
|
||||
};
|
||||
|
||||
handleAccountClick = (e) => {
|
||||
if (e.button === 0 && !(e.ctrlKey || e.metaKey) && this.props.history) {
|
||||
e.preventDefault();
|
||||
this.props.history.push(`/@${this.props.status.getIn(['account', 'acct'])}`);
|
||||
}
|
||||
|
||||
e.stopPropagation();
|
||||
};
|
||||
|
||||
handleOpenVideo = (options) => {
|
||||
this.props.onOpenVideo(this.props.status.getIn(['media_attachments', 0]), options);
|
||||
};
|
||||
|
||||
handleExpandedToggle = () => {
|
||||
this.props.onToggleHidden(this.props.status);
|
||||
};
|
||||
|
||||
_measureHeight (heightJustChanged) {
|
||||
if (this.props.measureHeight && this.node) {
|
||||
scheduleIdleTask(() => this.node && this.setState({ height: Math.ceil(this.node.scrollHeight) + 1 }));
|
||||
|
||||
if (this.props.onHeightChange && heightJustChanged) {
|
||||
this.props.onHeightChange();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
setRef = c => {
|
||||
this.node = c;
|
||||
this._measureHeight();
|
||||
};
|
||||
|
||||
componentDidUpdate (prevProps, prevState) {
|
||||
this._measureHeight(prevState.height !== this.state.height);
|
||||
}
|
||||
|
||||
handleModalLink = e => {
|
||||
e.preventDefault();
|
||||
|
||||
let href;
|
||||
|
||||
if (e.target.nodeName !== 'A') {
|
||||
href = e.target.parentNode.href;
|
||||
} else {
|
||||
href = e.target.href;
|
||||
}
|
||||
|
||||
window.open(href, 'mastodon-intent', 'width=445,height=600,resizable=no,menubar=no,status=no,scrollbars=yes');
|
||||
};
|
||||
|
||||
handleTranslate = () => {
|
||||
const { onTranslate, status } = this.props;
|
||||
onTranslate(status);
|
||||
};
|
||||
|
||||
_properStatus () {
|
||||
const { status } = this.props;
|
||||
|
||||
if (status.get('reblog', null) !== null && typeof status.get('reblog') === 'object') {
|
||||
return status.get('reblog');
|
||||
} else {
|
||||
return status;
|
||||
}
|
||||
}
|
||||
|
||||
getAttachmentAspectRatio () {
|
||||
const attachments = this._properStatus().get('media_attachments');
|
||||
|
||||
if (attachments.getIn([0, 'type']) === 'video') {
|
||||
return `${attachments.getIn([0, 'meta', 'original', 'width'])} / ${attachments.getIn([0, 'meta', 'original', 'height'])}`;
|
||||
} else if (attachments.getIn([0, 'type']) === 'audio') {
|
||||
return '16 / 9';
|
||||
} else {
|
||||
return (attachments.size === 1 && attachments.getIn([0, 'meta', 'small', 'aspect'])) ? attachments.getIn([0, 'meta', 'small', 'aspect']) : '3 / 2';
|
||||
}
|
||||
}
|
||||
|
||||
render () {
|
||||
const status = this._properStatus();
|
||||
const outerStyle = { boxSizing: 'border-box' };
|
||||
const { compact, pictureInPicture } = this.props;
|
||||
|
||||
if (!status) {
|
||||
return null;
|
||||
}
|
||||
|
||||
let media = '';
|
||||
let applicationLink = '';
|
||||
let reblogLink = '';
|
||||
let favouriteLink = '';
|
||||
|
||||
if (this.props.measureHeight) {
|
||||
outerStyle.height = `${this.state.height}px`;
|
||||
}
|
||||
|
||||
const language = status.getIn(['translation', 'language']) || status.get('language');
|
||||
|
||||
if (pictureInPicture.get('inUse')) {
|
||||
media = <PictureInPicturePlaceholder aspectRatio={this.getAttachmentAspectRatio()} />;
|
||||
} else if (status.get('media_attachments').size > 0) {
|
||||
if (status.getIn(['media_attachments', 0, 'type']) === 'audio') {
|
||||
const attachment = status.getIn(['media_attachments', 0]);
|
||||
const description = attachment.getIn(['translation', 'description']) || attachment.get('description');
|
||||
|
||||
media = (
|
||||
<Audio
|
||||
src={attachment.get('url')}
|
||||
alt={description}
|
||||
lang={language}
|
||||
duration={attachment.getIn(['meta', 'original', 'duration'], 0)}
|
||||
poster={attachment.get('preview_url') || status.getIn(['account', 'avatar_static'])}
|
||||
backgroundColor={attachment.getIn(['meta', 'colors', 'background'])}
|
||||
foregroundColor={attachment.getIn(['meta', 'colors', 'foreground'])}
|
||||
accentColor={attachment.getIn(['meta', 'colors', 'accent'])}
|
||||
sensitive={status.get('sensitive')}
|
||||
visible={this.props.showMedia}
|
||||
blurhash={attachment.get('blurhash')}
|
||||
height={150}
|
||||
onToggleVisibility={this.props.onToggleMediaVisibility}
|
||||
/>
|
||||
);
|
||||
} else if (status.getIn(['media_attachments', 0, 'type']) === 'video') {
|
||||
const attachment = status.getIn(['media_attachments', 0]);
|
||||
const description = attachment.getIn(['translation', 'description']) || attachment.get('description');
|
||||
|
||||
media = (
|
||||
<Video
|
||||
preview={attachment.get('preview_url')}
|
||||
frameRate={attachment.getIn(['meta', 'original', 'frame_rate'])}
|
||||
aspectRatio={`${attachment.getIn(['meta', 'original', 'width'])} / ${attachment.getIn(['meta', 'original', 'height'])}`}
|
||||
blurhash={attachment.get('blurhash')}
|
||||
src={attachment.get('url')}
|
||||
alt={description}
|
||||
lang={language}
|
||||
width={300}
|
||||
height={150}
|
||||
onOpenVideo={this.handleOpenVideo}
|
||||
sensitive={status.get('sensitive')}
|
||||
visible={this.props.showMedia}
|
||||
onToggleVisibility={this.props.onToggleMediaVisibility}
|
||||
/>
|
||||
);
|
||||
} else {
|
||||
media = (
|
||||
<MediaGallery
|
||||
standalone
|
||||
sensitive={status.get('sensitive')}
|
||||
media={status.get('media_attachments')}
|
||||
lang={language}
|
||||
height={300}
|
||||
onOpenMedia={this.props.onOpenMedia}
|
||||
visible={this.props.showMedia}
|
||||
onToggleVisibility={this.props.onToggleMediaVisibility}
|
||||
/>
|
||||
);
|
||||
}
|
||||
} else if (status.get('spoiler_text').length === 0) {
|
||||
media = <Card sensitive={status.get('sensitive')} onOpenMedia={this.props.onOpenMedia} card={status.get('card', null)} />;
|
||||
}
|
||||
|
||||
if (status.get('application')) {
|
||||
applicationLink = <>·<a className='detailed-status__application' href={status.getIn(['application', 'website'])} target='_blank' rel='noopener noreferrer'>{status.getIn(['application', 'name'])}</a></>;
|
||||
}
|
||||
|
||||
const visibilityLink = <>·<VisibilityIcon visibility={status.get('visibility')} /></>;
|
||||
|
||||
if (['private', 'direct'].includes(status.get('visibility'))) {
|
||||
reblogLink = '';
|
||||
} else if (this.props.history) {
|
||||
reblogLink = (
|
||||
<Link to={`/@${status.getIn(['account', 'acct'])}/${status.get('id')}/reblogs`} className='detailed-status__link'>
|
||||
<span className='detailed-status__reblogs'>
|
||||
<AnimatedNumber value={status.get('reblogs_count')} />
|
||||
</span>
|
||||
<FormattedMessage id='status.reblogs' defaultMessage='{count, plural, one {boost} other {boosts}}' values={{ count: status.get('reblogs_count') }} />
|
||||
</Link>
|
||||
);
|
||||
} else {
|
||||
reblogLink = (
|
||||
<a href={`/interact/${status.get('id')}?type=reblog`} className='detailed-status__link' onClick={this.handleModalLink}>
|
||||
<span className='detailed-status__reblogs'>
|
||||
<AnimatedNumber value={status.get('reblogs_count')} />
|
||||
</span>
|
||||
<FormattedMessage id='status.reblogs' defaultMessage='{count, plural, one {boost} other {boosts}}' values={{ count: status.get('reblogs_count') }} />
|
||||
</a>
|
||||
);
|
||||
}
|
||||
|
||||
if (this.props.history) {
|
||||
favouriteLink = (
|
||||
<Link to={`/@${status.getIn(['account', 'acct'])}/${status.get('id')}/favourites`} className='detailed-status__link'>
|
||||
<span className='detailed-status__favorites'>
|
||||
<AnimatedNumber value={status.get('favourites_count')} />
|
||||
</span>
|
||||
<FormattedMessage id='status.favourites' defaultMessage='{count, plural, one {favorite} other {favorites}}' values={{ count: status.get('favourites_count') }} />
|
||||
</Link>
|
||||
);
|
||||
} else {
|
||||
favouriteLink = (
|
||||
<a href={`/interact/${status.get('id')}?type=favourite`} className='detailed-status__link' onClick={this.handleModalLink}>
|
||||
<span className='detailed-status__favorites'>
|
||||
<AnimatedNumber value={status.get('favourites_count')} />
|
||||
</span>
|
||||
<FormattedMessage id='status.favourites' defaultMessage='{count, plural, one {favorite} other {favorites}}' values={{ count: status.get('favourites_count') }} />
|
||||
</a>
|
||||
);
|
||||
}
|
||||
|
||||
const {statusContentProps, hashtagBar} = getHashtagBarForStatus(status);
|
||||
const expanded = !status.get('hidden') || status.get('spoiler_text').length === 0;
|
||||
|
||||
return (
|
||||
<div style={outerStyle}>
|
||||
<div ref={this.setRef} className={classNames('detailed-status', { compact })}>
|
||||
{status.get('visibility') === 'direct' && (
|
||||
<div className='status__prepend'>
|
||||
<div className='status__prepend-icon-wrapper'><Icon id='at' icon={AlternateEmailIcon} className='status__prepend-icon' /></div>
|
||||
<FormattedMessage id='status.direct_indicator' defaultMessage='Private mention' />
|
||||
</div>
|
||||
)}
|
||||
<a href={`/@${status.getIn(['account', 'acct'])}`} data-hover-card-account={status.getIn(['account', 'id'])} onClick={this.handleAccountClick} className='detailed-status__display-name'>
|
||||
<div className='detailed-status__display-avatar'><Avatar account={status.get('account')} size={46} /></div>
|
||||
<DisplayName account={status.get('account')} localDomain={this.props.domain} />
|
||||
</a>
|
||||
|
||||
{status.get('spoiler_text').length > 0 && <ContentWarning text={status.getIn(['translation', 'spoilerHtml']) || status.get('spoilerHtml')} expanded={expanded} onClick={this.handleExpandedToggle} />}
|
||||
|
||||
{expanded && (
|
||||
<>
|
||||
<StatusContent
|
||||
status={status}
|
||||
onTranslate={this.handleTranslate}
|
||||
{...statusContentProps}
|
||||
/>
|
||||
|
||||
{media}
|
||||
{hashtagBar}
|
||||
</>
|
||||
)}
|
||||
|
||||
<div className='detailed-status__meta'>
|
||||
<div className='detailed-status__meta__line'>
|
||||
<a className='detailed-status__datetime' href={`/@${status.getIn(['account', 'acct'])}/${status.get('id')}`} target='_blank' rel='noopener noreferrer'>
|
||||
<FormattedDate value={new Date(status.get('created_at'))} year='numeric' month='short' day='2-digit' hour='2-digit' minute='2-digit' />
|
||||
</a>
|
||||
|
||||
{visibilityLink}
|
||||
|
||||
{applicationLink}
|
||||
</div>
|
||||
|
||||
{status.get('edited_at') && <div className='detailed-status__meta__line'><EditedTimestamp statusId={status.get('id')} timestamp={status.get('edited_at')} /></div>}
|
||||
|
||||
<div className='detailed-status__meta__line'>
|
||||
{reblogLink}
|
||||
{reblogLink && <>·</>}
|
||||
{favouriteLink}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default withRouter(DetailedStatus);
|
@ -0,0 +1,390 @@
|
||||
/* eslint-disable @typescript-eslint/no-unsafe-member-access,
|
||||
@typescript-eslint/no-unsafe-call,
|
||||
@typescript-eslint/no-explicit-any,
|
||||
@typescript-eslint/no-unsafe-assignment */
|
||||
|
||||
import type { CSSProperties } from 'react';
|
||||
import { useState, useRef, useCallback } from 'react';
|
||||
|
||||
import { FormattedDate, FormattedMessage } from 'react-intl';
|
||||
|
||||
import classNames from 'classnames';
|
||||
import { Link } from 'react-router-dom';
|
||||
|
||||
import AlternateEmailIcon from '@/material-icons/400-24px/alternate_email.svg?react';
|
||||
import { AnimatedNumber } from 'mastodon/components/animated_number';
|
||||
import { ContentWarning } from 'mastodon/components/content_warning';
|
||||
import EditedTimestamp from 'mastodon/components/edited_timestamp';
|
||||
import type { StatusLike } from 'mastodon/components/hashtag_bar';
|
||||
import { getHashtagBarForStatus } from 'mastodon/components/hashtag_bar';
|
||||
import { Icon } from 'mastodon/components/icon';
|
||||
import { IconLogo } from 'mastodon/components/logo';
|
||||
import PictureInPicturePlaceholder from 'mastodon/components/picture_in_picture_placeholder';
|
||||
import { VisibilityIcon } from 'mastodon/components/visibility_icon';
|
||||
|
||||
import { Avatar } from '../../../components/avatar';
|
||||
import { DisplayName } from '../../../components/display_name';
|
||||
import MediaGallery from '../../../components/media_gallery';
|
||||
import StatusContent from '../../../components/status_content';
|
||||
import Audio from '../../audio';
|
||||
import scheduleIdleTask from '../../ui/util/schedule_idle_task';
|
||||
import Video from '../../video';
|
||||
|
||||
import Card from './card';
|
||||
|
||||
interface VideoModalOptions {
|
||||
startTime: number;
|
||||
autoPlay?: boolean;
|
||||
defaultVolume: number;
|
||||
componentIndex: number;
|
||||
}
|
||||
|
||||
export const DetailedStatus: React.FC<{
|
||||
status: any;
|
||||
onOpenMedia?: (status: any, index: number, lang: string) => void;
|
||||
onOpenVideo?: (status: any, lang: string, options: VideoModalOptions) => void;
|
||||
onTranslate?: (status: any) => void;
|
||||
measureHeight?: boolean;
|
||||
onHeightChange?: () => void;
|
||||
domain: string;
|
||||
showMedia?: boolean;
|
||||
withLogo?: boolean;
|
||||
pictureInPicture: any;
|
||||
onToggleHidden?: (status: any) => void;
|
||||
onToggleMediaVisibility?: () => void;
|
||||
}> = ({
|
||||
status,
|
||||
onOpenMedia,
|
||||
onOpenVideo,
|
||||
onTranslate,
|
||||
measureHeight,
|
||||
onHeightChange,
|
||||
domain,
|
||||
showMedia,
|
||||
withLogo,
|
||||
pictureInPicture,
|
||||
onToggleMediaVisibility,
|
||||
onToggleHidden,
|
||||
}) => {
|
||||
const properStatus = status?.get('reblog') ?? status;
|
||||
const [height, setHeight] = useState(0);
|
||||
const nodeRef = useRef<HTMLDivElement>();
|
||||
|
||||
const handleOpenVideo = useCallback(
|
||||
(options: VideoModalOptions) => {
|
||||
const lang = (status.getIn(['translation', 'language']) ||
|
||||
status.get('language')) as string;
|
||||
if (onOpenVideo)
|
||||
onOpenVideo(status.getIn(['media_attachments', 0]), lang, options);
|
||||
},
|
||||
[onOpenVideo, status],
|
||||
);
|
||||
|
||||
const handleExpandedToggle = useCallback(() => {
|
||||
if (onToggleHidden) onToggleHidden(status);
|
||||
}, [onToggleHidden, status]);
|
||||
|
||||
const _measureHeight = useCallback(
|
||||
(heightJustChanged?: boolean) => {
|
||||
if (measureHeight && nodeRef.current) {
|
||||
scheduleIdleTask(() => {
|
||||
if (nodeRef.current)
|
||||
setHeight(Math.ceil(nodeRef.current.scrollHeight) + 1);
|
||||
});
|
||||
|
||||
if (onHeightChange && heightJustChanged) {
|
||||
onHeightChange();
|
||||
}
|
||||
}
|
||||
},
|
||||
[onHeightChange, measureHeight, setHeight],
|
||||
);
|
||||
|
||||
const handleRef = useCallback(
|
||||
(c: HTMLDivElement) => {
|
||||
nodeRef.current = c;
|
||||
_measureHeight();
|
||||
},
|
||||
[_measureHeight],
|
||||
);
|
||||
|
||||
const handleTranslate = useCallback(() => {
|
||||
if (onTranslate) onTranslate(status);
|
||||
}, [onTranslate, status]);
|
||||
|
||||
if (!properStatus) {
|
||||
return null;
|
||||
}
|
||||
|
||||
let media;
|
||||
let applicationLink;
|
||||
let reblogLink;
|
||||
let attachmentAspectRatio;
|
||||
|
||||
if (properStatus.get('media_attachments').getIn([0, 'type']) === 'video') {
|
||||
attachmentAspectRatio = `${properStatus.get('media_attachments').getIn([0, 'meta', 'original', 'width'])} / ${properStatus.get('media_attachments').getIn([0, 'meta', 'original', 'height'])}`;
|
||||
} else if (
|
||||
properStatus.get('media_attachments').getIn([0, 'type']) === 'audio'
|
||||
) {
|
||||
attachmentAspectRatio = '16 / 9';
|
||||
} else {
|
||||
attachmentAspectRatio =
|
||||
properStatus.get('media_attachments').size === 1 &&
|
||||
properStatus
|
||||
.get('media_attachments')
|
||||
.getIn([0, 'meta', 'small', 'aspect'])
|
||||
? properStatus
|
||||
.get('media_attachments')
|
||||
.getIn([0, 'meta', 'small', 'aspect'])
|
||||
: '3 / 2';
|
||||
}
|
||||
|
||||
const outerStyle = { boxSizing: 'border-box' } as CSSProperties;
|
||||
|
||||
if (measureHeight) {
|
||||
outerStyle.height = height;
|
||||
}
|
||||
|
||||
const language =
|
||||
status.getIn(['translation', 'language']) || status.get('language');
|
||||
|
||||
if (pictureInPicture.get('inUse')) {
|
||||
media = <PictureInPicturePlaceholder aspectRatio={attachmentAspectRatio} />;
|
||||
} else if (status.get('media_attachments').size > 0) {
|
||||
if (status.getIn(['media_attachments', 0, 'type']) === 'audio') {
|
||||
const attachment = status.getIn(['media_attachments', 0]);
|
||||
const description =
|
||||
attachment.getIn(['translation', 'description']) ||
|
||||
attachment.get('description');
|
||||
|
||||
media = (
|
||||
<Audio
|
||||
src={attachment.get('url')}
|
||||
alt={description}
|
||||
lang={language}
|
||||
duration={attachment.getIn(['meta', 'original', 'duration'], 0)}
|
||||
poster={
|
||||
attachment.get('preview_url') ||
|
||||
status.getIn(['account', 'avatar_static'])
|
||||
}
|
||||
backgroundColor={attachment.getIn(['meta', 'colors', 'background'])}
|
||||
foregroundColor={attachment.getIn(['meta', 'colors', 'foreground'])}
|
||||
accentColor={attachment.getIn(['meta', 'colors', 'accent'])}
|
||||
sensitive={status.get('sensitive')}
|
||||
visible={showMedia}
|
||||
blurhash={attachment.get('blurhash')}
|
||||
height={150}
|
||||
onToggleVisibility={onToggleMediaVisibility}
|
||||
/>
|
||||
);
|
||||
} else if (status.getIn(['media_attachments', 0, 'type']) === 'video') {
|
||||
const attachment = status.getIn(['media_attachments', 0]);
|
||||
const description =
|
||||
attachment.getIn(['translation', 'description']) ||
|
||||
attachment.get('description');
|
||||
|
||||
media = (
|
||||
<Video
|
||||
preview={attachment.get('preview_url')}
|
||||
frameRate={attachment.getIn(['meta', 'original', 'frame_rate'])}
|
||||
aspectRatio={`${attachment.getIn(['meta', 'original', 'width'])} / ${attachment.getIn(['meta', 'original', 'height'])}`}
|
||||
blurhash={attachment.get('blurhash')}
|
||||
src={attachment.get('url')}
|
||||
alt={description}
|
||||
lang={language}
|
||||
width={300}
|
||||
height={150}
|
||||
onOpenVideo={handleOpenVideo}
|
||||
sensitive={status.get('sensitive')}
|
||||
visible={showMedia}
|
||||
onToggleVisibility={onToggleMediaVisibility}
|
||||
/>
|
||||
);
|
||||
} else {
|
||||
media = (
|
||||
<MediaGallery
|
||||
standalone
|
||||
sensitive={status.get('sensitive')}
|
||||
media={status.get('media_attachments')}
|
||||
lang={language}
|
||||
height={300}
|
||||
onOpenMedia={onOpenMedia}
|
||||
visible={showMedia}
|
||||
onToggleVisibility={onToggleMediaVisibility}
|
||||
/>
|
||||
);
|
||||
}
|
||||
} else if (status.get('spoiler_text').length === 0) {
|
||||
media = (
|
||||
<Card
|
||||
sensitive={status.get('sensitive')}
|
||||
onOpenMedia={onOpenMedia}
|
||||
card={status.get('card', null)}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
if (status.get('application')) {
|
||||
applicationLink = (
|
||||
<>
|
||||
·
|
||||
<a
|
||||
className='detailed-status__application'
|
||||
href={status.getIn(['application', 'website'])}
|
||||
target='_blank'
|
||||
rel='noopener noreferrer'
|
||||
>
|
||||
{status.getIn(['application', 'name'])}
|
||||
</a>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
const visibilityLink = (
|
||||
<>
|
||||
·<VisibilityIcon visibility={status.get('visibility')} />
|
||||
</>
|
||||
);
|
||||
|
||||
if (['private', 'direct'].includes(status.get('visibility') as string)) {
|
||||
reblogLink = '';
|
||||
} else {
|
||||
reblogLink = (
|
||||
<Link
|
||||
to={`/@${status.getIn(['account', 'acct'])}/${status.get('id')}/reblogs`}
|
||||
className='detailed-status__link'
|
||||
>
|
||||
<span className='detailed-status__reblogs'>
|
||||
<AnimatedNumber value={status.get('reblogs_count')} />
|
||||
</span>
|
||||
<FormattedMessage
|
||||
id='status.reblogs'
|
||||
defaultMessage='{count, plural, one {boost} other {boosts}}'
|
||||
values={{ count: status.get('reblogs_count') }}
|
||||
/>
|
||||
</Link>
|
||||
);
|
||||
}
|
||||
|
||||
const favouriteLink = (
|
||||
<Link
|
||||
to={`/@${status.getIn(['account', 'acct'])}/${status.get('id')}/favourites`}
|
||||
className='detailed-status__link'
|
||||
>
|
||||
<span className='detailed-status__favorites'>
|
||||
<AnimatedNumber value={status.get('favourites_count')} />
|
||||
</span>
|
||||
<FormattedMessage
|
||||
id='status.favourites'
|
||||
defaultMessage='{count, plural, one {favorite} other {favorites}}'
|
||||
values={{ count: status.get('favourites_count') }}
|
||||
/>
|
||||
</Link>
|
||||
);
|
||||
|
||||
const { statusContentProps, hashtagBar } = getHashtagBarForStatus(
|
||||
status as StatusLike,
|
||||
);
|
||||
const expanded =
|
||||
!status.get('hidden') || status.get('spoiler_text').length === 0;
|
||||
|
||||
return (
|
||||
<div style={outerStyle}>
|
||||
<div ref={handleRef} className={classNames('detailed-status')}>
|
||||
{status.get('visibility') === 'direct' && (
|
||||
<div className='status__prepend'>
|
||||
<div className='status__prepend-icon-wrapper'>
|
||||
<Icon
|
||||
id='at'
|
||||
icon={AlternateEmailIcon}
|
||||
className='status__prepend-icon'
|
||||
/>
|
||||
</div>
|
||||
<FormattedMessage
|
||||
id='status.direct_indicator'
|
||||
defaultMessage='Private mention'
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
<Link
|
||||
to={`/@${status.getIn(['account', 'acct'])}`}
|
||||
data-hover-card-account={status.getIn(['account', 'id'])}
|
||||
className='detailed-status__display-name'
|
||||
>
|
||||
<div className='detailed-status__display-avatar'>
|
||||
<Avatar account={status.get('account')} size={46} />
|
||||
</div>
|
||||
<DisplayName account={status.get('account')} localDomain={domain} />
|
||||
{withLogo && (
|
||||
<>
|
||||
<div className='spacer' />
|
||||
<IconLogo />
|
||||
</>
|
||||
)}
|
||||
</Link>
|
||||
|
||||
{status.get('spoiler_text').length > 0 && (
|
||||
<ContentWarning
|
||||
text={
|
||||
status.getIn(['translation', 'spoilerHtml']) ||
|
||||
status.get('spoilerHtml')
|
||||
}
|
||||
expanded={expanded}
|
||||
onClick={handleExpandedToggle}
|
||||
/>
|
||||
)}
|
||||
|
||||
{expanded && (
|
||||
<>
|
||||
<StatusContent
|
||||
status={status}
|
||||
onTranslate={handleTranslate}
|
||||
{...(statusContentProps as any)}
|
||||
/>
|
||||
|
||||
{media}
|
||||
{hashtagBar}
|
||||
</>
|
||||
)}
|
||||
|
||||
<div className='detailed-status__meta'>
|
||||
<div className='detailed-status__meta__line'>
|
||||
<a
|
||||
className='detailed-status__datetime'
|
||||
href={`/@${status.getIn(['account', 'acct'])}/${status.get('id')}`}
|
||||
target='_blank'
|
||||
rel='noopener noreferrer'
|
||||
>
|
||||
<FormattedDate
|
||||
value={new Date(status.get('created_at') as string)}
|
||||
year='numeric'
|
||||
month='short'
|
||||
day='2-digit'
|
||||
hour='2-digit'
|
||||
minute='2-digit'
|
||||
/>
|
||||
</a>
|
||||
|
||||
{visibilityLink}
|
||||
{applicationLink}
|
||||
</div>
|
||||
|
||||
{status.get('edited_at') && (
|
||||
<div className='detailed-status__meta__line'>
|
||||
<EditedTimestamp
|
||||
statusId={status.get('id')}
|
||||
timestamp={status.get('edited_at')}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div className='detailed-status__meta__line'>
|
||||
{reblogLink}
|
||||
{reblogLink && <>·</>}
|
||||
{favouriteLink}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
@ -1,140 +0,0 @@
|
||||
import { injectIntl } from 'react-intl';
|
||||
|
||||
import { connect } from 'react-redux';
|
||||
|
||||
import { showAlertForError } from '../../../actions/alerts';
|
||||
import { initBlockModal } from '../../../actions/blocks';
|
||||
import {
|
||||
replyCompose,
|
||||
mentionCompose,
|
||||
directCompose,
|
||||
} from '../../../actions/compose';
|
||||
import {
|
||||
toggleReblog,
|
||||
toggleFavourite,
|
||||
pin,
|
||||
unpin,
|
||||
} from '../../../actions/interactions';
|
||||
import { openModal } from '../../../actions/modal';
|
||||
import { initMuteModal } from '../../../actions/mutes';
|
||||
import { initReport } from '../../../actions/reports';
|
||||
import {
|
||||
muteStatus,
|
||||
unmuteStatus,
|
||||
deleteStatus,
|
||||
toggleStatusSpoilers,
|
||||
} from '../../../actions/statuses';
|
||||
import { deleteModal } from '../../../initial_state';
|
||||
import { makeGetStatus, makeGetPictureInPicture } from '../../../selectors';
|
||||
import DetailedStatus from '../components/detailed_status';
|
||||
|
||||
const makeMapStateToProps = () => {
|
||||
const getStatus = makeGetStatus();
|
||||
const getPictureInPicture = makeGetPictureInPicture();
|
||||
|
||||
const mapStateToProps = (state, props) => ({
|
||||
status: getStatus(state, props),
|
||||
domain: state.getIn(['meta', 'domain']),
|
||||
pictureInPicture: getPictureInPicture(state, props),
|
||||
});
|
||||
|
||||
return mapStateToProps;
|
||||
};
|
||||
|
||||
const mapDispatchToProps = (dispatch) => ({
|
||||
|
||||
onReply (status) {
|
||||
dispatch((_, getState) => {
|
||||
let state = getState();
|
||||
if (state.getIn(['compose', 'text']).trim().length !== 0) {
|
||||
dispatch(openModal({ modalType: 'CONFIRM_REPLY', modalProps: { status } }));
|
||||
} else {
|
||||
dispatch(replyCompose(status));
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
onReblog (status, e) {
|
||||
dispatch(toggleReblog(status.get('id'), e.shiftKey));
|
||||
},
|
||||
|
||||
onFavourite (status) {
|
||||
dispatch(toggleFavourite(status.get('id')));
|
||||
},
|
||||
|
||||
onPin (status) {
|
||||
if (status.get('pinned')) {
|
||||
dispatch(unpin(status));
|
||||
} else {
|
||||
dispatch(pin(status));
|
||||
}
|
||||
},
|
||||
|
||||
onEmbed (status) {
|
||||
dispatch(openModal({
|
||||
modalType: 'EMBED',
|
||||
modalProps: {
|
||||
id: status.get('id'),
|
||||
onError: error => dispatch(showAlertForError(error)),
|
||||
},
|
||||
}));
|
||||
},
|
||||
|
||||
onDelete (status, withRedraft = false) {
|
||||
if (!deleteModal) {
|
||||
dispatch(deleteStatus(status.get('id'), withRedraft));
|
||||
} else {
|
||||
dispatch(openModal({ modalType: 'CONFIRM_DELETE_STATUS', modalProps: { statusId: status.get('id'), withRedraft } }));
|
||||
}
|
||||
},
|
||||
|
||||
onDirect (account) {
|
||||
dispatch(directCompose(account));
|
||||
},
|
||||
|
||||
onMention (account) {
|
||||
dispatch(mentionCompose(account));
|
||||
},
|
||||
|
||||
onOpenMedia (media, index, lang) {
|
||||
dispatch(openModal({
|
||||
modalType: 'MEDIA',
|
||||
modalProps: { media, index, lang },
|
||||
}));
|
||||
},
|
||||
|
||||
onOpenVideo (media, lang, options) {
|
||||
dispatch(openModal({
|
||||
modalType: 'VIDEO',
|
||||
modalProps: { media, lang, options },
|
||||
}));
|
||||
},
|
||||
|
||||
onBlock (status) {
|
||||
const account = status.get('account');
|
||||
dispatch(initBlockModal(account));
|
||||
},
|
||||
|
||||
onReport (status) {
|
||||
dispatch(initReport(status.get('account'), status));
|
||||
},
|
||||
|
||||
onMute (account) {
|
||||
dispatch(initMuteModal(account));
|
||||
},
|
||||
|
||||
onMuteConversation (status) {
|
||||
if (status.get('muted')) {
|
||||
dispatch(unmuteStatus(status.get('id')));
|
||||
} else {
|
||||
dispatch(muteStatus(status.get('id')));
|
||||
}
|
||||
},
|
||||
|
||||
onToggleHidden (status) {
|
||||
dispatch(toggleStatusSpoilers(status.get('id')));
|
||||
},
|
||||
|
||||
});
|
||||
|
||||
export default injectIntl(connect(makeMapStateToProps, mapDispatchToProps)(DetailedStatus));
|
@ -69,7 +69,7 @@ import Column from '../ui/components/column';
|
||||
import { attachFullscreenListener, detachFullscreenListener, isFullscreen } from '../ui/util/fullscreen';
|
||||
|
||||
import ActionBar from './components/action_bar';
|
||||
import DetailedStatus from './components/detailed_status';
|
||||
import { DetailedStatus } from './components/detailed_status';
|
||||
|
||||
|
||||
const messages = defineMessages({
|
||||
|
@ -1,101 +0,0 @@
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
import { defineMessages, FormattedMessage, injectIntl } from 'react-intl';
|
||||
|
||||
import ImmutablePureComponent from 'react-immutable-pure-component';
|
||||
|
||||
import CloseIcon from '@/material-icons/400-24px/close.svg?react';
|
||||
import api from 'mastodon/api';
|
||||
import { IconButton } from 'mastodon/components/icon_button';
|
||||
|
||||
const messages = defineMessages({
|
||||
close: { id: 'lightbox.close', defaultMessage: 'Close' },
|
||||
});
|
||||
|
||||
class EmbedModal extends ImmutablePureComponent {
|
||||
|
||||
static propTypes = {
|
||||
id: PropTypes.string.isRequired,
|
||||
onClose: PropTypes.func.isRequired,
|
||||
onError: PropTypes.func.isRequired,
|
||||
intl: PropTypes.object.isRequired,
|
||||
};
|
||||
|
||||
state = {
|
||||
loading: false,
|
||||
oembed: null,
|
||||
};
|
||||
|
||||
componentDidMount () {
|
||||
const { id } = this.props;
|
||||
|
||||
this.setState({ loading: true });
|
||||
|
||||
api().get(`/api/web/embeds/${id}`).then(res => {
|
||||
this.setState({ loading: false, oembed: res.data });
|
||||
|
||||
const iframeDocument = this.iframe.contentWindow.document;
|
||||
|
||||
iframeDocument.open();
|
||||
iframeDocument.write(res.data.html);
|
||||
iframeDocument.close();
|
||||
|
||||
iframeDocument.body.style.margin = 0;
|
||||
this.iframe.width = iframeDocument.body.scrollWidth;
|
||||
this.iframe.height = iframeDocument.body.scrollHeight;
|
||||
}).catch(error => {
|
||||
this.props.onError(error);
|
||||
});
|
||||
}
|
||||
|
||||
setIframeRef = c => {
|
||||
this.iframe = c;
|
||||
};
|
||||
|
||||
handleTextareaClick = (e) => {
|
||||
e.target.select();
|
||||
};
|
||||
|
||||
render () {
|
||||
const { intl, onClose } = this.props;
|
||||
const { oembed } = this.state;
|
||||
|
||||
return (
|
||||
<div className='modal-root__modal report-modal embed-modal'>
|
||||
<div className='report-modal__target'>
|
||||
<IconButton className='media-modal__close' title={intl.formatMessage(messages.close)} icon='times' iconComponent={CloseIcon} onClick={onClose} size={16} />
|
||||
<FormattedMessage id='status.embed' defaultMessage='Embed' />
|
||||
</div>
|
||||
|
||||
<div className='report-modal__container embed-modal__container' style={{ display: 'block' }}>
|
||||
<p className='hint'>
|
||||
<FormattedMessage id='embed.instructions' defaultMessage='Embed this status on your website by copying the code below.' />
|
||||
</p>
|
||||
|
||||
<input
|
||||
type='text'
|
||||
className='embed-modal__html'
|
||||
readOnly
|
||||
value={oembed && oembed.html || ''}
|
||||
onClick={this.handleTextareaClick}
|
||||
/>
|
||||
|
||||
<p className='hint'>
|
||||
<FormattedMessage id='embed.preview' defaultMessage='Here is what it will look like:' />
|
||||
</p>
|
||||
|
||||
<iframe
|
||||
className='embed-modal__iframe'
|
||||
frameBorder='0'
|
||||
ref={this.setIframeRef}
|
||||
sandbox='allow-scripts allow-same-origin'
|
||||
title='preview'
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default injectIntl(EmbedModal);
|
116
app/javascript/mastodon/features/ui/components/embed_modal.tsx
Normal file
116
app/javascript/mastodon/features/ui/components/embed_modal.tsx
Normal file
@ -0,0 +1,116 @@
|
||||
import { useRef, useState, useEffect } from 'react';
|
||||
|
||||
import { FormattedMessage } from 'react-intl';
|
||||
|
||||
import { showAlertForError } from 'mastodon/actions/alerts';
|
||||
import api from 'mastodon/api';
|
||||
import { Button } from 'mastodon/components/button';
|
||||
import { CopyPasteText } from 'mastodon/components/copy_paste_text';
|
||||
import { useAppDispatch } from 'mastodon/store';
|
||||
|
||||
interface OEmbedResponse {
|
||||
html: string;
|
||||
}
|
||||
|
||||
const EmbedModal: React.FC<{
|
||||
id: string;
|
||||
onClose: () => void;
|
||||
}> = ({ id, onClose }) => {
|
||||
const iframeRef = useRef<HTMLIFrameElement>(null);
|
||||
const intervalRef = useRef<ReturnType<typeof setInterval>>();
|
||||
const [oembed, setOembed] = useState<OEmbedResponse | null>(null);
|
||||
const dispatch = useAppDispatch();
|
||||
|
||||
useEffect(() => {
|
||||
api()
|
||||
.get(`/api/web/embeds/${id}`)
|
||||
.then((res) => {
|
||||
const data = res.data as OEmbedResponse;
|
||||
|
||||
setOembed(data);
|
||||
|
||||
const iframeDocument = iframeRef.current?.contentWindow?.document;
|
||||
|
||||
if (!iframeDocument) {
|
||||
return '';
|
||||
}
|
||||
|
||||
iframeDocument.open();
|
||||
iframeDocument.write(data.html);
|
||||
iframeDocument.close();
|
||||
|
||||
iframeDocument.body.style.margin = '0px';
|
||||
|
||||
// This is our best chance to ensure the parent iframe has the correct height...
|
||||
intervalRef.current = setInterval(
|
||||
() =>
|
||||
window.requestAnimationFrame(() => {
|
||||
if (iframeRef.current) {
|
||||
iframeRef.current.width = `${iframeDocument.body.scrollWidth}px`;
|
||||
iframeRef.current.height = `${iframeDocument.body.scrollHeight}px`;
|
||||
}
|
||||
}),
|
||||
100,
|
||||
);
|
||||
|
||||
return '';
|
||||
})
|
||||
.catch((error: unknown) => {
|
||||
dispatch(showAlertForError(error));
|
||||
});
|
||||
}, [dispatch, id, setOembed]);
|
||||
|
||||
useEffect(
|
||||
() => () => {
|
||||
if (intervalRef.current) {
|
||||
clearInterval(intervalRef.current);
|
||||
}
|
||||
},
|
||||
[],
|
||||
);
|
||||
|
||||
return (
|
||||
<div className='modal-root__modal dialog-modal'>
|
||||
<div className='dialog-modal__header'>
|
||||
<Button onClick={onClose}>
|
||||
<FormattedMessage id='report.close' defaultMessage='Done' />
|
||||
</Button>
|
||||
<span className='dialog-modal__header__title'>
|
||||
<FormattedMessage id='status.embed' defaultMessage='Get embed code' />
|
||||
</span>
|
||||
<Button secondary onClick={onClose}>
|
||||
<FormattedMessage
|
||||
id='confirmation_modal.cancel'
|
||||
defaultMessage='Cancel'
|
||||
/>
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
<div className='dialog-modal__content'>
|
||||
<div className='dialog-modal__content__form'>
|
||||
<FormattedMessage
|
||||
id='embed.instructions'
|
||||
defaultMessage='Embed this status on your website by copying the code below.'
|
||||
/>
|
||||
|
||||
<CopyPasteText value={oembed?.html ?? ''} />
|
||||
|
||||
<FormattedMessage
|
||||
id='embed.preview'
|
||||
defaultMessage='Here is what it will look like:'
|
||||
/>
|
||||
|
||||
<iframe
|
||||
frameBorder='0'
|
||||
ref={iframeRef}
|
||||
sandbox='allow-scripts allow-same-origin'
|
||||
title='Preview'
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
// eslint-disable-next-line import/no-default-export
|
||||
export default EmbedModal;
|
@ -789,7 +789,7 @@
|
||||
"status.edit": "Edit",
|
||||
"status.edited": "Last edited {date}",
|
||||
"status.edited_x_times": "Edited {count, plural, one {{count} time} other {{count} times}}",
|
||||
"status.embed": "Embed",
|
||||
"status.embed": "Get embed code",
|
||||
"status.favourite": "Favorite",
|
||||
"status.favourites": "{count, plural, one {favorite} other {favorites}}",
|
||||
"status.filter": "Filter this post",
|
||||
|
@ -11,7 +11,6 @@
|
||||
@import 'mastodon/widgets';
|
||||
@import 'mastodon/forms';
|
||||
@import 'mastodon/accounts';
|
||||
@import 'mastodon/statuses';
|
||||
@import 'mastodon/components';
|
||||
@import 'mastodon/polls';
|
||||
@import 'mastodon/modal';
|
||||
|
@ -1677,18 +1677,6 @@ body > [data-popper-placement] {
|
||||
padding: 16px;
|
||||
border-top: 1px solid var(--background-border-color);
|
||||
|
||||
&--flex {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
justify-content: space-between;
|
||||
align-items: flex-start;
|
||||
|
||||
.status__content,
|
||||
.detailed-status__meta {
|
||||
flex: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.status__content {
|
||||
font-size: 19px;
|
||||
line-height: 24px;
|
||||
@ -1723,6 +1711,29 @@ body > [data-popper-placement] {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.logo {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
color: $dark-text-color;
|
||||
}
|
||||
}
|
||||
|
||||
.embed {
|
||||
position: relative;
|
||||
|
||||
&__overlay {
|
||||
display: block;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.detailed-status {
|
||||
border-top: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.scrollable > div:first-child .detailed-status {
|
||||
@ -6282,6 +6293,50 @@ a.status-card {
|
||||
}
|
||||
}
|
||||
|
||||
.dialog-modal {
|
||||
width: 588px;
|
||||
max-height: 80vh;
|
||||
flex-direction: column;
|
||||
background: var(--modal-background-color);
|
||||
backdrop-filter: var(--background-filter);
|
||||
border: 1px solid var(--modal-border-color);
|
||||
border-radius: 16px;
|
||||
|
||||
&__header {
|
||||
border-bottom: 1px solid var(--modal-border-color);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
flex-direction: row-reverse;
|
||||
padding: 12px 24px;
|
||||
|
||||
&__title {
|
||||
font-size: 16px;
|
||||
line-height: 24px;
|
||||
font-weight: 500;
|
||||
letter-spacing: 0.15px;
|
||||
}
|
||||
}
|
||||
|
||||
&__content {
|
||||
font-size: 14px;
|
||||
line-height: 20px;
|
||||
letter-spacing: 0.25px;
|
||||
overflow-y: auto;
|
||||
|
||||
&__form {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 16px;
|
||||
padding: 24px;
|
||||
}
|
||||
}
|
||||
|
||||
.copy-paste-text {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.hotkey-combination {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
@ -7730,69 +7785,6 @@ noscript {
|
||||
}
|
||||
}
|
||||
|
||||
.embed-modal {
|
||||
width: auto;
|
||||
max-width: 80vw;
|
||||
max-height: 80vh;
|
||||
|
||||
h4 {
|
||||
padding: 30px;
|
||||
font-weight: 500;
|
||||
font-size: 16px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.embed-modal__container {
|
||||
padding: 10px;
|
||||
|
||||
.hint {
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
|
||||
.embed-modal__html {
|
||||
outline: 0;
|
||||
box-sizing: border-box;
|
||||
display: block;
|
||||
width: 100%;
|
||||
border: 0;
|
||||
padding: 10px;
|
||||
font-family: $font-monospace, monospace;
|
||||
background: $ui-base-color;
|
||||
color: $primary-text-color;
|
||||
font-size: 14px;
|
||||
margin: 0;
|
||||
margin-bottom: 15px;
|
||||
border-radius: 4px;
|
||||
|
||||
&::-moz-focus-inner {
|
||||
border: 0;
|
||||
}
|
||||
|
||||
&::-moz-focus-inner,
|
||||
&:focus,
|
||||
&:active {
|
||||
outline: 0 !important;
|
||||
}
|
||||
|
||||
&:focus {
|
||||
background: lighten($ui-base-color, 4%);
|
||||
}
|
||||
|
||||
@media screen and (width <= 600px) {
|
||||
font-size: 16px;
|
||||
}
|
||||
}
|
||||
|
||||
.embed-modal__iframe {
|
||||
width: 400px;
|
||||
max-width: 100%;
|
||||
overflow: hidden;
|
||||
border: 0;
|
||||
border-radius: 4px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.moved-account-banner,
|
||||
.follow-request-banner,
|
||||
.account-memorial-banner {
|
||||
|
@ -1,152 +0,0 @@
|
||||
.activity-stream {
|
||||
box-shadow: 0 0 15px rgba($base-shadow-color, 0.2);
|
||||
border-radius: 4px;
|
||||
overflow: hidden;
|
||||
margin-bottom: 10px;
|
||||
|
||||
&--under-tabs {
|
||||
border-radius: 0 0 4px 4px;
|
||||
}
|
||||
|
||||
@media screen and (max-width: $no-gap-breakpoint) {
|
||||
margin-bottom: 0;
|
||||
border-radius: 0;
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
&--headless {
|
||||
border-radius: 0;
|
||||
margin: 0;
|
||||
box-shadow: none;
|
||||
|
||||
.detailed-status,
|
||||
.status {
|
||||
border-radius: 0 !important;
|
||||
}
|
||||
}
|
||||
|
||||
div[data-component] {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.entry {
|
||||
background: $ui-base-color;
|
||||
|
||||
.detailed-status,
|
||||
.status,
|
||||
.load-more {
|
||||
animation: none;
|
||||
}
|
||||
|
||||
&:last-child {
|
||||
.detailed-status,
|
||||
.status,
|
||||
.load-more {
|
||||
border-bottom: 0;
|
||||
border-radius: 0 0 4px 4px;
|
||||
}
|
||||
}
|
||||
|
||||
&:first-child {
|
||||
.detailed-status,
|
||||
.status,
|
||||
.load-more {
|
||||
border-radius: 4px 4px 0 0;
|
||||
}
|
||||
|
||||
&:last-child {
|
||||
.detailed-status,
|
||||
.status,
|
||||
.load-more {
|
||||
border-radius: 4px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (width <= 740px) {
|
||||
.detailed-status,
|
||||
.status,
|
||||
.load-more {
|
||||
border-radius: 0 !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&--highlighted .entry {
|
||||
background: lighten($ui-base-color, 8%);
|
||||
}
|
||||
}
|
||||
|
||||
.button.logo-button svg {
|
||||
width: 20px;
|
||||
height: auto;
|
||||
vertical-align: middle;
|
||||
margin-inline-end: 5px;
|
||||
fill: $primary-text-color;
|
||||
|
||||
@media screen and (max-width: $no-gap-breakpoint) {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
.embed {
|
||||
.status__content[data-spoiler='folded'] {
|
||||
.e-content {
|
||||
display: none;
|
||||
}
|
||||
|
||||
p:first-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.detailed-status {
|
||||
padding: 15px;
|
||||
|
||||
.detailed-status__display-avatar .account__avatar {
|
||||
width: 48px;
|
||||
height: 48px;
|
||||
}
|
||||
}
|
||||
|
||||
.status {
|
||||
padding: 15px 15px 15px (48px + 15px * 2);
|
||||
min-height: 48px + 2px;
|
||||
|
||||
&__avatar {
|
||||
inset-inline-start: 15px;
|
||||
top: 17px;
|
||||
|
||||
.account__avatar {
|
||||
width: 48px;
|
||||
height: 48px;
|
||||
}
|
||||
}
|
||||
|
||||
&__content {
|
||||
padding-top: 5px;
|
||||
}
|
||||
|
||||
&__prepend {
|
||||
margin-inline-start: 48px + 15px * 2;
|
||||
padding-top: 15px;
|
||||
}
|
||||
|
||||
&__prepend-icon-wrapper {
|
||||
inset-inline-start: -32px;
|
||||
}
|
||||
|
||||
.media-gallery,
|
||||
&__action-bar,
|
||||
.video-player {
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
&__action-bar-button {
|
||||
font-size: 18px;
|
||||
width: 23.1429px;
|
||||
height: 23.1429px;
|
||||
line-height: 23.15px;
|
||||
}
|
||||
}
|
||||
}
|
@ -225,7 +225,7 @@ class LinkDetailsExtractor
|
||||
end
|
||||
|
||||
def valid_url_or_nil(str, same_origin_only: false)
|
||||
return if str.blank? || str == 'null'
|
||||
return if str.blank? || str == 'null' || str == 'undefined'
|
||||
|
||||
url = @original_url + Addressable::URI.parse(str)
|
||||
|
||||
|
@ -1,6 +1,13 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
class OEmbedSerializer < ActiveModel::Serializer
|
||||
INLINE_STYLES = {
|
||||
blockquote: 'max-width: 540px; min-width: 270px; background:#FCF8FF; border: 1px solid #C9C4DA; border-radius: 8px; overflow: hidden; margin: 0; padding: 0;',
|
||||
a: "color: #1C1A25; text-decoration: none; display: flex; align-items: center; justify-content: center; flex-direction: column; padding: 24px; font-size: 14px; line-height: 20px; letter-spacing: 0.25px; font-family: system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Oxygen, Ubuntu, Cantarell, 'Fira Sans', 'Droid Sans', 'Helvetica Neue', Roboto, sans-serif;", # rubocop:disable Layout/LineLength
|
||||
div0: 'margin-top: 16px; color: #787588;',
|
||||
div1: 'font-weight: 500;',
|
||||
}.freeze
|
||||
|
||||
include RoutingHelper
|
||||
include ActionView::Helpers::TagHelper
|
||||
|
||||
@ -37,16 +44,16 @@ class OEmbedSerializer < ActiveModel::Serializer
|
||||
end
|
||||
|
||||
def html
|
||||
attributes = {
|
||||
src: embed_short_account_status_url(object.account, object),
|
||||
class: 'mastodon-embed',
|
||||
style: 'max-width: 100%; border: 0',
|
||||
width: width,
|
||||
height: height,
|
||||
allowfullscreen: true,
|
||||
}
|
||||
|
||||
content_tag(:iframe, nil, attributes) + content_tag(:script, nil, src: full_asset_url('embed.js', skip_pipeline: true), async: true)
|
||||
<<~HTML.squish
|
||||
<blockquote class="mastodon-embed" data-embed-url="#{embed_short_account_status_url(object.account, object)}" style="#{INLINE_STYLES[:blockquote]}">
|
||||
<a href="#{short_account_status_url(object.account, object)}" target="_blank" style="#{INLINE_STYLES[:a]}">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="32" height="32" viewBox="0 0 79 75"><path d="M74.7135 16.6043C73.6199 8.54587 66.5351 2.19527 58.1366 0.964691C56.7196 0.756754 51.351 0 38.9148 0H38.822C26.3824 0 23.7135 0.756754 22.2966 0.964691C14.1319 2.16118 6.67571 7.86752 4.86669 16.0214C3.99657 20.0369 3.90371 24.4888 4.06535 28.5726C4.29578 34.4289 4.34049 40.275 4.877 46.1075C5.24791 49.9817 5.89495 53.8251 6.81328 57.6088C8.53288 64.5968 15.4938 70.4122 22.3138 72.7848C29.6155 75.259 37.468 75.6697 44.9919 73.971C45.8196 73.7801 46.6381 73.5586 47.4475 73.3063C49.2737 72.7302 51.4164 72.086 52.9915 70.9542C53.0131 70.9384 53.0308 70.9178 53.0433 70.8942C53.0558 70.8706 53.0628 70.8445 53.0637 70.8179V65.1661C53.0634 65.1412 53.0574 65.1167 53.0462 65.0944C53.035 65.0721 53.0189 65.0525 52.9992 65.0371C52.9794 65.0218 52.9564 65.011 52.9318 65.0056C52.9073 65.0002 52.8819 65.0003 52.8574 65.0059C48.0369 66.1472 43.0971 66.7193 38.141 66.7103C29.6118 66.7103 27.3178 62.6981 26.6609 61.0278C26.1329 59.5842 25.7976 58.0784 25.6636 56.5486C25.6622 56.5229 25.667 56.4973 25.6775 56.4738C25.688 56.4502 25.7039 56.4295 25.724 56.4132C25.7441 56.397 25.7678 56.3856 25.7931 56.3801C25.8185 56.3746 25.8448 56.3751 25.8699 56.3816C30.6101 57.5151 35.4693 58.0873 40.3455 58.086C41.5183 58.086 42.6876 58.086 43.8604 58.0553C48.7647 57.919 53.9339 57.6701 58.7591 56.7361C58.8794 56.7123 58.9998 56.6918 59.103 56.6611C66.7139 55.2124 73.9569 50.665 74.6929 39.1501C74.7204 38.6967 74.7892 34.4016 74.7892 33.9312C74.7926 32.3325 75.3085 22.5901 74.7135 16.6043ZM62.9996 45.3371H54.9966V25.9069C54.9966 21.8163 53.277 19.7302 49.7793 19.7302C45.9343 19.7302 44.0083 22.1981 44.0083 27.0727V37.7082H36.0534V27.0727C36.0534 22.1981 34.124 19.7302 30.279 19.7302C26.8019 19.7302 25.0651 21.8163 25.0617 25.9069V45.3371H17.0656V25.3172C17.0656 21.2266 18.1191 17.9769 20.2262 15.568C22.3998 13.1648 25.2509 11.9308 28.7898 11.9308C32.8859 11.9308 35.9812 13.492 38.0447 16.6111L40.036 19.9245L42.0308 16.6111C44.0943 13.492 47.1896 11.9308 51.2788 11.9308C54.8143 11.9308 57.6654 13.1648 59.8459 15.568C61.9529 17.9746 63.0065 21.2243 63.0065 25.3172L62.9996 45.3371Z" fill="currentColor"/></svg>
|
||||
<div style="#{INLINE_STYLES[:div0]}">Post by @#{object.account.pretty_acct}@#{provider_name}</div>
|
||||
<div style="#{INLINE_STYLES[:div1]}">View on Mastodon</div>
|
||||
</a>
|
||||
</blockquote>
|
||||
<script data-allowed-prefixes="#{root_url}" async src="#{full_asset_url('embed.js', skip_pipeline: true)}"></script>
|
||||
HTML
|
||||
end
|
||||
|
||||
def width
|
||||
|
@ -15,8 +15,7 @@
|
||||
= javascript_pack_tag 'common', integrity: true, crossorigin: 'anonymous'
|
||||
= preload_locale_pack
|
||||
= render_initial_state
|
||||
= flavoured_javascript_pack_tag 'public', integrity: true, crossorigin: 'anonymous'
|
||||
|
||||
= flavoured_javascript_pack_tag 'embed', integrity: true, crossorigin: 'anonymous'
|
||||
%body.embed
|
||||
= yield
|
||||
|
||||
|
@ -1,80 +0,0 @@
|
||||
.detailed-status.detailed-status--flex{ class: "detailed-status-#{status.visibility}" }
|
||||
.p-author.h-card
|
||||
= link_to ActivityPub::TagManager.instance.url_for(status.account), class: 'detailed-status__display-name u-url', target: stream_link_target, rel: 'noopener' do
|
||||
.detailed-status__display-avatar
|
||||
- if prefers_autoplay?
|
||||
= image_tag status.account.avatar_original_url, alt: '', class: 'account__avatar u-photo'
|
||||
- else
|
||||
= image_tag status.account.avatar_static_url, alt: '', class: 'account__avatar u-photo'
|
||||
%span.display-name
|
||||
%bdi
|
||||
%strong.display-name__html.p-name.emojify= display_name(status.account, custom_emojify: true, autoplay: prefers_autoplay?)
|
||||
%span.display-name__account
|
||||
= acct(status.account)
|
||||
= material_symbol('lock') if status.account.locked?
|
||||
|
||||
= account_action_button(status.account)
|
||||
|
||||
.status__content.emojify{ data: ({ spoiler: current_account&.user&.setting_expand_spoilers ? 'expanded' : 'folded' } if status.spoiler_text?) }<
|
||||
- if status.spoiler_text?
|
||||
%p<
|
||||
%span.p-summary> #{prerender_custom_emojis(h(status.spoiler_text), status.emojis)}
|
||||
%button.status__content__spoiler-link= t('statuses.show_more')
|
||||
.e-content{ lang: status.language }
|
||||
= prerender_custom_emojis(status_content_format(status), status.emojis)
|
||||
|
||||
- if status.preloadable_poll
|
||||
= render_poll_component(status)
|
||||
|
||||
- if !status.ordered_media_attachments.empty?
|
||||
- if status.ordered_media_attachments.first.video?
|
||||
= render_video_component(status, width: 670, height: 380, detailed: true)
|
||||
- elsif status.ordered_media_attachments.first.audio?
|
||||
= render_audio_component(status, width: 670, height: 380)
|
||||
- else
|
||||
= render_media_gallery_component(status, height: 380, standalone: true)
|
||||
- elsif status.preview_card
|
||||
= render_card_component(status)
|
||||
|
||||
.detailed-status__meta
|
||||
%data.dt-published{ value: status.created_at.to_time.iso8601 }
|
||||
- if status.edited?
|
||||
%data.dt-updated{ value: status.edited_at.to_time.iso8601 }
|
||||
|
||||
= link_to ActivityPub::TagManager.instance.url_for(status), class: 'detailed-status__datetime u-url u-uid', target: stream_link_target, rel: 'noopener noreferrer' do
|
||||
%time.formatted{ datetime: status.created_at.iso8601, title: l(status.created_at) }= l(status.created_at)
|
||||
·
|
||||
- if status.edited?
|
||||
= t('statuses.edited_at_html', date: content_tag(:time, l(status.edited_at), datetime: status.edited_at.iso8601, title: l(status.edited_at), class: 'formatted'))
|
||||
·
|
||||
%span.detailed-status__visibility-icon
|
||||
= visibility_icon status
|
||||
·
|
||||
- if status.application && status.account.user&.setting_show_application
|
||||
- if status.application.website.blank?
|
||||
%strong.detailed-status__application= status.application.name
|
||||
- else
|
||||
= link_to status.application.name, status.application.website, class: 'detailed-status__application', target: '_blank', rel: 'noopener noreferrer'
|
||||
·
|
||||
%span.detailed-status__link
|
||||
- if status.in_reply_to_id.nil?
|
||||
= material_symbol('reply')
|
||||
- else
|
||||
= material_symbol('reply_all')
|
||||
%span.detailed-status__reblogs>= friendly_number_to_human status.replies_count
|
||||
|
||||
·
|
||||
- if status.public_visibility? || status.unlisted_visibility?
|
||||
%span.detailed-status__link
|
||||
= material_symbol('repeat')
|
||||
%span.detailed-status__reblogs>= friendly_number_to_human status.reblogs_count
|
||||
|
||||
·
|
||||
%span.detailed-status__link
|
||||
= material_symbol('star')
|
||||
%span.detailed-status__favorites>= friendly_number_to_human status.favourites_count
|
||||
|
||||
|
||||
- if user_signed_in?
|
||||
·
|
||||
= link_to t('statuses.open_in_web'), web_url("@#{status.account.pretty_acct}/#{status.id}"), class: 'detailed-status__application', target: '_blank', rel: 'noopener noreferrer'
|
@ -1,36 +0,0 @@
|
||||
:ruby
|
||||
show_results = (user_signed_in? && poll.voted?(current_account)) || poll.expired?
|
||||
total_votes_count = poll.voters_count || poll.votes_count
|
||||
|
||||
.poll
|
||||
%ul
|
||||
- poll.loaded_options.each do |option|
|
||||
%li
|
||||
- if show_results
|
||||
- percent = total_votes_count.positive? ? 100 * option.votes_count / total_votes_count : 0
|
||||
%label.poll__option><
|
||||
%span.poll__number><
|
||||
#{percent.round}%
|
||||
%span.poll__option__text
|
||||
= prerender_custom_emojis(h(option.title), status.emojis)
|
||||
|
||||
%progress{ max: 100, value: [percent, 1].max, 'aria-hidden': 'true' }
|
||||
%span.poll__chart
|
||||
- else
|
||||
%label.poll__option><
|
||||
%span.poll__input{ class: poll.multiple? ? 'checkbox' : nil }><
|
||||
%span.poll__option__text
|
||||
= prerender_custom_emojis(h(option.title), status.emojis)
|
||||
.poll__footer
|
||||
- unless show_results
|
||||
%button.button.button-secondary{ disabled: true }
|
||||
= t('statuses.poll.vote')
|
||||
|
||||
- if poll.voters_count.nil?
|
||||
%span= t('statuses.poll.total_votes', count: poll.votes_count)
|
||||
- else
|
||||
%span= t('statuses.poll.total_people', count: poll.voters_count)
|
||||
|
||||
- unless poll.expires_at.nil?
|
||||
·
|
||||
%span= l poll.expires_at
|
@ -1,70 +0,0 @@
|
||||
:ruby
|
||||
hide_show_thread ||= false
|
||||
|
||||
.status{ class: "status-#{status.visibility}" }
|
||||
.status__info
|
||||
= link_to ActivityPub::TagManager.instance.url_for(status), class: 'status__relative-time u-url u-uid', target: stream_link_target, rel: 'noopener noreferrer' do
|
||||
%span.status__visibility-icon><
|
||||
= visibility_icon status
|
||||
%time.time-ago{ datetime: status.created_at.iso8601, title: l(status.created_at) }= l(status.created_at)
|
||||
- if status.edited?
|
||||
%abbr{ title: t('statuses.edited_at_html', date: l(status.edited_at.to_date)) }
|
||||
*
|
||||
%data.dt-published{ value: status.created_at.to_time.iso8601 }
|
||||
|
||||
.p-author.h-card
|
||||
= link_to ActivityPub::TagManager.instance.url_for(status.account), class: 'status__display-name u-url', target: stream_link_target, rel: 'noopener noreferrer' do
|
||||
.status__avatar
|
||||
%div
|
||||
- if prefers_autoplay?
|
||||
= image_tag status.account.avatar_original_url, alt: '', class: 'u-photo account__avatar'
|
||||
- else
|
||||
= image_tag status.account.avatar_static_url, alt: '', class: 'u-photo account__avatar'
|
||||
%span.display-name
|
||||
%bdi
|
||||
%strong.display-name__html.p-name.emojify= display_name(status.account, custom_emojify: true, autoplay: prefers_autoplay?)
|
||||
|
||||
%span.display-name__account
|
||||
= acct(status.account)
|
||||
= material_symbol('lock') if status.account.locked?
|
||||
.status__content.emojify{ data: ({ spoiler: current_account&.user&.setting_expand_spoilers ? 'expanded' : 'folded' } if status.spoiler_text?) }<
|
||||
- if status.spoiler_text?
|
||||
%p<
|
||||
%span.p-summary> #{prerender_custom_emojis(h(status.spoiler_text), status.emojis)}
|
||||
%button.status__content__spoiler-link= t('statuses.show_more')
|
||||
.e-content{ lang: status.language }<
|
||||
= prerender_custom_emojis(status_content_format(status), status.emojis)
|
||||
|
||||
- if status.preloadable_poll
|
||||
= render_poll_component(status)
|
||||
|
||||
- if !status.ordered_media_attachments.empty?
|
||||
- if status.ordered_media_attachments.first.video?
|
||||
= render_video_component(status, width: 610, height: 343)
|
||||
- elsif status.ordered_media_attachments.first.audio?
|
||||
= render_audio_component(status, width: 610, height: 343)
|
||||
- else
|
||||
= render_media_gallery_component(status, height: 343)
|
||||
- elsif status.preview_card
|
||||
= render_card_component(status)
|
||||
|
||||
- if !status.in_reply_to_id.nil? && status.in_reply_to_account_id == status.account.id && !hide_show_thread
|
||||
= link_to ActivityPub::TagManager.instance.url_for(status), class: 'status__content__read-more-button', target: stream_link_target, rel: 'noopener noreferrer' do
|
||||
= t 'statuses.show_thread'
|
||||
|
||||
.status__action-bar
|
||||
%span.status__action-bar-button.icon-button.icon-button--with-counter
|
||||
- if status.in_reply_to_id.nil?
|
||||
= material_symbol 'reply'
|
||||
- else
|
||||
= material_symbol 'reply_all'
|
||||
%span.icon-button__counter= obscured_counter status.replies_count
|
||||
%span.status__action-bar-button.icon-button
|
||||
- if status.distributable?
|
||||
= material_symbol 'repeat'
|
||||
- elsif status.private_visibility? || status.limited_visibility?
|
||||
= material_symbol 'lock'
|
||||
- else
|
||||
= material_symbol 'alternate_email'
|
||||
%span.status__action-bar-button.icon-button
|
||||
= material_symbol 'star'
|
@ -1,2 +0,0 @@
|
||||
.entry
|
||||
= render (centered ? 'statuses/detailed_status' : 'statuses/simple_status'), status: status.proper, hide_show_thread: false
|
@ -1,2 +1 @@
|
||||
.activity-stream.activity-stream--headless
|
||||
= render 'status', status: @status, centered: true
|
||||
#mastodon-status{ data: { props: Oj.dump(default_props.merge(id: @status.id.to_s)) } }
|
||||
|
@ -38,17 +38,16 @@ Rails.application.config.content_security_policy do |p|
|
||||
p.img_src :self, :data, :blob, *media_hosts
|
||||
p.style_src :self, assets_host
|
||||
p.media_src :self, :data, *media_hosts
|
||||
p.frame_src :self, :https
|
||||
p.manifest_src :self, assets_host
|
||||
|
||||
if sso_host.present?
|
||||
p.form_action :self, sso_host
|
||||
p.form_action :self, sso_host
|
||||
else
|
||||
p.form_action :self
|
||||
p.form_action :self
|
||||
end
|
||||
|
||||
p.child_src :self, :blob, assets_host
|
||||
p.worker_src :self, :blob, assets_host
|
||||
p.child_src :self, :blob, assets_host
|
||||
p.worker_src :self, :blob, assets_host
|
||||
|
||||
if Rails.env.development?
|
||||
webpacker_public_host = ENV.fetch('WEBPACKER_DEV_SERVER_PUBLIC', Webpacker.config.dev_server[:public])
|
||||
@ -56,9 +55,11 @@ Rails.application.config.content_security_policy do |p|
|
||||
|
||||
p.connect_src :self, :data, :blob, *media_hosts, Rails.configuration.x.streaming_api_base_url, *front_end_build_urls
|
||||
p.script_src :self, :unsafe_inline, :unsafe_eval, assets_host
|
||||
p.frame_src :self, :https, :http
|
||||
else
|
||||
p.connect_src :self, :data, :blob, *media_hosts, Rails.configuration.x.streaming_api_base_url
|
||||
p.script_src :self, assets_host, "'wasm-unsafe-eval'"
|
||||
p.frame_src :self, :https
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -6,7 +6,6 @@ af:
|
||||
hosted_on: Mastodon gehuisves op %{domain}
|
||||
title: Aangaande
|
||||
accounts:
|
||||
follow: Volg
|
||||
followers:
|
||||
one: Volgeling
|
||||
other: Volgelinge
|
||||
|
@ -7,7 +7,6 @@ an:
|
||||
hosted_on: Mastodon alochau en %{domain}
|
||||
title: Sobre
|
||||
accounts:
|
||||
follow: Seguir
|
||||
followers:
|
||||
one: Seguidor
|
||||
other: Seguidores
|
||||
@ -1410,23 +1409,12 @@ an:
|
||||
edited_at_html: Editau %{date}
|
||||
errors:
|
||||
in_reply_not_found: Lo estau a lo qual intentas responder no existe.
|
||||
open_in_web: Ubrir en web
|
||||
over_character_limit: Limite de caracters de %{max} superau
|
||||
pin_errors:
|
||||
direct: Las publicacions que son visibles solo pa los usuarios mencionaus no pueden fixar-se
|
||||
limit: Ya has fixau lo numero maximo de publicacions
|
||||
ownership: La publicación d'unatra persona no puede fixar-se
|
||||
reblog: Un boost no puede fixar-se
|
||||
poll:
|
||||
total_people:
|
||||
one: "%{count} persona"
|
||||
other: "%{count} chent"
|
||||
total_votes:
|
||||
one: "%{count} voto"
|
||||
other: "%{count} votos"
|
||||
vote: Vota
|
||||
show_more: Amostrar mas
|
||||
show_thread: Amostrar discusión
|
||||
title: "%{name}: «%{quote}»"
|
||||
visibilities:
|
||||
direct: Directa
|
||||
|
@ -7,7 +7,6 @@ ar:
|
||||
hosted_on: ماستدون مُستضاف على %{domain}
|
||||
title: عن
|
||||
accounts:
|
||||
follow: متابَعة
|
||||
followers:
|
||||
few: متابِعون
|
||||
many: متابِعون
|
||||
@ -1772,31 +1771,12 @@ ar:
|
||||
edited_at_html: عُدّل في %{date}
|
||||
errors:
|
||||
in_reply_not_found: إنّ المنشور الذي تحاول الرد عليه غير موجود على ما يبدو.
|
||||
open_in_web: افتح في الويب
|
||||
over_character_limit: تم تجاوز حد الـ %{max} حرف المسموح بها
|
||||
pin_errors:
|
||||
direct: لا يمكن تثبيت المنشورات التي يراها فقط المتسخدمون المشار إليهم
|
||||
limit: لقد بلغت الحد الأقصى للمنشورات المثبتة
|
||||
ownership: لا يمكن تثبيت منشور نشره شخص آخر
|
||||
reblog: لا يمكن تثبيت إعادة نشر
|
||||
poll:
|
||||
total_people:
|
||||
few: "%{count} أشخاص"
|
||||
many: "%{count} أشخاص"
|
||||
one: "%{count} شخص واحد"
|
||||
other: "%{count} شخصا"
|
||||
two: "%{count} شخصين"
|
||||
zero: "%{count} شخص"
|
||||
total_votes:
|
||||
few: "%{count} أصوات"
|
||||
many: "%{count} أصوات"
|
||||
one: صوت واحد %{count}
|
||||
other: "%{count} صوتا"
|
||||
two: صوتين %{count}
|
||||
zero: بدون صوت %{count}
|
||||
vote: صوّت
|
||||
show_more: أظهر المزيد
|
||||
show_thread: اعرض خيط المحادثة
|
||||
title: '%{name}: "%{quote}"'
|
||||
visibilities:
|
||||
direct: مباشرة
|
||||
|
@ -800,20 +800,11 @@ ast:
|
||||
default_language: La mesma que la de la interfaz
|
||||
errors:
|
||||
in_reply_not_found: L'artículu al que tentes de responder paez que nun esiste.
|
||||
open_in_web: Abrir na web
|
||||
pin_errors:
|
||||
direct: Nun se puen fixar los artículos que son visibles namás pa los usuarios mentaos
|
||||
limit: Yá fixesti'l númberu máximu d'artículos
|
||||
ownership: Nun se pue fixar l'artículu d'otru perfil
|
||||
reblog: Nun se pue fixar un artículu compartíu
|
||||
poll:
|
||||
total_people:
|
||||
one: "%{count} persona"
|
||||
other: "%{count} persones"
|
||||
total_votes:
|
||||
one: "%{count} votu"
|
||||
other: "%{count} votos"
|
||||
show_more: Amosar más
|
||||
title: "%{name}: «%{quote}»"
|
||||
visibilities:
|
||||
direct: Mensaxe direutu
|
||||
|
@ -7,7 +7,6 @@ be:
|
||||
hosted_on: Mastodon месціцца на %{domain}
|
||||
title: Пра нас
|
||||
accounts:
|
||||
follow: Падпісацца
|
||||
followers:
|
||||
few: Падпісчыка
|
||||
many: Падпісчыкаў
|
||||
@ -1778,27 +1777,12 @@ be:
|
||||
edited_at_html: Адрэдагавана %{date}
|
||||
errors:
|
||||
in_reply_not_found: Здаецца, допіс, на які вы спрабуеце адказаць, не існуе.
|
||||
open_in_web: Адчыніць у вэб-версіі
|
||||
over_character_limit: перавышаная колькасць сімвалаў у %{max}
|
||||
pin_errors:
|
||||
direct: Допісы, бачныя толькі згаданым карыстальнікам, не могуць быць замацаваныя
|
||||
limit: Вы ўжо замацавалі максімальную колькасць допісаў
|
||||
ownership: Немагчыма замацаваць чужы допіс
|
||||
reblog: Немагчыма замацаваць пашырэнне
|
||||
poll:
|
||||
total_people:
|
||||
few: "%{count} чалавекі"
|
||||
many: "%{count} чалавек"
|
||||
one: "%{count} чалавек"
|
||||
other: "%{count} чалавека"
|
||||
total_votes:
|
||||
few: "%{count} галасы"
|
||||
many: "%{count} галасоў"
|
||||
one: "%{count} голас"
|
||||
other: "%{count} голасу"
|
||||
vote: Прагаласаваць
|
||||
show_more: Паказаць больш
|
||||
show_thread: Паказаць ланцуг
|
||||
title: '%{name}: "%{quote}"'
|
||||
visibilities:
|
||||
direct: Асабіста
|
||||
|
@ -7,7 +7,6 @@ bg:
|
||||
hosted_on: Mastodon е разположен на хост %{domain}
|
||||
title: Относно
|
||||
accounts:
|
||||
follow: Последване
|
||||
followers:
|
||||
one: Последовател
|
||||
other: Последователи
|
||||
@ -1664,23 +1663,12 @@ bg:
|
||||
edited_at_html: Редактирано на %{date}
|
||||
errors:
|
||||
in_reply_not_found: Изглежда, че публикацията, на която се опитвате да отговорите, не съществува.
|
||||
open_in_web: Отвори в уеб
|
||||
over_character_limit: прехвърлен лимит от %{max} символа
|
||||
pin_errors:
|
||||
direct: Публикациите, които са видими само за потребители споменати в тях, не могат да бъдат закачани
|
||||
limit: Вече сте закачили максималния брой публикации
|
||||
ownership: Публикация на някого другиго не може да бъде закачена
|
||||
reblog: Раздуване не може да бъде закачано
|
||||
poll:
|
||||
total_people:
|
||||
one: "%{count} човек"
|
||||
other: "%{count} души"
|
||||
total_votes:
|
||||
one: "%{count} глас"
|
||||
other: "%{count} гласа"
|
||||
vote: Гласуване
|
||||
show_more: Покажи повече
|
||||
show_thread: Показване на нишката
|
||||
title: "%{name}: „%{quote}“"
|
||||
visibilities:
|
||||
direct: Директно
|
||||
|
@ -7,7 +7,6 @@ bn:
|
||||
hosted_on: এই মাস্টাডনটি আছে %{domain} এ
|
||||
title: পরিচিতি
|
||||
accounts:
|
||||
follow: যুক্ত
|
||||
followers:
|
||||
one: যুক্ত আছে
|
||||
other: যারা যুক্ত হয়েছে
|
||||
|
@ -6,7 +6,6 @@ br:
|
||||
hosted_on: Servijer Mastodon herberc'hiet war %{domain}
|
||||
title: Diwar-benn
|
||||
accounts:
|
||||
follow: Heuliañ
|
||||
followers:
|
||||
few: Heulier·ez
|
||||
many: Heulier·ez
|
||||
@ -519,9 +518,6 @@ br:
|
||||
two: "%{count} skeudenn"
|
||||
pin_errors:
|
||||
ownership: N'hallit ket spilhennañ embannadurioù ar re all
|
||||
poll:
|
||||
vote: Mouezhiañ
|
||||
show_more: Diskouez muioc'h
|
||||
visibilities:
|
||||
direct: War-eeun
|
||||
public: Publik
|
||||
|
@ -7,7 +7,6 @@ ca:
|
||||
hosted_on: Mastodon allotjat a %{domain}
|
||||
title: Quant a
|
||||
accounts:
|
||||
follow: Segueix
|
||||
followers:
|
||||
one: Seguidor
|
||||
other: Seguidors
|
||||
@ -1734,23 +1733,12 @@ ca:
|
||||
edited_at_html: Editat %{date}
|
||||
errors:
|
||||
in_reply_not_found: El tut al qual intentes respondre sembla que no existeix.
|
||||
open_in_web: Obre en la web
|
||||
over_character_limit: Límit de caràcters de %{max} superat
|
||||
pin_errors:
|
||||
direct: Els tuts que només són visibles per als usuaris mencionats no poden ser fixats
|
||||
limit: Ja has fixat el màxim nombre de tuts
|
||||
ownership: No es pot fixar el tut d'algú altre
|
||||
reblog: No es pot fixar un impuls
|
||||
poll:
|
||||
total_people:
|
||||
one: "%{count} persona"
|
||||
other: "%{count} persones"
|
||||
total_votes:
|
||||
one: "%{count} vot"
|
||||
other: "%{count} vots"
|
||||
vote: Vota
|
||||
show_more: Mostra'n més
|
||||
show_thread: Mostra el fil
|
||||
title: '%{name}: "%{quote}"'
|
||||
visibilities:
|
||||
direct: Directe
|
||||
|
@ -7,7 +7,6 @@ ckb:
|
||||
hosted_on: مەستودۆن میوانداری کراوە لە %{domain}
|
||||
title: دەربارە
|
||||
accounts:
|
||||
follow: شوێن کەوە
|
||||
followers:
|
||||
one: شوێنکەوتوو
|
||||
other: شوێنکەوتووان
|
||||
@ -938,22 +937,11 @@ ckb:
|
||||
other: 'هاشتاگەکانی ڕێگەپێنەدراوەی تێدابوو: %{tags}'
|
||||
errors:
|
||||
in_reply_not_found: ئەو دۆخەی کە تۆ هەوڵی وەڵامدانەوەی دەدەیت وادەرناکەوێت کە هەبێت.
|
||||
open_in_web: کردنەوە لە وێب
|
||||
over_character_limit: سنووری نووسەی %{max} تێپەڕێنرا
|
||||
pin_errors:
|
||||
limit: تۆ پێشتر زۆرترین ژمارەی توتتی چەسپیوەت هەیە
|
||||
ownership: نووسراوەکانی تر ناتوانرێ بسەلمێت
|
||||
reblog: بەهێزکردن ناتوانرێت بچەسپێ
|
||||
poll:
|
||||
total_people:
|
||||
one: "%{count} کەس"
|
||||
other: "%{count} خەڵک"
|
||||
total_votes:
|
||||
one: "%{count} دەنگ"
|
||||
other: "%{count} دەنگەکان"
|
||||
vote: دەنگ
|
||||
show_more: زیاتر پیشان بدە
|
||||
show_thread: نیشاندانی ڕشتە
|
||||
visibilities:
|
||||
private: شوێنکەوتوانی تەنها
|
||||
private_long: تەنها بۆ شوێنکەوتوانی پیشان بدە
|
||||
|
@ -6,7 +6,6 @@ co:
|
||||
contact_unavailable: Micca dispunibule
|
||||
hosted_on: Mastodon allughjatu nant’à %{domain}
|
||||
accounts:
|
||||
follow: Siguità
|
||||
followers:
|
||||
one: Abbunatu·a
|
||||
other: Abbunati
|
||||
@ -922,22 +921,11 @@ co:
|
||||
other: 'cuntene l’hashtag disattivati: %{tags}'
|
||||
errors:
|
||||
in_reply_not_found: U statutu à quellu avete pruvatu di risponde ùn sembra micca esiste.
|
||||
open_in_web: Apre nant’à u web
|
||||
over_character_limit: site sopr’à a limita di %{max} caratteri
|
||||
pin_errors:
|
||||
limit: Avete digià puntarulatu u numeru massimale di statuti
|
||||
ownership: Pudete puntarulà solu unu di i vostri propii statuti
|
||||
reblog: Ùn pudete micca puntarulà una spartera
|
||||
poll:
|
||||
total_people:
|
||||
one: "%{count} persona"
|
||||
other: "%{count} persone"
|
||||
total_votes:
|
||||
one: "%{count} votu"
|
||||
other: "%{count} voti"
|
||||
vote: Vutà
|
||||
show_more: Vede di più
|
||||
show_thread: Vede u filu
|
||||
title: '%{name}: "%{quote}"'
|
||||
visibilities:
|
||||
direct: Direttu
|
||||
|
@ -7,7 +7,6 @@ cs:
|
||||
hosted_on: Mastodon na doméně %{domain}
|
||||
title: O aplikaci
|
||||
accounts:
|
||||
follow: Sledovat
|
||||
followers:
|
||||
few: Sledující
|
||||
many: Sledujících
|
||||
@ -1721,27 +1720,12 @@ cs:
|
||||
edited_at_html: Upraven %{date}
|
||||
errors:
|
||||
in_reply_not_found: Příspěvek, na který se pokoušíte odpovědět, neexistuje.
|
||||
open_in_web: Otevřít na webu
|
||||
over_character_limit: byl překročen limit %{max} znaků
|
||||
pin_errors:
|
||||
direct: Příspěvky viditelné pouze zmíněným uživatelům nelze připnout
|
||||
limit: Už jste si připnuli maximální počet příspěvků
|
||||
ownership: Nelze připnout příspěvek někoho jiného
|
||||
reblog: Boosty nelze připnout
|
||||
poll:
|
||||
total_people:
|
||||
few: "%{count} lidé"
|
||||
many: "%{count} lidí"
|
||||
one: "%{count} člověk"
|
||||
other: "%{count} lidí"
|
||||
total_votes:
|
||||
few: "%{count} hlasy"
|
||||
many: "%{count} hlasů"
|
||||
one: "%{count} hlas"
|
||||
other: "%{count} hlasů"
|
||||
vote: Hlasovat
|
||||
show_more: Zobrazit více
|
||||
show_thread: Zobrazit vlákno
|
||||
title: "%{name}: „%{quote}“"
|
||||
visibilities:
|
||||
direct: Přímé
|
||||
|
@ -7,7 +7,6 @@ cy:
|
||||
hosted_on: Mastodon wedi ei weinyddu ar %{domain}
|
||||
title: Ynghylch
|
||||
accounts:
|
||||
follow: Dilyn
|
||||
followers:
|
||||
few: Dilynwyr
|
||||
many: Dilynwyr
|
||||
@ -1860,31 +1859,12 @@ cy:
|
||||
edited_at_html: Wedi'i olygu %{date}
|
||||
errors:
|
||||
in_reply_not_found: Nid yw'n ymddangos bod y postiad rydych chi'n ceisio ei ateb yn bodoli.
|
||||
open_in_web: Agor yn y we
|
||||
over_character_limit: wedi mynd y tu hwnt i'r terfyn nodau o %{max}
|
||||
pin_errors:
|
||||
direct: Nid oes modd pinio postiadau sy'n weladwy i ddefnyddwyr a grybwyllwyd yn unig
|
||||
limit: Rydych chi eisoes wedi pinio uchafswm nifer y postiadau
|
||||
ownership: Nid oes modd pinio postiad rhywun arall
|
||||
reblog: Nid oes modd pinio hwb
|
||||
poll:
|
||||
total_people:
|
||||
few: "%{count} person"
|
||||
many: "%{count} person"
|
||||
one: "%{count} berson"
|
||||
other: "%{count} person"
|
||||
two: "%{count} person"
|
||||
zero: "%{count} o bersonau"
|
||||
total_votes:
|
||||
few: "%{count} pleidlais"
|
||||
many: "%{count} pleidlais"
|
||||
one: "%{count} bleidlais"
|
||||
other: "%{count} pleidlais"
|
||||
two: "%{count} pleidlais"
|
||||
zero: "%{count} o bleidleisiau"
|
||||
vote: Pleidlais
|
||||
show_more: Dangos mwy
|
||||
show_thread: Dangos edefyn
|
||||
title: '%{name}: "%{quote}"'
|
||||
visibilities:
|
||||
direct: Uniongyrchol
|
||||
|
@ -7,7 +7,6 @@ da:
|
||||
hosted_on: Mastodon hostet på %{domain}
|
||||
title: Om
|
||||
accounts:
|
||||
follow: Følg
|
||||
followers:
|
||||
one: Følger
|
||||
other: tilhængere
|
||||
@ -1740,23 +1739,12 @@ da:
|
||||
edited_at_html: Redigeret %{date}
|
||||
errors:
|
||||
in_reply_not_found: Indlægget, der forsøges besvaret, ser ikke ud til at eksistere.
|
||||
open_in_web: Åbn i webbrowser
|
||||
over_character_limit: grænsen på %{max} tegn overskredet
|
||||
pin_errors:
|
||||
direct: Indlæg, som kun kan ses af omtalte brugere, kan ikke fastgøres
|
||||
limit: Maksimalt antal indlæg allerede fastgjort
|
||||
ownership: Andres indlæg kan ikke fastgøres
|
||||
reblog: Et boost kan ikke fastgøres
|
||||
poll:
|
||||
total_people:
|
||||
one: "%{count} person"
|
||||
other: "%{count} personer"
|
||||
total_votes:
|
||||
one: "%{count} stemme"
|
||||
other: "%{count} stemmer"
|
||||
vote: Stem
|
||||
show_more: Vis flere
|
||||
show_thread: Vis tråd
|
||||
title: '%{name}: "%{quote}"'
|
||||
visibilities:
|
||||
direct: Direkte
|
||||
|
@ -7,7 +7,6 @@ de:
|
||||
hosted_on: Mastodon, gehostet auf %{domain}
|
||||
title: Über
|
||||
accounts:
|
||||
follow: Folgen
|
||||
followers:
|
||||
one: Follower
|
||||
other: Follower
|
||||
@ -1740,23 +1739,12 @@ de:
|
||||
edited_at_html: 'Bearbeitet: %{date}'
|
||||
errors:
|
||||
in_reply_not_found: Der Beitrag, auf den du antworten möchtest, scheint nicht zu existieren.
|
||||
open_in_web: Im Webinterface öffnen
|
||||
over_character_limit: Begrenzung von %{max} Zeichen überschritten
|
||||
pin_errors:
|
||||
direct: Beiträge, die nur für erwähnte Profile sichtbar sind, können nicht angeheftet werden
|
||||
limit: Du hast bereits die maximale Anzahl an Beiträgen angeheftet
|
||||
ownership: Du kannst nur eigene Beiträge anheften
|
||||
reblog: Du kannst keine geteilten Beiträge anheften
|
||||
poll:
|
||||
total_people:
|
||||
one: "%{count} Stimme"
|
||||
other: "%{count} Stimmen"
|
||||
total_votes:
|
||||
one: "%{count} Stimme"
|
||||
other: "%{count} Stimmen"
|
||||
vote: Abstimmen
|
||||
show_more: Mehr anzeigen
|
||||
show_thread: Thread anzeigen
|
||||
title: "%{name}: „%{quote}“"
|
||||
visibilities:
|
||||
direct: Direktnachricht
|
||||
|
@ -7,7 +7,6 @@ el:
|
||||
hosted_on: Το Mastodon φιλοξενείται στο %{domain}
|
||||
title: Σχετικά
|
||||
accounts:
|
||||
follow: Ακολούθησε
|
||||
followers:
|
||||
one: Ακόλουθος
|
||||
other: Ακόλουθοι
|
||||
@ -1636,23 +1635,12 @@ el:
|
||||
edited_at_html: Επεξεργάστηκε στις %{date}
|
||||
errors:
|
||||
in_reply_not_found: Η ανάρτηση στην οποία προσπαθείς να απαντήσεις δεν φαίνεται να υπάρχει.
|
||||
open_in_web: Άνοιγμα στο διαδίκτυο
|
||||
over_character_limit: υπέρβαση μέγιστου ορίου %{max} χαρακτήρων
|
||||
pin_errors:
|
||||
direct: Αναρτήσεις που είναι ορατές μόνο στους αναφερόμενους χρήστες δεν μπορούν να καρφιτσωθούν
|
||||
limit: Έχεις ήδη καρφιτσώσει το μέγιστο αριθμό επιτρεπτών αναρτήσεων
|
||||
ownership: Δεν μπορείς να καρφιτσώσεις ανάρτηση κάποιου άλλου
|
||||
reblog: Οι ενισχύσεις δεν καρφιτσώνονται
|
||||
poll:
|
||||
total_people:
|
||||
one: "%{count} άτομο"
|
||||
other: "%{count} άτομα"
|
||||
total_votes:
|
||||
one: "%{count} ψήφος"
|
||||
other: "%{count} ψήφοι"
|
||||
vote: Ψήφισε
|
||||
show_more: Δείξε περισσότερα
|
||||
show_thread: Εμφάνιση νήματος
|
||||
title: '%{name}: "%{quote}"'
|
||||
visibilities:
|
||||
direct: Άμεση
|
||||
|
@ -7,7 +7,6 @@ en-GB:
|
||||
hosted_on: Mastodon hosted on %{domain}
|
||||
title: About
|
||||
accounts:
|
||||
follow: Follow
|
||||
followers:
|
||||
one: Follower
|
||||
other: Followers
|
||||
@ -1740,23 +1739,12 @@ en-GB:
|
||||
edited_at_html: Edited %{date}
|
||||
errors:
|
||||
in_reply_not_found: The post you are trying to reply to does not appear to exist.
|
||||
open_in_web: Open in web
|
||||
over_character_limit: character limit of %{max} exceeded
|
||||
pin_errors:
|
||||
direct: Posts that are only visible to mentioned users cannot be pinned
|
||||
limit: You have already pinned the maximum number of posts
|
||||
ownership: Someone else's post cannot be pinned
|
||||
reblog: A boost cannot be pinned
|
||||
poll:
|
||||
total_people:
|
||||
one: "%{count} person"
|
||||
other: "%{count} people"
|
||||
total_votes:
|
||||
one: "%{count} vote"
|
||||
other: "%{count} votes"
|
||||
vote: Vote
|
||||
show_more: Show more
|
||||
show_thread: Show thread
|
||||
title: '%{name}: "%{quote}"'
|
||||
visibilities:
|
||||
direct: Direct
|
||||
|
@ -7,7 +7,6 @@ en:
|
||||
hosted_on: Mastodon hosted on %{domain}
|
||||
title: About
|
||||
accounts:
|
||||
follow: Follow
|
||||
followers:
|
||||
one: Follower
|
||||
other: Followers
|
||||
@ -1741,23 +1740,12 @@ en:
|
||||
edited_at_html: Edited %{date}
|
||||
errors:
|
||||
in_reply_not_found: The post you are trying to reply to does not appear to exist.
|
||||
open_in_web: Open in web
|
||||
over_character_limit: character limit of %{max} exceeded
|
||||
pin_errors:
|
||||
direct: Posts that are only visible to mentioned users cannot be pinned
|
||||
limit: You have already pinned the maximum number of posts
|
||||
ownership: Someone else's post cannot be pinned
|
||||
reblog: A boost cannot be pinned
|
||||
poll:
|
||||
total_people:
|
||||
one: "%{count} person"
|
||||
other: "%{count} people"
|
||||
total_votes:
|
||||
one: "%{count} vote"
|
||||
other: "%{count} votes"
|
||||
vote: Vote
|
||||
show_more: Show more
|
||||
show_thread: Show thread
|
||||
title: '%{name}: "%{quote}"'
|
||||
visibilities:
|
||||
direct: Direct
|
||||
|
@ -7,7 +7,6 @@ eo:
|
||||
hosted_on: "%{domain} estas nodo de Mastodon"
|
||||
title: Pri
|
||||
accounts:
|
||||
follow: Sekvi
|
||||
followers:
|
||||
one: Sekvanto
|
||||
other: Sekvantoj
|
||||
@ -1553,23 +1552,12 @@ eo:
|
||||
edited_at_html: Redaktis je %{date}
|
||||
errors:
|
||||
in_reply_not_found: Mesaĝo kiun vi provas respondi ŝajnas ne ekzisti.
|
||||
open_in_web: Malfermi retumile
|
||||
over_character_limit: limo de %{max} signoj transpasita
|
||||
pin_errors:
|
||||
direct: Mesaĝoj kiu videbla nun al la uzantoj ne povas alpinglitis
|
||||
limit: Vi jam atingis la maksimuman nombron de alpinglitaj mesaĝoj
|
||||
ownership: Mesaĝo de iu alia ne povas esti alpinglita
|
||||
reblog: Diskonigo ne povas esti alpinglita
|
||||
poll:
|
||||
total_people:
|
||||
one: "%{count} persono"
|
||||
other: "%{count} personoj"
|
||||
total_votes:
|
||||
one: "%{count} voĉdono"
|
||||
other: "%{count} voĉdonoj"
|
||||
vote: Voĉdoni
|
||||
show_more: Montri pli
|
||||
show_thread: Montri la mesaĝaron
|
||||
title: "%{name}: “%{quote}”"
|
||||
visibilities:
|
||||
direct: Rekta
|
||||
|
@ -7,7 +7,6 @@ es-AR:
|
||||
hosted_on: Mastodon alojado en %{domain}
|
||||
title: Información
|
||||
accounts:
|
||||
follow: Seguir
|
||||
followers:
|
||||
one: Seguidor
|
||||
other: Seguidores
|
||||
@ -1740,23 +1739,12 @@ es-AR:
|
||||
edited_at_html: Editado el %{date}
|
||||
errors:
|
||||
in_reply_not_found: El mensaje al que intentás responder no existe.
|
||||
open_in_web: Abrir en la web
|
||||
over_character_limit: se excedió el límite de %{max} caracteres
|
||||
pin_errors:
|
||||
direct: Los mensajes que sólo son visibles para los usuarios mencionados no pueden ser fijados
|
||||
limit: Ya fijaste el número máximo de mensajes
|
||||
ownership: No se puede fijar el mensaje de otra cuenta
|
||||
reblog: No se puede fijar una adhesión
|
||||
poll:
|
||||
total_people:
|
||||
one: "%{count} persona"
|
||||
other: "%{count} personas"
|
||||
total_votes:
|
||||
one: "%{count} voto"
|
||||
other: "%{count} votos"
|
||||
vote: Votar
|
||||
show_more: Mostrar más
|
||||
show_thread: Mostrar hilo
|
||||
title: '%{name}: "%{quote}"'
|
||||
visibilities:
|
||||
direct: Directo
|
||||
|
@ -7,7 +7,6 @@ es-MX:
|
||||
hosted_on: Mastodon alojado en %{domain}
|
||||
title: Acerca de
|
||||
accounts:
|
||||
follow: Seguir
|
||||
followers:
|
||||
one: Seguidor
|
||||
other: Seguidores
|
||||
@ -1730,23 +1729,12 @@ es-MX:
|
||||
edited_at_html: Editado %{date}
|
||||
errors:
|
||||
in_reply_not_found: El estado al que intentas responder no existe.
|
||||
open_in_web: Abrir en web
|
||||
over_character_limit: Límite de caracteres de %{max} superado
|
||||
pin_errors:
|
||||
direct: Las publicaciones que son visibles solo para los usuarios mencionados no pueden fijarse
|
||||
limit: Ya has fijado el número máximo de publicaciones
|
||||
ownership: El toot de alguien más no puede fijarse
|
||||
reblog: Un boost no puede fijarse
|
||||
poll:
|
||||
total_people:
|
||||
one: persona %{count}
|
||||
other: "%{count} gente"
|
||||
total_votes:
|
||||
one: "%{count} voto"
|
||||
other: "%{count} votos"
|
||||
vote: Vota
|
||||
show_more: Mostrar más
|
||||
show_thread: Mostrar discusión
|
||||
title: "%{name}: «%{quote}»"
|
||||
visibilities:
|
||||
direct: Directa
|
||||
|
@ -7,7 +7,6 @@ es:
|
||||
hosted_on: Mastodon alojado en %{domain}
|
||||
title: Acerca de
|
||||
accounts:
|
||||
follow: Seguir
|
||||
followers:
|
||||
one: Seguidor
|
||||
other: Seguidores
|
||||
@ -1730,23 +1729,12 @@ es:
|
||||
edited_at_html: Editado %{date}
|
||||
errors:
|
||||
in_reply_not_found: La publicación a la que intentas responder no existe.
|
||||
open_in_web: Abrir en web
|
||||
over_character_limit: Límite de caracteres de %{max} superado
|
||||
pin_errors:
|
||||
direct: Las publicaciones que son visibles solo para los usuarios mencionados no pueden fijarse
|
||||
limit: Ya has fijado el número máximo de publicaciones
|
||||
ownership: La publicación de otra persona no puede fijarse
|
||||
reblog: Un boost no puede fijarse
|
||||
poll:
|
||||
total_people:
|
||||
one: "%{count} persona"
|
||||
other: "%{count} personas"
|
||||
total_votes:
|
||||
one: "%{count} voto"
|
||||
other: "%{count} votos"
|
||||
vote: Vota
|
||||
show_more: Mostrar más
|
||||
show_thread: Mostrar discusión
|
||||
title: "%{name}: «%{quote}»"
|
||||
visibilities:
|
||||
direct: Directa
|
||||
|
@ -7,7 +7,6 @@ et:
|
||||
hosted_on: Mastodon majutatud %{domain}-is
|
||||
title: Teave
|
||||
accounts:
|
||||
follow: Jälgi
|
||||
followers:
|
||||
one: Jälgija
|
||||
other: Jälgijaid
|
||||
@ -1701,23 +1700,12 @@ et:
|
||||
edited_at_html: Muudetud %{date}
|
||||
errors:
|
||||
in_reply_not_found: Postitus, millele üritad vastata, ei näi enam eksisteerivat.
|
||||
open_in_web: Ava veebis
|
||||
over_character_limit: tähtmärkide limiit %{max} ületatud
|
||||
pin_errors:
|
||||
direct: Ei saa kinnitada postitusi, mis on nähtavad vaid mainitud kasutajatele
|
||||
limit: Kinnitatud on juba maksimaalne arv postitusi
|
||||
ownership: Kellegi teise postitust ei saa kinnitada
|
||||
reblog: Jagamist ei saa kinnitada
|
||||
poll:
|
||||
total_people:
|
||||
one: "%{count} inimene"
|
||||
other: "%{count} inimest"
|
||||
total_votes:
|
||||
one: "%{count} hääl"
|
||||
other: "%{count} häält"
|
||||
vote: Hääleta
|
||||
show_more: Näita rohkem
|
||||
show_thread: Kuva lõim
|
||||
title: '%{name}: "%{quote}"'
|
||||
visibilities:
|
||||
direct: Otsene
|
||||
|
@ -7,7 +7,6 @@ eu:
|
||||
hosted_on: Mastodon %{domain} domeinuan ostatatua
|
||||
title: Honi buruz
|
||||
accounts:
|
||||
follow: Jarraitu
|
||||
followers:
|
||||
one: Jarraitzaile
|
||||
other: jarraitzaile
|
||||
@ -1639,23 +1638,12 @@ eu:
|
||||
edited_at_html: Editatua %{date}
|
||||
errors:
|
||||
in_reply_not_found: Erantzuten saiatu zaren bidalketa antza ez da existitzen.
|
||||
open_in_web: Ireki web-ean
|
||||
over_character_limit: "%{max}eko karaktere muga gaindituta"
|
||||
pin_errors:
|
||||
direct: Aipatutako erabiltzaileentzat soilik ikusgai dauden bidalketak ezin dira finkatu
|
||||
limit: Gehienez finkatu daitekeen bidalketa kopurua finkatu duzu jada
|
||||
ownership: Ezin duzu beste norbaiten bidalketa bat finkatu
|
||||
reblog: Bultzada bat ezin da finkatu
|
||||
poll:
|
||||
total_people:
|
||||
one: pertsona %{count}
|
||||
other: "%{count} pertsona"
|
||||
total_votes:
|
||||
one: Boto %{count}
|
||||
other: "%{count} boto"
|
||||
vote: Bozkatu
|
||||
show_more: Erakutsi gehiago
|
||||
show_thread: Erakutsi haria
|
||||
title: '%{name}: "%{quote}"'
|
||||
visibilities:
|
||||
direct: Zuzena
|
||||
|
@ -7,7 +7,6 @@ fa:
|
||||
hosted_on: ماستودون، میزبانیشده روی %{domain}
|
||||
title: درباره
|
||||
accounts:
|
||||
follow: پیگیری
|
||||
followers:
|
||||
one: پیگیر
|
||||
other: پیگیر
|
||||
@ -1404,23 +1403,12 @@ fa:
|
||||
edited_at_html: ویراسته در %{date}
|
||||
errors:
|
||||
in_reply_not_found: به نظر نمیرسد وضعیتی که میخواهید به آن پاسخ دهید، وجود داشته باشد.
|
||||
open_in_web: گشودن در وب
|
||||
over_character_limit: از حد مجاز %{max} حرف فراتر رفتید
|
||||
pin_errors:
|
||||
direct: فرستههایی که فقط برای کاربران اشاره شده نمایانند نمیتوانند سنجاق شوند
|
||||
limit: از این بیشتر نمیشود نوشتههای ثابت داشت
|
||||
ownership: نوشتههای دیگران را نمیتوان ثابت کرد
|
||||
reblog: تقویت نمیتواند سنجاق شود
|
||||
poll:
|
||||
total_people:
|
||||
one: "%{count} نفر"
|
||||
other: "%{count} نفر"
|
||||
total_votes:
|
||||
one: "%{count} رأی"
|
||||
other: "%{count} رأی"
|
||||
vote: رأی
|
||||
show_more: نمایش
|
||||
show_thread: نمایش رشته
|
||||
title: "%{name}: «%{quote}»"
|
||||
visibilities:
|
||||
direct: مستقیم
|
||||
|
@ -7,7 +7,6 @@ fi:
|
||||
hosted_on: Mastodon palvelimella %{domain}
|
||||
title: Tietoja
|
||||
accounts:
|
||||
follow: Seuraa
|
||||
followers:
|
||||
one: seuraaja
|
||||
other: seuraajaa
|
||||
@ -1738,23 +1737,12 @@ fi:
|
||||
edited_at_html: Muokattu %{date}
|
||||
errors:
|
||||
in_reply_not_found: Julkaisua, johon yrität vastata, ei näytä olevan olemassa.
|
||||
open_in_web: Avaa selaimessa
|
||||
over_character_limit: merkkimäärän rajoitus %{max} ylitetty
|
||||
pin_errors:
|
||||
direct: Vain mainituille käyttäjille näkyviä julkaisuja ei voi kiinnittää
|
||||
limit: Olet jo kiinnittänyt enimmäismäärän julkaisuja
|
||||
ownership: Muiden julkaisuja ei voi kiinnittää
|
||||
reblog: Tehostusta ei voi kiinnittää
|
||||
poll:
|
||||
total_people:
|
||||
one: "%{count} käyttäjä"
|
||||
other: "%{count} käyttäjää"
|
||||
total_votes:
|
||||
one: "%{count} ääni"
|
||||
other: "%{count} ääntä"
|
||||
vote: Äänestä
|
||||
show_more: Näytä lisää
|
||||
show_thread: Näytä ketju
|
||||
title: "%{name}: ”%{quote}”"
|
||||
visibilities:
|
||||
direct: Suoraan
|
||||
|
@ -7,7 +7,6 @@ fo:
|
||||
hosted_on: Mastodon hýst á %{domain}
|
||||
title: Um
|
||||
accounts:
|
||||
follow: Fylg
|
||||
followers:
|
||||
one: Fylgjari
|
||||
other: Fylgjarar
|
||||
@ -1740,23 +1739,12 @@ fo:
|
||||
edited_at_html: Rættað %{date}
|
||||
errors:
|
||||
in_reply_not_found: Posturin, sum tú roynir at svara, sýnist ikki at finnast.
|
||||
open_in_web: Lat upp á vevinum
|
||||
over_character_limit: mesta tal av teknum, %{max}, rokkið
|
||||
pin_errors:
|
||||
direct: Postar, sum einans eru sjónligir hjá nevndum brúkarum, kunnu ikki festast
|
||||
limit: Tú hevur longu fest loyvda talið av postum
|
||||
ownership: Postar hjá øðrum kunnu ikki festast
|
||||
reblog: Ein stimbran kann ikki festast
|
||||
poll:
|
||||
total_people:
|
||||
one: "%{count} fólk"
|
||||
other: "%{count} fólk"
|
||||
total_votes:
|
||||
one: "%{count} atkvøða"
|
||||
other: "%{count} atkvøður"
|
||||
vote: Atkvøð
|
||||
show_more: Vís meira
|
||||
show_thread: Vís tráð
|
||||
title: '%{name}: "%{quote}"'
|
||||
visibilities:
|
||||
direct: Beinleiðis
|
||||
|
@ -7,7 +7,6 @@ fr-CA:
|
||||
hosted_on: Serveur Mastodon hébergé sur %{domain}
|
||||
title: À propos
|
||||
accounts:
|
||||
follow: Suivre
|
||||
followers:
|
||||
one: Abonné·e
|
||||
other: Abonné·e·s
|
||||
@ -1711,23 +1710,12 @@ fr-CA:
|
||||
edited_at_html: Édité le %{date}
|
||||
errors:
|
||||
in_reply_not_found: Le message auquel vous essayez de répondre ne semble pas exister.
|
||||
open_in_web: Ouvrir sur le web
|
||||
over_character_limit: limite de %{max} caractères dépassée
|
||||
pin_errors:
|
||||
direct: Les messages qui ne sont visibles que pour les utilisateur·rice·s mentionné·e·s ne peuvent pas être épinglés
|
||||
limit: Vous avez déjà épinglé le nombre maximum de messages
|
||||
ownership: Vous ne pouvez pas épingler un message ne vous appartenant pas
|
||||
reblog: Un partage ne peut pas être épinglé
|
||||
poll:
|
||||
total_people:
|
||||
one: "%{count} personne"
|
||||
other: "%{count} personnes"
|
||||
total_votes:
|
||||
one: "%{count} vote"
|
||||
other: "%{count} votes"
|
||||
vote: Voter
|
||||
show_more: Déplier
|
||||
show_thread: Afficher le fil de discussion
|
||||
title: "%{name} : « %{quote} »"
|
||||
visibilities:
|
||||
direct: Direct
|
||||
|
@ -7,7 +7,6 @@ fr:
|
||||
hosted_on: Serveur Mastodon hébergé sur %{domain}
|
||||
title: À propos
|
||||
accounts:
|
||||
follow: Suivre
|
||||
followers:
|
||||
one: Abonné·e
|
||||
other: Abonné·e·s
|
||||
@ -1711,23 +1710,12 @@ fr:
|
||||
edited_at_html: Modifié le %{date}
|
||||
errors:
|
||||
in_reply_not_found: Le message auquel vous essayez de répondre ne semble pas exister.
|
||||
open_in_web: Ouvrir sur le web
|
||||
over_character_limit: limite de %{max} caractères dépassée
|
||||
pin_errors:
|
||||
direct: Les messages qui ne sont visibles que pour les utilisateur·rice·s mentionné·e·s ne peuvent pas être épinglés
|
||||
limit: Vous avez déjà épinglé le nombre maximum de messages
|
||||
ownership: Vous ne pouvez pas épingler un message ne vous appartenant pas
|
||||
reblog: Un partage ne peut pas être épinglé
|
||||
poll:
|
||||
total_people:
|
||||
one: "%{count} personne"
|
||||
other: "%{count} personnes"
|
||||
total_votes:
|
||||
one: "%{count} vote"
|
||||
other: "%{count} votes"
|
||||
vote: Voter
|
||||
show_more: Déplier
|
||||
show_thread: Afficher le fil de discussion
|
||||
title: "%{name} : « %{quote} »"
|
||||
visibilities:
|
||||
direct: Direct
|
||||
|
@ -7,7 +7,6 @@ fy:
|
||||
hosted_on: Mastodon op %{domain}
|
||||
title: Oer
|
||||
accounts:
|
||||
follow: Folgje
|
||||
followers:
|
||||
one: Folger
|
||||
other: Folgers
|
||||
@ -1730,23 +1729,12 @@ fy:
|
||||
edited_at_html: Bewurke op %{date}
|
||||
errors:
|
||||
in_reply_not_found: It berjocht wêrop jo probearje te reagearjen liket net te bestean.
|
||||
open_in_web: Yn de webapp iepenje
|
||||
over_character_limit: Oer de limyt fan %{max} tekens
|
||||
pin_errors:
|
||||
direct: Berjochten dy’t allinnich sichtber binne foar fermelde brûkers kinne net fêstset wurde
|
||||
limit: Jo hawwe it maksimaal tal berjochten al fêstmakke
|
||||
ownership: In berjocht fan in oar kin net fêstmakke wurde
|
||||
reblog: In boost kin net fêstset wurde
|
||||
poll:
|
||||
total_people:
|
||||
one: "%{count} persoan"
|
||||
other: "%{count} persoanen"
|
||||
total_votes:
|
||||
one: "%{count} stim"
|
||||
other: "%{count} stimmen"
|
||||
vote: Stimme
|
||||
show_more: Mear toane
|
||||
show_thread: Petear toane
|
||||
title: '%{name}: "%{quote}"'
|
||||
visibilities:
|
||||
direct: Direkt
|
||||
|
@ -7,7 +7,6 @@ ga:
|
||||
hosted_on: Mastodon arna óstáil ar %{domain}
|
||||
title: Maidir le
|
||||
accounts:
|
||||
follow: Lean
|
||||
followers:
|
||||
few: Leantóirí
|
||||
many: Leantóirí
|
||||
@ -1823,29 +1822,12 @@ ga:
|
||||
edited_at_html: "%{date} curtha in eagar"
|
||||
errors:
|
||||
in_reply_not_found: Is cosúil nach ann don phostáil a bhfuil tú ag iarraidh freagra a thabhairt air.
|
||||
open_in_web: Oscail i ngréasán
|
||||
over_character_limit: teorainn carachtar %{max} sáraithe
|
||||
pin_errors:
|
||||
direct: Ní féidir postálacha nach bhfuil le feiceáil ach ag úsáideoirí luaite a phinnáil
|
||||
limit: Tá uaslíon na bpostálacha pinn agat cheana féin
|
||||
ownership: Ní féidir postáil duine éigin eile a phionnáil
|
||||
reblog: Ní féidir treisiú a phinnáil
|
||||
poll:
|
||||
total_people:
|
||||
few: "%{count} daoine"
|
||||
many: "%{count} daoine"
|
||||
one: "%{count} duine"
|
||||
other: "%{count} daoine"
|
||||
two: "%{count} daoine"
|
||||
total_votes:
|
||||
few: "%{count} vótaí"
|
||||
many: "%{count} vótaí"
|
||||
one: "%{count} vóta"
|
||||
other: "%{count} vótaí"
|
||||
two: "%{count} vótaí"
|
||||
vote: Vótáil
|
||||
show_more: Taispeáin níos mó
|
||||
show_thread: Taispeáin snáithe
|
||||
title: '%{name}: "%{quote}"'
|
||||
visibilities:
|
||||
direct: Díreach
|
||||
|
@ -7,7 +7,6 @@ gd:
|
||||
hosted_on: Mastodon ’ga òstadh air %{domain}
|
||||
title: Mu dhèidhinn
|
||||
accounts:
|
||||
follow: Lean
|
||||
followers:
|
||||
few: Luchd-leantainn
|
||||
one: Neach-leantainn
|
||||
@ -1793,27 +1792,12 @@ gd:
|
||||
edited_at_html: Air a dheasachadh %{date}
|
||||
errors:
|
||||
in_reply_not_found: Tha coltas nach eil am post dhan a tha thu airson freagairt ann.
|
||||
open_in_web: Fosgail air an lìon
|
||||
over_character_limit: chaidh thu thar crìoch charactaran de %{max}
|
||||
pin_errors:
|
||||
direct: Chan urrainn dhut post a phrìneachadh nach fhaic ach na cleachdaichean le iomradh orra
|
||||
limit: Tha an àireamh as motha de phostaichean prìnichte agad a tha ceadaichte
|
||||
ownership: Chan urrainn dhut post càich a phrìneachadh
|
||||
reblog: Chan urrainn dhut brosnachadh a phrìneachadh
|
||||
poll:
|
||||
total_people:
|
||||
few: "%{count} daoine"
|
||||
one: "%{count} neach"
|
||||
other: "%{count} duine"
|
||||
two: "%{count} neach"
|
||||
total_votes:
|
||||
few: "%{count} bhòtaichean"
|
||||
one: "%{count} bhòt"
|
||||
other: "%{count} bhòt"
|
||||
two: "%{count} bhòt"
|
||||
vote: Bhòt
|
||||
show_more: Seall barrachd dheth
|
||||
show_thread: Seall an snàithlean
|
||||
title: "%{name}: “%{quote}”"
|
||||
visibilities:
|
||||
direct: Dìreach
|
||||
|
@ -7,7 +7,6 @@ gl:
|
||||
hosted_on: Mastodon aloxado en %{domain}
|
||||
title: Sobre
|
||||
accounts:
|
||||
follow: Seguir
|
||||
followers:
|
||||
one: Seguidora
|
||||
other: Seguidoras
|
||||
@ -1740,23 +1739,12 @@ gl:
|
||||
edited_at_html: Editado %{date}
|
||||
errors:
|
||||
in_reply_not_found: A publicación á que tentas responder semella que non existe.
|
||||
open_in_web: Abrir na web
|
||||
over_character_limit: Excedeu o límite de caracteres %{max}
|
||||
pin_errors:
|
||||
direct: As publicacións que só son visibles para as usuarias mencionadas non se poden fixar
|
||||
limit: Xa fixaches o número máximo permitido de publicacións
|
||||
ownership: Non podes fixar a publicación doutra usuaria
|
||||
reblog: Non se poden fixar as mensaxes promovidas
|
||||
poll:
|
||||
total_people:
|
||||
one: "%{count} persoa"
|
||||
other: "%{count} persoas"
|
||||
total_votes:
|
||||
one: "%{count} voto"
|
||||
other: "%{count} votos"
|
||||
vote: Votar
|
||||
show_more: Mostrar máis
|
||||
show_thread: Amosar fío
|
||||
title: '%{name}: "%{quote}"'
|
||||
visibilities:
|
||||
direct: Directa
|
||||
|
@ -7,7 +7,6 @@ he:
|
||||
hosted_on: מסטודון שיושב בכתובת %{domain}
|
||||
title: אודות
|
||||
accounts:
|
||||
follow: לעקוב
|
||||
followers:
|
||||
many: עוקבים
|
||||
one: עוקב
|
||||
@ -1800,27 +1799,12 @@ he:
|
||||
edited_at_html: נערך ב-%{date}
|
||||
errors:
|
||||
in_reply_not_found: נראה שההודעה שאת/ה מנסה להגיב לה לא קיימת.
|
||||
open_in_web: פתח ברשת
|
||||
over_character_limit: חריגה מגבול התווים של %{max}
|
||||
pin_errors:
|
||||
direct: לא ניתן לקבע הודעות שנראותן מוגבלת למכותבים בלבד
|
||||
limit: הגעת למספר המירבי של ההודעות המוצמדות
|
||||
ownership: הודעות של אחרים לא יכולות להיות מוצמדות
|
||||
reblog: אין אפשרות להצמיד הדהודים
|
||||
poll:
|
||||
total_people:
|
||||
many: "%{count} אנשים"
|
||||
one: איש/ה %{count}
|
||||
other: "%{count} אנשים"
|
||||
two: "%{count} אנשים"
|
||||
total_votes:
|
||||
many: "%{count} קולות"
|
||||
one: קול %{count}
|
||||
other: "%{count} קולות"
|
||||
two: "%{count} קולות"
|
||||
vote: הצבעה
|
||||
show_more: עוד
|
||||
show_thread: הצג שרשור
|
||||
title: '%{name}: "%{quote}"'
|
||||
visibilities:
|
||||
direct: ישיר
|
||||
|
@ -5,7 +5,6 @@ hi:
|
||||
contact_unavailable: लागू नहीं है
|
||||
title: के बारे में
|
||||
accounts:
|
||||
follow: अनुसरे
|
||||
following: फ़ॉलो कर रहे हैं
|
||||
instance_actor_flash: यह खाता आभासी है जो सर्वर को दिखाने के लिये है और ये किसी व्यक्तिका प्रतिनिधित्व नहि करता। यह सिर्फ देखरेख के हेतु से कार्यरत है और इसको निलंबित करने कि आवश्यकता नहि है।
|
||||
last_active: आखिरि बार इस वक्त सक्रिय थे
|
||||
|
@ -5,7 +5,6 @@ hr:
|
||||
contact_missing: Nije postavljeno
|
||||
title: O aplikaciji
|
||||
accounts:
|
||||
follow: Prati
|
||||
following: Praćenih
|
||||
last_active: posljednja aktivnost
|
||||
nothing_here: Ovdje nema ničeg!
|
||||
@ -215,20 +214,7 @@ hr:
|
||||
statuses_cleanup: Automatsko brisanje postova
|
||||
two_factor_authentication: Dvofaktorska autentifikacija
|
||||
statuses:
|
||||
open_in_web: Otvori na webu
|
||||
over_character_limit: prijeđeno je ograničenje od %{max} znakova
|
||||
poll:
|
||||
total_people:
|
||||
few: "%{count} osobe"
|
||||
one: "%{count} osoba"
|
||||
other: "%{count} ljudi"
|
||||
total_votes:
|
||||
few: "%{count} glasa"
|
||||
one: "%{count} glas"
|
||||
other: "%{count} glasova"
|
||||
vote: Glasaj
|
||||
show_more: Prikaži više
|
||||
show_thread: Prikaži nit
|
||||
visibilities:
|
||||
private: Samo pratitelji
|
||||
public: Javno
|
||||
|
@ -7,7 +7,6 @@ hu:
|
||||
hosted_on: "%{domain} Mastodon-kiszolgáló"
|
||||
title: Névjegy
|
||||
accounts:
|
||||
follow: Követés
|
||||
followers:
|
||||
one: Követő
|
||||
other: Követő
|
||||
@ -1740,23 +1739,12 @@ hu:
|
||||
edited_at_html: 'Szerkesztve: %{date}'
|
||||
errors:
|
||||
in_reply_not_found: Már nem létezik az a bejegyzés, melyre válaszolni szeretnél.
|
||||
open_in_web: Megnyitás a weben
|
||||
over_character_limit: túllépted a maximális %{max} karakteres keretet
|
||||
pin_errors:
|
||||
direct: A csak a megemlített felhasználók számára látható bejegyzések nem tűzhetők ki
|
||||
limit: Elérted a kitűzhető bejegyzések maximális számát
|
||||
ownership: Nem tűzheted ki valaki más bejegyzését
|
||||
reblog: Megtolt bejegyzést nem tudsz kitűzni
|
||||
poll:
|
||||
total_people:
|
||||
one: "%{count} személy"
|
||||
other: "%{count} személy"
|
||||
total_votes:
|
||||
one: "%{count} szavazat"
|
||||
other: "%{count} szavazat"
|
||||
vote: Szavazás
|
||||
show_more: Több megjelenítése
|
||||
show_thread: Szál mutatása
|
||||
title: "%{name}: „%{quote}”"
|
||||
visibilities:
|
||||
direct: Közvetlen
|
||||
|
@ -7,7 +7,6 @@ hy:
|
||||
hosted_on: Մաստոդոնը տեղակայուած է %{domain}ում
|
||||
title: Մասին
|
||||
accounts:
|
||||
follow: Հետևել
|
||||
followers:
|
||||
one: Հետեւորդ
|
||||
other: Հետևորդներ
|
||||
@ -782,18 +781,7 @@ hy:
|
||||
other: "%{count} վիդեո"
|
||||
content_warning: Նախազգուշացում։ %{warning}
|
||||
edited_at_html: Խմբագրուած՝ %{date}
|
||||
open_in_web: Բացել վէբում
|
||||
over_character_limit: "%{max} նիշի սահմանը գերազանցուած է"
|
||||
poll:
|
||||
total_people:
|
||||
one: "%{count} մարդ"
|
||||
other: "%{count} մարդիկ"
|
||||
total_votes:
|
||||
one: "%{count} ձայն"
|
||||
other: "%{count} ձայներ"
|
||||
vote: Քուէարկել
|
||||
show_more: Աւելին
|
||||
show_thread: Բացել շղթան
|
||||
title: '%{name}: "%{quote}"'
|
||||
visibilities:
|
||||
direct: Հասցէագրուած
|
||||
|
@ -7,7 +7,6 @@ ia:
|
||||
hosted_on: Mastodon albergate sur %{domain}
|
||||
title: A proposito
|
||||
accounts:
|
||||
follow: Sequer
|
||||
followers:
|
||||
one: Sequitor
|
||||
other: Sequitores
|
||||
@ -1723,23 +1722,12 @@ ia:
|
||||
edited_at_html: Modificate le %{date}
|
||||
errors:
|
||||
in_reply_not_found: Le message a que tu tenta responder non pare exister.
|
||||
open_in_web: Aperir sur le web
|
||||
over_character_limit: limite de characteres de %{max} excedite
|
||||
pin_errors:
|
||||
direct: Messages que es solo visibile a usatores mentionate non pote esser appunctate
|
||||
limit: Tu ha jam appunctate le maxime numero de messages
|
||||
ownership: Le message de alcuno altere non pote esser appunctate
|
||||
reblog: Un impulso non pote esser affixate
|
||||
poll:
|
||||
total_people:
|
||||
one: "%{count} persona"
|
||||
other: "%{count} personas"
|
||||
total_votes:
|
||||
one: "%{count} voto"
|
||||
other: "%{count} votos"
|
||||
vote: Votar
|
||||
show_more: Monstrar plus
|
||||
show_thread: Monstrar discussion
|
||||
title: "%{name}: “%{quote}”"
|
||||
visibilities:
|
||||
direct: Directe
|
||||
|
@ -7,7 +7,6 @@ id:
|
||||
hosted_on: Mastodon dihosting di %{domain}
|
||||
title: Tentang
|
||||
accounts:
|
||||
follow: Ikuti
|
||||
followers:
|
||||
other: Pengikut
|
||||
following: Mengikuti
|
||||
@ -1378,21 +1377,12 @@ id:
|
||||
edited_at_html: Diedit %{date}
|
||||
errors:
|
||||
in_reply_not_found: Status yang ingin Anda balas sudah tidak ada.
|
||||
open_in_web: Buka di web
|
||||
over_character_limit: melebihi %{max} karakter
|
||||
pin_errors:
|
||||
direct: Kiriman yang hanya terlihat oleh pengguna yang disebutkan tidak dapat disematkan
|
||||
limit: Anda sudah mencapai jumlah maksimum kiriman yang dapat disematkan
|
||||
ownership: Kiriman orang lain tidak bisa disematkan
|
||||
reblog: Boost tidak bisa disematkan
|
||||
poll:
|
||||
total_people:
|
||||
other: "%{count} orang"
|
||||
total_votes:
|
||||
other: "%{count} memilih"
|
||||
vote: Pilih
|
||||
show_more: Tampilkan selengkapnya
|
||||
show_thread: Tampilkan utas
|
||||
title: '%{name}: "%{quote}"'
|
||||
visibilities:
|
||||
direct: Langsung
|
||||
|
@ -7,7 +7,6 @@ ie:
|
||||
hosted_on: Mastodon logiat che %{domain}
|
||||
title: Pri
|
||||
accounts:
|
||||
follow: Sequer
|
||||
followers:
|
||||
one: Sequitor
|
||||
other: Sequitores
|
||||
@ -1637,23 +1636,12 @@ ie:
|
||||
edited_at_html: Modificat ye %{date}
|
||||
errors:
|
||||
in_reply_not_found: Li posta a quel tu prova responder ne sembla exister.
|
||||
open_in_web: Aperter in web
|
||||
over_character_limit: límite de carácteres de %{max} transpassat
|
||||
pin_errors:
|
||||
direct: On ne posse pinglar postas queles es visibil solmen a mentionat usatores
|
||||
limit: Tu ja ha pinglat li maxim númere de postas
|
||||
ownership: On ne posse pinglar li posta de un altri person
|
||||
reblog: On ne posse pinglar un boost
|
||||
poll:
|
||||
total_people:
|
||||
one: "%{count} person"
|
||||
other: "%{count} persones"
|
||||
total_votes:
|
||||
one: "%{count} vote"
|
||||
other: "%{count} votes"
|
||||
vote: Votar
|
||||
show_more: Monstrar plu
|
||||
show_thread: Monstrar fil
|
||||
title: "%{name}: «%{quote}»"
|
||||
visibilities:
|
||||
direct: Direct
|
||||
|
@ -7,7 +7,6 @@ io:
|
||||
hosted_on: Mastodon hostigesas che %{domain}
|
||||
title: Pri co
|
||||
accounts:
|
||||
follow: Sequar
|
||||
followers:
|
||||
one: Sequanto
|
||||
other: Sequanti
|
||||
@ -1590,23 +1589,12 @@ io:
|
||||
edited_at_html: Modifikesis ye %{date}
|
||||
errors:
|
||||
in_reply_not_found: Posto quon vu probas respondar semblas ne existas.
|
||||
open_in_web: Apertar retnavigile
|
||||
over_character_limit: limito de %{max} signi ecesita
|
||||
pin_errors:
|
||||
direct: Posti quo povas videsar nur mencionita uzanti ne povas pinglagesar
|
||||
limit: Vu ja pinglagis maxima posti
|
||||
ownership: Posto di altra persono ne povas pinglagesar
|
||||
reblog: Repeto ne povas pinglizesar
|
||||
poll:
|
||||
total_people:
|
||||
one: "%{count} persono"
|
||||
other: "%{count} personi"
|
||||
total_votes:
|
||||
one: "%{count} voto"
|
||||
other: "%{count} voti"
|
||||
vote: Votez
|
||||
show_more: Montrar plue
|
||||
show_thread: Montrez postaro
|
||||
title: '%{name}: "%{quote}"'
|
||||
visibilities:
|
||||
direct: Direta
|
||||
|
@ -7,7 +7,6 @@ is:
|
||||
hosted_on: Mastodon hýst á %{domain}
|
||||
title: Um hugbúnaðinn
|
||||
accounts:
|
||||
follow: Fylgjast með
|
||||
followers:
|
||||
one: fylgjandi
|
||||
other: fylgjendur
|
||||
@ -1744,23 +1743,12 @@ is:
|
||||
edited_at_html: Breytt %{date}
|
||||
errors:
|
||||
in_reply_not_found: Færslan sem þú ert að reyna að svara að er líklega ekki til.
|
||||
open_in_web: Opna í vafra
|
||||
over_character_limit: hámarksfjölda stafa (%{max}) náð
|
||||
pin_errors:
|
||||
direct: Ekki er hægt að festa færslur sem einungis eru sýnilegar þeim notendum sem minnst er á
|
||||
limit: Þú hefur þegar fest leyfilegan hámarksfjölda færslna
|
||||
ownership: Færslur frá einhverjum öðrum er ekki hægt að festa
|
||||
reblog: Ekki er hægt að festa endurbirtingu
|
||||
poll:
|
||||
total_people:
|
||||
one: "%{count} aðili"
|
||||
other: "%{count} aðilar"
|
||||
total_votes:
|
||||
one: "%{count} atkvæði"
|
||||
other: "%{count} atkvæði"
|
||||
vote: Greiða atkvæði
|
||||
show_more: Sýna meira
|
||||
show_thread: Birta þráð
|
||||
title: "%{name}: „%{quote}‟"
|
||||
visibilities:
|
||||
direct: Beint
|
||||
|
@ -7,7 +7,6 @@ it:
|
||||
hosted_on: Mastodon ospitato su %{domain}
|
||||
title: Info
|
||||
accounts:
|
||||
follow: Segui
|
||||
followers:
|
||||
one: Seguace
|
||||
other: Seguaci
|
||||
@ -1742,23 +1741,12 @@ it:
|
||||
edited_at_html: Modificato il %{date}
|
||||
errors:
|
||||
in_reply_not_found: Il post a cui stai tentando di rispondere non sembra esistere.
|
||||
open_in_web: Apri sul Web
|
||||
over_character_limit: Limite caratteri superato di %{max}
|
||||
pin_errors:
|
||||
direct: I messaggi visibili solo agli utenti citati non possono essere fissati in cima
|
||||
limit: Hai già fissato in cima il massimo numero di post
|
||||
ownership: Non puoi fissare in cima un post di qualcun altro
|
||||
reblog: Un toot condiviso non può essere fissato in cima
|
||||
poll:
|
||||
total_people:
|
||||
one: "%{count} persona"
|
||||
other: "%{count} persone"
|
||||
total_votes:
|
||||
one: "%{count} voto"
|
||||
other: "%{count} voti"
|
||||
vote: Vota
|
||||
show_more: Mostra di più
|
||||
show_thread: Mostra thread
|
||||
title: '%{name}: "%{quote}"'
|
||||
visibilities:
|
||||
direct: Diretto
|
||||
|
@ -7,7 +7,6 @@ ja:
|
||||
hosted_on: Mastodon hosted on %{domain}
|
||||
title: このサーバーについて
|
||||
accounts:
|
||||
follow: フォロー
|
||||
followers:
|
||||
other: フォロワー
|
||||
following: フォロー中
|
||||
@ -1700,21 +1699,12 @@ ja:
|
||||
edited_at_html: "%{date} 編集済み"
|
||||
errors:
|
||||
in_reply_not_found: あなたが返信しようとしている投稿は存在しないようです。
|
||||
open_in_web: Webで開く
|
||||
over_character_limit: 上限は%{max}文字です
|
||||
pin_errors:
|
||||
direct: 返信したユーザーのみに表示される投稿はピン留めできません
|
||||
limit: 固定できる投稿数の上限に達しました
|
||||
ownership: 他人の投稿を固定することはできません
|
||||
reblog: ブーストを固定することはできません
|
||||
poll:
|
||||
total_people:
|
||||
other: "%{count}人"
|
||||
total_votes:
|
||||
other: "%{count}票"
|
||||
vote: 投票
|
||||
show_more: もっと見る
|
||||
show_thread: スレッドを表示
|
||||
title: '%{name}: "%{quote}"'
|
||||
visibilities:
|
||||
direct: ダイレクト
|
||||
|
@ -6,7 +6,6 @@ ka:
|
||||
contact_unavailable: მიუწ.
|
||||
hosted_on: მასტოდონს მასპინძლობს %{domain}
|
||||
accounts:
|
||||
follow: გაყევი
|
||||
following: მიჰყვება
|
||||
nothing_here: აქ არაფერია!
|
||||
pin_errors:
|
||||
@ -430,13 +429,11 @@ ka:
|
||||
disallowed_hashtags:
|
||||
one: 'მოიცავდა აკრძალულ ჰეშტეგს: %{tags}'
|
||||
other: 'მოიცავს აკრძალულ ჰეშტეგს: %{tags}'
|
||||
open_in_web: ვებში გახნსა
|
||||
over_character_limit: ნიშნების ლიმიტი გადასცდა %{max}-ს
|
||||
pin_errors:
|
||||
limit: ტუტების მაქსიმალური რაოდენობა უკვე აპინეთ
|
||||
ownership: სხვისი ტუტი ვერ აიპინება
|
||||
reblog: ბუსტი ვერ აიპინება
|
||||
show_more: მეტის ჩვენება
|
||||
visibilities:
|
||||
private: მხოლოდ-მიმდევრები
|
||||
private_long: აჩვენე მხოლოდ მიმდევრებს
|
||||
|
@ -7,7 +7,6 @@ kab:
|
||||
hosted_on: Maṣṭudun yersen deg %{domain}
|
||||
title: Ɣef
|
||||
accounts:
|
||||
follow: Ḍfeṛ
|
||||
followers:
|
||||
one: Umeḍfaṛ
|
||||
other: Imeḍfaṛen
|
||||
@ -798,17 +797,6 @@ kab:
|
||||
one: "%{count} n tbidyutt"
|
||||
other: "%{count} n tbidyutin"
|
||||
edited_at_html: Tettwaẓreg ass n %{date}
|
||||
open_in_web: Ldi deg Web
|
||||
poll:
|
||||
total_people:
|
||||
one: "%{count} n wemdan"
|
||||
other: "%{count} n yemdanen"
|
||||
total_votes:
|
||||
one: "%{count} n wedɣar"
|
||||
other: "%{count} n yedɣaren"
|
||||
vote: Dɣeṛ
|
||||
show_more: Ssken-d ugar
|
||||
show_thread: Ssken-d lxiḍ
|
||||
title: '%{name} : "%{quote}"'
|
||||
visibilities:
|
||||
direct: Usrid
|
||||
|
@ -6,7 +6,6 @@ kk:
|
||||
contact_unavailable: Белгісіз
|
||||
hosted_on: Mastodon орнатылған %{domain} доменінде
|
||||
accounts:
|
||||
follow: Жазылу
|
||||
followers:
|
||||
one: Оқырман
|
||||
other: Оқырман
|
||||
@ -647,22 +646,11 @@ kk:
|
||||
disallowed_hashtags:
|
||||
one: 'рұқсат етілмеген хэштег: %{tags}'
|
||||
other: 'рұқсат етілмеген хэштегтер: %{tags}'
|
||||
open_in_web: Вебте ашу
|
||||
over_character_limit: "%{max} максимум таңбадан асып кетті"
|
||||
pin_errors:
|
||||
limit: Жабыстырылатын жазба саны максимумынан асты
|
||||
ownership: Біреудің жазбасы жабыстырылмайды
|
||||
reblog: Бөлісілген жазба жабыстырылмайды
|
||||
poll:
|
||||
total_people:
|
||||
one: "%{count} адам"
|
||||
other: "%{count} адам"
|
||||
total_votes:
|
||||
one: "%{count} дауыс"
|
||||
other: "%{count} дауыс"
|
||||
vote: Дауыс беру
|
||||
show_more: Тағы әкел
|
||||
show_thread: Тақырыпты көрсет
|
||||
visibilities:
|
||||
private: Тек оқырмандарға
|
||||
private_long: Тек оқырмандарға ғана көрінеді
|
||||
|
@ -7,7 +7,6 @@ ko:
|
||||
hosted_on: "%{domain}에서 호스팅 되는 마스토돈"
|
||||
title: 정보
|
||||
accounts:
|
||||
follow: 팔로우
|
||||
followers:
|
||||
other: 팔로워
|
||||
following: 팔로잉
|
||||
@ -1705,21 +1704,12 @@ ko:
|
||||
edited_at_html: "%{date}에 편집됨"
|
||||
errors:
|
||||
in_reply_not_found: 답장하려는 게시물이 존재하지 않습니다.
|
||||
open_in_web: Web으로 열기
|
||||
over_character_limit: 최대 %{max}자까지 입력할 수 있습니다
|
||||
pin_errors:
|
||||
direct: 멘션된 사용자들에게만 보이는 게시물은 고정될 수 없습니다
|
||||
limit: 이미 너무 많은 게시물을 고정했습니다
|
||||
ownership: 다른 사람의 게시물은 고정될 수 없습니다
|
||||
reblog: 부스트는 고정될 수 없습니다
|
||||
poll:
|
||||
total_people:
|
||||
other: "%{count}명"
|
||||
total_votes:
|
||||
other: "%{count} 명 투표함"
|
||||
vote: 투표
|
||||
show_more: 더 보기
|
||||
show_thread: 글타래 보기
|
||||
title: '%{name}: "%{quote}"'
|
||||
visibilities:
|
||||
direct: 다이렉트
|
||||
|
@ -7,7 +7,6 @@ ku:
|
||||
hosted_on: Mastodon li ser %{domain} tê pêşkêşkirin
|
||||
title: Derbar
|
||||
accounts:
|
||||
follow: Bişopîne
|
||||
followers:
|
||||
one: Şopîner
|
||||
other: Şopîner
|
||||
@ -1404,23 +1403,12 @@ ku:
|
||||
edited_at_html: Di %{date} de hate serrastkirin
|
||||
errors:
|
||||
in_reply_not_found: Ew şandiya ku tu dikî nakî bersivê bide xuya nake an jî hatiye jêbirin.
|
||||
open_in_web: Di tevnê de veke
|
||||
over_character_limit: sînorê karakterê %{max} derbas kir
|
||||
pin_errors:
|
||||
direct: Şandiyên ku tenê ji bikarhênerên qalkirî re têne xuyangkirin, nayê derzîkirin
|
||||
limit: Jixwe te mezintirîn hejmara şandîyên xwe derzî kir
|
||||
ownership: Şandiya kesekî din nay derzî kirin
|
||||
reblog: Ev şandî nayê derzî kirin
|
||||
poll:
|
||||
total_people:
|
||||
one: "%{count} kes"
|
||||
other: "%{count} kes"
|
||||
total_votes:
|
||||
one: "%{count} deng"
|
||||
other: "%{count} deng"
|
||||
vote: Deng bide
|
||||
show_more: Bêtir nîşan bide
|
||||
show_thread: Mijarê nîşan bide
|
||||
title: "%{name}%{quote}"
|
||||
visibilities:
|
||||
direct: Rasterast
|
||||
|
@ -7,7 +7,6 @@ la:
|
||||
hosted_on: Mastodon in %{domain} hospitātum
|
||||
title: De
|
||||
accounts:
|
||||
follow: Sequere
|
||||
followers:
|
||||
one: Sectātor
|
||||
other: Sectātōrēs
|
||||
|
@ -7,7 +7,6 @@ lad:
|
||||
hosted_on: Mastodon balabayado en %{domain}
|
||||
title: Sovre mozotros
|
||||
accounts:
|
||||
follow: Sige
|
||||
followers:
|
||||
one: Suivante
|
||||
other: Suivantes
|
||||
@ -1677,23 +1676,12 @@ lad:
|
||||
edited_at_html: Editado %{date}
|
||||
errors:
|
||||
in_reply_not_found: La publikasion a la ke aprovas arispondir no egziste.
|
||||
open_in_web: Avre en web
|
||||
over_character_limit: limito de karakteres de %{max} superado
|
||||
pin_errors:
|
||||
direct: Las publikasyones ke son vizivles solo para los utilizadores enmentados no pueden fiksarse
|
||||
limit: Ya tienes fiksado el numero maksimo de publikasyones
|
||||
ownership: La publikasyon de otra persona no puede fiksarse
|
||||
reblog: No se puede fixar una repartajasyon
|
||||
poll:
|
||||
total_people:
|
||||
one: "%{count} persona"
|
||||
other: "%{count} personas"
|
||||
total_votes:
|
||||
one: "%{count} voto"
|
||||
other: "%{count} votos"
|
||||
vote: Vota
|
||||
show_more: Amostra mas
|
||||
show_thread: Amostra diskusyon
|
||||
title: '%{name}: "%{quote}"'
|
||||
visibilities:
|
||||
direct: Direkto
|
||||
|
@ -7,7 +7,6 @@ lt:
|
||||
hosted_on: Mastodon talpinamas %{domain}
|
||||
title: Apie
|
||||
accounts:
|
||||
follow: Sekti
|
||||
followers:
|
||||
few: Sekėjai
|
||||
many: Sekėjo
|
||||
@ -1107,16 +1106,11 @@ lt:
|
||||
other: "%{count} vaizdų"
|
||||
boosted_from_html: Pakelta iš %{acct_link}
|
||||
content_warning: 'Turinio įspėjimas: %{warning}'
|
||||
open_in_web: Atidaryti naudojan Web
|
||||
over_character_limit: pasiektas %{max} simbolių limitas
|
||||
pin_errors:
|
||||
limit: Jūs jau prisegėte maksimalų toot'ų skaičų
|
||||
ownership: Kitų vartotojų toot'ai negali būti prisegti
|
||||
reblog: Pakeltos žinutės negali būti prisegtos
|
||||
poll:
|
||||
vote: Balsuoti
|
||||
show_more: Rodyti daugiau
|
||||
show_thread: Rodyti giją
|
||||
visibilities:
|
||||
private: Tik sekėjams
|
||||
private_long: rodyti tik sekėjams
|
||||
|
@ -7,7 +7,6 @@ lv:
|
||||
hosted_on: Mastodon mitināts %{domain}
|
||||
title: Par
|
||||
accounts:
|
||||
follow: Sekot
|
||||
followers:
|
||||
one: Sekotājs
|
||||
other: Sekotāji
|
||||
@ -1645,25 +1644,12 @@ lv:
|
||||
edited_at_html: Labots %{date}
|
||||
errors:
|
||||
in_reply_not_found: Šķiet, ka ziņa, uz kuru tu mēģini atbildēt, nepastāv.
|
||||
open_in_web: Atvērt webā
|
||||
over_character_limit: pārsniegts %{max} rakstzīmju ierobežojums
|
||||
pin_errors:
|
||||
direct: Ziņojumus, kas ir redzami tikai minētajiem lietotājiem, nevar piespraust
|
||||
limit: Tu jau esi piespraudis maksimālo ziņu skaitu
|
||||
ownership: Kāda cita ierakstu nevar piespraust
|
||||
reblog: Izceltu ierakstu nevar piespraust
|
||||
poll:
|
||||
total_people:
|
||||
one: "%{count} cilvēks"
|
||||
other: "%{count} cilvēki"
|
||||
zero: "%{count} cilvēku"
|
||||
total_votes:
|
||||
one: "%{count} balss"
|
||||
other: "%{count} balsis"
|
||||
zero: "%{count} balsu"
|
||||
vote: Balsu skaits
|
||||
show_more: Rādīt vairāk
|
||||
show_thread: Rādīt tematu
|
||||
title: "%{name}: “%{quote}”"
|
||||
visibilities:
|
||||
direct: Tiešs
|
||||
|
@ -4,7 +4,6 @@ ml:
|
||||
contact_missing: സജ്ജമാക്കിയിട്ടില്ല
|
||||
contact_unavailable: ലഭ്യമല്ല
|
||||
accounts:
|
||||
follow: പിന്തുടരുക
|
||||
following: പിന്തുടരുന്നു
|
||||
last_active: അവസാനം സജീവമായിരുന്നത്
|
||||
link_verified_on: സന്ധിയുടെ ഉടമസ്ഥാവസ്കാശം %{date} ൽ പരിശോധിക്കപ്പെട്ടു
|
||||
|
@ -7,7 +7,6 @@ ms:
|
||||
hosted_on: Mastodon dihoskan di %{domain}
|
||||
title: Perihal
|
||||
accounts:
|
||||
follow: Ikut
|
||||
followers:
|
||||
other: Pengikut
|
||||
following: Mengikuti
|
||||
@ -1560,21 +1559,12 @@ ms:
|
||||
edited_at_html: Disunting %{date}
|
||||
errors:
|
||||
in_reply_not_found: Pos yang anda cuba balas nampaknya tidak wujud.
|
||||
open_in_web: Buka dalam web
|
||||
over_character_limit: had aksara %{max} melebihi
|
||||
pin_errors:
|
||||
direct: Pos yang hanya boleh dilihat oleh pengguna yang disebut tidak boleh disematkan
|
||||
limit: Anda telah menyematkan bilangan maksimum pos
|
||||
ownership: Siaran orang lain tidak boleh disematkan
|
||||
reblog: Rangsangan tidak boleh disematkan
|
||||
poll:
|
||||
total_people:
|
||||
other: "%{count} orang"
|
||||
total_votes:
|
||||
other: "%{count} undi"
|
||||
vote: Undi
|
||||
show_more: Tunjuk lebih banyak
|
||||
show_thread: Tunjuk bebenang
|
||||
title: '%{name}: "%{quote}"'
|
||||
visibilities:
|
||||
direct: Terus
|
||||
|
@ -7,7 +7,6 @@ my:
|
||||
hosted_on: "%{domain} မှ လက်ခံဆောင်ရွက်ထားသော Mastodon"
|
||||
title: အကြောင်း
|
||||
accounts:
|
||||
follow: စောင့်ကြည့်မယ်
|
||||
followers:
|
||||
other: စောင့်ကြည့်သူ
|
||||
following: စောင့်ကြည့်နေသည်
|
||||
@ -1560,21 +1559,12 @@ my:
|
||||
edited_at_html: "%{date} ကို ပြင်ဆင်ပြီးပါပြီ"
|
||||
errors:
|
||||
in_reply_not_found: သင် စာပြန်နေသည့်ပို့စ်မှာ မရှိတော့ပါ။
|
||||
open_in_web: ဝဘ်တွင် ဖွင့်ပါ
|
||||
over_character_limit: စာလုံးကန့်သတ်ချက် %{max} ကို ကျော်လွန်သွားပါပြီ
|
||||
pin_errors:
|
||||
direct: အမည်ဖော်ပြထားသည့် ပို့စ်များကို ပင်တွဲ၍မရပါ
|
||||
limit: သင်သည် ပို့စ်အရေအတွက်အများဆုံးကို ပင်တွဲထားပြီးဖြစ်သည်
|
||||
ownership: အခြားသူ၏ပို့စ်ကို ပင်တွဲ၍မရပါ
|
||||
reblog: Boost လုပ်ထားသောပို့စ်ကို ပင်ထား၍မရပါ
|
||||
poll:
|
||||
total_people:
|
||||
other: "%{count} ယောက်"
|
||||
total_votes:
|
||||
other: မဲအရေအတွက် %{count} မဲ
|
||||
vote: မဲပေးမည်
|
||||
show_more: ပိုမိုပြရန်
|
||||
show_thread: Thread ကို ပြပါ
|
||||
title: '%{name}: "%{quote}"'
|
||||
visibilities:
|
||||
direct: တိုက်ရိုက်
|
||||
|
@ -7,7 +7,6 @@ nl:
|
||||
hosted_on: Mastodon op %{domain}
|
||||
title: Over
|
||||
accounts:
|
||||
follow: Volgen
|
||||
followers:
|
||||
one: Volger
|
||||
other: Volgers
|
||||
@ -1740,23 +1739,12 @@ nl:
|
||||
edited_at_html: Bewerkt op %{date}
|
||||
errors:
|
||||
in_reply_not_found: Het bericht waarop je probeert te reageren lijkt niet te bestaan.
|
||||
open_in_web: In de webapp openen
|
||||
over_character_limit: Limiet van %{max} tekens overschreden
|
||||
pin_errors:
|
||||
direct: Berichten die alleen zichtbaar zijn voor vermelde gebruikers, kunnen niet worden vastgezet
|
||||
limit: Je hebt het maximaal aantal bericht al vastgemaakt
|
||||
ownership: Een bericht van iemand anders kan niet worden vastgemaakt
|
||||
reblog: Een boost kan niet worden vastgezet
|
||||
poll:
|
||||
total_people:
|
||||
one: "%{count} persoon"
|
||||
other: "%{count} personen"
|
||||
total_votes:
|
||||
one: "%{count} stem"
|
||||
other: "%{count} stemmen"
|
||||
vote: Stemmen
|
||||
show_more: Meer tonen
|
||||
show_thread: Gesprek tonen
|
||||
title: '%{name}: "%{quote}"'
|
||||
visibilities:
|
||||
direct: Privébericht
|
||||
|
@ -7,7 +7,6 @@ nn:
|
||||
hosted_on: "%{domain} er vert for Mastodon"
|
||||
title: Om
|
||||
accounts:
|
||||
follow: Fylg
|
||||
followers:
|
||||
one: Fylgjar
|
||||
other: Fylgjarar
|
||||
@ -1740,23 +1739,12 @@ nn:
|
||||
edited_at_html: Redigert %{date}
|
||||
errors:
|
||||
in_reply_not_found: Det ser ut til at tutet du freistar å svara ikkje finst.
|
||||
open_in_web: Opn på nett
|
||||
over_character_limit: øvregrensa for teikn, %{max}, er nådd
|
||||
pin_errors:
|
||||
direct: Innlegg som bare er synlige for nevnte brukere kan ikke festes
|
||||
limit: Du har allereie festa så mange tut som det går an å festa
|
||||
ownership: Du kan ikkje festa andre sine tut
|
||||
reblog: Ei framheving kan ikkje festast
|
||||
poll:
|
||||
total_people:
|
||||
one: "%{count} person"
|
||||
other: "%{count} folk"
|
||||
total_votes:
|
||||
one: "%{count} røyst"
|
||||
other: "%{count} røyster"
|
||||
vote: Røyst
|
||||
show_more: Vis meir
|
||||
show_thread: Vis tråden
|
||||
title: "%{name}: «%{quote}»"
|
||||
visibilities:
|
||||
direct: Direkte
|
||||
|
@ -7,7 +7,6 @@
|
||||
hosted_on: Mastodon driftet på %{domain}
|
||||
title: Om
|
||||
accounts:
|
||||
follow: Følg
|
||||
followers:
|
||||
one: Følger
|
||||
other: Følgere
|
||||
@ -1619,23 +1618,12 @@
|
||||
edited_at_html: Redigert %{date}
|
||||
errors:
|
||||
in_reply_not_found: Posten du prøver å svare ser ikke ut til eksisterer.
|
||||
open_in_web: Åpne i nettleser
|
||||
over_character_limit: grensen på %{max} tegn overskredet
|
||||
pin_errors:
|
||||
direct: Innlegg som bare er synlige for nevnte brukere kan ikke festes
|
||||
limit: Du har allerede festet det maksimale antall innlegg
|
||||
ownership: Kun egne innlegg kan festes
|
||||
reblog: En fremheving kan ikke festes
|
||||
poll:
|
||||
total_people:
|
||||
one: "%{count} person"
|
||||
other: "%{count} personer"
|
||||
total_votes:
|
||||
one: "%{count} stemme"
|
||||
other: "%{count} stemmer"
|
||||
vote: Stem
|
||||
show_more: Vis mer
|
||||
show_thread: Vis tråden
|
||||
title: "%{name}: «%{quote}»"
|
||||
visibilities:
|
||||
direct: Direkte
|
||||
|
@ -7,7 +7,6 @@ oc:
|
||||
hosted_on: Mastodon albergat sus %{domain}
|
||||
title: A prepaus
|
||||
accounts:
|
||||
follow: Sègre
|
||||
followers:
|
||||
one: Seguidor
|
||||
other: Seguidors
|
||||
@ -846,22 +845,11 @@ oc:
|
||||
edited_at_html: Modificat %{date}
|
||||
errors:
|
||||
in_reply_not_found: La publicacion que respondètz sembla pas mai exisitir.
|
||||
open_in_web: Dobrir sul web
|
||||
over_character_limit: limit de %{max} caractèrs passat
|
||||
pin_errors:
|
||||
limit: Avètz ja lo maximum de tuts penjats
|
||||
ownership: Se pòt pas penjar lo tut de qualqu’un mai
|
||||
reblog: Se pòt pas penjar un tut partejat
|
||||
poll:
|
||||
total_people:
|
||||
one: "%{count} persona"
|
||||
other: "%{count} personas"
|
||||
total_votes:
|
||||
one: "%{count} vòte"
|
||||
other: "%{count} vòtes"
|
||||
vote: Votar
|
||||
show_more: Ne veire mai
|
||||
show_thread: Mostrar lo fil
|
||||
title: '%{name} : "%{quote}"'
|
||||
visibilities:
|
||||
direct: Dirècte
|
||||
|
@ -7,7 +7,6 @@ pa:
|
||||
hosted_on: "%{domain} ਉੱਤੇ ਹੋਸਟ ਕੀਤਾ ਮਸਟਾਡੋਨ"
|
||||
title: ਇਸ ਬਾਰੇ
|
||||
accounts:
|
||||
follow: ਫ਼ਾਲੋ
|
||||
following: ਫ਼ਾਲੋ ਕੀਤੇ ਜਾ ਰਹੇ
|
||||
posts_tab_heading: ਪੋਸਟਾਂ
|
||||
admin:
|
||||
|
@ -7,7 +7,6 @@ pl:
|
||||
hosted_on: Mastodon prowadzony na %{domain}
|
||||
title: O nas
|
||||
accounts:
|
||||
follow: Obserwuj
|
||||
followers:
|
||||
few: śledzących
|
||||
many: śledzących
|
||||
@ -1800,27 +1799,12 @@ pl:
|
||||
edited_at_html: Edytowane %{date}
|
||||
errors:
|
||||
in_reply_not_found: Post, na który próbujesz odpowiedzieć, nie istnieje.
|
||||
open_in_web: Otwórz w przeglądarce
|
||||
over_character_limit: limit %{max} znaków przekroczony
|
||||
pin_errors:
|
||||
direct: Nie możesz przypiąć wpisu, który jest widoczny tylko dla wspomnianych użytkowników
|
||||
limit: Przekroczyłeś maksymalną liczbę przypiętych wpisów
|
||||
ownership: Nie możesz przypiąć cudzego wpisu
|
||||
reblog: Nie możesz przypiąć podbicia wpisu
|
||||
poll:
|
||||
total_people:
|
||||
few: "%{count} osoby"
|
||||
many: "%{count} osób"
|
||||
one: "%{count} osoba"
|
||||
other: "%{count} osoby"
|
||||
total_votes:
|
||||
few: "%{count} głosy"
|
||||
many: "%{count} głosy"
|
||||
one: "%{count} głos"
|
||||
other: "%{count} głosy"
|
||||
vote: Głosuj
|
||||
show_more: Pokaż więcej
|
||||
show_thread: Pokaż wątek
|
||||
title: '%{name}: "%{quote}"'
|
||||
visibilities:
|
||||
direct: Bezpośredni
|
||||
|
@ -7,7 +7,6 @@ pt-BR:
|
||||
hosted_on: Mastodon hospedado em %{domain}
|
||||
title: Sobre
|
||||
accounts:
|
||||
follow: Seguir
|
||||
followers:
|
||||
one: Seguidor
|
||||
other: Seguidores
|
||||
@ -1740,23 +1739,12 @@ pt-BR:
|
||||
edited_at_html: Editado em %{date}
|
||||
errors:
|
||||
in_reply_not_found: A publicação que você quer responder parece não existir.
|
||||
open_in_web: Abrir no navegador
|
||||
over_character_limit: limite de caracteres de %{max} excedido
|
||||
pin_errors:
|
||||
direct: Publicações visíveis apenas para usuários mencionados não podem ser fixadas
|
||||
limit: Você alcançou o número limite de publicações fixadas
|
||||
ownership: As publicações dos outros não podem ser fixadas
|
||||
reblog: Um impulso não pode ser fixado
|
||||
poll:
|
||||
total_people:
|
||||
one: "%{count} pessoa"
|
||||
other: "%{count} pessoas"
|
||||
total_votes:
|
||||
one: "%{count} voto"
|
||||
other: "%{count} votos"
|
||||
vote: Votar
|
||||
show_more: Mostrar mais
|
||||
show_thread: Mostrar conversa
|
||||
title: '%{name}: "%{quote}"'
|
||||
visibilities:
|
||||
direct: Direto
|
||||
|
@ -7,7 +7,6 @@ pt-PT:
|
||||
hosted_on: Mastodon alojado em %{domain}
|
||||
title: Sobre
|
||||
accounts:
|
||||
follow: Seguir
|
||||
followers:
|
||||
one: Seguidor
|
||||
other: Seguidores
|
||||
@ -1683,23 +1682,12 @@ pt-PT:
|
||||
edited_at_html: Editado em %{date}
|
||||
errors:
|
||||
in_reply_not_found: A publicação a que está a tentar responder parece não existir.
|
||||
open_in_web: Abrir na web
|
||||
over_character_limit: limite de caracter excedeu %{max}
|
||||
pin_errors:
|
||||
direct: Publicações visíveis apenas para utilizadores mencionados não podem ser afixadas
|
||||
limit: Já afixaste a quantidade máxima de publicações
|
||||
ownership: Não podem ser afixadas publicações doutras pessoas
|
||||
reblog: Não pode afixar um reforço
|
||||
poll:
|
||||
total_people:
|
||||
one: "%{count} pessoa"
|
||||
other: "%{count} pessoas"
|
||||
total_votes:
|
||||
one: "%{count} voto"
|
||||
other: "%{count} votos"
|
||||
vote: Votar
|
||||
show_more: Mostrar mais
|
||||
show_thread: Mostrar conversa
|
||||
title: '%{name}: "%{quote}"'
|
||||
visibilities:
|
||||
direct: Direto
|
||||
|
@ -7,7 +7,6 @@ ro:
|
||||
hosted_on: Mastodon găzduit de %{domain}
|
||||
title: Despre
|
||||
accounts:
|
||||
follow: Urmărește
|
||||
followers:
|
||||
few: Urmăritori
|
||||
one: Urmăritor
|
||||
@ -681,24 +680,11 @@ ro:
|
||||
other: 'conținea aceste hashtag-uri nepermise: %{tags}'
|
||||
errors:
|
||||
in_reply_not_found: Postarea la care încercați să răspundeți nu pare să existe.
|
||||
open_in_web: Deschide pe web
|
||||
over_character_limit: s-a depășit limita de caracter %{max}
|
||||
pin_errors:
|
||||
limit: Deja ai fixat numărul maxim de postări
|
||||
ownership: Postarea altcuiva nu poate fi fixată
|
||||
reblog: Un impuls nu poate fi fixat
|
||||
poll:
|
||||
total_people:
|
||||
few: "%{count} persoane"
|
||||
one: "%{count} persoană"
|
||||
other: "%{count} de persoane"
|
||||
total_votes:
|
||||
few: "%{count} voturi"
|
||||
one: "%{count} vot"
|
||||
other: "%{count} de voturi"
|
||||
vote: Votează
|
||||
show_more: Arată mai mult
|
||||
show_thread: Arată discuția
|
||||
visibilities:
|
||||
private: Doar urmăritorii
|
||||
private_long: Arată doar urmăritorilor
|
||||
|
@ -7,7 +7,6 @@ ru:
|
||||
hosted_on: Вы получили это сообщение, так как зарегистрированы на %{domain}
|
||||
title: О проекте
|
||||
accounts:
|
||||
follow: Подписаться
|
||||
followers:
|
||||
few: подписчика
|
||||
many: подписчиков
|
||||
@ -1692,27 +1691,12 @@ ru:
|
||||
edited_at_html: Редактировано %{date}
|
||||
errors:
|
||||
in_reply_not_found: Пост, на который вы пытаетесь ответить, не существует или удалён.
|
||||
open_in_web: Открыть в веб-версии
|
||||
over_character_limit: превышен лимит символов (%{max})
|
||||
pin_errors:
|
||||
direct: Сообщения, видимые только упомянутым пользователям, не могут быть закреплены
|
||||
limit: Вы закрепили максимально возможное число постов
|
||||
ownership: Нельзя закрепить чужой пост
|
||||
reblog: Нельзя закрепить продвинутый пост
|
||||
poll:
|
||||
total_people:
|
||||
few: "%{count} человека"
|
||||
many: "%{count} человек"
|
||||
one: "%{count} человек"
|
||||
other: "%{count} человек"
|
||||
total_votes:
|
||||
few: "%{count} голоса"
|
||||
many: "%{count} голосов"
|
||||
one: "%{count} голос"
|
||||
other: "%{count} голосов"
|
||||
vote: Голосовать
|
||||
show_more: Развернуть
|
||||
show_thread: Открыть обсуждение
|
||||
title: '%{name}: "%{quote}"'
|
||||
visibilities:
|
||||
direct: Адресованный
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user