Sync to 2.4.1
This commit is contained in:
commit
eebf345440
791 changed files with 22017 additions and 7132 deletions
|
|
@ -1,5 +1,5 @@
|
|||
import api, { getLinks } from '../api';
|
||||
import asyncDB from '../db/async';
|
||||
import openDB from '../storage/db';
|
||||
import { importAccount, importFetchedAccount, importFetchedAccounts } from './importer';
|
||||
|
||||
export const ACCOUNT_FETCH_REQUEST = 'ACCOUNT_FETCH_REQUEST';
|
||||
|
|
@ -94,16 +94,19 @@ export function fetchAccount(id) {
|
|||
|
||||
dispatch(fetchAccountRequest(id));
|
||||
|
||||
asyncDB.then(db => getFromDB(
|
||||
openDB().then(db => getFromDB(
|
||||
dispatch,
|
||||
getState,
|
||||
db.transaction('accounts', 'read').objectStore('accounts').index('id'),
|
||||
id
|
||||
)).catch(() => api(getState).get(`/api/v1/accounts/${id}`).then(response => {
|
||||
).then(() => db.close(), error => {
|
||||
db.close();
|
||||
throw error;
|
||||
})).catch(() => api(getState).get(`/api/v1/accounts/${id}`).then(response => {
|
||||
dispatch(importFetchedAccount(response.data));
|
||||
})).then(() => {
|
||||
dispatch(fetchAccountSuccess());
|
||||
}, error => {
|
||||
}).catch(error => {
|
||||
dispatch(fetchAccountFail(id, error));
|
||||
});
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,3 +1,10 @@
|
|||
import { defineMessages } from 'react-intl';
|
||||
|
||||
const messages = defineMessages({
|
||||
unexpectedTitle: { id: 'alert.unexpected.title', defaultMessage: 'Oops!' },
|
||||
unexpectedMessage: { id: 'alert.unexpected.message', defaultMessage: 'An unexpected error occurred.' },
|
||||
});
|
||||
|
||||
export const ALERT_SHOW = 'ALERT_SHOW';
|
||||
export const ALERT_DISMISS = 'ALERT_DISMISS';
|
||||
export const ALERT_CLEAR = 'ALERT_CLEAR';
|
||||
|
|
@ -22,3 +29,21 @@ export function showAlert(title, message) {
|
|||
message,
|
||||
};
|
||||
};
|
||||
|
||||
export function showAlertForError(error) {
|
||||
if (error.response) {
|
||||
const { data, status, statusText } = error.response;
|
||||
|
||||
let message = statusText;
|
||||
let title = `${status}`;
|
||||
|
||||
if (data.error) {
|
||||
message = data.error;
|
||||
}
|
||||
|
||||
return showAlert(title, message);
|
||||
} else {
|
||||
console.error(error);
|
||||
return showAlert(messages.unexpectedTitle, messages.unexpectedMessage);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,8 +1,9 @@
|
|||
import { saveSettings } from './settings';
|
||||
|
||||
export const COLUMN_ADD = 'COLUMN_ADD';
|
||||
export const COLUMN_REMOVE = 'COLUMN_REMOVE';
|
||||
export const COLUMN_MOVE = 'COLUMN_MOVE';
|
||||
export const COLUMN_ADD = 'COLUMN_ADD';
|
||||
export const COLUMN_REMOVE = 'COLUMN_REMOVE';
|
||||
export const COLUMN_MOVE = 'COLUMN_MOVE';
|
||||
export const COLUMN_PARAMS_CHANGE = 'COLUMN_PARAMS_CHANGE';
|
||||
|
||||
export function addColumn(id, params) {
|
||||
return dispatch => {
|
||||
|
|
@ -38,3 +39,15 @@ export function moveColumn(uuid, direction) {
|
|||
dispatch(saveSettings());
|
||||
};
|
||||
};
|
||||
|
||||
export function changeColumnParams(uuid, params) {
|
||||
return dispatch => {
|
||||
dispatch({
|
||||
type: COLUMN_PARAMS_CHANGE,
|
||||
uuid,
|
||||
params,
|
||||
});
|
||||
|
||||
dispatch(saveSettings());
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,11 +1,13 @@
|
|||
import api from '../api';
|
||||
import { CancelToken } from 'axios';
|
||||
import { CancelToken, isCancel } from 'axios';
|
||||
import { throttle } from 'lodash';
|
||||
import { search as emojiSearch } from '../features/emoji/emoji_mart_search_light';
|
||||
import { tagHistory } from '../settings';
|
||||
import { useEmoji } from './emojis';
|
||||
import resizeImage from '../utils/resize_image';
|
||||
import { importFetchedAccounts } from './importer';
|
||||
import { updateTimeline } from './timelines';
|
||||
import { showAlertForError } from './alerts';
|
||||
|
||||
let cancelFetchComposeSuggestionsAccounts;
|
||||
|
||||
|
|
@ -15,6 +17,7 @@ export const COMPOSE_SUBMIT_SUCCESS = 'COMPOSE_SUBMIT_SUCCESS';
|
|||
export const COMPOSE_SUBMIT_FAIL = 'COMPOSE_SUBMIT_FAIL';
|
||||
export const COMPOSE_REPLY = 'COMPOSE_REPLY';
|
||||
export const COMPOSE_REPLY_CANCEL = 'COMPOSE_REPLY_CANCEL';
|
||||
export const COMPOSE_DIRECT = 'COMPOSE_DIRECT';
|
||||
export const COMPOSE_MENTION = 'COMPOSE_MENTION';
|
||||
export const COMPOSE_RESET = 'COMPOSE_RESET';
|
||||
export const COMPOSE_UPLOAD_REQUEST = 'COMPOSE_UPLOAD_REQUEST';
|
||||
|
|
@ -91,6 +94,19 @@ export function mentionCompose(account, router) {
|
|||
};
|
||||
};
|
||||
|
||||
export function directCompose(account, router) {
|
||||
return (dispatch, getState) => {
|
||||
dispatch({
|
||||
type: COMPOSE_DIRECT,
|
||||
account: account,
|
||||
});
|
||||
|
||||
if (!getState().getIn(['compose', 'mounted'])) {
|
||||
router.push('/statuses/new');
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
export function submitCompose() {
|
||||
return function (dispatch, getState) {
|
||||
const status = getState().getIn(['compose', 'text'], '');
|
||||
|
|
@ -130,6 +146,8 @@ export function submitCompose() {
|
|||
if (response.data.in_reply_to_id === null && response.data.visibility === 'public') {
|
||||
insertIfOnline('community');
|
||||
insertIfOnline('public');
|
||||
} else if (response.data.visibility === 'direct') {
|
||||
insertIfOnline('direct');
|
||||
}
|
||||
}).catch(function (error) {
|
||||
dispatch(submitComposeFail(error));
|
||||
|
|
@ -165,18 +183,14 @@ export function uploadCompose(files) {
|
|||
|
||||
dispatch(uploadComposeRequest());
|
||||
|
||||
let data = new FormData();
|
||||
data.append('file', files[0]);
|
||||
resizeImage(files[0]).then(file => {
|
||||
const data = new FormData();
|
||||
data.append('file', file);
|
||||
|
||||
api(getState).post('/api/v1/media', data, {
|
||||
onUploadProgress: function (e) {
|
||||
dispatch(uploadComposeProgress(e.loaded, e.total));
|
||||
},
|
||||
}).then(function (response) {
|
||||
dispatch(uploadComposeSuccess(response.data));
|
||||
}).catch(function (error) {
|
||||
dispatch(uploadComposeFail(error));
|
||||
});
|
||||
return api(getState).post('/api/v1/media', data, {
|
||||
onUploadProgress: ({ loaded, total }) => dispatch(uploadComposeProgress(loaded, total)),
|
||||
}).then(({ data }) => dispatch(uploadComposeSuccess(data)));
|
||||
}).catch(error => dispatch(uploadComposeFail(error)));
|
||||
};
|
||||
};
|
||||
|
||||
|
|
@ -277,6 +291,10 @@ const fetchComposeSuggestionsAccounts = throttle((dispatch, getState, token) =>
|
|||
}).then(response => {
|
||||
dispatch(importFetchedAccounts(response.data));
|
||||
dispatch(readyComposeSuggestionsAccounts(token, response.data));
|
||||
}).catch(error => {
|
||||
if (!isCancel(error)) {
|
||||
dispatch(showAlertForError(error));
|
||||
}
|
||||
});
|
||||
}, 200, { leading: true, trailing: true });
|
||||
|
||||
|
|
@ -427,11 +445,12 @@ export function changeComposeVisibility(value) {
|
|||
};
|
||||
};
|
||||
|
||||
export function insertEmojiCompose(position, emoji) {
|
||||
export function insertEmojiCompose(position, emoji, needsSpace) {
|
||||
return {
|
||||
type: COMPOSE_EMOJI_INSERT,
|
||||
position,
|
||||
emoji,
|
||||
needsSpace,
|
||||
};
|
||||
};
|
||||
|
||||
|
|
|
|||
37
app/javascript/mastodon/actions/custom_emojis.js
Normal file
37
app/javascript/mastodon/actions/custom_emojis.js
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
import api from '../api';
|
||||
|
||||
export const CUSTOM_EMOJIS_FETCH_REQUEST = 'CUSTOM_EMOJIS_FETCH_REQUEST';
|
||||
export const CUSTOM_EMOJIS_FETCH_SUCCESS = 'CUSTOM_EMOJIS_FETCH_SUCCESS';
|
||||
export const CUSTOM_EMOJIS_FETCH_FAIL = 'CUSTOM_EMOJIS_FETCH_FAIL';
|
||||
|
||||
export function fetchCustomEmojis() {
|
||||
return (dispatch, getState) => {
|
||||
dispatch(fetchCustomEmojisRequest());
|
||||
|
||||
api(getState).get('/api/v1/custom_emojis').then(response => {
|
||||
dispatch(fetchCustomEmojisSuccess(response.data));
|
||||
}).catch(error => {
|
||||
dispatch(fetchCustomEmojisFail(error));
|
||||
});
|
||||
};
|
||||
};
|
||||
|
||||
export function fetchCustomEmojisRequest() {
|
||||
return {
|
||||
type: CUSTOM_EMOJIS_FETCH_REQUEST,
|
||||
};
|
||||
};
|
||||
|
||||
export function fetchCustomEmojisSuccess(custom_emojis) {
|
||||
return {
|
||||
type: CUSTOM_EMOJIS_FETCH_SUCCESS,
|
||||
custom_emojis,
|
||||
};
|
||||
};
|
||||
|
||||
export function fetchCustomEmojisFail(error) {
|
||||
return {
|
||||
type: CUSTOM_EMOJIS_FETCH_FAIL,
|
||||
error,
|
||||
};
|
||||
};
|
||||
|
|
@ -12,12 +12,18 @@ export const DOMAIN_BLOCKS_FETCH_REQUEST = 'DOMAIN_BLOCKS_FETCH_REQUEST';
|
|||
export const DOMAIN_BLOCKS_FETCH_SUCCESS = 'DOMAIN_BLOCKS_FETCH_SUCCESS';
|
||||
export const DOMAIN_BLOCKS_FETCH_FAIL = 'DOMAIN_BLOCKS_FETCH_FAIL';
|
||||
|
||||
export function blockDomain(domain, accountId) {
|
||||
export const DOMAIN_BLOCKS_EXPAND_REQUEST = 'DOMAIN_BLOCKS_EXPAND_REQUEST';
|
||||
export const DOMAIN_BLOCKS_EXPAND_SUCCESS = 'DOMAIN_BLOCKS_EXPAND_SUCCESS';
|
||||
export const DOMAIN_BLOCKS_EXPAND_FAIL = 'DOMAIN_BLOCKS_EXPAND_FAIL';
|
||||
|
||||
export function blockDomain(domain) {
|
||||
return (dispatch, getState) => {
|
||||
dispatch(blockDomainRequest(domain));
|
||||
|
||||
api(getState).post('/api/v1/domain_blocks', { domain }).then(() => {
|
||||
dispatch(blockDomainSuccess(domain, accountId));
|
||||
const at_domain = '@' + domain;
|
||||
const accounts = getState().get('accounts').filter(item => item.get('acct').endsWith(at_domain)).valueSeq().map(item => item.get('id'));
|
||||
dispatch(blockDomainSuccess(domain, accounts));
|
||||
}).catch(err => {
|
||||
dispatch(blockDomainFail(domain, err));
|
||||
});
|
||||
|
|
@ -31,11 +37,11 @@ export function blockDomainRequest(domain) {
|
|||
};
|
||||
};
|
||||
|
||||
export function blockDomainSuccess(domain, accountId) {
|
||||
export function blockDomainSuccess(domain, accounts) {
|
||||
return {
|
||||
type: DOMAIN_BLOCK_SUCCESS,
|
||||
domain,
|
||||
accountId,
|
||||
accounts,
|
||||
};
|
||||
};
|
||||
|
||||
|
|
@ -47,12 +53,14 @@ export function blockDomainFail(domain, error) {
|
|||
};
|
||||
};
|
||||
|
||||
export function unblockDomain(domain, accountId) {
|
||||
export function unblockDomain(domain) {
|
||||
return (dispatch, getState) => {
|
||||
dispatch(unblockDomainRequest(domain));
|
||||
|
||||
api(getState).delete('/api/v1/domain_blocks', { params: { domain } }).then(() => {
|
||||
dispatch(unblockDomainSuccess(domain, accountId));
|
||||
const at_domain = '@' + domain;
|
||||
const accounts = getState().get('accounts').filter(item => item.get('acct').endsWith(at_domain)).valueSeq().map(item => item.get('id'));
|
||||
dispatch(unblockDomainSuccess(domain, accounts));
|
||||
}).catch(err => {
|
||||
dispatch(unblockDomainFail(domain, err));
|
||||
});
|
||||
|
|
@ -66,11 +74,11 @@ export function unblockDomainRequest(domain) {
|
|||
};
|
||||
};
|
||||
|
||||
export function unblockDomainSuccess(domain, accountId) {
|
||||
export function unblockDomainSuccess(domain, accounts) {
|
||||
return {
|
||||
type: DOMAIN_UNBLOCK_SUCCESS,
|
||||
domain,
|
||||
accountId,
|
||||
accounts,
|
||||
};
|
||||
};
|
||||
|
||||
|
|
@ -86,7 +94,7 @@ export function fetchDomainBlocks() {
|
|||
return (dispatch, getState) => {
|
||||
dispatch(fetchDomainBlocksRequest());
|
||||
|
||||
api(getState).get().then(response => {
|
||||
api(getState).get('/api/v1/domain_blocks').then(response => {
|
||||
const next = getLinks(response).refs.find(link => link.rel === 'next');
|
||||
dispatch(fetchDomainBlocksSuccess(response.data, next ? next.uri : null));
|
||||
}).catch(err => {
|
||||
|
|
@ -115,3 +123,43 @@ export function fetchDomainBlocksFail(error) {
|
|||
error,
|
||||
};
|
||||
};
|
||||
|
||||
export function expandDomainBlocks() {
|
||||
return (dispatch, getState) => {
|
||||
const url = getState().getIn(['domain_lists', 'blocks', 'next']);
|
||||
|
||||
if (url === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
dispatch(expandDomainBlocksRequest());
|
||||
|
||||
api(getState).get(url).then(response => {
|
||||
const next = getLinks(response).refs.find(link => link.rel === 'next');
|
||||
dispatch(expandDomainBlocksSuccess(response.data, next ? next.uri : null));
|
||||
}).catch(err => {
|
||||
dispatch(expandDomainBlocksFail(err));
|
||||
});
|
||||
};
|
||||
};
|
||||
|
||||
export function expandDomainBlocksRequest() {
|
||||
return {
|
||||
type: DOMAIN_BLOCKS_EXPAND_REQUEST,
|
||||
};
|
||||
};
|
||||
|
||||
export function expandDomainBlocksSuccess(domains, next) {
|
||||
return {
|
||||
type: DOMAIN_BLOCKS_EXPAND_SUCCESS,
|
||||
domains,
|
||||
next,
|
||||
};
|
||||
};
|
||||
|
||||
export function expandDomainBlocksFail(error) {
|
||||
return {
|
||||
type: DOMAIN_BLOCKS_EXPAND_FAIL,
|
||||
error,
|
||||
};
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
import { putAccounts, putStatuses } from '../../db/modifier';
|
||||
import { autoPlayGif } from '../../initial_state';
|
||||
import { putAccounts, putStatuses } from '../../storage/modifier';
|
||||
import { normalizeAccount, normalizeStatus } from './normalizer';
|
||||
|
||||
export const ACCOUNT_IMPORT = 'ACCOUNT_IMPORT';
|
||||
|
|
@ -44,7 +45,7 @@ export function importFetchedAccounts(accounts) {
|
|||
}
|
||||
|
||||
accounts.forEach(processAccount);
|
||||
putAccounts(normalAccounts);
|
||||
putAccounts(normalAccounts, !autoPlayGif);
|
||||
|
||||
return importAccounts(normalAccounts);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,14 +1,31 @@
|
|||
import escapeTextContentForBrowser from 'escape-html';
|
||||
import emojify from '../../features/emoji/emoji';
|
||||
import { unescapeHTML } from '../../utils/html';
|
||||
|
||||
const domParser = new DOMParser();
|
||||
|
||||
const makeEmojiMap = record => record.emojis.reduce((obj, emoji) => {
|
||||
obj[`:${emoji.shortcode}:`] = emoji;
|
||||
return obj;
|
||||
}, {});
|
||||
|
||||
export function normalizeAccount(account) {
|
||||
account = { ...account };
|
||||
|
||||
const emojiMap = makeEmojiMap(account);
|
||||
const displayName = account.display_name.length === 0 ? account.username : account.display_name;
|
||||
account.display_name_html = emojify(escapeTextContentForBrowser(displayName));
|
||||
account.note_emojified = emojify(account.note);
|
||||
|
||||
account.display_name_html = emojify(escapeTextContentForBrowser(displayName), emojiMap);
|
||||
account.note_emojified = emojify(account.note, emojiMap);
|
||||
|
||||
if (account.fields) {
|
||||
account.fields = account.fields.map(pair => ({
|
||||
...pair,
|
||||
name_emojified: emojify(escapeTextContentForBrowser(pair.name)),
|
||||
value_emojified: emojify(pair.value, emojiMap),
|
||||
value_plain: unescapeHTML(pair.value),
|
||||
}));
|
||||
}
|
||||
|
||||
if (account.moved) {
|
||||
account.moved = account.moved.id;
|
||||
|
|
@ -34,11 +51,7 @@ export function normalizeStatus(status, normalOldStatus) {
|
|||
normalStatus.hidden = normalOldStatus.get('hidden');
|
||||
} else {
|
||||
const searchContent = [status.spoiler_text, status.content].join('\n\n').replace(/<br\s*\/?>/g, '\n').replace(/<\/p><p>/g, '\n\n');
|
||||
|
||||
const emojiMap = normalStatus.emojis.reduce((obj, emoji) => {
|
||||
obj[`:${emoji.shortcode}:`] = emoji;
|
||||
return obj;
|
||||
}, {});
|
||||
const emojiMap = makeEmojiMap(normalStatus);
|
||||
|
||||
normalStatus.search_index = domParser.parseFromString(searchContent, 'text/html').documentElement.textContent;
|
||||
normalStatus.contentHtml = emojify(normalStatus.content, emojiMap);
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
import api from '../api';
|
||||
import { importFetchedAccounts } from './importer';
|
||||
import { showAlertForError } from './alerts';
|
||||
|
||||
export const LIST_FETCH_REQUEST = 'LIST_FETCH_REQUEST';
|
||||
export const LIST_FETCH_SUCCESS = 'LIST_FETCH_SUCCESS';
|
||||
|
|
@ -236,7 +237,7 @@ export const fetchListSuggestions = q => (dispatch, getState) => {
|
|||
api(getState).get('/api/v1/accounts/search', { params }).then(({ data }) => {
|
||||
dispatch(importFetchedAccounts(data));
|
||||
dispatch(fetchListSuggestionsReady(q, data));
|
||||
});
|
||||
}).catch(error => dispatch(showAlertForError(error)));
|
||||
};
|
||||
|
||||
export const fetchListSuggestionsReady = (query, accounts) => ({
|
||||
|
|
|
|||
|
|
@ -8,8 +8,10 @@ import {
|
|||
importFetchedStatuses,
|
||||
} from './importer';
|
||||
import { defineMessages } from 'react-intl';
|
||||
import { unescapeHTML } from '../utils/html';
|
||||
|
||||
export const NOTIFICATIONS_UPDATE = 'NOTIFICATIONS_UPDATE';
|
||||
export const NOTIFICATIONS_UPDATE = 'NOTIFICATIONS_UPDATE';
|
||||
export const NOTIFICATIONS_UPDATE_NOOP = 'NOTIFICATIONS_UPDATE_NOOP';
|
||||
|
||||
export const NOTIFICATIONS_EXPAND_REQUEST = 'NOTIFICATIONS_EXPAND_REQUEST';
|
||||
export const NOTIFICATIONS_EXPAND_SUCCESS = 'NOTIFICATIONS_EXPAND_SUCCESS';
|
||||
|
|
@ -20,6 +22,7 @@ export const NOTIFICATIONS_SCROLL_TOP = 'NOTIFICATIONS_SCROLL_TOP';
|
|||
|
||||
defineMessages({
|
||||
mention: { id: 'notification.mention', defaultMessage: '{name} mentioned you' },
|
||||
group: { id: 'notifications.group', defaultMessage: '{count} notifications' },
|
||||
});
|
||||
|
||||
const fetchRelatedRelationships = (dispatch, notifications) => {
|
||||
|
|
@ -30,28 +33,32 @@ const fetchRelatedRelationships = (dispatch, notifications) => {
|
|||
}
|
||||
};
|
||||
|
||||
const unescapeHTML = (html) => {
|
||||
const wrapper = document.createElement('div');
|
||||
html = html.replace(/<br \/>|<br>|\n/g, ' ');
|
||||
wrapper.innerHTML = html;
|
||||
return wrapper.textContent;
|
||||
};
|
||||
|
||||
export function updateNotifications(notification, intlMessages, intlLocale) {
|
||||
return (dispatch, getState) => {
|
||||
const showAlert = getState().getIn(['settings', 'notifications', 'alerts', notification.type], true);
|
||||
const playSound = getState().getIn(['settings', 'notifications', 'sounds', notification.type], true);
|
||||
const showInColumn = getState().getIn(['settings', 'notifications', 'shows', notification.type], true);
|
||||
const showAlert = getState().getIn(['settings', 'notifications', 'alerts', notification.type], true);
|
||||
const playSound = getState().getIn(['settings', 'notifications', 'sounds', notification.type], true);
|
||||
|
||||
dispatch(importFetchedAccount(notification.account));
|
||||
dispatch(importFetchedStatus(notification.status));
|
||||
if (showInColumn) {
|
||||
dispatch(importFetchedAccount(notification.account));
|
||||
|
||||
dispatch({
|
||||
type: NOTIFICATIONS_UPDATE,
|
||||
notification,
|
||||
meta: playSound ? { sound: 'boop' } : undefined,
|
||||
});
|
||||
if (notification.status) {
|
||||
dispatch(importFetchedStatus(notification.status));
|
||||
}
|
||||
|
||||
fetchRelatedRelationships(dispatch, [notification]);
|
||||
dispatch({
|
||||
type: NOTIFICATIONS_UPDATE,
|
||||
notification,
|
||||
meta: playSound ? { sound: 'boop' } : undefined,
|
||||
});
|
||||
|
||||
fetchRelatedRelationships(dispatch, [notification]);
|
||||
} else if (playSound) {
|
||||
dispatch({
|
||||
type: NOTIFICATIONS_UPDATE_NOOP,
|
||||
meta: { sound: 'boop' },
|
||||
});
|
||||
}
|
||||
|
||||
// Desktop notifications
|
||||
if (typeof window.Notification !== 'undefined' && showAlert) {
|
||||
|
|
@ -59,6 +66,7 @@ export function updateNotifications(notification, intlMessages, intlLocale) {
|
|||
const body = (notification.status && notification.status.spoiler_text.length > 0) ? notification.status.spoiler_text : unescapeHTML(notification.status ? notification.status.content : '');
|
||||
|
||||
const notify = new Notification(title, { body, icon: notification.account.avatar, tag: notification.id });
|
||||
|
||||
notify.addEventListener('click', () => {
|
||||
window.focus();
|
||||
notify.close();
|
||||
|
|
@ -69,9 +77,14 @@ export function updateNotifications(notification, intlMessages, intlLocale) {
|
|||
|
||||
const excludeTypesFromSettings = state => state.getIn(['settings', 'notifications', 'shows']).filter(enabled => !enabled).keySeq().toJS();
|
||||
|
||||
export function expandNotifications({ maxId } = {}) {
|
||||
const noOp = () => {};
|
||||
|
||||
export function expandNotifications({ maxId } = {}, done = noOp) {
|
||||
return (dispatch, getState) => {
|
||||
if (getState().getIn(['notifications', 'isLoading'])) {
|
||||
const notifications = getState().get('notifications');
|
||||
|
||||
if (notifications.get('isLoading')) {
|
||||
done();
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -80,6 +93,10 @@ export function expandNotifications({ maxId } = {}) {
|
|||
exclude_types: excludeTypesFromSettings(getState()),
|
||||
};
|
||||
|
||||
if (!maxId && notifications.get('items').size > 0) {
|
||||
params.since_id = notifications.getIn(['items', 0]);
|
||||
}
|
||||
|
||||
dispatch(expandNotificationsRequest());
|
||||
|
||||
api(getState).get('/api/v1/notifications', { params }).then(response => {
|
||||
|
|
@ -90,8 +107,10 @@ export function expandNotifications({ maxId } = {}) {
|
|||
|
||||
dispatch(expandNotificationsSuccess(response.data, next ? next.uri : null));
|
||||
fetchRelatedRelationships(dispatch, response.data);
|
||||
done();
|
||||
}).catch(error => {
|
||||
dispatch(expandNotificationsFail(error));
|
||||
done();
|
||||
});
|
||||
};
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
import api from '../../api';
|
||||
import { decode as decodeBase64 } from '../../utils/base64';
|
||||
import { pushNotificationsSetting } from '../../settings';
|
||||
import { setBrowserSupport, setSubscription, clearSubscription } from './setter';
|
||||
import { me } from '../../initial_state';
|
||||
|
|
@ -10,13 +11,7 @@ const urlBase64ToUint8Array = (base64String) => {
|
|||
.replace(/\-/g, '+')
|
||||
.replace(/_/g, '/');
|
||||
|
||||
const rawData = window.atob(base64);
|
||||
const outputArray = new Uint8Array(rawData.length);
|
||||
|
||||
for (let i = 0; i < rawData.length; ++i) {
|
||||
outputArray[i] = rawData.charCodeAt(i);
|
||||
}
|
||||
return outputArray;
|
||||
return decodeBase64(base64);
|
||||
};
|
||||
|
||||
const getApplicationServerKey = () => document.querySelector('[name="applicationServerKey"]').getAttribute('content');
|
||||
|
|
@ -36,7 +31,7 @@ const subscribe = (registration) =>
|
|||
const unsubscribe = ({ registration, subscription }) =>
|
||||
subscription ? subscription.unsubscribe().then(() => registration) : registration;
|
||||
|
||||
const sendSubscriptionToBackend = (getState, subscription) => {
|
||||
const sendSubscriptionToBackend = (subscription) => {
|
||||
const params = { subscription };
|
||||
|
||||
if (me) {
|
||||
|
|
@ -46,7 +41,7 @@ const sendSubscriptionToBackend = (getState, subscription) => {
|
|||
}
|
||||
}
|
||||
|
||||
return api(getState).post('/api/web/push_subscriptions', params).then(response => response.data);
|
||||
return api().post('/api/web/push_subscriptions', params).then(response => response.data);
|
||||
};
|
||||
|
||||
// Last one checks for payload support: https://web-push-book.gauntface.com/chapter-06/01-non-standards-browsers/#no-payload
|
||||
|
|
@ -56,13 +51,6 @@ export function register () {
|
|||
return (dispatch, getState) => {
|
||||
dispatch(setBrowserSupport(supportsPushNotifications));
|
||||
|
||||
if (me && !pushNotificationsSetting.get(me)) {
|
||||
const alerts = getState().getIn(['push_notifications', 'alerts']);
|
||||
if (alerts) {
|
||||
pushNotificationsSetting.set(me, { alerts: alerts });
|
||||
}
|
||||
}
|
||||
|
||||
if (supportsPushNotifications) {
|
||||
if (!getApplicationServerKey()) {
|
||||
console.error('The VAPID public key is not set. You will not be able to receive Web Push Notifications.');
|
||||
|
|
@ -85,13 +73,13 @@ export function register () {
|
|||
} else {
|
||||
// Something went wrong, try to subscribe again
|
||||
return unsubscribe({ registration, subscription }).then(subscribe).then(
|
||||
subscription => sendSubscriptionToBackend(getState, subscription));
|
||||
subscription => sendSubscriptionToBackend(subscription));
|
||||
}
|
||||
}
|
||||
|
||||
// No subscription, try to subscribe
|
||||
return subscribe(registration).then(
|
||||
subscription => sendSubscriptionToBackend(getState, subscription));
|
||||
subscription => sendSubscriptionToBackend(subscription));
|
||||
})
|
||||
.then(subscription => {
|
||||
// If we got a PushSubscription (and not a subscription object from the backend)
|
||||
|
|
@ -116,14 +104,11 @@ export function register () {
|
|||
pushNotificationsSetting.remove(me);
|
||||
}
|
||||
|
||||
try {
|
||||
getRegistration()
|
||||
.then(getPushSubscription)
|
||||
.then(unsubscribe);
|
||||
} catch (e) {
|
||||
|
||||
}
|
||||
});
|
||||
return getRegistration()
|
||||
.then(getPushSubscription)
|
||||
.then(unsubscribe);
|
||||
})
|
||||
.catch(console.warn);
|
||||
} else {
|
||||
console.warn('Your browser does not support Web Push Notifications.');
|
||||
}
|
||||
|
|
@ -137,12 +122,12 @@ export function saveSettings() {
|
|||
const alerts = state.get('alerts');
|
||||
const data = { alerts };
|
||||
|
||||
api(getState).put(`/api/web/push_subscriptions/${subscription.get('id')}`, {
|
||||
api().put(`/api/web/push_subscriptions/${subscription.get('id')}`, {
|
||||
data,
|
||||
}).then(() => {
|
||||
if (me) {
|
||||
pushNotificationsSetting.set(me, data);
|
||||
}
|
||||
});
|
||||
}).catch(console.warn);
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@ export function submitSearch() {
|
|||
|
||||
dispatch(fetchSearchRequest());
|
||||
|
||||
api(getState).get('/api/v1/search', {
|
||||
api(getState).get('/api/v2/search', {
|
||||
params: {
|
||||
q: value,
|
||||
resolve: true,
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
import api from '../api';
|
||||
import { debounce } from 'lodash';
|
||||
import { showAlertForError } from './alerts';
|
||||
|
||||
export const SETTING_CHANGE = 'SETTING_CHANGE';
|
||||
export const SETTING_SAVE = 'SETTING_SAVE';
|
||||
|
|
@ -23,7 +24,9 @@ const debouncedSave = debounce((dispatch, getState) => {
|
|||
|
||||
const data = getState().get('settings').filter((_, path) => path !== 'saved').toJS();
|
||||
|
||||
api(getState).put('/api/web/settings', { data }).then(() => dispatch({ type: SETTING_SAVE }));
|
||||
api().put('/api/web/settings', { data })
|
||||
.then(() => dispatch({ type: SETTING_SAVE }))
|
||||
.catch(error => dispatch(showAlertForError(error)));
|
||||
}, 5000, { trailing: true });
|
||||
|
||||
export function saveSettings() {
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import api from '../api';
|
||||
import asyncDB from '../db/async';
|
||||
import { evictStatus } from '../db/modifier';
|
||||
import openDB from '../storage/db';
|
||||
import { evictStatus } from '../storage/modifier';
|
||||
|
||||
import { deleteFromTimelines } from './timelines';
|
||||
import { fetchStatusCard } from './cards';
|
||||
|
|
@ -29,6 +29,8 @@ export const STATUS_UNMUTE_FAIL = 'STATUS_UNMUTE_FAIL';
|
|||
export const STATUS_REVEAL = 'STATUS_REVEAL';
|
||||
export const STATUS_HIDE = 'STATUS_HIDE';
|
||||
|
||||
export const REDRAFT = 'REDRAFT';
|
||||
|
||||
export function fetchStatusRequest(id, skipLoading) {
|
||||
return {
|
||||
type: STATUS_FETCH_REQUEST,
|
||||
|
|
@ -92,12 +94,17 @@ export function fetchStatus(id) {
|
|||
|
||||
dispatch(fetchStatusRequest(id, skipLoading));
|
||||
|
||||
asyncDB.then(db => {
|
||||
openDB().then(db => {
|
||||
const transaction = db.transaction(['accounts', 'statuses'], 'read');
|
||||
const accountIndex = transaction.objectStore('accounts').index('id');
|
||||
const index = transaction.objectStore('statuses').index('id');
|
||||
|
||||
return getFromDB(dispatch, getState, accountIndex, index, id);
|
||||
return getFromDB(dispatch, getState, accountIndex, index, id).then(() => {
|
||||
db.close();
|
||||
}, error => {
|
||||
db.close();
|
||||
throw error;
|
||||
});
|
||||
}).then(() => {
|
||||
dispatch(fetchStatusSuccess(skipLoading));
|
||||
}, () => api(getState).get(`/api/v1/statuses/${id}`).then(response => {
|
||||
|
|
@ -126,14 +133,27 @@ export function fetchStatusFail(id, error, skipLoading) {
|
|||
};
|
||||
};
|
||||
|
||||
export function deleteStatus(id) {
|
||||
export function redraft(status) {
|
||||
return {
|
||||
type: REDRAFT,
|
||||
status,
|
||||
};
|
||||
};
|
||||
|
||||
export function deleteStatus(id, withRedraft = false) {
|
||||
return (dispatch, getState) => {
|
||||
const status = getState().getIn(['statuses', id]);
|
||||
|
||||
dispatch(deleteStatusRequest(id));
|
||||
|
||||
api(getState).delete(`/api/v1/statuses/${id}`).then(() => {
|
||||
evictStatus(id);
|
||||
dispatch(deleteStatusSuccess(id));
|
||||
dispatch(deleteFromTimelines(id));
|
||||
|
||||
if (withRedraft) {
|
||||
dispatch(redraft(status));
|
||||
}
|
||||
}).catch(error => {
|
||||
dispatch(deleteStatusFail(id, error));
|
||||
});
|
||||
|
|
|
|||
|
|
@ -36,14 +36,13 @@ export function connectTimelineStream (timelineId, path, pollingRefresh = null)
|
|||
});
|
||||
}
|
||||
|
||||
function refreshHomeTimelineAndNotification (dispatch) {
|
||||
dispatch(expandHomeTimeline());
|
||||
dispatch(expandNotifications());
|
||||
}
|
||||
const refreshHomeTimelineAndNotification = (dispatch, done) => {
|
||||
dispatch(expandHomeTimeline({}, () => dispatch(expandNotifications({}, done))));
|
||||
};
|
||||
|
||||
export const connectUserStream = () => connectTimelineStream('home', 'user', refreshHomeTimelineAndNotification);
|
||||
export const connectCommunityStream = () => connectTimelineStream('community', 'public:local');
|
||||
export const connectMediaStream = () => connectTimelineStream('community', 'public:local');
|
||||
export const connectPublicStream = () => connectTimelineStream('public', 'public');
|
||||
export const connectHashtagStream = (tag) => connectTimelineStream(`hashtag:${tag}`, `hashtag&tag=${tag}`);
|
||||
export const connectListStream = (id) => connectTimelineStream(`list:${id}`, `list&list=${id}`);
|
||||
export const connectUserStream = () => connectTimelineStream('home', 'user', refreshHomeTimelineAndNotification);
|
||||
export const connectCommunityStream = ({ onlyMedia } = {}) => connectTimelineStream(`community${onlyMedia ? ':media' : ''}`, `public:local${onlyMedia ? ':media' : ''}`);
|
||||
export const connectPublicStream = ({ onlyMedia } = {}) => connectTimelineStream(`public${onlyMedia ? ':media' : ''}`, `public${onlyMedia ? ':media' : ''}`);
|
||||
export const connectHashtagStream = tag => connectTimelineStream(`hashtag:${tag}`, `hashtag&tag=${tag}`);
|
||||
export const connectDirectStream = () => connectTimelineStream('direct', 'direct');
|
||||
export const connectListStream = id => connectTimelineStream(`list:${id}`, `list&list=${id}`);
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import { importFetchedStatus, importFetchedStatuses } from './importer';
|
||||
import api, { getLinks } from '../api';
|
||||
import { Map as ImmutableMap } from 'immutable';
|
||||
import { Map as ImmutableMap, List as ImmutableList } from 'immutable';
|
||||
|
||||
export const TIMELINE_UPDATE = 'TIMELINE_UPDATE';
|
||||
export const TIMELINE_DELETE = 'TIMELINE_DELETE';
|
||||
|
|
@ -13,21 +13,9 @@ export const TIMELINE_SCROLL_TOP = 'TIMELINE_SCROLL_TOP';
|
|||
|
||||
export const TIMELINE_DISCONNECT = 'TIMELINE_DISCONNECT';
|
||||
|
||||
export const TIMELINE_CONTEXT_UPDATE = 'CONTEXT_UPDATE';
|
||||
|
||||
export function updateTimeline(timeline, status) {
|
||||
return (dispatch, getState) => {
|
||||
const references = status.reblog ? getState().get('statuses').filter((item, itemId) => (itemId === status.reblog.id || item.get('reblog') === status.reblog.id)).map((_, itemId) => itemId) : [];
|
||||
const parents = [];
|
||||
|
||||
if (status.in_reply_to_id) {
|
||||
let parent = getState().getIn(['statuses', status.in_reply_to_id]);
|
||||
|
||||
while (parent && parent.get('in_reply_to_id')) {
|
||||
parents.push(parent.get('id'));
|
||||
parent = getState().getIn(['statuses', parent.get('in_reply_to_id')]);
|
||||
}
|
||||
}
|
||||
|
||||
dispatch(importFetchedStatus(status));
|
||||
|
||||
|
|
@ -37,14 +25,6 @@ export function updateTimeline(timeline, status) {
|
|||
status,
|
||||
references,
|
||||
});
|
||||
|
||||
if (parents.length > 0) {
|
||||
dispatch({
|
||||
type: TIMELINE_CONTEXT_UPDATE,
|
||||
status,
|
||||
references: parents,
|
||||
});
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
|
|
@ -64,34 +44,44 @@ export function deleteFromTimelines(id) {
|
|||
};
|
||||
};
|
||||
|
||||
export function expandTimeline(timelineId, path, params = {}) {
|
||||
const noOp = () => {};
|
||||
|
||||
export function expandTimeline(timelineId, path, params = {}, done = noOp) {
|
||||
return (dispatch, getState) => {
|
||||
const timeline = getState().getIn(['timelines', timelineId], ImmutableMap());
|
||||
|
||||
if (timeline.get('isLoading')) {
|
||||
done();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!params.max_id && timeline.get('items', ImmutableList()).size > 0) {
|
||||
params.since_id = timeline.getIn(['items', 0]);
|
||||
}
|
||||
|
||||
dispatch(expandTimelineRequest(timelineId));
|
||||
|
||||
api(getState).get(path, { params }).then(response => {
|
||||
const next = getLinks(response).refs.find(link => link.rel === 'next');
|
||||
dispatch(importFetchedStatuses(response.data));
|
||||
dispatch(expandTimelineSuccess(timelineId, response.data, next ? next.uri : null, response.code === 206));
|
||||
done();
|
||||
}).catch(error => {
|
||||
dispatch(expandTimelineFail(timelineId, error));
|
||||
done();
|
||||
});
|
||||
};
|
||||
};
|
||||
|
||||
export const expandHomeTimeline = ({ maxId } = {}) => expandTimeline('home', '/api/v1/timelines/home', { max_id: maxId });
|
||||
export const expandPublicTimeline = ({ maxId } = {}) => expandTimeline('public', '/api/v1/timelines/public', { max_id: maxId });
|
||||
export const expandCommunityTimeline = ({ maxId } = {}) => expandTimeline('community', '/api/v1/timelines/public', { local: true, max_id: maxId });
|
||||
export const expandAccountTimeline = (accountId, { maxId, withReplies } = {}) => expandTimeline(`account:${accountId}${withReplies ? ':with_replies' : ''}`, `/api/v1/accounts/${accountId}/statuses`, { exclude_replies: !withReplies, max_id: maxId });
|
||||
export const expandHomeTimeline = ({ maxId } = {}, done = noOp) => expandTimeline('home', '/api/v1/timelines/home', { max_id: maxId }, done);
|
||||
export const expandPublicTimeline = ({ maxId, onlyMedia } = {}, done = noOp) => expandTimeline(`public${onlyMedia ? ':media' : ''}`, '/api/v1/timelines/public', { max_id: maxId, only_media: !!onlyMedia }, done);
|
||||
export const expandCommunityTimeline = ({ maxId, onlyMedia } = {}, done = noOp) => expandTimeline(`community${onlyMedia ? ':media' : ''}`, '/api/v1/timelines/public', { local: true, max_id: maxId, only_media: !!onlyMedia }, done);
|
||||
export const expandDirectTimeline = ({ maxId } = {}, done = noOp) => expandTimeline('direct', '/api/v1/timelines/direct', { max_id: maxId }, done);
|
||||
export const expandAccountTimeline = (accountId, { maxId, withReplies } = {}) => expandTimeline(`account:${accountId}${withReplies ? ':with_replies' : ''}`, `/api/v1/accounts/${accountId}/statuses`, { exclude_replies: !withReplies, max_id: maxId });
|
||||
export const expandAccountFeaturedTimeline = accountId => expandTimeline(`account:${accountId}:pinned`, `/api/v1/accounts/${accountId}/statuses`, { pinned: true });
|
||||
export const expandAccountMediaTimeline = (accountId, { maxId } = {}) => expandTimeline(`account:${accountId}:media`, `/api/v1/accounts/${accountId}/statuses`, { max_id: maxId, only_media: true });
|
||||
export const expandHashtagTimeline = (hashtag, { maxId } = {}) => expandTimeline(`hashtag:${hashtag}`, `/api/v1/timelines/tag/${hashtag}`, { max_id: maxId });
|
||||
export const expandListTimeline = (id, { maxId } = {}) => expandTimeline(`list:${id}`, `/api/v1/timelines/list/${id}`, { max_id: maxId });
|
||||
export const expandAccountMediaTimeline = (accountId, { maxId } = {}) => expandTimeline(`account:${accountId}:media`, `/api/v1/accounts/${accountId}/statuses`, { max_id: maxId, only_media: true });
|
||||
export const expandHashtagTimeline = (hashtag, { maxId } = {}, done = noOp) => expandTimeline(`hashtag:${hashtag}`, `/api/v1/timelines/tag/${hashtag}`, { max_id: maxId }, done);
|
||||
export const expandListTimeline = (id, { maxId } = {}, done = noOp) => expandTimeline(`list:${id}`, `/api/v1/timelines/list/${id}`, { max_id: maxId }, done);
|
||||
|
||||
export function expandTimelineRequest(timeline) {
|
||||
return {
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import includes from 'array-includes';
|
|||
import assign from 'object-assign';
|
||||
import values from 'object.values';
|
||||
import isNaN from 'is-nan';
|
||||
import { decode as decodeBase64 } from './utils/base64';
|
||||
|
||||
if (!Array.prototype.includes) {
|
||||
includes.shim();
|
||||
|
|
@ -21,3 +22,23 @@ if (!Object.values) {
|
|||
if (!Number.isNaN) {
|
||||
Number.isNaN = isNaN;
|
||||
}
|
||||
|
||||
if (!HTMLCanvasElement.prototype.toBlob) {
|
||||
const BASE64_MARKER = ';base64,';
|
||||
|
||||
Object.defineProperty(HTMLCanvasElement.prototype, 'toBlob', {
|
||||
value(callback, type = 'image/png', quality) {
|
||||
const dataURL = this.toDataURL(type, quality);
|
||||
let data;
|
||||
|
||||
if (dataURL.indexOf(BASE64_MARKER) >= 0) {
|
||||
const [, base64] = dataURL.split(BASE64_MARKER);
|
||||
data = decodeBase64(base64);
|
||||
} else {
|
||||
[, data] = dataURL.split(',');
|
||||
}
|
||||
|
||||
callback(new Blob([data], { type }));
|
||||
},
|
||||
});
|
||||
}
|
||||
|
|
|
|||
10
app/javascript/mastodon/compare_id.js
Normal file
10
app/javascript/mastodon/compare_id.js
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
export default function compareId(id1, id2) {
|
||||
if (id1 === id2) {
|
||||
return 0;
|
||||
}
|
||||
if (id1.length === id2.length) {
|
||||
return id1 > id2 ? 1 : -1;
|
||||
} else {
|
||||
return id1.length > id2.length ? 1 : -1;
|
||||
}
|
||||
}
|
||||
|
|
@ -84,9 +84,17 @@ export default class AutosuggestTextarea extends ImmutablePureComponent {
|
|||
return;
|
||||
}
|
||||
|
||||
if (e.which === 229 || e.isComposing) {
|
||||
// Ignore key events during text composition
|
||||
// e.key may be a name of the physical key even in this case (e.x. Safari / Chrome on Mac)
|
||||
return;
|
||||
}
|
||||
|
||||
switch(e.key) {
|
||||
case 'Escape':
|
||||
if (!suggestionsHidden) {
|
||||
if (suggestions.size === 0 || suggestionsHidden) {
|
||||
document.querySelector('.ui').parentElement.focus();
|
||||
} else {
|
||||
e.preventDefault();
|
||||
this.setState({ suggestionsHidden: true });
|
||||
}
|
||||
|
|
@ -125,16 +133,6 @@ export default class AutosuggestTextarea extends ImmutablePureComponent {
|
|||
this.props.onKeyDown(e);
|
||||
}
|
||||
|
||||
onKeyUp = e => {
|
||||
if (e.key === 'Escape' && this.state.suggestionsHidden) {
|
||||
document.querySelector('.ui').parentElement.focus();
|
||||
}
|
||||
|
||||
if (this.props.onKeyUp) {
|
||||
this.props.onKeyUp(e);
|
||||
}
|
||||
}
|
||||
|
||||
onBlur = () => {
|
||||
this.setState({ suggestionsHidden: true });
|
||||
}
|
||||
|
|
@ -186,7 +184,7 @@ export default class AutosuggestTextarea extends ImmutablePureComponent {
|
|||
}
|
||||
|
||||
render () {
|
||||
const { value, suggestions, disabled, placeholder, autoFocus } = this.props;
|
||||
const { value, suggestions, disabled, placeholder, onKeyUp, autoFocus } = this.props;
|
||||
const { suggestionsHidden } = this.state;
|
||||
const style = { direction: 'ltr' };
|
||||
|
||||
|
|
@ -208,7 +206,7 @@ export default class AutosuggestTextarea extends ImmutablePureComponent {
|
|||
value={value}
|
||||
onChange={this.onChange}
|
||||
onKeyDown={this.onKeyDown}
|
||||
onKeyUp={this.onKeyUp}
|
||||
onKeyUp={onKeyUp}
|
||||
onBlur={this.onBlur}
|
||||
onPaste={this.onPaste}
|
||||
style={style}
|
||||
|
|
|
|||
|
|
@ -1,22 +0,0 @@
|
|||
import React from 'react';
|
||||
import Motion from '../features/ui/util/optional_motion';
|
||||
import spring from 'react-motion/lib/spring';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
const Collapsable = ({ fullHeight, isVisible, children }) => (
|
||||
<Motion defaultStyle={{ opacity: !isVisible ? 0 : 100, height: isVisible ? fullHeight : 0 }} style={{ opacity: spring(!isVisible ? 0 : 100), height: spring(!isVisible ? 0 : fullHeight) }}>
|
||||
{({ opacity, height }) => (
|
||||
<div style={{ height: `${height}px`, overflow: 'hidden', opacity: opacity / 100, display: Math.floor(opacity) === 0 ? 'none' : 'block' }}>
|
||||
{children}
|
||||
</div>
|
||||
)}
|
||||
</Motion>
|
||||
);
|
||||
|
||||
Collapsable.propTypes = {
|
||||
fullHeight: PropTypes.number.isRequired,
|
||||
isVisible: PropTypes.bool.isRequired,
|
||||
children: PropTypes.node.isRequired,
|
||||
};
|
||||
|
||||
export default Collapsable;
|
||||
42
app/javascript/mastodon/components/domain.js
Normal file
42
app/javascript/mastodon/components/domain.js
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import IconButton from './icon_button';
|
||||
import { defineMessages, injectIntl } from 'react-intl';
|
||||
import ImmutablePureComponent from 'react-immutable-pure-component';
|
||||
|
||||
const messages = defineMessages({
|
||||
unblockDomain: { id: 'account.unblock_domain', defaultMessage: 'Unhide {domain}' },
|
||||
});
|
||||
|
||||
@injectIntl
|
||||
export default class Account extends ImmutablePureComponent {
|
||||
|
||||
static propTypes = {
|
||||
domain: PropTypes.string,
|
||||
onUnblockDomain: PropTypes.func.isRequired,
|
||||
intl: PropTypes.object.isRequired,
|
||||
};
|
||||
|
||||
handleDomainUnblock = () => {
|
||||
this.props.onUnblockDomain(this.props.domain);
|
||||
}
|
||||
|
||||
render () {
|
||||
const { domain, intl } = this.props;
|
||||
|
||||
return (
|
||||
<div className='domain'>
|
||||
<div className='domain__wrapper'>
|
||||
<span className='domain__domain-name'>
|
||||
<strong>{domain}</strong>
|
||||
</span>
|
||||
|
||||
<div className='domain__buttons'>
|
||||
<IconButton active icon='unlock-alt' title={intl.formatMessage(messages.unblockDomain, { domain })} onClick={this.handleDomainUnblock} />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -43,6 +43,7 @@ class DropdownMenu extends React.PureComponent {
|
|||
componentDidMount () {
|
||||
document.addEventListener('click', this.handleDocumentClick, false);
|
||||
document.addEventListener('touchend', this.handleDocumentClick, listenerOptions);
|
||||
if (this.focusedItem) this.focusedItem.focus();
|
||||
this.setState({ mounted: true });
|
||||
}
|
||||
|
||||
|
|
@ -55,6 +56,46 @@ class DropdownMenu extends React.PureComponent {
|
|||
this.node = c;
|
||||
}
|
||||
|
||||
setFocusRef = c => {
|
||||
this.focusedItem = c;
|
||||
}
|
||||
|
||||
handleKeyDown = e => {
|
||||
const items = Array.from(this.node.getElementsByTagName('a'));
|
||||
const index = items.indexOf(e.currentTarget);
|
||||
let element;
|
||||
|
||||
switch(e.key) {
|
||||
case 'Enter':
|
||||
this.handleClick(e);
|
||||
break;
|
||||
case 'ArrowDown':
|
||||
element = items[index+1];
|
||||
if (element) {
|
||||
element.focus();
|
||||
}
|
||||
break;
|
||||
case 'ArrowUp':
|
||||
element = items[index-1];
|
||||
if (element) {
|
||||
element.focus();
|
||||
}
|
||||
break;
|
||||
case 'Home':
|
||||
element = items[0];
|
||||
if (element) {
|
||||
element.focus();
|
||||
}
|
||||
break;
|
||||
case 'End':
|
||||
element = items[items.length-1];
|
||||
if (element) {
|
||||
element.focus();
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
handleClick = e => {
|
||||
const i = Number(e.currentTarget.getAttribute('data-index'));
|
||||
const { action, to } = this.props.items[i];
|
||||
|
|
@ -63,7 +104,7 @@ class DropdownMenu extends React.PureComponent {
|
|||
|
||||
if (typeof action === 'function') {
|
||||
e.preventDefault();
|
||||
action();
|
||||
action(e);
|
||||
} else if (to) {
|
||||
e.preventDefault();
|
||||
this.context.router.history.push(to);
|
||||
|
|
@ -79,7 +120,7 @@ class DropdownMenu extends React.PureComponent {
|
|||
|
||||
return (
|
||||
<li className='dropdown-menu__item' key={`${text}-${i}`}>
|
||||
<a href={href} target='_blank' rel='noopener' role='button' tabIndex='0' autoFocus={i === 0} onClick={this.handleClick} data-index={i}>
|
||||
<a href={href} target='_blank' rel='noopener' role='button' tabIndex='0' ref={i === 0 ? this.setFocusRef : null} onClick={this.handleClick} onKeyDown={this.handleKeyDown} data-index={i}>
|
||||
{text}
|
||||
</a>
|
||||
</li>
|
||||
|
|
@ -156,9 +197,6 @@ export default class Dropdown extends React.PureComponent {
|
|||
|
||||
handleKeyDown = e => {
|
||||
switch(e.key) {
|
||||
case 'Enter':
|
||||
this.handleClick(e);
|
||||
break;
|
||||
case 'Escape':
|
||||
this.handleClose();
|
||||
break;
|
||||
|
|
|
|||
34
app/javascript/mastodon/components/hashtag.js
Normal file
34
app/javascript/mastodon/components/hashtag.js
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
import React from 'react';
|
||||
import { Sparklines, SparklinesCurve } from 'react-sparklines';
|
||||
import { Link } from 'react-router-dom';
|
||||
import { FormattedMessage } from 'react-intl';
|
||||
import ImmutablePropTypes from 'react-immutable-proptypes';
|
||||
import { shortNumberFormat } from '../utils/numbers';
|
||||
|
||||
const Hashtag = ({ hashtag }) => (
|
||||
<div className='trends__item'>
|
||||
<div className='trends__item__name'>
|
||||
<Link to={`/timelines/tag/${hashtag.get('name')}`}>
|
||||
#<span>{hashtag.get('name')}</span>
|
||||
</Link>
|
||||
|
||||
<FormattedMessage id='trends.count_by_accounts' defaultMessage='{count} {rawCount, plural, one {person} other {people}} talking' values={{ rawCount: hashtag.getIn(['history', 0, 'accounts']), count: <strong>{shortNumberFormat(hashtag.getIn(['history', 0, 'accounts']))}</strong> }} />
|
||||
</div>
|
||||
|
||||
<div className='trends__item__current'>
|
||||
{shortNumberFormat(hashtag.getIn(['history', 0, 'uses']))}
|
||||
</div>
|
||||
|
||||
<div className='trends__item__sparkline'>
|
||||
<Sparklines width={50} height={28} data={hashtag.get('history').reverse().map(day => day.get('uses')).toArray()}>
|
||||
<SparklinesCurve style={{ fill: 'none' }} />
|
||||
</Sparklines>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
Hashtag.propTypes = {
|
||||
hashtag: ImmutablePropTypes.map.isRequired,
|
||||
};
|
||||
|
||||
export default Hashtag;
|
||||
33
app/javascript/mastodon/components/load_gap.js
Normal file
33
app/javascript/mastodon/components/load_gap.js
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { injectIntl, defineMessages } from 'react-intl';
|
||||
|
||||
const messages = defineMessages({
|
||||
load_more: { id: 'status.load_more', defaultMessage: 'Load more' },
|
||||
});
|
||||
|
||||
@injectIntl
|
||||
export default class LoadGap extends React.PureComponent {
|
||||
|
||||
static propTypes = {
|
||||
disabled: PropTypes.bool,
|
||||
maxId: PropTypes.string,
|
||||
onClick: PropTypes.func.isRequired,
|
||||
intl: PropTypes.object.isRequired,
|
||||
};
|
||||
|
||||
handleClick = () => {
|
||||
this.props.onClick(this.props.maxId);
|
||||
}
|
||||
|
||||
render () {
|
||||
const { disabled, intl } = this.props;
|
||||
|
||||
return (
|
||||
<button className='load-more load-gap' disabled={disabled} onClick={this.handleClick} aria-label={intl.formatMessage(messages.load_more)}>
|
||||
<i className='fa fa-ellipsis-h' />
|
||||
</button>
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -20,6 +20,7 @@ class Item extends React.PureComponent {
|
|||
index: PropTypes.number.isRequired,
|
||||
size: PropTypes.number.isRequired,
|
||||
onClick: PropTypes.func.isRequired,
|
||||
displayWidth: PropTypes.number,
|
||||
};
|
||||
|
||||
static defaultProps = {
|
||||
|
|
@ -58,7 +59,7 @@ class Item extends React.PureComponent {
|
|||
}
|
||||
|
||||
render () {
|
||||
const { attachment, index, size, standalone } = this.props;
|
||||
const { attachment, index, size, standalone, displayWidth } = this.props;
|
||||
|
||||
let width = 50;
|
||||
let height = 100;
|
||||
|
|
@ -121,7 +122,7 @@ class Item extends React.PureComponent {
|
|||
const hasSize = typeof originalWidth === 'number' && typeof previewWidth === 'number';
|
||||
|
||||
const srcSet = hasSize ? `${originalUrl} ${originalWidth}w, ${previewUrl} ${previewWidth}w` : null;
|
||||
const sizes = hasSize ? `(min-width: 1025px) ${320 * (width / 100)}px, ${width}vw` : null;
|
||||
const sizes = hasSize ? `${displayWidth * (width / 100)}px` : null;
|
||||
|
||||
const focusX = attachment.getIn(['meta', 'focus', 'x']) || 0;
|
||||
const focusY = attachment.getIn(['meta', 'focus', 'y']) || 0;
|
||||
|
|
@ -263,9 +264,9 @@ export default class MediaGallery extends React.PureComponent {
|
|||
const size = media.take(4).size;
|
||||
|
||||
if (this.isStandaloneEligible()) {
|
||||
children = <Item standalone onClick={this.handleClick} attachment={media.get(0)} />;
|
||||
children = <Item standalone onClick={this.handleClick} attachment={media.get(0)} displayWidth={width} />;
|
||||
} else {
|
||||
children = media.take(4).map((attachment, i) => <Item key={attachment.get('id')} onClick={this.handleClick} attachment={attachment} index={i} size={size} />);
|
||||
children = media.take(4).map((attachment, i) => <Item key={attachment.get('id')} onClick={this.handleClick} attachment={attachment} index={i} size={size} displayWidth={width} />);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ const dateFormatOptions = {
|
|||
};
|
||||
|
||||
const shortDateFormatOptions = {
|
||||
month: 'numeric',
|
||||
month: 'short',
|
||||
day: 'numeric',
|
||||
};
|
||||
|
||||
|
|
@ -66,12 +66,17 @@ export default class RelativeTimestamp extends React.Component {
|
|||
static propTypes = {
|
||||
intl: PropTypes.object.isRequired,
|
||||
timestamp: PropTypes.string.isRequired,
|
||||
year: PropTypes.number.isRequired,
|
||||
};
|
||||
|
||||
state = {
|
||||
now: this.props.intl.now(),
|
||||
};
|
||||
|
||||
static defaultProps = {
|
||||
year: (new Date()).getFullYear(),
|
||||
};
|
||||
|
||||
shouldComponentUpdate (nextProps, nextState) {
|
||||
// As of right now the locale doesn't change without a new page load,
|
||||
// but we might as well check in case that ever changes.
|
||||
|
|
@ -114,7 +119,7 @@ export default class RelativeTimestamp extends React.Component {
|
|||
}
|
||||
|
||||
render () {
|
||||
const { timestamp, intl } = this.props;
|
||||
const { timestamp, intl, year } = this.props;
|
||||
|
||||
const date = new Date(timestamp);
|
||||
const delta = this.state.now - date.getTime();
|
||||
|
|
@ -123,7 +128,7 @@ export default class RelativeTimestamp extends React.Component {
|
|||
|
||||
if (delta < 10 * SECOND) {
|
||||
relativeTime = intl.formatMessage(messages.just_now);
|
||||
} else if (delta < 3 * DAY) {
|
||||
} else if (delta < 7 * DAY) {
|
||||
if (delta < MINUTE) {
|
||||
relativeTime = intl.formatMessage(messages.seconds, { number: Math.floor(delta / SECOND) });
|
||||
} else if (delta < HOUR) {
|
||||
|
|
@ -133,8 +138,10 @@ export default class RelativeTimestamp extends React.Component {
|
|||
} else {
|
||||
relativeTime = intl.formatMessage(messages.days, { number: Math.floor(delta / DAY) });
|
||||
}
|
||||
} else {
|
||||
} else if (date.getFullYear() === year) {
|
||||
relativeTime = intl.formatDate(date, shortDateFormatOptions);
|
||||
} else {
|
||||
relativeTime = intl.formatDate(date, { ...shortDateFormatOptions, year: 'numeric' });
|
||||
}
|
||||
|
||||
return (
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@ export default class ScrollableList extends PureComponent {
|
|||
isLoading: PropTypes.bool,
|
||||
hasMore: PropTypes.bool,
|
||||
prepend: PropTypes.node,
|
||||
alwaysPrepend: PropTypes.bool,
|
||||
emptyMessage: PropTypes.node,
|
||||
children: PropTypes.node,
|
||||
};
|
||||
|
|
@ -34,7 +35,7 @@ export default class ScrollableList extends PureComponent {
|
|||
};
|
||||
|
||||
state = {
|
||||
lastMouseMove: null,
|
||||
fullscreen: null,
|
||||
};
|
||||
|
||||
intersectionObserverWrapper = new IntersectionObserverWrapper();
|
||||
|
|
@ -43,7 +44,6 @@ export default class ScrollableList extends PureComponent {
|
|||
if (this.node) {
|
||||
const { scrollTop, scrollHeight, clientHeight } = this.node;
|
||||
const offset = scrollHeight - scrollTop - clientHeight;
|
||||
this._oldScrollPosition = scrollHeight - scrollTop;
|
||||
|
||||
if (400 > offset && this.props.onLoadMore && !this.props.isLoading) {
|
||||
this.props.onLoadMore();
|
||||
|
|
@ -59,14 +59,6 @@ export default class ScrollableList extends PureComponent {
|
|||
trailing: true,
|
||||
});
|
||||
|
||||
handleMouseMove = throttle(() => {
|
||||
this._lastMouseMove = new Date();
|
||||
}, 300);
|
||||
|
||||
handleMouseLeave = () => {
|
||||
this._lastMouseMove = null;
|
||||
}
|
||||
|
||||
componentDidMount () {
|
||||
this.attachScrollListener();
|
||||
this.attachIntersectionObserver();
|
||||
|
|
@ -76,21 +68,26 @@ export default class ScrollableList extends PureComponent {
|
|||
this.handleScroll();
|
||||
}
|
||||
|
||||
componentDidUpdate (prevProps) {
|
||||
getSnapshotBeforeUpdate (prevProps) {
|
||||
const someItemInserted = React.Children.count(prevProps.children) > 0 &&
|
||||
React.Children.count(prevProps.children) < React.Children.count(this.props.children) &&
|
||||
this.getFirstChildKey(prevProps) !== this.getFirstChildKey(this.props);
|
||||
if (someItemInserted && this.node.scrollTop > 0) {
|
||||
return this.node.scrollHeight - this.node.scrollTop;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
componentDidUpdate (prevProps, prevState, snapshot) {
|
||||
// Reset the scroll position when a new child comes in in order not to
|
||||
// jerk the scrollbar around if you're already scrolled down the page.
|
||||
if (someItemInserted && this._oldScrollPosition && this.node.scrollTop > 0) {
|
||||
const newScrollTop = this.node.scrollHeight - this._oldScrollPosition;
|
||||
if (snapshot !== null) {
|
||||
const newScrollTop = this.node.scrollHeight - snapshot;
|
||||
|
||||
if (this.node.scrollTop !== newScrollTop) {
|
||||
this.node.scrollTop = newScrollTop;
|
||||
}
|
||||
} else {
|
||||
this._oldScrollPosition = this.node.scrollHeight - this.node.scrollTop;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -143,12 +140,8 @@ export default class ScrollableList extends PureComponent {
|
|||
this.props.onLoadMore();
|
||||
}
|
||||
|
||||
_recentlyMoved () {
|
||||
return this._lastMouseMove !== null && ((new Date()) - this._lastMouseMove < 600);
|
||||
}
|
||||
|
||||
render () {
|
||||
const { children, scrollKey, trackScroll, shouldUpdateScroll, isLoading, hasMore, prepend, emptyMessage, onLoadMore } = this.props;
|
||||
const { children, scrollKey, trackScroll, shouldUpdateScroll, isLoading, hasMore, prepend, alwaysPrepend, emptyMessage, onLoadMore } = this.props;
|
||||
const { fullscreen } = this.state;
|
||||
const childrenCount = React.Children.count(children);
|
||||
|
||||
|
|
@ -157,7 +150,7 @@ export default class ScrollableList extends PureComponent {
|
|||
|
||||
if (isLoading || childrenCount > 0 || !emptyMessage) {
|
||||
scrollableArea = (
|
||||
<div className={classNames('scrollable', { fullscreen })} ref={this.setRef} onMouseMove={this.handleMouseMove} onMouseLeave={this.handleMouseLeave}>
|
||||
<div className={classNames('scrollable', { fullscreen })} ref={this.setRef}>
|
||||
<div role='feed' className='item-list'>
|
||||
{prepend}
|
||||
|
||||
|
|
@ -180,8 +173,12 @@ export default class ScrollableList extends PureComponent {
|
|||
);
|
||||
} else {
|
||||
scrollableArea = (
|
||||
<div className='empty-column-indicator' ref={this.setRef}>
|
||||
{emptyMessage}
|
||||
<div style={{ flex: '1 1 auto', display: 'flex', flexDirection: 'column' }}>
|
||||
{alwaysPrepend && prepend}
|
||||
|
||||
<div className='empty-column-indicator' ref={this.setRef}>
|
||||
{emptyMessage}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -31,6 +31,8 @@ export default class Status extends ImmutablePureComponent {
|
|||
onFavourite: PropTypes.func,
|
||||
onReblog: PropTypes.func,
|
||||
onDelete: PropTypes.func,
|
||||
onDirect: PropTypes.func,
|
||||
onMention: PropTypes.func,
|
||||
onPin: PropTypes.func,
|
||||
onOpenMedia: PropTypes.func,
|
||||
onOpenVideo: PropTypes.func,
|
||||
|
|
@ -82,8 +84,8 @@ export default class Status extends ImmutablePureComponent {
|
|||
return <div className='media-spoiler-video' style={{ height: '110px' }} />;
|
||||
}
|
||||
|
||||
handleOpenVideo = startTime => {
|
||||
this.props.onOpenVideo(this._properStatus().getIn(['media_attachments', 0]), startTime);
|
||||
handleOpenVideo = (media, startTime) => {
|
||||
this.props.onOpenVideo(media, startTime);
|
||||
}
|
||||
|
||||
handleHotkeyReply = e => {
|
||||
|
|
@ -112,12 +114,16 @@ export default class Status extends ImmutablePureComponent {
|
|||
this.context.router.history.push(`/accounts/${this._properStatus().getIn(['account', 'id'])}`);
|
||||
}
|
||||
|
||||
handleHotkeyMoveUp = () => {
|
||||
this.props.onMoveUp(this.props.status.get('id'));
|
||||
handleHotkeyMoveUp = e => {
|
||||
this.props.onMoveUp(this.props.status.get('id'), e.target.getAttribute('data-featured'));
|
||||
}
|
||||
|
||||
handleHotkeyMoveDown = () => {
|
||||
this.props.onMoveDown(this.props.status.get('id'));
|
||||
handleHotkeyMoveDown = e => {
|
||||
this.props.onMoveDown(this.props.status.get('id'), e.target.getAttribute('data-featured'));
|
||||
}
|
||||
|
||||
handleHotkeyToggleHidden = () => {
|
||||
this.props.onToggleHidden(this._properStatus());
|
||||
}
|
||||
|
||||
_properStatus () {
|
||||
|
|
@ -200,7 +206,7 @@ export default class Status extends ImmutablePureComponent {
|
|||
);
|
||||
} else {
|
||||
media = (
|
||||
<Bundle fetchComponent={MediaGallery} loading={this.renderLoadingMediaGallery} >
|
||||
<Bundle fetchComponent={MediaGallery} loading={this.renderLoadingMediaGallery}>
|
||||
{Component => <Component media={status.get('media_attachments')} sensitive={status.get('sensitive')} height={110} onOpenMedia={this.props.onOpenMedia} />}
|
||||
</Bundle>
|
||||
);
|
||||
|
|
@ -222,11 +228,12 @@ export default class Status extends ImmutablePureComponent {
|
|||
openProfile: this.handleHotkeyOpenProfile,
|
||||
moveUp: this.handleHotkeyMoveUp,
|
||||
moveDown: this.handleHotkeyMoveDown,
|
||||
toggleHidden: this.handleHotkeyToggleHidden,
|
||||
};
|
||||
|
||||
return (
|
||||
<HotKeys handlers={handlers}>
|
||||
<div className={classNames('status__wrapper', `status__wrapper-${status.get('visibility')}`, { focusable: !this.props.muted })} tabIndex={this.props.muted ? null : 0}>
|
||||
<div className={classNames('status__wrapper', `status__wrapper-${status.get('visibility')}`, { focusable: !this.props.muted })} tabIndex={this.props.muted ? null : 0} data-featured={featured ? 'true' : null}>
|
||||
{prepend}
|
||||
|
||||
<div className={classNames('status', `status-${status.get('visibility')}`, { muted: this.props.muted })} data-id={status.get('id')}>
|
||||
|
|
|
|||
|
|
@ -9,6 +9,8 @@ import { me } from '../initial_state';
|
|||
|
||||
const messages = defineMessages({
|
||||
delete: { id: 'status.delete', defaultMessage: 'Delete' },
|
||||
redraft: { id: 'status.redraft', defaultMessage: 'Delete & re-draft' },
|
||||
direct: { id: 'status.direct', defaultMessage: 'Direct message @{name}' },
|
||||
mention: { id: 'status.mention', defaultMessage: 'Mention @{name}' },
|
||||
mute: { id: 'account.mute', defaultMessage: 'Mute @{name}' },
|
||||
block: { id: 'account.block', defaultMessage: 'Block @{name}' },
|
||||
|
|
@ -17,6 +19,8 @@ const messages = defineMessages({
|
|||
more: { id: 'status.more', defaultMessage: 'More' },
|
||||
replyAll: { id: 'status.replyAll', defaultMessage: 'Reply to thread' },
|
||||
reblog: { id: 'status.reblog', defaultMessage: 'Boost' },
|
||||
reblog_private: { id: 'status.reblog_private', defaultMessage: 'Boost to original audience' },
|
||||
cancel_reblog_private: { id: 'status.cancel_reblog_private', defaultMessage: 'Unboost' },
|
||||
cannot_reblog: { id: 'status.cannot_reblog', defaultMessage: 'This post cannot be boosted' },
|
||||
favourite: { id: 'status.favourite', defaultMessage: 'Favourite' },
|
||||
open: { id: 'status.open', defaultMessage: 'Expand this status' },
|
||||
|
|
@ -41,6 +45,7 @@ export default class StatusActionBar extends ImmutablePureComponent {
|
|||
onFavourite: PropTypes.func,
|
||||
onReblog: PropTypes.func,
|
||||
onDelete: PropTypes.func,
|
||||
onDirect: PropTypes.func,
|
||||
onMention: PropTypes.func,
|
||||
onMute: PropTypes.func,
|
||||
onBlock: PropTypes.func,
|
||||
|
|
@ -67,6 +72,8 @@ export default class StatusActionBar extends ImmutablePureComponent {
|
|||
navigator.share({
|
||||
text: this.props.status.get('search_index'),
|
||||
url: this.props.status.get('url'),
|
||||
}).catch((e) => {
|
||||
if (e.name !== 'AbortError') console.error(e);
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -82,6 +89,10 @@ export default class StatusActionBar extends ImmutablePureComponent {
|
|||
this.props.onDelete(this.props.status);
|
||||
}
|
||||
|
||||
handleRedraftClick = () => {
|
||||
this.props.onDelete(this.props.status, true);
|
||||
}
|
||||
|
||||
handlePinClick = () => {
|
||||
this.props.onPin(this.props.status);
|
||||
}
|
||||
|
|
@ -90,6 +101,10 @@ export default class StatusActionBar extends ImmutablePureComponent {
|
|||
this.props.onMention(this.props.status.get('account'), this.context.router.history);
|
||||
}
|
||||
|
||||
handleDirectClick = () => {
|
||||
this.props.onDirect(this.props.status.get('account'), this.context.router.history);
|
||||
}
|
||||
|
||||
handleMuteClick = () => {
|
||||
this.props.onMute(this.props.status.get('account'));
|
||||
}
|
||||
|
|
@ -142,11 +157,17 @@ export default class StatusActionBar extends ImmutablePureComponent {
|
|||
if (status.getIn(['account', 'id']) === me) {
|
||||
if (publicStatus) {
|
||||
menu.push({ text: intl.formatMessage(status.get('pinned') ? messages.unpin : messages.pin), action: this.handlePinClick });
|
||||
} else {
|
||||
if (status.get('visibility') === 'private') {
|
||||
menu.push({ text: intl.formatMessage(status.get('reblogged') ? messages.cancel_reblog_private : messages.reblog_private), action: this.handleReblogClick });
|
||||
}
|
||||
}
|
||||
|
||||
menu.push({ text: intl.formatMessage(messages.delete), action: this.handleDeleteClick });
|
||||
menu.push({ text: intl.formatMessage(messages.redraft), action: this.handleRedraftClick });
|
||||
} else {
|
||||
menu.push({ text: intl.formatMessage(messages.mention, { name: status.getIn(['account', 'username']) }), action: this.handleMentionClick });
|
||||
menu.push({ text: intl.formatMessage(messages.direct, { name: status.getIn(['account', 'username']) }), action: this.handleDirectClick });
|
||||
menu.push(null);
|
||||
menu.push({ text: intl.formatMessage(messages.mute, { name: status.getIn(['account', 'username']) }), action: this.handleMuteClick });
|
||||
menu.push({ text: intl.formatMessage(messages.block, { name: status.getIn(['account', 'username']) }), action: this.handleBlockClick });
|
||||
|
|
|
|||
|
|
@ -4,28 +4,10 @@ import ImmutablePropTypes from 'react-immutable-proptypes';
|
|||
import PropTypes from 'prop-types';
|
||||
import StatusContainer from '../containers/status_container';
|
||||
import ImmutablePureComponent from 'react-immutable-pure-component';
|
||||
import LoadMore from './load_more';
|
||||
import LoadGap from './load_gap';
|
||||
import ScrollableList from './scrollable_list';
|
||||
import { FormattedMessage } from 'react-intl';
|
||||
|
||||
class LoadGap extends ImmutablePureComponent {
|
||||
|
||||
static propTypes = {
|
||||
disabled: PropTypes.bool,
|
||||
maxId: PropTypes.string,
|
||||
onClick: PropTypes.func.isRequired,
|
||||
};
|
||||
|
||||
handleClick = () => {
|
||||
this.props.onClick(this.props.maxId);
|
||||
}
|
||||
|
||||
render () {
|
||||
return <LoadMore onClick={this.handleClick} disabled={this.props.disabled} />;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default class StatusList extends ImmutablePureComponent {
|
||||
|
||||
static propTypes = {
|
||||
|
|
@ -42,19 +24,32 @@ export default class StatusList extends ImmutablePureComponent {
|
|||
hasMore: PropTypes.bool,
|
||||
prepend: PropTypes.node,
|
||||
emptyMessage: PropTypes.node,
|
||||
alwaysPrepend: PropTypes.bool,
|
||||
};
|
||||
|
||||
static defaultProps = {
|
||||
trackScroll: true,
|
||||
};
|
||||
|
||||
handleMoveUp = id => {
|
||||
const elementIndex = this.props.statusIds.indexOf(id) - 1;
|
||||
getFeaturedStatusCount = () => {
|
||||
return this.props.featuredStatusIds ? this.props.featuredStatusIds.size : 0;
|
||||
}
|
||||
|
||||
getCurrentStatusIndex = (id, featured) => {
|
||||
if (featured) {
|
||||
return this.props.featuredStatusIds.indexOf(id);
|
||||
} else {
|
||||
return this.props.statusIds.indexOf(id) + this.getFeaturedStatusCount();
|
||||
}
|
||||
}
|
||||
|
||||
handleMoveUp = (id, featured) => {
|
||||
const elementIndex = this.getCurrentStatusIndex(id, featured) - 1;
|
||||
this._selectChild(elementIndex);
|
||||
}
|
||||
|
||||
handleMoveDown = id => {
|
||||
const elementIndex = this.props.statusIds.indexOf(id) + 1;
|
||||
handleMoveDown = (id, featured) => {
|
||||
const elementIndex = this.getCurrentStatusIndex(id, featured) + 1;
|
||||
this._selectChild(elementIndex);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,18 +0,0 @@
|
|||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import Card from '../features/status/components/card';
|
||||
import { fromJS } from 'immutable';
|
||||
|
||||
export default class CardContainer extends React.PureComponent {
|
||||
|
||||
static propTypes = {
|
||||
locale: PropTypes.string,
|
||||
card: PropTypes.array.isRequired,
|
||||
};
|
||||
|
||||
render () {
|
||||
const { card, ...props } = this.props;
|
||||
return <Card card={fromJS(card)} {...props} />;
|
||||
}
|
||||
|
||||
}
|
||||
33
app/javascript/mastodon/containers/domain_container.js
Normal file
33
app/javascript/mastodon/containers/domain_container.js
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
import React from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
import { blockDomain, unblockDomain } from '../actions/domain_blocks';
|
||||
import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
|
||||
import Domain from '../components/domain';
|
||||
import { openModal } from '../actions/modal';
|
||||
|
||||
const messages = defineMessages({
|
||||
blockDomainConfirm: { id: 'confirmations.domain_block.confirm', defaultMessage: 'Hide entire domain' },
|
||||
});
|
||||
|
||||
const makeMapStateToProps = () => {
|
||||
const mapStateToProps = (state, { }) => ({
|
||||
});
|
||||
|
||||
return mapStateToProps;
|
||||
};
|
||||
|
||||
const mapDispatchToProps = (dispatch, { intl }) => ({
|
||||
onBlockDomain (domain) {
|
||||
dispatch(openModal('CONFIRM', {
|
||||
message: <FormattedMessage id='confirmations.domain_block.message' defaultMessage='Are you really, really sure you want to block the entire {domain}? In most cases a few targeted blocks or mutes are sufficient and preferable.' values={{ domain: <strong>{domain}</strong> }} />,
|
||||
confirm: intl.formatMessage(messages.blockDomainConfirm),
|
||||
onConfirm: () => dispatch(blockDomain(domain)),
|
||||
}));
|
||||
},
|
||||
|
||||
onUnblockDomain (domain) {
|
||||
dispatch(unblockDomain(domain));
|
||||
},
|
||||
});
|
||||
|
||||
export default injectIntl(connect(makeMapStateToProps, mapDispatchToProps)(Domain));
|
||||
|
|
@ -6,6 +6,7 @@ import { showOnboardingOnce } from '../actions/onboarding';
|
|||
import { BrowserRouter, Route } from 'react-router-dom';
|
||||
import { ScrollContext } from 'react-router-scroll-4';
|
||||
import UI from '../features/ui';
|
||||
import { fetchCustomEmojis } from '../actions/custom_emojis';
|
||||
import { hydrateStore } from '../actions/store';
|
||||
import { connectUserStream } from '../actions/streaming';
|
||||
import { IntlProvider, addLocaleData } from 'react-intl';
|
||||
|
|
@ -19,6 +20,9 @@ export const store = configureStore();
|
|||
const hydrateAction = hydrateStore(initialState);
|
||||
store.dispatch(hydrateAction);
|
||||
|
||||
// load custom emojis
|
||||
store.dispatch(fetchCustomEmojis());
|
||||
|
||||
export default class Mastodon extends React.PureComponent {
|
||||
|
||||
static propTypes = {
|
||||
|
|
|
|||
90
app/javascript/mastodon/containers/media_container.js
Normal file
90
app/javascript/mastodon/containers/media_container.js
Normal file
|
|
@ -0,0 +1,90 @@
|
|||
import React, { PureComponent, Fragment } from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
import PropTypes from 'prop-types';
|
||||
import { IntlProvider, addLocaleData } from 'react-intl';
|
||||
import { getLocale } from '../locales';
|
||||
import MediaGallery from '../components/media_gallery';
|
||||
import Video from '../features/video';
|
||||
import Card from '../features/status/components/card';
|
||||
import ModalRoot from '../components/modal_root';
|
||||
import MediaModal from '../features/ui/components/media_modal';
|
||||
import { List as ImmutableList, fromJS } from 'immutable';
|
||||
|
||||
const { localeData, messages } = getLocale();
|
||||
addLocaleData(localeData);
|
||||
|
||||
const MEDIA_COMPONENTS = { MediaGallery, Video, Card };
|
||||
|
||||
export default class MediaContainer extends PureComponent {
|
||||
|
||||
static propTypes = {
|
||||
locale: PropTypes.string.isRequired,
|
||||
components: PropTypes.object.isRequired,
|
||||
};
|
||||
|
||||
state = {
|
||||
media: null,
|
||||
index: null,
|
||||
time: null,
|
||||
};
|
||||
|
||||
handleOpenMedia = (media, index) => {
|
||||
document.body.classList.add('media-standalone__body');
|
||||
this.setState({ media, index });
|
||||
}
|
||||
|
||||
handleOpenVideo = (video, time) => {
|
||||
const media = ImmutableList([video]);
|
||||
|
||||
document.body.classList.add('media-standalone__body');
|
||||
this.setState({ media, time });
|
||||
}
|
||||
|
||||
handleCloseMedia = () => {
|
||||
document.body.classList.remove('media-standalone__body');
|
||||
this.setState({ media: null, index: null, time: null });
|
||||
}
|
||||
|
||||
render () {
|
||||
const { locale, components } = this.props;
|
||||
|
||||
return (
|
||||
<IntlProvider locale={locale} messages={messages}>
|
||||
<Fragment>
|
||||
{[].map.call(components, (component, i) => {
|
||||
const componentName = component.getAttribute('data-component');
|
||||
const Component = MEDIA_COMPONENTS[componentName];
|
||||
const { media, card, ...props } = JSON.parse(component.getAttribute('data-props'));
|
||||
|
||||
Object.assign(props, {
|
||||
...(media ? { media: fromJS(media) } : {}),
|
||||
...(card ? { card: fromJS(card) } : {}),
|
||||
|
||||
...(componentName === 'Video' ? {
|
||||
onOpenVideo: this.handleOpenVideo,
|
||||
} : {
|
||||
onOpenMedia: this.handleOpenMedia,
|
||||
}),
|
||||
});
|
||||
|
||||
return ReactDOM.createPortal(
|
||||
<Component {...props} key={`media-${i}`} />,
|
||||
component,
|
||||
);
|
||||
})}
|
||||
<ModalRoot onClose={this.handleCloseMedia}>
|
||||
{this.state.media && (
|
||||
<MediaModal
|
||||
media={this.state.media}
|
||||
index={this.state.index || 0}
|
||||
time={this.state.time}
|
||||
onClose={this.handleCloseMedia}
|
||||
/>
|
||||
)}
|
||||
</ModalRoot>
|
||||
</Fragment>
|
||||
</IntlProvider>
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,68 +0,0 @@
|
|||
import React from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
import PropTypes from 'prop-types';
|
||||
import { IntlProvider, addLocaleData } from 'react-intl';
|
||||
import { getLocale } from '../locales';
|
||||
import MediaGallery from '../components/media_gallery';
|
||||
import ModalRoot from '../components/modal_root';
|
||||
import MediaModal from '../features/ui/components/media_modal';
|
||||
import { fromJS } from 'immutable';
|
||||
|
||||
const { localeData, messages } = getLocale();
|
||||
addLocaleData(localeData);
|
||||
|
||||
export default class MediaGalleriesContainer extends React.PureComponent {
|
||||
|
||||
static propTypes = {
|
||||
locale: PropTypes.string.isRequired,
|
||||
galleries: PropTypes.object.isRequired,
|
||||
};
|
||||
|
||||
state = {
|
||||
media: null,
|
||||
index: null,
|
||||
};
|
||||
|
||||
handleOpenMedia = (media, index) => {
|
||||
document.body.classList.add('media-gallery-standalone__body');
|
||||
this.setState({ media, index });
|
||||
}
|
||||
|
||||
handleCloseMedia = () => {
|
||||
document.body.classList.remove('media-gallery-standalone__body');
|
||||
this.setState({ media: null, index: null });
|
||||
}
|
||||
|
||||
render () {
|
||||
const { locale, galleries } = this.props;
|
||||
|
||||
return (
|
||||
<IntlProvider locale={locale} messages={messages}>
|
||||
<React.Fragment>
|
||||
{[].map.call(galleries, gallery => {
|
||||
const { media, ...props } = JSON.parse(gallery.getAttribute('data-props'));
|
||||
|
||||
return ReactDOM.createPortal(
|
||||
<MediaGallery
|
||||
{...props}
|
||||
media={fromJS(media)}
|
||||
onOpenMedia={this.handleOpenMedia}
|
||||
/>,
|
||||
gallery
|
||||
);
|
||||
})}
|
||||
<ModalRoot onClose={this.handleCloseMedia}>
|
||||
{this.state.media === null || this.state.index === null ? null : (
|
||||
<MediaModal
|
||||
media={this.state.media}
|
||||
index={this.state.index}
|
||||
onClose={this.handleCloseMedia}
|
||||
/>
|
||||
)}
|
||||
</ModalRoot>
|
||||
</React.Fragment>
|
||||
</IntlProvider>
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -5,6 +5,7 @@ import { makeGetStatus } from '../selectors';
|
|||
import {
|
||||
replyCompose,
|
||||
mentionCompose,
|
||||
directCompose,
|
||||
} from '../actions/compose';
|
||||
import {
|
||||
reblog,
|
||||
|
|
@ -27,10 +28,13 @@ import { initReport } from '../actions/reports';
|
|||
import { openModal } from '../actions/modal';
|
||||
import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
|
||||
import { boostModal, deleteModal } from '../initial_state';
|
||||
import { showAlertForError } from '../actions/alerts';
|
||||
|
||||
const messages = defineMessages({
|
||||
deleteConfirm: { id: 'confirmations.delete.confirm', defaultMessage: 'Delete' },
|
||||
deleteMessage: { id: 'confirmations.delete.message', defaultMessage: 'Are you sure you want to delete this status?' },
|
||||
redraftConfirm: { id: 'confirmations.redraft.confirm', defaultMessage: 'Delete & redraft' },
|
||||
redraftMessage: { id: 'confirmations.redraft.message', defaultMessage: 'Are you sure you want to delete this status and re-draft it? You will lose all replies, boosts and favourites to it.' },
|
||||
blockConfirm: { id: 'confirmations.block.confirm', defaultMessage: 'Block' },
|
||||
});
|
||||
|
||||
|
|
@ -83,21 +87,28 @@ const mapDispatchToProps = (dispatch, { intl }) => ({
|
|||
},
|
||||
|
||||
onEmbed (status) {
|
||||
dispatch(openModal('EMBED', { url: status.get('url') }));
|
||||
dispatch(openModal('EMBED', {
|
||||
url: status.get('url'),
|
||||
onError: error => dispatch(showAlertForError(error)),
|
||||
}));
|
||||
},
|
||||
|
||||
onDelete (status) {
|
||||
onDelete (status, withRedraft = false) {
|
||||
if (!deleteModal) {
|
||||
dispatch(deleteStatus(status.get('id')));
|
||||
dispatch(deleteStatus(status.get('id'), withRedraft));
|
||||
} else {
|
||||
dispatch(openModal('CONFIRM', {
|
||||
message: intl.formatMessage(messages.deleteMessage),
|
||||
confirm: intl.formatMessage(messages.deleteConfirm),
|
||||
onConfirm: () => dispatch(deleteStatus(status.get('id'))),
|
||||
message: intl.formatMessage(withRedraft ? messages.redraftMessage : messages.deleteMessage),
|
||||
confirm: intl.formatMessage(withRedraft ? messages.redraftConfirm : messages.deleteConfirm),
|
||||
onConfirm: () => dispatch(deleteStatus(status.get('id'), withRedraft)),
|
||||
}));
|
||||
}
|
||||
},
|
||||
|
||||
onDirect (account, router) {
|
||||
dispatch(directCompose(account, router));
|
||||
},
|
||||
|
||||
onMention (account, router) {
|
||||
dispatch(mentionCompose(account, router));
|
||||
},
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
import React from 'react';
|
||||
import React, { Fragment } from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
import { Provider } from 'react-redux';
|
||||
import PropTypes from 'prop-types';
|
||||
import configureStore from '../store/configureStore';
|
||||
|
|
@ -8,6 +9,7 @@ import { getLocale } from '../locales';
|
|||
import PublicTimeline from '../features/standalone/public_timeline';
|
||||
import CommunityTimeline from '../features/standalone/community_timeline';
|
||||
import HashtagTimeline from '../features/standalone/hashtag_timeline';
|
||||
import ModalContainer from '../features/ui/containers/modal_container';
|
||||
import initialState from '../initial_state';
|
||||
|
||||
const { localeData, messages } = getLocale();
|
||||
|
|
@ -47,7 +49,13 @@ export default class TimelineContainer extends React.PureComponent {
|
|||
return (
|
||||
<IntlProvider locale={locale} messages={messages}>
|
||||
<Provider store={store}>
|
||||
{timeline}
|
||||
<Fragment>
|
||||
{timeline}
|
||||
{ReactDOM.createPortal(
|
||||
<ModalContainer />,
|
||||
document.getElementById('modal-container'),
|
||||
)}
|
||||
</Fragment>
|
||||
</Provider>
|
||||
</IntlProvider>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -1,26 +0,0 @@
|
|||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { IntlProvider, addLocaleData } from 'react-intl';
|
||||
import { getLocale } from '../locales';
|
||||
import Video from '../features/video';
|
||||
|
||||
const { localeData, messages } = getLocale();
|
||||
addLocaleData(localeData);
|
||||
|
||||
export default class VideoContainer extends React.PureComponent {
|
||||
|
||||
static propTypes = {
|
||||
locale: PropTypes.string.isRequired,
|
||||
};
|
||||
|
||||
render () {
|
||||
const { locale, ...props } = this.props;
|
||||
|
||||
return (
|
||||
<IntlProvider locale={locale} messages={messages}>
|
||||
<Video {...props} />
|
||||
</IntlProvider>
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,93 +0,0 @@
|
|||
import asyncDB from './async';
|
||||
|
||||
const limit = 1024;
|
||||
|
||||
function put(name, objects, callback) {
|
||||
asyncDB.then(db => {
|
||||
const putTransaction = db.transaction(name, 'readwrite');
|
||||
const putStore = putTransaction.objectStore(name);
|
||||
const putIndex = putStore.index('id');
|
||||
|
||||
objects.forEach(object => {
|
||||
function add() {
|
||||
putStore.add(object);
|
||||
}
|
||||
|
||||
putIndex.getKey(object.id).onsuccess = retrieval => {
|
||||
if (retrieval.target.result) {
|
||||
putStore.delete(retrieval.target.result).onsuccess = add;
|
||||
} else {
|
||||
add();
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
putTransaction.oncomplete = () => {
|
||||
const readTransaction = db.transaction(name, 'readonly');
|
||||
const readStore = readTransaction.objectStore(name);
|
||||
|
||||
readStore.count().onsuccess = count => {
|
||||
const excess = count.target.result - limit;
|
||||
|
||||
if (excess > 0) {
|
||||
readStore.getAll(null, excess).onsuccess =
|
||||
retrieval => callback(retrieval.target.result.map(({ id }) => id));
|
||||
}
|
||||
};
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
export function evictAccounts(ids) {
|
||||
asyncDB.then(db => {
|
||||
const transaction = db.transaction(['accounts', 'statuses'], 'readwrite');
|
||||
const accounts = transaction.objectStore('accounts');
|
||||
const accountsIdIndex = accounts.index('id');
|
||||
const accountsMovedIndex = accounts.index('moved');
|
||||
const statuses = transaction.objectStore('statuses');
|
||||
const statusesIndex = statuses.index('account');
|
||||
|
||||
function evict(toEvict) {
|
||||
toEvict.forEach(id => {
|
||||
accountsMovedIndex.getAllKeys(id).onsuccess =
|
||||
({ target }) => evict(target.result);
|
||||
|
||||
statusesIndex.getAll(id).onsuccess =
|
||||
({ target }) => evictStatuses(target.result.map(({ id }) => id));
|
||||
|
||||
accountsIdIndex.getKey(id).onsuccess =
|
||||
({ target }) => target.result && accounts.delete(target.result);
|
||||
});
|
||||
}
|
||||
|
||||
evict(ids);
|
||||
});
|
||||
}
|
||||
|
||||
export function evictStatus(id) {
|
||||
return evictStatuses([id]);
|
||||
}
|
||||
|
||||
export function evictStatuses(ids) {
|
||||
asyncDB.then(db => {
|
||||
const store = db.transaction('statuses', 'readwrite').objectStore('statuses');
|
||||
const idIndex = store.index('id');
|
||||
const reblogIndex = store.index('reblog');
|
||||
|
||||
ids.forEach(id => {
|
||||
reblogIndex.getAllKeys(id).onsuccess =
|
||||
({ target }) => target.result.forEach(reblogKey => store.delete(reblogKey));
|
||||
|
||||
idIndex.getKey(id).onsuccess =
|
||||
({ target }) => target.result && store.delete(target.result);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
export function putAccounts(records) {
|
||||
put('accounts', records, evictAccounts);
|
||||
}
|
||||
|
||||
export function putStatuses(records) {
|
||||
put('statuses', records, evictStatuses);
|
||||
}
|
||||
|
|
@ -3,11 +3,13 @@ import ImmutablePropTypes from 'react-immutable-proptypes';
|
|||
import PropTypes from 'prop-types';
|
||||
import DropdownMenuContainer from '../../../containers/dropdown_menu_container';
|
||||
import { Link } from 'react-router-dom';
|
||||
import { defineMessages, injectIntl, FormattedMessage, FormattedNumber } from 'react-intl';
|
||||
import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
|
||||
import { me } from '../../../initial_state';
|
||||
import { shortNumberFormat } from '../../../utils/numbers';
|
||||
|
||||
const messages = defineMessages({
|
||||
mention: { id: 'account.mention', defaultMessage: 'Mention @{name}' },
|
||||
direct: { id: 'account.direct', defaultMessage: 'Direct message @{name}' },
|
||||
edit_profile: { id: 'account.edit_profile', defaultMessage: 'Edit profile' },
|
||||
unblock: { id: 'account.unblock', defaultMessage: 'Unblock @{name}' },
|
||||
unfollow: { id: 'account.unfollow', defaultMessage: 'Unfollow' },
|
||||
|
|
@ -22,6 +24,14 @@ const messages = defineMessages({
|
|||
unblockDomain: { id: 'account.unblock_domain', defaultMessage: 'Unhide {domain}' },
|
||||
hideReblogs: { id: 'account.hide_reblogs', defaultMessage: 'Hide boosts from @{name}' },
|
||||
showReblogs: { id: 'account.show_reblogs', defaultMessage: 'Show boosts from @{name}' },
|
||||
pins: { id: 'navigation_bar.pins', defaultMessage: 'Pinned toots' },
|
||||
preferences: { id: 'navigation_bar.preferences', defaultMessage: 'Preferences' },
|
||||
follow_requests: { id: 'navigation_bar.follow_requests', defaultMessage: 'Follow requests' },
|
||||
favourites: { id: 'navigation_bar.favourites', defaultMessage: 'Favourites' },
|
||||
lists: { id: 'navigation_bar.lists', defaultMessage: 'Lists' },
|
||||
blocks: { id: 'navigation_bar.blocks', defaultMessage: 'Blocked users' },
|
||||
domain_blocks: { id: 'navigation_bar.domain_blocks', defaultMessage: 'Hidden domains' },
|
||||
mutes: { id: 'navigation_bar.mutes', defaultMessage: 'Muted users' },
|
||||
});
|
||||
|
||||
@injectIntl
|
||||
|
|
@ -32,6 +42,7 @@ export default class ActionBar extends React.PureComponent {
|
|||
onFollow: PropTypes.func,
|
||||
onBlock: PropTypes.func.isRequired,
|
||||
onMention: PropTypes.func.isRequired,
|
||||
onDirect: PropTypes.func.isRequired,
|
||||
onReblogToggle: PropTypes.func.isRequired,
|
||||
onReport: PropTypes.func.isRequired,
|
||||
onMute: PropTypes.func.isRequired,
|
||||
|
|
@ -52,16 +63,29 @@ export default class ActionBar extends React.PureComponent {
|
|||
let menu = [];
|
||||
let extraInfo = '';
|
||||
|
||||
menu.push({ text: intl.formatMessage(messages.mention, { name: account.get('username') }), action: this.props.onMention });
|
||||
if (account.get('id') !== me) {
|
||||
menu.push({ text: intl.formatMessage(messages.mention, { name: account.get('username') }), action: this.props.onMention });
|
||||
menu.push({ text: intl.formatMessage(messages.direct, { name: account.get('username') }), action: this.props.onDirect });
|
||||
menu.push(null);
|
||||
}
|
||||
|
||||
if ('share' in navigator) {
|
||||
menu.push({ text: intl.formatMessage(messages.share, { name: account.get('username') }), action: this.handleShare });
|
||||
menu.push(null);
|
||||
}
|
||||
|
||||
menu.push(null);
|
||||
|
||||
if (account.get('id') === me) {
|
||||
menu.push({ text: intl.formatMessage(messages.edit_profile), href: '/settings/profile' });
|
||||
menu.push({ text: intl.formatMessage(messages.preferences), href: '/settings/preferences' });
|
||||
menu.push({ text: intl.formatMessage(messages.pins), to: '/pinned' });
|
||||
menu.push(null);
|
||||
menu.push({ text: intl.formatMessage(messages.follow_requests), to: '/follow_requests' });
|
||||
menu.push({ text: intl.formatMessage(messages.favourites), to: '/favourites' });
|
||||
menu.push({ text: intl.formatMessage(messages.lists), to: '/lists' });
|
||||
menu.push(null);
|
||||
menu.push({ text: intl.formatMessage(messages.mutes), to: '/mutes' });
|
||||
menu.push({ text: intl.formatMessage(messages.blocks), to: '/blocks' });
|
||||
menu.push({ text: intl.formatMessage(messages.domain_blocks), to: '/domain_blocks' });
|
||||
} else {
|
||||
if (account.getIn(['relationship', 'following'])) {
|
||||
if (account.getIn(['relationship', 'showing_reblogs'])) {
|
||||
|
|
@ -123,17 +147,17 @@ export default class ActionBar extends React.PureComponent {
|
|||
<div className='account__action-bar-links'>
|
||||
<Link className='account__action-bar__tab' to={`/accounts/${account.get('id')}`}>
|
||||
<span><FormattedMessage id='account.posts' defaultMessage='Toots' /></span>
|
||||
<strong><FormattedNumber value={account.get('statuses_count')} /></strong>
|
||||
<strong>{shortNumberFormat(account.get('statuses_count'))}</strong>
|
||||
</Link>
|
||||
|
||||
<Link className='account__action-bar__tab' to={`/accounts/${account.get('id')}/following`}>
|
||||
<span><FormattedMessage id='account.follows' defaultMessage='Follows' /></span>
|
||||
<strong><FormattedNumber value={account.get('following_count')} /></strong>
|
||||
<strong>{shortNumberFormat(account.get('following_count'))}</strong>
|
||||
</Link>
|
||||
|
||||
<Link className='account__action-bar__tab' to={`/accounts/${account.get('id')}/followers`}>
|
||||
<span><FormattedMessage id='account.followers' defaultMessage='Followers' /></span>
|
||||
<strong><FormattedNumber value={account.get('followers_count')} /></strong>
|
||||
<strong>{shortNumberFormat(account.get('followers_count'))}</strong>
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ const messages = defineMessages({
|
|||
follow: { id: 'account.follow', defaultMessage: 'Follow' },
|
||||
requested: { id: 'account.requested', defaultMessage: 'Awaiting approval. Click to cancel follow request' },
|
||||
unblock: { id: 'account.unblock', defaultMessage: 'Unblock @{name}' },
|
||||
edit_profile: { id: 'account.edit_profile', defaultMessage: 'Edit profile' },
|
||||
});
|
||||
|
||||
class Avatar extends ImmutablePureComponent {
|
||||
|
|
@ -74,6 +75,10 @@ export default class Header extends ImmutablePureComponent {
|
|||
intl: PropTypes.object.isRequired,
|
||||
};
|
||||
|
||||
openEditProfile = () => {
|
||||
window.open('/settings/profile', '_blank');
|
||||
}
|
||||
|
||||
render () {
|
||||
const { account, intl } = this.props;
|
||||
|
||||
|
|
@ -118,6 +123,12 @@ export default class Header extends ImmutablePureComponent {
|
|||
</div>
|
||||
);
|
||||
}
|
||||
} else {
|
||||
actionBtn = (
|
||||
<div className='account--action-button'>
|
||||
<IconButton size={26} icon='pencil' title={intl.formatMessage(messages.edit_profile)} onClick={this.openEditProfile} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
if (account.get('moved') && !account.getIn(['relationship', 'following'])) {
|
||||
|
|
@ -130,6 +141,8 @@ export default class Header extends ImmutablePureComponent {
|
|||
|
||||
const content = { __html: account.get('note_emojified') };
|
||||
const displayNameHtml = { __html: account.get('display_name_html') };
|
||||
const fields = account.get('fields');
|
||||
const badge = account.get('bot') ? (<div className='roles'><div className='account-role bot'><FormattedMessage id='account.badges.bot' defaultMessage='Bot' /></div></div>) : null;
|
||||
|
||||
return (
|
||||
<div className={classNames('account__header', { inactive: !!account.get('moved') })} style={{ backgroundImage: `url(${account.get('header')})` }}>
|
||||
|
|
@ -138,8 +151,22 @@ export default class Header extends ImmutablePureComponent {
|
|||
|
||||
<span className='account__header__display-name' dangerouslySetInnerHTML={displayNameHtml} />
|
||||
<span className='account__header__username'>@{account.get('acct')} {lockedIcon}</span>
|
||||
|
||||
{badge}
|
||||
|
||||
<div className='account__header__content' dangerouslySetInnerHTML={content} />
|
||||
|
||||
{fields.size > 0 && (
|
||||
<div className='account__header__fields'>
|
||||
{fields.map((pair, i) => (
|
||||
<dl key={i}>
|
||||
<dt dangerouslySetInnerHTML={{ __html: pair.get('name_emojified') }} title={pair.get('name')} />
|
||||
<dd dangerouslySetInnerHTML={{ __html: pair.get('value_emojified') }} title={pair.get('value_plain')} />
|
||||
</dl>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
|
||||
{info}
|
||||
{mutingInfo}
|
||||
{actionBtn}
|
||||
|
|
|
|||
|
|
@ -67,7 +67,7 @@ export default class AccountGallery extends ImmutablePureComponent {
|
|||
|
||||
handleScrollToBottom = () => {
|
||||
if (this.props.hasMore) {
|
||||
this.handleLoadMore(this.props.medias.last().get('id'));
|
||||
this.handleLoadMore(this.props.medias.last().getIn(['status', 'id']));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ export default class Header extends ImmutablePureComponent {
|
|||
onFollow: PropTypes.func.isRequired,
|
||||
onBlock: PropTypes.func.isRequired,
|
||||
onMention: PropTypes.func.isRequired,
|
||||
onDirect: PropTypes.func.isRequired,
|
||||
onReblogToggle: PropTypes.func.isRequired,
|
||||
onReport: PropTypes.func.isRequired,
|
||||
onMute: PropTypes.func.isRequired,
|
||||
|
|
@ -40,6 +41,10 @@ export default class Header extends ImmutablePureComponent {
|
|||
this.props.onMention(this.props.account, this.context.router.history);
|
||||
}
|
||||
|
||||
handleDirect = () => {
|
||||
this.props.onDirect(this.props.account, this.context.router.history);
|
||||
}
|
||||
|
||||
handleReport = () => {
|
||||
this.props.onReport(this.props.account);
|
||||
}
|
||||
|
|
@ -57,7 +62,7 @@ export default class Header extends ImmutablePureComponent {
|
|||
|
||||
if (!domain) return;
|
||||
|
||||
this.props.onBlockDomain(domain, this.props.account.get('id'));
|
||||
this.props.onBlockDomain(domain);
|
||||
}
|
||||
|
||||
handleUnblockDomain = () => {
|
||||
|
|
@ -65,7 +70,7 @@ export default class Header extends ImmutablePureComponent {
|
|||
|
||||
if (!domain) return;
|
||||
|
||||
this.props.onUnblockDomain(domain, this.props.account.get('id'));
|
||||
this.props.onUnblockDomain(domain);
|
||||
}
|
||||
|
||||
render () {
|
||||
|
|
@ -89,6 +94,7 @@ export default class Header extends ImmutablePureComponent {
|
|||
account={account}
|
||||
onBlock={this.handleBlock}
|
||||
onMention={this.handleMention}
|
||||
onDirect={this.handleDirect}
|
||||
onReblogToggle={this.handleReblogToggle}
|
||||
onReport={this.handleReport}
|
||||
onMute={this.handleMute}
|
||||
|
|
|
|||
|
|
@ -9,7 +9,10 @@ import {
|
|||
unblockAccount,
|
||||
unmuteAccount,
|
||||
} from '../../../actions/accounts';
|
||||
import { mentionCompose } from '../../../actions/compose';
|
||||
import {
|
||||
mentionCompose,
|
||||
directCompose,
|
||||
} from '../../../actions/compose';
|
||||
import { initMuteModal } from '../../../actions/mutes';
|
||||
import { initReport } from '../../../actions/reports';
|
||||
import { openModal } from '../../../actions/modal';
|
||||
|
|
@ -67,6 +70,10 @@ const mapDispatchToProps = (dispatch, { intl }) => ({
|
|||
dispatch(mentionCompose(account, router));
|
||||
},
|
||||
|
||||
onDirect (account, router) {
|
||||
dispatch(directCompose(account, router));
|
||||
},
|
||||
|
||||
onReblogToggle (account) {
|
||||
if (account.getIn(['relationship', 'showing_reblogs'])) {
|
||||
dispatch(followAccount(account.get('id'), false));
|
||||
|
|
@ -87,16 +94,16 @@ const mapDispatchToProps = (dispatch, { intl }) => ({
|
|||
}
|
||||
},
|
||||
|
||||
onBlockDomain (domain, accountId) {
|
||||
onBlockDomain (domain) {
|
||||
dispatch(openModal('CONFIRM', {
|
||||
message: <FormattedMessage id='confirmations.domain_block.message' defaultMessage='Are you really, really sure you want to block the entire {domain}? In most cases a few targeted blocks or mutes are sufficient and preferable.' values={{ domain: <strong>{domain}</strong> }} />,
|
||||
message: <FormattedMessage id='confirmations.domain_block.message' defaultMessage='Are you really, really sure you want to block the entire {domain}? In most cases a few targeted blocks or mutes are sufficient and preferable. You will not see content from that domain in any public timelines or your notifications. Your followers from that domain will be removed.' values={{ domain: <strong>{domain}</strong> }} />,
|
||||
confirm: intl.formatMessage(messages.blockDomainConfirm),
|
||||
onConfirm: () => dispatch(blockDomain(domain, accountId)),
|
||||
onConfirm: () => dispatch(blockDomain(domain)),
|
||||
}));
|
||||
},
|
||||
|
||||
onUnblockDomain (domain, accountId) {
|
||||
dispatch(unblockDomain(domain, accountId));
|
||||
onUnblockDomain (domain) {
|
||||
dispatch(unblockDomain(domain));
|
||||
},
|
||||
|
||||
});
|
||||
|
|
|
|||
|
|
@ -0,0 +1,59 @@
|
|||
import PropTypes from 'prop-types';
|
||||
import React, { Component, Fragment } from 'react';
|
||||
import { FormattedMessage } from 'react-intl';
|
||||
import { NavLink } from 'react-router-dom';
|
||||
|
||||
export default class SectionHeadline extends Component {
|
||||
|
||||
static propTypes = {
|
||||
timelineId: PropTypes.string.isRequired,
|
||||
to: PropTypes.string.isRequired,
|
||||
pinned: PropTypes.bool.isRequired,
|
||||
onlyMedia: PropTypes.bool.isRequired,
|
||||
onClick: PropTypes.func,
|
||||
};
|
||||
|
||||
shouldComponentUpdate (nextProps) {
|
||||
return (
|
||||
this.props.onlyMedia !== nextProps.onlyMedia ||
|
||||
this.props.pinned !== nextProps.pinned ||
|
||||
this.props.to !== nextProps.to ||
|
||||
this.props.timelineId !== nextProps.timelineId
|
||||
);
|
||||
}
|
||||
|
||||
handleClick = e => {
|
||||
const { onClick } = this.props;
|
||||
|
||||
if (typeof onClick === 'function') {
|
||||
e.preventDefault();
|
||||
|
||||
onClick.call(this, e);
|
||||
}
|
||||
}
|
||||
|
||||
render () {
|
||||
const { timelineId, to, pinned, onlyMedia } = this.props;
|
||||
|
||||
return (
|
||||
<div className={`${timelineId}-timeline__section-headline`}>
|
||||
{pinned ? (
|
||||
<Fragment>
|
||||
<a href={to} className={!onlyMedia ? 'active' : undefined} onClick={this.handleClick}>
|
||||
<FormattedMessage id='timeline.posts' defaultMessage='Toots' />
|
||||
</a>
|
||||
<a href={`${to}/media`} className={onlyMedia ? 'active' : undefined} onClick={this.handleClick}>
|
||||
<FormattedMessage id='timeline.media' defaultMessage='Media' />
|
||||
</a>
|
||||
</Fragment>
|
||||
) : (
|
||||
<Fragment>
|
||||
<NavLink exact to={to} replace><FormattedMessage id='timeline.posts' defaultMessage='Toots' /></NavLink>
|
||||
<NavLink exact to={`${to}/media`} replace><FormattedMessage id='timeline.media' defaultMessage='Media' /></NavLink>
|
||||
</Fragment>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,42 +1,48 @@
|
|||
import React from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
|
||||
import PropTypes from 'prop-types';
|
||||
import StatusListContainer from '../ui/containers/status_list_container';
|
||||
import Column from '../../components/column';
|
||||
import ColumnHeader from '../../components/column_header';
|
||||
import { expandCommunityTimeline } from '../../actions/timelines';
|
||||
import { addColumn, removeColumn, moveColumn } from '../../actions/columns';
|
||||
import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
|
||||
import { addColumn, removeColumn, moveColumn, changeColumnParams } from '../../actions/columns';
|
||||
import ColumnSettingsContainer from './containers/column_settings_container';
|
||||
import SectionHeadline from './components/section_headline';
|
||||
import { connectCommunityStream } from '../../actions/streaming';
|
||||
|
||||
const messages = defineMessages({
|
||||
title: { id: 'column.community', defaultMessage: 'Local timeline' },
|
||||
});
|
||||
|
||||
const mapStateToProps = state => ({
|
||||
hasUnread: state.getIn(['timelines', 'community', 'unread']) > 0,
|
||||
const mapStateToProps = (state, { onlyMedia }) => ({
|
||||
hasUnread: state.getIn(['timelines', `community${onlyMedia ? ':media' : ''}`, 'unread']) > 0,
|
||||
});
|
||||
|
||||
@connect(mapStateToProps)
|
||||
@injectIntl
|
||||
export default class CommunityTimeline extends React.PureComponent {
|
||||
|
||||
static defaultProps = {
|
||||
onlyMedia: false,
|
||||
};
|
||||
|
||||
static propTypes = {
|
||||
dispatch: PropTypes.func.isRequired,
|
||||
columnId: PropTypes.string,
|
||||
intl: PropTypes.object.isRequired,
|
||||
hasUnread: PropTypes.bool,
|
||||
multiColumn: PropTypes.bool,
|
||||
onlyMedia: PropTypes.bool,
|
||||
};
|
||||
|
||||
handlePin = () => {
|
||||
const { columnId, dispatch } = this.props;
|
||||
const { columnId, dispatch, onlyMedia } = this.props;
|
||||
|
||||
if (columnId) {
|
||||
dispatch(removeColumn(columnId));
|
||||
} else {
|
||||
dispatch(addColumn('COMMUNITY', {}));
|
||||
dispatch(addColumn('COMMUNITY', { other: { onlyMedia } }));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -50,10 +56,20 @@ export default class CommunityTimeline extends React.PureComponent {
|
|||
}
|
||||
|
||||
componentDidMount () {
|
||||
const { dispatch } = this.props;
|
||||
const { dispatch, onlyMedia } = this.props;
|
||||
|
||||
dispatch(expandCommunityTimeline());
|
||||
this.disconnect = dispatch(connectCommunityStream());
|
||||
dispatch(expandCommunityTimeline({ onlyMedia }));
|
||||
this.disconnect = dispatch(connectCommunityStream({ onlyMedia }));
|
||||
}
|
||||
|
||||
componentDidUpdate (prevProps) {
|
||||
if (prevProps.onlyMedia !== this.props.onlyMedia) {
|
||||
const { dispatch, onlyMedia } = this.props;
|
||||
|
||||
this.disconnect();
|
||||
dispatch(expandCommunityTimeline({ onlyMedia }));
|
||||
this.disconnect = dispatch(connectCommunityStream({ onlyMedia }));
|
||||
}
|
||||
}
|
||||
|
||||
componentWillUnmount () {
|
||||
|
|
@ -68,13 +84,32 @@ export default class CommunityTimeline extends React.PureComponent {
|
|||
}
|
||||
|
||||
handleLoadMore = maxId => {
|
||||
this.props.dispatch(expandCommunityTimeline({ maxId }));
|
||||
const { dispatch, onlyMedia } = this.props;
|
||||
|
||||
dispatch(expandCommunityTimeline({ maxId, onlyMedia }));
|
||||
}
|
||||
|
||||
handleHeadlineLinkClick = e => {
|
||||
const { columnId, dispatch } = this.props;
|
||||
const onlyMedia = /\/media$/.test(e.currentTarget.href);
|
||||
|
||||
dispatch(changeColumnParams(columnId, { other: { onlyMedia } }));
|
||||
}
|
||||
|
||||
render () {
|
||||
const { intl, hasUnread, columnId, multiColumn } = this.props;
|
||||
const { intl, hasUnread, columnId, multiColumn, onlyMedia } = this.props;
|
||||
const pinned = !!columnId;
|
||||
|
||||
const headline = (
|
||||
<SectionHeadline
|
||||
timelineId='community'
|
||||
to='/timelines/public/local'
|
||||
pinned={pinned}
|
||||
onlyMedia={onlyMedia}
|
||||
onClick={this.handleHeadlineLinkClick}
|
||||
/>
|
||||
);
|
||||
|
||||
return (
|
||||
<Column ref={this.setRef}>
|
||||
<ColumnHeader
|
||||
|
|
@ -91,9 +126,11 @@ export default class CommunityTimeline extends React.PureComponent {
|
|||
</ColumnHeader>
|
||||
|
||||
<StatusListContainer
|
||||
prepend={headline}
|
||||
alwaysPrepend
|
||||
trackScroll={!pinned}
|
||||
scrollKey={`community_timeline-${columnId}`}
|
||||
timelineId='community'
|
||||
timelineId={`community${onlyMedia ? ':media' : ''}`}
|
||||
onLoadMore={this.handleLoadMore}
|
||||
emptyMessage={<FormattedMessage id='empty_column.community' defaultMessage='The local timeline is empty. Write something publicly to get the ball rolling!' />}
|
||||
/>
|
||||
|
|
|
|||
|
|
@ -7,7 +7,6 @@ import ReplyIndicatorContainer from '../containers/reply_indicator_container';
|
|||
import AutosuggestTextarea from '../../../components/autosuggest_textarea';
|
||||
import UploadButtonContainer from '../containers/upload_button_container';
|
||||
import { defineMessages, injectIntl } from 'react-intl';
|
||||
import Collapsable from '../../../components/collapsable';
|
||||
import SpoilerButtonContainer from '../containers/spoiler_button_container';
|
||||
import PrivacyDropdownContainer from '../containers/privacy_dropdown_container';
|
||||
import SensitiveButtonContainer from '../containers/sensitive_button_container';
|
||||
|
|
@ -19,6 +18,8 @@ import ImmutablePureComponent from 'react-immutable-pure-component';
|
|||
import { length } from 'stringz';
|
||||
import { countableText } from '../util/counter';
|
||||
|
||||
const allowedAroundShortCode = '><\u0085\u0020\u00a0\u1680\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u3000\u2028\u2029\u0009\u000a\u000b\u000c\u000d';
|
||||
|
||||
const messages = defineMessages({
|
||||
placeholder: { id: 'compose_form.placeholder', defaultMessage: 'What is on your mind?' },
|
||||
spoiler_placeholder: { id: 'compose_form.spoiler_placeholder', defaultMessage: 'Write your warning here' },
|
||||
|
|
@ -38,6 +39,7 @@ export default class ComposeForm extends ImmutablePureComponent {
|
|||
privacy: PropTypes.string,
|
||||
spoiler_text: PropTypes.string,
|
||||
focusDate: PropTypes.instanceOf(Date),
|
||||
caretPosition: PropTypes.number,
|
||||
preselectDate: PropTypes.instanceOf(Date),
|
||||
is_submitting: PropTypes.bool,
|
||||
is_uploading: PropTypes.bool,
|
||||
|
|
@ -74,6 +76,14 @@ export default class ComposeForm extends ImmutablePureComponent {
|
|||
this.props.onChange(this.autosuggestTextarea.textarea.value);
|
||||
}
|
||||
|
||||
// Submit disabled:
|
||||
const { is_submitting, is_uploading, anyMedia } = this.props;
|
||||
const fulltext = [this.props.spoiler_text, countableText(this.props.text)].join('');
|
||||
|
||||
if (is_submitting || is_uploading || length(fulltext) > 500 || (fulltext.length !== 0 && fulltext.trim().length === 0 && !anyMedia)) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.props.onSubmit();
|
||||
}
|
||||
|
||||
|
|
@ -86,7 +96,6 @@ export default class ComposeForm extends ImmutablePureComponent {
|
|||
}
|
||||
|
||||
onSuggestionSelected = (tokenStart, token, value) => {
|
||||
this._restoreCaret = null;
|
||||
this.props.onSuggestionSelected(tokenStart, token, value);
|
||||
}
|
||||
|
||||
|
|
@ -94,31 +103,21 @@ export default class ComposeForm extends ImmutablePureComponent {
|
|||
this.props.onChangeSpoilerText(e.target.value);
|
||||
}
|
||||
|
||||
componentWillReceiveProps (nextProps) {
|
||||
// If this is the update where we've finished uploading,
|
||||
// save the last caret position so we can restore it below!
|
||||
if (!nextProps.is_uploading && this.props.is_uploading) {
|
||||
this._restoreCaret = this.autosuggestTextarea.textarea.selectionStart;
|
||||
}
|
||||
}
|
||||
|
||||
componentDidUpdate (prevProps) {
|
||||
// This statement does several things:
|
||||
// - If we're beginning a reply, and,
|
||||
// - Replying to zero or one users, places the cursor at the end of the textbox.
|
||||
// - Replying to more than one user, selects any usernames past the first;
|
||||
// this provides a convenient shortcut to drop everyone else from the conversation.
|
||||
// - If we've just finished uploading an image, and have a saved caret position,
|
||||
// restores the cursor to that position after the text changes!
|
||||
if (this.props.focusDate !== prevProps.focusDate || (prevProps.is_uploading && !this.props.is_uploading && typeof this._restoreCaret === 'number')) {
|
||||
if (this.props.focusDate !== prevProps.focusDate) {
|
||||
let selectionEnd, selectionStart;
|
||||
|
||||
if (this.props.preselectDate !== prevProps.preselectDate) {
|
||||
selectionEnd = this.props.text.length;
|
||||
selectionStart = this.props.text.search(/\s/) + 1;
|
||||
} else if (typeof this._restoreCaret === 'number') {
|
||||
selectionStart = this._restoreCaret;
|
||||
selectionEnd = this._restoreCaret;
|
||||
} else if (typeof this.props.caretPosition === 'number') {
|
||||
selectionStart = this.props.caretPosition;
|
||||
selectionEnd = this.props.caretPosition;
|
||||
} else {
|
||||
selectionEnd = this.props.text.length;
|
||||
selectionStart = selectionEnd;
|
||||
|
|
@ -129,17 +128,30 @@ export default class ComposeForm extends ImmutablePureComponent {
|
|||
} else if(prevProps.is_submitting && !this.props.is_submitting) {
|
||||
this.autosuggestTextarea.textarea.focus();
|
||||
}
|
||||
|
||||
if (this.props.spoiler !== prevProps.spoiler) {
|
||||
if (this.props.spoiler) {
|
||||
this.spoilerText.focus();
|
||||
} else {
|
||||
this.autosuggestTextarea.textarea.focus();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
setAutosuggestTextarea = (c) => {
|
||||
this.autosuggestTextarea = c;
|
||||
}
|
||||
|
||||
setSpoilerText = (c) => {
|
||||
this.spoilerText = c;
|
||||
}
|
||||
|
||||
handleEmojiPick = (data) => {
|
||||
const { text } = this.props;
|
||||
const position = this.autosuggestTextarea.textarea.selectionStart;
|
||||
const emojiChar = data.native;
|
||||
this._restoreCaret = position + emojiChar.length + 1;
|
||||
this.props.onPickEmoji(position, data);
|
||||
const needsSpace = data.custom && position > 0 && !allowedAroundShortCode.includes(text[position - 1]);
|
||||
|
||||
this.props.onPickEmoji(position, data, needsSpace);
|
||||
}
|
||||
|
||||
render () {
|
||||
|
|
@ -159,17 +171,15 @@ export default class ComposeForm extends ImmutablePureComponent {
|
|||
<div className='compose-form'>
|
||||
<WarningContainer />
|
||||
|
||||
<Collapsable isVisible={this.props.spoiler} fullHeight={50}>
|
||||
<div className='spoiler-input'>
|
||||
<label>
|
||||
<span style={{ display: 'none' }}>{intl.formatMessage(messages.spoiler_placeholder)}</span>
|
||||
<input placeholder={intl.formatMessage(messages.spoiler_placeholder)} value={this.props.spoiler_text} onChange={this.handleChangeSpoilerText} onKeyDown={this.handleKeyDown} type='text' className='spoiler-input__input' id='cw-spoiler-input' />
|
||||
</label>
|
||||
</div>
|
||||
</Collapsable>
|
||||
|
||||
<ReplyIndicatorContainer />
|
||||
|
||||
<div className={`spoiler-input ${this.props.spoiler ? 'spoiler-input--visible' : ''}`}>
|
||||
<label>
|
||||
<span style={{ display: 'none' }}>{intl.formatMessage(messages.spoiler_placeholder)}</span>
|
||||
<input placeholder={intl.formatMessage(messages.spoiler_placeholder)} value={this.props.spoiler_text} onChange={this.handleChangeSpoilerText} onKeyDown={this.handleKeyDown} type='text' className='spoiler-input__input' id='cw-spoiler-input' ref={this.setSpoilerText} />
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div className='compose-form__autosuggest-wrapper'>
|
||||
<AutosuggestTextarea
|
||||
ref={this.setAutosuggestTextarea}
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ const messages = defineMessages({
|
|||
const assetHost = process.env.CDN_HOST || '';
|
||||
let EmojiPicker, Emoji; // load asynchronously
|
||||
|
||||
const backgroundImageFn = () => `${assetHost}/emoji/sheet.png`;
|
||||
const backgroundImageFn = () => `${assetHost}/emoji/sheet_10.png`;
|
||||
const listenerOptions = detectPassiveEvents.hasSupport ? { passive: true } : false;
|
||||
|
||||
const categoriesSort = [
|
||||
|
|
@ -162,12 +162,12 @@ class EmojiPickerMenu extends React.PureComponent {
|
|||
static defaultProps = {
|
||||
style: {},
|
||||
loading: true,
|
||||
placement: 'bottom',
|
||||
frequentlyUsedEmojis: [],
|
||||
};
|
||||
|
||||
state = {
|
||||
modifierOpen: false,
|
||||
placement: null,
|
||||
};
|
||||
|
||||
handleDocumentClick = e => {
|
||||
|
|
@ -298,7 +298,7 @@ export default class EmojiPickerDropdown extends React.PureComponent {
|
|||
this.dropdown = c;
|
||||
}
|
||||
|
||||
onShowDropdown = () => {
|
||||
onShowDropdown = ({ target }) => {
|
||||
this.setState({ active: true });
|
||||
|
||||
if (!EmojiPicker) {
|
||||
|
|
@ -313,6 +313,9 @@ export default class EmojiPickerDropdown extends React.PureComponent {
|
|||
this.setState({ loading: false });
|
||||
});
|
||||
}
|
||||
|
||||
const { top } = target.getBoundingClientRect();
|
||||
this.setState({ placement: top * 2 < innerHeight ? 'bottom' : 'top' });
|
||||
}
|
||||
|
||||
onHideDropdown = () => {
|
||||
|
|
@ -324,7 +327,7 @@ export default class EmojiPickerDropdown extends React.PureComponent {
|
|||
if (this.state.active) {
|
||||
this.onHideDropdown();
|
||||
} else {
|
||||
this.onShowDropdown();
|
||||
this.onShowDropdown(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -346,7 +349,7 @@ export default class EmojiPickerDropdown extends React.PureComponent {
|
|||
render () {
|
||||
const { intl, onPickEmoji, onSkinTone, skinTone, frequentlyUsedEmojis } = this.props;
|
||||
const title = intl.formatMessage(messages.emoji);
|
||||
const { active, loading } = this.state;
|
||||
const { active, loading, placement } = this.state;
|
||||
|
||||
return (
|
||||
<div className='emoji-picker-dropdown' onKeyDown={this.handleKeyDown}>
|
||||
|
|
@ -358,7 +361,7 @@ export default class EmojiPickerDropdown extends React.PureComponent {
|
|||
/>
|
||||
</div>
|
||||
|
||||
<Overlay show={active} placement='bottom' target={this.findTarget}>
|
||||
<Overlay show={active} placement={placement} target={this.findTarget}>
|
||||
<EmojiPickerMenu
|
||||
custom_emojis={this.props.custom_emojis}
|
||||
loading={loading}
|
||||
|
|
|
|||
|
|
@ -32,28 +32,76 @@ class PrivacyDropdownMenu extends React.PureComponent {
|
|||
onChange: PropTypes.func.isRequired,
|
||||
};
|
||||
|
||||
state = {
|
||||
mounted: false,
|
||||
};
|
||||
|
||||
handleDocumentClick = e => {
|
||||
if (this.node && !this.node.contains(e.target)) {
|
||||
this.props.onClose();
|
||||
}
|
||||
}
|
||||
|
||||
handleClick = e => {
|
||||
if (e.key === 'Escape') {
|
||||
this.props.onClose();
|
||||
} else if (!e.key || e.key === 'Enter') {
|
||||
const value = e.currentTarget.getAttribute('data-index');
|
||||
|
||||
e.preventDefault();
|
||||
handleKeyDown = e => {
|
||||
const { items } = this.props;
|
||||
const value = e.currentTarget.getAttribute('data-index');
|
||||
const index = items.findIndex(item => {
|
||||
return (item.value === value);
|
||||
});
|
||||
let element;
|
||||
|
||||
switch(e.key) {
|
||||
case 'Escape':
|
||||
this.props.onClose();
|
||||
this.props.onChange(value);
|
||||
break;
|
||||
case 'Enter':
|
||||
this.handleClick(e);
|
||||
break;
|
||||
case 'ArrowDown':
|
||||
element = this.node.childNodes[index + 1];
|
||||
if (element) {
|
||||
element.focus();
|
||||
this.props.onChange(element.getAttribute('data-index'));
|
||||
}
|
||||
break;
|
||||
case 'ArrowUp':
|
||||
element = this.node.childNodes[index - 1];
|
||||
if (element) {
|
||||
element.focus();
|
||||
this.props.onChange(element.getAttribute('data-index'));
|
||||
}
|
||||
break;
|
||||
case 'Home':
|
||||
element = this.node.firstChild;
|
||||
if (element) {
|
||||
element.focus();
|
||||
this.props.onChange(element.getAttribute('data-index'));
|
||||
}
|
||||
break;
|
||||
case 'End':
|
||||
element = this.node.lastChild;
|
||||
if (element) {
|
||||
element.focus();
|
||||
this.props.onChange(element.getAttribute('data-index'));
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
handleClick = e => {
|
||||
const value = e.currentTarget.getAttribute('data-index');
|
||||
|
||||
e.preventDefault();
|
||||
|
||||
this.props.onClose();
|
||||
this.props.onChange(value);
|
||||
}
|
||||
|
||||
componentDidMount () {
|
||||
document.addEventListener('click', this.handleDocumentClick, false);
|
||||
document.addEventListener('touchend', this.handleDocumentClick, listenerOptions);
|
||||
if (this.focusedItem) this.focusedItem.focus();
|
||||
this.setState({ mounted: true });
|
||||
}
|
||||
|
||||
componentWillUnmount () {
|
||||
|
|
@ -65,15 +113,23 @@ class PrivacyDropdownMenu extends React.PureComponent {
|
|||
this.node = c;
|
||||
}
|
||||
|
||||
setFocusRef = c => {
|
||||
this.focusedItem = c;
|
||||
}
|
||||
|
||||
render () {
|
||||
const { mounted } = this.state;
|
||||
const { style, items, value } = this.props;
|
||||
|
||||
return (
|
||||
<Motion defaultStyle={{ opacity: 0, scaleX: 0.85, scaleY: 0.75 }} style={{ opacity: spring(1, { damping: 35, stiffness: 400 }), scaleX: spring(1, { damping: 35, stiffness: 400 }), scaleY: spring(1, { damping: 35, stiffness: 400 }) }}>
|
||||
{({ opacity, scaleX, scaleY }) => (
|
||||
<div className='privacy-dropdown__dropdown' style={{ ...style, opacity: opacity, transform: `scale(${scaleX}, ${scaleY})` }} ref={this.setRef}>
|
||||
// It should not be transformed when mounting because the resulting
|
||||
// size will be used to determine the coordinate of the menu by
|
||||
// react-overlays
|
||||
<div className='privacy-dropdown__dropdown' style={{ ...style, opacity: opacity, transform: mounted ? `scale(${scaleX}, ${scaleY})` : null }} role='listbox' ref={this.setRef}>
|
||||
{items.map(item => (
|
||||
<div role='button' tabIndex='0' key={item.value} data-index={item.value} onKeyDown={this.handleClick} onClick={this.handleClick} className={classNames('privacy-dropdown__option', { active: item.value === value })}>
|
||||
<div role='option' tabIndex='0' key={item.value} data-index={item.value} onKeyDown={this.handleKeyDown} onClick={this.handleClick} className={classNames('privacy-dropdown__option', { active: item.value === value })} aria-selected={item.value === value} ref={item.value === value ? this.setFocusRef : null}>
|
||||
<div className='privacy-dropdown__option__icon'>
|
||||
<i className={`fa fa-fw fa-${item.icon}`} />
|
||||
</div>
|
||||
|
|
@ -107,9 +163,10 @@ export default class PrivacyDropdown extends React.PureComponent {
|
|||
|
||||
state = {
|
||||
open: false,
|
||||
placement: null,
|
||||
};
|
||||
|
||||
handleToggle = () => {
|
||||
handleToggle = ({ target }) => {
|
||||
if (this.props.isUserTouching()) {
|
||||
if (this.state.open) {
|
||||
this.props.onModalClose();
|
||||
|
|
@ -120,6 +177,8 @@ export default class PrivacyDropdown extends React.PureComponent {
|
|||
});
|
||||
}
|
||||
} else {
|
||||
const { top } = target.getBoundingClientRect();
|
||||
this.setState({ placement: top * 2 < innerHeight ? 'bottom' : 'top' });
|
||||
this.setState({ open: !this.state.open });
|
||||
}
|
||||
}
|
||||
|
|
@ -135,9 +194,6 @@ export default class PrivacyDropdown extends React.PureComponent {
|
|||
|
||||
handleKeyDown = e => {
|
||||
switch(e.key) {
|
||||
case 'Enter':
|
||||
this.handleToggle();
|
||||
break;
|
||||
case 'Escape':
|
||||
this.handleClose();
|
||||
break;
|
||||
|
|
@ -165,7 +221,7 @@ export default class PrivacyDropdown extends React.PureComponent {
|
|||
|
||||
render () {
|
||||
const { value, intl } = this.props;
|
||||
const { open } = this.state;
|
||||
const { open, placement } = this.state;
|
||||
|
||||
const valueOption = this.options.find(item => item.value === value);
|
||||
|
||||
|
|
@ -185,7 +241,7 @@ export default class PrivacyDropdown extends React.PureComponent {
|
|||
/>
|
||||
</div>
|
||||
|
||||
<Overlay show={open} placement='bottom' target={this}>
|
||||
<Overlay show={open} placement={placement} target={this}>
|
||||
<PrivacyDropdownMenu
|
||||
items={this.options}
|
||||
value={value}
|
||||
|
|
|
|||
|
|
@ -51,7 +51,7 @@ export default class ReplyIndicator extends ImmutablePureComponent {
|
|||
return (
|
||||
<div className='reply-indicator'>
|
||||
<div className='reply-indicator__header'>
|
||||
<div className='reply-indicator__cancel'><IconButton title={intl.formatMessage(messages.cancel)} icon='times' onClick={this.handleClick} /></div>
|
||||
<div className='reply-indicator__cancel'><IconButton title={intl.formatMessage(messages.cancel)} icon='times' onClick={this.handleClick} inverted /></div>
|
||||
|
||||
<a href={status.getIn(['account', 'url'])} onClick={this.handleAccountClick} className='reply-indicator__display-name'>
|
||||
<div className='reply-indicator__display-avatar'><Avatar account={status.get('account')} size={24} /></div>
|
||||
|
|
|
|||
|
|
@ -3,8 +3,8 @@ import ImmutablePropTypes from 'react-immutable-proptypes';
|
|||
import { FormattedMessage } from 'react-intl';
|
||||
import AccountContainer from '../../../containers/account_container';
|
||||
import StatusContainer from '../../../containers/status_container';
|
||||
import { Link } from 'react-router-dom';
|
||||
import ImmutablePureComponent from 'react-immutable-pure-component';
|
||||
import Hashtag from '../../../components/hashtag';
|
||||
|
||||
export default class SearchResults extends ImmutablePureComponent {
|
||||
|
||||
|
|
@ -22,7 +22,7 @@ export default class SearchResults extends ImmutablePureComponent {
|
|||
count += results.get('accounts').size;
|
||||
accounts = (
|
||||
<div className='search-results__section'>
|
||||
<h5><FormattedMessage id='search_results.accounts' defaultMessage='People' /></h5>
|
||||
<h5><i className='fa fa-fw fa-users' /><FormattedMessage id='search_results.accounts' defaultMessage='People' /></h5>
|
||||
|
||||
{results.get('accounts').map(accountId => <AccountContainer key={accountId} id={accountId} />)}
|
||||
</div>
|
||||
|
|
@ -33,7 +33,7 @@ export default class SearchResults extends ImmutablePureComponent {
|
|||
count += results.get('statuses').size;
|
||||
statuses = (
|
||||
<div className='search-results__section'>
|
||||
<h5><FormattedMessage id='search_results.statuses' defaultMessage='Toots' /></h5>
|
||||
<h5><i className='fa fa-fw fa-quote-right' /><FormattedMessage id='search_results.statuses' defaultMessage='Toots' /></h5>
|
||||
|
||||
{results.get('statuses').map(statusId => <StatusContainer key={statusId} id={statusId} />)}
|
||||
</div>
|
||||
|
|
@ -44,13 +44,9 @@ export default class SearchResults extends ImmutablePureComponent {
|
|||
count += results.get('hashtags').size;
|
||||
hashtags = (
|
||||
<div className='search-results__section'>
|
||||
<h5><FormattedMessage id='search_results.hashtags' defaultMessage='Hashtags' /></h5>
|
||||
<h5><i className='fa fa-fw fa-hashtag' /><FormattedMessage id='search_results.hashtags' defaultMessage='Hashtags' /></h5>
|
||||
|
||||
{results.get('hashtags').map(hashtag => (
|
||||
<Link key={hashtag} className='search-results__hashtag' to={`/timelines/tag/${hashtag}`}>
|
||||
#{hashtag}
|
||||
</Link>
|
||||
))}
|
||||
{results.get('hashtags').map(hashtag => <Hashtag key={hashtag.get('name')} hashtag={hashtag} />)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
@ -58,6 +54,7 @@ export default class SearchResults extends ImmutablePureComponent {
|
|||
return (
|
||||
<div className='search-results'>
|
||||
<div className='search-results__header'>
|
||||
<i className='fa fa-search fa-fw' />
|
||||
<FormattedMessage id='search_results.total' defaultMessage='{count, number} {count, plural, one {result} other {results}}' values={{ count }} />
|
||||
</div>
|
||||
|
||||
|
|
|
|||
|
|
@ -77,7 +77,7 @@ export default class Upload extends ImmutablePureComponent {
|
|||
{({ scale }) => (
|
||||
<div className='compose-form__upload-thumbnail' style={{ transform: `scale(${scale})`, backgroundImage: `url(${media.get('preview_url')})`, backgroundPosition: `${x}% ${y}%` }}>
|
||||
<div className={classNames('compose-form__upload__actions', { active })}>
|
||||
<button className='icon-button' onClick={this.handleUndoClick}><i className='fa fa-times' /> <FormattedMessage id='upload_form.undo' defaultMessage='Undo' /></button>
|
||||
<button className='icon-button' onClick={this.handleUndoClick}><i className='fa fa-times' /> <FormattedMessage id='upload_form.undo' defaultMessage='Delete' /></button>
|
||||
{media.get('type') === 'image' && <button className='icon-button' onClick={this.handleFocalPointClick}><i className='fa fa-crosshairs' /> <FormattedMessage id='upload_form.focus' defaultMessage='Crop' /></button>}
|
||||
</div>
|
||||
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ const mapStateToProps = state => ({
|
|||
spoiler_text: state.getIn(['compose', 'spoiler_text']),
|
||||
privacy: state.getIn(['compose', 'privacy']),
|
||||
focusDate: state.getIn(['compose', 'focusDate']),
|
||||
caretPosition: state.getIn(['compose', 'caretPosition']),
|
||||
preselectDate: state.getIn(['compose', 'preselectDate']),
|
||||
is_submitting: state.getIn(['compose', 'is_submitting']),
|
||||
is_uploading: state.getIn(['compose', 'is_uploading']),
|
||||
|
|
@ -56,8 +57,8 @@ const mapDispatchToProps = (dispatch) => ({
|
|||
dispatch(uploadCompose(files));
|
||||
},
|
||||
|
||||
onPickEmoji (position, data) {
|
||||
dispatch(insertEmojiCompose(position, data));
|
||||
onPickEmoji (position, data, needsSpace) {
|
||||
dispatch(insertEmojiCompose(position, data, needsSpace));
|
||||
},
|
||||
|
||||
});
|
||||
|
|
|
|||
|
|
@ -38,7 +38,8 @@ const getFrequentlyUsedEmojis = createSelector([
|
|||
.toArray();
|
||||
|
||||
if (emojis.length < DEFAULTS.length) {
|
||||
emojis = emojis.concat(DEFAULTS.slice(0, DEFAULTS.length - emojis.length));
|
||||
let uniqueDefaults = DEFAULTS.filter(emoji => !emojis.includes(emoji));
|
||||
emojis = emojis.concat(uniqueDefaults.slice(0, DEFAULTS.length - emojis.length));
|
||||
}
|
||||
|
||||
return emojis;
|
||||
|
|
|
|||
|
|
@ -10,22 +10,35 @@ const APPROX_HASHTAG_RE = /(?:^|[^\/\)\w])#(\w*[a-zA-Z·]\w*)/i;
|
|||
const mapStateToProps = state => ({
|
||||
needsLockWarning: state.getIn(['compose', 'privacy']) === 'private' && !state.getIn(['accounts', me, 'locked']),
|
||||
hashtagWarning: state.getIn(['compose', 'privacy']) !== 'public' && APPROX_HASHTAG_RE.test(state.getIn(['compose', 'text'])),
|
||||
directMessageWarning: state.getIn(['compose', 'privacy']) === 'direct',
|
||||
});
|
||||
|
||||
const WarningWrapper = ({ needsLockWarning, hashtagWarning }) => {
|
||||
const WarningWrapper = ({ needsLockWarning, hashtagWarning, directMessageWarning }) => {
|
||||
if (needsLockWarning) {
|
||||
return <Warning message={<FormattedMessage id='compose_form.lock_disclaimer' defaultMessage='Your account is not {locked}. Anyone can follow you to view your follower-only posts.' values={{ locked: <a href='/settings/profile'><FormattedMessage id='compose_form.lock_disclaimer.lock' defaultMessage='locked' /></a> }} />} />;
|
||||
}
|
||||
|
||||
if (hashtagWarning) {
|
||||
return <Warning message={<FormattedMessage id='compose_form.hashtag_warning' defaultMessage="This toot won't be listed under any hashtag as it is unlisted. Only public toots can be searched by hashtag." />} />;
|
||||
}
|
||||
|
||||
if (directMessageWarning) {
|
||||
const message = (
|
||||
<span>
|
||||
<FormattedMessage id='compose_form.direct_message_warning' defaultMessage='This toot will only be sent to all the mentioned users.' /> <a href='/terms' target='_blank'><FormattedMessage id='compose_form.direct_message_warning_learn_more' defaultMessage='Learn more' /></a>
|
||||
</span>
|
||||
);
|
||||
|
||||
return <Warning message={message} />;
|
||||
}
|
||||
|
||||
return null;
|
||||
};
|
||||
|
||||
WarningWrapper.propTypes = {
|
||||
needsLockWarning: PropTypes.bool,
|
||||
hashtagWarning: PropTypes.bool,
|
||||
directMessageWarning: PropTypes.bool,
|
||||
};
|
||||
|
||||
export default connect(mapStateToProps)(WarningWrapper);
|
||||
|
|
|
|||
|
|
@ -24,9 +24,9 @@ const messages = defineMessages({
|
|||
logout: { id: 'navigation_bar.logout', defaultMessage: 'Logout' },
|
||||
});
|
||||
|
||||
const mapStateToProps = state => ({
|
||||
const mapStateToProps = (state, ownProps) => ({
|
||||
columns: state.getIn(['settings', 'columns']),
|
||||
showSearch: state.getIn(['search', 'submitted']) && !state.getIn(['search', 'hidden']),
|
||||
showSearch: ownProps.multiColumn ? state.getIn(['search', 'submitted']) && !state.getIn(['search', 'hidden']) : ownProps.isSearchPage,
|
||||
});
|
||||
|
||||
@connect(mapStateToProps)
|
||||
|
|
@ -38,15 +38,24 @@ export default class Compose extends React.PureComponent {
|
|||
columns: ImmutablePropTypes.list.isRequired,
|
||||
multiColumn: PropTypes.bool,
|
||||
showSearch: PropTypes.bool,
|
||||
isSearchPage: PropTypes.bool,
|
||||
intl: PropTypes.object.isRequired,
|
||||
};
|
||||
|
||||
componentDidMount () {
|
||||
this.props.dispatch(mountCompose());
|
||||
const { isSearchPage } = this.props;
|
||||
|
||||
if (!isSearchPage) {
|
||||
this.props.dispatch(mountCompose());
|
||||
}
|
||||
}
|
||||
|
||||
componentWillUnmount () {
|
||||
this.props.dispatch(unmountCompose());
|
||||
const { isSearchPage } = this.props;
|
||||
|
||||
if (!isSearchPage) {
|
||||
this.props.dispatch(unmountCompose());
|
||||
}
|
||||
}
|
||||
|
||||
onFocus = () => {
|
||||
|
|
@ -58,7 +67,7 @@ export default class Compose extends React.PureComponent {
|
|||
}
|
||||
|
||||
render () {
|
||||
const { multiColumn, showSearch, intl } = this.props;
|
||||
const { multiColumn, showSearch, isSearchPage, intl } = this.props;
|
||||
|
||||
let header = '';
|
||||
|
||||
|
|
@ -66,7 +75,7 @@ export default class Compose extends React.PureComponent {
|
|||
const { columns } = this.props;
|
||||
header = (
|
||||
<nav className='drawer__header'>
|
||||
<Link to='/getting-started' className='drawer__tab' title={intl.formatMessage(messages.start)} aria-label={intl.formatMessage(messages.start)}><i role='img' className='fa fa-fw fa-asterisk' /></Link>
|
||||
<Link to='/getting-started' className='drawer__tab' title={intl.formatMessage(messages.start)} aria-label={intl.formatMessage(messages.start)}><i role='img' className='fa fa-fw fa-bars' /></Link>
|
||||
{!columns.some(column => column.get('id') === 'HOME') && (
|
||||
<Link to='/timelines/home' className='drawer__tab' title={intl.formatMessage(messages.home_timeline)} aria-label={intl.formatMessage(messages.home_timeline)}><i role='img' className='fa fa-fw fa-home' /></Link>
|
||||
)}
|
||||
|
|
@ -89,10 +98,10 @@ export default class Compose extends React.PureComponent {
|
|||
<div className='drawer'>
|
||||
{header}
|
||||
|
||||
<SearchContainer />
|
||||
{(multiColumn || isSearchPage) && <SearchContainer /> }
|
||||
|
||||
<div className='drawer__pager'>
|
||||
<div className='drawer__inner' onFocus={this.onFocus}>
|
||||
{!isSearchPage && <div className='drawer__inner' onFocus={this.onFocus}>
|
||||
<NavigationContainer onClose={this.onBlur} />
|
||||
<ComposeFormContainer />
|
||||
{multiColumn && (
|
||||
|
|
@ -100,9 +109,9 @@ export default class Compose extends React.PureComponent {
|
|||
<img alt='' draggable='false' src={elephantUIPlane} />
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>}
|
||||
|
||||
<Motion defaultStyle={{ x: -100 }} style={{ x: spring(showSearch ? 0 : -100, { stiffness: 210, damping: 20 }) }}>
|
||||
<Motion defaultStyle={{ x: isSearchPage ? 0 : -100 }} style={{ x: spring(showSearch || isSearchPage ? 0 : -100, { stiffness: 210, damping: 20 }) }}>
|
||||
{({ x }) => (
|
||||
<div className='drawer__inner darker' style={{ transform: `translateX(${x}%)`, visibility: x === -100 ? 'hidden' : 'visible' }}>
|
||||
<SearchResultsContainer />
|
||||
|
|
|
|||
|
|
@ -0,0 +1,17 @@
|
|||
import { connect } from 'react-redux';
|
||||
import ColumnSettings from '../../community_timeline/components/column_settings';
|
||||
import { changeSetting } from '../../../actions/settings';
|
||||
|
||||
const mapStateToProps = state => ({
|
||||
settings: state.getIn(['settings', 'direct']),
|
||||
});
|
||||
|
||||
const mapDispatchToProps = dispatch => ({
|
||||
|
||||
onChange (key, checked) {
|
||||
dispatch(changeSetting(['direct', ...key], checked));
|
||||
},
|
||||
|
||||
});
|
||||
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(ColumnSettings);
|
||||
104
app/javascript/mastodon/features/direct_timeline/index.js
Normal file
104
app/javascript/mastodon/features/direct_timeline/index.js
Normal file
|
|
@ -0,0 +1,104 @@
|
|||
import React from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
import PropTypes from 'prop-types';
|
||||
import StatusListContainer from '../ui/containers/status_list_container';
|
||||
import Column from '../../components/column';
|
||||
import ColumnHeader from '../../components/column_header';
|
||||
import { expandDirectTimeline } from '../../actions/timelines';
|
||||
import { addColumn, removeColumn, moveColumn } from '../../actions/columns';
|
||||
import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
|
||||
import ColumnSettingsContainer from './containers/column_settings_container';
|
||||
import { connectDirectStream } from '../../actions/streaming';
|
||||
|
||||
const messages = defineMessages({
|
||||
title: { id: 'column.direct', defaultMessage: 'Direct messages' },
|
||||
});
|
||||
|
||||
const mapStateToProps = state => ({
|
||||
hasUnread: state.getIn(['timelines', 'direct', 'unread']) > 0,
|
||||
});
|
||||
|
||||
@connect(mapStateToProps)
|
||||
@injectIntl
|
||||
export default class DirectTimeline extends React.PureComponent {
|
||||
|
||||
static propTypes = {
|
||||
dispatch: PropTypes.func.isRequired,
|
||||
columnId: PropTypes.string,
|
||||
intl: PropTypes.object.isRequired,
|
||||
hasUnread: PropTypes.bool,
|
||||
multiColumn: PropTypes.bool,
|
||||
};
|
||||
|
||||
handlePin = () => {
|
||||
const { columnId, dispatch } = this.props;
|
||||
|
||||
if (columnId) {
|
||||
dispatch(removeColumn(columnId));
|
||||
} else {
|
||||
dispatch(addColumn('DIRECT', {}));
|
||||
}
|
||||
}
|
||||
|
||||
handleMove = (dir) => {
|
||||
const { columnId, dispatch } = this.props;
|
||||
dispatch(moveColumn(columnId, dir));
|
||||
}
|
||||
|
||||
handleHeaderClick = () => {
|
||||
this.column.scrollTop();
|
||||
}
|
||||
|
||||
componentDidMount () {
|
||||
const { dispatch } = this.props;
|
||||
|
||||
dispatch(expandDirectTimeline());
|
||||
this.disconnect = dispatch(connectDirectStream());
|
||||
}
|
||||
|
||||
componentWillUnmount () {
|
||||
if (this.disconnect) {
|
||||
this.disconnect();
|
||||
this.disconnect = null;
|
||||
}
|
||||
}
|
||||
|
||||
setRef = c => {
|
||||
this.column = c;
|
||||
}
|
||||
|
||||
handleLoadMore = maxId => {
|
||||
this.props.dispatch(expandDirectTimeline({ maxId }));
|
||||
}
|
||||
|
||||
render () {
|
||||
const { intl, hasUnread, columnId, multiColumn } = this.props;
|
||||
const pinned = !!columnId;
|
||||
|
||||
return (
|
||||
<Column ref={this.setRef}>
|
||||
<ColumnHeader
|
||||
icon='envelope'
|
||||
active={hasUnread}
|
||||
title={intl.formatMessage(messages.title)}
|
||||
onPin={this.handlePin}
|
||||
onMove={this.handleMove}
|
||||
onClick={this.handleHeaderClick}
|
||||
pinned={pinned}
|
||||
multiColumn={multiColumn}
|
||||
>
|
||||
<ColumnSettingsContainer />
|
||||
</ColumnHeader>
|
||||
|
||||
<StatusListContainer
|
||||
trackScroll={!pinned}
|
||||
scrollKey={`direct_timeline-${columnId}`}
|
||||
timelineId='direct'
|
||||
onLoadMore={this.handleLoadMore}
|
||||
emptyMessage={<FormattedMessage id='empty_column.direct' defaultMessage="You don't have any direct messages yet. When you send or receive one, it will show up here." />}
|
||||
/>
|
||||
</Column>
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
66
app/javascript/mastodon/features/domain_blocks/index.js
Normal file
66
app/javascript/mastodon/features/domain_blocks/index.js
Normal file
|
|
@ -0,0 +1,66 @@
|
|||
import React from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
import ImmutablePropTypes from 'react-immutable-proptypes';
|
||||
import PropTypes from 'prop-types';
|
||||
import LoadingIndicator from '../../components/loading_indicator';
|
||||
import Column from '../ui/components/column';
|
||||
import ColumnBackButtonSlim from '../../components/column_back_button_slim';
|
||||
import DomainContainer from '../../containers/domain_container';
|
||||
import { fetchDomainBlocks, expandDomainBlocks } from '../../actions/domain_blocks';
|
||||
import { defineMessages, injectIntl } from 'react-intl';
|
||||
import ImmutablePureComponent from 'react-immutable-pure-component';
|
||||
import { debounce } from 'lodash';
|
||||
import ScrollableList from '../../components/scrollable_list';
|
||||
|
||||
const messages = defineMessages({
|
||||
heading: { id: 'column.domain_blocks', defaultMessage: 'Hidden domains' },
|
||||
unblockDomain: { id: 'account.unblock_domain', defaultMessage: 'Unhide {domain}' },
|
||||
});
|
||||
|
||||
const mapStateToProps = state => ({
|
||||
domains: state.getIn(['domain_lists', 'blocks', 'items']),
|
||||
});
|
||||
|
||||
@connect(mapStateToProps)
|
||||
@injectIntl
|
||||
export default class Blocks extends ImmutablePureComponent {
|
||||
|
||||
static propTypes = {
|
||||
params: PropTypes.object.isRequired,
|
||||
dispatch: PropTypes.func.isRequired,
|
||||
domains: ImmutablePropTypes.orderedSet,
|
||||
intl: PropTypes.object.isRequired,
|
||||
};
|
||||
|
||||
componentWillMount () {
|
||||
this.props.dispatch(fetchDomainBlocks());
|
||||
}
|
||||
|
||||
handleLoadMore = debounce(() => {
|
||||
this.props.dispatch(expandDomainBlocks());
|
||||
}, 300, { leading: true });
|
||||
|
||||
render () {
|
||||
const { intl, domains } = this.props;
|
||||
|
||||
if (!domains) {
|
||||
return (
|
||||
<Column>
|
||||
<LoadingIndicator />
|
||||
</Column>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<Column icon='minus-circle' heading={intl.formatMessage(messages.heading)}>
|
||||
<ColumnBackButtonSlim />
|
||||
<ScrollableList scrollKey='domain_blocks' onLoadMore={this.handleLoadMore}>
|
||||
{domains.map(domain =>
|
||||
<DomainContainer key={domain} domain={domain} />
|
||||
)}
|
||||
</ScrollableList>
|
||||
</Column>
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -51,7 +51,7 @@ describe('emoji', () => {
|
|||
});
|
||||
|
||||
it('does an emoji that has no shortcode', () => {
|
||||
expect(emojify('🕉️')).toEqual('<img draggable="false" class="emojione" alt="🕉️" title="" src="/emoji/1f549.svg" />');
|
||||
expect(emojify('👁🗨')).toEqual('<img draggable="false" class="emojione" alt="👁🗨" title="" src="/emoji/1f441-200d-1f5e8.svg" />');
|
||||
});
|
||||
|
||||
it('does an emoji whose filename is irregular', () => {
|
||||
|
|
|
|||
|
|
@ -44,6 +44,57 @@ describe('emoji_index', () => {
|
|||
expect(emojiIndex.search('apple').map(trimEmojis)).toEqual(expected);
|
||||
});
|
||||
|
||||
it('can include/exclude categories', () => {
|
||||
expect(search('flag', { include: ['people'] })).toEqual([]);
|
||||
expect(emojiIndex.search('flag', { include: ['people'] })).toEqual([]);
|
||||
});
|
||||
|
||||
it('(different behavior from emoji-mart) do not erases custom emoji if not passed again', () => {
|
||||
const custom = [
|
||||
{
|
||||
id: 'mastodon',
|
||||
name: 'mastodon',
|
||||
short_names: ['mastodon'],
|
||||
text: '',
|
||||
emoticons: [],
|
||||
keywords: ['mastodon'],
|
||||
imageUrl: 'http://example.com',
|
||||
custom: true,
|
||||
},
|
||||
];
|
||||
search('', { custom });
|
||||
emojiIndex.search('', { custom });
|
||||
const expected = [];
|
||||
const lightExpected = [
|
||||
{
|
||||
id: 'mastodon',
|
||||
custom: true,
|
||||
},
|
||||
];
|
||||
expect(search('masto').map(trimEmojis)).toEqual(lightExpected);
|
||||
expect(emojiIndex.search('masto').map(trimEmojis)).toEqual(expected);
|
||||
});
|
||||
|
||||
it('(different behavior from emoji-mart) erases custom emoji if another is passed', () => {
|
||||
const custom = [
|
||||
{
|
||||
id: 'mastodon',
|
||||
name: 'mastodon',
|
||||
short_names: ['mastodon'],
|
||||
text: '',
|
||||
emoticons: [],
|
||||
keywords: ['mastodon'],
|
||||
imageUrl: 'http://example.com',
|
||||
custom: true,
|
||||
},
|
||||
];
|
||||
search('', { custom });
|
||||
emojiIndex.search('', { custom });
|
||||
const expected = [];
|
||||
expect(search('masto', { custom: [] }).map(trimEmojis)).toEqual(expected);
|
||||
expect(emojiIndex.search('masto').map(trimEmojis)).toEqual(expected);
|
||||
});
|
||||
|
||||
it('handles custom emoji', () => {
|
||||
const custom = [
|
||||
{
|
||||
|
|
@ -65,23 +116,18 @@ describe('emoji_index', () => {
|
|||
custom: true,
|
||||
},
|
||||
];
|
||||
expect(search('masto').map(trimEmojis)).toEqual(expected);
|
||||
expect(emojiIndex.search('masto').map(trimEmojis)).toEqual(expected);
|
||||
expect(search('masto', { custom }).map(trimEmojis)).toEqual(expected);
|
||||
expect(emojiIndex.search('masto', { custom }).map(trimEmojis)).toEqual(expected);
|
||||
});
|
||||
|
||||
it('should filter only emojis we care about, exclude pineapple', () => {
|
||||
const emojisToShowFilter = unified => unified !== '1F34D';
|
||||
const emojisToShowFilter = emoji => emoji.unified !== '1F34D';
|
||||
expect(search('apple', { emojisToShowFilter }).map((obj) => obj.id))
|
||||
.not.toContain('pineapple');
|
||||
expect(emojiIndex.search('apple', { emojisToShowFilter }).map((obj) => obj.id))
|
||||
.not.toContain('pineapple');
|
||||
});
|
||||
|
||||
it('can include/exclude categories', () => {
|
||||
expect(search('flag', { include: ['people'] })).toEqual([]);
|
||||
expect(emojiIndex.search('flag', { include: ['people'] })).toEqual([]);
|
||||
});
|
||||
|
||||
it('does an emoji whose unified name is irregular', () => {
|
||||
const expected = [
|
||||
{
|
||||
|
|
|
|||
|
|
@ -9,7 +9,13 @@ const { unicodeToFilename } = require('./unicode_to_filename');
|
|||
const { unicodeToUnifiedName } = require('./unicode_to_unified_name');
|
||||
const emojiMap = require('./emoji_map.json');
|
||||
const { emojiIndex } = require('emoji-mart');
|
||||
const { default: emojiMartData } = require('emoji-mart/dist/data');
|
||||
const { uncompress: emojiMartUncompress } = require('emoji-mart/dist/utils/data');
|
||||
let data = require('emoji-mart/data/all.json');
|
||||
|
||||
if(data.compressed) {
|
||||
data = emojiMartUncompress(data);
|
||||
}
|
||||
const emojiMartData = data;
|
||||
|
||||
const excluded = ['®', '©', '™'];
|
||||
const skins = ['🏻', '🏼', '🏽', '🏾', '🏿'];
|
||||
|
|
@ -88,6 +94,6 @@ module.exports = JSON.parse(JSON.stringify([
|
|||
shortCodesToEmojiData,
|
||||
emojiMartData.skins,
|
||||
emojiMartData.categories,
|
||||
emojiMartData.short_names,
|
||||
emojiMartData.aliases,
|
||||
emojisWithoutShortCodes,
|
||||
]));
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ let originalPool = {};
|
|||
let index = {};
|
||||
let emojisList = {};
|
||||
let emoticonsList = {};
|
||||
let customEmojisList = [];
|
||||
|
||||
for (let emoji in data.emojis) {
|
||||
let emojiData = data.emojis[emoji];
|
||||
|
|
@ -28,7 +29,18 @@ for (let emoji in data.emojis) {
|
|||
originalPool[id] = emojiData;
|
||||
}
|
||||
|
||||
function clearCustomEmojis(pool) {
|
||||
customEmojisList.forEach((emoji) => {
|
||||
let emojiId = emoji.id || emoji.short_names[0];
|
||||
|
||||
delete pool[emojiId];
|
||||
delete emojisList[emojiId];
|
||||
});
|
||||
}
|
||||
|
||||
function addCustomToPool(custom, pool) {
|
||||
if (customEmojisList.length) clearCustomEmojis(pool);
|
||||
|
||||
custom.forEach((emoji) => {
|
||||
let emojiId = emoji.id || emoji.short_names[0];
|
||||
|
||||
|
|
@ -37,10 +49,18 @@ function addCustomToPool(custom, pool) {
|
|||
emojisList[emojiId] = getSanitizedData(emoji);
|
||||
}
|
||||
});
|
||||
|
||||
customEmojisList = custom;
|
||||
index = {};
|
||||
}
|
||||
|
||||
function search(value, { emojisToShowFilter, maxResults, include, exclude, custom = [] } = {}) {
|
||||
addCustomToPool(custom, originalPool);
|
||||
function search(value, { emojisToShowFilter, maxResults, include, exclude, custom } = {}) {
|
||||
if (custom !== undefined) {
|
||||
if (customEmojisList !== custom)
|
||||
addCustomToPool(custom, originalPool);
|
||||
} else {
|
||||
custom = [];
|
||||
}
|
||||
|
||||
maxResults = maxResults || 75;
|
||||
include = include || [];
|
||||
|
|
@ -143,7 +163,7 @@ function search(value, { emojisToShowFilter, maxResults, include, exclude, custo
|
|||
|
||||
if (results) {
|
||||
if (emojisToShowFilter) {
|
||||
results = results.filter((result) => emojisToShowFilter(data.emojis[result.id].unified));
|
||||
results = results.filter((result) => emojisToShowFilter(data.emojis[result.id]));
|
||||
}
|
||||
|
||||
if (results && results.length > maxResults) {
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import Picker from 'emoji-mart/dist-es/components/picker';
|
||||
import Emoji from 'emoji-mart/dist-es/components/emoji';
|
||||
import Picker from 'emoji-mart/dist-es/components/picker/picker';
|
||||
import Emoji from 'emoji-mart/dist-es/components/emoji/emoji';
|
||||
|
||||
export {
|
||||
Picker,
|
||||
|
|
|
|||
|
|
@ -10,32 +10,32 @@ import ImmutablePureComponent from 'react-immutable-pure-component';
|
|||
import { me } from '../../initial_state';
|
||||
import { fetchFollowRequests } from '../../actions/accounts';
|
||||
import { List as ImmutableList } from 'immutable';
|
||||
import { Link } from 'react-router-dom';
|
||||
import NavigationBar from '../compose/components/navigation_bar';
|
||||
|
||||
const messages = defineMessages({
|
||||
heading: { id: 'getting_started.heading', defaultMessage: 'Getting started' },
|
||||
home_timeline: { id: 'tabs_bar.home', defaultMessage: 'Home' },
|
||||
notifications: { id: 'tabs_bar.notifications', defaultMessage: 'Notifications' },
|
||||
public_timeline: { id: 'navigation_bar.public_timeline', defaultMessage: 'Federated timeline' },
|
||||
navigation_subheading: { id: 'column_subheading.navigation', defaultMessage: 'Navigation' },
|
||||
settings_subheading: { id: 'column_subheading.settings', defaultMessage: 'Settings' },
|
||||
community_timeline: { id: 'navigation_bar.community_timeline', defaultMessage: 'Local timeline' },
|
||||
direct: { id: 'navigation_bar.direct', defaultMessage: 'Direct messages' },
|
||||
preferences: { id: 'navigation_bar.preferences', defaultMessage: 'Preferences' },
|
||||
follow_requests: { id: 'navigation_bar.follow_requests', defaultMessage: 'Follow requests' },
|
||||
sign_out: { id: 'navigation_bar.logout', defaultMessage: 'Logout' },
|
||||
favourites: { id: 'navigation_bar.favourites', defaultMessage: 'Favourites' },
|
||||
blocks: { id: 'navigation_bar.blocks', defaultMessage: 'Blocked users' },
|
||||
domain_blocks: { id: 'navigation_bar.domain_blocks', defaultMessage: 'Hidden domains' },
|
||||
mutes: { id: 'navigation_bar.mutes', defaultMessage: 'Muted users' },
|
||||
info: { id: 'navigation_bar.info', defaultMessage: 'Extended information' },
|
||||
pins: { id: 'navigation_bar.pins', defaultMessage: 'Pinned toots' },
|
||||
lists: { id: 'navigation_bar.lists', defaultMessage: 'Lists' },
|
||||
keyboard_shortcuts: { id: 'navigation_bar.keyboard_shortcuts', defaultMessage: 'Keyboard shortcuts' },
|
||||
discover: { id: 'navigation_bar.discover', defaultMessage: 'Discover' },
|
||||
personal: { id: 'navigation_bar.personal', defaultMessage: 'Personal' },
|
||||
security: { id: 'navigation_bar.security', defaultMessage: 'Security' },
|
||||
});
|
||||
|
||||
const mapStateToProps = state => ({
|
||||
myAccount: state.getIn(['accounts', me]),
|
||||
columns: state.getIn(['settings', 'columns']),
|
||||
unreadFollowRequests: state.getIn(['user_lists', 'follow_requests', 'items'], ImmutableList()).size,
|
||||
unreadNotifications: state.getIn(['notifications', 'unread']),
|
||||
});
|
||||
|
||||
const mapDispatchToProps = dispatch => ({
|
||||
|
|
@ -75,60 +75,73 @@ export default class GettingStarted extends ImmutablePureComponent {
|
|||
}
|
||||
|
||||
render () {
|
||||
const { intl, myAccount, columns, multiColumn, unreadFollowRequests, unreadNotifications } = this.props;
|
||||
const { intl, myAccount, multiColumn, unreadFollowRequests } = this.props;
|
||||
|
||||
const navItems = [];
|
||||
let i = 1;
|
||||
let height = 0;
|
||||
|
||||
if (multiColumn) {
|
||||
if (!columns.find(item => item.get('id') === 'HOME')) {
|
||||
navItems.push(<ColumnLink key='0' icon='home' text={intl.formatMessage(messages.home_timeline)} to='/timelines/home' />);
|
||||
}
|
||||
navItems.push(
|
||||
<ColumnSubheading key={i++} text={intl.formatMessage(messages.discover)} />,
|
||||
<ColumnLink key={i++} icon='users' text={intl.formatMessage(messages.community_timeline)} to='/timelines/public/local' />,
|
||||
<ColumnLink key={i++} icon='globe' text={intl.formatMessage(messages.public_timeline)} to='/timelines/public' />,
|
||||
<ColumnSubheading key={i++} text={intl.formatMessage(messages.personal)} />
|
||||
);
|
||||
|
||||
if (!columns.find(item => item.get('id') === 'NOTIFICATIONS')) {
|
||||
navItems.push(<ColumnLink key='1' icon='bell' text={intl.formatMessage(messages.notifications)} badge={badgeDisplay(unreadNotifications)} to='/notifications' />);
|
||||
}
|
||||
|
||||
if (!columns.find(item => item.get('id') === 'COMMUNITY')) {
|
||||
navItems.push(<ColumnLink key='2' icon='users' text={intl.formatMessage(messages.community_timeline)} to='/timelines/public/local' />);
|
||||
}
|
||||
|
||||
if (!columns.find(item => item.get('id') === 'PUBLIC')) {
|
||||
navItems.push(<ColumnLink key='3' icon='globe' text={intl.formatMessage(messages.public_timeline)} to='/timelines/public' />);
|
||||
}
|
||||
height += 34*2 + 48*2;
|
||||
}
|
||||
|
||||
navItems.push(
|
||||
<ColumnLink key='4' icon='star' text={intl.formatMessage(messages.favourites)} to='/favourites' />,
|
||||
<ColumnLink key='5' icon='bars' text={intl.formatMessage(messages.lists)} to='/lists' />
|
||||
<ColumnLink key={i++} icon='envelope' text={intl.formatMessage(messages.direct)} to='/timelines/direct' />,
|
||||
<ColumnLink key={i++} icon='star' text={intl.formatMessage(messages.favourites)} to='/favourites' />,
|
||||
<ColumnLink key={i++} icon='bars' text={intl.formatMessage(messages.lists)} to='/lists' />
|
||||
);
|
||||
|
||||
height += 48*3;
|
||||
|
||||
if (myAccount.get('locked')) {
|
||||
navItems.push(<ColumnLink key='6' icon='users' text={intl.formatMessage(messages.follow_requests)} badge={badgeDisplay(unreadFollowRequests, 40)} to='/follow_requests' />);
|
||||
navItems.push(<ColumnLink key={i++} icon='users' text={intl.formatMessage(messages.follow_requests)} badge={badgeDisplay(unreadFollowRequests, 40)} to='/follow_requests' />);
|
||||
height += 48;
|
||||
}
|
||||
|
||||
if (multiColumn) {
|
||||
navItems.push(<ColumnLink key='7' icon='question' text={intl.formatMessage(messages.keyboard_shortcuts)} to='/keyboard-shortcuts' />);
|
||||
}
|
||||
if (!multiColumn) {
|
||||
navItems.push(
|
||||
<ColumnSubheading key={i++} text={intl.formatMessage(messages.settings_subheading)} />,
|
||||
<ColumnLink key={i++} icon='gears' text={intl.formatMessage(messages.preferences)} href='/settings/preferences' />,
|
||||
<ColumnLink key={i++} icon='lock' text={intl.formatMessage(messages.security)} href='/auth/edit' />
|
||||
);
|
||||
|
||||
navItems.push(<ColumnLink key='8' icon='book' text={intl.formatMessage(messages.info)} href='/about/more' />);
|
||||
height += 34 + 48*2;
|
||||
}
|
||||
|
||||
return (
|
||||
<Column icon='asterisk' heading={intl.formatMessage(messages.heading)} hideHeadingOnMobile>
|
||||
<div className='getting-started__wrapper'>
|
||||
<ColumnSubheading text={intl.formatMessage(messages.navigation_subheading)} />
|
||||
<Column>
|
||||
{multiColumn && <div className='column-header__wrapper'>
|
||||
<h1 className='column-header'>
|
||||
<button>
|
||||
<i className='fa fa-bars fa-fw column-header__icon' />
|
||||
<FormattedMessage id='getting_started.heading' defaultMessage='Getting started' />
|
||||
</button>
|
||||
</h1>
|
||||
</div>}
|
||||
|
||||
<div className='getting-started__wrapper' style={{ height }}>
|
||||
{!multiColumn && <NavigationBar account={myAccount} />}
|
||||
{navItems}
|
||||
<ColumnSubheading text={intl.formatMessage(messages.settings_subheading)} />
|
||||
<ColumnLink icon='thumb-tack' text={intl.formatMessage(messages.pins)} to='/pinned' />
|
||||
<ColumnLink icon='volume-off' text={intl.formatMessage(messages.mutes)} to='/mutes' />
|
||||
<ColumnLink icon='ban' text={intl.formatMessage(messages.blocks)} to='/blocks' />
|
||||
<ColumnLink icon='cog' text={intl.formatMessage(messages.preferences)} href='/settings/preferences' />
|
||||
<ColumnLink icon='sign-out' text={intl.formatMessage(messages.sign_out)} href='/auth/sign_out' method='delete' />
|
||||
</div>
|
||||
|
||||
<div className='static-content getting-started'>
|
||||
<p>
|
||||
<a href='https://github.com/tootsuite/documentation/blob/master/Using-Mastodon/FAQ.md' rel='noopener' target='_blank'><FormattedMessage id='getting_started.faq' defaultMessage='FAQ' /></a> • <a href='https://github.com/tootsuite/documentation/blob/master/Using-Mastodon/User-guide.md' rel='noopener' target='_blank'><FormattedMessage id='getting_started.userguide' defaultMessage='User Guide' /></a> • <a href='https://github.com/tootsuite/documentation/blob/master/Using-Mastodon/Apps.md' rel='noopener' target='_blank'><FormattedMessage id='getting_started.appsshort' defaultMessage='Apps' /></a>
|
||||
</p>
|
||||
{!multiColumn && <div className='flex-spacer' />}
|
||||
|
||||
<div className='getting-started getting-started__footer'>
|
||||
<ul>
|
||||
{multiColumn && <li><Link to='/keyboard-shortcuts'><FormattedMessage id='navigation_bar.keyboard_shortcuts' defaultMessage='Hotkeys' /></Link> · </li>}
|
||||
<li><a href='/about/more' target='_blank'><FormattedMessage id='navigation_bar.info' defaultMessage='About this instance' /></a> · </li>
|
||||
<li><a href='/terms' target='_blank'><FormattedMessage id='getting_started.terms' defaultMessage='Terms of service' /></a> · </li>
|
||||
<li><a href='https://github.com/tootsuite/documentation#documentation' target='_blank'><FormattedMessage id='getting_started.documentation' defaultMessage='Documentation' /></a> · </li>
|
||||
<li><a href='/auth/sign_out' data-method='delete'><FormattedMessage id='navigation_bar.logout' defaultMessage='Logout' /></a></li>
|
||||
</ul>
|
||||
|
||||
<p>
|
||||
<FormattedMessage
|
||||
id='getting_started.open_source_notice'
|
||||
|
|
|
|||
|
|
@ -52,6 +52,10 @@ export default class KeyboardShortcuts extends ImmutablePureComponent {
|
|||
<td><kbd>enter</kbd></td>
|
||||
<td><FormattedMessage id='keyboard_shortcuts.enter' defaultMessage='to open status' /></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><kbd>x</kbd></td>
|
||||
<td><FormattedMessage id='keyboard_shortcuts.toggle_hidden' defaultMessage='to show/hide text behind CW' /></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><kbd>up</kbd></td>
|
||||
<td><FormattedMessage id='keyboard_shortcuts.up' defaultMessage='to move up in the list' /></td>
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ import { createSelector } from 'reselect';
|
|||
import { List as ImmutableList } from 'immutable';
|
||||
import { debounce } from 'lodash';
|
||||
import ScrollableList from '../../components/scrollable_list';
|
||||
import LoadMore from '../../components/load_more';
|
||||
import LoadGap from '../../components/load_gap';
|
||||
|
||||
const messages = defineMessages({
|
||||
title: { id: 'column.notifications', defaultMessage: 'Notifications' },
|
||||
|
|
@ -24,24 +24,6 @@ const getNotifications = createSelector([
|
|||
state => state.getIn(['notifications', 'items']),
|
||||
], (excludedTypes, notifications) => notifications.filterNot(item => item !== null && excludedTypes.includes(item.get('type'))));
|
||||
|
||||
class LoadGap extends React.PureComponent {
|
||||
|
||||
static propTypes = {
|
||||
disabled: PropTypes.bool,
|
||||
maxId: PropTypes.string,
|
||||
onClick: PropTypes.func.isRequired,
|
||||
};
|
||||
|
||||
handleClick = () => {
|
||||
this.props.onClick(this.props.maxId);
|
||||
}
|
||||
|
||||
render () {
|
||||
return <LoadMore onClick={this.handleClick} disabled={this.props.disabled} />;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
const mapStateToProps = state => ({
|
||||
notifications: getNotifications(state),
|
||||
isLoading: state.getIn(['notifications', 'isLoading'], true),
|
||||
|
|
|
|||
|
|
@ -1,42 +1,48 @@
|
|||
import React from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
|
||||
import PropTypes from 'prop-types';
|
||||
import StatusListContainer from '../ui/containers/status_list_container';
|
||||
import Column from '../../components/column';
|
||||
import ColumnHeader from '../../components/column_header';
|
||||
import { expandPublicTimeline } from '../../actions/timelines';
|
||||
import { addColumn, removeColumn, moveColumn } from '../../actions/columns';
|
||||
import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
|
||||
import { addColumn, removeColumn, moveColumn, changeColumnParams } from '../../actions/columns';
|
||||
import ColumnSettingsContainer from './containers/column_settings_container';
|
||||
import SectionHeadline from '../community_timeline/components/section_headline';
|
||||
import { connectPublicStream } from '../../actions/streaming';
|
||||
|
||||
const messages = defineMessages({
|
||||
title: { id: 'column.public', defaultMessage: 'Federated timeline' },
|
||||
});
|
||||
|
||||
const mapStateToProps = state => ({
|
||||
hasUnread: state.getIn(['timelines', 'public', 'unread']) > 0,
|
||||
const mapStateToProps = (state, { onlyMedia }) => ({
|
||||
hasUnread: state.getIn(['timelines', `public${onlyMedia ? ':media' : ''}`, 'unread']) > 0,
|
||||
});
|
||||
|
||||
@connect(mapStateToProps)
|
||||
@injectIntl
|
||||
export default class PublicTimeline extends React.PureComponent {
|
||||
|
||||
static defaultProps = {
|
||||
onlyMedia: false,
|
||||
};
|
||||
|
||||
static propTypes = {
|
||||
dispatch: PropTypes.func.isRequired,
|
||||
intl: PropTypes.object.isRequired,
|
||||
columnId: PropTypes.string,
|
||||
multiColumn: PropTypes.bool,
|
||||
hasUnread: PropTypes.bool,
|
||||
onlyMedia: PropTypes.bool,
|
||||
};
|
||||
|
||||
handlePin = () => {
|
||||
const { columnId, dispatch } = this.props;
|
||||
const { columnId, dispatch, onlyMedia } = this.props;
|
||||
|
||||
if (columnId) {
|
||||
dispatch(removeColumn(columnId));
|
||||
} else {
|
||||
dispatch(addColumn('PUBLIC', {}));
|
||||
dispatch(addColumn('PUBLIC', { other: { onlyMedia } }));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -50,10 +56,20 @@ export default class PublicTimeline extends React.PureComponent {
|
|||
}
|
||||
|
||||
componentDidMount () {
|
||||
const { dispatch } = this.props;
|
||||
const { dispatch, onlyMedia } = this.props;
|
||||
|
||||
dispatch(expandPublicTimeline());
|
||||
this.disconnect = dispatch(connectPublicStream());
|
||||
dispatch(expandPublicTimeline({ onlyMedia }));
|
||||
this.disconnect = dispatch(connectPublicStream({ onlyMedia }));
|
||||
}
|
||||
|
||||
componentDidUpdate (prevProps) {
|
||||
if (prevProps.onlyMedia !== this.props.onlyMedia) {
|
||||
const { dispatch, onlyMedia } = this.props;
|
||||
|
||||
this.disconnect();
|
||||
dispatch(expandPublicTimeline({ onlyMedia }));
|
||||
this.disconnect = dispatch(connectPublicStream({ onlyMedia }));
|
||||
}
|
||||
}
|
||||
|
||||
componentWillUnmount () {
|
||||
|
|
@ -68,13 +84,32 @@ export default class PublicTimeline extends React.PureComponent {
|
|||
}
|
||||
|
||||
handleLoadMore = maxId => {
|
||||
this.props.dispatch(expandPublicTimeline({ maxId }));
|
||||
const { dispatch, onlyMedia } = this.props;
|
||||
|
||||
dispatch(expandPublicTimeline({ maxId, onlyMedia }));
|
||||
}
|
||||
|
||||
handleHeadlineLinkClick = e => {
|
||||
const { columnId, dispatch } = this.props;
|
||||
const onlyMedia = /\/media$/.test(e.currentTarget.href);
|
||||
|
||||
dispatch(changeColumnParams(columnId, { other: { onlyMedia } }));
|
||||
}
|
||||
|
||||
render () {
|
||||
const { intl, columnId, hasUnread, multiColumn } = this.props;
|
||||
const { intl, columnId, hasUnread, multiColumn, onlyMedia } = this.props;
|
||||
const pinned = !!columnId;
|
||||
|
||||
const headline = (
|
||||
<SectionHeadline
|
||||
timelineId='public'
|
||||
to='/timelines/public'
|
||||
pinned={pinned}
|
||||
onlyMedia={onlyMedia}
|
||||
onClick={this.handleHeadlineLinkClick}
|
||||
/>
|
||||
);
|
||||
|
||||
return (
|
||||
<Column ref={this.setRef}>
|
||||
<ColumnHeader
|
||||
|
|
@ -91,7 +126,9 @@ export default class PublicTimeline extends React.PureComponent {
|
|||
</ColumnHeader>
|
||||
|
||||
<StatusListContainer
|
||||
timelineId='public'
|
||||
prepend={headline}
|
||||
alwaysPrepend
|
||||
timelineId={`public${onlyMedia ? ':media' : ''}`}
|
||||
onLoadMore={this.handleLoadMore}
|
||||
trackScroll={!pinned}
|
||||
scrollKey={`public_timeline-${columnId}`}
|
||||
|
|
|
|||
|
|
@ -8,9 +8,13 @@ import { me } from '../../../initial_state';
|
|||
|
||||
const messages = defineMessages({
|
||||
delete: { id: 'status.delete', defaultMessage: 'Delete' },
|
||||
redraft: { id: 'status.redraft', defaultMessage: 'Delete & re-draft' },
|
||||
direct: { id: 'status.direct', defaultMessage: 'Direct message @{name}' },
|
||||
mention: { id: 'status.mention', defaultMessage: 'Mention @{name}' },
|
||||
reply: { id: 'status.reply', defaultMessage: 'Reply' },
|
||||
reblog: { id: 'status.reblog', defaultMessage: 'Boost' },
|
||||
reblog_private: { id: 'status.reblog_private', defaultMessage: 'Boost to original audience' },
|
||||
cancel_reblog_private: { id: 'status.cancel_reblog_private', defaultMessage: 'Unboost' },
|
||||
cannot_reblog: { id: 'status.cannot_reblog', defaultMessage: 'This post cannot be boosted' },
|
||||
favourite: { id: 'status.favourite', defaultMessage: 'Favourite' },
|
||||
mute: { id: 'status.mute', defaultMessage: 'Mute @{name}' },
|
||||
|
|
@ -37,6 +41,7 @@ export default class ActionBar extends React.PureComponent {
|
|||
onReblog: PropTypes.func.isRequired,
|
||||
onFavourite: PropTypes.func.isRequired,
|
||||
onDelete: PropTypes.func.isRequired,
|
||||
onDirect: PropTypes.func.isRequired,
|
||||
onMention: PropTypes.func.isRequired,
|
||||
onMute: PropTypes.func,
|
||||
onMuteConversation: PropTypes.func,
|
||||
|
|
@ -63,6 +68,14 @@ export default class ActionBar extends React.PureComponent {
|
|||
this.props.onDelete(this.props.status);
|
||||
}
|
||||
|
||||
handleRedraftClick = () => {
|
||||
this.props.onDelete(this.props.status, true);
|
||||
}
|
||||
|
||||
handleDirectClick = () => {
|
||||
this.props.onDirect(this.props.status.get('account'), this.context.router.history);
|
||||
}
|
||||
|
||||
handleMentionClick = () => {
|
||||
this.props.onMention(this.props.status.get('account'), this.context.router.history);
|
||||
}
|
||||
|
|
@ -108,19 +121,26 @@ export default class ActionBar extends React.PureComponent {
|
|||
|
||||
if (publicStatus) {
|
||||
menu.push({ text: intl.formatMessage(messages.embed), action: this.handleEmbed });
|
||||
menu.push(null);
|
||||
}
|
||||
|
||||
if (me === status.getIn(['account', 'id'])) {
|
||||
if (publicStatus) {
|
||||
menu.push({ text: intl.formatMessage(status.get('pinned') ? messages.unpin : messages.pin), action: this.handlePinClick });
|
||||
} else {
|
||||
if (status.get('visibility') === 'private') {
|
||||
menu.push({ text: intl.formatMessage(status.get('reblogged') ? messages.cancel_reblog_private : messages.reblog_private), action: this.handleReblogClick });
|
||||
}
|
||||
}
|
||||
|
||||
menu.push(null);
|
||||
menu.push({ text: intl.formatMessage(mutingConversation ? messages.unmuteConversation : messages.muteConversation), action: this.handleConversationMuteClick });
|
||||
menu.push(null);
|
||||
menu.push({ text: intl.formatMessage(messages.delete), action: this.handleDeleteClick });
|
||||
menu.push({ text: intl.formatMessage(messages.redraft), action: this.handleRedraftClick });
|
||||
} else {
|
||||
menu.push({ text: intl.formatMessage(messages.mention, { name: status.getIn(['account', 'username']) }), action: this.handleMentionClick });
|
||||
menu.push({ text: intl.formatMessage(messages.direct, { name: status.getIn(['account', 'username']) }), action: this.handleDirectClick });
|
||||
menu.push(null);
|
||||
menu.push({ text: intl.formatMessage(messages.mute, { name: status.getIn(['account', 'username']) }), action: this.handleMuteClick });
|
||||
menu.push({ text: intl.formatMessage(messages.block, { name: status.getIn(['account', 'username']) }), action: this.handleBlockClick });
|
||||
|
|
@ -141,7 +161,7 @@ export default class ActionBar extends React.PureComponent {
|
|||
<div className='detailed-status__action-bar'>
|
||||
<div className='detailed-status__button'><IconButton title={intl.formatMessage(messages.reply)} icon={status.get('in_reply_to_id', null) === null ? 'reply' : 'reply-all'} onClick={this.handleReplyClick} /></div>
|
||||
<div className='detailed-status__button'><IconButton disabled={reblog_disabled} active={status.get('reblogged')} title={reblog_disabled ? intl.formatMessage(messages.cannot_reblog) : intl.formatMessage(messages.reblog)} icon={reblogIcon} onClick={this.handleReblogClick} /></div>
|
||||
<div className='detailed-status__button'><IconButton animate active={status.get('favourited')} title={intl.formatMessage(messages.favourite)} icon='star' onClick={this.handleFavouriteClick} activeStyle={{ color: '#ca8f04' }} /></div>
|
||||
<div className='detailed-status__button'><IconButton className='star-icon' animate active={status.get('favourited')} title={intl.formatMessage(messages.favourite)} icon='star' onClick={this.handleFavouriteClick} /></div>
|
||||
{shareButton}
|
||||
|
||||
<div className='detailed-status__action-bar-dropdown'>
|
||||
|
|
|
|||
|
|
@ -34,8 +34,8 @@ export default class DetailedStatus extends ImmutablePureComponent {
|
|||
e.stopPropagation();
|
||||
}
|
||||
|
||||
handleOpenVideo = startTime => {
|
||||
this.props.onOpenVideo(this.props.status.getIn(['media_attachments', 0]), startTime);
|
||||
handleOpenVideo = (media, startTime) => {
|
||||
this.props.onOpenVideo(media, startTime);
|
||||
}
|
||||
|
||||
handleExpandedToggle = () => {
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
import Immutable from 'immutable';
|
||||
import React from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
import PropTypes from 'prop-types';
|
||||
|
|
@ -19,6 +20,7 @@ import {
|
|||
import {
|
||||
replyCompose,
|
||||
mentionCompose,
|
||||
directCompose,
|
||||
} from '../../actions/compose';
|
||||
import { blockAccount } from '../../actions/accounts';
|
||||
import {
|
||||
|
|
@ -45,6 +47,8 @@ import { attachFullscreenListener, detachFullscreenListener, isFullscreen } from
|
|||
const messages = defineMessages({
|
||||
deleteConfirm: { id: 'confirmations.delete.confirm', defaultMessage: 'Delete' },
|
||||
deleteMessage: { id: 'confirmations.delete.message', defaultMessage: 'Are you sure you want to delete this status?' },
|
||||
redraftConfirm: { id: 'confirmations.redraft.confirm', defaultMessage: 'Delete & redraft' },
|
||||
redraftMessage: { id: 'confirmations.redraft.message', defaultMessage: 'Are you sure you want to delete this status and re-draft it? You will lose all replies, boosts and favourites to it.' },
|
||||
blockConfirm: { id: 'confirmations.block.confirm', defaultMessage: 'Block' },
|
||||
revealAll: { id: 'status.show_more_all', defaultMessage: 'Show more for all' },
|
||||
hideAll: { id: 'status.show_less_all', defaultMessage: 'Show less for all' },
|
||||
|
|
@ -53,11 +57,47 @@ const messages = defineMessages({
|
|||
const makeMapStateToProps = () => {
|
||||
const getStatus = makeGetStatus();
|
||||
|
||||
const mapStateToProps = (state, props) => ({
|
||||
status: getStatus(state, props.params.statusId),
|
||||
ancestorsIds: state.getIn(['contexts', 'ancestors', props.params.statusId]),
|
||||
descendantsIds: state.getIn(['contexts', 'descendants', props.params.statusId]),
|
||||
});
|
||||
const mapStateToProps = (state, props) => {
|
||||
const status = getStatus(state, props.params.statusId);
|
||||
let ancestorsIds = Immutable.List();
|
||||
let descendantsIds = Immutable.List();
|
||||
|
||||
if (status) {
|
||||
ancestorsIds = ancestorsIds.withMutations(mutable => {
|
||||
let id = status.get('in_reply_to_id');
|
||||
|
||||
while (id) {
|
||||
mutable.unshift(id);
|
||||
id = state.getIn(['contexts', 'inReplyTos', id]);
|
||||
}
|
||||
});
|
||||
|
||||
descendantsIds = descendantsIds.withMutations(mutable => {
|
||||
const ids = [status.get('id')];
|
||||
|
||||
while (ids.length > 0) {
|
||||
let id = ids.shift();
|
||||
const replies = state.getIn(['contexts', 'replies', id]);
|
||||
|
||||
if (status.get('id') !== id) {
|
||||
mutable.push(id);
|
||||
}
|
||||
|
||||
if (replies) {
|
||||
replies.reverse().forEach(reply => {
|
||||
ids.unshift(reply);
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return {
|
||||
status,
|
||||
ancestorsIds,
|
||||
descendantsIds,
|
||||
};
|
||||
};
|
||||
|
||||
return mapStateToProps;
|
||||
};
|
||||
|
|
@ -134,20 +174,24 @@ export default class Status extends ImmutablePureComponent {
|
|||
}
|
||||
}
|
||||
|
||||
handleDeleteClick = (status) => {
|
||||
handleDeleteClick = (status, withRedraft = false) => {
|
||||
const { dispatch, intl } = this.props;
|
||||
|
||||
if (!deleteModal) {
|
||||
dispatch(deleteStatus(status.get('id')));
|
||||
dispatch(deleteStatus(status.get('id'), withRedraft));
|
||||
} else {
|
||||
dispatch(openModal('CONFIRM', {
|
||||
message: intl.formatMessage(messages.deleteMessage),
|
||||
confirm: intl.formatMessage(messages.deleteConfirm),
|
||||
onConfirm: () => dispatch(deleteStatus(status.get('id'))),
|
||||
message: intl.formatMessage(withRedraft ? messages.redraftMessage : messages.deleteMessage),
|
||||
confirm: intl.formatMessage(withRedraft ? messages.redraftConfirm : messages.deleteConfirm),
|
||||
onConfirm: () => dispatch(deleteStatus(status.get('id'), withRedraft)),
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
handleDirectClick = (account, router) => {
|
||||
this.props.dispatch(directCompose(account, router));
|
||||
}
|
||||
|
||||
handleMentionClick = (account, router) => {
|
||||
this.props.dispatch(mentionCompose(account, router));
|
||||
}
|
||||
|
|
@ -239,6 +283,10 @@ export default class Status extends ImmutablePureComponent {
|
|||
this.context.router.history.push(`/accounts/${this.props.status.getIn(['account', 'id'])}`);
|
||||
}
|
||||
|
||||
handleHotkeyToggleHidden = () => {
|
||||
this.handleToggleHidden(this.props.status);
|
||||
}
|
||||
|
||||
handleMoveUp = id => {
|
||||
const { status, ancestorsIds, descendantsIds } = this.props;
|
||||
|
||||
|
|
@ -349,6 +397,7 @@ export default class Status extends ImmutablePureComponent {
|
|||
boost: this.handleHotkeyBoost,
|
||||
mention: this.handleHotkeyMention,
|
||||
openProfile: this.handleHotkeyOpenProfile,
|
||||
toggleHidden: this.handleHotkeyToggleHidden,
|
||||
};
|
||||
|
||||
return (
|
||||
|
|
@ -379,6 +428,7 @@ export default class Status extends ImmutablePureComponent {
|
|||
onFavourite={this.handleFavouriteClick}
|
||||
onReblog={this.handleReblogClick}
|
||||
onDelete={this.handleDeleteClick}
|
||||
onDirect={this.handleDirectClick}
|
||||
onMention={this.handleMentionClick}
|
||||
onMute={this.handleMuteClick}
|
||||
onMuteConversation={this.handleConversationMuteClick}
|
||||
|
|
|
|||
66
app/javascript/mastodon/features/trends/index.js
Normal file
66
app/javascript/mastodon/features/trends/index.js
Normal file
|
|
@ -0,0 +1,66 @@
|
|||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import ImmutablePropTypes from 'react-immutable-proptypes';
|
||||
import ImmutablePureComponent from 'react-immutable-pure-component';
|
||||
import { connect } from 'react-redux';
|
||||
import { injectIntl, defineMessages } from 'react-intl';
|
||||
import Column from '../ui/components/column';
|
||||
import ColumnHeader from '../../components/column_header';
|
||||
import Hashtag from '../../components/hashtag';
|
||||
import classNames from 'classnames';
|
||||
import { fetchTrends } from '../../actions/trends';
|
||||
|
||||
const messages = defineMessages({
|
||||
title: { id: 'trends.header', defaultMessage: 'Trending now' },
|
||||
refreshTrends: { id: 'trends.refresh', defaultMessage: 'Refresh trends' },
|
||||
});
|
||||
|
||||
const mapStateToProps = state => ({
|
||||
trends: state.getIn(['trends', 'items']),
|
||||
loading: state.getIn(['trends', 'isLoading']),
|
||||
});
|
||||
|
||||
const mapDispatchToProps = dispatch => ({
|
||||
fetchTrends: () => dispatch(fetchTrends()),
|
||||
});
|
||||
|
||||
@connect(mapStateToProps, mapDispatchToProps)
|
||||
@injectIntl
|
||||
export default class Trends extends ImmutablePureComponent {
|
||||
|
||||
static propTypes = {
|
||||
intl: PropTypes.object.isRequired,
|
||||
trends: ImmutablePropTypes.list,
|
||||
fetchTrends: PropTypes.func.isRequired,
|
||||
loading: PropTypes.bool,
|
||||
};
|
||||
|
||||
componentDidMount () {
|
||||
this.props.fetchTrends();
|
||||
}
|
||||
|
||||
handleRefresh = () => {
|
||||
this.props.fetchTrends();
|
||||
}
|
||||
|
||||
render () {
|
||||
const { trends, loading, intl } = this.props;
|
||||
|
||||
return (
|
||||
<Column>
|
||||
<ColumnHeader
|
||||
icon='fire'
|
||||
title={intl.formatMessage(messages.title)}
|
||||
extraButton={(
|
||||
<button className='column-header__button' title={intl.formatMessage(messages.refreshTrends)} aria-label={intl.formatMessage(messages.refreshTrends)} onClick={this.handleRefresh}><i className={classNames('fa', 'fa-refresh', { 'fa-spin': loading })} /></button>
|
||||
)}
|
||||
/>
|
||||
|
||||
<div className='scrollable'>
|
||||
{trends && trends.map(hashtag => <Hashtag key={hashtag.get('name')} hashtag={hashtag} />)}
|
||||
</div>
|
||||
</Column>
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -27,7 +27,7 @@ export default class ActionsModal extends ImmutablePureComponent {
|
|||
return (
|
||||
<li key={`${text}-${i}`}>
|
||||
<a href={href} target='_blank' rel='noopener' onClick={this.props.onClick} data-index={i} className={classNames({ active })}>
|
||||
{icon && <IconButton title={text} icon={icon} role='presentation' tabIndex='-1' />}
|
||||
{icon && <IconButton title={text} icon={icon} role='presentation' tabIndex='-1' inverted />}
|
||||
<div>
|
||||
<div className={classNames({ 'actions-modal__item-label': !!meta })}>{text}</div>
|
||||
<div>{meta}</div>
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ import BundleContainer from '../containers/bundle_container';
|
|||
import ColumnLoading from './column_loading';
|
||||
import DrawerLoading from './drawer_loading';
|
||||
import BundleColumnError from './bundle_column_error';
|
||||
import { Compose, Notifications, HomeTimeline, CommunityTimeline, PublicTimeline, HashtagTimeline, FavouritedStatuses, ListTimeline } from '../../ui/util/async-components';
|
||||
import { Compose, Notifications, HomeTimeline, CommunityTimeline, PublicTimeline, HashtagTimeline, DirectTimeline, FavouritedStatuses, ListTimeline } from '../../ui/util/async-components';
|
||||
|
||||
import detectPassiveEvents from 'detect-passive-events';
|
||||
import { scrollRight } from '../../../scroll';
|
||||
|
|
@ -24,6 +24,7 @@ const componentMap = {
|
|||
'PUBLIC': PublicTimeline,
|
||||
'COMMUNITY': CommunityTimeline,
|
||||
'HASHTAG': HashtagTimeline,
|
||||
'DIRECT': DirectTimeline,
|
||||
'FAVOURITES': FavouritedStatuses,
|
||||
'LIST': ListTimeline,
|
||||
};
|
||||
|
|
@ -174,10 +175,11 @@ export default class ColumnsArea extends ImmutablePureComponent {
|
|||
<div className={`columns-area ${ isModalOpen ? 'unscrollable' : '' }`} ref={this.setRef}>
|
||||
{columns.map(column => {
|
||||
const params = column.get('params', null) === null ? null : column.get('params').toJS();
|
||||
const other = params && params.other ? params.other : {};
|
||||
|
||||
return (
|
||||
<BundleContainer key={column.get('uuid')} fetchComponent={componentMap[column.get('id')]} loading={this.renderLoading(column.get('id'))} error={this.renderError}>
|
||||
{SpecificComponent => <SpecificComponent columnId={column.get('uuid')} params={params} multiColumn />}
|
||||
{SpecificComponent => <SpecificComponent columnId={column.get('uuid')} params={params} multiColumn {...other} />}
|
||||
</BundleContainer>
|
||||
);
|
||||
})}
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ export default class EmbedModal extends ImmutablePureComponent {
|
|||
static propTypes = {
|
||||
url: PropTypes.string.isRequired,
|
||||
onClose: PropTypes.func.isRequired,
|
||||
onError: PropTypes.func.isRequired,
|
||||
intl: PropTypes.object.isRequired,
|
||||
}
|
||||
|
||||
|
|
@ -35,6 +36,8 @@ export default class EmbedModal extends ImmutablePureComponent {
|
|||
iframeDocument.body.style.margin = 0;
|
||||
this.iframe.width = iframeDocument.body.scrollWidth;
|
||||
this.iframe.height = iframeDocument.body.scrollHeight;
|
||||
}).catch(error => {
|
||||
this.props.onError(error);
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ import React from 'react';
|
|||
import ReactSwipeableViews from 'react-swipeable-views';
|
||||
import ImmutablePropTypes from 'react-immutable-proptypes';
|
||||
import PropTypes from 'prop-types';
|
||||
import Video from '../../video';
|
||||
import ExtendedVideoPlayer from '../../../components/extended_video_player';
|
||||
import classNames from 'classnames';
|
||||
import { defineMessages, injectIntl } from 'react-intl';
|
||||
|
|
@ -112,6 +113,22 @@ export default class MediaModal extends ImmutablePureComponent {
|
|||
onClick={this.toggleNavigation}
|
||||
/>
|
||||
);
|
||||
} else if (image.get('type') === 'video') {
|
||||
const { time } = this.props;
|
||||
|
||||
return (
|
||||
<Video
|
||||
preview={image.get('preview_url')}
|
||||
src={image.get('url')}
|
||||
width={image.get('width')}
|
||||
height={image.get('height')}
|
||||
startTime={time || 0}
|
||||
onCloseVideo={onClose}
|
||||
detailed
|
||||
description={image.get('description')}
|
||||
key={image.get('url')}
|
||||
/>
|
||||
);
|
||||
} else if (image.get('type') === 'gifv') {
|
||||
return (
|
||||
<ExtendedVideoPlayer
|
||||
|
|
|
|||
|
|
@ -40,6 +40,17 @@ export default class ModalRoot extends React.PureComponent {
|
|||
onClose: PropTypes.func.isRequired,
|
||||
};
|
||||
|
||||
getSnapshotBeforeUpdate () {
|
||||
const visible = !!this.props.type;
|
||||
return {
|
||||
overflowY: visible ? 'hidden' : null,
|
||||
};
|
||||
}
|
||||
|
||||
componentDidUpdate (prevProps, prevState, { overflowY }) {
|
||||
document.body.style.overflowY = overflowY;
|
||||
}
|
||||
|
||||
renderLoading = modalId => () => {
|
||||
return ['MEDIA', 'VIDEO', 'BOOST', 'CONFIRM', 'ACTIONS'].indexOf(modalId) === -1 ? <ModalLoading /> : null;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@ const makeMapStateToProps = () => {
|
|||
account: getAccount(state, accountId),
|
||||
comment: state.getIn(['reports', 'new', 'comment']),
|
||||
forward: state.getIn(['reports', 'new', 'forward']),
|
||||
statusIds: OrderedSet(state.getIn(['timelines', `account:${accountId}`, 'items'])).union(state.getIn(['reports', 'new', 'status_ids'])),
|
||||
statusIds: OrderedSet(state.getIn(['timelines', `account:${accountId}:with_replies`, 'items'])).union(state.getIn(['reports', 'new', 'status_ids'])),
|
||||
};
|
||||
};
|
||||
|
||||
|
|
@ -63,13 +63,19 @@ export default class ReportModal extends ImmutablePureComponent {
|
|||
this.props.dispatch(submitReport());
|
||||
}
|
||||
|
||||
handleKeyDown = e => {
|
||||
if (e.keyCode === 13 && (e.ctrlKey || e.metaKey)) {
|
||||
this.handleSubmit();
|
||||
}
|
||||
}
|
||||
|
||||
componentDidMount () {
|
||||
this.props.dispatch(expandAccountTimeline(this.props.account.get('id')));
|
||||
this.props.dispatch(expandAccountTimeline(this.props.account.get('id'), { withReplies: true }));
|
||||
}
|
||||
|
||||
componentWillReceiveProps (nextProps) {
|
||||
if (this.props.account !== nextProps.account && nextProps.account) {
|
||||
this.props.dispatch(expandAccountTimeline(nextProps.account.get('id')));
|
||||
this.props.dispatch(expandAccountTimeline(nextProps.account.get('id'), { withReplies: true }));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -98,6 +104,7 @@ export default class ReportModal extends ImmutablePureComponent {
|
|||
placeholder={intl.formatMessage(messages.placeholder)}
|
||||
value={comment}
|
||||
onChange={this.handleCommentChange}
|
||||
onKeyDown={this.handleKeyDown}
|
||||
disabled={isSubmitting}
|
||||
/>
|
||||
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ import { isUserTouching } from '../../../is_mobile';
|
|||
export const links = [
|
||||
<NavLink className='tabs-bar__link primary' to='/timelines/home' data-preview-title-id='column.home' data-preview-icon='home' ><i className='fa fa-fw fa-home' /><FormattedMessage id='tabs_bar.home' defaultMessage='Home' /></NavLink>,
|
||||
<NavLink className='tabs-bar__link primary' to='/notifications' data-preview-title-id='column.notifications' data-preview-icon='bell' ><i className='fa fa-fw fa-bell' /><FormattedMessage id='tabs_bar.notifications' defaultMessage='Notifications' /></NavLink>,
|
||||
<NavLink className='tabs-bar__link primary' to='/search' data-preview-title-id='tabs_bar.search' data-preview-icon='bell' ><i className='fa fa-fw fa-search' /><FormattedMessage id='tabs_bar.search' defaultMessage='Search' /></NavLink>,
|
||||
|
||||
<NavLink className='tabs-bar__link secondary' to='/timelines/public/local' data-preview-title-id='column.community' data-preview-icon='users' ><i className='fa fa-fw fa-users' /><FormattedMessage id='tabs_bar.local_timeline' defaultMessage='Local' /></NavLink>,
|
||||
<NavLink className='tabs-bar__link secondary' exact to='/timelines/public' data-preview-title-id='column.public' data-preview-icon='globe' ><i className='fa fa-fw fa-globe' /><FormattedMessage id='tabs_bar.federated_timeline' defaultMessage='Federated' /></NavLink>,
|
||||
|
|
|
|||
|
|
@ -21,6 +21,8 @@ const makeGetStatusIds = () => createSelector([
|
|||
}
|
||||
|
||||
return statusIds.filter(id => {
|
||||
if (id === null) return true;
|
||||
|
||||
const statusForId = statuses.get(id);
|
||||
let showStatus = true;
|
||||
|
||||
|
|
|
|||
|
|
@ -30,6 +30,7 @@ import {
|
|||
Following,
|
||||
Reblogs,
|
||||
Favourites,
|
||||
DirectTimeline,
|
||||
HashtagTimeline,
|
||||
Notifications,
|
||||
FollowRequests,
|
||||
|
|
@ -37,6 +38,7 @@ import {
|
|||
FavouritedStatuses,
|
||||
ListTimeline,
|
||||
Blocks,
|
||||
DomainBlocks,
|
||||
Mutes,
|
||||
PinnedStatuses,
|
||||
Lists,
|
||||
|
|
@ -78,12 +80,14 @@ const keyMap = {
|
|||
goToNotifications: 'g n',
|
||||
goToLocal: 'g l',
|
||||
goToFederated: 'g t',
|
||||
goToDirect: 'g d',
|
||||
goToStart: 'g s',
|
||||
goToFavourites: 'g f',
|
||||
goToPinned: 'g p',
|
||||
goToProfile: 'g u',
|
||||
goToBlocked: 'g b',
|
||||
goToMuted: 'g m',
|
||||
toggleHidden: 'x',
|
||||
};
|
||||
|
||||
class SwitchingColumnsArea extends React.PureComponent {
|
||||
|
|
@ -128,16 +132,20 @@ class SwitchingColumnsArea extends React.PureComponent {
|
|||
render () {
|
||||
const { children } = this.props;
|
||||
const { mobile } = this.state;
|
||||
const redirect = mobile ? <Redirect from='/' to='/timelines/home' exact /> : <Redirect from='/' to='/getting-started' exact />;
|
||||
|
||||
return (
|
||||
<ColumnsAreaContainer ref={this.setRef} singleColumn={mobile}>
|
||||
<WrappedSwitch>
|
||||
<Redirect from='/' to='/getting-started' exact />
|
||||
{redirect}
|
||||
<WrappedRoute path='/getting-started' component={GettingStarted} content={children} />
|
||||
<WrappedRoute path='/keyboard-shortcuts' component={KeyboardShortcuts} content={children} />
|
||||
<WrappedRoute path='/timelines/home' component={HomeTimeline} content={children} />
|
||||
<WrappedRoute path='/timelines/public' exact component={PublicTimeline} content={children} />
|
||||
<WrappedRoute path='/timelines/public/local' component={CommunityTimeline} content={children} />
|
||||
<WrappedRoute path='/timelines/public/media' component={PublicTimeline} content={children} componentParams={{ onlyMedia: true }} />
|
||||
<WrappedRoute path='/timelines/public/local' exact component={CommunityTimeline} content={children} />
|
||||
<WrappedRoute path='/timelines/public/local/media' component={CommunityTimeline} content={children} componentParams={{ onlyMedia: true }} />
|
||||
<WrappedRoute path='/timelines/direct' component={DirectTimeline} content={children} />
|
||||
<WrappedRoute path='/timelines/tag/:id' component={HashtagTimeline} content={children} />
|
||||
<WrappedRoute path='/timelines/list/:id' component={ListTimeline} content={children} />
|
||||
|
||||
|
|
@ -145,6 +153,8 @@ class SwitchingColumnsArea extends React.PureComponent {
|
|||
<WrappedRoute path='/favourites' component={FavouritedStatuses} content={children} />
|
||||
<WrappedRoute path='/pinned' component={PinnedStatuses} content={children} />
|
||||
|
||||
<WrappedRoute path='/search' component={Compose} content={children} componentParams={{ isSearchPage: true }} />
|
||||
|
||||
<WrappedRoute path='/statuses/new' component={Compose} content={children} />
|
||||
<WrappedRoute path='/statuses/:statusId' exact component={Status} content={children} />
|
||||
<WrappedRoute path='/statuses/:statusId/reblogs' component={Reblogs} content={children} />
|
||||
|
|
@ -158,6 +168,7 @@ class SwitchingColumnsArea extends React.PureComponent {
|
|||
|
||||
<WrappedRoute path='/follow_requests' component={FollowRequests} content={children} />
|
||||
<WrappedRoute path='/blocks' component={Blocks} content={children} />
|
||||
<WrappedRoute path='/domain_blocks' component={DomainBlocks} content={children} />
|
||||
<WrappedRoute path='/mutes' component={Mutes} content={children} />
|
||||
<WrappedRoute path='/lists' component={Lists} content={children} />
|
||||
|
||||
|
|
@ -381,6 +392,10 @@ export default class UI extends React.PureComponent {
|
|||
this.context.router.history.push('/timelines/public');
|
||||
}
|
||||
|
||||
handleHotkeyGoToDirect = () => {
|
||||
this.context.router.history.push('/timelines/direct');
|
||||
}
|
||||
|
||||
handleHotkeyGoToStart = () => {
|
||||
this.context.router.history.push('/getting-started');
|
||||
}
|
||||
|
|
@ -420,6 +435,7 @@ export default class UI extends React.PureComponent {
|
|||
goToNotifications: this.handleHotkeyGoToNotifications,
|
||||
goToLocal: this.handleHotkeyGoToLocal,
|
||||
goToFederated: this.handleHotkeyGoToFederated,
|
||||
goToDirect: this.handleHotkeyGoToDirect,
|
||||
goToStart: this.handleHotkeyGoToStart,
|
||||
goToFavourites: this.handleHotkeyGoToFavourites,
|
||||
goToPinned: this.handleHotkeyGoToPinned,
|
||||
|
|
|
|||
|
|
@ -26,6 +26,10 @@ export function HashtagTimeline () {
|
|||
return import(/* webpackChunkName: "features/hashtag_timeline" */'../../hashtag_timeline');
|
||||
}
|
||||
|
||||
export function DirectTimeline() {
|
||||
return import(/* webpackChunkName: "features/direct_timeline" */'../../direct_timeline');
|
||||
}
|
||||
|
||||
export function ListTimeline () {
|
||||
return import(/* webpackChunkName: "features/list_timeline" */'../../list_timeline');
|
||||
}
|
||||
|
|
@ -90,6 +94,10 @@ export function Blocks () {
|
|||
return import(/* webpackChunkName: "features/blocks" */'../../blocks');
|
||||
}
|
||||
|
||||
export function DomainBlocks () {
|
||||
return import(/* webpackChunkName: "features/domain_blocks" */'../../domain_blocks');
|
||||
}
|
||||
|
||||
export function Mutes () {
|
||||
return import(/* webpackChunkName: "features/mutes" */'../../mutes');
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
|
||||
import { fromJS } from 'immutable';
|
||||
import { throttle } from 'lodash';
|
||||
import classNames from 'classnames';
|
||||
import { isFullscreen, requestFullscreen, exitFullscreen } from '../ui/util/fullscreen';
|
||||
|
|
@ -131,6 +132,8 @@ export default class Video extends React.PureComponent {
|
|||
this.seek = c;
|
||||
}
|
||||
|
||||
handleClickRoot = e => e.stopPropagation();
|
||||
|
||||
handlePlay = () => {
|
||||
this.setState({ paused: false });
|
||||
}
|
||||
|
|
@ -244,8 +247,17 @@ export default class Video extends React.PureComponent {
|
|||
}
|
||||
|
||||
handleOpenVideo = () => {
|
||||
const { src, preview, width, height } = this.props;
|
||||
const media = fromJS({
|
||||
type: 'video',
|
||||
url: src,
|
||||
preview_url: preview,
|
||||
width,
|
||||
height,
|
||||
});
|
||||
|
||||
this.video.pause();
|
||||
this.props.onOpenVideo(this.video.currentTime);
|
||||
this.props.onOpenVideo(media, this.video.currentTime);
|
||||
}
|
||||
|
||||
handleCloseVideo = () => {
|
||||
|
|
@ -270,7 +282,16 @@ export default class Video extends React.PureComponent {
|
|||
}
|
||||
|
||||
return (
|
||||
<div className={classNames('video-player', { inactive: !revealed, detailed, inline: inline && !fullscreen, fullscreen })} style={playerStyle} ref={this.setPlayerRef} onMouseEnter={this.handleMouseEnter} onMouseLeave={this.handleMouseLeave}>
|
||||
<div
|
||||
role='menuitem'
|
||||
className={classNames('video-player', { inactive: !revealed, detailed, inline: inline && !fullscreen, fullscreen })}
|
||||
style={playerStyle}
|
||||
ref={this.setPlayerRef}
|
||||
onMouseEnter={this.handleMouseEnter}
|
||||
onMouseLeave={this.handleMouseLeave}
|
||||
onClick={this.handleClickRoot}
|
||||
tabIndex={0}
|
||||
>
|
||||
<video
|
||||
ref={this.setVideoRef}
|
||||
src={src}
|
||||
|
|
|
|||
|
|
@ -12,12 +12,13 @@ function importExtraPolyfills() {
|
|||
|
||||
function loadPolyfills() {
|
||||
const needsBasePolyfills = !(
|
||||
Array.prototype.includes &&
|
||||
HTMLCanvasElement.prototype.toBlob &&
|
||||
window.Intl &&
|
||||
Number.isNaN &&
|
||||
Object.assign &&
|
||||
Object.values &&
|
||||
Number.isNaN &&
|
||||
window.Symbol &&
|
||||
Array.prototype.includes
|
||||
window.Symbol
|
||||
);
|
||||
|
||||
// Latest version of Firefox and Safari do not have IntersectionObserver.
|
||||
|
|
|
|||
|
|
@ -1,7 +1,9 @@
|
|||
{
|
||||
"account.badges.bot": "روبوت",
|
||||
"account.block": "حظر @{name}",
|
||||
"account.block_domain": "إخفاء كل شيئ قادم من إسم النطاق {domain}",
|
||||
"account.blocked": "محظور",
|
||||
"account.direct": "رسالة خاصة إلى @{name}",
|
||||
"account.disclaimer_full": "قد لا تعكس المعلومات أدناه الملف الشخصي الكامل للمستخدم.",
|
||||
"account.domain_blocked": "النطاق مخفي",
|
||||
"account.edit_profile": "تعديل الملف الشخصي",
|
||||
|
|
@ -17,7 +19,7 @@
|
|||
"account.mute_notifications": "كتم إخطارات @{name}",
|
||||
"account.muted": "مكتوم",
|
||||
"account.posts": "التبويقات",
|
||||
"account.posts_with_replies": "تبويقات تحتوي على رُدود",
|
||||
"account.posts_with_replies": "التبويقات و الردود",
|
||||
"account.report": "أبلغ عن @{name}",
|
||||
"account.requested": "في انتظار الموافقة",
|
||||
"account.share": "مشاركة @{name}'s profile",
|
||||
|
|
@ -28,8 +30,8 @@
|
|||
"account.unmute": "إلغاء الكتم عن @{name}",
|
||||
"account.unmute_notifications": "إلغاء كتم إخطارات @{name}",
|
||||
"account.view_full_profile": "عرض الملف الشخصي كاملا",
|
||||
"alert.unexpected.message": "An unexpected error occurred.",
|
||||
"alert.unexpected.title": "Oops!",
|
||||
"alert.unexpected.message": "لقد طرأ هناك خطأ غير متوقّع.",
|
||||
"alert.unexpected.title": "المعذرة !",
|
||||
"boost_modal.combo": "يمكنك ضغط {combo} لتخطّي هذه في المرّة القادمة",
|
||||
"bundle_column_error.body": "لقد وقع هناك خطأ أثناء عملية تحميل هذا العنصر.",
|
||||
"bundle_column_error.retry": "إعادة المحاولة",
|
||||
|
|
@ -39,6 +41,8 @@
|
|||
"bundle_modal_error.retry": "إعادة المحاولة",
|
||||
"column.blocks": "الحسابات المحجوبة",
|
||||
"column.community": "الخيط العام المحلي",
|
||||
"column.direct": "الرسائل المباشرة",
|
||||
"column.domain_blocks": "النطاقات المخفية",
|
||||
"column.favourites": "المفضلة",
|
||||
"column.follow_requests": "طلبات المتابعة",
|
||||
"column.home": "الرئيسية",
|
||||
|
|
@ -54,8 +58,9 @@
|
|||
"column_header.pin": "تدبيس",
|
||||
"column_header.show_settings": "عرض الإعدادات",
|
||||
"column_header.unpin": "فك التدبيس",
|
||||
"column_subheading.navigation": "التصفح",
|
||||
"column_subheading.settings": "الإعدادات",
|
||||
"compose_form.direct_message_warning": "لن يَظهر هذا التبويق إلا للمستخدمين المذكورين.",
|
||||
"compose_form.direct_message_warning_learn_more": "Learn more",
|
||||
"compose_form.hashtag_warning": "هذا التبويق لن يُدرَج تحت أي وسم كان بما أنه غير مُدرَج. لا يُسمح بالبحث إلّا عن التبويقات العمومية عن طريق الوسوم.",
|
||||
"compose_form.lock_disclaimer": "حسابك ليس {locked}. يمكن لأي شخص متابعتك و عرض المنشورات.",
|
||||
"compose_form.lock_disclaimer.lock": "مقفل",
|
||||
|
|
@ -63,7 +68,7 @@
|
|||
"compose_form.publish": "بوّق",
|
||||
"compose_form.publish_loud": "{publish}!",
|
||||
"compose_form.sensitive.marked": "لقد تم تحديد هذه الصورة كحساسة",
|
||||
"compose_form.sensitive.unmarked": "Media is not marked as sensitive",
|
||||
"compose_form.sensitive.unmarked": "لم يتم تحديد الصورة كحساسة",
|
||||
"compose_form.spoiler.marked": "إنّ النص مخفي وراء تحذير",
|
||||
"compose_form.spoiler.unmarked": "النص غير مخفي",
|
||||
"compose_form.spoiler_placeholder": "تنبيه عن المحتوى",
|
||||
|
|
@ -78,6 +83,8 @@
|
|||
"confirmations.domain_block.message": "متأكد من أنك تود حظر إسم النطاق {domain} بالكامل ؟ في غالب الأحيان يُستَحسَن كتم أو حظر بعض الحسابات بدلا من حظر نطاق بالكامل.",
|
||||
"confirmations.mute.confirm": "أكتم",
|
||||
"confirmations.mute.message": "هل أنت متأكد أنك تريد كتم {name} ؟",
|
||||
"confirmations.redraft.confirm": "Delete & redraft",
|
||||
"confirmations.redraft.message": "Are you sure you want to delete this status and re-draft it? You will lose all replies, boosts and favourites to it.",
|
||||
"confirmations.unfollow.confirm": "إلغاء المتابعة",
|
||||
"confirmations.unfollow.message": "متأكد من أنك تريد إلغاء متابعة {name} ؟",
|
||||
"embed.instructions": "يمكنكم إدماج هذه الحالة على موقعكم الإلكتروني عن طريق نسخ الشفرة أدناه.",
|
||||
|
|
@ -97,6 +104,7 @@
|
|||
"emoji_button.symbols": "رموز",
|
||||
"emoji_button.travel": "أماكن و أسفار",
|
||||
"empty_column.community": "الخط الزمني المحلي فارغ. أكتب شيئا ما للعامة كبداية !",
|
||||
"empty_column.direct": "لم تتلق أية رسالة خاصة مباشِرة بعد. سوف يتم عرض الرسائل المباشرة هنا إن قمت بإرسال واحدة أو تلقيت البعض منها.",
|
||||
"empty_column.hashtag": "ليس هناك بعدُ أي محتوى ذو علاقة بهذا الوسم.",
|
||||
"empty_column.home": "إنك لا تتبع بعد أي شخص إلى حد الآن. زر {public} أو استخدام حقل البحث لكي تبدأ على التعرف على مستخدمين آخرين.",
|
||||
"empty_column.home.public_timeline": "الخيط العام",
|
||||
|
|
@ -105,11 +113,10 @@
|
|||
"empty_column.public": "لا يوجد أي شيء هنا ! قم بنشر شيء ما للعامة، أو إتبع مستخدمين آخرين في الخوادم المثيلة الأخرى لملء خيط المحادثات العام",
|
||||
"follow_request.authorize": "ترخيص",
|
||||
"follow_request.reject": "رفض",
|
||||
"getting_started.appsshort": "تطبيقات",
|
||||
"getting_started.faq": "أسئلة وأجوبة شائعة",
|
||||
"getting_started.documentation": "Documentation",
|
||||
"getting_started.heading": "إستعدّ للبدء",
|
||||
"getting_started.open_source_notice": "ماستدون برنامج مفتوح المصدر. يمكنك المساهمة، أو الإبلاغ عن تقارير الأخطاء، على جيت هب {github}.",
|
||||
"getting_started.userguide": "دليل المستخدم",
|
||||
"getting_started.terms": "Terms of service",
|
||||
"home.column_settings.advanced": "متقدمة",
|
||||
"home.column_settings.basic": "أساسية",
|
||||
"home.column_settings.filter_regex": "تصفية حسب التعبيرات العادية",
|
||||
|
|
@ -130,6 +137,7 @@
|
|||
"keyboard_shortcuts.mention": "لذِكر الناشر",
|
||||
"keyboard_shortcuts.reply": "للردّ",
|
||||
"keyboard_shortcuts.search": "للتركيز على البحث",
|
||||
"keyboard_shortcuts.toggle_hidden": "لعرض أو إخفاء النص مِن وراء التحذير",
|
||||
"keyboard_shortcuts.toot": "لتحرير تبويق جديد",
|
||||
"keyboard_shortcuts.unfocus": "لإلغاء التركيز على حقل النص أو نافذة البحث",
|
||||
"keyboard_shortcuts.up": "للإنتقال إلى أعلى القائمة",
|
||||
|
|
@ -151,6 +159,9 @@
|
|||
"mute_modal.hide_notifications": "هل تود إخفاء الإخطارات القادمة من هذا المستخدم ؟",
|
||||
"navigation_bar.blocks": "الحسابات المحجوبة",
|
||||
"navigation_bar.community_timeline": "الخيط العام المحلي",
|
||||
"navigation_bar.direct": "الرسائل المباشِرة",
|
||||
"navigation_bar.discover": "Discover",
|
||||
"navigation_bar.domain_blocks": "النطاقات المخفية",
|
||||
"navigation_bar.edit_profile": "تعديل الملف الشخصي",
|
||||
"navigation_bar.favourites": "المفضلة",
|
||||
"navigation_bar.follow_requests": "طلبات المتابعة",
|
||||
|
|
@ -159,9 +170,11 @@
|
|||
"navigation_bar.lists": "القوائم",
|
||||
"navigation_bar.logout": "خروج",
|
||||
"navigation_bar.mutes": "الحسابات المكتومة",
|
||||
"navigation_bar.personal": "Personal",
|
||||
"navigation_bar.pins": "التبويقات المثبتة",
|
||||
"navigation_bar.preferences": "التفضيلات",
|
||||
"navigation_bar.public_timeline": "الخيط العام الموحد",
|
||||
"navigation_bar.security": "Security",
|
||||
"notification.favourite": "{name} أعجب بمنشورك",
|
||||
"notification.follow": "{name} يتابعك",
|
||||
"notification.mention": "{name} ذكرك",
|
||||
|
|
@ -177,6 +190,7 @@
|
|||
"notifications.column_settings.reblog": "الترقيّات:",
|
||||
"notifications.column_settings.show": "إعرِضها في عمود",
|
||||
"notifications.column_settings.sound": "أصدر صوتا",
|
||||
"notifications.group": "{count} notifications",
|
||||
"onboarding.done": "تم",
|
||||
"onboarding.next": "التالي",
|
||||
"onboarding.page_five.public_timelines": "تُعرَض في الخيط الزمني المحلي المشاركات العامة المحررة من طرف جميع المسجلين في {domain}. أما في الخيط الزمني الموحد ، فإنه يتم عرض جميع المشاركات العامة المنشورة من طرف جميع الأشخاص المتابَعين من طرف أعضاء {domain}. هذه هي الخيوط الزمنية العامة، وهي طريقة رائعة للتعرف أشخاص جدد.",
|
||||
|
|
@ -217,7 +231,7 @@
|
|||
"reply_indicator.cancel": "إلغاء",
|
||||
"report.forward": "التحويل إلى {target}",
|
||||
"report.forward_hint": "هذا الحساب ينتمي إلى خادوم آخَر. هل تودّ إرسال نسخة مجهولة مِن التقرير إلى هنالك أيضًا ؟",
|
||||
"report.hint": "The report will be sent to your instance moderators. You can provide an explanation of why you are reporting this account below:",
|
||||
"report.hint": "سوف يتم إرسال التقرير إلى مُشرِفي مثيل خادومكم. بإمكانك الإدلاء بشرح عن سبب الإبلاغ عن الحساب أسفله :",
|
||||
"report.placeholder": "تعليقات إضافية",
|
||||
"report.submit": "إرسال",
|
||||
"report.target": "إبلاغ",
|
||||
|
|
@ -234,8 +248,10 @@
|
|||
"search_results.total": "{count, number} {count, plural, one {result} و {results}}",
|
||||
"standalone.public_title": "نظرة على ...",
|
||||
"status.block": "Block @{name}",
|
||||
"status.cancel_reblog_private": "إلغاء الترقية",
|
||||
"status.cannot_reblog": "تعذرت ترقية هذا المنشور",
|
||||
"status.delete": "إحذف",
|
||||
"status.direct": "رسالة خاصة إلى @{name}",
|
||||
"status.embed": "إدماج",
|
||||
"status.favourite": "أضف إلى المفضلة",
|
||||
"status.load_more": "حمّل المزيد",
|
||||
|
|
@ -248,7 +264,9 @@
|
|||
"status.pin": "تدبيس على الملف الشخصي",
|
||||
"status.pinned": "تبويق مثبَّت",
|
||||
"status.reblog": "رَقِّي",
|
||||
"status.reblog_private": "القيام بالترقية إلى الجمهور الأصلي",
|
||||
"status.reblogged_by": "{name} رقى",
|
||||
"status.redraft": "Delete & re-draft",
|
||||
"status.reply": "ردّ",
|
||||
"status.replyAll": "رُد على الخيط",
|
||||
"status.report": "إبلِغ عن @{name}",
|
||||
|
|
@ -265,12 +283,16 @@
|
|||
"tabs_bar.home": "الرئيسية",
|
||||
"tabs_bar.local_timeline": "المحلي",
|
||||
"tabs_bar.notifications": "الإخطارات",
|
||||
"tabs_bar.search": "البحث",
|
||||
"timeline.media": "Media",
|
||||
"timeline.posts": "Toots",
|
||||
"trends.count_by_accounts": "{count} {rawCount, plural, one {person} other {people}} talking",
|
||||
"ui.beforeunload": "سوف تفقد مسودتك إن تركت ماستدون.",
|
||||
"upload_area.title": "إسحب ثم أفلت للرفع",
|
||||
"upload_button.label": "إضافة وسائط",
|
||||
"upload_form.description": "وصف للمعاقين بصريا",
|
||||
"upload_form.focus": "قص",
|
||||
"upload_form.undo": "إلغاء",
|
||||
"upload_form.undo": "حذف",
|
||||
"upload_progress.label": "يرفع...",
|
||||
"video.close": "إغلاق الفيديو",
|
||||
"video.exit_fullscreen": "الخروج من وضع الشاشة المليئة",
|
||||
|
|
|
|||
|
|
@ -1,7 +1,9 @@
|
|||
{
|
||||
"account.badges.bot": "Bot",
|
||||
"account.block": "Блокирай",
|
||||
"account.block_domain": "Hide everything from {domain}",
|
||||
"account.blocked": "Blocked",
|
||||
"account.direct": "Direct Message @{name}",
|
||||
"account.disclaimer_full": "Information below may reflect the user's profile incompletely.",
|
||||
"account.domain_blocked": "Domain hidden",
|
||||
"account.edit_profile": "Редактирай профила си",
|
||||
|
|
@ -39,6 +41,8 @@
|
|||
"bundle_modal_error.retry": "Try again",
|
||||
"column.blocks": "Blocked users",
|
||||
"column.community": "Local timeline",
|
||||
"column.direct": "Direct messages",
|
||||
"column.domain_blocks": "Hidden domains",
|
||||
"column.favourites": "Favourites",
|
||||
"column.follow_requests": "Follow requests",
|
||||
"column.home": "Начало",
|
||||
|
|
@ -54,8 +58,9 @@
|
|||
"column_header.pin": "Pin",
|
||||
"column_header.show_settings": "Show settings",
|
||||
"column_header.unpin": "Unpin",
|
||||
"column_subheading.navigation": "Navigation",
|
||||
"column_subheading.settings": "Settings",
|
||||
"compose_form.direct_message_warning": "This toot will only be visible to all the mentioned users.",
|
||||
"compose_form.direct_message_warning_learn_more": "Learn more",
|
||||
"compose_form.hashtag_warning": "This toot won't be listed under any hashtag as it is unlisted. Only public toots can be searched by hashtag.",
|
||||
"compose_form.lock_disclaimer": "Your account is not {locked}. Anyone can follow you to view your follower-only posts.",
|
||||
"compose_form.lock_disclaimer.lock": "locked",
|
||||
|
|
@ -78,6 +83,8 @@
|
|||
"confirmations.domain_block.message": "Are you really, really sure you want to block the entire {domain}? In most cases a few targeted blocks or mutes are sufficient and preferable.",
|
||||
"confirmations.mute.confirm": "Mute",
|
||||
"confirmations.mute.message": "Are you sure you want to mute {name}?",
|
||||
"confirmations.redraft.confirm": "Delete & redraft",
|
||||
"confirmations.redraft.message": "Are you sure you want to delete this status and re-draft it? You will lose all replies, boosts and favourites to it.",
|
||||
"confirmations.unfollow.confirm": "Unfollow",
|
||||
"confirmations.unfollow.message": "Are you sure you want to unfollow {name}?",
|
||||
"embed.instructions": "Embed this status on your website by copying the code below.",
|
||||
|
|
@ -97,6 +104,7 @@
|
|||
"emoji_button.symbols": "Symbols",
|
||||
"emoji_button.travel": "Travel & Places",
|
||||
"empty_column.community": "The local timeline is empty. Write something publicly to get the ball rolling!",
|
||||
"empty_column.direct": "You don't have any direct messages yet. When you send or receive one, it will show up here.",
|
||||
"empty_column.hashtag": "There is nothing in this hashtag yet.",
|
||||
"empty_column.home": "Your home timeline is empty! Visit {public} or use search to get started and meet other users.",
|
||||
"empty_column.home.public_timeline": "the public timeline",
|
||||
|
|
@ -105,11 +113,10 @@
|
|||
"empty_column.public": "There is nothing here! Write something publicly, or manually follow users from other instances to fill it up",
|
||||
"follow_request.authorize": "Authorize",
|
||||
"follow_request.reject": "Reject",
|
||||
"getting_started.appsshort": "Apps",
|
||||
"getting_started.faq": "FAQ",
|
||||
"getting_started.documentation": "Documentation",
|
||||
"getting_started.heading": "Първи стъпки",
|
||||
"getting_started.open_source_notice": "Mastodon е софтуер с отворен код. Можеш да помогнеш или да докладваш за проблеми в Github: {github}.",
|
||||
"getting_started.userguide": "User Guide",
|
||||
"getting_started.terms": "Terms of service",
|
||||
"home.column_settings.advanced": "Advanced",
|
||||
"home.column_settings.basic": "Basic",
|
||||
"home.column_settings.filter_regex": "Filter out by regular expressions",
|
||||
|
|
@ -130,6 +137,7 @@
|
|||
"keyboard_shortcuts.mention": "to mention author",
|
||||
"keyboard_shortcuts.reply": "to reply",
|
||||
"keyboard_shortcuts.search": "to focus search",
|
||||
"keyboard_shortcuts.toggle_hidden": "to show/hide text behind CW",
|
||||
"keyboard_shortcuts.toot": "to start a brand new toot",
|
||||
"keyboard_shortcuts.unfocus": "to un-focus compose textarea/search",
|
||||
"keyboard_shortcuts.up": "to move up in the list",
|
||||
|
|
@ -151,6 +159,9 @@
|
|||
"mute_modal.hide_notifications": "Hide notifications from this user?",
|
||||
"navigation_bar.blocks": "Blocked users",
|
||||
"navigation_bar.community_timeline": "Local timeline",
|
||||
"navigation_bar.direct": "Direct messages",
|
||||
"navigation_bar.discover": "Discover",
|
||||
"navigation_bar.domain_blocks": "Hidden domains",
|
||||
"navigation_bar.edit_profile": "Редактирай профил",
|
||||
"navigation_bar.favourites": "Favourites",
|
||||
"navigation_bar.follow_requests": "Follow requests",
|
||||
|
|
@ -159,9 +170,11 @@
|
|||
"navigation_bar.lists": "Lists",
|
||||
"navigation_bar.logout": "Излизане",
|
||||
"navigation_bar.mutes": "Muted users",
|
||||
"navigation_bar.personal": "Personal",
|
||||
"navigation_bar.pins": "Pinned toots",
|
||||
"navigation_bar.preferences": "Предпочитания",
|
||||
"navigation_bar.public_timeline": "Публичен канал",
|
||||
"navigation_bar.security": "Security",
|
||||
"notification.favourite": "{name} хареса твоята публикация",
|
||||
"notification.follow": "{name} те последва",
|
||||
"notification.mention": "{name} те спомена",
|
||||
|
|
@ -177,6 +190,7 @@
|
|||
"notifications.column_settings.reblog": "Споделяния:",
|
||||
"notifications.column_settings.show": "Покажи в колона",
|
||||
"notifications.column_settings.sound": "Play sound",
|
||||
"notifications.group": "{count} notifications",
|
||||
"onboarding.done": "Done",
|
||||
"onboarding.next": "Next",
|
||||
"onboarding.page_five.public_timelines": "The local timeline shows public posts from everyone on {domain}. The federated timeline shows public posts from everyone who people on {domain} follow. These are the Public Timelines, a great way to discover new people.",
|
||||
|
|
@ -234,8 +248,10 @@
|
|||
"search_results.total": "{count, number} {count, plural, one {result} other {results}}",
|
||||
"standalone.public_title": "A look inside...",
|
||||
"status.block": "Block @{name}",
|
||||
"status.cancel_reblog_private": "Unboost",
|
||||
"status.cannot_reblog": "This post cannot be boosted",
|
||||
"status.delete": "Изтриване",
|
||||
"status.direct": "Direct message @{name}",
|
||||
"status.embed": "Embed",
|
||||
"status.favourite": "Предпочитани",
|
||||
"status.load_more": "Load more",
|
||||
|
|
@ -248,7 +264,9 @@
|
|||
"status.pin": "Pin on profile",
|
||||
"status.pinned": "Pinned toot",
|
||||
"status.reblog": "Споделяне",
|
||||
"status.reblog_private": "Boost to original audience",
|
||||
"status.reblogged_by": "{name} сподели",
|
||||
"status.redraft": "Delete & re-draft",
|
||||
"status.reply": "Отговор",
|
||||
"status.replyAll": "Reply to thread",
|
||||
"status.report": "Report @{name}",
|
||||
|
|
@ -265,6 +283,10 @@
|
|||
"tabs_bar.home": "Начало",
|
||||
"tabs_bar.local_timeline": "Local",
|
||||
"tabs_bar.notifications": "Известия",
|
||||
"tabs_bar.search": "Search",
|
||||
"timeline.media": "Media",
|
||||
"timeline.posts": "Toots",
|
||||
"trends.count_by_accounts": "{count} {rawCount, plural, one {person} other {people}} talking",
|
||||
"ui.beforeunload": "Your draft will be lost if you leave Mastodon.",
|
||||
"upload_area.title": "Drag & drop to upload",
|
||||
"upload_button.label": "Добави медия",
|
||||
|
|
|
|||
|
|
@ -1,7 +1,9 @@
|
|||
{
|
||||
"account.badges.bot": "Bot",
|
||||
"account.block": "Bloca @{name}",
|
||||
"account.block_domain": "Amaga-ho tot de {domain}",
|
||||
"account.blocked": "Bloquejat",
|
||||
"account.direct": "Missatge directe @{name}",
|
||||
"account.disclaimer_full": "La informació següent pot reflectir incompleta el perfil de l'usuari.",
|
||||
"account.domain_blocked": "Domini ocult",
|
||||
"account.edit_profile": "Edita el perfil",
|
||||
|
|
@ -17,7 +19,7 @@
|
|||
"account.mute_notifications": "Notificacions desactivades de @{name}",
|
||||
"account.muted": "Silenciat",
|
||||
"account.posts": "Toots",
|
||||
"account.posts_with_replies": "Toots amb respostes",
|
||||
"account.posts_with_replies": "Toots i respostes",
|
||||
"account.report": "Informe @{name}",
|
||||
"account.requested": "Esperant aprovació. Clic per a cancel·lar la petició de seguiment",
|
||||
"account.share": "Comparteix el perfil de @{name}",
|
||||
|
|
@ -28,8 +30,8 @@
|
|||
"account.unmute": "Treure silenci de @{name}",
|
||||
"account.unmute_notifications": "Activar notificacions de @{name}",
|
||||
"account.view_full_profile": "Mostra el perfil complet",
|
||||
"alert.unexpected.message": "An unexpected error occurred.",
|
||||
"alert.unexpected.title": "Oops!",
|
||||
"alert.unexpected.message": "S'ha produït un error inesperat.",
|
||||
"alert.unexpected.title": "Vaja!",
|
||||
"boost_modal.combo": "Pots premer {combo} per saltar-te això el proper cop",
|
||||
"bundle_column_error.body": "S'ha produït un error en carregar aquest component.",
|
||||
"bundle_column_error.retry": "Torna-ho a provar",
|
||||
|
|
@ -39,6 +41,8 @@
|
|||
"bundle_modal_error.retry": "Torna-ho a provar",
|
||||
"column.blocks": "Usuaris blocats",
|
||||
"column.community": "Línia de temps local",
|
||||
"column.direct": "Missatges directes",
|
||||
"column.domain_blocks": "Dominis ocults",
|
||||
"column.favourites": "Favorits",
|
||||
"column.follow_requests": "Peticions per seguir-te",
|
||||
"column.home": "Inici",
|
||||
|
|
@ -54,8 +58,9 @@
|
|||
"column_header.pin": "Fixa",
|
||||
"column_header.show_settings": "Mostra la configuració",
|
||||
"column_header.unpin": "No fixis",
|
||||
"column_subheading.navigation": "Navegació",
|
||||
"column_subheading.settings": "Configuració",
|
||||
"compose_form.direct_message_warning": "Aquest toot només serà enviat als usuaris esmentats. De totes maneres, els operadors de la teva o de qualsevol de les instàncies receptores poden inspeccionar aquest missatge.",
|
||||
"compose_form.direct_message_warning_learn_more": "Aprèn més",
|
||||
"compose_form.hashtag_warning": "Aquest toot no es mostrarà en cap etiqueta ja que no està llistat. Només els toots públics poden ser cercats per etiqueta.",
|
||||
"compose_form.lock_disclaimer": "El teu compte no està bloquejat {locked}. Tothom pot seguir-te i veure els teus missatges a seguidors.",
|
||||
"compose_form.lock_disclaimer.lock": "blocat",
|
||||
|
|
@ -64,7 +69,7 @@
|
|||
"compose_form.publish_loud": "{publish}!",
|
||||
"compose_form.sensitive.marked": "Mèdia marcat com a sensible",
|
||||
"compose_form.sensitive.unmarked": "Mèdia no està marcat com a sensible",
|
||||
"compose_form.spoiler.marked": "Text ocult sota l'avís",
|
||||
"compose_form.spoiler.marked": "Text es ocult sota l'avís",
|
||||
"compose_form.spoiler.unmarked": "Text no ocult",
|
||||
"compose_form.spoiler_placeholder": "Escriu l'avís aquí",
|
||||
"confirmation_modal.cancel": "Cancel·la",
|
||||
|
|
@ -78,6 +83,8 @@
|
|||
"confirmations.domain_block.message": "Estàs realment, realment segur que vols blocar totalment {domain}? En la majoria dels casos blocar o silenciar uns pocs objectius és suficient i preferible.",
|
||||
"confirmations.mute.confirm": "Silencia",
|
||||
"confirmations.mute.message": "Estàs segur que vols silenciar {name}?",
|
||||
"confirmations.redraft.confirm": "Esborrar i refer",
|
||||
"confirmations.redraft.message": "Estàs segur que vols esborrar aquesta publicació i tornar a redactar-la? Perderàs totes les respostes, impulsos i favorits.",
|
||||
"confirmations.unfollow.confirm": "Deixa de seguir",
|
||||
"confirmations.unfollow.message": "Estàs segur que vols deixar de seguir {name}?",
|
||||
"embed.instructions": "Incrusta aquest estat al lloc web copiant el codi a continuació.",
|
||||
|
|
@ -97,6 +104,7 @@
|
|||
"emoji_button.symbols": "Símbols",
|
||||
"emoji_button.travel": "Viatges i Llocs",
|
||||
"empty_column.community": "La línia de temps local és buida. Escriu alguna cosa públicament per fer rodar la pilota!",
|
||||
"empty_column.direct": "Encara no tens missatges directes. Quan enviïs o rebis un, es mostrarà aquí.",
|
||||
"empty_column.hashtag": "Encara no hi ha res amb aquesta etiqueta.",
|
||||
"empty_column.home": "Encara no segueixes ningú. Visita {public} o fes cerca per començar i conèixer altres usuaris.",
|
||||
"empty_column.home.public_timeline": "la línia de temps pública",
|
||||
|
|
@ -105,11 +113,10 @@
|
|||
"empty_column.public": "No hi ha res aquí! Escriu alguna cosa públicament o segueix manualment usuaris d'altres instàncies per omplir-ho",
|
||||
"follow_request.authorize": "Autoritzar",
|
||||
"follow_request.reject": "Rebutjar",
|
||||
"getting_started.appsshort": "Aplicacions",
|
||||
"getting_started.faq": "PMF",
|
||||
"getting_started.documentation": "Documentation",
|
||||
"getting_started.heading": "Començant",
|
||||
"getting_started.open_source_notice": "Mastodon és un programari de codi obert. Pots contribuir o informar de problemes a GitHub a {github}.",
|
||||
"getting_started.userguide": "Guia de l'usuari",
|
||||
"getting_started.terms": "Termes del servei",
|
||||
"home.column_settings.advanced": "Avançat",
|
||||
"home.column_settings.basic": "Bàsic",
|
||||
"home.column_settings.filter_regex": "Filtrar per expressió regular",
|
||||
|
|
@ -130,6 +137,7 @@
|
|||
"keyboard_shortcuts.mention": "per esmentar l'autor",
|
||||
"keyboard_shortcuts.reply": "respondre",
|
||||
"keyboard_shortcuts.search": "per centrar la cerca",
|
||||
"keyboard_shortcuts.toggle_hidden": "per a mostrar/amagar text sota CW",
|
||||
"keyboard_shortcuts.toot": "per a començar un toot nou de trinca",
|
||||
"keyboard_shortcuts.unfocus": "descentrar l'area de composició de text/cerca",
|
||||
"keyboard_shortcuts.up": "moure amunt en la llista",
|
||||
|
|
@ -151,6 +159,9 @@
|
|||
"mute_modal.hide_notifications": "Amagar notificacions d'aquest usuari?",
|
||||
"navigation_bar.blocks": "Usuaris bloquejats",
|
||||
"navigation_bar.community_timeline": "Línia de temps Local",
|
||||
"navigation_bar.direct": "Missatges directes",
|
||||
"navigation_bar.discover": "Descobreix",
|
||||
"navigation_bar.domain_blocks": "Dominis ocults",
|
||||
"navigation_bar.edit_profile": "Editar perfil",
|
||||
"navigation_bar.favourites": "Favorits",
|
||||
"navigation_bar.follow_requests": "Sol·licituds de seguiment",
|
||||
|
|
@ -159,9 +170,11 @@
|
|||
"navigation_bar.lists": "Llistes",
|
||||
"navigation_bar.logout": "Tancar sessió",
|
||||
"navigation_bar.mutes": "Usuaris silenciats",
|
||||
"navigation_bar.personal": "Personal",
|
||||
"navigation_bar.pins": "Toots fixats",
|
||||
"navigation_bar.preferences": "Preferències",
|
||||
"navigation_bar.public_timeline": "Línia de temps federada",
|
||||
"navigation_bar.security": "Seguretat",
|
||||
"notification.favourite": "{name} ha afavorit el teu estat",
|
||||
"notification.follow": "{name} et segueix",
|
||||
"notification.mention": "{name} t'ha esmentat",
|
||||
|
|
@ -177,6 +190,7 @@
|
|||
"notifications.column_settings.reblog": "Impulsos:",
|
||||
"notifications.column_settings.show": "Mostrar en la columna",
|
||||
"notifications.column_settings.sound": "Reproduïr so",
|
||||
"notifications.group": "{count} notificacions",
|
||||
"onboarding.done": "Fet",
|
||||
"onboarding.next": "Següent",
|
||||
"onboarding.page_five.public_timelines": "La línia de temps local mostra missatges públics de tothom de {domain}. La línia de temps federada mostra els missatges públics de tothom que la gent de {domain} segueix. Aquests són les línies de temps Públiques, una bona manera de descobrir noves persones.",
|
||||
|
|
@ -234,8 +248,10 @@
|
|||
"search_results.total": "{count, number} {count, plural, un {result} altres {results}}",
|
||||
"standalone.public_title": "Una mirada a l'interior ...",
|
||||
"status.block": "Block @{name}",
|
||||
"status.cancel_reblog_private": "Desfer l'impuls",
|
||||
"status.cannot_reblog": "Aquesta publicació no pot ser retootejada",
|
||||
"status.delete": "Esborrar",
|
||||
"status.direct": "Missatge directe @{name}",
|
||||
"status.embed": "Incrustar",
|
||||
"status.favourite": "Favorit",
|
||||
"status.load_more": "Carrega més",
|
||||
|
|
@ -248,7 +264,9 @@
|
|||
"status.pin": "Fixat en el perfil",
|
||||
"status.pinned": "Toot fixat",
|
||||
"status.reblog": "Impuls",
|
||||
"status.reblog_private": "Impulsar a l'audiència original",
|
||||
"status.reblogged_by": "{name} ha retootejat",
|
||||
"status.redraft": "Esborrar i reescriure",
|
||||
"status.reply": "Respondre",
|
||||
"status.replyAll": "Respondre al tema",
|
||||
"status.report": "Informar sobre @{name}",
|
||||
|
|
@ -265,12 +283,16 @@
|
|||
"tabs_bar.home": "Inici",
|
||||
"tabs_bar.local_timeline": "Local",
|
||||
"tabs_bar.notifications": "Notificacions",
|
||||
"tabs_bar.search": "Cerca",
|
||||
"timeline.media": "Media",
|
||||
"timeline.posts": "Toots",
|
||||
"trends.count_by_accounts": "{count} {rawCount, plural, una {person} altres {people}} parlant",
|
||||
"ui.beforeunload": "El vostre esborrany es perdrà si sortiu de Mastodon.",
|
||||
"upload_area.title": "Arrossega i deixa anar per carregar",
|
||||
"upload_button.label": "Afegir multimèdia",
|
||||
"upload_form.description": "Descriure els problemes visuals",
|
||||
"upload_form.focus": "Retallar",
|
||||
"upload_form.undo": "Desfer",
|
||||
"upload_form.undo": "Esborra",
|
||||
"upload_progress.label": "Pujant...",
|
||||
"video.close": "Tancar el vídeo",
|
||||
"video.exit_fullscreen": "Surt de pantalla completa",
|
||||
|
|
|
|||
306
app/javascript/mastodon/locales/co.json
Normal file
306
app/javascript/mastodon/locales/co.json
Normal file
|
|
@ -0,0 +1,306 @@
|
|||
{
|
||||
"account.badges.bot": "Bot",
|
||||
"account.block": "Bluccà @{name}",
|
||||
"account.block_domain": "Piattà tuttu da {domain}",
|
||||
"account.blocked": "Bluccatu",
|
||||
"account.direct": "Missaghju direttu @{name}",
|
||||
"account.disclaimer_full": "Ghjè pussibule chì l’infurmazione quì sottu ùn rifletta micca u prufile sanu di l’utilizatore.",
|
||||
"account.domain_blocked": "Duminiu piattatu",
|
||||
"account.edit_profile": "Mudificà u prufile",
|
||||
"account.follow": "Siguità",
|
||||
"account.followers": "Abbunati",
|
||||
"account.follows": "Abbunamenti",
|
||||
"account.follows_you": "Vi seguita",
|
||||
"account.hide_reblogs": "Piattà spartere da @{name}",
|
||||
"account.media": "Media",
|
||||
"account.mention": "Mintuvà @{name}",
|
||||
"account.moved_to": "{name} hè partutu nant'à:",
|
||||
"account.mute": "Piattà @{name}",
|
||||
"account.mute_notifications": "Piattà nutificazione da @{name}",
|
||||
"account.muted": "Piattatu",
|
||||
"account.posts": "Statuti",
|
||||
"account.posts_with_replies": "Statuti è risposte",
|
||||
"account.report": "Palisà @{name}",
|
||||
"account.requested": "In attesa d'apprubazione. Cliccate per annullà a dumanda",
|
||||
"account.share": "Sparte u prufile di @{name}",
|
||||
"account.show_reblogs": "Vede spartere da @{name}",
|
||||
"account.unblock": "Sbluccà @{name}",
|
||||
"account.unblock_domain": "Ùn piattà più {domain}",
|
||||
"account.unfollow": "Ùn siguità più",
|
||||
"account.unmute": "Ùn piattà più @{name}",
|
||||
"account.unmute_notifications": "Ùn piattà più nutificazione da @{name}",
|
||||
"account.view_full_profile": "Vede tuttu u prufile",
|
||||
"alert.unexpected.message": "Un prublemu inaspettatu hè accadutu.",
|
||||
"alert.unexpected.title": "Uups!",
|
||||
"boost_modal.combo": "Pudete appughjà nant'à {combo} per saltà quessa a prussima volta",
|
||||
"bundle_column_error.body": "C'hè statu un prublemu caricandu st'elementu.",
|
||||
"bundle_column_error.retry": "Pruvà torna",
|
||||
"bundle_column_error.title": "Errore di cunnessione",
|
||||
"bundle_modal_error.close": "Chjudà",
|
||||
"bundle_modal_error.message": "C'hè statu un prublemu caricandu st'elementu.",
|
||||
"bundle_modal_error.retry": "Pruvà torna",
|
||||
"column.blocks": "Utilizatori bluccati",
|
||||
"column.community": "Linea pubblica lucale",
|
||||
"column.direct": "Missaghji diretti",
|
||||
"column.domain_blocks": "Duminii piattati",
|
||||
"column.favourites": "Favuriti",
|
||||
"column.follow_requests": "Dumande d'abbunamentu",
|
||||
"column.home": "Accolta",
|
||||
"column.lists": "Liste",
|
||||
"column.mutes": "Utilizatori piattati",
|
||||
"column.notifications": "Nutificazione",
|
||||
"column.pins": "Statuti puntarulati",
|
||||
"column.public": "Linea pubblica glubale",
|
||||
"column_back_button.label": "Ritornu",
|
||||
"column_header.hide_settings": "Piattà i parametri",
|
||||
"column_header.moveLeft_settings": "Spiazzà à manca",
|
||||
"column_header.moveRight_settings": "Spiazzà à diritta",
|
||||
"column_header.pin": "Puntarulà",
|
||||
"column_header.show_settings": "Mustrà i parametri",
|
||||
"column_header.unpin": "Spuntarulà",
|
||||
"column_subheading.settings": "Parametri",
|
||||
"compose_form.direct_message_warning": "Solu l'utilizatori mintuvati puderenu vede stu statutu.",
|
||||
"compose_form.direct_message_warning_learn_more": "Learn more",
|
||||
"compose_form.hashtag_warning": "Stu statutu ùn hè \"Micca listatu\" è ùn sarà micca listatu indè e circate da hashtag. Per esse vistu in quesse, u statutu deve esse \"Pubblicu\".",
|
||||
"compose_form.lock_disclaimer": "U vostru contu ùn hè micca {locked}. Tuttu u mondu pò seguitavi è vede i vostri statuti privati.",
|
||||
"compose_form.lock_disclaimer.lock": "privatu",
|
||||
"compose_form.placeholder": "À chè pensate?",
|
||||
"compose_form.publish": "Toot",
|
||||
"compose_form.publish_loud": "{publish}!",
|
||||
"compose_form.sensitive.marked": "Media indicatu cum'è sensibile",
|
||||
"compose_form.sensitive.unmarked": "Media micca indicatu cum'è sensibile",
|
||||
"compose_form.spoiler.marked": "Testu piattatu daret'à un'avertimentu",
|
||||
"compose_form.spoiler.unmarked": "Testu micca piattatu",
|
||||
"compose_form.spoiler_placeholder": "Scrive u vostr'avertimentu quì",
|
||||
"confirmation_modal.cancel": "Annullà",
|
||||
"confirmations.block.confirm": "Bluccà",
|
||||
"confirmations.block.message": "Site sicuru·a che vulete bluccà @{name}?",
|
||||
"confirmations.delete.confirm": "Toglie",
|
||||
"confirmations.delete.message": "Site sicuru·a che vulete supprime stu statutu?",
|
||||
"confirmations.delete_list.confirm": "Toglie",
|
||||
"confirmations.delete_list.message": "Site sicuru·a che vulete supprime sta lista?",
|
||||
"confirmations.domain_block.confirm": "Piattà tuttu u duminiu",
|
||||
"confirmations.domain_block.message": "Site sicuru·a che vulete piattà tuttu à {domain}? Saria forse abbastanza di bluccà ò piattà alcuni conti da quallà.",
|
||||
"confirmations.mute.confirm": "Piattà",
|
||||
"confirmations.mute.message": "Site sicuru·a che vulete piattà @{name}?",
|
||||
"confirmations.redraft.confirm": "Delete & redraft",
|
||||
"confirmations.redraft.message": "Are you sure you want to delete this status and re-draft it? You will lose all replies, boosts and favourites to it.",
|
||||
"confirmations.unfollow.confirm": "Disabbunassi",
|
||||
"confirmations.unfollow.message": "Site sicuru·a ch'ùn vulete più siguità @{name}?",
|
||||
"embed.instructions": "Integrà stu statutu à u vostru situ cù u codice quì sottu.",
|
||||
"embed.preview": "Assumiglierà à qualcosa cusì:",
|
||||
"emoji_button.activity": "Attività",
|
||||
"emoji_button.custom": "Persunalizati",
|
||||
"emoji_button.flags": "Bandere",
|
||||
"emoji_button.food": "Manghjusca è Bienda",
|
||||
"emoji_button.label": "Mette un'emoji",
|
||||
"emoji_button.nature": "Natura",
|
||||
"emoji_button.not_found": "Ùn c'hè nunda! (╯°□°)╯︵ ┻━┻",
|
||||
"emoji_button.objects": "Oggetti",
|
||||
"emoji_button.people": "Parsunaghji",
|
||||
"emoji_button.recent": "Assai utilizati",
|
||||
"emoji_button.search": "Cercà...",
|
||||
"emoji_button.search_results": "Risultati di a cerca",
|
||||
"emoji_button.symbols": "Simbuli",
|
||||
"emoji_button.travel": "Lochi è Viaghju",
|
||||
"empty_column.community": "Ùn c'hè nunda indè a linea lucale. Scrivete puru qualcosa!",
|
||||
"empty_column.direct": "Ùn avete ancu nisun missaghju direttu. S'è voi mandate o ricevete unu, u vidarete quì.",
|
||||
"empty_column.hashtag": "Ùn c'hè ancu nunda quì.",
|
||||
"empty_column.home": "A vostr'accolta hè viota! Pudete andà nant'à {public} o pruvà a ricerca per truvà parsone da siguità.",
|
||||
"empty_column.home.public_timeline": "a linea pubblica",
|
||||
"empty_column.list": "Ùn c'hè ancu nunda quì. Quandu membri di sta lista manderanu novi statuti, i vidarete quì.",
|
||||
"empty_column.notifications": "Ùn avete ancu nisuna nutificazione. Interact with others to start the conversation.",
|
||||
"empty_column.public": "Ùn c'hè nunda quì! Scrivete qualcosa in pubblicu o seguitate utilizatori d'altre istanze per empie a linea pubblica",
|
||||
"follow_request.authorize": "Auturizà",
|
||||
"follow_request.reject": "Righjittà",
|
||||
"getting_started.documentation": "Documentation",
|
||||
"getting_started.heading": "Per principià",
|
||||
"getting_started.open_source_notice": "Mastodon ghjè un lugiziale liberu. Pudete cuntribuisce à u codice o a traduzione, o palisà un bug, nant'à GitHub: {github}.",
|
||||
"getting_started.terms": "Terms of service",
|
||||
"home.column_settings.advanced": "Avanzati",
|
||||
"home.column_settings.basic": "Bàsichi",
|
||||
"home.column_settings.filter_regex": "Filtrà cù spressione regulare (regex)",
|
||||
"home.column_settings.show_reblogs": "Vede e spartere",
|
||||
"home.column_settings.show_replies": "Vede e risposte",
|
||||
"home.settings": "Parametri di a colonna",
|
||||
"keyboard_shortcuts.back": "rivultà",
|
||||
"keyboard_shortcuts.boost": "sparte",
|
||||
"keyboard_shortcuts.column": "fucalizà un statutu indè una colonna",
|
||||
"keyboard_shortcuts.compose": "fucalizà nant'à l'area di ridazzione",
|
||||
"keyboard_shortcuts.description": "Descrizzione",
|
||||
"keyboard_shortcuts.down": "falà indè a lista",
|
||||
"keyboard_shortcuts.enter": "apre u statutu",
|
||||
"keyboard_shortcuts.favourite": "aghjunghje à i favuriti",
|
||||
"keyboard_shortcuts.heading": "Accorte cù a tastera",
|
||||
"keyboard_shortcuts.hotkey": "Accorta",
|
||||
"keyboard_shortcuts.legend": "vede a legenda",
|
||||
"keyboard_shortcuts.mention": "mintuvà l'autore",
|
||||
"keyboard_shortcuts.reply": "risponde",
|
||||
"keyboard_shortcuts.search": "fucalizà nant'à l'area di circata",
|
||||
"keyboard_shortcuts.toggle_hidden": "vede/piattà u testu daretu à l'avertimentu CW",
|
||||
"keyboard_shortcuts.toot": "scrive un novu statutu",
|
||||
"keyboard_shortcuts.unfocus": "ùn fucalizà più l'area di testu",
|
||||
"keyboard_shortcuts.up": "cullà indè a lista",
|
||||
"lightbox.close": "Chjudà",
|
||||
"lightbox.next": "Siguente",
|
||||
"lightbox.previous": "Pricidente",
|
||||
"lists.account.add": "Aghjunghje à a lista",
|
||||
"lists.account.remove": "Toglie di a lista",
|
||||
"lists.delete": "Supprime a lista",
|
||||
"lists.edit": "Mudificà a lista",
|
||||
"lists.new.create": "Aghjustà una lista",
|
||||
"lists.new.title_placeholder": "Titulu di a lista",
|
||||
"lists.search": "Circà indè i vostr'abbunamenti",
|
||||
"lists.subheading": "E vo liste",
|
||||
"loading_indicator.label": "Caricamentu...",
|
||||
"media_gallery.toggle_visible": "Cambià a visibilità",
|
||||
"missing_indicator.label": "Micca trovu",
|
||||
"missing_indicator.sublabel": "Ùn era micca pussivule di truvà sta risorsa",
|
||||
"mute_modal.hide_notifications": "Piattà nutificazione da st'utilizatore?",
|
||||
"navigation_bar.blocks": "Utilizatori bluccati",
|
||||
"navigation_bar.community_timeline": "Linea pubblica lucale",
|
||||
"navigation_bar.direct": "Missaghji diretti",
|
||||
"navigation_bar.discover": "Discover",
|
||||
"navigation_bar.domain_blocks": "Duminii piattati",
|
||||
"navigation_bar.edit_profile": "Mudificà u prufile",
|
||||
"navigation_bar.favourites": "Favuriti",
|
||||
"navigation_bar.follow_requests": "Dumande d'abbunamentu",
|
||||
"navigation_bar.info": "À prupositu di l'istanza",
|
||||
"navigation_bar.keyboard_shortcuts": "Accorte cù a tastera",
|
||||
"navigation_bar.lists": "Liste",
|
||||
"navigation_bar.logout": "Scunnettassi",
|
||||
"navigation_bar.mutes": "Utilizatori piattati",
|
||||
"navigation_bar.personal": "Personal",
|
||||
"navigation_bar.pins": "Statuti puntarulati",
|
||||
"navigation_bar.preferences": "Preferenze",
|
||||
"navigation_bar.public_timeline": "Linea pubblica glubale",
|
||||
"navigation_bar.security": "Security",
|
||||
"notification.favourite": "{name} hà aghjuntu u vostru statutu à i so favuriti",
|
||||
"notification.follow": "{name} v'hà seguitatu",
|
||||
"notification.mention": "{name} v'hà mintuvatu",
|
||||
"notification.reblog": "{name} hà spartutu u vostru statutu",
|
||||
"notifications.clear": "Purgà e nutificazione",
|
||||
"notifications.clear_confirmation": "Site sicuru·a che vulete toglie tutte ste nutificazione?",
|
||||
"notifications.column_settings.alert": "Nutificazione nant'à l'urdinatore",
|
||||
"notifications.column_settings.favourite": "Favuriti:",
|
||||
"notifications.column_settings.follow": "Abbunati novi:",
|
||||
"notifications.column_settings.mention": "Minzione:",
|
||||
"notifications.column_settings.push": "Nutificazione Push",
|
||||
"notifications.column_settings.push_meta": "Quess'apparechju",
|
||||
"notifications.column_settings.reblog": "Spartere:",
|
||||
"notifications.column_settings.show": "Mustrà indè a colonna",
|
||||
"notifications.column_settings.sound": "Sunà",
|
||||
"notifications.group": "{count} notifications",
|
||||
"onboarding.done": "Fatta",
|
||||
"onboarding.next": "Siguente",
|
||||
"onboarding.page_five.public_timelines": "A linea pubblica lucale mostra statuti pubblichi da tuttu u mondu nant'à {domain}. A linea pubblica glubale mostra ancu quelli di a ghjente seguitata da l'utilizatori di {domain}. Quesse sò una bona manera d'incuntrà nove parsone.",
|
||||
"onboarding.page_four.home": "A linea d'accolta mostra i statuti di i vostr'abbunamenti.",
|
||||
"onboarding.page_four.notifications": "A colonna di nutificazione mostra l'interazzione ch'altre parsone anu cù u vostru contu.",
|
||||
"onboarding.page_one.federation": "Mastodon ghjè una rete di servori independenti, chjamati istanze, uniti indè una sola rete suciale.",
|
||||
"onboarding.page_one.full_handle": "U vostru identificatore cumplettu",
|
||||
"onboarding.page_one.handle_hint": "Quessu ghjè cio chì direte à i vostri amichi per circavi.",
|
||||
"onboarding.page_one.welcome": "Benvenuti/a nant'à Mastodon!",
|
||||
"onboarding.page_six.admin": "L'amministratore di a vostr'istanza hè {admin}.",
|
||||
"onboarding.page_six.almost_done": "Quasgi finitu...",
|
||||
"onboarding.page_six.appetoot": "Bon Appetoot!",
|
||||
"onboarding.page_six.apps_available": "Ci sò {apps} dispunibule per iOS, Android è altre piattaforme.",
|
||||
"onboarding.page_six.github": "Mastodon ghjè un lugiziale liberu. Pudete cuntribuisce à u codice o a traduzione, o palisà un prublemu, nant'à {github}.",
|
||||
"onboarding.page_six.guidelines": "regule di a cumunità",
|
||||
"onboarding.page_six.read_guidelines": "Ùn vi scurdate di leghje e {guidelines} di {domain}!",
|
||||
"onboarding.page_six.various_app": "applicazione pè u telefuninu",
|
||||
"onboarding.page_three.profile": "Pudete mudificà u prufile per cambia u ritrattu, a descrizzione è u nome affissatu. Ci sò ancu alcun'altre preferenze.",
|
||||
"onboarding.page_three.search": "Fate usu di l'area di ricerca per truvà altre persone è vede hashtag cum'è {illustration} o {introductions}. Per vede qualcunu ch'ùn hè micca nant'à st'istanza, cercate u so identificatore complettu (pare un'email).",
|
||||
"onboarding.page_two.compose": "I statuti è missaghji si scrivenu indè l'area di ridazzione. Pudete caricà imagine, cambià i parametri di pubblicazione, è mette avertimenti di cuntenuti cù i buttoni quì sottu.",
|
||||
"onboarding.skip": "Passà",
|
||||
"privacy.change": "Mudificà a cunfidenzialità di u statutu",
|
||||
"privacy.direct.long": "Mandà solu à quelli chì so mintuvati",
|
||||
"privacy.direct.short": "Direttu",
|
||||
"privacy.private.long": "Mustrà solu à l'abbunati",
|
||||
"privacy.private.short": "Privatu",
|
||||
"privacy.public.long": "Mustrà à tuttu u mondu nant'a linea pubblica",
|
||||
"privacy.public.short": "Pubblicu",
|
||||
"privacy.unlisted.long": "Ùn mette micca nant'a linea pubblica (ma tutt'u mondu pò vede u statutu nant'à u vostru prufile)",
|
||||
"privacy.unlisted.short": "Micca listatu",
|
||||
"regeneration_indicator.label": "Caricamentu…",
|
||||
"regeneration_indicator.sublabel": "Priparazione di a vostra pagina d'accolta!",
|
||||
"relative_time.days": "{number}d",
|
||||
"relative_time.hours": "{number}h",
|
||||
"relative_time.just_now": "avà",
|
||||
"relative_time.minutes": "{number}m",
|
||||
"relative_time.seconds": "{number}s",
|
||||
"reply_indicator.cancel": "Annullà",
|
||||
"report.forward": "Trasferisce à {target}",
|
||||
"report.forward_hint": "U contu hè nant'à un'altru servore. Vulete ancu mandà una copia anonima di u signalamentu quallà?",
|
||||
"report.hint": "U signalamentu sarà mandatu à i muderatori di l'istanza. Pudete spiegà perchè avete palisatu stu contu quì sottu:",
|
||||
"report.placeholder": "Altri cummenti",
|
||||
"report.submit": "Mandà",
|
||||
"report.target": "Signalamentu",
|
||||
"search.placeholder": "Circà",
|
||||
"search_popout.search_format": "Ricerca avanzata",
|
||||
"search_popout.tips.full_text": "I testi simplici rimandanu i statuti ch'avete scritti, aghjunti à i vostri favuriti, spartuti o induve quelli site mintuvatu·a, è ancu i cugnomi, nomi pubblichi è hashtag chì currispondenu.",
|
||||
"search_popout.tips.hashtag": "hashtag",
|
||||
"search_popout.tips.status": "statutu",
|
||||
"search_popout.tips.text": "Un testu simplice rimanda i nomi pubblichi, cugnomi è hashtag",
|
||||
"search_popout.tips.user": "utilizatore",
|
||||
"search_results.accounts": "Ghjente",
|
||||
"search_results.hashtags": "Hashtag",
|
||||
"search_results.statuses": "Statuti",
|
||||
"search_results.total": "{count, number} {count, plural, one {risultatu} other {risultati}}",
|
||||
"standalone.public_title": "Una vista di...",
|
||||
"status.block": "Bluccà @{name}",
|
||||
"status.cancel_reblog_private": "Ùn sparte più",
|
||||
"status.cannot_reblog": "Stu statutu ùn pò micca esse spartutu",
|
||||
"status.delete": "Toglie",
|
||||
"status.direct": "Mandà un missaghju @{name}",
|
||||
"status.embed": "Integrà",
|
||||
"status.favourite": "Aghjunghje à i favuriti",
|
||||
"status.load_more": "Vede di più",
|
||||
"status.media_hidden": "Media piattata",
|
||||
"status.mention": "Mintuvà @{name}",
|
||||
"status.more": "Più",
|
||||
"status.mute": "Piattà @{name}",
|
||||
"status.mute_conversation": "Piattà a cunversazione",
|
||||
"status.open": "Apre stu statutu",
|
||||
"status.pin": "Puntarulà à u prufile",
|
||||
"status.pinned": "Statutu puntarulatu",
|
||||
"status.reblog": "Sparte",
|
||||
"status.reblog_private": "Sparte à l'audienza uriginale",
|
||||
"status.reblogged_by": "{name} hà spartutu",
|
||||
"status.redraft": "Delete & re-draft",
|
||||
"status.reply": "Risponde",
|
||||
"status.replyAll": "Risponde à tutti",
|
||||
"status.report": "Palisà @{name}",
|
||||
"status.sensitive_toggle": "Cliccate per vede",
|
||||
"status.sensitive_warning": "Cuntinutu sensibile",
|
||||
"status.share": "Sparte",
|
||||
"status.show_less": "Ripiegà",
|
||||
"status.show_less_all": "Ripiegà tuttu",
|
||||
"status.show_more": "Slibrà",
|
||||
"status.show_more_all": "Slibrà tuttu",
|
||||
"status.unmute_conversation": "Ùn piattà più a cunversazione",
|
||||
"status.unpin": "Spuntarulà da u prufile",
|
||||
"tabs_bar.federated_timeline": "Glubale",
|
||||
"tabs_bar.home": "Accolta",
|
||||
"tabs_bar.local_timeline": "Lucale",
|
||||
"tabs_bar.notifications": "Nutificazione",
|
||||
"tabs_bar.search": "Cercà",
|
||||
"timeline.media": "Media",
|
||||
"timeline.posts": "Toots",
|
||||
"trends.count_by_accounts": "{count} {rawCount, plural, one {person} other {people}} talking",
|
||||
"ui.beforeunload": "A bruttacopia sarà persa s'ellu hè chjosu Mastodon.",
|
||||
"upload_area.title": "Drag & drop per caricà un fugliale",
|
||||
"upload_button.label": "Aghjunghje un media",
|
||||
"upload_form.description": "Discrive per i malvistosi",
|
||||
"upload_form.focus": "Riquatrà",
|
||||
"upload_form.undo": "Sguassà",
|
||||
"upload_progress.label": "Caricamentu...",
|
||||
"video.close": "Chjudà a video",
|
||||
"video.exit_fullscreen": "Caccià u pienu screnu",
|
||||
"video.expand": "Ingrandà a video",
|
||||
"video.fullscreen": "Pienu screnu",
|
||||
"video.hide": "Piattà a video",
|
||||
"video.mute": "Surdina",
|
||||
"video.pause": "Pausa",
|
||||
"video.play": "Lettura",
|
||||
"video.unmute": "Caccià a surdina"
|
||||
}
|
||||
|
|
@ -1,7 +1,9 @@
|
|||
{
|
||||
"account.badges.bot": "Bot",
|
||||
"account.block": "@{name} blocken",
|
||||
"account.block_domain": "Alles von {domain} verstecken",
|
||||
"account.blocked": "Blockiert",
|
||||
"account.direct": "Direct Message @{name}",
|
||||
"account.disclaimer_full": "Das Profil wird möglicherweise unvollständig wiedergegeben.",
|
||||
"account.domain_blocked": "Domain versteckt",
|
||||
"account.edit_profile": "Profil bearbeiten",
|
||||
|
|
@ -17,7 +19,7 @@
|
|||
"account.mute_notifications": "Benachrichtigungen von @{name} verbergen",
|
||||
"account.muted": "Stummgeschaltet",
|
||||
"account.posts": "Beiträge",
|
||||
"account.posts_with_replies": "Beiträge mit Antworten",
|
||||
"account.posts_with_replies": "Beiträge und Antworten",
|
||||
"account.report": "@{name} melden",
|
||||
"account.requested": "Warte auf Erlaubnis. Klicke zum Abbrechen",
|
||||
"account.share": "Profil von @{name} teilen",
|
||||
|
|
@ -28,8 +30,8 @@
|
|||
"account.unmute": "@{name} nicht mehr stummschalten",
|
||||
"account.unmute_notifications": "Benachrichtigungen von @{name} einschalten",
|
||||
"account.view_full_profile": "Vollständiges Profil anzeigen",
|
||||
"alert.unexpected.message": "An unexpected error occurred.",
|
||||
"alert.unexpected.title": "Oops!",
|
||||
"alert.unexpected.message": "Ein unerwarteter Fehler ist aufgetreten.",
|
||||
"alert.unexpected.title": "Hoppla!",
|
||||
"boost_modal.combo": "Du kannst {combo} drücken, um dies beim nächsten Mal zu überspringen",
|
||||
"bundle_column_error.body": "Etwas ist beim Laden schiefgelaufen.",
|
||||
"bundle_column_error.retry": "Erneut versuchen",
|
||||
|
|
@ -39,6 +41,8 @@
|
|||
"bundle_modal_error.retry": "Erneut versuchen",
|
||||
"column.blocks": "Blockierte Profile",
|
||||
"column.community": "Lokale Zeitleiste",
|
||||
"column.direct": "Direktnachrichten",
|
||||
"column.domain_blocks": "Versteckte Domains",
|
||||
"column.favourites": "Favoriten",
|
||||
"column.follow_requests": "Folgeanfragen",
|
||||
"column.home": "Startseite",
|
||||
|
|
@ -54,18 +58,19 @@
|
|||
"column_header.pin": "Anheften",
|
||||
"column_header.show_settings": "Einstellungen anzeigen",
|
||||
"column_header.unpin": "Lösen",
|
||||
"column_subheading.navigation": "Navigation",
|
||||
"column_subheading.settings": "Einstellungen",
|
||||
"compose_form.direct_message_warning": "Dieser Beitrag wird nur für die erwähnten Nutzer sichtbar sein.",
|
||||
"compose_form.direct_message_warning_learn_more": "Learn more",
|
||||
"compose_form.hashtag_warning": "Dieser Beitrag wird nicht unter einen dieser Hashtags sichtbar sein, solange er ungelistet ist. Bei einer Suche kann er nicht gefunden werden.",
|
||||
"compose_form.lock_disclaimer": "Dein Profil ist nicht {locked}. Wer dir folgen will, kann das jederzeit tun und dann auch deine privaten Beiträge sehen.",
|
||||
"compose_form.lock_disclaimer.lock": "gesperrt",
|
||||
"compose_form.placeholder": "Worüber möchtest du schreiben?",
|
||||
"compose_form.publish": "Tröt",
|
||||
"compose_form.publish_loud": "{publish}!",
|
||||
"compose_form.sensitive.marked": "Media is marked as sensitive",
|
||||
"compose_form.sensitive.unmarked": "Media is not marked as sensitive",
|
||||
"compose_form.spoiler.marked": "Text is hidden behind warning",
|
||||
"compose_form.spoiler.unmarked": "Text is not hidden",
|
||||
"compose_form.sensitive.marked": "Medien sind als heikel markiert",
|
||||
"compose_form.sensitive.unmarked": "Medien sind nicht als heikel markiert",
|
||||
"compose_form.spoiler.marked": "Text ist hinter einer Warnung versteckt",
|
||||
"compose_form.spoiler.unmarked": "Text ist nicht versteckt",
|
||||
"compose_form.spoiler_placeholder": "Inhaltswarnung",
|
||||
"confirmation_modal.cancel": "Abbrechen",
|
||||
"confirmations.block.confirm": "Blockieren",
|
||||
|
|
@ -78,6 +83,8 @@
|
|||
"confirmations.domain_block.message": "Bist du dir wirklich sicher, dass du die ganze Domain {domain} verbergen willst? In den meisten Fällen reichen ein paar gezielte Blocks aus.",
|
||||
"confirmations.mute.confirm": "Stummschalten",
|
||||
"confirmations.mute.message": "Bist du dir sicher, dass du {name} stummschalten möchtest?",
|
||||
"confirmations.redraft.confirm": "Delete & redraft",
|
||||
"confirmations.redraft.message": "Are you sure you want to delete this status and re-draft it? You will lose all replies, boosts and favourites to it.",
|
||||
"confirmations.unfollow.confirm": "Entfolgen",
|
||||
"confirmations.unfollow.message": "Bist du dir sicher, dass du {name} entfolgen möchtest?",
|
||||
"embed.instructions": "Du kannst diesen Beitrag auf deiner Webseite einbetten, indem du den folgenden Code einfügst.",
|
||||
|
|
@ -97,6 +104,7 @@
|
|||
"emoji_button.symbols": "Symbole",
|
||||
"emoji_button.travel": "Reisen und Orte",
|
||||
"empty_column.community": "Die lokale Zeitleiste ist leer. Schreibe einen öffentlichen Beitrag, um den Ball ins Rollen zu bringen!",
|
||||
"empty_column.direct": "Du hast noch keine Direktnachrichten erhalten. Wenn du eine sendest oder empfängst, wird sie hier zu sehen sein.",
|
||||
"empty_column.hashtag": "Unter diesem Hashtag gibt es noch nichts.",
|
||||
"empty_column.home": "Deine Startseite ist leer! Besuche {public} oder nutze die Suche, um loszulegen und andere Leute zu finden.",
|
||||
"empty_column.home.public_timeline": "die öffentliche Zeitleiste",
|
||||
|
|
@ -105,11 +113,10 @@
|
|||
"empty_column.public": "Hier ist nichts zu sehen! Schreibe etwas öffentlich oder folge Profilen von anderen Instanzen, um die Zeitleiste aufzufüllen",
|
||||
"follow_request.authorize": "Erlauben",
|
||||
"follow_request.reject": "Ablehnen",
|
||||
"getting_started.appsshort": "Apps",
|
||||
"getting_started.faq": "Häufig gestellte Fragen",
|
||||
"getting_started.documentation": "Documentation",
|
||||
"getting_started.heading": "Erste Schritte",
|
||||
"getting_started.open_source_notice": "Mastodon ist quelloffene Software. Du kannst auf GitHub unter {github} dazu beitragen oder Probleme melden.",
|
||||
"getting_started.userguide": "Bedienungsanleitung",
|
||||
"getting_started.terms": "Terms of service",
|
||||
"home.column_settings.advanced": "Erweitert",
|
||||
"home.column_settings.basic": "Einfach",
|
||||
"home.column_settings.filter_regex": "Mit regulären Ausdrücken filtern",
|
||||
|
|
@ -125,11 +132,12 @@
|
|||
"keyboard_shortcuts.enter": "um den Status zu öffnen",
|
||||
"keyboard_shortcuts.favourite": "um zu favorisieren",
|
||||
"keyboard_shortcuts.heading": "Tastenkombinationen",
|
||||
"keyboard_shortcuts.hotkey": "Hotkey",
|
||||
"keyboard_shortcuts.hotkey": "Tastenkürzel",
|
||||
"keyboard_shortcuts.legend": "um diese Übersicht anzuzeigen",
|
||||
"keyboard_shortcuts.mention": "um Autor_in zu erwähnen",
|
||||
"keyboard_shortcuts.reply": "um zu antworten",
|
||||
"keyboard_shortcuts.search": "um die Suche zu fokussieren",
|
||||
"keyboard_shortcuts.toggle_hidden": "um den Text hinter einer Inhaltswarnung zu verstecken oder ihn anzuzeigen",
|
||||
"keyboard_shortcuts.toot": "um einen neuen Toot zu beginnen",
|
||||
"keyboard_shortcuts.unfocus": "um das Textfeld/die Suche nicht mehr zu fokussieren",
|
||||
"keyboard_shortcuts.up": "sich in der Liste hinauf bewegen",
|
||||
|
|
@ -151,6 +159,9 @@
|
|||
"mute_modal.hide_notifications": "Benachrichtigungen von diesem Account verbergen?",
|
||||
"navigation_bar.blocks": "Blockierte Profile",
|
||||
"navigation_bar.community_timeline": "Lokale Zeitleiste",
|
||||
"navigation_bar.direct": "Direktnachrichten",
|
||||
"navigation_bar.discover": "Discover",
|
||||
"navigation_bar.domain_blocks": "Versteckte Domains",
|
||||
"navigation_bar.edit_profile": "Profil bearbeiten",
|
||||
"navigation_bar.favourites": "Favoriten",
|
||||
"navigation_bar.follow_requests": "Folgeanfragen",
|
||||
|
|
@ -159,9 +170,11 @@
|
|||
"navigation_bar.lists": "Listen",
|
||||
"navigation_bar.logout": "Abmelden",
|
||||
"navigation_bar.mutes": "Stummgeschaltete Profile",
|
||||
"navigation_bar.personal": "Personal",
|
||||
"navigation_bar.pins": "Angeheftete Beiträge",
|
||||
"navigation_bar.preferences": "Einstellungen",
|
||||
"navigation_bar.public_timeline": "Föderierte Zeitleiste",
|
||||
"navigation_bar.security": "Security",
|
||||
"notification.favourite": "{name} hat deinen Beitrag favorisiert",
|
||||
"notification.follow": "{name} folgt dir",
|
||||
"notification.mention": "{name} hat dich erwähnt",
|
||||
|
|
@ -177,14 +190,15 @@
|
|||
"notifications.column_settings.reblog": "Geteilte Beiträge:",
|
||||
"notifications.column_settings.show": "In der Spalte anzeigen",
|
||||
"notifications.column_settings.sound": "Ton abspielen",
|
||||
"notifications.group": "{count} notifications",
|
||||
"onboarding.done": "Fertig",
|
||||
"onboarding.next": "Weiter",
|
||||
"onboarding.page_five.public_timelines": "Die lokale Zeitleiste zeigt alle Beiträge von Leuten, die auch auf {domain} sind. Das gesamte bekannte Netz zeigt Beiträge von allen, denen von Leuten auf {domain} gefolgt wird. Zusammen sind sie die öffentlichen Zeitleisten, ein guter Weg, um neue Leute zu finden.",
|
||||
"onboarding.page_four.home": "Die Startseite zeigt dir Beiträge von Leuten, denen du folgst.",
|
||||
"onboarding.page_four.notifications": "Wenn jemand mit dir interagiert, bekommst du eine Mitteilung.",
|
||||
"onboarding.page_one.federation": "Mastodon ist ein soziales Netzwerk, das aus unabhängigen Servern besteht. Diese Server nennen wir auch Instanzen.",
|
||||
"onboarding.page_one.full_handle": "Your full handle",
|
||||
"onboarding.page_one.handle_hint": "This is what you would tell your friends to search for.",
|
||||
"onboarding.page_one.full_handle": "Dein vollständiger Benutzername",
|
||||
"onboarding.page_one.handle_hint": "Das ist das, was du deinen Freunden sagst, um nach dir zu suchen.",
|
||||
"onboarding.page_one.welcome": "Willkommen bei Mastodon!",
|
||||
"onboarding.page_six.admin": "Für deine Instanz ist {admin} zuständig.",
|
||||
"onboarding.page_six.almost_done": "Fast fertig …",
|
||||
|
|
@ -207,48 +221,52 @@
|
|||
"privacy.public.short": "Öffentlich",
|
||||
"privacy.unlisted.long": "Nicht in öffentlichen Zeitleisten anzeigen",
|
||||
"privacy.unlisted.short": "Nicht gelistet",
|
||||
"regeneration_indicator.label": "Loading…",
|
||||
"regeneration_indicator.sublabel": "Your home feed is being prepared!",
|
||||
"regeneration_indicator.label": "Laden…",
|
||||
"regeneration_indicator.sublabel": "Deine Heimzeitleiste wird gerade vorbereitet!",
|
||||
"relative_time.days": "{number}d",
|
||||
"relative_time.hours": "{number}h",
|
||||
"relative_time.just_now": "now",
|
||||
"relative_time.just_now": "jetzt",
|
||||
"relative_time.minutes": "{number}m",
|
||||
"relative_time.seconds": "{number}s",
|
||||
"reply_indicator.cancel": "Abbrechen",
|
||||
"report.forward": "Forward to {target}",
|
||||
"report.forward_hint": "The account is from another server. Send an anonymized copy of the report there as well?",
|
||||
"report.hint": "The report will be sent to your instance moderators. You can provide an explanation of why you are reporting this account below:",
|
||||
"report.forward": "An {target} weiterleiten",
|
||||
"report.forward_hint": "Dieses Konto ist von einem anderen Server. Soll eine anonymisierte Kopie des Berichts auch dorthin geschickt werden?",
|
||||
"report.hint": "Der Bericht wird an die Moderatoren deiner Instanz geschickt. Du kannst hier eine Erklärung angeben, warum du dieses Konto meldest:",
|
||||
"report.placeholder": "Zusätzliche Kommentare",
|
||||
"report.submit": "Absenden",
|
||||
"report.target": "{target} melden",
|
||||
"search.placeholder": "Suche",
|
||||
"search_popout.search_format": "Advanced search format",
|
||||
"search_popout.tips.full_text": "Simple text returns statuses you have written, favourited, boosted, or have been mentioned in, as well as matching usernames, display names, and hashtags.",
|
||||
"search_popout.tips.hashtag": "hashtag",
|
||||
"search_popout.search_format": "Fortgeschrittenes Suchformat",
|
||||
"search_popout.tips.full_text": "Simpler Text gibt Beiträge, die du geschrieben, favorisiert und geteilt hast zurück. Außerdem auch Beiträge in denen du erwähnt wurdest, als auch passende Nutzernamen, Anzeigenamen oder Hashtags.",
|
||||
"search_popout.tips.hashtag": "Hashtag",
|
||||
"search_popout.tips.status": "status",
|
||||
"search_popout.tips.text": "Simple text returns matching display names, usernames and hashtags",
|
||||
"search_popout.tips.user": "user",
|
||||
"search_results.accounts": "People",
|
||||
"search_popout.tips.text": "Einfacher Text gibt Anzeigenamen, Benutzernamen und Hashtags zurück",
|
||||
"search_popout.tips.user": "Nutzer",
|
||||
"search_results.accounts": "Personen",
|
||||
"search_results.hashtags": "Hashtags",
|
||||
"search_results.statuses": "Toots",
|
||||
"search_results.statuses": "Beiträge",
|
||||
"search_results.total": "{count, number} {count, plural, one {Ergebnis} other {Ergebnisse}}",
|
||||
"standalone.public_title": "Ein kleiner Einblick …",
|
||||
"status.block": "Block @{name}",
|
||||
"status.cancel_reblog_private": "Nicht mehr teilen",
|
||||
"status.cannot_reblog": "Dieser Beitrag kann nicht geteilt werden",
|
||||
"status.delete": "Löschen",
|
||||
"status.direct": "Direktnachricht @{name}",
|
||||
"status.embed": "Einbetten",
|
||||
"status.favourite": "Favorisieren",
|
||||
"status.load_more": "Weitere laden",
|
||||
"status.media_hidden": "Medien versteckt",
|
||||
"status.mention": "@{name} erwähnen",
|
||||
"status.more": "Mehr",
|
||||
"status.mute": "Mute @{name}",
|
||||
"status.mute": "@{name} stummschalten",
|
||||
"status.mute_conversation": "Thread stummschalten",
|
||||
"status.open": "Diesen Beitrag öffnen",
|
||||
"status.pin": "Im Profil anheften",
|
||||
"status.pinned": "Pinned toot",
|
||||
"status.pinned": "Angehefteter Beitrag",
|
||||
"status.reblog": "Teilen",
|
||||
"status.reblog_private": "An das eigentliche Publikum teilen",
|
||||
"status.reblogged_by": "{name} teilte",
|
||||
"status.redraft": "Delete & re-draft",
|
||||
"status.reply": "Antworten",
|
||||
"status.replyAll": "Auf Thread antworten",
|
||||
"status.report": "@{name} melden",
|
||||
|
|
@ -256,20 +274,24 @@
|
|||
"status.sensitive_warning": "Heikle Inhalte",
|
||||
"status.share": "Teilen",
|
||||
"status.show_less": "Weniger anzeigen",
|
||||
"status.show_less_all": "Show less for all",
|
||||
"status.show_less_all": "Zeige weniger für alles",
|
||||
"status.show_more": "Mehr anzeigen",
|
||||
"status.show_more_all": "Show more for all",
|
||||
"status.show_more_all": "Zeige mehr für alles",
|
||||
"status.unmute_conversation": "Stummschaltung von Thread aufheben",
|
||||
"status.unpin": "Vom Profil lösen",
|
||||
"tabs_bar.federated_timeline": "Föderation",
|
||||
"tabs_bar.home": "Startseite",
|
||||
"tabs_bar.local_timeline": "Lokal",
|
||||
"tabs_bar.notifications": "Mitteilungen",
|
||||
"ui.beforeunload": "Your draft will be lost if you leave Mastodon.",
|
||||
"tabs_bar.search": "Suchen",
|
||||
"timeline.media": "Media",
|
||||
"timeline.posts": "Toots",
|
||||
"trends.count_by_accounts": "{count} {rawCount, plural, one {person} other {people}} talking",
|
||||
"ui.beforeunload": "Dein Entwurf geht verloren, wenn du Mastodon verlässt.",
|
||||
"upload_area.title": "Zum Hochladen hereinziehen",
|
||||
"upload_button.label": "Mediendatei hinzufügen",
|
||||
"upload_form.description": "Für Menschen mit Sehbehinderung beschreiben",
|
||||
"upload_form.focus": "Crop",
|
||||
"upload_form.focus": "Zuschneiden",
|
||||
"upload_form.undo": "Entfernen",
|
||||
"upload_progress.label": "Wird hochgeladen …",
|
||||
"video.close": "Video schließen",
|
||||
|
|
|
|||
|
|
@ -1,9 +1,26 @@
|
|||
[
|
||||
{
|
||||
"descriptors": [
|
||||
{
|
||||
"defaultMessage": "Oops!",
|
||||
"id": "alert.unexpected.title"
|
||||
},
|
||||
{
|
||||
"defaultMessage": "An unexpected error occurred.",
|
||||
"id": "alert.unexpected.message"
|
||||
}
|
||||
],
|
||||
"path": "app/javascript/mastodon/actions/alerts.json"
|
||||
},
|
||||
{
|
||||
"descriptors": [
|
||||
{
|
||||
"defaultMessage": "{name} mentioned you",
|
||||
"id": "notification.mention"
|
||||
},
|
||||
{
|
||||
"defaultMessage": "{count} notifications",
|
||||
"id": "notifications.group"
|
||||
}
|
||||
],
|
||||
"path": "app/javascript/mastodon/actions/notifications.json"
|
||||
|
|
@ -92,6 +109,33 @@
|
|||
],
|
||||
"path": "app/javascript/mastodon/components/column_header.json"
|
||||
},
|
||||
{
|
||||
"descriptors": [
|
||||
{
|
||||
"defaultMessage": "Unhide {domain}",
|
||||
"id": "account.unblock_domain"
|
||||
}
|
||||
],
|
||||
"path": "app/javascript/mastodon/components/domain.json"
|
||||
},
|
||||
{
|
||||
"descriptors": [
|
||||
{
|
||||
"defaultMessage": "{count} {rawCount, plural, one {person} other {people}} talking",
|
||||
"id": "trends.count_by_accounts"
|
||||
}
|
||||
],
|
||||
"path": "app/javascript/mastodon/components/hashtag.json"
|
||||
},
|
||||
{
|
||||
"descriptors": [
|
||||
{
|
||||
"defaultMessage": "Load more",
|
||||
"id": "status.load_more"
|
||||
}
|
||||
],
|
||||
"path": "app/javascript/mastodon/components/load_gap.json"
|
||||
},
|
||||
{
|
||||
"descriptors": [
|
||||
{
|
||||
|
|
@ -175,6 +219,14 @@
|
|||
"defaultMessage": "Delete",
|
||||
"id": "status.delete"
|
||||
},
|
||||
{
|
||||
"defaultMessage": "Delete & re-draft",
|
||||
"id": "status.redraft"
|
||||
},
|
||||
{
|
||||
"defaultMessage": "Direct message @{name}",
|
||||
"id": "status.direct"
|
||||
},
|
||||
{
|
||||
"defaultMessage": "Mention @{name}",
|
||||
"id": "status.mention"
|
||||
|
|
@ -207,6 +259,14 @@
|
|||
"defaultMessage": "Boost",
|
||||
"id": "status.reblog"
|
||||
},
|
||||
{
|
||||
"defaultMessage": "Boost to original audience",
|
||||
"id": "status.reblog_private"
|
||||
},
|
||||
{
|
||||
"defaultMessage": "Unboost",
|
||||
"id": "status.cancel_reblog_private"
|
||||
},
|
||||
{
|
||||
"defaultMessage": "This post cannot be boosted",
|
||||
"id": "status.cannot_reblog"
|
||||
|
|
@ -298,6 +358,19 @@
|
|||
],
|
||||
"path": "app/javascript/mastodon/containers/account_container.json"
|
||||
},
|
||||
{
|
||||
"descriptors": [
|
||||
{
|
||||
"defaultMessage": "Hide entire domain",
|
||||
"id": "confirmations.domain_block.confirm"
|
||||
},
|
||||
{
|
||||
"defaultMessage": "Are you really, really sure you want to block the entire {domain}? In most cases a few targeted blocks or mutes are sufficient and preferable.",
|
||||
"id": "confirmations.domain_block.message"
|
||||
}
|
||||
],
|
||||
"path": "app/javascript/mastodon/containers/domain_container.json"
|
||||
},
|
||||
{
|
||||
"descriptors": [
|
||||
{
|
||||
|
|
@ -308,6 +381,14 @@
|
|||
"defaultMessage": "Are you sure you want to delete this status?",
|
||||
"id": "confirmations.delete.message"
|
||||
},
|
||||
{
|
||||
"defaultMessage": "Delete & redraft",
|
||||
"id": "confirmations.redraft.confirm"
|
||||
},
|
||||
{
|
||||
"defaultMessage": "Are you sure you want to delete this status and re-draft it? You will lose all replies, boosts and favourites to it.",
|
||||
"id": "confirmations.redraft.message"
|
||||
},
|
||||
{
|
||||
"defaultMessage": "Block",
|
||||
"id": "confirmations.block.confirm"
|
||||
|
|
@ -368,7 +449,7 @@
|
|||
"id": "confirmations.block.message"
|
||||
},
|
||||
{
|
||||
"defaultMessage": "Are you really, really sure you want to block the entire {domain}? In most cases a few targeted blocks or mutes are sufficient and preferable.",
|
||||
"defaultMessage": "Are you really, really sure you want to block the entire {domain}? In most cases a few targeted blocks or mutes are sufficient and preferable. You will not see content from that domain in any public timelines or your notifications. Your followers from that domain will be removed.",
|
||||
"id": "confirmations.domain_block.message"
|
||||
}
|
||||
],
|
||||
|
|
@ -380,6 +461,10 @@
|
|||
"defaultMessage": "Mention @{name}",
|
||||
"id": "account.mention"
|
||||
},
|
||||
{
|
||||
"defaultMessage": "Direct message @{name}",
|
||||
"id": "account.direct"
|
||||
},
|
||||
{
|
||||
"defaultMessage": "Edit profile",
|
||||
"id": "account.edit_profile"
|
||||
|
|
@ -436,6 +521,38 @@
|
|||
"defaultMessage": "Show boosts from @{name}",
|
||||
"id": "account.show_reblogs"
|
||||
},
|
||||
{
|
||||
"defaultMessage": "Pinned toots",
|
||||
"id": "navigation_bar.pins"
|
||||
},
|
||||
{
|
||||
"defaultMessage": "Preferences",
|
||||
"id": "navigation_bar.preferences"
|
||||
},
|
||||
{
|
||||
"defaultMessage": "Follow requests",
|
||||
"id": "navigation_bar.follow_requests"
|
||||
},
|
||||
{
|
||||
"defaultMessage": "Favourites",
|
||||
"id": "navigation_bar.favourites"
|
||||
},
|
||||
{
|
||||
"defaultMessage": "Lists",
|
||||
"id": "navigation_bar.lists"
|
||||
},
|
||||
{
|
||||
"defaultMessage": "Blocked users",
|
||||
"id": "navigation_bar.blocks"
|
||||
},
|
||||
{
|
||||
"defaultMessage": "Hidden domains",
|
||||
"id": "navigation_bar.domain_blocks"
|
||||
},
|
||||
{
|
||||
"defaultMessage": "Muted users",
|
||||
"id": "navigation_bar.mutes"
|
||||
},
|
||||
{
|
||||
"defaultMessage": "Information below may reflect the user's profile incompletely.",
|
||||
"id": "account.disclaimer_full"
|
||||
|
|
@ -477,6 +594,10 @@
|
|||
"defaultMessage": "Unblock @{name}",
|
||||
"id": "account.unblock"
|
||||
},
|
||||
{
|
||||
"defaultMessage": "Edit profile",
|
||||
"id": "account.edit_profile"
|
||||
},
|
||||
{
|
||||
"defaultMessage": "Follows you",
|
||||
"id": "account.follows_you"
|
||||
|
|
@ -492,6 +613,10 @@
|
|||
{
|
||||
"defaultMessage": "Domain hidden",
|
||||
"id": "account.domain_blocked"
|
||||
},
|
||||
{
|
||||
"defaultMessage": "Bot",
|
||||
"id": "account.badges.bot"
|
||||
}
|
||||
],
|
||||
"path": "app/javascript/mastodon/features/account/components/header.json"
|
||||
|
|
@ -522,6 +647,19 @@
|
|||
],
|
||||
"path": "app/javascript/mastodon/features/community_timeline/components/column_settings.json"
|
||||
},
|
||||
{
|
||||
"descriptors": [
|
||||
{
|
||||
"defaultMessage": "Toots",
|
||||
"id": "timeline.posts"
|
||||
},
|
||||
{
|
||||
"defaultMessage": "Media",
|
||||
"id": "timeline.media"
|
||||
}
|
||||
],
|
||||
"path": "app/javascript/mastodon/features/community_timeline/components/section_headline.json"
|
||||
},
|
||||
{
|
||||
"descriptors": [
|
||||
{
|
||||
|
|
@ -755,7 +893,7 @@
|
|||
"id": "upload_form.description"
|
||||
},
|
||||
{
|
||||
"defaultMessage": "Undo",
|
||||
"defaultMessage": "Delete",
|
||||
"id": "upload_form.undo"
|
||||
},
|
||||
{
|
||||
|
|
@ -804,6 +942,14 @@
|
|||
{
|
||||
"defaultMessage": "This toot won't be listed under any hashtag as it is unlisted. Only public toots can be searched by hashtag.",
|
||||
"id": "compose_form.hashtag_warning"
|
||||
},
|
||||
{
|
||||
"defaultMessage": "This toot will only be sent to all the mentioned users.",
|
||||
"id": "compose_form.direct_message_warning"
|
||||
},
|
||||
{
|
||||
"defaultMessage": "Learn more",
|
||||
"id": "compose_form.direct_message_warning_learn_more"
|
||||
}
|
||||
],
|
||||
"path": "app/javascript/mastodon/features/compose/containers/warning_container.json"
|
||||
|
|
@ -841,6 +987,32 @@
|
|||
],
|
||||
"path": "app/javascript/mastodon/features/compose/index.json"
|
||||
},
|
||||
{
|
||||
"descriptors": [
|
||||
{
|
||||
"defaultMessage": "Direct messages",
|
||||
"id": "column.direct"
|
||||
},
|
||||
{
|
||||
"defaultMessage": "You don't have any direct messages yet. When you send or receive one, it will show up here.",
|
||||
"id": "empty_column.direct"
|
||||
}
|
||||
],
|
||||
"path": "app/javascript/mastodon/features/direct_timeline/index.json"
|
||||
},
|
||||
{
|
||||
"descriptors": [
|
||||
{
|
||||
"defaultMessage": "Hidden domains",
|
||||
"id": "column.domain_blocks"
|
||||
},
|
||||
{
|
||||
"defaultMessage": "Unhide {domain}",
|
||||
"id": "account.unblock_domain"
|
||||
}
|
||||
],
|
||||
"path": "app/javascript/mastodon/features/domain_blocks/index.json"
|
||||
},
|
||||
{
|
||||
"descriptors": [
|
||||
{
|
||||
|
|
@ -874,10 +1046,6 @@
|
|||
},
|
||||
{
|
||||
"descriptors": [
|
||||
{
|
||||
"defaultMessage": "Getting started",
|
||||
"id": "getting_started.heading"
|
||||
},
|
||||
{
|
||||
"defaultMessage": "Home",
|
||||
"id": "tabs_bar.home"
|
||||
|
|
@ -890,10 +1058,6 @@
|
|||
"defaultMessage": "Federated timeline",
|
||||
"id": "navigation_bar.public_timeline"
|
||||
},
|
||||
{
|
||||
"defaultMessage": "Navigation",
|
||||
"id": "column_subheading.navigation"
|
||||
},
|
||||
{
|
||||
"defaultMessage": "Settings",
|
||||
"id": "column_subheading.settings"
|
||||
|
|
@ -902,6 +1066,10 @@
|
|||
"defaultMessage": "Local timeline",
|
||||
"id": "navigation_bar.community_timeline"
|
||||
},
|
||||
{
|
||||
"defaultMessage": "Direct messages",
|
||||
"id": "navigation_bar.direct"
|
||||
},
|
||||
{
|
||||
"defaultMessage": "Preferences",
|
||||
"id": "navigation_bar.preferences"
|
||||
|
|
@ -910,10 +1078,6 @@
|
|||
"defaultMessage": "Follow requests",
|
||||
"id": "navigation_bar.follow_requests"
|
||||
},
|
||||
{
|
||||
"defaultMessage": "Logout",
|
||||
"id": "navigation_bar.logout"
|
||||
},
|
||||
{
|
||||
"defaultMessage": "Favourites",
|
||||
"id": "navigation_bar.favourites"
|
||||
|
|
@ -923,12 +1087,12 @@
|
|||
"id": "navigation_bar.blocks"
|
||||
},
|
||||
{
|
||||
"defaultMessage": "Muted users",
|
||||
"id": "navigation_bar.mutes"
|
||||
"defaultMessage": "Hidden domains",
|
||||
"id": "navigation_bar.domain_blocks"
|
||||
},
|
||||
{
|
||||
"defaultMessage": "Extended information",
|
||||
"id": "navigation_bar.info"
|
||||
"defaultMessage": "Muted users",
|
||||
"id": "navigation_bar.mutes"
|
||||
},
|
||||
{
|
||||
"defaultMessage": "Pinned toots",
|
||||
|
|
@ -939,20 +1103,40 @@
|
|||
"id": "navigation_bar.lists"
|
||||
},
|
||||
{
|
||||
"defaultMessage": "Keyboard shortcuts",
|
||||
"defaultMessage": "Discover",
|
||||
"id": "navigation_bar.discover"
|
||||
},
|
||||
{
|
||||
"defaultMessage": "Personal",
|
||||
"id": "navigation_bar.personal"
|
||||
},
|
||||
{
|
||||
"defaultMessage": "Security",
|
||||
"id": "navigation_bar.security"
|
||||
},
|
||||
{
|
||||
"defaultMessage": "Getting started",
|
||||
"id": "getting_started.heading"
|
||||
},
|
||||
{
|
||||
"defaultMessage": "Hotkeys",
|
||||
"id": "navigation_bar.keyboard_shortcuts"
|
||||
},
|
||||
{
|
||||
"defaultMessage": "FAQ",
|
||||
"id": "getting_started.faq"
|
||||
"defaultMessage": "About this instance",
|
||||
"id": "navigation_bar.info"
|
||||
},
|
||||
{
|
||||
"defaultMessage": "User Guide",
|
||||
"id": "getting_started.userguide"
|
||||
"defaultMessage": "Terms of service",
|
||||
"id": "getting_started.terms"
|
||||
},
|
||||
{
|
||||
"defaultMessage": "Apps",
|
||||
"id": "getting_started.appsshort"
|
||||
"defaultMessage": "Documentation",
|
||||
"id": "getting_started.documentation"
|
||||
},
|
||||
{
|
||||
"defaultMessage": "Logout",
|
||||
"id": "navigation_bar.logout"
|
||||
},
|
||||
{
|
||||
"defaultMessage": "Mastodon is open source software. You can contribute or report issues on GitHub at {github}.",
|
||||
|
|
@ -1050,6 +1234,10 @@
|
|||
"defaultMessage": "to open status",
|
||||
"id": "keyboard_shortcuts.enter"
|
||||
},
|
||||
{
|
||||
"defaultMessage": "to show/hide text behind CW",
|
||||
"id": "keyboard_shortcuts.toggle_hidden"
|
||||
},
|
||||
{
|
||||
"defaultMessage": "to move up in the list",
|
||||
"id": "keyboard_shortcuts.up"
|
||||
|
|
@ -1310,6 +1498,14 @@
|
|||
"defaultMessage": "Delete",
|
||||
"id": "status.delete"
|
||||
},
|
||||
{
|
||||
"defaultMessage": "Delete & re-draft",
|
||||
"id": "status.redraft"
|
||||
},
|
||||
{
|
||||
"defaultMessage": "Direct message @{name}",
|
||||
"id": "status.direct"
|
||||
},
|
||||
{
|
||||
"defaultMessage": "Mention @{name}",
|
||||
"id": "status.mention"
|
||||
|
|
@ -1322,6 +1518,14 @@
|
|||
"defaultMessage": "Boost",
|
||||
"id": "status.reblog"
|
||||
},
|
||||
{
|
||||
"defaultMessage": "Boost to original audience",
|
||||
"id": "status.reblog_private"
|
||||
},
|
||||
{
|
||||
"defaultMessage": "Unboost",
|
||||
"id": "status.cancel_reblog_private"
|
||||
},
|
||||
{
|
||||
"defaultMessage": "This post cannot be boosted",
|
||||
"id": "status.cannot_reblog"
|
||||
|
|
@ -1379,6 +1583,14 @@
|
|||
"defaultMessage": "Are you sure you want to delete this status?",
|
||||
"id": "confirmations.delete.message"
|
||||
},
|
||||
{
|
||||
"defaultMessage": "Delete & redraft",
|
||||
"id": "confirmations.redraft.confirm"
|
||||
},
|
||||
{
|
||||
"defaultMessage": "Are you sure you want to delete this status and re-draft it? You will lose all replies, boosts and favourites to it.",
|
||||
"id": "confirmations.redraft.message"
|
||||
},
|
||||
{
|
||||
"defaultMessage": "Block",
|
||||
"id": "confirmations.block.confirm"
|
||||
|
|
@ -1657,6 +1869,10 @@
|
|||
"defaultMessage": "Notifications",
|
||||
"id": "tabs_bar.notifications"
|
||||
},
|
||||
{
|
||||
"defaultMessage": "Search",
|
||||
"id": "tabs_bar.search"
|
||||
},
|
||||
{
|
||||
"defaultMessage": "Local",
|
||||
"id": "tabs_bar.local_timeline"
|
||||
|
|
@ -1734,18 +1950,5 @@
|
|||
}
|
||||
],
|
||||
"path": "app/javascript/mastodon/features/video/index.json"
|
||||
},
|
||||
{
|
||||
"descriptors": [
|
||||
{
|
||||
"defaultMessage": "Oops!",
|
||||
"id": "alert.unexpected.title"
|
||||
},
|
||||
{
|
||||
"defaultMessage": "An unexpected error occurred.",
|
||||
"id": "alert.unexpected.message"
|
||||
}
|
||||
],
|
||||
"path": "app/javascript/mastodon/middleware/errors.json"
|
||||
}
|
||||
]
|
||||
306
app/javascript/mastodon/locales/el.json
Normal file
306
app/javascript/mastodon/locales/el.json
Normal file
|
|
@ -0,0 +1,306 @@
|
|||
{
|
||||
"account.badges.bot": "Bot",
|
||||
"account.block": "Απόκλεισε τον/την @{name}",
|
||||
"account.block_domain": "Απόκρυψε τα πάντα από τον/την",
|
||||
"account.blocked": "Αποκλεισμένος/η",
|
||||
"account.direct": "Άμεσο μήνυμα προς @{name}",
|
||||
"account.disclaimer_full": "Οι παρακάτω πληροφορίες μπορει να μην αντανακλούν το προφίλ του χρήστη επαρκως.",
|
||||
"account.domain_blocked": "Κρυμμένος τομέας",
|
||||
"account.edit_profile": "Επεξεργάσου το προφίλ",
|
||||
"account.follow": "Ακολούθησε",
|
||||
"account.followers": "Ακόλουθοι",
|
||||
"account.follows": "Ακολουθεί",
|
||||
"account.follows_you": "Σε ακολουθεί",
|
||||
"account.hide_reblogs": "Απόκρυψη προωθήσεων από @{name}",
|
||||
"account.media": "Πολυμέσα",
|
||||
"account.mention": "Ανάφερε @{name}",
|
||||
"account.moved_to": "{name} μεταφέρθηκε στο:",
|
||||
"account.mute": "Σώπασε τον/την @{name}",
|
||||
"account.mute_notifications": "Σώπασε τις ειδοποιήσεις από τον/την @{name}",
|
||||
"account.muted": "Αποσιωπημένος/η",
|
||||
"account.posts": "Τουτ",
|
||||
"account.posts_with_replies": "Τουτ και απαντήσεις",
|
||||
"account.report": "Κατάγγειλε τον/την @{name}",
|
||||
"account.requested": "Εκκρεμεί έγκριση. Κάνε κλικ για να ακυρώσεις το αίτημα ακολούθησης",
|
||||
"account.share": "Μοιράσου το προφίλ του/της @{name}",
|
||||
"account.show_reblogs": "Δείξε τις προωθήσεις του/της @{name}",
|
||||
"account.unblock": "Ξεμπλόκαρε τον/την @{name}",
|
||||
"account.unblock_domain": "Αποκάλυψε το {domain}",
|
||||
"account.unfollow": "Διακοπή παρακολούθησης",
|
||||
"account.unmute": "Διακοπή αποσιώπησης του/της @{name}",
|
||||
"account.unmute_notifications": "Διακοπή αποσιώπησης ειδοποιήσεων του/της @{name}",
|
||||
"account.view_full_profile": "Δες το πλήρες προφίλ",
|
||||
"alert.unexpected.message": "Προέκυψε απροσδόκητο σφάλμα.",
|
||||
"alert.unexpected.title": "Εεπ!",
|
||||
"boost_modal.combo": "Μπορείς να πατήσεις {combo} για να το προσπεράσεις αυτό την επόμενη φορά",
|
||||
"bundle_column_error.body": "Κάτι πήγε στραβά ενώ φορτωνόταν αυτό το στοιχείο.",
|
||||
"bundle_column_error.retry": "Δοκίμασε ξανά",
|
||||
"bundle_column_error.title": "Σφάλμα δικτύου",
|
||||
"bundle_modal_error.close": "Κλείσε",
|
||||
"bundle_modal_error.message": "Κάτι πήγε στραβά ενώ φορτωνόταν αυτό το στοιχείο.",
|
||||
"bundle_modal_error.retry": "Δοκίμασε ξανά",
|
||||
"column.blocks": "Αποκλεισμένοι χρήστες",
|
||||
"column.community": "Τοπική ροή",
|
||||
"column.direct": "Απευθείας μηνύματα",
|
||||
"column.domain_blocks": "Κρυμμένοι τομείς",
|
||||
"column.favourites": "Αγαπημένα",
|
||||
"column.follow_requests": "Αιτήματα ακολούθησης",
|
||||
"column.home": "Αρχική",
|
||||
"column.lists": "Λίστες",
|
||||
"column.mutes": "Αποσιωπημένοι χρήστες",
|
||||
"column.notifications": "Ειδοποιήσεις",
|
||||
"column.pins": "Καρφιτσωμένα τουτ",
|
||||
"column.public": "Ομοσπονδιακή ροή",
|
||||
"column_back_button.label": "Πίσω",
|
||||
"column_header.hide_settings": "Απόκρυψη ρυθμίσεων",
|
||||
"column_header.moveLeft_settings": "Μεταφορά κολώνας αριστερά",
|
||||
"column_header.moveRight_settings": "Μεταφορά κολώνας δεξιά",
|
||||
"column_header.pin": "Καρφίτσωμα",
|
||||
"column_header.show_settings": "Εμφάνιση ρυθμίσεων",
|
||||
"column_header.unpin": "Ξεκαρφίτσωμα",
|
||||
"column_subheading.settings": "Ρυθμίσεις",
|
||||
"compose_form.direct_message_warning": "Αυτό το τουτ θα σταλεί μόνο στους αναφερόμενους χρήστες.",
|
||||
"compose_form.direct_message_warning_learn_more": "Μάθετε περισσότερα",
|
||||
"compose_form.hashtag_warning": "Αυτό το τουτ δεν θα εμφανίζεται κάτω από κανένα hashtag καθώς είναι αφανές. Μόνο τα δημόσια τουτ μπορούν να αναζητηθούν ανά hashtag.",
|
||||
"compose_form.lock_disclaimer": "Ο λογαριασμός σου δεν είναι {locked}. Οποιοσδήποτε μπορεί να σε ακολουθήσει για να δει τις δημοσιεύσεις σας προς τους ακολούθους σας.",
|
||||
"compose_form.lock_disclaimer.lock": "κλειδωμένος",
|
||||
"compose_form.placeholder": "Τι σκέφτεσαι;",
|
||||
"compose_form.publish": "Τουτ",
|
||||
"compose_form.publish_loud": "{publish}!",
|
||||
"compose_form.sensitive.marked": "Το πολυμέσο έχει σημειωθεί ως ευαίσθητο",
|
||||
"compose_form.sensitive.unmarked": "Το πολυμέσο δεν έχει σημειωθεί ως ευαίσθητο",
|
||||
"compose_form.spoiler.marked": "Κείμενο κρυμμένο πίσω από προειδοποίηση",
|
||||
"compose_form.spoiler.unmarked": "Κείμενο μη κρυμμένο",
|
||||
"compose_form.spoiler_placeholder": "Γράψε την προειδοποίησή σου εδώ",
|
||||
"confirmation_modal.cancel": "Άκυρο",
|
||||
"confirmations.block.confirm": "Απόκλεισε",
|
||||
"confirmations.block.message": "Σίγουρα θες να αποκλείσεις τον/την {name};",
|
||||
"confirmations.delete.confirm": "Διέγραψε",
|
||||
"confirmations.delete.message": "Σίγουρα θες να διαγράψεις αυτή την κατάσταση;",
|
||||
"confirmations.delete_list.confirm": "Διέγραψε",
|
||||
"confirmations.delete_list.message": "Σίγουρα θες να διαγράψεις οριστικά αυτή τη λίστα;",
|
||||
"confirmations.domain_block.confirm": "Απόκρυψη ολόκληρου του τομέα",
|
||||
"confirmations.domain_block.message": "Σίγουρα θες να μπλοκάρεις ολόκληρο το {domain}; Συνήθως μερικά εστιασμένα μπλοκ ή αποσιωπήσεις επαρκούν και προτιμούνται.",
|
||||
"confirmations.mute.confirm": "Αποσιώπηση",
|
||||
"confirmations.mute.message": "Σίγουρα θες να αποσιωπήσεις τον/την {name};",
|
||||
"confirmations.redraft.confirm": "Delete & redraft",
|
||||
"confirmations.redraft.message": "Are you sure you want to delete this status and re-draft it? You will lose all replies, boosts and favourites to it.",
|
||||
"confirmations.unfollow.confirm": "Διακοπή παρακολούθησης",
|
||||
"confirmations.unfollow.message": "Σίγουρα θες να πάψεις να ακολουθείς τον/την {name};",
|
||||
"embed.instructions": "Ενσωματώστε αυτή την κατάσταση στην ιστοσελίδα σας αντιγράφοντας τον παρακάτω κώδικα.",
|
||||
"embed.preview": "Ορίστε πως θα φαίνεται:",
|
||||
"emoji_button.activity": "Δραστηριότητα",
|
||||
"emoji_button.custom": "Προσαρμοσμένα",
|
||||
"emoji_button.flags": "Σημαίες",
|
||||
"emoji_button.food": "Φαγητά & Ποτά",
|
||||
"emoji_button.label": "Εισάγετε emoji",
|
||||
"emoji_button.nature": "Φύση",
|
||||
"emoji_button.not_found": "Ουδέν emojo!! (╯°□°)╯︵ ┻━┻",
|
||||
"emoji_button.objects": "Αντικείμενα",
|
||||
"emoji_button.people": "Άνθρωποι",
|
||||
"emoji_button.recent": "Δημοφιλή",
|
||||
"emoji_button.search": "Αναζήτηση…",
|
||||
"emoji_button.search_results": "Αποτελέσματα αναζήτησης",
|
||||
"emoji_button.symbols": "Σύμβολα",
|
||||
"emoji_button.travel": "Ταξίδια & Τοποθεσίες",
|
||||
"empty_column.community": "Η τοπική ροή είναι κενή. Γράψε κάτι δημόσιο παραμύθι ν' αρχινίσει!",
|
||||
"empty_column.direct": "Δεν έχεις απευθείας μηνύματα ακόμα. Όταν στείλεις ή λάβεις κανένα, θα εμφανιστεί εδώ.",
|
||||
"empty_column.hashtag": "Δεν υπάρχει ακόμα κάτι για αυτή την ταμπέλα.",
|
||||
"empty_column.home": "Η τοπική σου ροή είναι κενή! Πήγαινε στο {public} ή κάνε αναζήτηση για να ξεκινήσεις και να γνωρίσεις άλλους χρήστες.",
|
||||
"empty_column.home.public_timeline": "η δημόσια ροή",
|
||||
"empty_column.list": "Δεν υπάρχει τίποτα σε αυτή τη λίστα ακόμα. Όταν τα μέλη της δημοσιεύσουν νέες καταστάσεις, θα εμφανιστούν εδώ.",
|
||||
"empty_column.notifications": "Δεν έχεις ειδοποιήσεις ακόμα. Αλληλεπίδρασε με άλλους χρήστες για να ξεκινήσεις την κουβέντα.",
|
||||
"empty_column.public": "Δεν υπάρχει τίποτα εδώ! Γράψε κάτι δημόσιο, ή ακολούθησε χειροκίνητα χρήστες από άλλα instances για να τη γεμίσεις",
|
||||
"follow_request.authorize": "Ενέκρινε",
|
||||
"follow_request.reject": "Απέρριψε",
|
||||
"getting_started.documentation": "Documentation",
|
||||
"getting_started.heading": "Ξεκινώντας",
|
||||
"getting_started.open_source_notice": "Το Mastodon είναι ελεύθερο λογισμικό. Μπορείς να συνεισφέρεις ή να αναφέρεις ζητήματα στο GitHub στο {github}.",
|
||||
"getting_started.terms": "Terms of service",
|
||||
"home.column_settings.advanced": "Προχωρημένα",
|
||||
"home.column_settings.basic": "Βασικά",
|
||||
"home.column_settings.filter_regex": "Φιλτράρετε μέσω regular expressions",
|
||||
"home.column_settings.show_reblogs": "Εμφάνιση προωθήσεων",
|
||||
"home.column_settings.show_replies": "Εμφάνιση απαντήσεων",
|
||||
"home.settings": "Ρυθμίσεις στηλών",
|
||||
"keyboard_shortcuts.back": "για επιστροφή πίσω",
|
||||
"keyboard_shortcuts.boost": "για προώθηση",
|
||||
"keyboard_shortcuts.column": "για εστίαση μιας κατάστασης σε μια από τις στήλες",
|
||||
"keyboard_shortcuts.compose": "για εστίαση στην περιοχή κειμένου συγγραφής",
|
||||
"keyboard_shortcuts.description": "Description",
|
||||
"keyboard_shortcuts.down": "για κίνηση προς τα κάτω στη λίστα",
|
||||
"keyboard_shortcuts.enter": "to open status",
|
||||
"keyboard_shortcuts.favourite": "για σημείωση αγαπημένου",
|
||||
"keyboard_shortcuts.heading": "Keyboard Shortcuts",
|
||||
"keyboard_shortcuts.hotkey": "Συντόμευση",
|
||||
"keyboard_shortcuts.legend": "για να εμφανίσεις αυτόν τον οδηγό",
|
||||
"keyboard_shortcuts.mention": "για να αναφέρεις το συγγραφέα",
|
||||
"keyboard_shortcuts.reply": "για απάντηση",
|
||||
"keyboard_shortcuts.search": "για εστίαση αναζήτησης",
|
||||
"keyboard_shortcuts.toggle_hidden": "για εμφάνιση/απόκρυψη κειμένου πίσω από την προειδοποίηση",
|
||||
"keyboard_shortcuts.toot": "για δημιουργία ολοκαίνουριου τουτ",
|
||||
"keyboard_shortcuts.unfocus": "για την απο-εστίαση του πεδίου σύνθεσης/αναζήτησης",
|
||||
"keyboard_shortcuts.up": "για να ανέβεις στη λίστα",
|
||||
"lightbox.close": "Close",
|
||||
"lightbox.next": "Επόμενο",
|
||||
"lightbox.previous": "Προηγούμενο",
|
||||
"lists.account.add": "Πρόσθεσε στη λίστα",
|
||||
"lists.account.remove": "Αφαίρεσε από τη λίστα",
|
||||
"lists.delete": "Delete list",
|
||||
"lists.edit": "Τροποποίησε τη λίστα",
|
||||
"lists.new.create": "Πρόσθεσε λίστα",
|
||||
"lists.new.title_placeholder": "Τίτλος νέας λίστα",
|
||||
"lists.search": "Αναζήτησε ανάμεσα σε όσους/όσες ακολουθείς",
|
||||
"lists.subheading": "Οι λίστες σου",
|
||||
"loading_indicator.label": "Φορτώνει...",
|
||||
"media_gallery.toggle_visible": "Αντιστροφή ορατότητας",
|
||||
"missing_indicator.label": "Δε βρέθηκε",
|
||||
"missing_indicator.sublabel": "Αυτό το υλικό δε βρέθηκε",
|
||||
"mute_modal.hide_notifications": "Απόκρυψη ειδοποιήσεων αυτού του χρήστη;",
|
||||
"navigation_bar.blocks": "Αποκλεισμένοι χρήστες",
|
||||
"navigation_bar.community_timeline": "Local timeline",
|
||||
"navigation_bar.direct": "Απευθείας μηνύματα",
|
||||
"navigation_bar.discover": "Discover",
|
||||
"navigation_bar.domain_blocks": "Hidden domains",
|
||||
"navigation_bar.edit_profile": "Edit profile",
|
||||
"navigation_bar.favourites": "Favourites",
|
||||
"navigation_bar.follow_requests": "Follow requests",
|
||||
"navigation_bar.info": "Extended information",
|
||||
"navigation_bar.keyboard_shortcuts": "Συντομεύσεις πληκτρολογίου",
|
||||
"navigation_bar.lists": "Lists",
|
||||
"navigation_bar.logout": "Αποσύνδεση",
|
||||
"navigation_bar.mutes": "Muted users",
|
||||
"navigation_bar.personal": "Personal",
|
||||
"navigation_bar.pins": "Pinned toots",
|
||||
"navigation_bar.preferences": "Προτιμήσεις",
|
||||
"navigation_bar.public_timeline": "Ομοσπονδιακή ροή",
|
||||
"navigation_bar.security": "Security",
|
||||
"notification.favourite": "Ο/Η {name} σημείωσε ως αγαπημένη την κατάστασή σου",
|
||||
"notification.follow": "Ο/Η {name} σε ακολούθησε",
|
||||
"notification.mention": "Ο/Η {name} σε ανέφερε",
|
||||
"notification.reblog": "Ο/Η {name} προώθησε την κατάστασή σου",
|
||||
"notifications.clear": "Καθαρισμός ειδοποιήσεων",
|
||||
"notifications.clear_confirmation": "Σίγουρα θέλεις να καθαρίσεις όλες τις ειδοποιήσεις σου;",
|
||||
"notifications.column_settings.alert": "Desktop notifications",
|
||||
"notifications.column_settings.favourite": "Αγαπημένα:",
|
||||
"notifications.column_settings.follow": "Νέοι ακόλουθοι:",
|
||||
"notifications.column_settings.mention": "Αναφορές:",
|
||||
"notifications.column_settings.push": "Push notifications",
|
||||
"notifications.column_settings.push_meta": "Αυτή η συσκευή",
|
||||
"notifications.column_settings.reblog": "Προωθήσεις:",
|
||||
"notifications.column_settings.show": "Εμφάνισε σε στήλη",
|
||||
"notifications.column_settings.sound": "Ηχητική ειδοποίηση",
|
||||
"notifications.group": "{count} notifications",
|
||||
"onboarding.done": "Έγινε",
|
||||
"onboarding.next": "Επόμενο",
|
||||
"onboarding.page_five.public_timelines": "Η τοπική ροή δείχνει τις δημόσιες δημοσιεύσεις από όσους εδρεύουν στον κόμβο {domain}. Η ομοσπονδιακή ροή δείχνει τις δημόσιες δημοσιεύσεις εκείνων που οι χρήστες του {domain} ακολουθούν. Αυτές οι είναι Δημόσιες Ροές, ένας ωραίος τρόπος να ανακαλύψεις καινούριους ανθρώπους.",
|
||||
"onboarding.page_four.home": "The home timeline shows posts from people you follow.",
|
||||
"onboarding.page_four.notifications": "The notifications column shows when someone interacts with you.",
|
||||
"onboarding.page_one.federation": "Mastodon is a network of independent servers joining up to make one larger social network. We call these servers instances.",
|
||||
"onboarding.page_one.full_handle": "Your full handle",
|
||||
"onboarding.page_one.handle_hint": "This is what you would tell your friends to search for.",
|
||||
"onboarding.page_one.welcome": "Welcome to Mastodon!",
|
||||
"onboarding.page_six.admin": "Ο διαχειριστής του κόμβου σου είναι ο/η {admin}.",
|
||||
"onboarding.page_six.almost_done": "Almost done...",
|
||||
"onboarding.page_six.appetoot": "Bon Appetoot!",
|
||||
"onboarding.page_six.apps_available": "There are {apps} available for iOS, Android and other platforms.",
|
||||
"onboarding.page_six.github": "Το Mastodon είναι ελεύθερο λογισμικό. Μπορείς να αναφέρεις σφάλματα, να αιτηθείς νέες λειτουργίες ή να συνεισφέρεις κώδικα στο {github}.",
|
||||
"onboarding.page_six.guidelines": "community guidelines",
|
||||
"onboarding.page_six.read_guidelines": "Please read {domain}'s {guidelines}!",
|
||||
"onboarding.page_six.various_app": "mobile apps",
|
||||
"onboarding.page_three.profile": "Edit your profile to change your avatar, bio, and display name. There, you will also find other preferences.",
|
||||
"onboarding.page_three.search": "Use the search bar to find people and look at hashtags, such as {illustration} and {introductions}. To look for a person who is not on this instance, use their full handle.",
|
||||
"onboarding.page_two.compose": "Write posts from the compose column. You can upload images, change privacy settings, and add content warnings with the icons below.",
|
||||
"onboarding.skip": "Skip",
|
||||
"privacy.change": "Adjust status privacy",
|
||||
"privacy.direct.long": "Post to mentioned users only",
|
||||
"privacy.direct.short": "Direct",
|
||||
"privacy.private.long": "Post to followers only",
|
||||
"privacy.private.short": "Followers-only",
|
||||
"privacy.public.long": "Post to public timelines",
|
||||
"privacy.public.short": "Public",
|
||||
"privacy.unlisted.long": "Do not show in public timelines",
|
||||
"privacy.unlisted.short": "Unlisted",
|
||||
"regeneration_indicator.label": "Loading…",
|
||||
"regeneration_indicator.sublabel": "Your home feed is being prepared!",
|
||||
"relative_time.days": "{number}d",
|
||||
"relative_time.hours": "{number}h",
|
||||
"relative_time.just_now": "now",
|
||||
"relative_time.minutes": "{number}m",
|
||||
"relative_time.seconds": "{number}s",
|
||||
"reply_indicator.cancel": "Cancel",
|
||||
"report.forward": "Forward to {target}",
|
||||
"report.forward_hint": "Ο λογαριασμός είναι από διαφορετικό διακομιστή. Να σταλεί ανώνυμο αντίγραφο της καταγγελίας κι εκεί;",
|
||||
"report.hint": "Η καταγγελία θα σταλεί στους διαχειριστές του κόμβου σου. Μπορείς να περιγράψεις γιατί καταγγέλεις το λογαριασμό παρακάτω:",
|
||||
"report.placeholder": "Additional comments",
|
||||
"report.submit": "Submit",
|
||||
"report.target": "Καταγγελία {target}",
|
||||
"search.placeholder": "Search",
|
||||
"search_popout.search_format": "Προχωρημένη αναζήτηση",
|
||||
"search_popout.tips.full_text": "Simple text returns statuses you have written, favourited, boosted, or have been mentioned in, as well as matching usernames, display names, and hashtags.",
|
||||
"search_popout.tips.hashtag": "hashtag",
|
||||
"search_popout.tips.status": "status",
|
||||
"search_popout.tips.text": "Simple text returns matching display names, usernames and hashtags",
|
||||
"search_popout.tips.user": "user",
|
||||
"search_results.accounts": "People",
|
||||
"search_results.hashtags": "Hashtags",
|
||||
"search_results.statuses": "Toots",
|
||||
"search_results.total": "{count, number} {count, plural, one {result} other {results}}",
|
||||
"standalone.public_title": "A look inside...",
|
||||
"status.block": "Block @{name}",
|
||||
"status.cancel_reblog_private": "Unboost",
|
||||
"status.cannot_reblog": "This post cannot be boosted",
|
||||
"status.delete": "Διαγραφή",
|
||||
"status.direct": "Direct message @{name}",
|
||||
"status.embed": "Embed",
|
||||
"status.favourite": "Favourite",
|
||||
"status.load_more": "Φόρτωσε περισσότερα",
|
||||
"status.media_hidden": "Media hidden",
|
||||
"status.mention": "Mention @{name}",
|
||||
"status.more": "More",
|
||||
"status.mute": "Mute @{name}",
|
||||
"status.mute_conversation": "Mute conversation",
|
||||
"status.open": "Διεύρυνε αυτή την κατάσταση",
|
||||
"status.pin": "Pin on profile",
|
||||
"status.pinned": "Pinned toot",
|
||||
"status.reblog": "Boost",
|
||||
"status.reblog_private": "Boost to original audience",
|
||||
"status.reblogged_by": "{name} boosted",
|
||||
"status.redraft": "Delete & re-draft",
|
||||
"status.reply": "Reply",
|
||||
"status.replyAll": "Reply to thread",
|
||||
"status.report": "Καταγγελία @{name}",
|
||||
"status.sensitive_toggle": "Click to view",
|
||||
"status.sensitive_warning": "Sensitive content",
|
||||
"status.share": "Share",
|
||||
"status.show_less": "Show less",
|
||||
"status.show_less_all": "Show less for all",
|
||||
"status.show_more": "Show more",
|
||||
"status.show_more_all": "Show more for all",
|
||||
"status.unmute_conversation": "Unmute conversation",
|
||||
"status.unpin": "Unpin from profile",
|
||||
"tabs_bar.federated_timeline": "Ομοσπονδιακή",
|
||||
"tabs_bar.home": "Home",
|
||||
"tabs_bar.local_timeline": "Local",
|
||||
"tabs_bar.notifications": "Notifications",
|
||||
"tabs_bar.search": "Search",
|
||||
"timeline.media": "Media",
|
||||
"timeline.posts": "Toots",
|
||||
"trends.count_by_accounts": "{count} {rawCount, plural, one {person} other {people}} talking",
|
||||
"ui.beforeunload": "Your draft will be lost if you leave Mastodon.",
|
||||
"upload_area.title": "Drag & drop to upload",
|
||||
"upload_button.label": "Add media",
|
||||
"upload_form.description": "Describe for the visually impaired",
|
||||
"upload_form.focus": "Crop",
|
||||
"upload_form.undo": "Διαγραφή",
|
||||
"upload_progress.label": "Uploading...",
|
||||
"video.close": "Close video",
|
||||
"video.exit_fullscreen": "Exit full screen",
|
||||
"video.expand": "Expand video",
|
||||
"video.fullscreen": "Full screen",
|
||||
"video.hide": "Hide video",
|
||||
"video.mute": "Mute sound",
|
||||
"video.pause": "Pause",
|
||||
"video.play": "Play",
|
||||
"video.unmute": "Unmute sound"
|
||||
}
|
||||
|
|
@ -1,7 +1,9 @@
|
|||
{
|
||||
"account.badges.bot": "Bot",
|
||||
"account.block": "Block @{name}",
|
||||
"account.block_domain": "Hide everything from {domain}",
|
||||
"account.blocked": "Blocked",
|
||||
"account.direct": "Direct message @{name}",
|
||||
"account.disclaimer_full": "Information below may reflect the user's profile incompletely.",
|
||||
"account.domain_blocked": "Domain hidden",
|
||||
"account.edit_profile": "Edit profile",
|
||||
|
|
@ -39,6 +41,8 @@
|
|||
"bundle_modal_error.retry": "Try again",
|
||||
"column.blocks": "Blocked users",
|
||||
"column.community": "Local timeline",
|
||||
"column.direct": "Direct messages",
|
||||
"column.domain_blocks": "Hidden domains",
|
||||
"column.favourites": "Favourites",
|
||||
"column.follow_requests": "Follow requests",
|
||||
"column.home": "Home",
|
||||
|
|
@ -54,8 +58,9 @@
|
|||
"column_header.pin": "Pin",
|
||||
"column_header.show_settings": "Show settings",
|
||||
"column_header.unpin": "Unpin",
|
||||
"column_subheading.navigation": "Navigation",
|
||||
"column_subheading.settings": "Settings",
|
||||
"compose_form.direct_message_warning": "This toot will only be sent to the mentioned users.",
|
||||
"compose_form.direct_message_warning_learn_more": "Learn more",
|
||||
"compose_form.hashtag_warning": "This toot won't be listed under any hashtag as it is unlisted. Only public toots can be searched by hashtag.",
|
||||
"compose_form.lock_disclaimer": "Your account is not {locked}. Anyone can follow you to view your follower-only posts.",
|
||||
"compose_form.lock_disclaimer.lock": "locked",
|
||||
|
|
@ -75,9 +80,11 @@
|
|||
"confirmations.delete_list.confirm": "Delete",
|
||||
"confirmations.delete_list.message": "Are you sure you want to permanently delete this list?",
|
||||
"confirmations.domain_block.confirm": "Hide entire domain",
|
||||
"confirmations.domain_block.message": "Are you really, really sure you want to block the entire {domain}? In most cases a few targeted blocks or mutes are sufficient and preferable.",
|
||||
"confirmations.domain_block.message": "Are you really, really sure you want to block the entire {domain}? In most cases a few targeted blocks or mutes are sufficient and preferable. You will not see content from that domain in any public timelines or your notifications. Your followers from that domain will be removed.",
|
||||
"confirmations.mute.confirm": "Mute",
|
||||
"confirmations.mute.message": "Are you sure you want to mute {name}?",
|
||||
"confirmations.redraft.confirm": "Delete & redraft",
|
||||
"confirmations.redraft.message": "Are you sure you want to delete this status and re-draft it? You will lose all replies, boosts and favourites to it.",
|
||||
"confirmations.unfollow.confirm": "Unfollow",
|
||||
"confirmations.unfollow.message": "Are you sure you want to unfollow {name}?",
|
||||
"embed.instructions": "Embed this status on your website by copying the code below.",
|
||||
|
|
@ -97,6 +104,7 @@
|
|||
"emoji_button.symbols": "Symbols",
|
||||
"emoji_button.travel": "Travel & Places",
|
||||
"empty_column.community": "The local timeline is empty. Write something publicly to get the ball rolling!",
|
||||
"empty_column.direct": "You don't have any direct messages yet. When you send or receive one, it will show up here.",
|
||||
"empty_column.hashtag": "There is nothing in this hashtag yet.",
|
||||
"empty_column.home": "Your home timeline is empty! Visit {public} or use search to get started and meet other users.",
|
||||
"empty_column.home.public_timeline": "the public timeline",
|
||||
|
|
@ -105,11 +113,10 @@
|
|||
"empty_column.public": "There is nothing here! Write something publicly, or manually follow users from other instances to fill it up",
|
||||
"follow_request.authorize": "Authorize",
|
||||
"follow_request.reject": "Reject",
|
||||
"getting_started.appsshort": "Apps",
|
||||
"getting_started.faq": "FAQ",
|
||||
"getting_started.documentation": "Documentation",
|
||||
"getting_started.heading": "Getting started",
|
||||
"getting_started.open_source_notice": "Mastodon is open source software. You can contribute or report issues on GitHub at {github}.",
|
||||
"getting_started.userguide": "User Guide",
|
||||
"getting_started.terms": "Terms of service",
|
||||
"home.column_settings.advanced": "Advanced",
|
||||
"home.column_settings.basic": "Basic",
|
||||
"home.column_settings.filter_regex": "Filter out by regular expressions",
|
||||
|
|
@ -130,6 +137,7 @@
|
|||
"keyboard_shortcuts.mention": "to mention author",
|
||||
"keyboard_shortcuts.reply": "to reply",
|
||||
"keyboard_shortcuts.search": "to focus search",
|
||||
"keyboard_shortcuts.toggle_hidden": "to show/hide text behind CW",
|
||||
"keyboard_shortcuts.toot": "to start a brand new toot",
|
||||
"keyboard_shortcuts.unfocus": "to un-focus compose textarea/search",
|
||||
"keyboard_shortcuts.up": "to move up in the list",
|
||||
|
|
@ -151,17 +159,22 @@
|
|||
"mute_modal.hide_notifications": "Hide notifications from this user?",
|
||||
"navigation_bar.blocks": "Blocked users",
|
||||
"navigation_bar.community_timeline": "Local timeline",
|
||||
"navigation_bar.direct": "Direct messages",
|
||||
"navigation_bar.discover": "Discover",
|
||||
"navigation_bar.domain_blocks": "Hidden domains",
|
||||
"navigation_bar.edit_profile": "Edit profile",
|
||||
"navigation_bar.favourites": "Favourites",
|
||||
"navigation_bar.follow_requests": "Follow requests",
|
||||
"navigation_bar.info": "About this instance",
|
||||
"navigation_bar.keyboard_shortcuts": "Keyboard shortcuts",
|
||||
"navigation_bar.keyboard_shortcuts": "Hotkeys",
|
||||
"navigation_bar.lists": "Lists",
|
||||
"navigation_bar.logout": "Logout",
|
||||
"navigation_bar.mutes": "Muted users",
|
||||
"navigation_bar.personal": "Personal",
|
||||
"navigation_bar.pins": "Pinned toots",
|
||||
"navigation_bar.preferences": "Preferences",
|
||||
"navigation_bar.public_timeline": "Federated timeline",
|
||||
"navigation_bar.security": "Security",
|
||||
"notification.favourite": "{name} favourited your status",
|
||||
"notification.follow": "{name} followed you",
|
||||
"notification.mention": "{name} mentioned you",
|
||||
|
|
@ -177,6 +190,7 @@
|
|||
"notifications.column_settings.reblog": "Boosts:",
|
||||
"notifications.column_settings.show": "Show in column",
|
||||
"notifications.column_settings.sound": "Play sound",
|
||||
"notifications.group": "{count} notifications",
|
||||
"onboarding.done": "Done",
|
||||
"onboarding.next": "Next",
|
||||
"onboarding.page_five.public_timelines": "The local timeline shows public posts from everyone on {domain}. The federated timeline shows public posts from everyone who people on {domain} follow. These are the Public Timelines, a great way to discover new people.",
|
||||
|
|
@ -234,8 +248,10 @@
|
|||
"search_results.total": "{count, number} {count, plural, one {result} other {results}}",
|
||||
"standalone.public_title": "A look inside...",
|
||||
"status.block": "Block @{name}",
|
||||
"status.cancel_reblog_private": "Unboost",
|
||||
"status.cannot_reblog": "This post cannot be boosted",
|
||||
"status.delete": "Delete",
|
||||
"status.direct": "Direct message @{name}",
|
||||
"status.embed": "Embed",
|
||||
"status.favourite": "Favourite",
|
||||
"status.load_more": "Load more",
|
||||
|
|
@ -248,7 +264,9 @@
|
|||
"status.pin": "Pin on profile",
|
||||
"status.pinned": "Pinned toot",
|
||||
"status.reblog": "Boost",
|
||||
"status.reblog_private": "Boost to original audience",
|
||||
"status.reblogged_by": "{name} boosted",
|
||||
"status.redraft": "Delete & re-draft",
|
||||
"status.reply": "Reply",
|
||||
"status.replyAll": "Reply to thread",
|
||||
"status.report": "Report @{name}",
|
||||
|
|
@ -265,12 +283,16 @@
|
|||
"tabs_bar.home": "Home",
|
||||
"tabs_bar.local_timeline": "Local",
|
||||
"tabs_bar.notifications": "Notifications",
|
||||
"tabs_bar.search": "Search",
|
||||
"timeline.media": "Media",
|
||||
"timeline.posts": "Toots",
|
||||
"trends.count_by_accounts": "{count} {rawCount, plural, one {person} other {people}} talking",
|
||||
"ui.beforeunload": "Your draft will be lost if you leave Mastodon.",
|
||||
"upload_area.title": "Drag & drop to upload",
|
||||
"upload_button.label": "Add media",
|
||||
"upload_form.description": "Describe for the visually impaired",
|
||||
"upload_form.focus": "Crop",
|
||||
"upload_form.undo": "Undo",
|
||||
"upload_form.undo": "Delete",
|
||||
"upload_progress.label": "Uploading...",
|
||||
"video.close": "Close video",
|
||||
"video.exit_fullscreen": "Exit full screen",
|
||||
|
|
|
|||
|
|
@ -1,7 +1,9 @@
|
|||
{
|
||||
"account.badges.bot": "Roboto",
|
||||
"account.block": "Bloki @{name}",
|
||||
"account.block_domain": "Kaŝi ĉion de {domain}",
|
||||
"account.blocked": "Blokita",
|
||||
"account.direct": "Rekte mesaĝi @{name}",
|
||||
"account.disclaimer_full": "Subaj informoj povas reflekti la profilon de la uzanto nekomplete.",
|
||||
"account.domain_blocked": "Domajno kaŝita",
|
||||
"account.edit_profile": "Redakti profilon",
|
||||
|
|
@ -17,7 +19,7 @@
|
|||
"account.mute_notifications": "Silentigi sciigojn el @{name}",
|
||||
"account.muted": "Silentigita",
|
||||
"account.posts": "Mesaĝoj",
|
||||
"account.posts_with_replies": "Mesaĝoj kun respondoj",
|
||||
"account.posts_with_replies": "Kun respondoj",
|
||||
"account.report": "Signali @{name}",
|
||||
"account.requested": "Atendo de aprobo. Alklaku por nuligi peton de sekvado",
|
||||
"account.share": "Diskonigi la profilon de @{name}",
|
||||
|
|
@ -28,8 +30,8 @@
|
|||
"account.unmute": "Malsilentigi @{name}",
|
||||
"account.unmute_notifications": "Malsilentigi sciigojn de @{name}",
|
||||
"account.view_full_profile": "Vidi plenan profilon",
|
||||
"alert.unexpected.message": "An unexpected error occurred.",
|
||||
"alert.unexpected.title": "Oops!",
|
||||
"alert.unexpected.message": "Neatendita eraro okazis.",
|
||||
"alert.unexpected.title": "Ups!",
|
||||
"boost_modal.combo": "Vi povas premi {combo} por preterpasi sekvafoje",
|
||||
"bundle_column_error.body": "Io misfunkciis en la ŝargado de ĉi tiu elemento.",
|
||||
"bundle_column_error.retry": "Bonvolu reprovi",
|
||||
|
|
@ -39,6 +41,8 @@
|
|||
"bundle_modal_error.retry": "Bonvolu reprovi",
|
||||
"column.blocks": "Blokitaj uzantoj",
|
||||
"column.community": "Loka tempolinio",
|
||||
"column.direct": "Rektaj mesaĝoj",
|
||||
"column.domain_blocks": "Kaŝitaj domajnoj",
|
||||
"column.favourites": "Stelumoj",
|
||||
"column.follow_requests": "Petoj de sekvado",
|
||||
"column.home": "Hejmo",
|
||||
|
|
@ -54,18 +58,19 @@
|
|||
"column_header.pin": "Alpingli",
|
||||
"column_header.show_settings": "Montri agordojn",
|
||||
"column_header.unpin": "Depingli",
|
||||
"column_subheading.navigation": "Navigado",
|
||||
"column_subheading.settings": "Agordado",
|
||||
"compose_form.direct_message_warning": "Tiu mesaĝo estos sendita nur al menciitaj uzantoj.",
|
||||
"compose_form.direct_message_warning_learn_more": "Lerni pli",
|
||||
"compose_form.hashtag_warning": "Ĉi tiu mesaĝo ne estos listigita per ajna kradvorto. Nur publikaj mesaĝoj estas serĉeblaj per kradvortoj.",
|
||||
"compose_form.lock_disclaimer": "Via konta ne estas {locked}. Iu ajn povas sekvi vin por vidi viajn mesaĝojn nur por sekvantoj.",
|
||||
"compose_form.lock_disclaimer": "Via konta ne estas {locked}. Iu ajn povas sekvi vin por vidi viajn mesaĝojn, kiuj estas nur por sekvantoj.",
|
||||
"compose_form.lock_disclaimer.lock": "ŝlosita",
|
||||
"compose_form.placeholder": "Pri kio vi pensas?",
|
||||
"compose_form.publish": "Hup",
|
||||
"compose_form.publish_loud": "{publish}!",
|
||||
"compose_form.sensitive.marked": "Media is marked as sensitive",
|
||||
"compose_form.sensitive.unmarked": "Media is not marked as sensitive",
|
||||
"compose_form.spoiler.marked": "Text is hidden behind warning",
|
||||
"compose_form.spoiler.unmarked": "Text is not hidden",
|
||||
"compose_form.sensitive.marked": "Aŭdovidaĵo markita tikla",
|
||||
"compose_form.sensitive.unmarked": "Aŭdovidaĵo ne markita tikla",
|
||||
"compose_form.spoiler.marked": "Teksto kaŝita malantaŭ averto",
|
||||
"compose_form.spoiler.unmarked": "Teksto ne kaŝita",
|
||||
"compose_form.spoiler_placeholder": "Skribu vian averton ĉi tie",
|
||||
"confirmation_modal.cancel": "Nuligi",
|
||||
"confirmations.block.confirm": "Bloki",
|
||||
|
|
@ -78,6 +83,8 @@
|
|||
"confirmations.domain_block.message": "Ĉu vi vere, vere certas, ke vi volas tute bloki {domain}? Plej ofte, trafa blokado kaj silentigado sufiĉas kaj preferindas.",
|
||||
"confirmations.mute.confirm": "Silentigi",
|
||||
"confirmations.mute.message": "Ĉu vi certas, ke vi volas silentigi {name}?",
|
||||
"confirmations.redraft.confirm": "Delete & redraft",
|
||||
"confirmations.redraft.message": "Are you sure you want to delete this status and re-draft it? You will lose all replies, boosts and favourites to it.",
|
||||
"confirmations.unfollow.confirm": "Ne plu sekvi",
|
||||
"confirmations.unfollow.message": "Ĉu vi certas, ke vi volas ĉesi sekvi {name}?",
|
||||
"embed.instructions": "Enkorpigu ĉi tiun mesaĝon en vian retejon per kopio de la suba kodo.",
|
||||
|
|
@ -97,19 +104,19 @@
|
|||
"emoji_button.symbols": "Simboloj",
|
||||
"emoji_button.travel": "Vojaĝoj kaj lokoj",
|
||||
"empty_column.community": "La loka tempolinio estas malplena. Skribu ion por plenigi ĝin!",
|
||||
"empty_column.direct": "Vi ankoraŭ ne havas rektan mesaĝon. Kiam vi sendos aŭ ricevos iun, ĝi aperos ĉi tie.",
|
||||
"empty_column.hashtag": "Ankoraŭ estas nenio per ĉi tiu kradvorto.",
|
||||
"empty_column.home": "Via hejma tempolinio estas malplena! Vizitu {public} aŭ uzu la serĉilon por renkonti aliajn uzantojn.",
|
||||
"empty_column.home.public_timeline": "la publika tempolinio",
|
||||
"empty_column.home.public_timeline": "la publikan tempolinion",
|
||||
"empty_column.list": "Ankoraŭ estas nenio en ĉi tiu listo. Kiam membroj de ĉi tiu listo afiŝos novajn mesaĝojn, ili aperos ĉi tie.",
|
||||
"empty_column.notifications": "Vi ankoraŭ ne havas sciigojn. Interagu kun aliaj por komenci konversacion.",
|
||||
"empty_column.public": "Estas nenio ĉi tie! Publike skribu ion, aŭ mane sekvu uzantojn de aliaj nodoj por plenigi la publikan tempolinion",
|
||||
"follow_request.authorize": "Rajtigi",
|
||||
"follow_request.reject": "Rifuzi",
|
||||
"getting_started.appsshort": "Aplikaĵoj",
|
||||
"getting_started.faq": "Oftaj demandoj",
|
||||
"getting_started.documentation": "Dokumentado",
|
||||
"getting_started.heading": "Por komenci",
|
||||
"getting_started.open_source_notice": "Mastodon estas malfermitkoda programo. Vi povas kontribui aŭ raporti problemojn en GitHub je {github}.",
|
||||
"getting_started.userguide": "Gvidilo de uzo",
|
||||
"getting_started.terms": "Uzkondiĉoj",
|
||||
"home.column_settings.advanced": "Precizaj agordoj",
|
||||
"home.column_settings.basic": "Bazaj agordoj",
|
||||
"home.column_settings.filter_regex": "Filtri per regulesprimoj",
|
||||
|
|
@ -130,6 +137,7 @@
|
|||
"keyboard_shortcuts.mention": "por mencii la aŭtoron",
|
||||
"keyboard_shortcuts.reply": "por respondi",
|
||||
"keyboard_shortcuts.search": "por fokusigi la serĉilon",
|
||||
"keyboard_shortcuts.toggle_hidden": "por montri/kaŝi tekston malantaŭ enhava averto",
|
||||
"keyboard_shortcuts.toot": "por komenci tute novan mesaĝon",
|
||||
"keyboard_shortcuts.unfocus": "por malfokusigi la tekstujon aŭ la serĉilon",
|
||||
"keyboard_shortcuts.up": "por iri supren en la listo",
|
||||
|
|
@ -147,21 +155,26 @@
|
|||
"loading_indicator.label": "Ŝargado…",
|
||||
"media_gallery.toggle_visible": "Baskuligi videblecon",
|
||||
"missing_indicator.label": "Ne trovita",
|
||||
"missing_indicator.sublabel": "Ĉi tiu rimedo ne estis trovita",
|
||||
"mute_modal.hide_notifications": "Ĉu kaŝi sciigojn el ĉi tiu uzanto?",
|
||||
"missing_indicator.sublabel": "Ĉi tiu elemento ne estis trovita",
|
||||
"mute_modal.hide_notifications": "Ĉu vi volas kaŝi la sciigojn el ĉi tiu uzanto?",
|
||||
"navigation_bar.blocks": "Blokitaj uzantoj",
|
||||
"navigation_bar.community_timeline": "Loka tempolinio",
|
||||
"navigation_bar.direct": "Rektaj mesaĝoj",
|
||||
"navigation_bar.discover": "Esplori",
|
||||
"navigation_bar.domain_blocks": "Kaŝitaj domajnoj",
|
||||
"navigation_bar.edit_profile": "Redakti profilon",
|
||||
"navigation_bar.favourites": "Stelumoj",
|
||||
"navigation_bar.follow_requests": "Petoj de sekvado",
|
||||
"navigation_bar.info": "Pri ĉi tiu nodo",
|
||||
"navigation_bar.keyboard_shortcuts": "Klavaraj mallongigoj",
|
||||
"navigation_bar.keyboard_shortcuts": "Rapidklavoj",
|
||||
"navigation_bar.lists": "Listoj",
|
||||
"navigation_bar.logout": "Elsaluti",
|
||||
"navigation_bar.mutes": "Silentigitaj uzantoj",
|
||||
"navigation_bar.personal": "Personal",
|
||||
"navigation_bar.pins": "Alpinglitaj mesaĝoj",
|
||||
"navigation_bar.preferences": "Preferoj",
|
||||
"navigation_bar.public_timeline": "Fratara tempolinio",
|
||||
"navigation_bar.security": "Sekureco",
|
||||
"notification.favourite": "{name} stelumis vian mesaĝon",
|
||||
"notification.follow": "{name} eksekvis vin",
|
||||
"notification.mention": "{name} menciis vin",
|
||||
|
|
@ -177,6 +190,7 @@
|
|||
"notifications.column_settings.reblog": "Diskonigoj:",
|
||||
"notifications.column_settings.show": "Montri en kolumno",
|
||||
"notifications.column_settings.sound": "Eligi sonon",
|
||||
"notifications.group": "{count} sciigoj",
|
||||
"onboarding.done": "Farita",
|
||||
"onboarding.next": "Sekva",
|
||||
"onboarding.page_five.public_timelines": "La loka tempolinio montras publikajn mesaĝojn de ĉiuj en {domain}. La fratara tempolinio montras publikajn mesaĝojn de ĉiuj, kiuj estas sekvataj de homoj en {domain}. Tio estas la publikaj tempolinioj, kio estas bona maniero por malkovri novajn homojn.",
|
||||
|
|
@ -234,8 +248,10 @@
|
|||
"search_results.total": "{count, number} {count, plural, one {rezulto} other {rezultoj}}",
|
||||
"standalone.public_title": "Enrigardo…",
|
||||
"status.block": "Bloki @{name}",
|
||||
"status.cancel_reblog_private": "Eksdiskonigi",
|
||||
"status.cannot_reblog": "Ĉi tiu mesaĝo ne diskonigeblas",
|
||||
"status.delete": "Forigi",
|
||||
"status.direct": "Rekte mesaĝi @{name}",
|
||||
"status.embed": "Enkorpigi",
|
||||
"status.favourite": "Stelumi",
|
||||
"status.load_more": "Ŝargi pli",
|
||||
|
|
@ -244,11 +260,13 @@
|
|||
"status.more": "Pli",
|
||||
"status.mute": "Silentigi @{name}",
|
||||
"status.mute_conversation": "Silentigi konversacion",
|
||||
"status.open": "Grandigi ĉi tiun mesaĝon",
|
||||
"status.pin": "Alpingli en la profilo",
|
||||
"status.open": "Grandigi",
|
||||
"status.pin": "Alpingli profile",
|
||||
"status.pinned": "Alpinglita mesaĝo",
|
||||
"status.reblog": "Diskonigi",
|
||||
"status.reblog_private": "Diskonigi al la originala atentaro",
|
||||
"status.reblogged_by": "{name} diskonigis",
|
||||
"status.redraft": "Delete & re-draft",
|
||||
"status.reply": "Respondi",
|
||||
"status.replyAll": "Respondi al la fadeno",
|
||||
"status.report": "Signali @{name}",
|
||||
|
|
@ -256,21 +274,25 @@
|
|||
"status.sensitive_warning": "Tikla enhavo",
|
||||
"status.share": "Diskonigi",
|
||||
"status.show_less": "Malgrandigi",
|
||||
"status.show_less_all": "Show less for all",
|
||||
"status.show_less_all": "Malgrandigi ĉiujn",
|
||||
"status.show_more": "Grandigi",
|
||||
"status.show_more_all": "Show more for all",
|
||||
"status.show_more_all": "Grandigi ĉiujn",
|
||||
"status.unmute_conversation": "Malsilentigi konversacion",
|
||||
"status.unpin": "Depingli de profilo",
|
||||
"tabs_bar.federated_timeline": "Fratara tempolinio",
|
||||
"tabs_bar.home": "Hejmo",
|
||||
"tabs_bar.local_timeline": "Loka tempolinio",
|
||||
"tabs_bar.notifications": "Sciigoj",
|
||||
"tabs_bar.search": "Serĉi",
|
||||
"timeline.media": "Aŭdovidaĵoj",
|
||||
"timeline.posts": "Mesaĝoj",
|
||||
"trends.count_by_accounts": "{count} {rawCount, pluraj, unu {person} alia(j) {people}} parolas",
|
||||
"ui.beforeunload": "Via malneto perdiĝos se vi eliras de Mastodon.",
|
||||
"upload_area.title": "Altreni kaj lasi por alŝuti",
|
||||
"upload_button.label": "Aldoni aŭdovidaĵon",
|
||||
"upload_form.description": "Priskribi por misvidantaj homoj",
|
||||
"upload_form.focus": "Stuci",
|
||||
"upload_form.undo": "Malfari",
|
||||
"upload_form.undo": "Forigi",
|
||||
"upload_progress.label": "Alŝutado…",
|
||||
"video.close": "Fermi videon",
|
||||
"video.exit_fullscreen": "Eksigi plenekrana",
|
||||
|
|
|
|||
|
|
@ -1,7 +1,9 @@
|
|||
{
|
||||
"account.badges.bot": "Bot",
|
||||
"account.block": "Bloquear",
|
||||
"account.block_domain": "Ocultar todo de {domain}",
|
||||
"account.blocked": "Bloqueado",
|
||||
"account.direct": "Direct Message @{name}",
|
||||
"account.disclaimer_full": "La siguiente información del usuario puede estar incompleta.",
|
||||
"account.domain_blocked": "Dominio oculto",
|
||||
"account.edit_profile": "Editar perfil",
|
||||
|
|
@ -39,6 +41,8 @@
|
|||
"bundle_modal_error.retry": "Inténtalo de nuevo",
|
||||
"column.blocks": "Usuarios bloqueados",
|
||||
"column.community": "Línea de tiempo local",
|
||||
"column.direct": "Direct messages",
|
||||
"column.domain_blocks": "Hidden domains",
|
||||
"column.favourites": "Favoritos",
|
||||
"column.follow_requests": "Solicitudes de seguimiento",
|
||||
"column.home": "Inicio",
|
||||
|
|
@ -54,8 +58,9 @@
|
|||
"column_header.pin": "Fijar",
|
||||
"column_header.show_settings": "Mostrar ajustes",
|
||||
"column_header.unpin": "Dejar de fijar",
|
||||
"column_subheading.navigation": "Navegación",
|
||||
"column_subheading.settings": "Ajustes",
|
||||
"compose_form.direct_message_warning": "This toot will only be visible to all the mentioned users.",
|
||||
"compose_form.direct_message_warning_learn_more": "Learn more",
|
||||
"compose_form.hashtag_warning": "Este toot no se mostrará bajo hashtags porque no es público. Sólo los toots públicos se pueden buscar por hashtag.",
|
||||
"compose_form.lock_disclaimer": "Tu cuenta no está bloqueada. Todos pueden seguirte para ver tus toots solo para seguidores.",
|
||||
"compose_form.lock_disclaimer.lock": "bloqueado",
|
||||
|
|
@ -78,6 +83,8 @@
|
|||
"confirmations.domain_block.message": "¿Seguro de que quieres bloquear al dominio entero? En algunos casos es preferible bloquear o silenciar objetivos determinados.",
|
||||
"confirmations.mute.confirm": "Silenciar",
|
||||
"confirmations.mute.message": "¿Estás seguro de que quieres silenciar a {name}?",
|
||||
"confirmations.redraft.confirm": "Delete & redraft",
|
||||
"confirmations.redraft.message": "Are you sure you want to delete this status and re-draft it? You will lose all replies, boosts and favourites to it.",
|
||||
"confirmations.unfollow.confirm": "Dejar de seguir",
|
||||
"confirmations.unfollow.message": "¿Estás seguro de que quieres dejar de seguir a {name}?",
|
||||
"embed.instructions": "Añade este toot a tu sitio web con el siguiente código.",
|
||||
|
|
@ -97,6 +104,7 @@
|
|||
"emoji_button.symbols": "Símbolos",
|
||||
"emoji_button.travel": "Viajes y lugares",
|
||||
"empty_column.community": "La línea de tiempo local está vacía. ¡Escribe algo para empezar la fiesta!",
|
||||
"empty_column.direct": "You don't have any direct messages yet. When you send or receive one, it will show up here.",
|
||||
"empty_column.hashtag": "No hay nada en este hashtag aún.",
|
||||
"empty_column.home": "No estás siguiendo a nadie aún. Visita {public} o haz búsquedas para empezar y conocer gente nueva.",
|
||||
"empty_column.home.public_timeline": "la línea de tiempo pública",
|
||||
|
|
@ -105,11 +113,10 @@
|
|||
"empty_column.public": "¡No hay nada aquí! Escribe algo públicamente, o sigue usuarios de otras instancias manualmente para llenarlo",
|
||||
"follow_request.authorize": "Autorizar",
|
||||
"follow_request.reject": "Rechazar",
|
||||
"getting_started.appsshort": "Aplicaciones",
|
||||
"getting_started.faq": "FAQ",
|
||||
"getting_started.documentation": "Documentation",
|
||||
"getting_started.heading": "Primeros pasos",
|
||||
"getting_started.open_source_notice": "Mastodon es software libre. Puedes contribuir o reportar errores en {github}.",
|
||||
"getting_started.userguide": "Guía de usuario",
|
||||
"getting_started.terms": "Terms of service",
|
||||
"home.column_settings.advanced": "Avanzado",
|
||||
"home.column_settings.basic": "Básico",
|
||||
"home.column_settings.filter_regex": "Filtrar con expresiones regulares",
|
||||
|
|
@ -130,6 +137,7 @@
|
|||
"keyboard_shortcuts.mention": "para mencionar al autor",
|
||||
"keyboard_shortcuts.reply": "para responder",
|
||||
"keyboard_shortcuts.search": "para poner el foco en la búsqueda",
|
||||
"keyboard_shortcuts.toggle_hidden": "to show/hide text behind CW",
|
||||
"keyboard_shortcuts.toot": "para comenzar un nuevo toot",
|
||||
"keyboard_shortcuts.unfocus": "para retirar el foco de la caja de redacción/búsqueda",
|
||||
"keyboard_shortcuts.up": "para ir hacia arriba en la lista",
|
||||
|
|
@ -151,6 +159,9 @@
|
|||
"mute_modal.hide_notifications": "Ocultar notificaciones de este usuario?",
|
||||
"navigation_bar.blocks": "Usuarios bloqueados",
|
||||
"navigation_bar.community_timeline": "Historia local",
|
||||
"navigation_bar.direct": "Direct messages",
|
||||
"navigation_bar.discover": "Discover",
|
||||
"navigation_bar.domain_blocks": "Hidden domains",
|
||||
"navigation_bar.edit_profile": "Editar perfil",
|
||||
"navigation_bar.favourites": "Favoritos",
|
||||
"navigation_bar.follow_requests": "Solicitudes para seguirte",
|
||||
|
|
@ -159,9 +170,11 @@
|
|||
"navigation_bar.lists": "Listas",
|
||||
"navigation_bar.logout": "Cerrar sesión",
|
||||
"navigation_bar.mutes": "Usuarios silenciados",
|
||||
"navigation_bar.personal": "Personal",
|
||||
"navigation_bar.pins": "Toots fijados",
|
||||
"navigation_bar.preferences": "Preferencias",
|
||||
"navigation_bar.public_timeline": "Historia federada",
|
||||
"navigation_bar.security": "Security",
|
||||
"notification.favourite": "{name} marcó tu estado como favorito",
|
||||
"notification.follow": "{name} te empezó a seguir",
|
||||
"notification.mention": "{name} te ha mencionado",
|
||||
|
|
@ -177,6 +190,7 @@
|
|||
"notifications.column_settings.reblog": "Retoots:",
|
||||
"notifications.column_settings.show": "Mostrar en columna",
|
||||
"notifications.column_settings.sound": "Reproducir sonido",
|
||||
"notifications.group": "{count} notifications",
|
||||
"onboarding.done": "Listo",
|
||||
"onboarding.next": "Siguiente",
|
||||
"onboarding.page_five.public_timelines": "La línea de tiempo local muestra toots públicos de todos en {domain}. La línea de tiempo federada muestra toots públicos de cualquiera a quien la gente de {domain} siga. Estas son las líneas de tiempo públicas, una buena forma de conocer gente nueva.",
|
||||
|
|
@ -234,8 +248,10 @@
|
|||
"search_results.total": "{count, number} {count, plural, one {resultado} other {resultados}}",
|
||||
"standalone.public_title": "Un pequeño vistazo...",
|
||||
"status.block": "Block @{name}",
|
||||
"status.cancel_reblog_private": "Unboost",
|
||||
"status.cannot_reblog": "Este toot no puede retootearse",
|
||||
"status.delete": "Borrar",
|
||||
"status.direct": "Direct message @{name}",
|
||||
"status.embed": "Incrustado",
|
||||
"status.favourite": "Favorito",
|
||||
"status.load_more": "Cargar más",
|
||||
|
|
@ -248,7 +264,9 @@
|
|||
"status.pin": "Fijar",
|
||||
"status.pinned": "Toot fijado",
|
||||
"status.reblog": "Retootear",
|
||||
"status.reblog_private": "Boost to original audience",
|
||||
"status.reblogged_by": "Retooteado por {name}",
|
||||
"status.redraft": "Delete & re-draft",
|
||||
"status.reply": "Responder",
|
||||
"status.replyAll": "Responder al hilo",
|
||||
"status.report": "Reportar",
|
||||
|
|
@ -265,6 +283,10 @@
|
|||
"tabs_bar.home": "Inicio",
|
||||
"tabs_bar.local_timeline": "Local",
|
||||
"tabs_bar.notifications": "Notificaciones",
|
||||
"tabs_bar.search": "Search",
|
||||
"timeline.media": "Media",
|
||||
"timeline.posts": "Toots",
|
||||
"trends.count_by_accounts": "{count} {rawCount, plural, one {person} other {people}} talking",
|
||||
"ui.beforeunload": "Tu borrador se perderá si sales de Mastodon.",
|
||||
"upload_area.title": "Arrastra y suelta para subir",
|
||||
"upload_button.label": "Subir multimedia",
|
||||
|
|
|
|||
306
app/javascript/mastodon/locales/eu.json
Normal file
306
app/javascript/mastodon/locales/eu.json
Normal file
|
|
@ -0,0 +1,306 @@
|
|||
{
|
||||
"account.badges.bot": "Bot",
|
||||
"account.block": "Blokeatu @{name}",
|
||||
"account.block_domain": "Ezkutatu {domain} domeinuko guztia",
|
||||
"account.blocked": "Blokeatuta",
|
||||
"account.direct": "Mezu zuzena @{name}(r)i",
|
||||
"account.disclaimer_full": "Baliteke beheko informazioak erabiltzailearen profilaren zati bat baino ez erakustea.",
|
||||
"account.domain_blocked": "Ezkutatutako domeinua",
|
||||
"account.edit_profile": "Profila aldatu",
|
||||
"account.follow": "Jarraitu",
|
||||
"account.followers": "Jarraitzaileak",
|
||||
"account.follows": "Jarraitzen",
|
||||
"account.follows_you": "Jarraitzen zaitu",
|
||||
"account.hide_reblogs": "Ezkutatu @{name}(r)en bultzadak",
|
||||
"account.media": "Media",
|
||||
"account.mention": "Aipatu @{name}",
|
||||
"account.moved_to": "{name} hona lekualdatu da:",
|
||||
"account.mute": "Mututu @{name}",
|
||||
"account.mute_notifications": "Mututu @{name}(r)en jakinarazpenak",
|
||||
"account.muted": "Mutututa",
|
||||
"account.posts": "Toot-ak",
|
||||
"account.posts_with_replies": "Toot eta erantzunak",
|
||||
"account.report": "Salatu @{name}",
|
||||
"account.requested": "Onarpenaren zain. Klikatu jarraitzeko eskaera ezeztatzeko",
|
||||
"account.share": "@{name}(e)ren profila elkarbanatu",
|
||||
"account.show_reblogs": "Erakutsi @{name}(r)en bultzadak",
|
||||
"account.unblock": "Desblokeatu @{name}",
|
||||
"account.unblock_domain": "Berriz erakutsi {domain}",
|
||||
"account.unfollow": "Jarraitzeari utzi",
|
||||
"account.unmute": "Desmututu @{name}",
|
||||
"account.unmute_notifications": "Desmututu @{name}(r)en jakinarazpenak",
|
||||
"account.view_full_profile": "Ikusi profil osoa",
|
||||
"alert.unexpected.message": "Ustekabeko errore bat gertatu da.",
|
||||
"alert.unexpected.title": "Ene!",
|
||||
"boost_modal.combo": "{combo} sakatu dezakezu hurrengoan hau saltatzeko",
|
||||
"bundle_column_error.body": "Zerbait okerra gertatu da osagai hau kargatzean.",
|
||||
"bundle_column_error.retry": "Saiatu berriro",
|
||||
"bundle_column_error.title": "Network error",
|
||||
"bundle_modal_error.close": "Itxi",
|
||||
"bundle_modal_error.message": "Zerbait okerra gertatu da osagai hau kargatzean.",
|
||||
"bundle_modal_error.retry": "Saiatu berriro",
|
||||
"column.blocks": "Blokeatutako erabiltzaileak",
|
||||
"column.community": "Denbora-lerro lokala",
|
||||
"column.direct": "Mezu zuzenak",
|
||||
"column.domain_blocks": "Ezkutatutako domeinuak",
|
||||
"column.favourites": "Gogokoak",
|
||||
"column.follow_requests": "Jarraitzeko eskariak",
|
||||
"column.home": "Hasiera",
|
||||
"column.lists": "Zerrendak",
|
||||
"column.mutes": "Mutututako erabiltzaileak",
|
||||
"column.notifications": "Jakinarazpenak",
|
||||
"column.pins": "Pinned toot",
|
||||
"column.public": "Federatutako denbora-lerroa",
|
||||
"column_back_button.label": "Atzera",
|
||||
"column_header.hide_settings": "Ezkutatu ezarpenak",
|
||||
"column_header.moveLeft_settings": "Eraman zutabea ezkerrera",
|
||||
"column_header.moveRight_settings": "Eraman zutabea eskuinera",
|
||||
"column_header.pin": "Finkatu",
|
||||
"column_header.show_settings": "Erakutsi ezarpenak",
|
||||
"column_header.unpin": "Desfinkatu",
|
||||
"column_subheading.settings": "Ezarpenak",
|
||||
"compose_form.direct_message_warning": "Toot hau aipatutako erabiltzaileei besterik ez zaie bidaliko.",
|
||||
"compose_form.direct_message_warning_learn_more": "Ikasi gehiago",
|
||||
"compose_form.hashtag_warning": "Toot hau ez da traoletan agertuko zerrendatu gabekoa baita. Traoletan toot publikoak besterik ez dira agertzen.",
|
||||
"compose_form.lock_disclaimer": "Zure kontua ez dago {locked}. Edonork jarraitu zaitzake zure jarraitzaileentzako soilik diren mezuak ikusteko.",
|
||||
"compose_form.lock_disclaimer.lock": "giltzapetuta",
|
||||
"compose_form.placeholder": "Zer duzu buruan?",
|
||||
"compose_form.publish": "Toot",
|
||||
"compose_form.publish_loud": "{publish}!",
|
||||
"compose_form.sensitive.marked": "Multimedia edukia hunkigarri gisa markatu da",
|
||||
"compose_form.sensitive.unmarked": "Multimedia edukia ez da hunkigarri gisa markatu",
|
||||
"compose_form.spoiler.marked": "Testua abisu batek ezkutatzen du",
|
||||
"compose_form.spoiler.unmarked": "Testua ez dago ezkutatuta",
|
||||
"compose_form.spoiler_placeholder": "Idatzi zure abisua hemen",
|
||||
"confirmation_modal.cancel": "Utzi",
|
||||
"confirmations.block.confirm": "Block",
|
||||
"confirmations.block.message": "Ziur {name} blokeatu nahi duzula?",
|
||||
"confirmations.delete.confirm": "Ezabatu",
|
||||
"confirmations.delete.message": "Ziur mezu hau ezabatu nahi duzula?",
|
||||
"confirmations.delete_list.confirm": "Ezabatu",
|
||||
"confirmations.delete_list.message": "Ziur behin betiko ezabatu nahi duzula zerrenda hau?",
|
||||
"confirmations.domain_block.confirm": "Ezkutatu domeinu osoa",
|
||||
"confirmations.domain_block.message": "Ziur, erabat ziur, {domain} domeinu osoa blokeatu nahi duzula? Gehienetan gutxi batzuk blokeatu edo mututzearekin nahikoa da.",
|
||||
"confirmations.mute.confirm": "Mututu",
|
||||
"confirmations.mute.message": "Ziur {name} mututu nahi duzula?",
|
||||
"confirmations.redraft.confirm": "Ezabatu eta berridatzi",
|
||||
"confirmations.redraft.message": "Ziur mezu hau ezabatu eta berridatzi nahi duzula? Berari egindako erantzun, bultzada eta gogokoak galduko dira.",
|
||||
"confirmations.unfollow.confirm": "Utzi jarraitzeari",
|
||||
"confirmations.unfollow.message": "Ziur {name} jarraitzeari utzi nahi diozula?",
|
||||
"embed.instructions": "Txertatu mezu hau zure webgunean beheko kodea kopatuz.",
|
||||
"embed.preview": "Hau da izango duen itxura:",
|
||||
"emoji_button.activity": "Jarduera",
|
||||
"emoji_button.custom": "Pertsonalizatua",
|
||||
"emoji_button.flags": "Banderak",
|
||||
"emoji_button.food": "Janari eta edaria",
|
||||
"emoji_button.label": "Txertatu emoji-a",
|
||||
"emoji_button.nature": "Natura",
|
||||
"emoji_button.not_found": "Emojirik ez!! (╯°□°)╯︵ ┻━┻",
|
||||
"emoji_button.objects": "Objektuak",
|
||||
"emoji_button.people": "Jendea",
|
||||
"emoji_button.recent": "Maiz erabiliak",
|
||||
"emoji_button.search": "Bilatu...",
|
||||
"emoji_button.search_results": "Bilaketaren emaitzak",
|
||||
"emoji_button.symbols": "Sinboloak",
|
||||
"emoji_button.travel": "Bidaiak eta tokiak",
|
||||
"empty_column.community": "Denbora-lerro lokala hutsik dago. Idatzi zerbait publikoki pilota biraka jartzeko!",
|
||||
"empty_column.direct": "Ez duzu mezu zuzenik oraindik. Baten bat bidali edo jasotzen duzunean, hemen agertuko da.",
|
||||
"empty_column.hashtag": "Ez dago ezer traola honetan oraindik.",
|
||||
"empty_column.home": "Zure hasierako denbora-lerroa hutsik dago! Ikusi {public} edo erabili bilaketa lehen urratsak eman eta beste batzuk aurkitzeko.",
|
||||
"empty_column.home.public_timeline": "denbora-lerro publikoa",
|
||||
"empty_column.list": "Ez dago ezer zerrenda honetan. Zerrenda honetako kideek mezu berriak argitaratzean, hemen agertuko dira.",
|
||||
"empty_column.notifications": "Ez duzu jakinarazpenik oraindik. Jarri besteekin harremanetan elkarrizketa abiatzeko.",
|
||||
"empty_column.public": "Ez dago ezer hemen! Idatzi zerbait publikoki edo jarraitu eskuz beste instantzia batzuetako erabiltzailean hau betetzeko",
|
||||
"follow_request.authorize": "Baimendu",
|
||||
"follow_request.reject": "Ukatu",
|
||||
"getting_started.documentation": "Dokumentazioa",
|
||||
"getting_started.heading": "Menua",
|
||||
"getting_started.open_source_notice": "Mastodon software librea da. Ekarpenak egin ditzakezu edo akatsen berri eman GitHub bidez: {github}.",
|
||||
"getting_started.terms": "Erabilera baldintzak",
|
||||
"home.column_settings.advanced": "Aurreratua",
|
||||
"home.column_settings.basic": "Oinarrizkoa",
|
||||
"home.column_settings.filter_regex": "Iragazi adierazpen erregularren bidez",
|
||||
"home.column_settings.show_reblogs": "Erakutsi bultzadak",
|
||||
"home.column_settings.show_replies": "Erakutsi erantzunak",
|
||||
"home.settings": "Zutabearen ezarpenak",
|
||||
"keyboard_shortcuts.back": "atzera nabigatzeko",
|
||||
"keyboard_shortcuts.boost": "bultzada ematea",
|
||||
"keyboard_shortcuts.column": "mezu bat zutabe batean fokatzea",
|
||||
"keyboard_shortcuts.compose": "testua konposatzeko arean fokatzea",
|
||||
"keyboard_shortcuts.description": "Description",
|
||||
"keyboard_shortcuts.down": "zerrendan behera mugitzea",
|
||||
"keyboard_shortcuts.enter": "to open status",
|
||||
"keyboard_shortcuts.favourite": "gogoko egitea",
|
||||
"keyboard_shortcuts.heading": "Keyboard Shortcuts",
|
||||
"keyboard_shortcuts.hotkey": "Laster-tekla",
|
||||
"keyboard_shortcuts.legend": "legenda hau bistaratzea",
|
||||
"keyboard_shortcuts.mention": "egilea aipatzea",
|
||||
"keyboard_shortcuts.reply": "erantzutea",
|
||||
"keyboard_shortcuts.search": "bilaketan fokua jartzea",
|
||||
"keyboard_shortcuts.toggle_hidden": "testua erakustea/ezkutatzea abisu baten atzean",
|
||||
"keyboard_shortcuts.toot": "toot berria hastea",
|
||||
"keyboard_shortcuts.unfocus": "testua konposatzeko area / bilaketatik fokua kentzea",
|
||||
"keyboard_shortcuts.up": "zerrendan gora mugitzea",
|
||||
"lightbox.close": "Itxi",
|
||||
"lightbox.next": "Hurrengoa",
|
||||
"lightbox.previous": "Aurrekoa",
|
||||
"lists.account.add": "Gehitu zerrendara",
|
||||
"lists.account.remove": "Kendu zerrendatik",
|
||||
"lists.delete": "Ezabatu zerrenda",
|
||||
"lists.edit": "Editatu zerrenda",
|
||||
"lists.new.create": "Gehitu zerrenda",
|
||||
"lists.new.title_placeholder": "Zerrenda berriaren izena",
|
||||
"lists.search": "Bilatu jarraitzen dituzun pertsonen artean",
|
||||
"lists.subheading": "Zure zerrendak",
|
||||
"loading_indicator.label": "Kargatzen...",
|
||||
"media_gallery.toggle_visible": "Txandakatu ikusgaitasuna",
|
||||
"missing_indicator.label": "Ez aurkitua",
|
||||
"missing_indicator.sublabel": "Baliabide hau ezin izan da aurkitu",
|
||||
"mute_modal.hide_notifications": "Ezkutatu erabiltzaile honen jakinarazpenak?",
|
||||
"navigation_bar.blocks": "Blokeatutako erabiltzaileak",
|
||||
"navigation_bar.community_timeline": "Denbora-lerro lokala",
|
||||
"navigation_bar.direct": "Mezu zuzenak",
|
||||
"navigation_bar.discover": "Aurkitu",
|
||||
"navigation_bar.domain_blocks": "Ezkutatutako domeinuak",
|
||||
"navigation_bar.edit_profile": "Aldatu profila",
|
||||
"navigation_bar.favourites": "Gogokoak",
|
||||
"navigation_bar.follow_requests": "Jarraitzeko eskariak",
|
||||
"navigation_bar.info": "Instantzia honi buruz",
|
||||
"navigation_bar.keyboard_shortcuts": "Laster-teklak",
|
||||
"navigation_bar.lists": "Zerrendak",
|
||||
"navigation_bar.logout": "Amaitu saioa",
|
||||
"navigation_bar.mutes": "Mutututako erabiltzaileak",
|
||||
"navigation_bar.personal": "Personal",
|
||||
"navigation_bar.pins": "Finkatutako toot-ak",
|
||||
"navigation_bar.preferences": "Hobespenak",
|
||||
"navigation_bar.public_timeline": "Federatutako denbora-lerroa",
|
||||
"navigation_bar.security": "Segurtasuna",
|
||||
"notification.favourite": "{name}(e)k zure mezua gogoko du",
|
||||
"notification.follow": "{name}(e)k jarraitzen zaitu",
|
||||
"notification.mention": "{name}(e)k aipatu zaitu",
|
||||
"notification.reblog": "{name}(e)k bultzada eman dio zure mezuari",
|
||||
"notifications.clear": "Garbitu jakinarazpenak",
|
||||
"notifications.clear_confirmation": "Ziur zure jakinarazpen guztiak behin betirako garbitu nahi dituzula?",
|
||||
"notifications.column_settings.alert": "Mahaigaineko jakinarazpenak",
|
||||
"notifications.column_settings.favourite": "Gogokoak:",
|
||||
"notifications.column_settings.follow": "Jarraitzaile berriak:",
|
||||
"notifications.column_settings.mention": "Aipamenak:",
|
||||
"notifications.column_settings.push": "Push jakinarazpenak",
|
||||
"notifications.column_settings.push_meta": "Gailu hau",
|
||||
"notifications.column_settings.reblog": "Bultzadak:",
|
||||
"notifications.column_settings.show": "Erakutsi zutabean",
|
||||
"notifications.column_settings.sound": "Jo soinua",
|
||||
"notifications.group": "{count} jakinarazpen",
|
||||
"onboarding.done": "Egina",
|
||||
"onboarding.next": "Hurrengoa",
|
||||
"onboarding.page_five.public_timelines": "Denbora-lerro lokalak {domain} domeinuko guztien mezu publikoak erakusten ditu. Federatutako denbora-lerroak {domain} domeinuko edonork jarraitutakoen mezu publikoak erakusten ditu. Hauek denbora-lerro publikoak dira, jende berria ezagutzeko primerakoak.",
|
||||
"onboarding.page_four.home": "Hasierako denbora-lerroak jarraitzen duzun jendearen mezuak erakusten ditu.",
|
||||
"onboarding.page_four.notifications": "Jakinarazpenen zutabeak besteek zurekin hasitako hartu-emanak erakusten ditu.",
|
||||
"onboarding.page_one.federation": "Mastodon lotutako zerbitzari independenteez eraikitako gizarte sare bat da. Zerbitzari hauei instantzia deitzen diegu.",
|
||||
"onboarding.page_one.full_handle": "Zure erabiltzaile-izen osoa",
|
||||
"onboarding.page_one.handle_hint": "Hau da zure lagunei zu aurkitzeko emango zeniena.",
|
||||
"onboarding.page_one.welcome": "Ongi etorri Mastodon-era!",
|
||||
"onboarding.page_six.admin": "Zure instantziaren administratzailea {admin} da.",
|
||||
"onboarding.page_six.almost_done": "Ia eginda...",
|
||||
"onboarding.page_six.appetoot": "Bon Appetoot!",
|
||||
"onboarding.page_six.apps_available": "{apps} eskuragarri daude iOS, Android eta beste plataformetarako.",
|
||||
"onboarding.page_six.github": "Mastodon software librea da. Akatsen berri eman ezakezu, ezaugarriak eskatu, edo kodea proposatu hemen: {github}.",
|
||||
"onboarding.page_six.guidelines": "komunitatearen gida-lerroak",
|
||||
"onboarding.page_six.read_guidelines": "Irakurri {domain} {guidelines} mesedez!",
|
||||
"onboarding.page_six.various_app": "mugikorrerako aplikazioak",
|
||||
"onboarding.page_three.profile": "Editatu zure profila zure abatarra, biografia eta pantaila-izena aldatzeko. Han hobespen gehiago daude ere.",
|
||||
"onboarding.page_three.search": "Erabili bilaketa-barra jendea aurkitzeko eta traolak begiratzeko, esaterako {illustration} edo {introductions}. Instantzia honetan ez dagoen pertsona bat bilatzeko , erabili erabiltzaile-izen osoa.",
|
||||
"onboarding.page_two.compose": "Idatzi mezuak konposizio-zutabean. Irudiak igo ditzakezu, pribatutasun ezarpenak aldatu, eta edukiei abisuak gehitu beheko ikonoekin.",
|
||||
"onboarding.skip": "Saltatu",
|
||||
"privacy.change": "Doitu mezuaren pribatutasuna",
|
||||
"privacy.direct.long": "Bidali aipatutako erabiltzaileei besterik ez",
|
||||
"privacy.direct.short": "Zuzena",
|
||||
"privacy.private.long": "Bidali jarraitzaileei besterik ez",
|
||||
"privacy.private.short": "Jarraitzaileak soilik",
|
||||
"privacy.public.long": "Bistaratu denbora-lerro publikoetan",
|
||||
"privacy.public.short": "Publikoa",
|
||||
"privacy.unlisted.long": "Do not show in public timelines",
|
||||
"privacy.unlisted.short": "Zerrendatu gabea",
|
||||
"regeneration_indicator.label": "Kargatzen…",
|
||||
"regeneration_indicator.sublabel": "Zure hasiera-jarioa prestatzen ari da!",
|
||||
"relative_time.days": "{number}d",
|
||||
"relative_time.hours": "{number}h",
|
||||
"relative_time.just_now": "orain",
|
||||
"relative_time.minutes": "{number}m",
|
||||
"relative_time.seconds": "{number}s",
|
||||
"reply_indicator.cancel": "Utzi",
|
||||
"report.forward": "Birbidali hona: {target}",
|
||||
"report.forward_hint": "Kontu hau beste zerbitzari batekoa da. Bidali txostenaren kopia anonimo hara ere?",
|
||||
"report.hint": "Txostena zure instantziaren moderatzaileei bidaliko zaio. Kontu hau zergatik salatzen duzun behean azaldu dezakezu:",
|
||||
"report.placeholder": "Iruzkin gehigarriak",
|
||||
"report.submit": "Submit",
|
||||
"report.target": "{target} salatzen",
|
||||
"search.placeholder": "Bilatu",
|
||||
"search_popout.search_format": "Bilaketa aurreratuaren formatua",
|
||||
"search_popout.tips.full_text": "Testu hutsarekin zuk idatzitako mezuak, gogokoak, bultzadak edo aipamenak aurkitu ditzakezu, bat datozen erabiltzaile-izenak, pantaila-izenak, eta traolak.",
|
||||
"search_popout.tips.hashtag": "traola",
|
||||
"search_popout.tips.status": "status",
|
||||
"search_popout.tips.text": "Testu hutsak pantaila-izenak, erabiltzaile-izenak eta traolak bilatzen ditu",
|
||||
"search_popout.tips.user": "erabiltzailea",
|
||||
"search_results.accounts": "Jendea",
|
||||
"search_results.hashtags": "Traolak",
|
||||
"search_results.statuses": "Toot-ak",
|
||||
"search_results.total": "{count, number} {count, plural, one {result} other {results}}",
|
||||
"standalone.public_title": "Begiradatxo bat...",
|
||||
"status.block": "Block @{name}",
|
||||
"status.cancel_reblog_private": "Kendu bultzada",
|
||||
"status.cannot_reblog": "Mezu honi ezin zaio bultzada eman",
|
||||
"status.delete": "Ezabatu",
|
||||
"status.direct": "Mezu zuzena @{name}(r)i",
|
||||
"status.embed": "Txertatu",
|
||||
"status.favourite": "Gogokoa",
|
||||
"status.load_more": "Kargatu gehiago",
|
||||
"status.media_hidden": "Multimedia ezkutatua",
|
||||
"status.mention": "Aipatu @{name}",
|
||||
"status.more": "Gehiago",
|
||||
"status.mute": "Mututu @{name}",
|
||||
"status.mute_conversation": "Mututu elkarrizketa",
|
||||
"status.open": "Hedatu mezu hau",
|
||||
"status.pin": "Finkatu profilean",
|
||||
"status.pinned": "Finkatutako toot-a",
|
||||
"status.reblog": "Bultzada",
|
||||
"status.reblog_private": "Bultzada jatorrizko hartzaileei",
|
||||
"status.reblogged_by": "{name}(r)en bultzada",
|
||||
"status.redraft": "Ezabatu eta berridatzi",
|
||||
"status.reply": "Erantzun",
|
||||
"status.replyAll": "Erantzun harian",
|
||||
"status.report": "Salatu @{name}",
|
||||
"status.sensitive_toggle": "Egin klik ikusteko",
|
||||
"status.sensitive_warning": "Eduki hunkigarria",
|
||||
"status.share": "Partekatu",
|
||||
"status.show_less": "Erakutsi gutxiago",
|
||||
"status.show_less_all": "Erakutsi denetarik gutxiago",
|
||||
"status.show_more": "Erakutsi gehiago",
|
||||
"status.show_more_all": "Erakutsi denetarik gehiago",
|
||||
"status.unmute_conversation": "Desmututu elkarrizketa",
|
||||
"status.unpin": "Desfinkatu profiletik",
|
||||
"tabs_bar.federated_timeline": "Federatua",
|
||||
"tabs_bar.home": "Hasiera",
|
||||
"tabs_bar.local_timeline": "Lokala",
|
||||
"tabs_bar.notifications": "Jakinarazpenak",
|
||||
"tabs_bar.search": "Bilatu",
|
||||
"timeline.media": "Media",
|
||||
"timeline.posts": "Toot-ak",
|
||||
"trends.count_by_accounts": "{count} {rawCount, plural, one {person} other {people}} hitz egiten",
|
||||
"ui.beforeunload": "Zure zirriborroa galduko da Mastodon uzten baduzu.",
|
||||
"upload_area.title": "Arrastatu eta jaregin igotzeko",
|
||||
"upload_button.label": "Gehitu multimedia",
|
||||
"upload_form.description": "Deskribatu ikusmen arazoak dituztenentzat",
|
||||
"upload_form.focus": "Moztu",
|
||||
"upload_form.undo": "Ezabatu",
|
||||
"upload_progress.label": "Igotzen...",
|
||||
"video.close": "Itxi bideoa",
|
||||
"video.exit_fullscreen": "Irten pantaila osotik",
|
||||
"video.expand": "Hedatu bideoa",
|
||||
"video.fullscreen": "Full screen",
|
||||
"video.hide": "Ezkutatu bideoa",
|
||||
"video.mute": "Mututu soinua",
|
||||
"video.pause": "Pause",
|
||||
"video.play": "Jo",
|
||||
"video.unmute": "Desmututu soinua"
|
||||
}
|
||||
|
|
@ -1,23 +1,25 @@
|
|||
{
|
||||
"account.badges.bot": "ربات",
|
||||
"account.block": "مسدودسازی @{name}",
|
||||
"account.block_domain": "پنهانسازی همه چیز از سرور {domain}",
|
||||
"account.blocked": "Blocked",
|
||||
"account.blocked": "مسدودشده",
|
||||
"account.direct": "پیغام خصوصی به @{name}",
|
||||
"account.disclaimer_full": "اطلاعات زیر ممکن است نمایهٔ این کاربر را به تمامی نشان ندهد.",
|
||||
"account.domain_blocked": "Domain hidden",
|
||||
"account.domain_blocked": "دامین پنهانشده",
|
||||
"account.edit_profile": "ویرایش نمایه",
|
||||
"account.follow": "پی بگیرید",
|
||||
"account.followers": "پیگیران",
|
||||
"account.follows": "پی میگیرد",
|
||||
"account.follows_you": "پیگیر شماست",
|
||||
"account.hide_reblogs": "پنهان کردن بازبوقهای @{name}",
|
||||
"account.media": "رسانه",
|
||||
"account.media": "عکس و ویدیو",
|
||||
"account.mention": "نامبردن از @{name}",
|
||||
"account.moved_to": "{name} منتقل شده است به:",
|
||||
"account.mute": "بیصدا کردن @{name}",
|
||||
"account.mute_notifications": "بیصداکردن اعلانها از طرف @{name}",
|
||||
"account.muted": "Muted",
|
||||
"account.muted": "بیصداشده",
|
||||
"account.posts": "نوشتهها",
|
||||
"account.posts_with_replies": "Toots with replies",
|
||||
"account.posts_with_replies": "نوشتهها و پاسخها",
|
||||
"account.report": "گزارش @{name}",
|
||||
"account.requested": "در انتظار پذیرش",
|
||||
"account.share": "همرسانی نمایهٔ @{name}",
|
||||
|
|
@ -28,8 +30,8 @@
|
|||
"account.unmute": "باصدا کردن @{name}",
|
||||
"account.unmute_notifications": "باصداکردن اعلانها از طرف @{name}",
|
||||
"account.view_full_profile": "نمایش نمایهٔ کامل",
|
||||
"alert.unexpected.message": "An unexpected error occurred.",
|
||||
"alert.unexpected.title": "Oops!",
|
||||
"alert.unexpected.message": "خطای پیشبینینشدهای رخ داد.",
|
||||
"alert.unexpected.title": "ای وای!",
|
||||
"boost_modal.combo": "دکمهٔ {combo} را بزنید تا دیگر این را نبینید",
|
||||
"bundle_column_error.body": "هنگام بازکردن این بخش خطایی رخ داد.",
|
||||
"bundle_column_error.retry": "تلاش دوباره",
|
||||
|
|
@ -39,6 +41,8 @@
|
|||
"bundle_modal_error.retry": "تلاش دوباره",
|
||||
"column.blocks": "کاربران مسدودشده",
|
||||
"column.community": "نوشتههای محلی",
|
||||
"column.direct": "پیغامهای خصوصی",
|
||||
"column.domain_blocks": "دامینهای پنهانشده",
|
||||
"column.favourites": "پسندیدهها",
|
||||
"column.follow_requests": "درخواستهای پیگیری",
|
||||
"column.home": "خانه",
|
||||
|
|
@ -54,18 +58,19 @@
|
|||
"column_header.pin": "ثابتکردن",
|
||||
"column_header.show_settings": "نمایش تنظیمات",
|
||||
"column_header.unpin": "رهاکردن",
|
||||
"column_subheading.navigation": "گشت و گذار",
|
||||
"column_subheading.settings": "تنظیمات",
|
||||
"compose_form.hashtag_warning": "This toot won't be listed under any hashtag as it is unlisted. Only public toots can be searched by hashtag.",
|
||||
"compose_form.direct_message_warning": "این بوق تنها به کاربرانی که از آنها نام برده شده فرستاده خواهد شد.",
|
||||
"compose_form.direct_message_warning_learn_more": "بیشتر بدانید",
|
||||
"compose_form.hashtag_warning": "از آنجا که این بوق فهرستنشده است، در نتایج جستجوی هشتگها پیدا نخواهد شد. تنها بوقهای عمومی را میتوان با جستجوی هشتگ پیدا کرد.",
|
||||
"compose_form.lock_disclaimer": "حساب شما {locked} نیست. هر کسی میتواند پیگیر شما شود و نوشتههای ویژهٔ پیگیران شما را ببیند.",
|
||||
"compose_form.lock_disclaimer.lock": "قفل",
|
||||
"compose_form.placeholder": "تازه چه خبر؟",
|
||||
"compose_form.publish": "بوق",
|
||||
"compose_form.publish_loud": "{publish}!",
|
||||
"compose_form.sensitive.marked": "Media is marked as sensitive",
|
||||
"compose_form.sensitive.unmarked": "Media is not marked as sensitive",
|
||||
"compose_form.spoiler.marked": "Text is hidden behind warning",
|
||||
"compose_form.spoiler.unmarked": "Text is not hidden",
|
||||
"compose_form.sensitive.marked": "این تصویر به عنوان حساس علامتگذاری شده",
|
||||
"compose_form.sensitive.unmarked": "این تصویر به عنوان حساس علامتگذاری نشده",
|
||||
"compose_form.spoiler.marked": "نوشته پشت هشدار محتوا پنهان است",
|
||||
"compose_form.spoiler.unmarked": "نوشته پنهان نیست",
|
||||
"compose_form.spoiler_placeholder": "هشدار محتوا",
|
||||
"confirmation_modal.cancel": "بیخیال",
|
||||
"confirmations.block.confirm": "مسدود کن",
|
||||
|
|
@ -78,6 +83,8 @@
|
|||
"confirmations.domain_block.message": "آیا جدی جدی میخواهید کل دامین {domain} را مسدود کنید؟ بیشتر وقتها مسدودکردن یا بیصداکردن چند حساب کاربری خاص کافی است و توصیه میشود.",
|
||||
"confirmations.mute.confirm": "بیصدا کن",
|
||||
"confirmations.mute.message": "آیا واقعاً میخواهید {name} را بیصدا کنید؟",
|
||||
"confirmations.redraft.confirm": "پاککردن و بازنویسی",
|
||||
"confirmations.redraft.message": "آیا واقعاً میخواهید این نوشته را پاک کنید و آن را از نو بنویسید؟ با این کار همهٔ پاسخها، بازبوقها، و پسندیدهشدنهای آن از دست میرود.",
|
||||
"confirmations.unfollow.confirm": "لغو پیگیری",
|
||||
"confirmations.unfollow.message": "آیا واقعاً میخواهید به پیگیری از {name} پایان دهید؟",
|
||||
"embed.instructions": "برای جاگذاری این نوشته در سایت خودتان، کد زیر را کپی کنید.",
|
||||
|
|
@ -97,6 +104,7 @@
|
|||
"emoji_button.symbols": "نمادها",
|
||||
"emoji_button.travel": "سفر و مکان",
|
||||
"empty_column.community": "فهرست نوشتههای محلی خالی است. چیزی بنویسید تا چرخش بچرخد!",
|
||||
"empty_column.direct": "شما هیچ پیغام مستقیمی ندارید. اگر چنین پیغامی بگیرید یا بفرستید اینجا نمایش خواهد یافت.",
|
||||
"empty_column.hashtag": "هنوز هیچ چیزی با این هشتگ نیست.",
|
||||
"empty_column.home": "شما هنوز پیگیر کسی نیستید. {public} را ببینید یا چیزی را جستجو کنید تا کاربران دیگر را ببینید.",
|
||||
"empty_column.home.public_timeline": "فهرست نوشتههای همهجا",
|
||||
|
|
@ -105,14 +113,13 @@
|
|||
"empty_column.public": "اینجا هنوز چیزی نیست! خودتان چیزی بنویسید یا کاربران دیگر را پی بگیرید تا اینجا پر شود",
|
||||
"follow_request.authorize": "اجازه دهید",
|
||||
"follow_request.reject": "اجازه ندهید",
|
||||
"getting_started.appsshort": "اپها",
|
||||
"getting_started.faq": "پرسشهای رایج",
|
||||
"getting_started.documentation": "Documentation",
|
||||
"getting_started.heading": "آغاز کنید",
|
||||
"getting_started.open_source_notice": "ماستدون یک نرمافزار آزاد است. میتوانید در ساخت آن مشارکت کنید یا مشکلاتش را در {github} گزارش دهید.",
|
||||
"getting_started.userguide": "راهنمای کاربری",
|
||||
"getting_started.terms": "شرایط استفاده",
|
||||
"home.column_settings.advanced": "پیشرفته",
|
||||
"home.column_settings.basic": "اصلی",
|
||||
"home.column_settings.filter_regex": "با عبارتهای باقاعده فیلتر کنید",
|
||||
"home.column_settings.filter_regex": "با عبارتهای باقاعده (regexp) فیلتر کنید",
|
||||
"home.column_settings.show_reblogs": "نمایش بازبوقها",
|
||||
"home.column_settings.show_replies": "نمایش پاسخها",
|
||||
"home.settings": "تنظیمات ستون",
|
||||
|
|
@ -120,16 +127,17 @@
|
|||
"keyboard_shortcuts.boost": "برای بازبوقیدن",
|
||||
"keyboard_shortcuts.column": "برای برجستهکردن یک نوشته در یکی از ستونها",
|
||||
"keyboard_shortcuts.compose": "برای فعالکردن کادر نوشتهٔ تازه",
|
||||
"keyboard_shortcuts.description": "Description",
|
||||
"keyboard_shortcuts.description": "توضیح",
|
||||
"keyboard_shortcuts.down": "برای پایینرفتن در فهرست",
|
||||
"keyboard_shortcuts.enter": "to open status",
|
||||
"keyboard_shortcuts.enter": "برای گشودن نوشته",
|
||||
"keyboard_shortcuts.favourite": "برای پسندیدن",
|
||||
"keyboard_shortcuts.heading": "Keyboard Shortcuts",
|
||||
"keyboard_shortcuts.heading": "میانبرهای صفحهکلید",
|
||||
"keyboard_shortcuts.hotkey": "میانبر",
|
||||
"keyboard_shortcuts.legend": "برای نمایش این راهنما",
|
||||
"keyboard_shortcuts.mention": "برای نامبردن از نویسنده",
|
||||
"keyboard_shortcuts.reply": "برای پاسخدادن",
|
||||
"keyboard_shortcuts.search": "برای فعالکردن جستجو",
|
||||
"keyboard_shortcuts.toggle_hidden": "برای نمایش/نهفتن نوشتهٔ پشت هشدار محتوا",
|
||||
"keyboard_shortcuts.toot": "برای آغاز یک بوق تازه",
|
||||
"keyboard_shortcuts.unfocus": "برای برداشتن توجه از نوشتن/جستجو",
|
||||
"keyboard_shortcuts.up": "برای بالا رفتن در فهرست",
|
||||
|
|
@ -147,10 +155,13 @@
|
|||
"loading_indicator.label": "بارگیری...",
|
||||
"media_gallery.toggle_visible": "تغییر پیدایی",
|
||||
"missing_indicator.label": "پیدا نشد",
|
||||
"missing_indicator.sublabel": "This resource could not be found",
|
||||
"missing_indicator.sublabel": "این منبع پیدا نشد",
|
||||
"mute_modal.hide_notifications": "اعلانهای این کاربر پنهان شود؟",
|
||||
"navigation_bar.blocks": "کاربران مسدودشده",
|
||||
"navigation_bar.community_timeline": "نوشتههای محلی",
|
||||
"navigation_bar.direct": "پیغامهای خصوصی",
|
||||
"navigation_bar.discover": "گشت و گذار",
|
||||
"navigation_bar.domain_blocks": "دامینهای پنهانشده",
|
||||
"navigation_bar.edit_profile": "ویرایش نمایه",
|
||||
"navigation_bar.favourites": "پسندیدهها",
|
||||
"navigation_bar.follow_requests": "درخواستهای پیگیری",
|
||||
|
|
@ -159,9 +170,11 @@
|
|||
"navigation_bar.lists": "فهرستها",
|
||||
"navigation_bar.logout": "خروج",
|
||||
"navigation_bar.mutes": "کاربران بیصداشده",
|
||||
"navigation_bar.personal": "Personal",
|
||||
"navigation_bar.pins": "نوشتههای ثابت",
|
||||
"navigation_bar.preferences": "ترجیحات",
|
||||
"navigation_bar.public_timeline": "نوشتههای همهجا",
|
||||
"navigation_bar.security": "امنیت",
|
||||
"notification.favourite": "{name} نوشتهٔ شما را پسندید",
|
||||
"notification.follow": "{name} پیگیر شما شد",
|
||||
"notification.mention": "{name} از شما نام برد",
|
||||
|
|
@ -177,14 +190,15 @@
|
|||
"notifications.column_settings.reblog": "بازبوقها:",
|
||||
"notifications.column_settings.show": "نمایش در ستون",
|
||||
"notifications.column_settings.sound": "پخش صدا",
|
||||
"notifications.group": "{count} اعلان",
|
||||
"onboarding.done": "پایان",
|
||||
"onboarding.next": "بعدی",
|
||||
"onboarding.page_five.public_timelines": "نوشتههای محلی یعنی نوشتههای همهٔ کاربران {domain}. نوشتههای همهجا یعنی نوشتههای همهٔ کسانی که کاربران {domain} آنها را پی میگیرند. این فهرستهای عمومی راه خوبی برای یافتن کاربران تازه هستند.",
|
||||
"onboarding.page_four.home": "ستون «خانه» نوشتههای کسانی را نشان میدهد که شما پی میگیرید.",
|
||||
"onboarding.page_four.notifications": "ستون «اعلانها» ارتباطهای شما با دیگران را نشان میدهد.",
|
||||
"onboarding.page_one.federation": "ماستدون شبکهای از سرورهای مستقل است که با پیوستن به یکدیگر یک شبکهٔ اجتماعی بزرگ را تشکیل میدهند.",
|
||||
"onboarding.page_one.full_handle": "Your full handle",
|
||||
"onboarding.page_one.handle_hint": "This is what you would tell your friends to search for.",
|
||||
"onboarding.page_one.full_handle": "شناسهٔ کاربری کامل شما",
|
||||
"onboarding.page_one.handle_hint": "این چیزی است که باید به دوستان خود بگویید تا بتوانند شما را پیدا کنند.",
|
||||
"onboarding.page_one.welcome": "به ماستدون خوش آمدید!",
|
||||
"onboarding.page_six.admin": "نشانی مسئول سرور شما {admin} است.",
|
||||
"onboarding.page_six.almost_done": "الان تقریباً آمادهاید...",
|
||||
|
|
@ -203,52 +217,56 @@
|
|||
"privacy.direct.short": "مستقیم",
|
||||
"privacy.private.long": "تنها به پیگیران نشان بده",
|
||||
"privacy.private.short": "خصوصی",
|
||||
"privacy.public.long": "در فهرست عمومی نشان بده",
|
||||
"privacy.public.long": "نمایش در فهرست عمومی",
|
||||
"privacy.public.short": "عمومی",
|
||||
"privacy.unlisted.long": "عمومی، ولی فهرست نکن",
|
||||
"privacy.unlisted.short": "فهرستنشده",
|
||||
"regeneration_indicator.label": "Loading…",
|
||||
"regeneration_indicator.sublabel": "Your home feed is being prepared!",
|
||||
"regeneration_indicator.label": "در حال باز شدن…",
|
||||
"regeneration_indicator.sublabel": "این فهرست دارد آماده میشود!",
|
||||
"relative_time.days": "{number}d",
|
||||
"relative_time.hours": "{number}h",
|
||||
"relative_time.just_now": "الان",
|
||||
"relative_time.minutes": "{number}m",
|
||||
"relative_time.seconds": "{number}s",
|
||||
"reply_indicator.cancel": "لغو",
|
||||
"report.forward": "Forward to {target}",
|
||||
"report.forward_hint": "The account is from another server. Send an anonymized copy of the report there as well?",
|
||||
"report.hint": "The report will be sent to your instance moderators. You can provide an explanation of why you are reporting this account below:",
|
||||
"report.forward": "فرستادن به {target}",
|
||||
"report.forward_hint": "این حساب در سرور دیگری ثبت شده. آیا میخواهید رونوشتی از این گزارش به طور ناشناس به آنجا هم فرستاده شود؟",
|
||||
"report.hint": "این گزارش به مدیران سرور شما فرستاده خواهد شد. میتوانید دلیل گزارشدادن این حساب را در اینجا بنویسید:",
|
||||
"report.placeholder": "توضیح اضافه",
|
||||
"report.submit": "بفرست",
|
||||
"report.target": "گزارشدادن",
|
||||
"search.placeholder": "جستجو",
|
||||
"search_popout.search_format": "راهنمای جستجوی پیشرفته",
|
||||
"search_popout.tips.full_text": "Simple text returns statuses you have written, favourited, boosted, or have been mentioned in, as well as matching usernames, display names, and hashtags.",
|
||||
"search_popout.tips.full_text": "جستجوی متنی ساده میتواند بوقهایی که شما نوشتهاید، پسندیدهاید، بازبوقیدهاید، یا در آنها از شما نام برده شده است را پیدا کند. همچنین نامهای کاربری، نام نمایشیافته، و هشتگها را هم شامل میشود.",
|
||||
"search_popout.tips.hashtag": "هشتگ",
|
||||
"search_popout.tips.status": "نوشته",
|
||||
"search_popout.tips.text": "جستجوی متنی ساده برای نامها، نامهای کاربری، و هشتگها",
|
||||
"search_popout.tips.user": "کاربر",
|
||||
"search_results.accounts": "People",
|
||||
"search_results.hashtags": "Hashtags",
|
||||
"search_results.statuses": "Toots",
|
||||
"search_results.accounts": "افراد",
|
||||
"search_results.hashtags": "هشتگها",
|
||||
"search_results.statuses": "بوقها",
|
||||
"search_results.total": "{count, number} {count, plural, one {نتیجه} other {نتیجه}}",
|
||||
"standalone.public_title": "نگاهی به کاربران این سرور...",
|
||||
"status.block": "Block @{name}",
|
||||
"status.block": "مسدودسازی @{name}",
|
||||
"status.cancel_reblog_private": "حذف بازبوق",
|
||||
"status.cannot_reblog": "این نوشته را نمیشود بازبوقید",
|
||||
"status.delete": "پاککردن",
|
||||
"status.direct": "پیغام مستقیم به @{name}",
|
||||
"status.embed": "جاگذاری",
|
||||
"status.favourite": "پسندیدن",
|
||||
"status.load_more": "بیشتر نشان بده",
|
||||
"status.media_hidden": "تصویر پنهان شده",
|
||||
"status.mention": "نامبردن از @{name}",
|
||||
"status.more": "بیشتر",
|
||||
"status.mute": "Mute @{name}",
|
||||
"status.mute": "بیصدا کردن @{name}",
|
||||
"status.mute_conversation": "بیصداکردن گفتگو",
|
||||
"status.open": "این نوشته را باز کن",
|
||||
"status.pin": "نوشتهٔ ثابت نمایه",
|
||||
"status.pinned": "Pinned toot",
|
||||
"status.pinned": "بوق ثابت",
|
||||
"status.reblog": "بازبوقیدن",
|
||||
"status.reblog_private": "بازبوق به مخاطبان اولیه",
|
||||
"status.reblogged_by": "{name} بازبوقید",
|
||||
"status.redraft": "پاککردن و بازنویسی",
|
||||
"status.reply": "پاسخ",
|
||||
"status.replyAll": "به نوشته پاسخ دهید",
|
||||
"status.report": "گزارش دادن @{name}",
|
||||
|
|
@ -256,21 +274,25 @@
|
|||
"status.sensitive_warning": "محتوای حساس",
|
||||
"status.share": "همرسانی",
|
||||
"status.show_less": "نهفتن",
|
||||
"status.show_less_all": "Show less for all",
|
||||
"status.show_less_all": "نمایش کمتر همه",
|
||||
"status.show_more": "نمایش",
|
||||
"status.show_more_all": "Show more for all",
|
||||
"status.show_more_all": "نمایش بیشتر همه",
|
||||
"status.unmute_conversation": "باصداکردن گفتگو",
|
||||
"status.unpin": "برداشتن نوشتهٔ ثابت نمایه",
|
||||
"tabs_bar.federated_timeline": "همگانی",
|
||||
"tabs_bar.home": "خانه",
|
||||
"tabs_bar.local_timeline": "محلی",
|
||||
"tabs_bar.notifications": "اعلانها",
|
||||
"tabs_bar.search": "جستجو",
|
||||
"timeline.media": "عکس و ویدیو",
|
||||
"timeline.posts": "بوقها",
|
||||
"trends.count_by_accounts": "{count} {rawCount, plural, one {نفر نوشته است} other {نفر نوشتهاند}}",
|
||||
"ui.beforeunload": "اگر از ماستدون خارج شوید پیشنویس شما پاک خواهد شد.",
|
||||
"upload_area.title": "برای بارگذاری به اینجا بکشید",
|
||||
"upload_button.label": "افزودن تصویر",
|
||||
"upload_form.description": "نوشتهٔ توضیحی برای کمبینایان و نابینایان",
|
||||
"upload_form.focus": "Crop",
|
||||
"upload_form.undo": "واگردانی",
|
||||
"upload_form.focus": "بریدن لبهها",
|
||||
"upload_form.undo": "حذف",
|
||||
"upload_progress.label": "بارگذاری...",
|
||||
"video.close": "بستن ویدیو",
|
||||
"video.exit_fullscreen": "خروج از حالت تمام صفحه",
|
||||
|
|
|
|||
|
|
@ -1,7 +1,9 @@
|
|||
{
|
||||
"account.badges.bot": "Botti",
|
||||
"account.block": "Estä @{name}",
|
||||
"account.block_domain": "Piilota kaikki sisältö verkkotunnuksesta {domain}",
|
||||
"account.blocked": "Estetty",
|
||||
"account.direct": "Viesti käyttäjälle @{name}",
|
||||
"account.disclaimer_full": "Alla olevat käyttäjän profiilitiedot saattavat olla epätäydellisiä.",
|
||||
"account.domain_blocked": "Verkko-osoite piilotettu",
|
||||
"account.edit_profile": "Muokkaa",
|
||||
|
|
@ -16,36 +18,38 @@
|
|||
"account.mute": "Mykistä @{name}",
|
||||
"account.mute_notifications": "Mykistä ilmoitukset käyttäjältä @{name}",
|
||||
"account.muted": "Mykistetty",
|
||||
"account.posts": "Töötit",
|
||||
"account.posts_with_replies": "Töötit ja vastaukset",
|
||||
"account.report": "Report @{name}",
|
||||
"account.requested": "Odottaa hyväksyntää. Klikkaa peruuttaaksesi seurauspyynnön",
|
||||
"account.posts": "Tuuttaukset",
|
||||
"account.posts_with_replies": "Tuuttaukset ja vastaukset",
|
||||
"account.report": "Raportoi @{name}",
|
||||
"account.requested": "Odottaa hyväksyntää. Peruuta seuraamispyyntö klikkaamalla",
|
||||
"account.share": "Jaa käyttäjän @{name} profiili",
|
||||
"account.show_reblogs": "Näytä boostaukset käyttäjältä @{name}",
|
||||
"account.show_reblogs": "Näytä buustaukset käyttäjältä @{name}",
|
||||
"account.unblock": "Salli @{name}",
|
||||
"account.unblock_domain": "Näytä {domain}",
|
||||
"account.unfollow": "Lakkaa seuraamasta",
|
||||
"account.unmute": "Poista mykistys käyttäjältä @{name}",
|
||||
"account.unmute": "Poista käyttäjän @{name} mykistys",
|
||||
"account.unmute_notifications": "Poista mykistys käyttäjän @{name} ilmoituksilta",
|
||||
"account.view_full_profile": "Näytä koko profiili",
|
||||
"alert.unexpected.message": "An unexpected error occurred.",
|
||||
"alert.unexpected.title": "Oops!",
|
||||
"boost_modal.combo": "Voit painaa näppäimiä {combo} ohittaaksesi tämän ensi kerralla",
|
||||
"bundle_column_error.body": "Jokin meni vikaan tätä komponenttia ladatessa.",
|
||||
"alert.unexpected.message": "Tapahtui odottamaton virhe.",
|
||||
"alert.unexpected.title": "Hups!",
|
||||
"boost_modal.combo": "Ensi kerralla voit ohittaa tämän painamalla {combo}",
|
||||
"bundle_column_error.body": "Jokin meni vikaan komponenttia ladattaessa.",
|
||||
"bundle_column_error.retry": "Yritä uudestaan",
|
||||
"bundle_column_error.title": "Network error",
|
||||
"bundle_column_error.title": "Verkkovirhe",
|
||||
"bundle_modal_error.close": "Sulje",
|
||||
"bundle_modal_error.message": "Jokin meni vikaan tätä komponenttia ladatessa.",
|
||||
"bundle_modal_error.message": "Jokin meni vikaan komponenttia ladattaessa.",
|
||||
"bundle_modal_error.retry": "Yritä uudestaan",
|
||||
"column.blocks": "Estetyt käyttäjät",
|
||||
"column.community": "Paikallinen aikajana",
|
||||
"column.direct": "Viestit",
|
||||
"column.domain_blocks": "Piilotetut verkkotunnukset",
|
||||
"column.favourites": "Suosikit",
|
||||
"column.follow_requests": "Seurauspyynnöt",
|
||||
"column.follow_requests": "Seuraamispyynnöt",
|
||||
"column.home": "Koti",
|
||||
"column.lists": "Listat",
|
||||
"column.mutes": "Mykistetyt käyttäjät",
|
||||
"column.notifications": "Ilmoitukset",
|
||||
"column.pins": "Pinned toot",
|
||||
"column.pins": "Kiinnitetty tuuttaus",
|
||||
"column.public": "Yleinen aikajana",
|
||||
"column_back_button.label": "Takaisin",
|
||||
"column_header.hide_settings": "Piilota asetukset",
|
||||
|
|
@ -54,34 +58,37 @@
|
|||
"column_header.pin": "Kiinnitä",
|
||||
"column_header.show_settings": "Näytä asetukset",
|
||||
"column_header.unpin": "Poista kiinnitys",
|
||||
"column_subheading.navigation": "Navigaatio",
|
||||
"column_subheading.settings": "Asetukset",
|
||||
"compose_form.hashtag_warning": "Tämä töötti ei tule näkymään hashtag-hauissa, koska se ei näy julkisilla aikajanoilla. Vain julkisia tööttejä voi hakea hashtageilla.",
|
||||
"compose_form.lock_disclaimer": "Tilisi ei ole {locked}. Kuka tahansa voi seurata tiliäsi ja nähdä vain seuraajille -postauksesi.",
|
||||
"compose_form.direct_message_warning": "Tämä tuuttaus näkyy vain mainituille käyttäjille.",
|
||||
"compose_form.direct_message_warning_learn_more": "Lisätietoja",
|
||||
"compose_form.hashtag_warning": "Tämä tuuttaus ei näy hashtag-hauissa, koska se on listaamaton. Hashtagien avulla voi hakea vain julkisia tuuttauksia.",
|
||||
"compose_form.lock_disclaimer": "Tilisi ei ole {locked}. Kuka tahansa voi seurata tiliäsi ja nähdä vain seuraajille rajaamasi julkaisut.",
|
||||
"compose_form.lock_disclaimer.lock": "lukittu",
|
||||
"compose_form.placeholder": "Mitä sinulla on mielessä?",
|
||||
"compose_form.publish": "Toot",
|
||||
"compose_form.placeholder": "Mitä mietit?",
|
||||
"compose_form.publish": "Tuuttaa",
|
||||
"compose_form.publish_loud": "{publish}!",
|
||||
"compose_form.sensitive.marked": "Media on merkitty arkaluontoiseksi",
|
||||
"compose_form.sensitive.unmarked": "Mediaa ei ole merkitty arkaluontoiseksi",
|
||||
"compose_form.spoiler.marked": "Teksti on piilotettu varoituksen taakse",
|
||||
"compose_form.spoiler.unmarked": "Teksti ei ole piilotettu",
|
||||
"compose_form.spoiler_placeholder": "Content warning",
|
||||
"compose_form.spoiler_placeholder": "Sisältövaroitus",
|
||||
"confirmation_modal.cancel": "Peruuta",
|
||||
"confirmations.block.confirm": "Estä",
|
||||
"confirmations.block.message": "Oletko varma, että haluat estää käyttäjän {name}?",
|
||||
"confirmations.delete.confirm": "Delete",
|
||||
"confirmations.delete.message": "Oletko varma, että haluat poistaa tämän statuspäivityksen?",
|
||||
"confirmations.delete_list.confirm": "Delete",
|
||||
"confirmations.delete_list.message": "Oletko varma, että haluat poistaa tämän listan pysyvästi?",
|
||||
"confirmations.block.message": "Haluatko varmasti estää käyttäjän {name}?",
|
||||
"confirmations.delete.confirm": "Poista",
|
||||
"confirmations.delete.message": "Haluatko varmasti poistaa tämän tilapäivityksen?",
|
||||
"confirmations.delete_list.confirm": "Poista",
|
||||
"confirmations.delete_list.message": "Haluatko varmasti poistaa tämän listan kokonaan?",
|
||||
"confirmations.domain_block.confirm": "Piilota koko verkko-osoite",
|
||||
"confirmations.domain_block.message": "Oletko aivan oikeasti varma että haluat estää koko verkko-osoitteen {domain}? Useimmissa tapauksissa muutamat kohdistetut estot ja mykistykset ovat riittäviä ja suositeltavampia.",
|
||||
"confirmations.domain_block.message": "Haluatko aivan varmasti estää koko verkko-osoitteen {domain}? Useimmiten jokunen kohdistettu esto ja mykistys riittää, ja se on suositeltavampi tapa toimia.",
|
||||
"confirmations.mute.confirm": "Mykistä",
|
||||
"confirmations.mute.message": "Oletko varma että haluat mykistää käyttäjän {name}?",
|
||||
"confirmations.mute.message": "Haluatko varmasti mykistää käyttäjän {name}?",
|
||||
"confirmations.redraft.confirm": "Delete & redraft",
|
||||
"confirmations.redraft.message": "Are you sure you want to delete this status and re-draft it? You will lose all replies, boosts and favourites to it.",
|
||||
"confirmations.unfollow.confirm": "Lakkaa seuraamasta",
|
||||
"confirmations.unfollow.message": "Oletko varma, että haluat lakata seuraamasta käyttäjää {name}?",
|
||||
"embed.instructions": "Upota tämä statuspäivitys sivullesi kopioimalla alla oleva koodi.",
|
||||
"embed.preview": "Tältä se tulee näyttämään:",
|
||||
"confirmations.unfollow.message": "Haluatko varmasti lakata seuraamasta käyttäjää {name}?",
|
||||
"embed.instructions": "Upota statuspäivitys sivullesi kopioimalla alla oleva koodi.",
|
||||
"embed.preview": "Se tulee näyttämään tältä:",
|
||||
"emoji_button.activity": "Aktiviteetit",
|
||||
"emoji_button.custom": "Mukautetut",
|
||||
"emoji_button.flags": "Liput",
|
||||
|
|
@ -89,153 +96,162 @@
|
|||
"emoji_button.label": "Lisää emoji",
|
||||
"emoji_button.nature": "Luonto",
|
||||
"emoji_button.not_found": "Ei emojeja!! (╯°□°)╯︵ ┻━┻",
|
||||
"emoji_button.objects": "Objektit",
|
||||
"emoji_button.objects": "Esineet",
|
||||
"emoji_button.people": "Ihmiset",
|
||||
"emoji_button.recent": "Usein käytetyt",
|
||||
"emoji_button.search": "Etsi...",
|
||||
"emoji_button.search_results": "Hakutulokset",
|
||||
"emoji_button.symbols": "Symbolit",
|
||||
"emoji_button.travel": "Matkailu",
|
||||
"empty_column.community": "Paikallinen aikajana on tyhjä. Kirjoita jotain julkista saadaksesi pyörät pyörimään!",
|
||||
"empty_column.hashtag": "Tässä hashtagissa ei ole vielä mitään.",
|
||||
"empty_column.home": "Kotiaikajanasi on tyhjä! Käy vierailemassa {public}ssa tai käytä hakutoimintoa aloittaaksesi ja tavataksesi muita käyttäjiä.",
|
||||
"empty_column.community": "Paikallinen aikajana on tyhjä. Homma lähtee käyntiin, kun kirjoitat jotain julkista!",
|
||||
"empty_column.direct": "Sinulla ei ole vielä yhtään viestiä yksittäiselle käyttäjälle. Kun lähetät tai vastaanotat sellaisen, se näkyy täällä.",
|
||||
"empty_column.hashtag": "Tällä hashtagilla ei ole vielä mitään.",
|
||||
"empty_column.home": "Kotiaikajanasi on tyhjä! {public} ja hakutoiminto auttavat alkuun ja kohtaamaan muita käyttäjiä.",
|
||||
"empty_column.home.public_timeline": "yleinen aikajana",
|
||||
"empty_column.list": "Tämä lista on vielä tyhjä. Kun listan jäsenet julkaisevat statuspäivityksiä, ne näkyvät tässä.",
|
||||
"empty_column.notifications": "Sinulle ei ole vielä ilmoituksia. Juttele muille aloittaaksesi keskustelun.",
|
||||
"empty_column.public": "Täällä ei ole mitään! Kirjoita jotain julkisesti, tai käy manuaalisesti seuraamassa käyttäjiä muista instansseista saadaksesi sisältöä",
|
||||
"empty_column.list": "Lista on vielä tyhjä. Listan jäsenten julkaisemat tilapäivitykset tulevat tähän näkyviin.",
|
||||
"empty_column.notifications": "Sinulle ei ole vielä ilmoituksia. Aloita keskustelu juttelemalla muille.",
|
||||
"empty_column.public": "Täällä ei ole mitään! Saat sisältöä, kun kirjoitat jotain julkisesti tai käyt manuaalisesti seuraamassa muiden instanssien käyttäjiä",
|
||||
"follow_request.authorize": "Valtuuta",
|
||||
"follow_request.reject": "Hylkää",
|
||||
"getting_started.appsshort": "Sovellukset",
|
||||
"getting_started.faq": "FAQ",
|
||||
"getting_started.documentation": "Documentation",
|
||||
"getting_started.heading": "Aloitus",
|
||||
"getting_started.open_source_notice": "Mastodon on avoimen lähdekoodin ohjelma. Voit avustaa tai raportoida ongelmia GitHub palvelussa {github}.",
|
||||
"getting_started.userguide": "Käyttöopas",
|
||||
"home.column_settings.advanced": "Tarkemmat asetukset",
|
||||
"getting_started.open_source_notice": "Mastodon on avoimen lähdekoodin ohjelma. Voit avustaa tai raportoida ongelmia GitHubissa: {github}.",
|
||||
"getting_started.terms": "Terms of service",
|
||||
"home.column_settings.advanced": "Lisäasetukset",
|
||||
"home.column_settings.basic": "Perusasetukset",
|
||||
"home.column_settings.filter_regex": "Suodata säännöllisten lauseiden avulla",
|
||||
"home.column_settings.filter_regex": "Suodata säännöllisillä lausekkeilla",
|
||||
"home.column_settings.show_reblogs": "Näytä buustaukset",
|
||||
"home.column_settings.show_replies": "Näytä vastaukset",
|
||||
"home.settings": "Sarakeasetukset",
|
||||
"keyboard_shortcuts.back": "liikkuaksesi taaksepäin",
|
||||
"keyboard_shortcuts.boost": "buustataksesi",
|
||||
"keyboard_shortcuts.column": "keskittääksesi statuspäivitykseen yhdessä sarakkeista",
|
||||
"keyboard_shortcuts.compose": "aktivoidaksesi tekstinkirjoitusalueen",
|
||||
"keyboard_shortcuts.description": "Description",
|
||||
"keyboard_shortcuts.down": "liikkuaksesi listassa alaspäin",
|
||||
"keyboard_shortcuts.enter": "to open status",
|
||||
"keyboard_shortcuts.favourite": "tykätäksesi",
|
||||
"keyboard_shortcuts.heading": "Näppäinoikotiet",
|
||||
"keyboard_shortcuts.back": "liiku taaksepäin",
|
||||
"keyboard_shortcuts.boost": "buustaa",
|
||||
"keyboard_shortcuts.column": "siirrä fokus tietyn sarakkeen tilapäivitykseen",
|
||||
"keyboard_shortcuts.compose": "siirry tekstinsyöttöön",
|
||||
"keyboard_shortcuts.description": "Kuvaus",
|
||||
"keyboard_shortcuts.down": "siirry listassa alaspäin",
|
||||
"keyboard_shortcuts.enter": "avaa tilapäivitys",
|
||||
"keyboard_shortcuts.favourite": "tykkää",
|
||||
"keyboard_shortcuts.heading": "Näppäinkomennot",
|
||||
"keyboard_shortcuts.hotkey": "Pikanäppäin",
|
||||
"keyboard_shortcuts.legend": "näyttääksesi tämän selitteen",
|
||||
"keyboard_shortcuts.mention": "mainitaksesi julkaisijan",
|
||||
"keyboard_shortcuts.reply": "vastataksesi",
|
||||
"keyboard_shortcuts.search": "aktivoidaksesi hakukentän",
|
||||
"keyboard_shortcuts.toot": "aloittaaksesi uuden töötin kirjoittamisen",
|
||||
"keyboard_shortcuts.unfocus": "poistaaksesi aktivoinnin tekstikentästä/hakukentästä",
|
||||
"keyboard_shortcuts.up": "liikkuaksesi listassa ylöspäin",
|
||||
"keyboard_shortcuts.legend": "näytä tämä selite",
|
||||
"keyboard_shortcuts.mention": "mainitse julkaisija",
|
||||
"keyboard_shortcuts.reply": "vastaa",
|
||||
"keyboard_shortcuts.search": "siirry hakukenttään",
|
||||
"keyboard_shortcuts.toggle_hidden": "näytä/piilota sisältövaroituksella merkitty teksti",
|
||||
"keyboard_shortcuts.toot": "ala kirjoittaa uutta tuuttausta",
|
||||
"keyboard_shortcuts.unfocus": "siirry pois tekstikentästä tai hakukentästä",
|
||||
"keyboard_shortcuts.up": "siirry listassa ylöspäin",
|
||||
"lightbox.close": "Sulje",
|
||||
"lightbox.next": "Seuraava",
|
||||
"lightbox.previous": "Edellinen",
|
||||
"lists.account.add": "Lisää listaan",
|
||||
"lists.account.remove": "Poista listalta",
|
||||
"lists.delete": "Delete list",
|
||||
"lists.account.remove": "Poista listasta",
|
||||
"lists.delete": "Poista lista",
|
||||
"lists.edit": "Muokkaa listaa",
|
||||
"lists.new.create": "Lisää lista",
|
||||
"lists.new.title_placeholder": "Uuden listan otsikko",
|
||||
"lists.search": "Etsi seuraamiesi henkilöiden joukosta",
|
||||
"lists.new.title_placeholder": "Uuden listan nimi",
|
||||
"lists.search": "Etsi seuraamistasi henkilöistä",
|
||||
"lists.subheading": "Omat listat",
|
||||
"loading_indicator.label": "Ladataan...",
|
||||
"media_gallery.toggle_visible": "Säädä näkyvyyttä",
|
||||
"missing_indicator.label": "Ei löydetty",
|
||||
"missing_indicator.label": "Ei löytynyt",
|
||||
"missing_indicator.sublabel": "Tätä resurssia ei löytynyt",
|
||||
"mute_modal.hide_notifications": "Piilota ilmoitukset tältä käyttäjältä?",
|
||||
"mute_modal.hide_notifications": "Piilota tältä käyttäjältä tulevat ilmoitukset?",
|
||||
"navigation_bar.blocks": "Estetyt käyttäjät",
|
||||
"navigation_bar.community_timeline": "Paikallinen aikajana",
|
||||
"navigation_bar.direct": "Viestit",
|
||||
"navigation_bar.discover": "Discover",
|
||||
"navigation_bar.domain_blocks": "Piilotetut verkkotunnukset",
|
||||
"navigation_bar.edit_profile": "Muokkaa profiilia",
|
||||
"navigation_bar.favourites": "Suosikit",
|
||||
"navigation_bar.follow_requests": "Seurauspyynnöt",
|
||||
"navigation_bar.follow_requests": "Seuraamispyynnöt",
|
||||
"navigation_bar.info": "Tietoa tästä instanssista",
|
||||
"navigation_bar.keyboard_shortcuts": "Näppäinoikotiet",
|
||||
"navigation_bar.keyboard_shortcuts": "Näppäinkomennot",
|
||||
"navigation_bar.lists": "Listat",
|
||||
"navigation_bar.logout": "Kirjaudu ulos",
|
||||
"navigation_bar.mutes": "Mykistetyt käyttäjät",
|
||||
"navigation_bar.pins": "Kiinnitetyt töötit",
|
||||
"navigation_bar.preferences": "Ominaisuudet",
|
||||
"navigation_bar.personal": "Personal",
|
||||
"navigation_bar.pins": "Kiinnitetyt tuuttaukset",
|
||||
"navigation_bar.preferences": "Asetukset",
|
||||
"navigation_bar.public_timeline": "Yleinen aikajana",
|
||||
"notification.favourite": "{name} tykkäsi statuksestasi",
|
||||
"navigation_bar.security": "Security",
|
||||
"notification.favourite": "{name} tykkäsi tilastasi",
|
||||
"notification.follow": "{name} seurasi sinua",
|
||||
"notification.mention": "{name} mainitsi sinut",
|
||||
"notification.reblog": "{name} buustasi statustasi",
|
||||
"notification.reblog": "{name} buustasi tilaasi",
|
||||
"notifications.clear": "Tyhjennä ilmoitukset",
|
||||
"notifications.clear_confirmation": "Oletko varma, että haluat lopullisesti tyhjentää kaikki ilmoituksesi?",
|
||||
"notifications.column_settings.alert": "Työpöytä ilmoitukset",
|
||||
"notifications.column_settings.favourite": "Tykkäyksiä:",
|
||||
"notifications.column_settings.follow": "Uusia seuraajia:",
|
||||
"notifications.column_settings.mention": "Mainintoja:",
|
||||
"notifications.clear_confirmation": "Haluatko varmasti poistaa kaikki ilmoitukset pysyvästi?",
|
||||
"notifications.column_settings.alert": "Työpöytäilmoitukset",
|
||||
"notifications.column_settings.favourite": "Tykkäykset:",
|
||||
"notifications.column_settings.follow": "Uudet seuraajat:",
|
||||
"notifications.column_settings.mention": "Maininnat:",
|
||||
"notifications.column_settings.push": "Push-ilmoitukset",
|
||||
"notifications.column_settings.push_meta": "Tämä laite",
|
||||
"notifications.column_settings.reblog": "Buusteja:",
|
||||
"notifications.column_settings.reblog": "Buustit:",
|
||||
"notifications.column_settings.show": "Näytä sarakkeessa",
|
||||
"notifications.column_settings.sound": "Soita ääni",
|
||||
"notifications.column_settings.sound": "Äänimerkki",
|
||||
"notifications.group": "{count} notifications",
|
||||
"onboarding.done": "Valmis",
|
||||
"onboarding.next": "Seuraava",
|
||||
"onboarding.page_five.public_timelines": "Paikallinen aikajana näyttää kaikki julkiset julkaisut kaikilta, jotka ovat verkko-osoitteessa {domain}. Yleinen aikajana näyttää julkiset julkaisut kaikilta niiltä, joita käyttäjät verkko-osoitteessa {domain} seuraavat. Nämä ovat julkiset aikajanat, ja ne ovat hyviä tapoja löytää uusia ihmisiä.",
|
||||
"onboarding.page_four.home": "Kotiaikajana näyttää julkaisut ihmisiltä joita seuraat.",
|
||||
"onboarding.page_four.notifications": "Ilmoitukset-sarake näyttää sinulle, kun joku on viestii kanssasi.",
|
||||
"onboarding.page_one.federation": "Mastodon on yhteisöpalvelu, joka toimii monen itsenäisen palvelimen muodostamassa verkossa. Me kutsumme näitä palvelimia instansseiksi.",
|
||||
"onboarding.page_five.public_timelines": "Paikallisella aikajanalla näytetään instanssin {domain} kaikkien käyttäjien julkiset julkaisut. Yleisellä aikajanalla näytetään kaikkien instanssin {domain} käyttäjien seuraamien käyttäjien julkiset julkaisut. Nämä julkiset aikajanat ovat loistavia paikkoja löytää uusia ihmisiä.",
|
||||
"onboarding.page_four.home": "Kotiaikajanalla näytetään seuraamiesi ihmisten julkaisut.",
|
||||
"onboarding.page_four.notifications": "Ilmoitukset-sarakkeessa näytetään muiden sinuun liittyvä toiminta.",
|
||||
"onboarding.page_one.federation": "Mastodon on usean itsenäisen palvelimen muodostama yhteisöpalvelu. Näitä palvelimia kutsutaan instansseiksi.",
|
||||
"onboarding.page_one.full_handle": "Koko käyttäjänimesi",
|
||||
"onboarding.page_one.handle_hint": "Tämä on se, mitä voisit ehdottaa ystäviäsi etsimään.",
|
||||
"onboarding.page_one.handle_hint": "Tällä nimellä ystäväsi löytävät sinut.",
|
||||
"onboarding.page_one.welcome": "Tervetuloa Mastodoniin!",
|
||||
"onboarding.page_six.admin": "Instanssisi ylläpitäjä on {admin}.",
|
||||
"onboarding.page_six.admin": "Instanssin ylläpitäjä on {admin}.",
|
||||
"onboarding.page_six.almost_done": "Melkein valmista...",
|
||||
"onboarding.page_six.appetoot": "Bon Appetööt!",
|
||||
"onboarding.page_six.appetoot": "Tuuttailun iloa!",
|
||||
"onboarding.page_six.apps_available": "{apps} on saatavilla iOS:lle, Androidille ja muille alustoille.",
|
||||
"onboarding.page_six.github": "Mastodon on ilmainen, vapaan lähdekoodin ohjelma. Voit raportoida bugeja, pyytää ominaisuuksia tai osallistua kehittämiseen GitHub-palvelussa: {github}.",
|
||||
"onboarding.page_six.github": "Mastodon on ilmainen, vapaan lähdekoodin ohjelma. Voit raportoida bugeja, ehdottaa ominaisuuksia tai osallistua kehittämiseen GitHubissa: {github}.",
|
||||
"onboarding.page_six.guidelines": "yhteisön säännöt",
|
||||
"onboarding.page_six.read_guidelines": "Ole hyvä ja lue {domain}:n {guidelines}!",
|
||||
"onboarding.page_six.various_app": "mobiilisovellukset",
|
||||
"onboarding.page_three.profile": "Muokkaa profiiliasi muuttaaksesi kuvakettasi, esittelyäsi ja nimimerkkiäsi. Löydät sieltä myös muita henkilökohtaisia asetuksia.",
|
||||
"onboarding.page_three.search": "Käytä hakukenttää löytääksesi ihmisiä ja etsiäksesi hashtageja, kuten {illustration} tai {introductions}. Hakeaksesi henkilöä joka on toisessa instanssissa, käytä hänen käyttäjänimeään kokonaisuudessaan.",
|
||||
"onboarding.page_two.compose": "Kirjoita postauksia kirjoita-sarakkeessa. Voit ladata kuvia, vaihtaa yksityisyysasetuksia ja lisätä sisältövaroituksia alla olevista painikkeista.",
|
||||
"onboarding.page_three.profile": "Voit muuttaa profiilikuvaasi, esittelyäsi ja nimimerkkiäsi sekä muita asetuksia muokkaamalla profiiliasi.",
|
||||
"onboarding.page_three.search": "Etsi ihmisiä ja hashtageja (esimerkiksi {illustration} tai {introductions}) hakukentän avulla. Jos haet toista instanssia käyttävää henkilöä, käytä hänen koko käyttäjänimeään.",
|
||||
"onboarding.page_two.compose": "Kirjoita julkaisuja kirjoitussarakkeessa. Voit ladata kuvia, vaihtaa näkyvyysasetuksia ja lisätä sisältövaroituksia alla olevista painikkeista.",
|
||||
"onboarding.skip": "Ohita",
|
||||
"privacy.change": "Säädä töötin yksityisyysasetuksia",
|
||||
"privacy.change": "Säädä tuuttauksen näkyvyyttä",
|
||||
"privacy.direct.long": "Julkaise vain mainituille käyttäjille",
|
||||
"privacy.direct.short": "Yksityisviesti",
|
||||
"privacy.direct.short": "Suora viesti",
|
||||
"privacy.private.long": "Julkaise vain seuraajille",
|
||||
"privacy.private.short": "Vain seuraajat",
|
||||
"privacy.public.long": "Julkaise julkisille aikajanoille",
|
||||
"privacy.public.short": "Julkinen",
|
||||
"privacy.unlisted.long": "Älä julkaise yleisillä aikajanoilla",
|
||||
"privacy.unlisted.short": "Julkinen, mutta älä näytä julkisella aikajanalla",
|
||||
"privacy.unlisted.long": "Älä julkaise julkisilla aikajanoilla",
|
||||
"privacy.unlisted.short": "Listaamaton julkinen",
|
||||
"regeneration_indicator.label": "Ladataan…",
|
||||
"regeneration_indicator.sublabel": "Kotinäkymääsi valmistellaan!",
|
||||
"relative_time.days": "{number}d",
|
||||
"relative_time.hours": "{number}h",
|
||||
"relative_time.days": "{number} pv",
|
||||
"relative_time.hours": "{number} h",
|
||||
"relative_time.just_now": "nyt",
|
||||
"relative_time.minutes": "{number}m",
|
||||
"relative_time.seconds": "{number}s",
|
||||
"relative_time.minutes": "{number} m",
|
||||
"relative_time.seconds": "{number} s",
|
||||
"reply_indicator.cancel": "Peruuta",
|
||||
"report.forward": "Uudelleenohjaa kohteeseen {target}",
|
||||
"report.forward_hint": "Tämä tili on toiselta serveriltä. Haluatko, että myös sinne lähetetään anonymisoitu kopio ilmiantoraportista?",
|
||||
"report.hint": "Ilmianto lähetetään instanssisi moderaattoreille. Voit antaa kuvauksen käyttäjän ilmiantamisen syystä alle:",
|
||||
"report.forward": "Välitä kohteeseen {target}",
|
||||
"report.forward_hint": "Tämä tili on toisella palvelimella. Haluatko lähettää nimettömän raportin myös sinne?",
|
||||
"report.hint": "Raportti lähetetään oman instanssisi moderaattoreille. Seuraavassa voit kertoa, miksi raportoit tästä tilistä:",
|
||||
"report.placeholder": "Lisäkommentit",
|
||||
"report.submit": "Submit",
|
||||
"report.target": "Reporting",
|
||||
"report.submit": "Lähetä",
|
||||
"report.target": "Raportoidaan {target}",
|
||||
"search.placeholder": "Hae",
|
||||
"search_popout.search_format": "Tarkennettu haku",
|
||||
"search_popout.tips.full_text": "Tekstihaku palauttaa statuspäivitykset jotka olet kirjoittanut, lisännyt suosikkeihisi, boostannut tai joissa sinut mainitaan, sekä käyttäjänimet, nimimerkit ja hastagit jotka sisältävät tekstin.",
|
||||
"search_popout.tips.hashtag": "hashtagi",
|
||||
"search_popout.tips.status": "status",
|
||||
"search_popout.tips.text": "Pelkkä tekstihaku palauttaa hakua vastaavat nimimerkit, käyttäjänimet ja hastagit",
|
||||
"search_popout.tips.full_text": "Tekstihaku palauttaa tilapäivitykset, jotka olet kirjoittanut, lisännyt suosikkeihisi, boostannut tai joissa sinut mainitaan, sekä tekstin sisältävät käyttäjänimet, nimimerkit ja hastagit.",
|
||||
"search_popout.tips.hashtag": "hashtag",
|
||||
"search_popout.tips.status": "tila",
|
||||
"search_popout.tips.text": "Tekstihaku palauttaa hakua vastaavat nimimerkit, käyttäjänimet ja hastagit",
|
||||
"search_popout.tips.user": "käyttäjä",
|
||||
"search_results.accounts": "Ihmiset",
|
||||
"search_results.hashtags": "Hashtagit",
|
||||
"search_results.statuses": "Töötit",
|
||||
"search_results.statuses": "Tuuttaukset",
|
||||
"search_results.total": "{count, number} {count, plural, one {result} other {results}}",
|
||||
"standalone.public_title": "Kurkistus sisälle...",
|
||||
"status.block": "Block @{name}",
|
||||
"status.cannot_reblog": "Tätä postausta ei voi buustata",
|
||||
"status.block": "Estä @{name}",
|
||||
"status.cancel_reblog_private": "Peru buustaus",
|
||||
"status.cannot_reblog": "Tätä julkaisua ei voi buustata",
|
||||
"status.delete": "Poista",
|
||||
"status.direct": "Viesti käyttäjälle @{name}",
|
||||
"status.embed": "Upota",
|
||||
"status.favourite": "Tykkää",
|
||||
"status.load_more": "Lataa lisää",
|
||||
|
|
@ -244,29 +260,35 @@
|
|||
"status.more": "Lisää",
|
||||
"status.mute": "Mykistä @{name}",
|
||||
"status.mute_conversation": "Mykistä keskustelu",
|
||||
"status.open": "Laajenna statuspäivitys",
|
||||
"status.open": "Laajenna tilapäivitys",
|
||||
"status.pin": "Kiinnitä profiiliin",
|
||||
"status.pinned": "Kiinnitetty töötti",
|
||||
"status.pinned": "Kiinnitetty tuuttaus",
|
||||
"status.reblog": "Buustaa",
|
||||
"status.reblog_private": "Buustaa alkuperäiselle yleisölle",
|
||||
"status.reblogged_by": "{name} buustasi",
|
||||
"status.redraft": "Delete & re-draft",
|
||||
"status.reply": "Vastaa",
|
||||
"status.replyAll": "Vastaa ketjuun",
|
||||
"status.report": "Report @{name}",
|
||||
"status.report": "Raportoi @{name}",
|
||||
"status.sensitive_toggle": "Klikkaa nähdäksesi",
|
||||
"status.sensitive_warning": "Arkaluontoista sisältöä",
|
||||
"status.share": "Jaa",
|
||||
"status.show_less": "Näytä vähemmän",
|
||||
"status.show_less_all": "Näytä vähemmän kaikista",
|
||||
"status.show_more": "Näytä lisää",
|
||||
"status.show_more_all": "Näytä enemmän kaikista",
|
||||
"status.unmute_conversation": "Poista mykistys keskustelulta",
|
||||
"status.show_more_all": "Näytä lisää kaikista",
|
||||
"status.unmute_conversation": "Poista keskustelun mykistys",
|
||||
"status.unpin": "Irrota profiilista",
|
||||
"tabs_bar.federated_timeline": "Yleinen",
|
||||
"tabs_bar.home": "Koti",
|
||||
"tabs_bar.local_timeline": "Paikallinen",
|
||||
"tabs_bar.notifications": "Ilmoitukset",
|
||||
"ui.beforeunload": "Luonnoksesi menetetään, jos poistut Mastodonista.",
|
||||
"upload_area.title": "Raahaa ja pudota tähän ladataksesi",
|
||||
"tabs_bar.search": "Hae",
|
||||
"timeline.media": "Media",
|
||||
"timeline.posts": "Toots",
|
||||
"trends.count_by_accounts": "{count} {rawCount, plural, one {person} other {people}} talking",
|
||||
"ui.beforeunload": "Luonnos häviää, jos poistut Mastodonista.",
|
||||
"upload_area.title": "Lataa raahaamalla ja pudottamalla tähän",
|
||||
"upload_button.label": "Lisää mediaa",
|
||||
"upload_form.description": "Anna kuvaus näkörajoitteisia varten",
|
||||
"upload_form.focus": "Rajaa",
|
||||
|
|
@ -275,10 +297,10 @@
|
|||
"video.close": "Sulje video",
|
||||
"video.exit_fullscreen": "Poistu koko näytön tilasta",
|
||||
"video.expand": "Laajenna video",
|
||||
"video.fullscreen": "Full screen",
|
||||
"video.fullscreen": "Koko näyttö",
|
||||
"video.hide": "Piilota video",
|
||||
"video.mute": "Mykistä ääni",
|
||||
"video.pause": "Keskeytä",
|
||||
"video.play": "Toista",
|
||||
"video.unmute": "Poista mykistys ääneltä"
|
||||
"video.unmute": "Poista äänen mykistys"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,9 @@
|
|||
{
|
||||
"account.badges.bot": "Bot",
|
||||
"account.block": "Bloquer @{name}",
|
||||
"account.block_domain": "Tout masquer venant de {domain}",
|
||||
"account.blocked": "Bloqué",
|
||||
"account.direct": "Message direct à @{name}",
|
||||
"account.disclaimer_full": "Les données ci-dessous peuvent ne pas refléter ce profil dans sa totalité.",
|
||||
"account.domain_blocked": "Domaine caché",
|
||||
"account.edit_profile": "Modifier le profil",
|
||||
|
|
@ -12,14 +14,14 @@
|
|||
"account.hide_reblogs": "Masquer les partages de @{name}",
|
||||
"account.media": "Média",
|
||||
"account.mention": "Mentionner",
|
||||
"account.moved_to": "{name} a déménagé vers :",
|
||||
"account.moved_to": "{name} a déménagé vers :",
|
||||
"account.mute": "Masquer @{name}",
|
||||
"account.mute_notifications": "Ignorer les notifications de @{name}",
|
||||
"account.muted": "Silencé",
|
||||
"account.posts": "Pouets",
|
||||
"account.posts_with_replies": "Pouets avec réponses",
|
||||
"account.posts_with_replies": "Pouets et réponses",
|
||||
"account.report": "Signaler",
|
||||
"account.requested": "Invitation envoyée",
|
||||
"account.requested": "En attente d'approbation. Cliquez pour annuler la requête",
|
||||
"account.share": "Partager le profil de @{name}",
|
||||
"account.show_reblogs": "Afficher les partages de @{name}",
|
||||
"account.unblock": "Débloquer",
|
||||
|
|
@ -28,8 +30,8 @@
|
|||
"account.unmute": "Ne plus masquer",
|
||||
"account.unmute_notifications": "Réactiver les notifications de @{name}",
|
||||
"account.view_full_profile": "Afficher le profil complet",
|
||||
"alert.unexpected.message": "An unexpected error occurred.",
|
||||
"alert.unexpected.title": "Oops!",
|
||||
"alert.unexpected.message": "Une erreur non-attendue s'est produite.",
|
||||
"alert.unexpected.title": "Oups !",
|
||||
"boost_modal.combo": "Vous pouvez appuyer sur {combo} pour pouvoir passer ceci, la prochaine fois",
|
||||
"bundle_column_error.body": "Une erreur s’est produite lors du chargement de ce composant.",
|
||||
"bundle_column_error.retry": "Réessayer",
|
||||
|
|
@ -39,6 +41,8 @@
|
|||
"bundle_modal_error.retry": "Réessayer",
|
||||
"column.blocks": "Comptes bloqués",
|
||||
"column.community": "Fil public local",
|
||||
"column.direct": "Messages directs",
|
||||
"column.domain_blocks": "Domaines cachés",
|
||||
"column.favourites": "Favoris",
|
||||
"column.follow_requests": "Demandes de suivi",
|
||||
"column.home": "Accueil",
|
||||
|
|
@ -54,8 +58,9 @@
|
|||
"column_header.pin": "Épingler",
|
||||
"column_header.show_settings": "Afficher les paramètres",
|
||||
"column_header.unpin": "Retirer",
|
||||
"column_subheading.navigation": "Navigation",
|
||||
"column_subheading.settings": "Paramètres",
|
||||
"compose_form.direct_message_warning": "Ce pouet sera uniquement envoyé qu'aux personnes mentionnées. Cependant, l'administration de votre instance et des instances réceptrices pourront inspecter ce message.",
|
||||
"compose_form.direct_message_warning_learn_more": "En savoir plus",
|
||||
"compose_form.hashtag_warning": "Ce pouet ne sera pas listé dans les recherches par hashtag car sa visibilité est réglée sur \"non-listé\". Seuls les pouets avec une visibilité \"publique\" peuvent être recherchés par hashtag.",
|
||||
"compose_form.lock_disclaimer": "Votre compte n’est pas {locked}. Tout le monde peut vous suivre et voir vos pouets privés.",
|
||||
"compose_form.lock_disclaimer.lock": "verrouillé",
|
||||
|
|
@ -73,43 +78,45 @@
|
|||
"confirmations.delete.confirm": "Supprimer",
|
||||
"confirmations.delete.message": "Confirmez-vous la suppression de ce pouet ?",
|
||||
"confirmations.delete_list.confirm": "Supprimer",
|
||||
"confirmations.delete_list.message": "Êtes-vous sûr de vouloir supprimer définitivement cette liste ?",
|
||||
"confirmations.delete_list.message": "Êtes-vous sûr de vouloir supprimer définitivement cette liste ?",
|
||||
"confirmations.domain_block.confirm": "Masquer le domaine entier",
|
||||
"confirmations.domain_block.message": "Êtes-vous vraiment, vraiment sûr⋅e de vouloir bloquer {domain} en entier ? Dans la plupart des cas, quelques blocages ou masquages ciblés sont suffisants et préférables.",
|
||||
"confirmations.mute.confirm": "Masquer",
|
||||
"confirmations.mute.message": "Confirmez-vous le masquage de {name} ?",
|
||||
"confirmations.redraft.confirm": "Delete & redraft",
|
||||
"confirmations.redraft.message": "Are you sure you want to delete this status and re-draft it? You will lose all replies, boosts and favourites to it.",
|
||||
"confirmations.unfollow.confirm": "Ne plus suivre",
|
||||
"confirmations.unfollow.message": "Voulez-vous arrêter de suivre {name} ?",
|
||||
"embed.instructions": "Intégrez ce statut à votre site en copiant le code ci-dessous.",
|
||||
"embed.preview": "Il apparaîtra comme cela :",
|
||||
"embed.preview": "Il apparaîtra comme cela :",
|
||||
"emoji_button.activity": "Activités",
|
||||
"emoji_button.custom": "Personnalisés",
|
||||
"emoji_button.flags": "Drapeaux",
|
||||
"emoji_button.food": "Boire et manger",
|
||||
"emoji_button.food": "Nourriture & Boisson",
|
||||
"emoji_button.label": "Insérer un émoji",
|
||||
"emoji_button.nature": "Nature",
|
||||
"emoji_button.not_found": "Pas d'emojis !! (╯°□°)╯︵ ┻━┻",
|
||||
"emoji_button.not_found": "Pas d'emojis !! (╯°□°)╯︵ ┻━┻",
|
||||
"emoji_button.objects": "Objets",
|
||||
"emoji_button.people": "Personnages",
|
||||
"emoji_button.recent": "Fréquemment utilisés",
|
||||
"emoji_button.search": "Recherche…",
|
||||
"emoji_button.search_results": "Résultats de la recherche",
|
||||
"emoji_button.symbols": "Symboles",
|
||||
"emoji_button.travel": "Lieux et voyages",
|
||||
"emoji_button.travel": "Lieux & Voyages",
|
||||
"empty_column.community": "Le fil public local est vide. Écrivez donc quelque chose pour le remplir !",
|
||||
"empty_column.direct": "Vous n'avez pas encore de messages directs. Lorsque vous en enverrez ou recevrez un, il s'affichera ici.",
|
||||
"empty_column.hashtag": "Il n’y a encore aucun contenu associé à ce hashtag.",
|
||||
"empty_column.home": "Vous ne suivez encore personne. Visitez {public} ou bien utilisez la recherche pour vous connecter à d’autres utilisateur⋅ice⋅s.",
|
||||
"empty_column.home": "Vous ne suivez personne. Visitez {public} ou utilisez la recherche pour trouver d’autres personnes à suivre.",
|
||||
"empty_column.home.public_timeline": "le fil public",
|
||||
"empty_column.list": "Il n'y a rien dans cette liste pour l'instant. Dès que des personnes de cette liste publierons de nouveaux statuts, ils apparaîtront ici.",
|
||||
"empty_column.notifications": "Vous n’avez pas encore de notification. Interagissez avec d’autres utilisateur⋅ice⋅s pour débuter la conversation.",
|
||||
"empty_column.public": "Il n’y a rien ici ! Écrivez quelque chose publiquement, ou bien suivez manuellement des utilisateur⋅ice·s d’autres instances pour remplir le fil public",
|
||||
"empty_column.notifications": "Vous n’avez pas encore de notification. Interagissez avec d’autres personnes pour débuter la conversation.",
|
||||
"empty_column.public": "Il n’y a rien ici ! Écrivez quelque chose publiquement, ou bien suivez manuellement des personnes d’autres instances pour remplir le fil public",
|
||||
"follow_request.authorize": "Accepter",
|
||||
"follow_request.reject": "Rejeter",
|
||||
"getting_started.appsshort": "Applications",
|
||||
"getting_started.faq": "FAQ",
|
||||
"getting_started.documentation": "Documentation",
|
||||
"getting_started.heading": "Pour commencer",
|
||||
"getting_started.open_source_notice": "Mastodon est un logiciel libre. Vous pouvez contribuer et envoyer vos commentaires et rapports de bogues via {github} sur GitHub.",
|
||||
"getting_started.userguide": "Guide d’utilisation",
|
||||
"getting_started.terms": "Conditions d’utilisation",
|
||||
"home.column_settings.advanced": "Avancé",
|
||||
"home.column_settings.basic": "Basique",
|
||||
"home.column_settings.filter_regex": "Filtrer avec une expression rationnelle",
|
||||
|
|
@ -119,9 +126,9 @@
|
|||
"keyboard_shortcuts.back": "revenir en arrière",
|
||||
"keyboard_shortcuts.boost": "partager",
|
||||
"keyboard_shortcuts.column": "focaliser un statut dans l'une des colonnes",
|
||||
"keyboard_shortcuts.compose": "pour centrer la zone de redaction",
|
||||
"keyboard_shortcuts.compose": "pour centrer la zone de rédaction",
|
||||
"keyboard_shortcuts.description": "Description",
|
||||
"keyboard_shortcuts.down": "descendre dans la liste",
|
||||
"keyboard_shortcuts.down": "pour descendre dans la liste",
|
||||
"keyboard_shortcuts.enter": "pour ouvrir le statut",
|
||||
"keyboard_shortcuts.favourite": "vers les favoris",
|
||||
"keyboard_shortcuts.heading": "Raccourcis clavier",
|
||||
|
|
@ -130,6 +137,7 @@
|
|||
"keyboard_shortcuts.mention": "pour mentionner l'auteur",
|
||||
"keyboard_shortcuts.reply": "pour répondre",
|
||||
"keyboard_shortcuts.search": "pour cibler la recherche",
|
||||
"keyboard_shortcuts.toggle_hidden": "pour afficher/cacher un texte derrière CW",
|
||||
"keyboard_shortcuts.toot": "pour démarrer un tout nouveau pouet",
|
||||
"keyboard_shortcuts.unfocus": "pour recentrer composer textarea/search",
|
||||
"keyboard_shortcuts.up": "pour remonter dans la liste",
|
||||
|
|
@ -148,9 +156,12 @@
|
|||
"media_gallery.toggle_visible": "Modifier la visibilité",
|
||||
"missing_indicator.label": "Non trouvé",
|
||||
"missing_indicator.sublabel": "Ressource introuvable",
|
||||
"mute_modal.hide_notifications": "Masquer les notifications de cet utilisateur ?",
|
||||
"mute_modal.hide_notifications": "Masquer les notifications de cette personne ?",
|
||||
"navigation_bar.blocks": "Comptes bloqués",
|
||||
"navigation_bar.community_timeline": "Fil public local",
|
||||
"navigation_bar.direct": "Messages directs",
|
||||
"navigation_bar.discover": "Découvrir",
|
||||
"navigation_bar.domain_blocks": "Domaines cachés",
|
||||
"navigation_bar.edit_profile": "Modifier le profil",
|
||||
"navigation_bar.favourites": "Favoris",
|
||||
"navigation_bar.follow_requests": "Demandes de suivi",
|
||||
|
|
@ -159,32 +170,35 @@
|
|||
"navigation_bar.lists": "Listes",
|
||||
"navigation_bar.logout": "Déconnexion",
|
||||
"navigation_bar.mutes": "Comptes masqués",
|
||||
"navigation_bar.personal": "Personal",
|
||||
"navigation_bar.pins": "Pouets épinglés",
|
||||
"navigation_bar.preferences": "Préférences",
|
||||
"navigation_bar.public_timeline": "Fil public global",
|
||||
"navigation_bar.security": "Sécurité",
|
||||
"notification.favourite": "{name} a ajouté à ses favoris :",
|
||||
"notification.follow": "{name} vous suit",
|
||||
"notification.mention": "{name} vous a mentionné⋅e :",
|
||||
"notification.reblog": "{name} a partagé votre statut :",
|
||||
"notifications.clear": "Nettoyer",
|
||||
"notifications.clear": "Nettoyer les notifications",
|
||||
"notifications.clear_confirmation": "Voulez-vous vraiment supprimer toutes vos notifications ?",
|
||||
"notifications.column_settings.alert": "Notifications locales",
|
||||
"notifications.column_settings.favourite": "Favoris :",
|
||||
"notifications.column_settings.follow": "Nouveaux⋅elles abonné⋅e·s :",
|
||||
"notifications.column_settings.mention": "Mentions :",
|
||||
"notifications.column_settings.push": "Notifications push",
|
||||
"notifications.column_settings.favourite": "Favoris :",
|
||||
"notifications.column_settings.follow": "Nouveaux⋅elles abonné⋅e·s :",
|
||||
"notifications.column_settings.mention": "Mentions :",
|
||||
"notifications.column_settings.push": "Notifications",
|
||||
"notifications.column_settings.push_meta": "Cet appareil",
|
||||
"notifications.column_settings.reblog": "Partages :",
|
||||
"notifications.column_settings.show": "Afficher dans la colonne",
|
||||
"notifications.column_settings.sound": "Émettre un son",
|
||||
"notifications.group": "{count} notifications",
|
||||
"onboarding.done": "Effectué",
|
||||
"onboarding.next": "Suivant",
|
||||
"onboarding.page_five.public_timelines": "Le fil public global affiche les posts de tou⋅te⋅s les utilisateur⋅ice⋅s suivi⋅es par les membres de {domain}. Le fil public local est identique mais se limite aux utilisateur⋅ice⋅s de {domain}.",
|
||||
"onboarding.page_four.home": "L’Accueil affiche les posts de tou⋅te·s les utilisateur⋅ice·s que vous suivez.",
|
||||
"onboarding.page_four.notifications": "Les Notifications vous informent lorsque quelqu’un interagit avec vous.",
|
||||
"onboarding.page_one.federation": "Mastodon est un réseau social qui appartient à tou⋅te⋅s.",
|
||||
"onboarding.page_one.full_handle": "Votre pleine maîtrise",
|
||||
"onboarding.page_one.handle_hint": "C'est ce que vous diriez à vos amis de rechercher.",
|
||||
"onboarding.page_five.public_timelines": "Le fil public global affiche les messages de toutes les personnes suivies par les membres de {domain}. Le fil public local est identique, mais se limite aux membres de {domain}.",
|
||||
"onboarding.page_four.home": "L’accueil affiche les messages des personnes que vous suivez.",
|
||||
"onboarding.page_four.notifications": "La colonne de notification vous avertit lors d'une interaction avec vous.",
|
||||
"onboarding.page_one.federation": "Mastodon est un réseau de serveurs indépendants qui se joignent pour former un réseau social plus vaste. Nous appelons ces serveurs des instances.",
|
||||
"onboarding.page_one.full_handle": "Votre identifiant complet",
|
||||
"onboarding.page_one.handle_hint": "C'est ce que vos amis devront rechercher.",
|
||||
"onboarding.page_one.welcome": "Bienvenue sur Mastodon !",
|
||||
"onboarding.page_six.admin": "L’administrateur⋅ice de votre instance est {admin}.",
|
||||
"onboarding.page_six.almost_done": "Nous y sommes presque…",
|
||||
|
|
@ -195,47 +209,49 @@
|
|||
"onboarding.page_six.read_guidelines": "S’il vous plaît, n’oubliez pas de lire les {guidelines} !",
|
||||
"onboarding.page_six.various_app": "applications mobiles",
|
||||
"onboarding.page_three.profile": "Modifiez votre profil pour changer votre avatar, votre description ainsi que votre nom. Vous y trouverez également d’autres préférences.",
|
||||
"onboarding.page_three.search": "Utilisez la barre de recherche pour trouver des utilisateur⋅ice⋅s et regarder des hashtags tels que {illustration} et {introductions}. Pour trouver quelqu’un qui n’est pas sur cette instance, utilisez son nom d’utilisateur⋅ice complet.",
|
||||
"onboarding.page_three.search": "Utilisez la barre de recherche pour trouver des utilisateur⋅ice⋅s ou regardez des hashtags tels que {illustration} et {introductions}. Pour trouver quelqu’un qui n’est pas sur cette instance, utilisez son identifiant complet.",
|
||||
"onboarding.page_two.compose": "Écrivez depuis la colonne de composition. Vous pouvez ajouter des images, changer les réglages de confidentialité, et ajouter des avertissements de contenu (Content Warning) grâce aux icônes en dessous.",
|
||||
"onboarding.skip": "Passer",
|
||||
"privacy.change": "Ajuster la confidentialité du message",
|
||||
"privacy.direct.long": "N'envoyer qu'aux personnes mentionnées",
|
||||
"privacy.direct.short": "Direct",
|
||||
"privacy.private.long": "N'envoyer qu'à vos abonné⋅e⋅s",
|
||||
"privacy.private.short": "Privé",
|
||||
"privacy.private.long": "Seul⋅e⋅s vos abonné⋅e⋅s verront vos statuts",
|
||||
"privacy.private.short": "Abonné⋅e⋅s uniquement",
|
||||
"privacy.public.long": "Afficher dans les fils publics",
|
||||
"privacy.public.short": "Public",
|
||||
"privacy.unlisted.long": "Ne pas afficher dans les fils publics",
|
||||
"privacy.unlisted.short": "Non-listé",
|
||||
"regeneration_indicator.label": "Chargement…",
|
||||
"regeneration_indicator.sublabel": "Le flux de votre page principale est en cours de préparation !",
|
||||
"relative_time.days": "{number} j",
|
||||
"relative_time.hours": "{number} h",
|
||||
"regeneration_indicator.sublabel": "Le flux de votre page principale est en cours de préparation !",
|
||||
"relative_time.days": "{number} j",
|
||||
"relative_time.hours": "{number} h",
|
||||
"relative_time.just_now": "à l’instant",
|
||||
"relative_time.minutes": "{number} min",
|
||||
"relative_time.seconds": "{number} s",
|
||||
"reply_indicator.cancel": "Annuler",
|
||||
"report.forward": "Transférer à {target}",
|
||||
"report.forward_hint": "Le compte provient d'un autre serveur. Envoyez également une copie anonyme du rapport ?",
|
||||
"report.hint": "Le rapport sera envoyé aux modérateurs de votre instance. Vous pouvez expliquer pourquoi vous signalez ce compte ci-dessous :",
|
||||
"report.forward_hint": "Le compte provient d'un autre serveur. Envoyez également une copie anonyme du rapport ?",
|
||||
"report.hint": "Le rapport sera envoyé aux modérateurs de votre instance. Vous pouvez expliquer pourquoi vous signalez le compte ci-dessous :",
|
||||
"report.placeholder": "Commentaires additionnels",
|
||||
"report.submit": "Envoyer",
|
||||
"report.target": "Signalement",
|
||||
"search.placeholder": "Rechercher",
|
||||
"search_popout.search_format": "Recherche avancée",
|
||||
"search_popout.tips.full_text": "Les textes simples retournent les pouets que vous avez écris, mis en favori, épinglés, ou ayant été mentionnés, ainsi que les noms d'utilisateurs, les noms affichés, et les hashtags correspondant.",
|
||||
"search_popout.tips.full_text": "Les textes simples retournent les pouets que vous avez écris, mis en favori, épinglés, ou ayant été mentionnés, ainsi que les identifiants, les noms affichés, et les hashtags des personnes et messages correspondant.",
|
||||
"search_popout.tips.hashtag": "hashtag",
|
||||
"search_popout.tips.status": "statuts",
|
||||
"search_popout.tips.text": "Un texte simple renvoie les noms affichés, les noms d’utilisateur⋅ice et les hashtags correspondants",
|
||||
"search_popout.tips.text": "Un texte simple renvoie les noms affichés, les identifiants et les hashtags correspondants",
|
||||
"search_popout.tips.user": "utilisateur⋅ice",
|
||||
"search_results.accounts": "Personnes",
|
||||
"search_results.accounts": "Comptes",
|
||||
"search_results.hashtags": "Hashtags",
|
||||
"search_results.statuses": "Pouets",
|
||||
"search_results.total": "{count, number} {count, plural, one {résultat} other {résultats}}",
|
||||
"standalone.public_title": "Jeter un coup d’œil…",
|
||||
"standalone.public_title": "Un aperçu …",
|
||||
"status.block": "Block @{name}",
|
||||
"status.cancel_reblog_private": "Dé-booster",
|
||||
"status.cannot_reblog": "Cette publication ne peut être boostée",
|
||||
"status.delete": "Effacer",
|
||||
"status.direct": "Message direct à @{name}",
|
||||
"status.embed": "Intégrer",
|
||||
"status.favourite": "Ajouter aux favoris",
|
||||
"status.load_more": "Charger plus",
|
||||
|
|
@ -248,7 +264,9 @@
|
|||
"status.pin": "Épingler sur le profil",
|
||||
"status.pinned": "Pouet épinglé",
|
||||
"status.reblog": "Partager",
|
||||
"status.reblog_private": "Booster vers l'audience originale",
|
||||
"status.reblogged_by": "{name} a partagé :",
|
||||
"status.redraft": "Delete & re-draft",
|
||||
"status.reply": "Répondre",
|
||||
"status.replyAll": "Répondre au fil",
|
||||
"status.report": "Signaler @{name}",
|
||||
|
|
@ -265,12 +283,16 @@
|
|||
"tabs_bar.home": "Accueil",
|
||||
"tabs_bar.local_timeline": "Fil public local",
|
||||
"tabs_bar.notifications": "Notifications",
|
||||
"tabs_bar.search": "Chercher",
|
||||
"timeline.media": "Media",
|
||||
"timeline.posts": "Pouets",
|
||||
"trends.count_by_accounts": "{count} {rawCount, plural, one {person} other {people}} talking",
|
||||
"ui.beforeunload": "Votre brouillon sera perdu si vous quittez Mastodon.",
|
||||
"upload_area.title": "Glissez et déposez pour envoyer",
|
||||
"upload_button.label": "Joindre un média",
|
||||
"upload_form.description": "Décrire pour les malvoyants",
|
||||
"upload_form.focus": "Recadrer",
|
||||
"upload_form.undo": "Annuler",
|
||||
"upload_form.undo": "Supprimer",
|
||||
"upload_progress.label": "Envoi en cours…",
|
||||
"video.close": "Fermer la vidéo",
|
||||
"video.exit_fullscreen": "Quitter plein écran",
|
||||
|
|
|
|||
|
|
@ -1,9 +1,11 @@
|
|||
{
|
||||
"account.badges.bot": "Bot",
|
||||
"account.block": "Bloquear @{name}",
|
||||
"account.block_domain": "Ocultar calquer contido de {domain}",
|
||||
"account.blocked": "Blocked",
|
||||
"account.blocked": "Bloqueada",
|
||||
"account.direct": "Mensaxe directa @{name}",
|
||||
"account.disclaimer_full": "A información inferior podería mostrar un perfil incompleto da usuaria.",
|
||||
"account.domain_blocked": "Domain hidden",
|
||||
"account.domain_blocked": "Dominio agochado",
|
||||
"account.edit_profile": "Editar perfil",
|
||||
"account.follow": "Seguir",
|
||||
"account.followers": "Seguidoras",
|
||||
|
|
@ -15,9 +17,9 @@
|
|||
"account.moved_to": "{name} marchou a:",
|
||||
"account.mute": "Acalar @{name}",
|
||||
"account.mute_notifications": "Acalar as notificacións de @{name}",
|
||||
"account.muted": "Muted",
|
||||
"account.muted": "Acalada",
|
||||
"account.posts": "Toots",
|
||||
"account.posts_with_replies": "Toots with replies",
|
||||
"account.posts_with_replies": "Toots e respostas",
|
||||
"account.report": "Informar sobre @{name}",
|
||||
"account.requested": "Agardando aceptación. Pulse para cancelar a solicitude de seguimento",
|
||||
"account.share": "Compartir o perfil de @{name}",
|
||||
|
|
@ -28,8 +30,8 @@
|
|||
"account.unmute": "Non acalar @{name}",
|
||||
"account.unmute_notifications": "Desbloquear as notificacións de @{name}",
|
||||
"account.view_full_profile": "Ver o perfil completo",
|
||||
"alert.unexpected.message": "An unexpected error occurred.",
|
||||
"alert.unexpected.title": "Oops!",
|
||||
"alert.unexpected.message": "Aconteceu un fallo non agardado.",
|
||||
"alert.unexpected.title": "Vaia!",
|
||||
"boost_modal.combo": "Pulse {combo} para saltar esto a próxima vez",
|
||||
"bundle_column_error.body": "Houbo un fallo mentras se cargaba este compoñente.",
|
||||
"bundle_column_error.retry": "Inténteo de novo",
|
||||
|
|
@ -39,6 +41,8 @@
|
|||
"bundle_modal_error.retry": "Inténteo de novo",
|
||||
"column.blocks": "Usuarias bloqueadas",
|
||||
"column.community": "Liña temporal local",
|
||||
"column.direct": "Mensaxes directas",
|
||||
"column.domain_blocks": "Dominios agochados",
|
||||
"column.favourites": "Favoritas",
|
||||
"column.follow_requests": "Peticións de seguimento",
|
||||
"column.home": "Inicio",
|
||||
|
|
@ -54,18 +58,19 @@
|
|||
"column_header.pin": "Fixar",
|
||||
"column_header.show_settings": "Mostras axustes",
|
||||
"column_header.unpin": "Soltar",
|
||||
"column_subheading.navigation": "Navegación",
|
||||
"column_subheading.settings": "Axustes",
|
||||
"compose_form.direct_message_warning": "Este toot enviarase só as usuarias mencionadas. Porén, a súa proveedora de internet e calquera das instancias receptoras poderían examinar esta mensaxe.",
|
||||
"compose_form.direct_message_warning_learn_more": "Learn more",
|
||||
"compose_form.hashtag_warning": "Esta mensaxe non será listada baixo ningunha etiqueta xa que está marcada como non listada. Só os toots públicos poden buscarse por etiquetas.",
|
||||
"compose_form.lock_disclaimer": "A súa conta non está {locked}. Calquera pode seguila para ver as súas mensaxes só-para-seguidoras.",
|
||||
"compose_form.lock_disclaimer.lock": "bloqueado",
|
||||
"compose_form.placeholder": "A qué andas?",
|
||||
"compose_form.publish": "Toot",
|
||||
"compose_form.publish_loud": "{publish}!",
|
||||
"compose_form.sensitive.marked": "Media is marked as sensitive",
|
||||
"compose_form.sensitive.unmarked": "Media is not marked as sensitive",
|
||||
"compose_form.spoiler.marked": "Text is hidden behind warning",
|
||||
"compose_form.spoiler.unmarked": "Text is not hidden",
|
||||
"compose_form.sensitive.marked": "Medios marcados como sensibles",
|
||||
"compose_form.sensitive.unmarked": "Os medios non están marcados como sensibles",
|
||||
"compose_form.spoiler.marked": "O texto está agochado tras un aviso",
|
||||
"compose_form.spoiler.unmarked": "O texto non está agochado",
|
||||
"compose_form.spoiler_placeholder": "Escriba o aviso aquí",
|
||||
"confirmation_modal.cancel": "Cancelar",
|
||||
"confirmations.block.confirm": "Bloquear",
|
||||
|
|
@ -78,6 +83,8 @@
|
|||
"confirmations.domain_block.message": "Realmente está segura de que quere bloquear por completo o dominio {domain}? Normalmente é suficiente, e preferible, bloquear de xeito selectivo varios elementos.",
|
||||
"confirmations.mute.confirm": "Acalar",
|
||||
"confirmations.mute.message": "Está segura de que quere acalar a {name}?",
|
||||
"confirmations.redraft.confirm": "Delete & redraft",
|
||||
"confirmations.redraft.message": "Are you sure you want to delete this status and re-draft it? You will lose all replies, boosts and favourites to it.",
|
||||
"confirmations.unfollow.confirm": "Deixar de seguir",
|
||||
"confirmations.unfollow.message": "Quere deixar de seguir a {name}?",
|
||||
"embed.instructions": "Copie o código inferior para incrustar no seu sitio web este estado.",
|
||||
|
|
@ -97,6 +104,7 @@
|
|||
"emoji_button.symbols": "Símbolos",
|
||||
"emoji_button.travel": "Viaxes e Lugares",
|
||||
"empty_column.community": "A liña temporal local está baldeira. Escriba algo de xeito público para que rule!",
|
||||
"empty_column.direct": "Aínda non ten mensaxes directas. Cando envíe ou reciba unha, aparecerá aquí.",
|
||||
"empty_column.hashtag": "Aínda non hai nada con esta etiqueta.",
|
||||
"empty_column.home": "A súa liña temporal de inicio está baldeira! Visite {public} ou utilice a busca para atopar outras usuarias.",
|
||||
"empty_column.home.public_timeline": "a liña temporal pública",
|
||||
|
|
@ -105,11 +113,10 @@
|
|||
"empty_column.public": "Nada por aquí! Escriba algo de xeito público, ou siga manualmente usuarias de outras instancias para ir enchéndoa",
|
||||
"follow_request.authorize": "Autorizar",
|
||||
"follow_request.reject": "Rexeitar",
|
||||
"getting_started.appsshort": "Aplicacións",
|
||||
"getting_started.faq": "PMF",
|
||||
"getting_started.documentation": "Documentation",
|
||||
"getting_started.heading": "Comezando",
|
||||
"getting_started.open_source_notice": "Mastodon é software de código aberto. Pode contribuír ou informar de fallos en GitHub en {github}.",
|
||||
"getting_started.userguide": "Guía de usuaria",
|
||||
"getting_started.terms": "Terms of service",
|
||||
"home.column_settings.advanced": "Avanzado",
|
||||
"home.column_settings.basic": "Básico",
|
||||
"home.column_settings.filter_regex": "Filtrar expresións regulares",
|
||||
|
|
@ -130,6 +137,7 @@
|
|||
"keyboard_shortcuts.mention": "para mencionar o autor",
|
||||
"keyboard_shortcuts.reply": "para responder",
|
||||
"keyboard_shortcuts.search": "para centrar a busca",
|
||||
"keyboard_shortcuts.toggle_hidden": "mostrar/agochar un texto detrás do AC",
|
||||
"keyboard_shortcuts.toot": "escribir un toot novo",
|
||||
"keyboard_shortcuts.unfocus": "quitar o foco do área de escritura/busca",
|
||||
"keyboard_shortcuts.up": "ir hacia arriba na lista",
|
||||
|
|
@ -145,23 +153,28 @@
|
|||
"lists.search": "Procurar entre a xente que segues",
|
||||
"lists.subheading": "As túas listas",
|
||||
"loading_indicator.label": "Cargando...",
|
||||
"media_gallery.toggle_visible": "Dar visibilidade",
|
||||
"media_gallery.toggle_visible": "Ocultar",
|
||||
"missing_indicator.label": "Non atopado",
|
||||
"missing_indicator.sublabel": "This resource could not be found",
|
||||
"missing_indicator.sublabel": "Non se puido atopar o recurso",
|
||||
"mute_modal.hide_notifications": "Esconder notificacións deste usuario?",
|
||||
"navigation_bar.blocks": "Usuarias bloqueadas",
|
||||
"navigation_bar.community_timeline": "Liña temporal local",
|
||||
"navigation_bar.direct": "Mensaxes directas",
|
||||
"navigation_bar.discover": "Discover",
|
||||
"navigation_bar.domain_blocks": "Dominios agochados",
|
||||
"navigation_bar.edit_profile": "Editar perfil",
|
||||
"navigation_bar.favourites": "Favoritas",
|
||||
"navigation_bar.follow_requests": "Peticións de seguimento",
|
||||
"navigation_bar.info": "Sobre esta instancia",
|
||||
"navigation_bar.keyboard_shortcuts": "Atallos do teclado",
|
||||
"navigation_bar.keyboard_shortcuts": "Atallos",
|
||||
"navigation_bar.lists": "Listas",
|
||||
"navigation_bar.logout": "Sair",
|
||||
"navigation_bar.mutes": "Usuarias acaladas",
|
||||
"navigation_bar.personal": "Personal",
|
||||
"navigation_bar.pins": "Mensaxes fixadas",
|
||||
"navigation_bar.preferences": "Preferencias",
|
||||
"navigation_bar.public_timeline": "Liña temporal federada",
|
||||
"navigation_bar.security": "Security",
|
||||
"notification.favourite": "{name} marcou como favorito o seu estado",
|
||||
"notification.follow": "{name} está a seguila",
|
||||
"notification.mention": "{name} mencionoute",
|
||||
|
|
@ -177,6 +190,7 @@
|
|||
"notifications.column_settings.reblog": "Promocións:",
|
||||
"notifications.column_settings.show": "Mostrar en columna",
|
||||
"notifications.column_settings.sound": "Reproducir son",
|
||||
"notifications.group": "{count} notifications",
|
||||
"onboarding.done": "Feito",
|
||||
"onboarding.next": "Seguinte",
|
||||
"onboarding.page_five.public_timelines": "A liña de tempo local mostra as publicacións públicas de todos en {domain}. A liña de tempo federada mostra as publicacións públicas de todos os que as persoas en {domain} seguen. Estas son as Liñas de tempo públicas, unha boa forma de descubrir novas persoas.",
|
||||
|
|
@ -207,35 +221,37 @@
|
|||
"privacy.public.short": "Pública",
|
||||
"privacy.unlisted.long": "Non publicar en liñas temporais públicas",
|
||||
"privacy.unlisted.short": "Non listada",
|
||||
"regeneration_indicator.label": "Loading…",
|
||||
"regeneration_indicator.sublabel": "Your home feed is being prepared!",
|
||||
"regeneration_indicator.label": "Cargando…",
|
||||
"regeneration_indicator.sublabel": "Estase a preparar a súa liña temporal de inicio!",
|
||||
"relative_time.days": "{number}d",
|
||||
"relative_time.hours": "{number}h",
|
||||
"relative_time.just_now": "agora",
|
||||
"relative_time.minutes": "{number}m",
|
||||
"relative_time.seconds": "{number}s",
|
||||
"reply_indicator.cancel": "Cancelar",
|
||||
"report.forward": "Forward to {target}",
|
||||
"report.forward_hint": "The account is from another server. Send an anonymized copy of the report there as well?",
|
||||
"report.hint": "The report will be sent to your instance moderators. You can provide an explanation of why you are reporting this account below:",
|
||||
"report.forward": "Reenviar a {target}",
|
||||
"report.forward_hint": "A conta pertence a outro servidor. Enviar unha copia anónima do informe alí tamén?",
|
||||
"report.hint": "O informe enviarase a moderación da súa instancia. Abaixo pode explicar a razón pola que está a información:",
|
||||
"report.placeholder": "Comentarios adicionais",
|
||||
"report.submit": "Enviar",
|
||||
"report.target": "Informar {target}",
|
||||
"search.placeholder": "Buscar",
|
||||
"search_popout.search_format": "Formato de busca avanzada",
|
||||
"search_popout.tips.full_text": "Simple text returns statuses you have written, favourited, boosted, or have been mentioned in, as well as matching usernames, display names, and hashtags.",
|
||||
"search_popout.tips.full_text": "Texto simple devolve estados que vostede escribeu, promoveu, marcou favoritos, ou foi mencionada, así como nomes de usuaria coincidentes, nomes públicos e etiquetas.",
|
||||
"search_popout.tips.hashtag": "etiqueta",
|
||||
"search_popout.tips.status": "estado",
|
||||
"search_popout.tips.text": "Texto simple devolve coincidencias con nomes públicos, nomes de usuaria e etiquetas",
|
||||
"search_popout.tips.user": "usuaria",
|
||||
"search_results.accounts": "People",
|
||||
"search_results.hashtags": "Hashtags",
|
||||
"search_results.accounts": "Xente",
|
||||
"search_results.hashtags": "Etiquetas",
|
||||
"search_results.statuses": "Toots",
|
||||
"search_results.total": "{count, number} {count,plural,one {result} outros {results}}",
|
||||
"standalone.public_title": "Ollada dentro...",
|
||||
"status.block": "Block @{name}",
|
||||
"status.cannot_reblog": "Esta mensaxe non pode ser promocionada",
|
||||
"status.cancel_reblog_private": "Non promover",
|
||||
"status.cannot_reblog": "Esta mensaxe non pode ser promovida",
|
||||
"status.delete": "Eliminar",
|
||||
"status.direct": "Mensaxe directa @{name}",
|
||||
"status.embed": "Incrustar",
|
||||
"status.favourite": "Favorita",
|
||||
"status.load_more": "Cargar máis",
|
||||
|
|
@ -246,9 +262,11 @@
|
|||
"status.mute_conversation": "Acalar conversa",
|
||||
"status.open": "Expandir este estado",
|
||||
"status.pin": "Fixar no perfil",
|
||||
"status.pinned": "Pinned toot",
|
||||
"status.pinned": "Toot fixado",
|
||||
"status.reblog": "Promover",
|
||||
"status.reblog_private": "Promover a audiencia orixinal",
|
||||
"status.reblogged_by": "{name} promoveu",
|
||||
"status.redraft": "Delete & re-draft",
|
||||
"status.reply": "Resposta",
|
||||
"status.replyAll": "Resposta a conversa",
|
||||
"status.report": "Informar @{name}",
|
||||
|
|
@ -256,21 +274,25 @@
|
|||
"status.sensitive_warning": "Contido sensible",
|
||||
"status.share": "Compartir",
|
||||
"status.show_less": "Mostrar menos",
|
||||
"status.show_less_all": "Show less for all",
|
||||
"status.show_less_all": "Mostrar menos para todas",
|
||||
"status.show_more": "Mostrar máis",
|
||||
"status.show_more_all": "Show more for all",
|
||||
"status.show_more_all": "Mostrar máis para todas",
|
||||
"status.unmute_conversation": "Non acalar a conversa",
|
||||
"status.unpin": "Despegar do perfil",
|
||||
"tabs_bar.federated_timeline": "Federado",
|
||||
"tabs_bar.home": "Inicio",
|
||||
"tabs_bar.local_timeline": "Local",
|
||||
"tabs_bar.notifications": "Notificacións",
|
||||
"tabs_bar.search": "Buscar",
|
||||
"timeline.media": "Media",
|
||||
"timeline.posts": "Toots",
|
||||
"trends.count_by_accounts": "{count} {rawCount, plural, one {person} other {people}} talking",
|
||||
"ui.beforeunload": "O borrador perderase se sae de Mastodon.",
|
||||
"upload_area.title": "Arrastre e solte para subir",
|
||||
"upload_button.label": "Engadir medios",
|
||||
"upload_form.description": "Describa para deficientes visuais",
|
||||
"upload_form.focus": "Crop",
|
||||
"upload_form.undo": "Desfacer",
|
||||
"upload_form.focus": "Recortar",
|
||||
"upload_form.undo": "Eliminar",
|
||||
"upload_progress.label": "Subindo...",
|
||||
"video.close": "Pechar video",
|
||||
"video.exit_fullscreen": "Saír da pantalla completa",
|
||||
|
|
|
|||
|
|
@ -1,7 +1,9 @@
|
|||
{
|
||||
"account.badges.bot": "Bot",
|
||||
"account.block": "חסימת @{name}",
|
||||
"account.block_domain": "להסתיר הכל מהקהילה {domain}",
|
||||
"account.blocked": "Blocked",
|
||||
"account.direct": "Direct Message @{name}",
|
||||
"account.disclaimer_full": "המידע להלן עשוי להיות לא עדכני או לא שלם.",
|
||||
"account.domain_blocked": "Domain hidden",
|
||||
"account.edit_profile": "עריכת פרופיל",
|
||||
|
|
@ -39,6 +41,8 @@
|
|||
"bundle_modal_error.retry": "לנסות שוב",
|
||||
"column.blocks": "חסימות",
|
||||
"column.community": "ציר זמן מקומי",
|
||||
"column.direct": "Direct messages",
|
||||
"column.domain_blocks": "Hidden domains",
|
||||
"column.favourites": "חיבובים",
|
||||
"column.follow_requests": "בקשות מעקב",
|
||||
"column.home": "בבית",
|
||||
|
|
@ -54,8 +58,9 @@
|
|||
"column_header.pin": "קיבוע",
|
||||
"column_header.show_settings": "הצגת העדפות",
|
||||
"column_header.unpin": "שחרור קיבוע",
|
||||
"column_subheading.navigation": "ניווט",
|
||||
"column_subheading.settings": "אפשרויות",
|
||||
"compose_form.direct_message_warning": "This toot will only be visible to all the mentioned users.",
|
||||
"compose_form.direct_message_warning_learn_more": "Learn more",
|
||||
"compose_form.hashtag_warning": "This toot won't be listed under any hashtag as it is unlisted. Only public toots can be searched by hashtag.",
|
||||
"compose_form.lock_disclaimer": "חשבונך אינו {locked}. כל אחד יוכל לעקוב אחריך כדי לקרוא את הודעותיך המיועדות לעוקבים בלבד.",
|
||||
"compose_form.lock_disclaimer.lock": "נעול",
|
||||
|
|
@ -78,6 +83,8 @@
|
|||
"confirmations.domain_block.message": "באמת באמת לחסום את כל קהילת {domain}? ברב המקרים השתקות נבחרות של מספר משתמשים מסויימים צריכה להספיק.",
|
||||
"confirmations.mute.confirm": "להשתיק",
|
||||
"confirmations.mute.message": "להשתיק את {name}?",
|
||||
"confirmations.redraft.confirm": "Delete & redraft",
|
||||
"confirmations.redraft.message": "Are you sure you want to delete this status and re-draft it? You will lose all replies, boosts and favourites to it.",
|
||||
"confirmations.unfollow.confirm": "להפסיק מעקב",
|
||||
"confirmations.unfollow.message": "להפסיק מעקב אחרי {name}?",
|
||||
"embed.instructions": "ניתן להטמיע את ההודעה באתרך ע\"י העתקת הקוד שלהלן.",
|
||||
|
|
@ -97,6 +104,7 @@
|
|||
"emoji_button.symbols": "סמלים",
|
||||
"emoji_button.travel": "טיולים ואתרים",
|
||||
"empty_column.community": "טור הסביבה ריק. יש לפרסם משהו כדי שדברים יתרחילו להתגלגל!",
|
||||
"empty_column.direct": "You don't have any direct messages yet. When you send or receive one, it will show up here.",
|
||||
"empty_column.hashtag": "אין כלום בהאשתג הזה עדיין.",
|
||||
"empty_column.home": "אף אחד לא במעקב עדיין. אפשר לבקר ב{public} או להשתמש בחיפוש כדי להתחיל ולהכיר חצוצרנים אחרים.",
|
||||
"empty_column.home.public_timeline": "ציר זמן בין-קהילתי",
|
||||
|
|
@ -105,11 +113,10 @@
|
|||
"empty_column.public": "אין פה כלום! כדי למלא את הטור הזה אפשר לכתוב משהו, או להתחיל לעקוב אחרי אנשים מקהילות אחרות",
|
||||
"follow_request.authorize": "קבלה",
|
||||
"follow_request.reject": "דחיה",
|
||||
"getting_started.appsshort": "יישומונים לניידים",
|
||||
"getting_started.faq": "שאלות ותשובות",
|
||||
"getting_started.documentation": "Documentation",
|
||||
"getting_started.heading": "בואו נתחיל",
|
||||
"getting_started.open_source_notice": "מסטודון היא תוכנה חופשית (בקוד פתוח). ניתן לתרום או לדווח על בעיות בגיטהאב: {github}.",
|
||||
"getting_started.userguide": "מדריך למשתמשים",
|
||||
"getting_started.terms": "Terms of service",
|
||||
"home.column_settings.advanced": "למתקדמים",
|
||||
"home.column_settings.basic": "למתחילים",
|
||||
"home.column_settings.filter_regex": "סינון באמצעות ביטויים רגולריים (regular expressions)",
|
||||
|
|
@ -130,6 +137,7 @@
|
|||
"keyboard_shortcuts.mention": "לאזכר את המחבר(ת)",
|
||||
"keyboard_shortcuts.reply": "לענות",
|
||||
"keyboard_shortcuts.search": "להתמקד בחלון החיפוש",
|
||||
"keyboard_shortcuts.toggle_hidden": "to show/hide text behind CW",
|
||||
"keyboard_shortcuts.toot": "להתחיל חיצרוץ חדש",
|
||||
"keyboard_shortcuts.unfocus": "לצאת מתיבת חיבור/חיפוש",
|
||||
"keyboard_shortcuts.up": "לנוע במעלה הרשימה",
|
||||
|
|
@ -151,6 +159,9 @@
|
|||
"mute_modal.hide_notifications": "להסתיר הודעות מחשבון זה?",
|
||||
"navigation_bar.blocks": "חסימות",
|
||||
"navigation_bar.community_timeline": "ציר זמן מקומי",
|
||||
"navigation_bar.direct": "Direct messages",
|
||||
"navigation_bar.discover": "Discover",
|
||||
"navigation_bar.domain_blocks": "Hidden domains",
|
||||
"navigation_bar.edit_profile": "עריכת פרופיל",
|
||||
"navigation_bar.favourites": "חיבובים",
|
||||
"navigation_bar.follow_requests": "בקשות מעקב",
|
||||
|
|
@ -159,9 +170,11 @@
|
|||
"navigation_bar.lists": "Lists",
|
||||
"navigation_bar.logout": "יציאה",
|
||||
"navigation_bar.mutes": "השתקות",
|
||||
"navigation_bar.personal": "Personal",
|
||||
"navigation_bar.pins": "חיצרוצים מקובעים",
|
||||
"navigation_bar.preferences": "העדפות",
|
||||
"navigation_bar.public_timeline": "ציר זמן בין-קהילתי",
|
||||
"navigation_bar.security": "Security",
|
||||
"notification.favourite": "חצרוצך חובב על ידי {name}",
|
||||
"notification.follow": "{name} במעקב אחרייך",
|
||||
"notification.mention": "אוזכרת על ידי {name}",
|
||||
|
|
@ -177,6 +190,7 @@
|
|||
"notifications.column_settings.reblog": "הדהודים:",
|
||||
"notifications.column_settings.show": "הצגה בטור",
|
||||
"notifications.column_settings.sound": "שמע מופעל",
|
||||
"notifications.group": "{count} notifications",
|
||||
"onboarding.done": "יציאה",
|
||||
"onboarding.next": "הלאה",
|
||||
"onboarding.page_five.public_timelines": "ציר הזמן המקומי מראה הודעות פומביות מכל באי קהילת {domain}. ציר הזמן העולמי מראה הודעות פומביות מאת כי מי שבאי קהילת {domain} עוקבים אחריו. אלו צירי הזמן הפומביים, דרך נהדרת לגלות אנשים חדשים.",
|
||||
|
|
@ -234,8 +248,10 @@
|
|||
"search_results.total": "{count, number} {count, plural, one {תוצאה} other {תוצאות}}",
|
||||
"standalone.public_title": "הצצה פנימה...",
|
||||
"status.block": "Block @{name}",
|
||||
"status.cancel_reblog_private": "Unboost",
|
||||
"status.cannot_reblog": "לא ניתן להדהד הודעה זו",
|
||||
"status.delete": "מחיקה",
|
||||
"status.direct": "Direct message @{name}",
|
||||
"status.embed": "הטמעה",
|
||||
"status.favourite": "חיבוב",
|
||||
"status.load_more": "עוד",
|
||||
|
|
@ -248,7 +264,9 @@
|
|||
"status.pin": "לקבע באודות",
|
||||
"status.pinned": "Pinned toot",
|
||||
"status.reblog": "הדהוד",
|
||||
"status.reblog_private": "Boost to original audience",
|
||||
"status.reblogged_by": "הודהד על ידי {name}",
|
||||
"status.redraft": "Delete & re-draft",
|
||||
"status.reply": "תגובה",
|
||||
"status.replyAll": "תגובה לכולם",
|
||||
"status.report": "דיווח על @{name}",
|
||||
|
|
@ -265,6 +283,10 @@
|
|||
"tabs_bar.home": "בבית",
|
||||
"tabs_bar.local_timeline": "ציר זמן מקומי",
|
||||
"tabs_bar.notifications": "התראות",
|
||||
"tabs_bar.search": "Search",
|
||||
"timeline.media": "Media",
|
||||
"timeline.posts": "Toots",
|
||||
"trends.count_by_accounts": "{count} {rawCount, plural, one {person} other {people}} talking",
|
||||
"ui.beforeunload": "הטיוטא תאבד אם תעזבו את מסטודון.",
|
||||
"upload_area.title": "ניתן להעלות על ידי Drag & drop",
|
||||
"upload_button.label": "הוספת מדיה",
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue