mirror of
https://github.com/funamitech/mastodon
synced 2024-11-23 14:46:52 +09:00
Merge pull request #2718 from ClearlyClaire/glitch-soc/merge-upstream
Merge upstream changes up to b6fd14f0e2
This commit is contained in:
commit
ef01546957
@ -1,18 +1,10 @@
|
||||
import type { ApiRelationshipJSON } from 'flavours/glitch/api_types/relationships';
|
||||
import { createAppAsyncThunk } from 'flavours/glitch/store/typed_functions';
|
||||
import { apiSubmitAccountNote } from 'flavours/glitch/api/accounts';
|
||||
import { createDataLoadingThunk } from 'flavours/glitch/store/typed_functions';
|
||||
|
||||
import api from '../api';
|
||||
|
||||
export const submitAccountNote = createAppAsyncThunk(
|
||||
export const submitAccountNote = createDataLoadingThunk(
|
||||
'account_note/submit',
|
||||
async (args: { id: string; value: string }) => {
|
||||
const response = await api().post<ApiRelationshipJSON>(
|
||||
`/api/v1/accounts/${args.id}/note`,
|
||||
{
|
||||
comment: args.value,
|
||||
},
|
||||
);
|
||||
|
||||
return { relationship: response.data };
|
||||
},
|
||||
({ accountId, note }: { accountId: string; note: string }) =>
|
||||
apiSubmitAccountNote(accountId, note),
|
||||
(relationship) => ({ relationship }),
|
||||
{ skipLoading: true },
|
||||
);
|
||||
|
@ -3,10 +3,6 @@ import api, { getLinks } from '../api';
|
||||
import { fetchRelationships } from './accounts';
|
||||
import { importFetchedAccounts, importFetchedStatus } from './importer';
|
||||
|
||||
export const REBLOG_REQUEST = 'REBLOG_REQUEST';
|
||||
export const REBLOG_SUCCESS = 'REBLOG_SUCCESS';
|
||||
export const REBLOG_FAIL = 'REBLOG_FAIL';
|
||||
|
||||
export const REBLOGS_EXPAND_REQUEST = 'REBLOGS_EXPAND_REQUEST';
|
||||
export const REBLOGS_EXPAND_SUCCESS = 'REBLOGS_EXPAND_SUCCESS';
|
||||
export const REBLOGS_EXPAND_FAIL = 'REBLOGS_EXPAND_FAIL';
|
||||
@ -15,10 +11,6 @@ export const FAVOURITE_REQUEST = 'FAVOURITE_REQUEST';
|
||||
export const FAVOURITE_SUCCESS = 'FAVOURITE_SUCCESS';
|
||||
export const FAVOURITE_FAIL = 'FAVOURITE_FAIL';
|
||||
|
||||
export const UNREBLOG_REQUEST = 'UNREBLOG_REQUEST';
|
||||
export const UNREBLOG_SUCCESS = 'UNREBLOG_SUCCESS';
|
||||
export const UNREBLOG_FAIL = 'UNREBLOG_FAIL';
|
||||
|
||||
export const UNFAVOURITE_REQUEST = 'UNFAVOURITE_REQUEST';
|
||||
export const UNFAVOURITE_SUCCESS = 'UNFAVOURITE_SUCCESS';
|
||||
export const UNFAVOURITE_FAIL = 'UNFAVOURITE_FAIL';
|
||||
@ -51,83 +43,7 @@ export const UNBOOKMARK_REQUEST = 'UNBOOKMARKED_REQUEST';
|
||||
export const UNBOOKMARK_SUCCESS = 'UNBOOKMARKED_SUCCESS';
|
||||
export const UNBOOKMARK_FAIL = 'UNBOOKMARKED_FAIL';
|
||||
|
||||
export function reblog(status, visibility) {
|
||||
return function (dispatch) {
|
||||
dispatch(reblogRequest(status));
|
||||
|
||||
api().post(`/api/v1/statuses/${status.get('id')}/reblog`, { visibility }).then(function (response) {
|
||||
// The reblog API method returns a new status wrapped around the original. In this case we are only
|
||||
// interested in how the original is modified, hence passing it skipping the wrapper
|
||||
dispatch(importFetchedStatus(response.data.reblog));
|
||||
dispatch(reblogSuccess(status));
|
||||
}).catch(function (error) {
|
||||
dispatch(reblogFail(status, error));
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
export function unreblog(status) {
|
||||
return (dispatch) => {
|
||||
dispatch(unreblogRequest(status));
|
||||
|
||||
api().post(`/api/v1/statuses/${status.get('id')}/unreblog`).then(response => {
|
||||
dispatch(importFetchedStatus(response.data));
|
||||
dispatch(unreblogSuccess(status));
|
||||
}).catch(error => {
|
||||
dispatch(unreblogFail(status, error));
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
export function reblogRequest(status) {
|
||||
return {
|
||||
type: REBLOG_REQUEST,
|
||||
status: status,
|
||||
skipLoading: true,
|
||||
};
|
||||
}
|
||||
|
||||
export function reblogSuccess(status) {
|
||||
return {
|
||||
type: REBLOG_SUCCESS,
|
||||
status: status,
|
||||
skipLoading: true,
|
||||
};
|
||||
}
|
||||
|
||||
export function reblogFail(status, error) {
|
||||
return {
|
||||
type: REBLOG_FAIL,
|
||||
status: status,
|
||||
error: error,
|
||||
skipLoading: true,
|
||||
};
|
||||
}
|
||||
|
||||
export function unreblogRequest(status) {
|
||||
return {
|
||||
type: UNREBLOG_REQUEST,
|
||||
status: status,
|
||||
skipLoading: true,
|
||||
};
|
||||
}
|
||||
|
||||
export function unreblogSuccess(status) {
|
||||
return {
|
||||
type: UNREBLOG_SUCCESS,
|
||||
status: status,
|
||||
skipLoading: true,
|
||||
};
|
||||
}
|
||||
|
||||
export function unreblogFail(status, error) {
|
||||
return {
|
||||
type: UNREBLOG_FAIL,
|
||||
status: status,
|
||||
error: error,
|
||||
skipLoading: true,
|
||||
};
|
||||
}
|
||||
export * from "./interactions_typed";
|
||||
|
||||
export function favourite(status) {
|
||||
return function (dispatch) {
|
||||
|
35
app/javascript/flavours/glitch/actions/interactions_typed.ts
Normal file
35
app/javascript/flavours/glitch/actions/interactions_typed.ts
Normal file
@ -0,0 +1,35 @@
|
||||
import { apiReblog, apiUnreblog } from 'flavours/glitch/api/interactions';
|
||||
import type { StatusVisibility } from 'flavours/glitch/models/status';
|
||||
import { createDataLoadingThunk } from 'flavours/glitch/store/typed_functions';
|
||||
|
||||
import { importFetchedStatus } from './importer';
|
||||
|
||||
export const reblog = createDataLoadingThunk(
|
||||
'status/reblog',
|
||||
({
|
||||
statusId,
|
||||
visibility,
|
||||
}: {
|
||||
statusId: string;
|
||||
visibility: StatusVisibility;
|
||||
}) => apiReblog(statusId, visibility),
|
||||
(data, { dispatch, discardLoadData }) => {
|
||||
// The reblog API method returns a new status wrapped around the original. In this case we are only
|
||||
// interested in how the original is modified, hence passing it skipping the wrapper
|
||||
dispatch(importFetchedStatus(data.reblog));
|
||||
|
||||
// The payload is not used in any actions
|
||||
return discardLoadData;
|
||||
},
|
||||
);
|
||||
|
||||
export const unreblog = createDataLoadingThunk(
|
||||
'status/unreblog',
|
||||
({ statusId }: { statusId: string }) => apiUnreblog(statusId),
|
||||
(data, { dispatch, discardLoadData }) => {
|
||||
dispatch(importFetchedStatus(data));
|
||||
|
||||
// The payload is not used in any actions
|
||||
return discardLoadData;
|
||||
},
|
||||
);
|
@ -1,4 +1,4 @@
|
||||
import type { AxiosResponse, RawAxiosRequestHeaders } from 'axios';
|
||||
import type { AxiosResponse, Method, RawAxiosRequestHeaders } from 'axios';
|
||||
import axios from 'axios';
|
||||
import LinkHeader from 'http-link-header';
|
||||
|
||||
@ -40,11 +40,11 @@ const authorizationTokenFromInitialState = (): RawAxiosRequestHeaders => {
|
||||
};
|
||||
|
||||
// eslint-disable-next-line import/no-default-export
|
||||
export default function api() {
|
||||
export default function api(withAuthorization = true) {
|
||||
return axios.create({
|
||||
headers: {
|
||||
...csrfHeader,
|
||||
...authorizationTokenFromInitialState(),
|
||||
...(withAuthorization ? authorizationTokenFromInitialState() : {}),
|
||||
},
|
||||
|
||||
transformResponse: [
|
||||
@ -58,3 +58,17 @@ export default function api() {
|
||||
],
|
||||
});
|
||||
}
|
||||
|
||||
export async function apiRequest<ApiResponse = unknown>(
|
||||
method: Method,
|
||||
url: string,
|
||||
params?: Record<string, unknown>,
|
||||
) {
|
||||
const { data } = await api().request<ApiResponse>({
|
||||
method,
|
||||
url: '/api/' + url,
|
||||
data: params,
|
||||
});
|
||||
|
||||
return data;
|
||||
}
|
||||
|
7
app/javascript/flavours/glitch/api/accounts.ts
Normal file
7
app/javascript/flavours/glitch/api/accounts.ts
Normal file
@ -0,0 +1,7 @@
|
||||
import { apiRequest } from 'flavours/glitch/api';
|
||||
import type { ApiRelationshipJSON } from 'flavours/glitch/api_types/relationships';
|
||||
|
||||
export const apiSubmitAccountNote = (id: string, value: string) =>
|
||||
apiRequest<ApiRelationshipJSON>('post', `v1/accounts/${id}/note`, {
|
||||
comment: value,
|
||||
});
|
10
app/javascript/flavours/glitch/api/interactions.ts
Normal file
10
app/javascript/flavours/glitch/api/interactions.ts
Normal file
@ -0,0 +1,10 @@
|
||||
import { apiRequest } from 'flavours/glitch/api';
|
||||
import type { Status, StatusVisibility } from 'flavours/glitch/models/status';
|
||||
|
||||
export const apiReblog = (statusId: string, visibility: StatusVisibility) =>
|
||||
apiRequest<{ reblog: Status }>('post', `v1/statuses/${statusId}/reblog`, {
|
||||
visibility,
|
||||
});
|
||||
|
||||
export const apiUnreblog = (statusId: string) =>
|
||||
apiRequest<Status>('post', `v1/statuses/${statusId}/unreblog`);
|
@ -48,7 +48,7 @@ export default class Counter extends PureComponent {
|
||||
componentDidMount () {
|
||||
const { measure, start_at, end_at, params } = this.props;
|
||||
|
||||
api().post('/api/v1/admin/measures', { keys: [measure], start_at, end_at, [measure]: params }).then(res => {
|
||||
api(false).post('/api/v1/admin/measures', { keys: [measure], start_at, end_at, [measure]: params }).then(res => {
|
||||
this.setState({
|
||||
loading: false,
|
||||
data: res.data,
|
||||
|
@ -26,7 +26,7 @@ export default class Dimension extends PureComponent {
|
||||
componentDidMount () {
|
||||
const { start_at, end_at, dimension, limit, params } = this.props;
|
||||
|
||||
api().post('/api/v1/admin/dimensions', { keys: [dimension], start_at, end_at, limit, [dimension]: params }).then(res => {
|
||||
api(false).post('/api/v1/admin/dimensions', { keys: [dimension], start_at, end_at, limit, [dimension]: params }).then(res => {
|
||||
this.setState({
|
||||
loading: false,
|
||||
data: res.data,
|
||||
|
@ -27,7 +27,7 @@ export default class ImpactReport extends PureComponent {
|
||||
include_subdomains: true,
|
||||
};
|
||||
|
||||
api().post('/api/v1/admin/measures', {
|
||||
api(false).post('/api/v1/admin/measures', {
|
||||
keys: ['instance_accounts', 'instance_follows', 'instance_followers'],
|
||||
start_at: null,
|
||||
end_at: null,
|
||||
|
@ -105,7 +105,7 @@ class ReportReasonSelector extends PureComponent {
|
||||
};
|
||||
|
||||
componentDidMount() {
|
||||
api().get('/api/v1/instance').then(res => {
|
||||
api(false).get('/api/v1/instance').then(res => {
|
||||
this.setState({
|
||||
rules: res.data.rules,
|
||||
});
|
||||
@ -122,7 +122,7 @@ class ReportReasonSelector extends PureComponent {
|
||||
return;
|
||||
}
|
||||
|
||||
api().put(`/api/v1/admin/reports/${id}`, {
|
||||
api(false).put(`/api/v1/admin/reports/${id}`, {
|
||||
category,
|
||||
rule_ids: category === 'violation' ? rule_ids : [],
|
||||
}).catch(err => {
|
||||
|
@ -34,7 +34,7 @@ export default class Retention extends PureComponent {
|
||||
componentDidMount () {
|
||||
const { start_at, end_at, frequency } = this.props;
|
||||
|
||||
api().post('/api/v1/admin/retention', { start_at, end_at, frequency }).then(res => {
|
||||
api(false).post('/api/v1/admin/retention', { start_at, end_at, frequency }).then(res => {
|
||||
this.setState({
|
||||
loading: false,
|
||||
data: res.data,
|
||||
|
@ -22,7 +22,7 @@ export default class Trends extends PureComponent {
|
||||
componentDidMount () {
|
||||
const { limit } = this.props;
|
||||
|
||||
api().get('/api/v1/admin/trends/tags', { params: { limit } }).then(res => {
|
||||
api(false).get('/api/v1/admin/trends/tags', { params: { limit } }).then(res => {
|
||||
this.setState({
|
||||
loading: false,
|
||||
data: res.data,
|
||||
|
@ -115,9 +115,9 @@ const mapDispatchToProps = (dispatch, { intl, contextType }) => ({
|
||||
|
||||
onModalReblog (status, privacy) {
|
||||
if (status.get('reblogged')) {
|
||||
dispatch(unreblog(status));
|
||||
dispatch(unreblog({ statusId: status.get('id') }));
|
||||
} else {
|
||||
dispatch(reblog(status, privacy));
|
||||
dispatch(reblog({ statusId: status.get('id'), visibility: privacy }));
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -11,7 +11,7 @@ const mapStateToProps = (state, { account }) => ({
|
||||
const mapDispatchToProps = (dispatch, { account }) => ({
|
||||
|
||||
onSave (value) {
|
||||
dispatch(submitAccountNote({ id: account.get('id'), value}));
|
||||
dispatch(submitAccountNote({ accountId: account.get('id'), note: value }));
|
||||
},
|
||||
|
||||
});
|
||||
|
@ -36,12 +36,12 @@ const mapDispatchToProps = dispatch => ({
|
||||
},
|
||||
|
||||
onModalReblog (status, privacy) {
|
||||
dispatch(reblog(status, privacy));
|
||||
dispatch(reblog({ statusId: status.get('id'), visibility: privacy }));
|
||||
},
|
||||
|
||||
onReblog (status, e) {
|
||||
if (status.get('reblogged')) {
|
||||
dispatch(unreblog(status));
|
||||
dispatch(unreblog({ statusId: status.get('id') }));
|
||||
} else {
|
||||
if (e.shiftKey || !boostModal) {
|
||||
this.onModalReblog(status);
|
||||
|
@ -125,7 +125,7 @@ class Footer extends ImmutablePureComponent {
|
||||
|
||||
_performReblog = (status, privacy) => {
|
||||
const { dispatch } = this.props;
|
||||
dispatch(reblog(status, privacy));
|
||||
dispatch(reblog({ statusId: status.get('id'), visibility: privacy }));
|
||||
};
|
||||
|
||||
handleReblogClick = e => {
|
||||
@ -134,7 +134,7 @@ class Footer extends ImmutablePureComponent {
|
||||
|
||||
if (signedIn) {
|
||||
if (status.get('reblogged')) {
|
||||
dispatch(unreblog(status));
|
||||
dispatch(unreblog({ statusId: status.get('id') }));
|
||||
} else if ((e && e.shiftKey) || !boostModal) {
|
||||
this._performReblog(status);
|
||||
} else {
|
||||
|
@ -71,12 +71,12 @@ const mapDispatchToProps = (dispatch, { intl }) => ({
|
||||
},
|
||||
|
||||
onModalReblog (status, privacy) {
|
||||
dispatch(reblog(status, privacy));
|
||||
dispatch(reblog({ statusId: status.get('id'), visibility: privacy }));
|
||||
},
|
||||
|
||||
onReblog (status, e) {
|
||||
if (status.get('reblogged')) {
|
||||
dispatch(unreblog(status));
|
||||
dispatch(unreblog({ statusId: status.get('id') }));
|
||||
} else {
|
||||
if (e.shiftKey || !boostModal) {
|
||||
this.onModalReblog(status);
|
||||
|
@ -346,9 +346,9 @@ class Status extends ImmutablePureComponent {
|
||||
const { dispatch } = this.props;
|
||||
|
||||
if (status.get('reblogged')) {
|
||||
dispatch(unreblog(status));
|
||||
dispatch(unreblog({ statusId: status.get('id') }));
|
||||
} else {
|
||||
dispatch(reblog(status, privacy));
|
||||
dispatch(reblog({ statusId: status.get('id'), visibility: privacy }));
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -3,10 +3,6 @@ import { Map as ImmutableMap, fromJS } from 'immutable';
|
||||
import { STATUS_IMPORT, STATUSES_IMPORT } from '../actions/importer';
|
||||
import { normalizeStatusTranslation } from '../actions/importer/normalizer';
|
||||
import {
|
||||
REBLOG_REQUEST,
|
||||
REBLOG_FAIL,
|
||||
UNREBLOG_REQUEST,
|
||||
UNREBLOG_FAIL,
|
||||
FAVOURITE_REQUEST,
|
||||
FAVOURITE_FAIL,
|
||||
UNFAVOURITE_REQUEST,
|
||||
@ -16,6 +12,10 @@ import {
|
||||
UNBOOKMARK_REQUEST,
|
||||
UNBOOKMARK_FAIL,
|
||||
} from '../actions/interactions';
|
||||
import {
|
||||
reblog,
|
||||
unreblog,
|
||||
} from '../actions/interactions_typed';
|
||||
import {
|
||||
STATUS_MUTE_SUCCESS,
|
||||
STATUS_UNMUTE_SUCCESS,
|
||||
@ -65,6 +65,7 @@ const statusTranslateUndo = (state, id) => {
|
||||
|
||||
const initialState = ImmutableMap();
|
||||
|
||||
/** @type {import('@reduxjs/toolkit').Reducer<typeof initialState>} */
|
||||
export default function statuses(state = initialState, action) {
|
||||
switch(action.type) {
|
||||
case STATUS_FETCH_REQUEST:
|
||||
@ -91,14 +92,6 @@ export default function statuses(state = initialState, action) {
|
||||
return state.get(action.status.get('id')) === undefined ? state : state.setIn([action.status.get('id'), 'bookmarked'], false);
|
||||
case UNBOOKMARK_FAIL:
|
||||
return state.get(action.status.get('id')) === undefined ? state : state.setIn([action.status.get('id'), 'bookmarked'], true);
|
||||
case REBLOG_REQUEST:
|
||||
return state.setIn([action.status.get('id'), 'reblogged'], true);
|
||||
case REBLOG_FAIL:
|
||||
return state.get(action.status.get('id')) === undefined ? state : state.setIn([action.status.get('id'), 'reblogged'], false);
|
||||
case UNREBLOG_REQUEST:
|
||||
return state.setIn([action.status.get('id'), 'reblogged'], false);
|
||||
case UNREBLOG_FAIL:
|
||||
return state.get(action.status.get('id')) === undefined ? state : state.setIn([action.status.get('id'), 'reblogged'], true);
|
||||
case STATUS_MUTE_SUCCESS:
|
||||
return state.setIn([action.id, 'muted'], true);
|
||||
case STATUS_UNMUTE_SUCCESS:
|
||||
@ -128,6 +121,15 @@ export default function statuses(state = initialState, action) {
|
||||
case STATUS_TRANSLATE_UNDO:
|
||||
return statusTranslateUndo(state, action.id);
|
||||
default:
|
||||
return state;
|
||||
if(reblog.pending.match(action))
|
||||
return state.setIn([action.meta.arg.statusId, 'reblogged'], true);
|
||||
else if(reblog.rejected.match(action))
|
||||
return state.get(action.meta.arg.statusId) === undefined ? state : state.setIn([action.meta.arg.statusId, 'reblogged'], false);
|
||||
else if(unreblog.pending.match(action))
|
||||
return state.setIn([action.meta.arg.statusId, 'reblogged'], false);
|
||||
else if(unreblog.rejected.match(action))
|
||||
return state.get(action.meta.arg.statusId) === undefined ? state : state.setIn([action.meta.arg.statusId, 'reblogged'], true);
|
||||
else
|
||||
return state;
|
||||
}
|
||||
}
|
||||
|
@ -2,6 +2,8 @@ import { createAsyncThunk } from '@reduxjs/toolkit';
|
||||
// eslint-disable-next-line @typescript-eslint/no-restricted-imports
|
||||
import { useDispatch, useSelector } from 'react-redux';
|
||||
|
||||
import type { BaseThunkAPI } from '@reduxjs/toolkit/dist/createAsyncThunk';
|
||||
|
||||
import type { AppDispatch, RootState } from './store';
|
||||
|
||||
export const useAppDispatch = useDispatch.withTypes<AppDispatch>();
|
||||
@ -13,8 +15,192 @@ export interface AsyncThunkRejectValue {
|
||||
error?: unknown;
|
||||
}
|
||||
|
||||
interface AppMeta {
|
||||
skipLoading?: boolean;
|
||||
}
|
||||
|
||||
export const createAppAsyncThunk = createAsyncThunk.withTypes<{
|
||||
state: RootState;
|
||||
dispatch: AppDispatch;
|
||||
rejectValue: AsyncThunkRejectValue;
|
||||
}>();
|
||||
|
||||
type AppThunkApi = Pick<
|
||||
BaseThunkAPI<
|
||||
RootState,
|
||||
unknown,
|
||||
AppDispatch,
|
||||
AsyncThunkRejectValue,
|
||||
AppMeta,
|
||||
AppMeta
|
||||
>,
|
||||
'getState' | 'dispatch'
|
||||
>;
|
||||
|
||||
interface AppThunkOptions {
|
||||
skipLoading?: boolean;
|
||||
}
|
||||
|
||||
const createBaseAsyncThunk = createAsyncThunk.withTypes<{
|
||||
state: RootState;
|
||||
dispatch: AppDispatch;
|
||||
rejectValue: AsyncThunkRejectValue;
|
||||
fulfilledMeta: AppMeta;
|
||||
rejectedMeta: AppMeta;
|
||||
}>();
|
||||
|
||||
export function createThunk<Arg = void, Returned = void>(
|
||||
name: string,
|
||||
creator: (arg: Arg, api: AppThunkApi) => Returned | Promise<Returned>,
|
||||
options: AppThunkOptions = {},
|
||||
) {
|
||||
return createBaseAsyncThunk(
|
||||
name,
|
||||
async (
|
||||
arg: Arg,
|
||||
{ getState, dispatch, fulfillWithValue, rejectWithValue },
|
||||
) => {
|
||||
try {
|
||||
const result = await creator(arg, { dispatch, getState });
|
||||
|
||||
return fulfillWithValue(result, {
|
||||
skipLoading: options.skipLoading,
|
||||
});
|
||||
} catch (error) {
|
||||
return rejectWithValue({ error }, { skipLoading: true });
|
||||
}
|
||||
},
|
||||
{
|
||||
getPendingMeta() {
|
||||
if (options.skipLoading) return { skipLoading: true };
|
||||
return {};
|
||||
},
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
const discardLoadDataInPayload = Symbol('discardLoadDataInPayload');
|
||||
type DiscardLoadData = typeof discardLoadDataInPayload;
|
||||
|
||||
type OnData<LoadDataResult, ReturnedData> = (
|
||||
data: LoadDataResult,
|
||||
api: AppThunkApi & {
|
||||
discardLoadData: DiscardLoadData;
|
||||
},
|
||||
) => ReturnedData | DiscardLoadData | Promise<ReturnedData | DiscardLoadData>;
|
||||
|
||||
// Overload when there is no `onData` method, the payload is the `onData` result
|
||||
export function createDataLoadingThunk<
|
||||
LoadDataResult,
|
||||
Args extends Record<string, unknown>,
|
||||
>(
|
||||
name: string,
|
||||
loadData: (args: Args) => Promise<LoadDataResult>,
|
||||
thunkOptions?: AppThunkOptions,
|
||||
): ReturnType<typeof createThunk<Args, LoadDataResult>>;
|
||||
|
||||
// Overload when the `onData` method returns discardLoadDataInPayload, then the payload is empty
|
||||
export function createDataLoadingThunk<
|
||||
LoadDataResult,
|
||||
Args extends Record<string, unknown>,
|
||||
>(
|
||||
name: string,
|
||||
loadData: (args: Args) => Promise<LoadDataResult>,
|
||||
onDataOrThunkOptions?:
|
||||
| AppThunkOptions
|
||||
| OnData<LoadDataResult, DiscardLoadData>,
|
||||
thunkOptions?: AppThunkOptions,
|
||||
): ReturnType<typeof createThunk<Args, void>>;
|
||||
|
||||
// Overload when the `onData` method returns nothing, then the mayload is the `onData` result
|
||||
export function createDataLoadingThunk<
|
||||
LoadDataResult,
|
||||
Args extends Record<string, unknown>,
|
||||
>(
|
||||
name: string,
|
||||
loadData: (args: Args) => Promise<LoadDataResult>,
|
||||
onDataOrThunkOptions?: AppThunkOptions | OnData<LoadDataResult, void>,
|
||||
thunkOptions?: AppThunkOptions,
|
||||
): ReturnType<typeof createThunk<Args, LoadDataResult>>;
|
||||
|
||||
// Overload when there is an `onData` method returning something
|
||||
export function createDataLoadingThunk<
|
||||
LoadDataResult,
|
||||
Args extends Record<string, unknown>,
|
||||
Returned,
|
||||
>(
|
||||
name: string,
|
||||
loadData: (args: Args) => Promise<LoadDataResult>,
|
||||
onDataOrThunkOptions?: AppThunkOptions | OnData<LoadDataResult, Returned>,
|
||||
thunkOptions?: AppThunkOptions,
|
||||
): ReturnType<typeof createThunk<Args, Returned>>;
|
||||
|
||||
/**
|
||||
* This function creates a Redux Thunk that handles loading data asynchronously (usually from the API), dispatching `pending`, `fullfilled` and `rejected` actions.
|
||||
*
|
||||
* You can run a callback on the `onData` results to either dispatch side effects or modify the payload.
|
||||
*
|
||||
* It is a wrapper around RTK's [`createAsyncThunk`](https://redux-toolkit.js.org/api/createAsyncThunk)
|
||||
* @param name Prefix for the actions types
|
||||
* @param loadData Function that loads the data. It's (object) argument will become the thunk's argument
|
||||
* @param onDataOrThunkOptions
|
||||
* Callback called on the results from `loadData`.
|
||||
*
|
||||
* First argument will be the return from `loadData`.
|
||||
*
|
||||
* Second argument is an object with: `dispatch`, `getState` and `discardLoadData`.
|
||||
* It can return:
|
||||
* - `undefined` (or no explicit return), meaning that the `onData` results will be the payload
|
||||
* - `discardLoadData` to discard the `onData` results and return an empty payload
|
||||
* - anything else, which will be the payload
|
||||
*
|
||||
* You can also omit this parameter and pass `thunkOptions` directly
|
||||
* @param maybeThunkOptions
|
||||
* Additional Mastodon specific options for the thunk. Currently supports:
|
||||
* - `skipLoading` to avoid showing the loading bar when the request is in progress
|
||||
* @returns The created thunk
|
||||
*/
|
||||
export function createDataLoadingThunk<
|
||||
LoadDataResult,
|
||||
Args extends Record<string, unknown>,
|
||||
Returned,
|
||||
>(
|
||||
name: string,
|
||||
loadData: (args: Args) => Promise<LoadDataResult>,
|
||||
onDataOrThunkOptions?: AppThunkOptions | OnData<LoadDataResult, Returned>,
|
||||
maybeThunkOptions?: AppThunkOptions,
|
||||
) {
|
||||
let onData: OnData<LoadDataResult, Returned> | undefined;
|
||||
let thunkOptions: AppThunkOptions | undefined;
|
||||
|
||||
if (typeof onDataOrThunkOptions === 'function') onData = onDataOrThunkOptions;
|
||||
else if (typeof onDataOrThunkOptions === 'object')
|
||||
thunkOptions = onDataOrThunkOptions;
|
||||
|
||||
if (maybeThunkOptions) {
|
||||
thunkOptions = maybeThunkOptions;
|
||||
}
|
||||
|
||||
return createThunk<Args, Returned>(
|
||||
name,
|
||||
async (arg, { getState, dispatch }) => {
|
||||
const data = await loadData(arg);
|
||||
|
||||
if (!onData) return data as Returned;
|
||||
|
||||
const result = await onData(data, {
|
||||
dispatch,
|
||||
getState,
|
||||
discardLoadData: discardLoadDataInPayload,
|
||||
});
|
||||
|
||||
// if there is no return in `onData`, we return the `onData` result
|
||||
if (typeof result === 'undefined') return data as Returned;
|
||||
// the user explicitely asked to discard the payload
|
||||
else if (result === discardLoadDataInPayload)
|
||||
return undefined as Returned;
|
||||
else return result;
|
||||
},
|
||||
thunkOptions,
|
||||
);
|
||||
}
|
||||
|
@ -1,18 +1,10 @@
|
||||
import type { ApiRelationshipJSON } from 'mastodon/api_types/relationships';
|
||||
import { createAppAsyncThunk } from 'mastodon/store/typed_functions';
|
||||
import { apiSubmitAccountNote } from 'mastodon/api/accounts';
|
||||
import { createDataLoadingThunk } from 'mastodon/store/typed_functions';
|
||||
|
||||
import api from '../api';
|
||||
|
||||
export const submitAccountNote = createAppAsyncThunk(
|
||||
export const submitAccountNote = createDataLoadingThunk(
|
||||
'account_note/submit',
|
||||
async (args: { id: string; value: string }) => {
|
||||
const response = await api().post<ApiRelationshipJSON>(
|
||||
`/api/v1/accounts/${args.id}/note`,
|
||||
{
|
||||
comment: args.value,
|
||||
},
|
||||
);
|
||||
|
||||
return { relationship: response.data };
|
||||
},
|
||||
({ accountId, note }: { accountId: string; note: string }) =>
|
||||
apiSubmitAccountNote(accountId, note),
|
||||
(relationship) => ({ relationship }),
|
||||
{ skipLoading: true },
|
||||
);
|
||||
|
@ -3,10 +3,6 @@ import api, { getLinks } from '../api';
|
||||
import { fetchRelationships } from './accounts';
|
||||
import { importFetchedAccounts, importFetchedStatus } from './importer';
|
||||
|
||||
export const REBLOG_REQUEST = 'REBLOG_REQUEST';
|
||||
export const REBLOG_SUCCESS = 'REBLOG_SUCCESS';
|
||||
export const REBLOG_FAIL = 'REBLOG_FAIL';
|
||||
|
||||
export const REBLOGS_EXPAND_REQUEST = 'REBLOGS_EXPAND_REQUEST';
|
||||
export const REBLOGS_EXPAND_SUCCESS = 'REBLOGS_EXPAND_SUCCESS';
|
||||
export const REBLOGS_EXPAND_FAIL = 'REBLOGS_EXPAND_FAIL';
|
||||
@ -15,10 +11,6 @@ export const FAVOURITE_REQUEST = 'FAVOURITE_REQUEST';
|
||||
export const FAVOURITE_SUCCESS = 'FAVOURITE_SUCCESS';
|
||||
export const FAVOURITE_FAIL = 'FAVOURITE_FAIL';
|
||||
|
||||
export const UNREBLOG_REQUEST = 'UNREBLOG_REQUEST';
|
||||
export const UNREBLOG_SUCCESS = 'UNREBLOG_SUCCESS';
|
||||
export const UNREBLOG_FAIL = 'UNREBLOG_FAIL';
|
||||
|
||||
export const UNFAVOURITE_REQUEST = 'UNFAVOURITE_REQUEST';
|
||||
export const UNFAVOURITE_SUCCESS = 'UNFAVOURITE_SUCCESS';
|
||||
export const UNFAVOURITE_FAIL = 'UNFAVOURITE_FAIL';
|
||||
@ -51,83 +43,7 @@ export const UNBOOKMARK_REQUEST = 'UNBOOKMARKED_REQUEST';
|
||||
export const UNBOOKMARK_SUCCESS = 'UNBOOKMARKED_SUCCESS';
|
||||
export const UNBOOKMARK_FAIL = 'UNBOOKMARKED_FAIL';
|
||||
|
||||
export function reblog(status, visibility) {
|
||||
return function (dispatch) {
|
||||
dispatch(reblogRequest(status));
|
||||
|
||||
api().post(`/api/v1/statuses/${status.get('id')}/reblog`, { visibility }).then(function (response) {
|
||||
// The reblog API method returns a new status wrapped around the original. In this case we are only
|
||||
// interested in how the original is modified, hence passing it skipping the wrapper
|
||||
dispatch(importFetchedStatus(response.data.reblog));
|
||||
dispatch(reblogSuccess(status));
|
||||
}).catch(function (error) {
|
||||
dispatch(reblogFail(status, error));
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
export function unreblog(status) {
|
||||
return (dispatch) => {
|
||||
dispatch(unreblogRequest(status));
|
||||
|
||||
api().post(`/api/v1/statuses/${status.get('id')}/unreblog`).then(response => {
|
||||
dispatch(importFetchedStatus(response.data));
|
||||
dispatch(unreblogSuccess(status));
|
||||
}).catch(error => {
|
||||
dispatch(unreblogFail(status, error));
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
export function reblogRequest(status) {
|
||||
return {
|
||||
type: REBLOG_REQUEST,
|
||||
status: status,
|
||||
skipLoading: true,
|
||||
};
|
||||
}
|
||||
|
||||
export function reblogSuccess(status) {
|
||||
return {
|
||||
type: REBLOG_SUCCESS,
|
||||
status: status,
|
||||
skipLoading: true,
|
||||
};
|
||||
}
|
||||
|
||||
export function reblogFail(status, error) {
|
||||
return {
|
||||
type: REBLOG_FAIL,
|
||||
status: status,
|
||||
error: error,
|
||||
skipLoading: true,
|
||||
};
|
||||
}
|
||||
|
||||
export function unreblogRequest(status) {
|
||||
return {
|
||||
type: UNREBLOG_REQUEST,
|
||||
status: status,
|
||||
skipLoading: true,
|
||||
};
|
||||
}
|
||||
|
||||
export function unreblogSuccess(status) {
|
||||
return {
|
||||
type: UNREBLOG_SUCCESS,
|
||||
status: status,
|
||||
skipLoading: true,
|
||||
};
|
||||
}
|
||||
|
||||
export function unreblogFail(status, error) {
|
||||
return {
|
||||
type: UNREBLOG_FAIL,
|
||||
status: status,
|
||||
error: error,
|
||||
skipLoading: true,
|
||||
};
|
||||
}
|
||||
export * from "./interactions_typed";
|
||||
|
||||
export function favourite(status) {
|
||||
return function (dispatch) {
|
||||
|
35
app/javascript/mastodon/actions/interactions_typed.ts
Normal file
35
app/javascript/mastodon/actions/interactions_typed.ts
Normal file
@ -0,0 +1,35 @@
|
||||
import { apiReblog, apiUnreblog } from 'mastodon/api/interactions';
|
||||
import type { StatusVisibility } from 'mastodon/models/status';
|
||||
import { createDataLoadingThunk } from 'mastodon/store/typed_functions';
|
||||
|
||||
import { importFetchedStatus } from './importer';
|
||||
|
||||
export const reblog = createDataLoadingThunk(
|
||||
'status/reblog',
|
||||
({
|
||||
statusId,
|
||||
visibility,
|
||||
}: {
|
||||
statusId: string;
|
||||
visibility: StatusVisibility;
|
||||
}) => apiReblog(statusId, visibility),
|
||||
(data, { dispatch, discardLoadData }) => {
|
||||
// The reblog API method returns a new status wrapped around the original. In this case we are only
|
||||
// interested in how the original is modified, hence passing it skipping the wrapper
|
||||
dispatch(importFetchedStatus(data.reblog));
|
||||
|
||||
// The payload is not used in any actions
|
||||
return discardLoadData;
|
||||
},
|
||||
);
|
||||
|
||||
export const unreblog = createDataLoadingThunk(
|
||||
'status/unreblog',
|
||||
({ statusId }: { statusId: string }) => apiUnreblog(statusId),
|
||||
(data, { dispatch, discardLoadData }) => {
|
||||
dispatch(importFetchedStatus(data));
|
||||
|
||||
// The payload is not used in any actions
|
||||
return discardLoadData;
|
||||
},
|
||||
);
|
@ -1,4 +1,4 @@
|
||||
import type { AxiosResponse, RawAxiosRequestHeaders } from 'axios';
|
||||
import type { AxiosResponse, Method, RawAxiosRequestHeaders } from 'axios';
|
||||
import axios from 'axios';
|
||||
import LinkHeader from 'http-link-header';
|
||||
|
||||
@ -40,11 +40,11 @@ const authorizationTokenFromInitialState = (): RawAxiosRequestHeaders => {
|
||||
};
|
||||
|
||||
// eslint-disable-next-line import/no-default-export
|
||||
export default function api() {
|
||||
export default function api(withAuthorization = true) {
|
||||
return axios.create({
|
||||
headers: {
|
||||
...csrfHeader,
|
||||
...authorizationTokenFromInitialState(),
|
||||
...(withAuthorization ? authorizationTokenFromInitialState() : {}),
|
||||
},
|
||||
|
||||
transformResponse: [
|
||||
@ -58,3 +58,17 @@ export default function api() {
|
||||
],
|
||||
});
|
||||
}
|
||||
|
||||
export async function apiRequest<ApiResponse = unknown>(
|
||||
method: Method,
|
||||
url: string,
|
||||
params?: Record<string, unknown>,
|
||||
) {
|
||||
const { data } = await api().request<ApiResponse>({
|
||||
method,
|
||||
url: '/api/' + url,
|
||||
data: params,
|
||||
});
|
||||
|
||||
return data;
|
||||
}
|
||||
|
7
app/javascript/mastodon/api/accounts.ts
Normal file
7
app/javascript/mastodon/api/accounts.ts
Normal file
@ -0,0 +1,7 @@
|
||||
import { apiRequest } from 'mastodon/api';
|
||||
import type { ApiRelationshipJSON } from 'mastodon/api_types/relationships';
|
||||
|
||||
export const apiSubmitAccountNote = (id: string, value: string) =>
|
||||
apiRequest<ApiRelationshipJSON>('post', `v1/accounts/${id}/note`, {
|
||||
comment: value,
|
||||
});
|
10
app/javascript/mastodon/api/interactions.ts
Normal file
10
app/javascript/mastodon/api/interactions.ts
Normal file
@ -0,0 +1,10 @@
|
||||
import { apiRequest } from 'mastodon/api';
|
||||
import type { Status, StatusVisibility } from 'mastodon/models/status';
|
||||
|
||||
export const apiReblog = (statusId: string, visibility: StatusVisibility) =>
|
||||
apiRequest<{ reblog: Status }>('post', `v1/statuses/${statusId}/reblog`, {
|
||||
visibility,
|
||||
});
|
||||
|
||||
export const apiUnreblog = (statusId: string) =>
|
||||
apiRequest<Status>('post', `v1/statuses/${statusId}/unreblog`);
|
@ -48,7 +48,7 @@ export default class Counter extends PureComponent {
|
||||
componentDidMount () {
|
||||
const { measure, start_at, end_at, params } = this.props;
|
||||
|
||||
api().post('/api/v1/admin/measures', { keys: [measure], start_at, end_at, [measure]: params }).then(res => {
|
||||
api(false).post('/api/v1/admin/measures', { keys: [measure], start_at, end_at, [measure]: params }).then(res => {
|
||||
this.setState({
|
||||
loading: false,
|
||||
data: res.data,
|
||||
|
@ -26,7 +26,7 @@ export default class Dimension extends PureComponent {
|
||||
componentDidMount () {
|
||||
const { start_at, end_at, dimension, limit, params } = this.props;
|
||||
|
||||
api().post('/api/v1/admin/dimensions', { keys: [dimension], start_at, end_at, limit, [dimension]: params }).then(res => {
|
||||
api(false).post('/api/v1/admin/dimensions', { keys: [dimension], start_at, end_at, limit, [dimension]: params }).then(res => {
|
||||
this.setState({
|
||||
loading: false,
|
||||
data: res.data,
|
||||
|
@ -27,7 +27,7 @@ export default class ImpactReport extends PureComponent {
|
||||
include_subdomains: true,
|
||||
};
|
||||
|
||||
api().post('/api/v1/admin/measures', {
|
||||
api(false).post('/api/v1/admin/measures', {
|
||||
keys: ['instance_accounts', 'instance_follows', 'instance_followers'],
|
||||
start_at: null,
|
||||
end_at: null,
|
||||
|
@ -105,7 +105,7 @@ class ReportReasonSelector extends PureComponent {
|
||||
};
|
||||
|
||||
componentDidMount() {
|
||||
api().get('/api/v1/instance').then(res => {
|
||||
api(false).get('/api/v1/instance').then(res => {
|
||||
this.setState({
|
||||
rules: res.data.rules,
|
||||
});
|
||||
@ -122,7 +122,7 @@ class ReportReasonSelector extends PureComponent {
|
||||
return;
|
||||
}
|
||||
|
||||
api().put(`/api/v1/admin/reports/${id}`, {
|
||||
api(false).put(`/api/v1/admin/reports/${id}`, {
|
||||
category,
|
||||
rule_ids: category === 'violation' ? rule_ids : [],
|
||||
}).catch(err => {
|
||||
|
@ -34,7 +34,7 @@ export default class Retention extends PureComponent {
|
||||
componentDidMount () {
|
||||
const { start_at, end_at, frequency } = this.props;
|
||||
|
||||
api().post('/api/v1/admin/retention', { start_at, end_at, frequency }).then(res => {
|
||||
api(false).post('/api/v1/admin/retention', { start_at, end_at, frequency }).then(res => {
|
||||
this.setState({
|
||||
loading: false,
|
||||
data: res.data,
|
||||
|
@ -22,7 +22,7 @@ export default class Trends extends PureComponent {
|
||||
componentDidMount () {
|
||||
const { limit } = this.props;
|
||||
|
||||
api().get('/api/v1/admin/trends/tags', { params: { limit } }).then(res => {
|
||||
api(false).get('/api/v1/admin/trends/tags', { params: { limit } }).then(res => {
|
||||
this.setState({
|
||||
loading: false,
|
||||
data: res.data,
|
||||
|
@ -96,9 +96,9 @@ const mapDispatchToProps = (dispatch, { intl, contextType }) => ({
|
||||
|
||||
onModalReblog (status, privacy) {
|
||||
if (status.get('reblogged')) {
|
||||
dispatch(unreblog(status));
|
||||
dispatch(unreblog({ statusId: status.get('id') }));
|
||||
} else {
|
||||
dispatch(reblog(status, privacy));
|
||||
dispatch(reblog({ statusId: status.get('id'), visibility: privacy }));
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -11,7 +11,7 @@ const mapStateToProps = (state, { account }) => ({
|
||||
const mapDispatchToProps = (dispatch, { account }) => ({
|
||||
|
||||
onSave (value) {
|
||||
dispatch(submitAccountNote({ id: account.get('id'), value}));
|
||||
dispatch(submitAccountNote({ accountId: account.get('id'), note: value }));
|
||||
},
|
||||
|
||||
});
|
||||
|
@ -39,12 +39,12 @@ const mapDispatchToProps = dispatch => ({
|
||||
},
|
||||
|
||||
onModalReblog (status, privacy) {
|
||||
dispatch(reblog(status, privacy));
|
||||
dispatch(reblog({ statusId: status.get('id'), visibility: privacy }));
|
||||
},
|
||||
|
||||
onReblog (status, e) {
|
||||
if (status.get('reblogged')) {
|
||||
dispatch(unreblog(status));
|
||||
dispatch(unreblog({ statusId: status.get('id') }));
|
||||
} else {
|
||||
if (e.shiftKey || !boostModal) {
|
||||
this.onModalReblog(status);
|
||||
|
@ -123,7 +123,7 @@ class Footer extends ImmutablePureComponent {
|
||||
|
||||
_performReblog = (status, privacy) => {
|
||||
const { dispatch } = this.props;
|
||||
dispatch(reblog(status, privacy));
|
||||
dispatch(reblog({ statusId: status.get('id'), visibility: privacy }));
|
||||
};
|
||||
|
||||
handleReblogClick = e => {
|
||||
@ -132,7 +132,7 @@ class Footer extends ImmutablePureComponent {
|
||||
|
||||
if (signedIn) {
|
||||
if (status.get('reblogged')) {
|
||||
dispatch(unreblog(status));
|
||||
dispatch(unreblog({ statusId: status.get('id') }));
|
||||
} else if ((e && e.shiftKey) || !boostModal) {
|
||||
this._performReblog(status);
|
||||
} else {
|
||||
|
@ -74,12 +74,12 @@ const mapDispatchToProps = (dispatch, { intl }) => ({
|
||||
},
|
||||
|
||||
onModalReblog (status, privacy) {
|
||||
dispatch(reblog(status, privacy));
|
||||
dispatch(reblog({ statusId: status.get('id'), visibility: privacy }));
|
||||
},
|
||||
|
||||
onReblog (status, e) {
|
||||
if (status.get('reblogged')) {
|
||||
dispatch(unreblog(status));
|
||||
dispatch(unreblog({ statusId: status.get('id') }));
|
||||
} else {
|
||||
if (e.shiftKey || !boostModal) {
|
||||
this.onModalReblog(status);
|
||||
|
@ -299,7 +299,7 @@ class Status extends ImmutablePureComponent {
|
||||
};
|
||||
|
||||
handleModalReblog = (status, privacy) => {
|
||||
this.props.dispatch(reblog(status, privacy));
|
||||
this.props.dispatch(reblog({ statusId: status.get('id'), visibility: privacy }));
|
||||
};
|
||||
|
||||
handleReblogClick = (status, e) => {
|
||||
@ -308,7 +308,7 @@ class Status extends ImmutablePureComponent {
|
||||
|
||||
if (signedIn) {
|
||||
if (status.get('reblogged')) {
|
||||
dispatch(unreblog(status));
|
||||
dispatch(unreblog({ statusId: status.get('id') }));
|
||||
} else {
|
||||
if ((e && e.shiftKey) || !boostModal) {
|
||||
this.handleModalReblog(status);
|
||||
|
@ -469,6 +469,7 @@
|
||||
"notification.follow": "{name} падпісаўся на вас",
|
||||
"notification.follow_request": "{name} адправіў запыт на падпіску",
|
||||
"notification.mention": "{name} згадаў вас",
|
||||
"notification.moderation-warning.learn_more": "Даведацца больш",
|
||||
"notification.own_poll": "Ваша апытанне скончылася",
|
||||
"notification.poll": "Апытанне, дзе вы прынялі ўдзел, скончылася",
|
||||
"notification.reblog": "{name} пашырыў ваш допіс",
|
||||
|
@ -491,7 +491,7 @@
|
||||
"onboarding.actions.go_to_home": "Dodieties uz manu mājas plūsmu",
|
||||
"onboarding.compose.template": "Sveiki, #Mastodon!",
|
||||
"onboarding.follows.empty": "Diemžēl pašlaik nevar parādīt rezultātus. Vari mēģināt izmantot meklēšanu vai pārlūkot izpētes lapu, lai atrastu cilvēkus, kuriem sekot, vai vēlāk mēģināt vēlreiz.",
|
||||
"onboarding.follows.lead": "Tava mājas plūsma ir galvenais veids, kā izbaudīt Mastodon. Jo vairāk cilvēku sekosi, jo aktīvāk un interesantāk tas būs. Lai sāktu, šeit ir daži ieteikumi:",
|
||||
"onboarding.follows.lead": "Tava mājas plūsma ir galvenais veids, kā pieredzēt Mastodon. Jo vairāk cilvēkiem sekosi, jo dzīvīgāka un aizraujošāka tā būs. Lai sāktu, šeit ir daži ieteikumi:",
|
||||
"onboarding.follows.title": "Pielāgo savu mājas barotni",
|
||||
"onboarding.profile.discoverable": "Padarīt manu profilu atklājamu",
|
||||
"onboarding.profile.display_name": "Attēlojamais vārds",
|
||||
|
@ -3,10 +3,6 @@ import { Map as ImmutableMap, fromJS } from 'immutable';
|
||||
import { STATUS_IMPORT, STATUSES_IMPORT } from '../actions/importer';
|
||||
import { normalizeStatusTranslation } from '../actions/importer/normalizer';
|
||||
import {
|
||||
REBLOG_REQUEST,
|
||||
REBLOG_FAIL,
|
||||
UNREBLOG_REQUEST,
|
||||
UNREBLOG_FAIL,
|
||||
FAVOURITE_REQUEST,
|
||||
FAVOURITE_FAIL,
|
||||
UNFAVOURITE_REQUEST,
|
||||
@ -16,6 +12,10 @@ import {
|
||||
UNBOOKMARK_REQUEST,
|
||||
UNBOOKMARK_FAIL,
|
||||
} from '../actions/interactions';
|
||||
import {
|
||||
reblog,
|
||||
unreblog,
|
||||
} from '../actions/interactions_typed';
|
||||
import {
|
||||
STATUS_MUTE_SUCCESS,
|
||||
STATUS_UNMUTE_SUCCESS,
|
||||
@ -65,6 +65,7 @@ const statusTranslateUndo = (state, id) => {
|
||||
|
||||
const initialState = ImmutableMap();
|
||||
|
||||
/** @type {import('@reduxjs/toolkit').Reducer<typeof initialState>} */
|
||||
export default function statuses(state = initialState, action) {
|
||||
switch(action.type) {
|
||||
case STATUS_FETCH_REQUEST:
|
||||
@ -91,14 +92,6 @@ export default function statuses(state = initialState, action) {
|
||||
return state.get(action.status.get('id')) === undefined ? state : state.setIn([action.status.get('id'), 'bookmarked'], false);
|
||||
case UNBOOKMARK_FAIL:
|
||||
return state.get(action.status.get('id')) === undefined ? state : state.setIn([action.status.get('id'), 'bookmarked'], true);
|
||||
case REBLOG_REQUEST:
|
||||
return state.setIn([action.status.get('id'), 'reblogged'], true);
|
||||
case REBLOG_FAIL:
|
||||
return state.get(action.status.get('id')) === undefined ? state : state.setIn([action.status.get('id'), 'reblogged'], false);
|
||||
case UNREBLOG_REQUEST:
|
||||
return state.setIn([action.status.get('id'), 'reblogged'], false);
|
||||
case UNREBLOG_FAIL:
|
||||
return state.get(action.status.get('id')) === undefined ? state : state.setIn([action.status.get('id'), 'reblogged'], true);
|
||||
case STATUS_MUTE_SUCCESS:
|
||||
return state.setIn([action.id, 'muted'], true);
|
||||
case STATUS_UNMUTE_SUCCESS:
|
||||
@ -128,6 +121,15 @@ export default function statuses(state = initialState, action) {
|
||||
case STATUS_TRANSLATE_UNDO:
|
||||
return statusTranslateUndo(state, action.id);
|
||||
default:
|
||||
return state;
|
||||
if(reblog.pending.match(action))
|
||||
return state.setIn([action.meta.arg.statusId, 'reblogged'], true);
|
||||
else if(reblog.rejected.match(action))
|
||||
return state.get(action.meta.arg.statusId) === undefined ? state : state.setIn([action.meta.arg.statusId, 'reblogged'], false);
|
||||
else if(unreblog.pending.match(action))
|
||||
return state.setIn([action.meta.arg.statusId, 'reblogged'], false);
|
||||
else if(unreblog.rejected.match(action))
|
||||
return state.get(action.meta.arg.statusId) === undefined ? state : state.setIn([action.meta.arg.statusId, 'reblogged'], true);
|
||||
else
|
||||
return state;
|
||||
}
|
||||
}
|
||||
|
@ -2,6 +2,8 @@ import { createAsyncThunk } from '@reduxjs/toolkit';
|
||||
// eslint-disable-next-line @typescript-eslint/no-restricted-imports
|
||||
import { useDispatch, useSelector } from 'react-redux';
|
||||
|
||||
import type { BaseThunkAPI } from '@reduxjs/toolkit/dist/createAsyncThunk';
|
||||
|
||||
import type { AppDispatch, RootState } from './store';
|
||||
|
||||
export const useAppDispatch = useDispatch.withTypes<AppDispatch>();
|
||||
@ -13,8 +15,192 @@ export interface AsyncThunkRejectValue {
|
||||
error?: unknown;
|
||||
}
|
||||
|
||||
interface AppMeta {
|
||||
skipLoading?: boolean;
|
||||
}
|
||||
|
||||
export const createAppAsyncThunk = createAsyncThunk.withTypes<{
|
||||
state: RootState;
|
||||
dispatch: AppDispatch;
|
||||
rejectValue: AsyncThunkRejectValue;
|
||||
}>();
|
||||
|
||||
type AppThunkApi = Pick<
|
||||
BaseThunkAPI<
|
||||
RootState,
|
||||
unknown,
|
||||
AppDispatch,
|
||||
AsyncThunkRejectValue,
|
||||
AppMeta,
|
||||
AppMeta
|
||||
>,
|
||||
'getState' | 'dispatch'
|
||||
>;
|
||||
|
||||
interface AppThunkOptions {
|
||||
skipLoading?: boolean;
|
||||
}
|
||||
|
||||
const createBaseAsyncThunk = createAsyncThunk.withTypes<{
|
||||
state: RootState;
|
||||
dispatch: AppDispatch;
|
||||
rejectValue: AsyncThunkRejectValue;
|
||||
fulfilledMeta: AppMeta;
|
||||
rejectedMeta: AppMeta;
|
||||
}>();
|
||||
|
||||
export function createThunk<Arg = void, Returned = void>(
|
||||
name: string,
|
||||
creator: (arg: Arg, api: AppThunkApi) => Returned | Promise<Returned>,
|
||||
options: AppThunkOptions = {},
|
||||
) {
|
||||
return createBaseAsyncThunk(
|
||||
name,
|
||||
async (
|
||||
arg: Arg,
|
||||
{ getState, dispatch, fulfillWithValue, rejectWithValue },
|
||||
) => {
|
||||
try {
|
||||
const result = await creator(arg, { dispatch, getState });
|
||||
|
||||
return fulfillWithValue(result, {
|
||||
skipLoading: options.skipLoading,
|
||||
});
|
||||
} catch (error) {
|
||||
return rejectWithValue({ error }, { skipLoading: true });
|
||||
}
|
||||
},
|
||||
{
|
||||
getPendingMeta() {
|
||||
if (options.skipLoading) return { skipLoading: true };
|
||||
return {};
|
||||
},
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
const discardLoadDataInPayload = Symbol('discardLoadDataInPayload');
|
||||
type DiscardLoadData = typeof discardLoadDataInPayload;
|
||||
|
||||
type OnData<LoadDataResult, ReturnedData> = (
|
||||
data: LoadDataResult,
|
||||
api: AppThunkApi & {
|
||||
discardLoadData: DiscardLoadData;
|
||||
},
|
||||
) => ReturnedData | DiscardLoadData | Promise<ReturnedData | DiscardLoadData>;
|
||||
|
||||
// Overload when there is no `onData` method, the payload is the `onData` result
|
||||
export function createDataLoadingThunk<
|
||||
LoadDataResult,
|
||||
Args extends Record<string, unknown>,
|
||||
>(
|
||||
name: string,
|
||||
loadData: (args: Args) => Promise<LoadDataResult>,
|
||||
thunkOptions?: AppThunkOptions,
|
||||
): ReturnType<typeof createThunk<Args, LoadDataResult>>;
|
||||
|
||||
// Overload when the `onData` method returns discardLoadDataInPayload, then the payload is empty
|
||||
export function createDataLoadingThunk<
|
||||
LoadDataResult,
|
||||
Args extends Record<string, unknown>,
|
||||
>(
|
||||
name: string,
|
||||
loadData: (args: Args) => Promise<LoadDataResult>,
|
||||
onDataOrThunkOptions?:
|
||||
| AppThunkOptions
|
||||
| OnData<LoadDataResult, DiscardLoadData>,
|
||||
thunkOptions?: AppThunkOptions,
|
||||
): ReturnType<typeof createThunk<Args, void>>;
|
||||
|
||||
// Overload when the `onData` method returns nothing, then the mayload is the `onData` result
|
||||
export function createDataLoadingThunk<
|
||||
LoadDataResult,
|
||||
Args extends Record<string, unknown>,
|
||||
>(
|
||||
name: string,
|
||||
loadData: (args: Args) => Promise<LoadDataResult>,
|
||||
onDataOrThunkOptions?: AppThunkOptions | OnData<LoadDataResult, void>,
|
||||
thunkOptions?: AppThunkOptions,
|
||||
): ReturnType<typeof createThunk<Args, LoadDataResult>>;
|
||||
|
||||
// Overload when there is an `onData` method returning something
|
||||
export function createDataLoadingThunk<
|
||||
LoadDataResult,
|
||||
Args extends Record<string, unknown>,
|
||||
Returned,
|
||||
>(
|
||||
name: string,
|
||||
loadData: (args: Args) => Promise<LoadDataResult>,
|
||||
onDataOrThunkOptions?: AppThunkOptions | OnData<LoadDataResult, Returned>,
|
||||
thunkOptions?: AppThunkOptions,
|
||||
): ReturnType<typeof createThunk<Args, Returned>>;
|
||||
|
||||
/**
|
||||
* This function creates a Redux Thunk that handles loading data asynchronously (usually from the API), dispatching `pending`, `fullfilled` and `rejected` actions.
|
||||
*
|
||||
* You can run a callback on the `onData` results to either dispatch side effects or modify the payload.
|
||||
*
|
||||
* It is a wrapper around RTK's [`createAsyncThunk`](https://redux-toolkit.js.org/api/createAsyncThunk)
|
||||
* @param name Prefix for the actions types
|
||||
* @param loadData Function that loads the data. It's (object) argument will become the thunk's argument
|
||||
* @param onDataOrThunkOptions
|
||||
* Callback called on the results from `loadData`.
|
||||
*
|
||||
* First argument will be the return from `loadData`.
|
||||
*
|
||||
* Second argument is an object with: `dispatch`, `getState` and `discardLoadData`.
|
||||
* It can return:
|
||||
* - `undefined` (or no explicit return), meaning that the `onData` results will be the payload
|
||||
* - `discardLoadData` to discard the `onData` results and return an empty payload
|
||||
* - anything else, which will be the payload
|
||||
*
|
||||
* You can also omit this parameter and pass `thunkOptions` directly
|
||||
* @param maybeThunkOptions
|
||||
* Additional Mastodon specific options for the thunk. Currently supports:
|
||||
* - `skipLoading` to avoid showing the loading bar when the request is in progress
|
||||
* @returns The created thunk
|
||||
*/
|
||||
export function createDataLoadingThunk<
|
||||
LoadDataResult,
|
||||
Args extends Record<string, unknown>,
|
||||
Returned,
|
||||
>(
|
||||
name: string,
|
||||
loadData: (args: Args) => Promise<LoadDataResult>,
|
||||
onDataOrThunkOptions?: AppThunkOptions | OnData<LoadDataResult, Returned>,
|
||||
maybeThunkOptions?: AppThunkOptions,
|
||||
) {
|
||||
let onData: OnData<LoadDataResult, Returned> | undefined;
|
||||
let thunkOptions: AppThunkOptions | undefined;
|
||||
|
||||
if (typeof onDataOrThunkOptions === 'function') onData = onDataOrThunkOptions;
|
||||
else if (typeof onDataOrThunkOptions === 'object')
|
||||
thunkOptions = onDataOrThunkOptions;
|
||||
|
||||
if (maybeThunkOptions) {
|
||||
thunkOptions = maybeThunkOptions;
|
||||
}
|
||||
|
||||
return createThunk<Args, Returned>(
|
||||
name,
|
||||
async (arg, { getState, dispatch }) => {
|
||||
const data = await loadData(arg);
|
||||
|
||||
if (!onData) return data as Returned;
|
||||
|
||||
const result = await onData(data, {
|
||||
dispatch,
|
||||
getState,
|
||||
discardLoadData: discardLoadDataInPayload,
|
||||
});
|
||||
|
||||
// if there is no return in `onData`, we return the `onData` result
|
||||
if (typeof result === 'undefined') return data as Returned;
|
||||
// the user explicitely asked to discard the payload
|
||||
else if (result === discardLoadDataInPayload)
|
||||
return undefined as Returned;
|
||||
else return result;
|
||||
},
|
||||
thunkOptions,
|
||||
);
|
||||
}
|
||||
|
@ -3,6 +3,8 @@
|
||||
class ActivityPub::Parser::StatusParser
|
||||
include JsonLdHelper
|
||||
|
||||
NORMALIZED_LOCALE_NAMES = LanguagesHelper::SUPPORTED_LOCALES.keys.index_by(&:downcase).freeze
|
||||
|
||||
# @param [Hash] json
|
||||
# @param [Hash] options
|
||||
# @option options [String] :followers_collection
|
||||
@ -89,6 +91,13 @@ class ActivityPub::Parser::StatusParser
|
||||
end
|
||||
|
||||
def language
|
||||
lang = raw_language_code
|
||||
lang.presence && NORMALIZED_LOCALE_NAMES.fetch(lang.downcase.to_sym, lang)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def raw_language_code
|
||||
if content_language_map?
|
||||
@object['contentMap'].keys.first
|
||||
elsif name_language_map?
|
||||
@ -102,8 +111,6 @@ class ActivityPub::Parser::StatusParser
|
||||
@object['directMessage']
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def audience_to
|
||||
as_array(@object['to'] || @json['to']).map { |x| value_or_id(x) }
|
||||
end
|
||||
|
@ -852,7 +852,6 @@ an:
|
||||
delete: Borrar
|
||||
edit_preset: Editar aviso predeterminau
|
||||
empty: Encara no has definiu garra preajuste d'alvertencia.
|
||||
title: Editar configuración predeterminada d'avisos
|
||||
webhooks:
|
||||
add_new: Anyadir endpoint
|
||||
delete: Eliminar
|
||||
|
@ -1013,7 +1013,6 @@ ar:
|
||||
delete: حذف
|
||||
edit_preset: تعديل نموذج التحذير
|
||||
empty: لم تحدد أي إعدادات تحذير مسبقة بعد.
|
||||
title: إدارة نماذج التحذير
|
||||
webhooks:
|
||||
add_new: إضافة نقطة نهاية
|
||||
delete: حذف
|
||||
|
@ -400,8 +400,6 @@ ast:
|
||||
usable: Pue usase
|
||||
title: Tendencies
|
||||
trending: En tendencia
|
||||
warning_presets:
|
||||
title: Xestión d'alvertencies preconfiguraes
|
||||
webhooks:
|
||||
add_new: Amestar un estremu
|
||||
delete: Desaniciar
|
||||
|
@ -983,7 +983,6 @@ be:
|
||||
delete: Выдаліць
|
||||
edit_preset: Рэдагаваць шаблон папярэджання
|
||||
empty: Вы яшчэ не вызначылі ніякіх шаблонаў папярэджанняў.
|
||||
title: Кіраванне шаблонамі папярэджанняў
|
||||
webhooks:
|
||||
add_new: Дадаць канцавую кропку
|
||||
delete: Выдаліць
|
||||
|
@ -951,7 +951,7 @@ bg:
|
||||
delete: Изтриване
|
||||
edit_preset: Редакция на предварителните настройки
|
||||
empty: Все още няма предварителни настройки за предупрежденията.
|
||||
title: Управление на предварителните настройки
|
||||
title: Предупредителни образци
|
||||
webhooks:
|
||||
add_new: Добавяне на крайна точка
|
||||
delete: Изтриване
|
||||
|
@ -951,7 +951,7 @@ ca:
|
||||
delete: Elimina
|
||||
edit_preset: Edita l'avís predeterminat
|
||||
empty: Encara no has definit cap preavís.
|
||||
title: Gestiona les configuracions predefinides dels avisos
|
||||
title: Predefinicions d'avís
|
||||
webhooks:
|
||||
add_new: Afegir extrem
|
||||
delete: Elimina
|
||||
|
@ -548,7 +548,6 @@ ckb:
|
||||
add_new: زیادکردنی نوێ
|
||||
delete: سڕینەوە
|
||||
edit_preset: دەستکاریکردنی ئاگاداری پێشگریمان
|
||||
title: بەڕێوەبردنی ئاگادارکردنەوە پێشسازدان
|
||||
admin_mailer:
|
||||
new_pending_account:
|
||||
body: وردەکاریهەژمارە نوێیەکە لە خوارەوەیە. دەتوانیت ئەم نەرمەکالا پەسەند بکەیت یان ڕەت بکەیتەوە.
|
||||
|
@ -510,7 +510,6 @@ co:
|
||||
add_new: Aghjunghje
|
||||
delete: Sguassà
|
||||
edit_preset: Cambià a preselezzione d'avertimentu
|
||||
title: Amministrà e preselezzione d'avertimentu
|
||||
admin_mailer:
|
||||
new_pending_account:
|
||||
body: I ditagli di u novu contu sò quì sottu. Pudete appruvà o righjittà a dumanda.
|
||||
|
@ -984,7 +984,6 @@ cs:
|
||||
delete: Smazat
|
||||
edit_preset: Upravit předlohu pro varování
|
||||
empty: Zatím jste nedefinovali žádné předlohy varování.
|
||||
title: Spravovat předlohy pro varování
|
||||
webhooks:
|
||||
add_new: Přidat koncový bod
|
||||
delete: Smazat
|
||||
|
@ -297,6 +297,7 @@ cy:
|
||||
update_custom_emoji_html: Mae %{name} wedi diweddaru emoji %{target}
|
||||
update_domain_block_html: Mae %{name} wedi diweddaru bloc parth %{target}
|
||||
update_ip_block_html: Mae %{name} wedi newid rheol IP %{target}
|
||||
update_report_html: Mae %{name} wedi diweddaru adroddiad %{target}
|
||||
update_status_html: Mae %{name} wedi diweddaru postiad gan %{target}
|
||||
update_user_role_html: Mae %{name} wedi newid rôl %{target}
|
||||
deleted_account: cyfrif wedi'i ddileu
|
||||
@ -1018,7 +1019,7 @@ cy:
|
||||
delete: Dileu
|
||||
edit_preset: Golygu rhagosodiad rhybudd
|
||||
empty: Nid ydych wedi diffinio unrhyw ragosodiadau rhybudd eto.
|
||||
title: Rheoli rhagosodiadau rhybudd
|
||||
title: Rhagosodiadau rhybuddion
|
||||
webhooks:
|
||||
add_new: Ychwanegu diweddbwynt
|
||||
delete: Dileu
|
||||
|
@ -951,7 +951,7 @@ da:
|
||||
delete: Slet
|
||||
edit_preset: Redigér advarselsforvalg
|
||||
empty: Ingen advarselsforvalg defineret endnu.
|
||||
title: Håndtérr advarselsforvalg
|
||||
title: Præindstillinger for advarsel
|
||||
webhooks:
|
||||
add_new: Tilføj endepunkt
|
||||
delete: Slet
|
||||
|
@ -951,7 +951,7 @@ de:
|
||||
delete: Löschen
|
||||
edit_preset: Warnvorlage bearbeiten
|
||||
empty: Du hast noch keine Warnvorlagen hinzugefügt.
|
||||
title: Warnvorlagen verwalten
|
||||
title: Warnvorlagen
|
||||
webhooks:
|
||||
add_new: Endpunkt hinzufügen
|
||||
delete: Löschen
|
||||
|
@ -22,7 +22,7 @@ lt:
|
||||
action: Patvirtinti el. pašto adresą
|
||||
action_with_app: Patvirtinti ir grįžti į %{app}
|
||||
explanation: Šiuo el. pašto adresu sukūrei paskyrą %{host}. Iki jos aktyvavimo liko vienas paspaudimas. Jei tai buvo ne tu, ignoruok šį el. laišką.
|
||||
explanation_when_pending: Šiuo el. pašto adresu pateikei paraišką pakvietimui į %{host}. Kai patvirtinsi savo el. pašto adresą, mes peržiūrėsime tavo paraišką. Gali prisijungti ir pakeisti savo duomenis arba ištrinti paskyrą, tačiau negalėsi naudotis daugeliu funkcijų, kol tavo paskyra nebus patvirtinta. Jei tavo paraiška bus atmesta, duomenys bus pašalinti, todėl jokių papildomų veiksmų iš tavęs nereikės. Jei tai buvo ne tu, ignoruok šį el. laišką.
|
||||
explanation_when_pending: Šiuo el. pašto adresu pateikei paraišką pakvietimui į %{host}. Kai patvirtinsi savo el. pašto adresą, mes peržiūrėsime tavo paraišką. Gali prisijungti ir pakeisti savo duomenis arba ištrinti paskyrą, bet negalėsi naudotis daugeliu funkcijų, kol tavo paskyra nebus patvirtinta. Jei tavo paraiška bus atmesta, duomenys bus pašalinti, todėl jokių papildomų veiksmų iš tavęs nereikės. Jei tai buvo ne tu, ignoruok šį el. laišką.
|
||||
extra_html: Taip pat peržiūrėk <a href="%{terms_path}">serverio taisykles</a> ir <a href="%{policy_path}">mūsų paslaugų teikimo sąlygas</a>.
|
||||
subject: 'Mastodon: patvirtinimo instrukcijos %{instance}'
|
||||
title: Patvirtinti el. pašto adresą
|
||||
|
@ -903,7 +903,6 @@ el:
|
||||
delete: Διαγραφή
|
||||
edit_preset: Ενημέρωση προκαθορισμένης προειδοποίησης
|
||||
empty: Δεν έχετε ακόμη ορίσει κάποια προκαθορισμένη προειδοποίηση.
|
||||
title: Διαχείριση προκαθορισμένων προειδοποιήσεων
|
||||
webhooks:
|
||||
add_new: Προσθήκη σημείου τερματισμού
|
||||
delete: Διαγραφή
|
||||
|
@ -950,7 +950,6 @@ en-GB:
|
||||
delete: Delete
|
||||
edit_preset: Edit warning preset
|
||||
empty: You haven't defined any warning presets yet.
|
||||
title: Warning presets
|
||||
webhooks:
|
||||
add_new: Add endpoint
|
||||
delete: Delete
|
||||
|
@ -919,7 +919,6 @@ eo:
|
||||
delete: Forigi
|
||||
edit_preset: Redakti avertan antaŭagordon
|
||||
empty: Vi ankoraŭ ne difinis iun ajn antaŭagordon de averto.
|
||||
title: Administri avertajn antaŭagordojn
|
||||
webhooks:
|
||||
add_new: Aldoni finpunkton
|
||||
delete: Forigi
|
||||
|
@ -951,7 +951,7 @@ es-AR:
|
||||
delete: Eliminar
|
||||
edit_preset: Editar preajuste de advertencia
|
||||
empty: Aún no ha definido ningún preajuste de advertencia.
|
||||
title: Administrar preajustes de advertencia
|
||||
title: Preajustes de advertencia
|
||||
webhooks:
|
||||
add_new: Agregar punto final
|
||||
delete: Eliminar
|
||||
|
@ -951,7 +951,7 @@ es-MX:
|
||||
delete: Borrar
|
||||
edit_preset: Editar aviso predeterminado
|
||||
empty: Aún no has definido ningún preajuste de advertencia.
|
||||
title: Editar configuración predeterminada de avisos
|
||||
title: Preajustes de advertencia
|
||||
webhooks:
|
||||
add_new: Añadir endpoint
|
||||
delete: Eliminar
|
||||
|
@ -951,7 +951,7 @@ es:
|
||||
delete: Borrar
|
||||
edit_preset: Editar aviso predeterminado
|
||||
empty: Aún no has definido ningún preajuste de advertencia.
|
||||
title: Editar configuración predeterminada de avisos
|
||||
title: Preajustes de advertencia
|
||||
webhooks:
|
||||
add_new: Añadir endpoint
|
||||
delete: Eliminar
|
||||
|
@ -949,7 +949,6 @@ et:
|
||||
delete: Kustuta
|
||||
edit_preset: Hoiatuse eelseadistuse muutmine
|
||||
empty: Hoiatuste eelseadeid pole defineeritud.
|
||||
title: Halda hoiatuste eelseadistusi
|
||||
webhooks:
|
||||
add_new: Lisa lõpp-punkt
|
||||
delete: Kustuta
|
||||
|
@ -952,7 +952,6 @@ eu:
|
||||
delete: Ezabatu
|
||||
edit_preset: Editatu abisu aurre-ezarpena
|
||||
empty: Ez duzu abisu aurrezarpenik definitu oraindik.
|
||||
title: Kudeatu abisu aurre-ezarpenak
|
||||
webhooks:
|
||||
add_new: Gehitu amaiera-puntua
|
||||
delete: Ezabatu
|
||||
|
@ -808,7 +808,6 @@ fa:
|
||||
delete: زدودن
|
||||
edit_preset: ویرایش هشدار پیشفرض
|
||||
empty: هنز هیچ پیشتنظیم هشداری را تعریف نکردهاید.
|
||||
title: مدیریت هشدارهای پیشفرض
|
||||
webhooks:
|
||||
add_new: افزودن نقطهٔ پایانی
|
||||
delete: حذف
|
||||
|
@ -951,7 +951,6 @@ fi:
|
||||
delete: Poista
|
||||
edit_preset: Muokkaa varoituksen esiasetusta
|
||||
empty: Et ole vielä määrittänyt yhtäkään varoitusten esiasetusta.
|
||||
title: Hallitse varoitusten esiasetuksia
|
||||
webhooks:
|
||||
add_new: Lisää päätepiste
|
||||
delete: Poista
|
||||
|
@ -951,7 +951,7 @@ fo:
|
||||
delete: Strika
|
||||
edit_preset: Rætta ávaringar-undanstilling
|
||||
empty: Tú hevur ikki ásett nakrar ávaringar-undanstillingar enn.
|
||||
title: Stýr ávaringar-undanstillingar
|
||||
title: Undanstillingar fyri ávaring
|
||||
webhooks:
|
||||
add_new: Legg endapunkt afturat
|
||||
delete: Strika
|
||||
|
@ -949,7 +949,6 @@ fr-CA:
|
||||
delete: Supprimer
|
||||
edit_preset: Éditer les avertissements prédéfinis
|
||||
empty: Vous n'avez pas encore créé de paramètres prédéfinis pour les avertissements.
|
||||
title: Gérer les avertissements prédéfinis
|
||||
webhooks:
|
||||
add_new: Ajouter un point de terminaison
|
||||
delete: Supprimer
|
||||
|
@ -949,7 +949,6 @@ fr:
|
||||
delete: Supprimer
|
||||
edit_preset: Éditer les avertissements prédéfinis
|
||||
empty: Vous n'avez pas encore créé de paramètres prédéfinis pour les avertissements.
|
||||
title: Gérer les avertissements prédéfinis
|
||||
webhooks:
|
||||
add_new: Ajouter un point de terminaison
|
||||
delete: Supprimer
|
||||
|
@ -949,7 +949,6 @@ fy:
|
||||
delete: Fuortsmite
|
||||
edit_preset: Foarynstelling foar warskôging bewurkje
|
||||
empty: Jo hawwe noch gjin foarynstellingen foar warskôgingen tafoege.
|
||||
title: Foarynstellingen foar warskôgingen beheare
|
||||
webhooks:
|
||||
add_new: Einpunt tafoegje
|
||||
delete: Fuortsmite
|
||||
|
@ -983,7 +983,6 @@ gd:
|
||||
delete: Sguab às
|
||||
edit_preset: Deasaich rabhadh ro-shuidhichte
|
||||
empty: Cha do mhìnich thu ro-sheataichean rabhaidhean fhathast.
|
||||
title: Stiùirich na rabhaidhean ro-shuidhichte
|
||||
webhooks:
|
||||
add_new: Cuir puing-dheiridh ris
|
||||
delete: Sguab às
|
||||
|
@ -951,7 +951,7 @@ gl:
|
||||
delete: Eliminar
|
||||
edit_preset: Editar aviso preestablecido
|
||||
empty: Non definiches os avisos prestablecidos.
|
||||
title: Xestionar avisos preestablecidos
|
||||
title: Preestablecidos de advertencia
|
||||
webhooks:
|
||||
add_new: Engadir punto de extremo
|
||||
delete: Eliminar
|
||||
|
@ -985,7 +985,7 @@ he:
|
||||
delete: למחוק
|
||||
edit_preset: ערוך/י טקסט מוכן מראש לאזהרה
|
||||
empty: לא הגדרת עדיין שום טקסט מוכן מראש לאזהרה.
|
||||
title: ניהול טקסטים מוכנים מראש לאזהרות
|
||||
title: תצורת אזהרות
|
||||
webhooks:
|
||||
add_new: הוספת נקודת קצה
|
||||
delete: מחיקה
|
||||
|
@ -951,7 +951,7 @@ hu:
|
||||
delete: Törlés
|
||||
edit_preset: Figyelmeztetés szerkesztése
|
||||
empty: Nem definiáltál még egyetlen figyelmeztetést sem.
|
||||
title: Figyelmeztetések
|
||||
title: Figyelmeztető szövegek
|
||||
webhooks:
|
||||
add_new: Végpont hozzáadása
|
||||
delete: Törlés
|
||||
|
@ -951,7 +951,7 @@ ia:
|
||||
delete: Deler
|
||||
edit_preset: Rediger aviso predefinite
|
||||
empty: Tu non ha ancora definite alcun avisos predefinite.
|
||||
title: Gerer avisos predefinite
|
||||
title: Predefinitiones de avisos
|
||||
webhooks:
|
||||
add_new: Adder terminal
|
||||
delete: Deler
|
||||
|
@ -831,7 +831,6 @@ id:
|
||||
delete: Hapus
|
||||
edit_preset: Sunting preset peringatan
|
||||
empty: Anda belum mendefinisikan peringatan apapun.
|
||||
title: Kelola preset peringatan
|
||||
webhooks:
|
||||
add_new: Tambah titik akhir
|
||||
delete: Hapus
|
||||
|
@ -950,7 +950,6 @@ ie:
|
||||
delete: Deleter
|
||||
edit_preset: Modificar prefiguration de avise
|
||||
empty: Vu ancor ha definit null prefigurationes de avise.
|
||||
title: Modificar prefigurationes de avise
|
||||
webhooks:
|
||||
add_new: Adjunter punctu terminal
|
||||
delete: Deleter
|
||||
|
@ -928,7 +928,6 @@ io:
|
||||
delete: Efacez
|
||||
edit_preset: Modifikez avertfixito
|
||||
empty: Vu ne fixis irga avertfixito til nun.
|
||||
title: Jerez avertfixiti
|
||||
webhooks:
|
||||
add_new: Insertez finpunto
|
||||
delete: Efacez
|
||||
|
@ -953,7 +953,7 @@ is:
|
||||
delete: Eyða
|
||||
edit_preset: Breyta forstilltri aðvörun
|
||||
empty: Þú hefur ekki enn skilgreint neinar aðvaranaforstillingar.
|
||||
title: Sýsla með forstilltar aðvaranir
|
||||
title: Forstilltar aðvaranir
|
||||
webhooks:
|
||||
add_new: Bæta við endapunkti
|
||||
delete: Eyða
|
||||
|
@ -951,7 +951,7 @@ it:
|
||||
delete: Cancella
|
||||
edit_preset: Modifica avviso predefinito
|
||||
empty: Non hai ancora definito alcun avviso preimpostato.
|
||||
title: Gestisci avvisi predefiniti
|
||||
title: Preimpostazioni di avviso
|
||||
webhooks:
|
||||
add_new: Aggiungi endpoint
|
||||
delete: Elimina
|
||||
|
@ -933,7 +933,6 @@ ja:
|
||||
delete: 削除
|
||||
edit_preset: プリセット警告文を編集
|
||||
empty: まだプリセット警告文が作成されていません。
|
||||
title: プリセット警告文を管理
|
||||
webhooks:
|
||||
add_new: エンドポイントを追加
|
||||
delete: 削除
|
||||
|
@ -299,7 +299,6 @@ kk:
|
||||
add_new: Add nеw
|
||||
delete: Deletе
|
||||
edit_preset: Edit warning prеset
|
||||
title: Manage warning presеts
|
||||
admin_mailer:
|
||||
new_pending_account:
|
||||
body: Жаңа есептік жазба туралы мәліметтер төменде берілген. Бұл қолданбаны мақұлдауыңызға немесе қабылдамауыңызға болады.
|
||||
|
@ -936,7 +936,7 @@ ko:
|
||||
delete: 삭제
|
||||
edit_preset: 경고 프리셋 편집
|
||||
empty: 아직 어떤 경고 틀도 정의되지 않았습니다.
|
||||
title: 경고 틀 관리
|
||||
title: 경고 프리셋
|
||||
webhooks:
|
||||
add_new: 엔드포인트 추가
|
||||
delete: 삭제
|
||||
|
@ -849,7 +849,6 @@ ku:
|
||||
delete: Jê bibe
|
||||
edit_preset: Hişyariyên pêşsazkirî serrast bike
|
||||
empty: Te hin tu hişyariyên pêşsazkirî destnîşan nekirine.
|
||||
title: Hişyariyên pêşsazkirî bi rêve bibe
|
||||
webhooks:
|
||||
add_new: Xala dawîbûnê tevlî bike
|
||||
delete: Jê bibe
|
||||
|
@ -950,7 +950,6 @@ lad:
|
||||
delete: Efasa
|
||||
edit_preset: Edita avizo predeterminado
|
||||
empty: Ainda no tienes definido ningun avizo predeterminado.
|
||||
title: Edita konfigurasyon predeterminada de avizos
|
||||
webhooks:
|
||||
add_new: Adjusta endpoint
|
||||
delete: Efasa
|
||||
|
@ -451,7 +451,7 @@ lt:
|
||||
filter:
|
||||
all: Visi
|
||||
available: Pasiekiamas
|
||||
expired: Pasibaigęs
|
||||
expired: Nebegaliojantis
|
||||
title: Filtras
|
||||
title: Kvietimai
|
||||
relays:
|
||||
@ -505,9 +505,15 @@ lt:
|
||||
unresolved: Neišspręsti
|
||||
updated_at: Atnaujinti
|
||||
roles:
|
||||
categories:
|
||||
invites: Kvietimai
|
||||
everyone: Numatytieji leidimai
|
||||
everyone_full_description_html: Tai – <strong>bazinis vaidmuo</strong>, turintis įtakos <strong>visiems naudotojams</strong>, net ir tiems, kurie neturi priskirto vaidmens. Visi kiti vaidmenys iš jo paveldi teises.
|
||||
privileges:
|
||||
invite_users: Kviesti naudotojus
|
||||
invite_users_description: Leidžia naudotojams pakviesti naujus žmones į serverį.
|
||||
manage_invites: Tvarkyti kvietimus
|
||||
manage_invites_description: Leidžia naudotojams naršyti ir deaktyvuoti kvietimų nuorodas.
|
||||
manage_taxonomies_description: Leidžia naudotojams peržiūrėti tendencingą turinį ir atnaujinti saitažodžių nustatymus
|
||||
settings:
|
||||
captcha_enabled:
|
||||
@ -522,12 +528,34 @@ lt:
|
||||
registrations:
|
||||
moderation_recommandation: Prieš atidarant registraciją visiems, įsitikink, kad turi tinkamą ir reaguojančią prižiūrėjimo komandą!
|
||||
software_updates:
|
||||
description: Rekomenduojama nuolat atnaujinti Mastodon diegyklę, kad galėtum naudotis naujausiais pataisymais ir funkcijomis. Be to, kartais labai svarbu laiku naujinti Mastodon, kad būtų išvengta saugumo problemų. Dėl šių priežasčių Mastodon kas 30 minučių tikrina, ar yra atnaujinimų, ir praneša tau apie tai pagal tavo el. pašto pranešimų parinktis.
|
||||
description: Rekomenduojama nuolat atnaujinti Mastodon diegyklę, kad galėtum naudotis naujausiais pataisymais ir funkcijomis. Be to, kartais labai svarbu laiku atnaujinti Mastodon, kad būtų išvengta saugumo problemų. Dėl šių priežasčių Mastodon kas 30 minučių tikrina, ar yra naujinimų, ir praneša tau apie tai pagal tavo el. pašto pranešimų parinktis.
|
||||
documentation_link: Sužinoti daugiau
|
||||
release_notes: Leidimo informacija
|
||||
title: Galimi naujinimai
|
||||
type: Tipas
|
||||
types:
|
||||
major: Pagrindinis leidimas
|
||||
minor: Nedidelis leidimas
|
||||
patch: Pataiso leidimas – riktų taisymai ir lengvai pritaikomi pakeitimai
|
||||
version: Versija
|
||||
statuses:
|
||||
account: Autorius (-ė)
|
||||
application: Programa
|
||||
back_to_account: Grįžti į paskyros puslapį
|
||||
back_to_report: Grįžti į ataskaitos puslapį
|
||||
batch:
|
||||
remove_from_report: Pašalinti iš ataskaitos
|
||||
deleted: Ištrinta
|
||||
favourites: Mėgstami
|
||||
history: Versijų istorija
|
||||
in_reply_to: Atsakydant į
|
||||
language: Kalba
|
||||
media:
|
||||
title: Medija
|
||||
no_status_selected: Jokie statusai nebuvo pakeisti, nes niekas nepasirinkta
|
||||
metadata: Metaduomenys
|
||||
no_status_selected: Jokie įrašai nebuvo pakeisti, nes nė vienas buvo pasirinktas
|
||||
open: Atidaryti įrašą
|
||||
original_status: Originalus įrašas
|
||||
title: Paskyros statusai
|
||||
trending: Tendencinga
|
||||
with_media: Su medija
|
||||
@ -537,6 +565,7 @@ lt:
|
||||
elasticsearch_preset:
|
||||
message_html: Tavo Elasticsearch klasteris turi daugiau nei vieną mazgą, bet Mastodon nėra sukonfigūruotas juos naudoti.
|
||||
elasticsearch_preset_single_node:
|
||||
action: Žiūrėti dokumentaciją
|
||||
message_html: Tavo Elasticsearch klasteris turi tik vieną mazgą, <code>ES_PRESET</code> turėtų būti nustatyta į <code>single_node_cluster</code>.
|
||||
title: Administracija
|
||||
trends:
|
||||
@ -571,8 +600,20 @@ lt:
|
||||
disallow_account: Neleisti autorių (-ę)
|
||||
no_status_selected: Jokie tendencingi įrašai nebuvo pakeisti, nes nė vienas iš jų nebuvo pasirinktas
|
||||
not_discoverable: Autorius (-ė) nesutiko, kad būtų galima juos atrasti
|
||||
shared_by:
|
||||
few: Bendrinta arba pamėgta %{friendly_count} kartus
|
||||
many: Bendrinta arba pamėgta %{friendly_count} karto
|
||||
one: Bendrinta arba pamėgta vieną kartą
|
||||
other: Bendrinta arba pamėgta %{friendly_count} kartų
|
||||
title: Tendencingi įrašai
|
||||
tags:
|
||||
dashboard:
|
||||
tag_accounts_measure: unikalūs naudojimai
|
||||
tag_languages_dimension: Populiariausios kalbos
|
||||
tag_servers_dimension: Populiariausi serveriai
|
||||
tag_servers_measure: skirtingi serveriai
|
||||
tag_uses_measure: bendri naudojimai
|
||||
listable: Gali būti siūloma
|
||||
not_trendable: Nepasirodys tendencijose
|
||||
title: Tendencingos saitažodžiai
|
||||
trendable: Gali pasirodyti tendencijose
|
||||
@ -583,7 +624,6 @@ lt:
|
||||
add_new: Pridėti naują
|
||||
delete: Ištrinti
|
||||
edit_preset: Keisti įspėjimo nustatymus
|
||||
title: Valdyti įspėjimo nustatymus
|
||||
webhooks:
|
||||
description_html: "<strong>Webhook</strong> leidžia Mastodon siųsti <strong>realaus laiko pranešimus</strong> apie pasirinktus įvykius į tavo programą, kad programa galėtų <strong>automatiškai paleisti reakcijas</strong>."
|
||||
events: Įvykiai
|
||||
@ -627,21 +667,32 @@ lt:
|
||||
warning: Būkite atsargūs su šia informacija. Niekada jos nesidalinkite!
|
||||
your_token: Tavo prieigos raktas
|
||||
auth:
|
||||
confirmations:
|
||||
welcome_title: Sveiki, %{name}!
|
||||
delete_account: Ištrinti paskyrą
|
||||
delete_account_html: Jeigu norite ištrinti savo paskyrą, galite eiti <a href="%{path}">čia</a>. Jūsų prašys patvirtinti pasirinkimą.
|
||||
description:
|
||||
prefix_invited_by_user: "@%{name} kviečia prisijungti prie šio Mastodon serverio!"
|
||||
prefix_sign_up: Užsiregistruok Mastodon šiandien!
|
||||
didnt_get_confirmation: Negavai patvirtinimo nuorodos?
|
||||
dont_have_your_security_key: Neturi saugumo rakto?
|
||||
forgot_password: Pamiršote slaptažodį?
|
||||
invalid_reset_password_token: Slaptažodžio atkūrimo žetonas netinkamas arba jo galiojimo laikas pasibaigęs. Prašykite naujo žetono.
|
||||
forgot_password: Pamiršai slaptažodį?
|
||||
invalid_reset_password_token: Slaptažodžio atkūrimo raktas yra netinkamas arba nebegaliojantis. Paprašyk naujo.
|
||||
log_in_with: Prisijungti su
|
||||
login: Prisijungti
|
||||
logout: Atsijungti
|
||||
migrate_account: Prisijungti prie kitos paskyros
|
||||
migrate_account_html: Jeigu norite nukreipti šią paskyrą į kita, galite tai <a href="%{path}">konfiguruoti čia</a>.
|
||||
or_log_in_with: Arba prisijungti su
|
||||
providers:
|
||||
cas: CAS
|
||||
saml: SAML
|
||||
register: Užsiregistruoti
|
||||
reset_password: Atstatyti slaptažodį
|
||||
rules:
|
||||
invited_by: 'Gali prisijungti prie %{domain} pagal kvietimą, kurį gavai iš:'
|
||||
preamble_invited: Prieš tęsiant, atsižvelk į pagrindines taisykles, kurias nustatė %{domain} prižiūrėtojai.
|
||||
title_invited: Esi pakviestas.
|
||||
security: Apsauga
|
||||
set_new_password: Nustatyti naują slaptažodį
|
||||
status:
|
||||
@ -673,6 +724,9 @@ lt:
|
||||
success_msg: Tavo paskyra buvo sėkmingai ištrinta
|
||||
disputes:
|
||||
strikes:
|
||||
created_at: Data
|
||||
title_actions:
|
||||
none: Įspėjimas
|
||||
your_appeal_approved: Tavo apeliacija buvo patvirtinta
|
||||
your_appeal_pending: Pateikei apeliaciją
|
||||
your_appeal_rejected: Tavo apeliacija buvo atmesta
|
||||
@ -699,6 +753,8 @@ lt:
|
||||
request: Prašyti savo archyvo
|
||||
size: Dydis
|
||||
blocks: Jūs blokuojate
|
||||
bookmarks: Žymės
|
||||
csv: CSV
|
||||
domain_blocks: Domeno blokai
|
||||
lists: Sąrašai
|
||||
mutes: Jūs tildote
|
||||
@ -708,11 +764,14 @@ lt:
|
||||
hint_html: "<strong>Savo profilyje parodyk svarbiausius saitažodžius.</strong> Tai puikus įrankis kūrybiniams darbams ir ilgalaikiams projektams sekti, todėl svarbiausios saitažodžiai rodomi matomoje vietoje profilyje ir leidžia greitai pasiekti tavo paties įrašus."
|
||||
filters:
|
||||
contexts:
|
||||
home: Namų laiko juosta
|
||||
notifications: Priminimai
|
||||
account: Profiliai
|
||||
home: Pagrindinis ir sąrašai
|
||||
notifications: Pranešimai
|
||||
public: Viešieji laiko skalės
|
||||
thread: Pokalbiai
|
||||
edit:
|
||||
add_keyword: Pridėti raktažodį
|
||||
keywords: Raktažodžiai
|
||||
title: Keisti filtrą
|
||||
errors:
|
||||
invalid_context: Jokio arba netinkamas pateiktas kontekstas
|
||||
@ -726,9 +785,14 @@ lt:
|
||||
all: Visi
|
||||
changes_saved_msg: Pakeitimai sėkmingai išsaugoti!
|
||||
copy: Kopijuoti
|
||||
delete: Ištrinti
|
||||
deselect: Panaikinti visus žymėjimus
|
||||
order_by: Tvarkyti pagal
|
||||
save_changes: Išsaugoti pakeitimus
|
||||
today: šiandien
|
||||
imports:
|
||||
errors:
|
||||
too_large: Failas per didelis.
|
||||
modes:
|
||||
merge: Sulieti
|
||||
merge_long: Išsaugoti esančius įrašus ir pridėti naujus
|
||||
@ -744,7 +808,7 @@ lt:
|
||||
upload: Įkelti
|
||||
invites:
|
||||
delete: Deaktyvuoti
|
||||
expired: Pasibaigė
|
||||
expired: Nebegaliojantis
|
||||
expires_in:
|
||||
'1800': 30 minučių
|
||||
'21600': 6 valandų
|
||||
@ -753,28 +817,29 @@ lt:
|
||||
'604800': 1 savaitės
|
||||
'86400': 1 dienos
|
||||
expires_in_prompt: Niekada
|
||||
generate: Generuoti
|
||||
generate: Generuoti kvietimo nuorodą
|
||||
invalid: Šis kvietimas negalioja.
|
||||
invited_by: 'Jus pakvietė:'
|
||||
invited_by: 'Tave pakvietė:'
|
||||
max_uses:
|
||||
few: "%{count} naudojimai"
|
||||
many: "%{count} naudojimo"
|
||||
one: 1 naudojimas
|
||||
other: "%{count} naudojimų"
|
||||
max_uses_prompt: Nėra limito
|
||||
max_uses_prompt: Nėra ribojimo
|
||||
prompt: Generuok ir bendrink nuorodas su kitais, kad suteiktum prieigą prie šio serverio
|
||||
table:
|
||||
expires_at: Baigsis
|
||||
uses: Naudojimai
|
||||
title: Pakviesti žmones
|
||||
title: Kviesti žmones
|
||||
media_attachments:
|
||||
validations:
|
||||
images_and_video: Negalima pridėti video prie statuso, kuris jau turi nuotrauką
|
||||
too_many: Negalima pridėti daugiau nei 4 failų
|
||||
migrations:
|
||||
acct: slapyvardis@domenas naujam vartotojui
|
||||
acct: Perkelta į
|
||||
cancel: Atšaukti nukreipimą
|
||||
moderation:
|
||||
title: Moderacija
|
||||
title: Prižiūrėjimas
|
||||
notification_mailer:
|
||||
favourite:
|
||||
body: 'Tavo įrašą pamėgo %{name}:'
|
||||
@ -801,11 +866,19 @@ lt:
|
||||
notifications:
|
||||
email_events: Įvykiai, skirti el. laiško pranešimams
|
||||
email_events_hint: 'Pasirink įvykius, apie kuriuos nori gauti pranešimus:'
|
||||
number:
|
||||
human:
|
||||
decimal_units:
|
||||
units:
|
||||
billion: mlrd.
|
||||
million: mln.
|
||||
thousand: tūkst.
|
||||
pagination:
|
||||
newer: Naujesnis
|
||||
next: Kitas
|
||||
older: Senesnis
|
||||
prev: Ankstesnis
|
||||
truncate: "…"
|
||||
preferences:
|
||||
other: Kita
|
||||
posting_defaults: Skelbimo numatytosios nuostatos
|
||||
@ -829,6 +902,7 @@ lt:
|
||||
dormant: Neaktyvus
|
||||
followers: Sekėjai
|
||||
following: Sekama
|
||||
invited: Pakviestas
|
||||
last_active: Paskutinį kartą aktyvus
|
||||
most_recent: Naujausias
|
||||
moved: Perkelta
|
||||
@ -851,24 +925,35 @@ lt:
|
||||
date: Data
|
||||
description: "%{browser} ant %{platform}"
|
||||
explanation: Čia rodomos web naršyklės prijungtos prie Jūsų Mastodon paskyros.
|
||||
ip: IP
|
||||
platforms:
|
||||
adobe_air: Adobe Air
|
||||
android: Android
|
||||
blackberry: BlackBerry
|
||||
chrome_os: ChromeOS
|
||||
firefox_os: Firefox OS
|
||||
ios: iOS
|
||||
kai_os: KaiOS
|
||||
linux: Linux
|
||||
mac: macOS
|
||||
unknown_platform: Nežinoma platforma
|
||||
windows: Windows
|
||||
windows_mobile: Windows Mobile
|
||||
windows_phone: Windows Phone
|
||||
revoke: Atšaukti
|
||||
revoke: Naikinti
|
||||
revoke_success: Seansas sėkmingai panaikintas.
|
||||
title: Seansai
|
||||
settings:
|
||||
authorized_apps: Autorizuotos aplikacijos
|
||||
account: Paskyra
|
||||
account_settings: Paskyros nustatymai
|
||||
aliases: Paskyros pseudonimai
|
||||
appearance: Išvaizda
|
||||
authorized_apps: Leidžiamos programėlės
|
||||
back: Grįžti į Mastodon
|
||||
delete: Paskyros trynimas
|
||||
development: Plėtojimas
|
||||
edit_profile: Keisti profilį
|
||||
export: Informacijos eksportas
|
||||
development: Kūrimas
|
||||
edit_profile: Redaguoti profilį
|
||||
export: Duomenų eksportas
|
||||
featured_tags: Rodomi saitažodžiai
|
||||
import: Importuoti
|
||||
migrate: Paskyros migracija
|
||||
@ -879,10 +964,22 @@ lt:
|
||||
severed_relationships: Nutrūkę sąryšiai
|
||||
two_factor_authentication: Dviejų veiksnių autentikacija
|
||||
severed_relationships:
|
||||
download: Atsisiųsti (%{count})
|
||||
preamble: Užblokavus domeną arba prižiūrėtojams nusprendus pristabdyti nuotolinio serverio veiklą, gali prarasti sekimus ir sekėjus. Kai taip atsitiks, galėsi atsisiųsti nutrauktų sąryšių sąrašus, kad juos patikrinti ir galbūt importuoti į kitą serverį.
|
||||
type: Įvykis
|
||||
statuses:
|
||||
attached:
|
||||
audio:
|
||||
few: "%{count} garso įrašai"
|
||||
many: "%{count} garso įrašo"
|
||||
one: "%{count} garso įrašas"
|
||||
other: "%{count} garso įrašų"
|
||||
description: 'Pridėta: %{attached}'
|
||||
image:
|
||||
few: "%{count} vaizdai"
|
||||
many: "%{count} vaizdo"
|
||||
one: "%{count} vaizdas"
|
||||
other: "%{count} vaizdų"
|
||||
boosted_from_html: Pakelta iš %{acct_link}
|
||||
content_warning: 'Turinio įspėjimas: %{warning}'
|
||||
open_in_web: Atidaryti naudojan Web
|
||||
@ -891,11 +988,14 @@ lt:
|
||||
limit: Jūs jau prisegėte maksimalų toot'ų skaičų
|
||||
ownership: Kitų vartotojų toot'ai negali būti prisegti
|
||||
reblog: Pakeltos žinutės negali būti prisegtos
|
||||
show_more: Daugiau
|
||||
poll:
|
||||
vote: Balsuoti
|
||||
show_more: Rodyti daugiau
|
||||
show_thread: Rodyti giją
|
||||
visibilities:
|
||||
private: Tik sekėjams
|
||||
private_long: rodyti tik sekėjams
|
||||
public: Viešas
|
||||
public: Vieša
|
||||
public_long: visi gali matyti
|
||||
unlisted: Neįtrauktas į sąrašus
|
||||
unlisted_long: matyti gali visi, bet nėra išvardyti į viešąsias laiko skales
|
||||
@ -904,6 +1004,7 @@ lt:
|
||||
keep_polls_hint: Neištrina jokių tavo apklausų
|
||||
keep_self_bookmark: Laikyti įrašus, kuriuos pažymėjai
|
||||
keep_self_bookmark_hint: Neištrina tavo pačių įrašų, jei esi juos pažymėjęs (-usi)
|
||||
keep_self_fav_hint: Neištrina tavo pačių įrašų, jei esi juos pamėgęs (-usi)
|
||||
stream_entries:
|
||||
sensitive_content: Jautrus turinys
|
||||
themes:
|
||||
@ -912,7 +1013,8 @@ lt:
|
||||
mastodon-light: Mastodon (šviesi)
|
||||
system: Automatinis (naudoti sistemos temą)
|
||||
two_factor_authentication:
|
||||
disable: Išjungti
|
||||
add: Pridėti
|
||||
disable: Išjungti 2FA
|
||||
enabled: Dviejų veiksnių autentikacija įjungta
|
||||
enabled_success: Dviejų veiksnių autentikacija sėkmingai įjungta
|
||||
generate_recovery_codes: Sugeneruoti atkūrimo kodus
|
||||
|
@ -961,7 +961,6 @@ lv:
|
||||
delete: Dzēst
|
||||
edit_preset: Labot iepriekš iestatītus brīdinājumus
|
||||
empty: Tu vēl neesi definējis iepriekš iestatītos brīdinājumus.
|
||||
title: Pārvaldīt brīdinājuma iestatījumus
|
||||
webhooks:
|
||||
add_new: Pievienot galapunktu
|
||||
delete: Dzēst
|
||||
|
@ -924,7 +924,6 @@ ms:
|
||||
delete: Padam
|
||||
edit_preset: Edit pratetap amaran
|
||||
empty: Anda belum menentukan sebarang pratetap amaran lagi.
|
||||
title: Urus pratetap amaran
|
||||
webhooks:
|
||||
add_new: Tambah titik akhir
|
||||
delete: Padam
|
||||
|
@ -909,7 +909,6 @@ my:
|
||||
delete: ဖျက်ပါ
|
||||
edit_preset: ကြိုသတိပေးချက်ကို ပြင်ဆင်ပါ
|
||||
empty: ကြိုသတိပေးချက်များကို မသတ်မှတ်ရသေးပါ။
|
||||
title: ကြိုသတိပေးချက်များကို စီမံပါ
|
||||
webhooks:
|
||||
add_new: ဆုံးမှတ် ထည့်ပါ
|
||||
delete: ဖျက်ပါ
|
||||
|
@ -951,7 +951,7 @@ nl:
|
||||
delete: Verwijderen
|
||||
edit_preset: Preset voor waarschuwing bewerken
|
||||
empty: Je hebt nog geen presets voor waarschuwingen toegevoegd.
|
||||
title: Presets voor waarschuwingen beheren
|
||||
title: Presets voor waarschuwingen
|
||||
webhooks:
|
||||
add_new: Eindpunt toevoegen
|
||||
delete: Verwijderen
|
||||
|
@ -950,7 +950,6 @@ nn:
|
||||
delete: Slett
|
||||
edit_preset: Endr åtvaringsoppsett
|
||||
empty: Du har ikke definert noen forhåndsinnstillinger for advarsler enda.
|
||||
title: Handsam åtvaringsoppsett
|
||||
webhooks:
|
||||
add_new: Legg til endepunkt
|
||||
delete: Slett
|
||||
|
@ -944,7 +944,6 @@
|
||||
delete: Slett
|
||||
edit_preset: Rediger advarsel forhåndsinnstilling
|
||||
empty: Du har ikke definert noen forhåndsinnstillinger for varsler enda.
|
||||
title: Endre forhåndsinnstillinger for advarsler
|
||||
webhooks:
|
||||
add_new: Legg til endepunkt
|
||||
delete: Slett
|
||||
|
@ -430,7 +430,6 @@ oc:
|
||||
add_new: N’ajustar un nòu
|
||||
delete: Escafar
|
||||
edit_preset: Modificar lo tèxt predefinit d’avertiment
|
||||
title: Gerir los tèxtes predefinits
|
||||
webhooks:
|
||||
delete: Suprimir
|
||||
disable: Desactivar
|
||||
|
@ -985,7 +985,7 @@ pl:
|
||||
delete: Usuń
|
||||
edit_preset: Edytuj szablon ostrzeżenia
|
||||
empty: Nie zdefiniowano jeszcze żadnych szablonów ostrzegawczych.
|
||||
title: Zarządzaj szablonami ostrzeżeń
|
||||
title: Zapisane ostrzeżenia
|
||||
webhooks:
|
||||
add_new: Dodaj punkt końcowy
|
||||
delete: Usuń
|
||||
|
@ -950,7 +950,6 @@ pt-BR:
|
||||
delete: Excluir
|
||||
edit_preset: Editar o aviso pré-definido
|
||||
empty: Você ainda não definiu nenhuma predefinição de alerta.
|
||||
title: Gerenciar os avisos pré-definidos
|
||||
webhooks:
|
||||
add_new: Adicionar endpoint
|
||||
delete: Excluir
|
||||
|
@ -951,7 +951,7 @@ pt-PT:
|
||||
delete: Eliminar
|
||||
edit_preset: Editar o aviso predefinido
|
||||
empty: Ainda não definiu nenhum aviso predefinido.
|
||||
title: Gerir os avisos predefinidos
|
||||
title: Predefinições de aviso
|
||||
webhooks:
|
||||
add_new: Adicionar endpoint
|
||||
delete: Eliminar
|
||||
|
@ -978,7 +978,6 @@ ru:
|
||||
delete: Удалить
|
||||
edit_preset: Удалить шаблон предупреждения
|
||||
empty: Вы еще не определили пресеты предупреждений.
|
||||
title: Управление шаблонами предупреждений
|
||||
webhooks:
|
||||
add_new: Добавить конечную точку
|
||||
delete: Удалить
|
||||
|
@ -535,7 +535,6 @@ sc:
|
||||
delete: Cantzella
|
||||
edit_preset: Modìfica s'avisu predefinidu
|
||||
empty: No as cunfiguradu ancora perunu avisu predefinidu.
|
||||
title: Gesti is cunfiguratziones predefinidas de is avisos
|
||||
webhooks:
|
||||
delete: Cantzella
|
||||
disable: Disativa
|
||||
|
@ -842,7 +842,6 @@ sco:
|
||||
delete: Delete
|
||||
edit_preset: Edit warnin preset
|
||||
empty: Ye huvnae definit onie warnin presets yit.
|
||||
title: Manage warnin presets
|
||||
webhooks:
|
||||
add_new: Add enpynt
|
||||
delete: Delete
|
||||
|
@ -726,7 +726,6 @@ si:
|
||||
delete: මකන්න
|
||||
edit_preset: අනතුරු ඇඟවීමේ පෙර සැකසුම සංස්කරණය කරන්න
|
||||
empty: ඔබ තවම කිසිදු අනතුරු ඇඟවීමේ පෙරසිටුවක් නිර්වචනය කර නැත.
|
||||
title: අනතුරු ඇඟවීමේ පෙරසිටුවීම් කළමනාකරණය කරන්න
|
||||
webhooks:
|
||||
add_new: අන්ත ලක්ෂ්යය එක් කරන්න
|
||||
delete: මකන්න
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user