Add terms of service (#33055)

This commit is contained in:
Eugen Rochko 2024-12-09 11:04:46 +01:00 committed by GitHub
parent 7a2a345c08
commit 30aa0df88c
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
129 changed files with 1456 additions and 238 deletions

View File

@ -0,0 +1,18 @@
# frozen_string_literal: true
class Admin::TermsOfService::DistributionsController < Admin::BaseController
before_action :set_terms_of_service
def create
authorize @terms_of_service, :distribute?
@terms_of_service.touch(:notification_sent_at)
Admin::DistributeTermsOfServiceNotificationWorker.perform_async(@terms_of_service.id)
redirect_to admin_terms_of_service_index_path
end
private
def set_terms_of_service
@terms_of_service = TermsOfService.find(params[:terms_of_service_id])
end
end

View File

@ -0,0 +1,36 @@
# frozen_string_literal: true
class Admin::TermsOfService::DraftsController < Admin::BaseController
before_action :set_terms_of_service
def show
authorize :terms_of_service, :create?
end
def update
authorize @terms_of_service, :update?
@terms_of_service.published_at = Time.now.utc if params[:action_type] == 'publish'
if @terms_of_service.update(resource_params)
log_action(:publish, @terms_of_service) if @terms_of_service.published?
redirect_to @terms_of_service.published? ? admin_terms_of_service_index_path : admin_terms_of_service_draft_path
else
render :show
end
end
private
def set_terms_of_service
@terms_of_service = TermsOfService.draft.first || TermsOfService.new(text: current_terms_of_service&.text)
end
def current_terms_of_service
TermsOfService.live.first
end
def resource_params
params.require(:terms_of_service).permit(:text, :changelog)
end
end

View File

@ -0,0 +1,37 @@
# frozen_string_literal: true
class Admin::TermsOfService::GeneratesController < Admin::BaseController
before_action :set_instance_presenter
def show
authorize :terms_of_service, :create?
@generator = TermsOfService::Generator.new(
domain: @instance_presenter.domain,
admin_email: @instance_presenter.contact.email
)
end
def create
authorize :terms_of_service, :create?
@generator = TermsOfService::Generator.new(resource_params)
if @generator.valid?
TermsOfService.create!(text: @generator.render)
redirect_to admin_terms_of_service_draft_path
else
render :show
end
end
private
def set_instance_presenter
@instance_presenter = InstancePresenter.new
end
def resource_params
params.require(:terms_of_service_generator).permit(*TermsOfService::Generator::VARIABLES)
end
end

View File

@ -0,0 +1,8 @@
# frozen_string_literal: true
class Admin::TermsOfService::HistoriesController < Admin::BaseController
def show
authorize :terms_of_service, :index?
@terms_of_service = TermsOfService.published.all
end
end

View File

@ -0,0 +1,16 @@
# frozen_string_literal: true
class Admin::TermsOfService::PreviewsController < Admin::BaseController
before_action :set_terms_of_service
def show
authorize @terms_of_service, :distribute?
@user_count = @terms_of_service.scope_for_notification.count
end
private
def set_terms_of_service
@terms_of_service = TermsOfService.find(params[:terms_of_service_id])
end
end

View File

@ -0,0 +1,17 @@
# frozen_string_literal: true
class Admin::TermsOfService::TestsController < Admin::BaseController
before_action :set_terms_of_service
def create
authorize @terms_of_service, :distribute?
UserMailer.terms_of_service_changed(current_user, @terms_of_service).deliver_later!
redirect_to admin_terms_of_service_preview_path(@terms_of_service)
end
private
def set_terms_of_service
@terms_of_service = TermsOfService.find(params[:terms_of_service_id])
end
end

View File

@ -0,0 +1,8 @@
# frozen_string_literal: true
class Admin::TermsOfServiceController < Admin::BaseController
def index
authorize :terms_of_service, :index?
@terms_of_service = TermsOfService.live.first
end
end

View File

@ -0,0 +1,16 @@
# frozen_string_literal: true
class Api::V1::Instances::TermsOfServicesController < Api::V1::Instances::BaseController
before_action :set_terms_of_service
def show
cache_even_if_authenticated!
render json: @terms_of_service, serializer: REST::PrivacyPolicySerializer
end
private
def set_terms_of_service
@terms_of_service = TermsOfService.live.first!
end
end

View File

@ -0,0 +1,11 @@
# frozen_string_literal: true
class TermsOfServiceController < ApplicationController
include WebAppControllerConcern
skip_before_action :require_functional!
def show
expires_in(15.seconds, public: true, stale_while_revalidate: 30.seconds, stale_if_error: 1.day) unless user_signed_in?
end
end

View File

@ -64,6 +64,10 @@ module FormattingHelper
end end
end end
def markdown(text)
Redcarpet::Markdown.new(Redcarpet::Render::HTML, escape_html: true, no_images: true).render(text).html_safe # rubocop:disable Rails/OutputSafety
end
private private
def wrapped_status_content_format(status) def wrapped_status_content_format(status)

View File

@ -0,0 +1,11 @@
import { apiRequestGet } from 'mastodon/api';
import type {
ApiTermsOfServiceJSON,
ApiPrivacyPolicyJSON,
} from 'mastodon/api_types/instance';
export const apiGetTermsOfService = () =>
apiRequestGet<ApiTermsOfServiceJSON>('v1/instance/terms_of_service');
export const apiGetPrivacyPolicy = () =>
apiRequestGet<ApiPrivacyPolicyJSON>('v1/instance/privacy_policy');

View File

@ -0,0 +1,9 @@
export interface ApiTermsOfServiceJSON {
updated_at: string;
content: string;
}
export interface ApiPrivacyPolicyJSON {
updated_at: string;
content: string;
}

View File

@ -18,7 +18,7 @@ import Column from 'mastodon/components/column';
import { Icon } from 'mastodon/components/icon'; import { Icon } from 'mastodon/components/icon';
import { ServerHeroImage } from 'mastodon/components/server_hero_image'; import { ServerHeroImage } from 'mastodon/components/server_hero_image';
import { Skeleton } from 'mastodon/components/skeleton'; import { Skeleton } from 'mastodon/components/skeleton';
import LinkFooter from 'mastodon/features/ui/components/link_footer'; import { LinkFooter} from 'mastodon/features/ui/components/link_footer';
const messages = defineMessages({ const messages = defineMessages({
title: { id: 'column.about', defaultMessage: 'About' }, title: { id: 'column.about', defaultMessage: 'About' },

View File

@ -25,7 +25,7 @@ import StarIcon from '@/material-icons/400-24px/star.svg?react';
import { fetchFollowRequests } from 'mastodon/actions/accounts'; import { fetchFollowRequests } from 'mastodon/actions/accounts';
import Column from 'mastodon/components/column'; import Column from 'mastodon/components/column';
import ColumnHeader from 'mastodon/components/column_header'; import ColumnHeader from 'mastodon/components/column_header';
import LinkFooter from 'mastodon/features/ui/components/link_footer'; import { LinkFooter } from 'mastodon/features/ui/components/link_footer';
import { identityContextPropShape, withIdentity } from 'mastodon/identity_context'; import { identityContextPropShape, withIdentity } from 'mastodon/identity_context';
import { canManageReports, canViewAdminDashboard } from 'mastodon/permissions'; import { canManageReports, canViewAdminDashboard } from 'mastodon/permissions';

View File

@ -1,65 +0,0 @@
import PropTypes from 'prop-types';
import { PureComponent } from 'react';
import { FormattedMessage, FormattedDate, injectIntl, defineMessages } from 'react-intl';
import { Helmet } from 'react-helmet';
import api from 'mastodon/api';
import Column from 'mastodon/components/column';
import { Skeleton } from 'mastodon/components/skeleton';
const messages = defineMessages({
title: { id: 'privacy_policy.title', defaultMessage: 'Privacy Policy' },
});
class PrivacyPolicy extends PureComponent {
static propTypes = {
intl: PropTypes.object,
multiColumn: PropTypes.bool,
};
state = {
content: null,
lastUpdated: null,
isLoading: true,
};
componentDidMount () {
api().get('/api/v1/instance/privacy_policy').then(({ data }) => {
this.setState({ content: data.content, lastUpdated: data.updated_at, isLoading: false });
}).catch(() => {
this.setState({ isLoading: false });
});
}
render () {
const { intl, multiColumn } = this.props;
const { isLoading, content, lastUpdated } = this.state;
return (
<Column bindToDocument={!multiColumn} label={intl.formatMessage(messages.title)}>
<div className='scrollable privacy-policy'>
<div className='column-title'>
<h3><FormattedMessage id='privacy_policy.title' defaultMessage='Privacy Policy' /></h3>
<p><FormattedMessage id='privacy_policy.last_updated' defaultMessage='Last updated {date}' values={{ date: isLoading ? <Skeleton width='10ch' /> : <FormattedDate value={lastUpdated} year='numeric' month='short' day='2-digit' /> }} /></p>
</div>
<div
className='privacy-policy__body prose'
dangerouslySetInnerHTML={{ __html: content }}
/>
</div>
<Helmet>
<title>{intl.formatMessage(messages.title)}</title>
<meta name='robots' content='all' />
</Helmet>
</Column>
);
}
}
export default injectIntl(PrivacyPolicy);

View File

@ -0,0 +1,90 @@
import { useState, useEffect } from 'react';
import {
FormattedMessage,
FormattedDate,
useIntl,
defineMessages,
} from 'react-intl';
import { Helmet } from 'react-helmet';
import { apiGetPrivacyPolicy } from 'mastodon/api/instance';
import type { ApiPrivacyPolicyJSON } from 'mastodon/api_types/instance';
import { Column } from 'mastodon/components/column';
import { Skeleton } from 'mastodon/components/skeleton';
const messages = defineMessages({
title: { id: 'privacy_policy.title', defaultMessage: 'Privacy Policy' },
});
const PrivacyPolicy: React.FC<{
multiColumn: boolean;
}> = ({ multiColumn }) => {
const intl = useIntl();
const [response, setResponse] = useState<ApiPrivacyPolicyJSON>();
const [loading, setLoading] = useState(true);
useEffect(() => {
apiGetPrivacyPolicy()
.then((data) => {
setResponse(data);
setLoading(false);
return '';
})
.catch(() => {
setLoading(false);
});
}, []);
return (
<Column
bindToDocument={!multiColumn}
label={intl.formatMessage(messages.title)}
>
<div className='scrollable privacy-policy'>
<div className='column-title'>
<h3>
<FormattedMessage
id='privacy_policy.title'
defaultMessage='Privacy Policy'
/>
</h3>
<p>
<FormattedMessage
id='privacy_policy.last_updated'
defaultMessage='Last updated {date}'
values={{
date: loading ? (
<Skeleton width='10ch' />
) : (
<FormattedDate
value={response?.updated_at}
year='numeric'
month='short'
day='2-digit'
/>
),
}}
/>
</p>
</div>
{response && (
<div
className='privacy-policy__body prose'
dangerouslySetInnerHTML={{ __html: response.content }}
/>
)}
</div>
<Helmet>
<title>{intl.formatMessage(messages.title)}</title>
<meta name='robots' content='all' />
</Helmet>
</Column>
);
};
// eslint-disable-next-line import/no-default-export
export default PrivacyPolicy;

View File

@ -0,0 +1,95 @@
import { useState, useEffect } from 'react';
import {
FormattedMessage,
FormattedDate,
useIntl,
defineMessages,
} from 'react-intl';
import { Helmet } from 'react-helmet';
import { apiGetTermsOfService } from 'mastodon/api/instance';
import type { ApiTermsOfServiceJSON } from 'mastodon/api_types/instance';
import { Column } from 'mastodon/components/column';
import { Skeleton } from 'mastodon/components/skeleton';
import BundleColumnError from 'mastodon/features/ui/components/bundle_column_error';
const messages = defineMessages({
title: { id: 'terms_of_service.title', defaultMessage: 'Terms of Service' },
});
const TermsOfService: React.FC<{
multiColumn: boolean;
}> = ({ multiColumn }) => {
const intl = useIntl();
const [response, setResponse] = useState<ApiTermsOfServiceJSON>();
const [loading, setLoading] = useState(true);
useEffect(() => {
apiGetTermsOfService()
.then((data) => {
setResponse(data);
setLoading(false);
return '';
})
.catch(() => {
setLoading(false);
});
}, []);
if (!loading && !response) {
return <BundleColumnError multiColumn={multiColumn} errorType='routing' />;
}
return (
<Column
bindToDocument={!multiColumn}
label={intl.formatMessage(messages.title)}
>
<div className='scrollable privacy-policy'>
<div className='column-title'>
<h3>
<FormattedMessage
id='terms_of_service.title'
defaultMessage='Terms of Service'
/>
</h3>
<p>
<FormattedMessage
id='privacy_policy.last_updated'
defaultMessage='Last updated {date}'
values={{
date: loading ? (
<Skeleton width='10ch' />
) : (
<FormattedDate
value={response?.updated_at}
year='numeric'
month='short'
day='2-digit'
/>
),
}}
/>
</p>
</div>
{response && (
<div
className='privacy-policy__body prose'
dangerouslySetInnerHTML={{ __html: response.content }}
/>
)}
</div>
<Helmet>
<title>{intl.formatMessage(messages.title)}</title>
<meta name='robots' content='all' />
</Helmet>
</Column>
);
};
// eslint-disable-next-line import/no-default-export
export default TermsOfService;

View File

@ -7,10 +7,9 @@ import { changeComposing, mountCompose, unmountCompose } from 'mastodon/actions/
import ServerBanner from 'mastodon/components/server_banner'; import ServerBanner from 'mastodon/components/server_banner';
import ComposeFormContainer from 'mastodon/features/compose/containers/compose_form_container'; import ComposeFormContainer from 'mastodon/features/compose/containers/compose_form_container';
import SearchContainer from 'mastodon/features/compose/containers/search_container'; import SearchContainer from 'mastodon/features/compose/containers/search_container';
import { LinkFooter } from 'mastodon/features/ui/components/link_footer';
import { identityContextPropShape, withIdentity } from 'mastodon/identity_context'; import { identityContextPropShape, withIdentity } from 'mastodon/identity_context';
import LinkFooter from './link_footer';
class ComposePanel extends PureComponent { class ComposePanel extends PureComponent {
static propTypes = { static propTypes = {
identity: identityContextPropShape, identity: identityContextPropShape,

View File

@ -1,95 +0,0 @@
import PropTypes from 'prop-types';
import { PureComponent } from 'react';
import { FormattedMessage, injectIntl } from 'react-intl';
import { Link } from 'react-router-dom';
import { connect } from 'react-redux';
import { openModal } from 'mastodon/actions/modal';
import { identityContextPropShape, withIdentity } from 'mastodon/identity_context';
import { domain, version, source_url, statusPageUrl, profile_directory as profileDirectory } from 'mastodon/initial_state';
import { PERMISSION_INVITE_USERS } from 'mastodon/permissions';
const mapDispatchToProps = (dispatch) => ({
onLogout () {
dispatch(openModal({ modalType: 'CONFIRM_LOG_OUT' }));
},
});
class LinkFooter extends PureComponent {
static propTypes = {
identity: identityContextPropShape,
multiColumn: PropTypes.bool,
onLogout: PropTypes.func.isRequired,
intl: PropTypes.object.isRequired,
};
handleLogoutClick = e => {
e.preventDefault();
e.stopPropagation();
this.props.onLogout();
return false;
};
render () {
const { signedIn, permissions } = this.props.identity;
const { multiColumn } = this.props;
const canInvite = signedIn && ((permissions & PERMISSION_INVITE_USERS) === PERMISSION_INVITE_USERS);
const canProfileDirectory = profileDirectory;
const DividingCircle = <span aria-hidden>{' · '}</span>;
return (
<div className='link-footer'>
<p>
<strong>{domain}</strong>:
{' '}
<Link to='/about' target={multiColumn ? '_blank' : undefined}><FormattedMessage id='footer.about' defaultMessage='About' /></Link>
{statusPageUrl && (
<>
{DividingCircle}
<a href={statusPageUrl} target='_blank' rel='noopener'><FormattedMessage id='footer.status' defaultMessage='Status' /></a>
</>
)}
{canInvite && (
<>
{DividingCircle}
<a href='/invites' target='_blank'><FormattedMessage id='footer.invite' defaultMessage='Invite people' /></a>
</>
)}
{canProfileDirectory && (
<>
{DividingCircle}
<Link to='/directory'><FormattedMessage id='footer.directory' defaultMessage='Profiles directory' /></Link>
</>
)}
{DividingCircle}
<Link to='/privacy-policy' target={multiColumn ? '_blank' : undefined}><FormattedMessage id='footer.privacy_policy' defaultMessage='Privacy policy' /></Link>
</p>
<p>
<strong>Mastodon</strong>:
{' '}
<a href='https://joinmastodon.org' target='_blank'><FormattedMessage id='footer.about' defaultMessage='About' /></a>
{DividingCircle}
<a href='https://joinmastodon.org/apps' target='_blank'><FormattedMessage id='footer.get_app' defaultMessage='Get the app' /></a>
{DividingCircle}
<Link to='/keyboard-shortcuts'><FormattedMessage id='footer.keyboard_shortcuts' defaultMessage='Keyboard shortcuts' /></Link>
{DividingCircle}
<a href={source_url} rel='noopener noreferrer' target='_blank'><FormattedMessage id='footer.source_code' defaultMessage='View source code' /></a>
{DividingCircle}
<span className='version'>v{version}</span>
</p>
</div>
);
}
}
export default injectIntl(withIdentity(connect(null, mapDispatchToProps)(LinkFooter)));

View File

@ -0,0 +1,105 @@
import { FormattedMessage } from 'react-intl';
import { Link } from 'react-router-dom';
import {
domain,
version,
source_url,
statusPageUrl,
profile_directory as canProfileDirectory,
termsOfServiceEnabled,
} from 'mastodon/initial_state';
const DividingCircle: React.FC = () => <span aria-hidden>{' · '}</span>;
export const LinkFooter: React.FC<{
multiColumn: boolean;
}> = ({ multiColumn }) => {
return (
<div className='link-footer'>
<p>
<strong>{domain}</strong>:{' '}
<Link to='/about' target={multiColumn ? '_blank' : undefined}>
<FormattedMessage id='footer.about' defaultMessage='About' />
</Link>
{statusPageUrl && (
<>
<DividingCircle />
<a href={statusPageUrl} target='_blank' rel='noopener noreferrer'>
<FormattedMessage id='footer.status' defaultMessage='Status' />
</a>
</>
)}
{canProfileDirectory && (
<>
<DividingCircle />
<Link to='/directory'>
<FormattedMessage
id='footer.directory'
defaultMessage='Profiles directory'
/>
</Link>
</>
)}
<DividingCircle />
<Link
to='/privacy-policy'
target={multiColumn ? '_blank' : undefined}
rel='privacy-policy'
>
<FormattedMessage
id='footer.privacy_policy'
defaultMessage='Privacy policy'
/>
</Link>
{termsOfServiceEnabled && (
<>
<DividingCircle />
<Link
to='/terms-of-service'
target={multiColumn ? '_blank' : undefined}
rel='terms-of-service'
>
<FormattedMessage
id='footer.terms_of_service'
defaultMessage='Terms of service'
/>
</Link>
</>
)}
</p>
<p>
<strong>Mastodon</strong>:{' '}
<a href='https://joinmastodon.org' target='_blank' rel='noreferrer'>
<FormattedMessage id='footer.about' defaultMessage='About' />
</a>
<DividingCircle />
<a
href='https://joinmastodon.org/apps'
target='_blank'
rel='noreferrer'
>
<FormattedMessage id='footer.get_app' defaultMessage='Get the app' />
</a>
<DividingCircle />
<Link to='/keyboard-shortcuts'>
<FormattedMessage
id='footer.keyboard_shortcuts'
defaultMessage='Keyboard shortcuts'
/>
</Link>
<DividingCircle />
<a href={source_url} rel='noopener noreferrer' target='_blank'>
<FormattedMessage
id='footer.source_code'
defaultMessage='View source code'
/>
</a>
<DividingCircle />
<span className='version'>v{version}</span>
</p>
</div>
);
};

View File

@ -71,6 +71,7 @@ import {
Explore, Explore,
About, About,
PrivacyPolicy, PrivacyPolicy,
TermsOfService,
} from './util/async-components'; } from './util/async-components';
import { ColumnsContextProvider } from './util/columns_context'; import { ColumnsContextProvider } from './util/columns_context';
import { WrappedSwitch, WrappedRoute } from './util/react_router_helpers'; import { WrappedSwitch, WrappedRoute } from './util/react_router_helpers';
@ -198,6 +199,7 @@ class SwitchingColumnsArea extends PureComponent {
<WrappedRoute path='/keyboard-shortcuts' component={KeyboardShortcuts} content={children} /> <WrappedRoute path='/keyboard-shortcuts' component={KeyboardShortcuts} content={children} />
<WrappedRoute path='/about' component={About} content={children} /> <WrappedRoute path='/about' component={About} content={children} />
<WrappedRoute path='/privacy-policy' component={PrivacyPolicy} content={children} /> <WrappedRoute path='/privacy-policy' component={PrivacyPolicy} content={children} />
<WrappedRoute path='/terms-of-service' component={TermsOfService} content={children} />
<WrappedRoute path={['/home', '/timelines/home']} component={HomeTimeline} content={children} /> <WrappedRoute path={['/home', '/timelines/home']} component={HomeTimeline} content={children} />
<Redirect from='/timelines/public' to='/public' exact /> <Redirect from='/timelines/public' to='/public' exact />

View File

@ -198,6 +198,10 @@ export function PrivacyPolicy () {
return import(/*webpackChunkName: "features/privacy_policy" */'../../privacy_policy'); return import(/*webpackChunkName: "features/privacy_policy" */'../../privacy_policy');
} }
export function TermsOfService () {
return import(/*webpackChunkName: "features/terms_of_service" */'../../terms_of_service');
}
export function NotificationRequests () { export function NotificationRequests () {
return import(/*webpackChunkName: "features/notifications/requests" */'../../notifications/requests'); return import(/*webpackChunkName: "features/notifications/requests" */'../../notifications/requests');
} }

View File

@ -43,6 +43,8 @@
* @property {boolean=} use_pending_items * @property {boolean=} use_pending_items
* @property {string} version * @property {string} version
* @property {string} sso_redirect * @property {string} sso_redirect
* @property {string} status_page_url
* @property {boolean} terms_of_service_enabled
*/ */
/** /**
@ -115,10 +117,9 @@ export const usePendingItems = getMeta('use_pending_items');
export const version = getMeta('version'); export const version = getMeta('version');
export const languages = initialState?.languages; export const languages = initialState?.languages;
export const criticalUpdatesPending = initialState?.critical_updates_pending; export const criticalUpdatesPending = initialState?.critical_updates_pending;
// @ts-expect-error
export const statusPageUrl = getMeta('status_page_url'); export const statusPageUrl = getMeta('status_page_url');
export const sso_redirect = getMeta('sso_redirect'); export const sso_redirect = getMeta('sso_redirect');
export const termsOfServiceEnabled = getMeta('terms_of_service_enabled');
/** /**
* @returns {string | undefined} * @returns {string | undefined}
*/ */

View File

@ -359,11 +359,11 @@
"footer.about": "About", "footer.about": "About",
"footer.directory": "Profiles directory", "footer.directory": "Profiles directory",
"footer.get_app": "Get the app", "footer.get_app": "Get the app",
"footer.invite": "Invite people",
"footer.keyboard_shortcuts": "Keyboard shortcuts", "footer.keyboard_shortcuts": "Keyboard shortcuts",
"footer.privacy_policy": "Privacy policy", "footer.privacy_policy": "Privacy policy",
"footer.source_code": "View source code", "footer.source_code": "View source code",
"footer.status": "Status", "footer.status": "Status",
"footer.terms_of_service": "Terms of service",
"generic.saved": "Saved", "generic.saved": "Saved",
"getting_started.heading": "Getting started", "getting_started.heading": "Getting started",
"hashtag.admin_moderation": "Open moderation interface for #{name}", "hashtag.admin_moderation": "Open moderation interface for #{name}",
@ -857,6 +857,7 @@
"subscribed_languages.target": "Change subscribed languages for {target}", "subscribed_languages.target": "Change subscribed languages for {target}",
"tabs_bar.home": "Home", "tabs_bar.home": "Home",
"tabs_bar.notifications": "Notifications", "tabs_bar.notifications": "Notifications",
"terms_of_service.title": "Terms of Service",
"time_remaining.days": "{number, plural, one {# day} other {# days}} left", "time_remaining.days": "{number, plural, one {# day} other {# days}} left",
"time_remaining.hours": "{number, plural, one {# hour} other {# hours}} left", "time_remaining.hours": "{number, plural, one {# hour} other {# hours}} left",
"time_remaining.minutes": "{number, plural, one {# minute} other {# minutes}} left", "time_remaining.minutes": "{number, plural, one {# minute} other {# minutes}} left",

View File

@ -173,7 +173,9 @@ table + p {
} }
.email-prose { .email-prose {
p { p,
ul,
ol {
color: #17063b; color: #17063b;
font-size: 14px; font-size: 14px;
line-height: 20px; line-height: 20px;

View File

@ -253,6 +253,10 @@ $content-width: 840px;
.time-period { .time-period {
padding: 0 10px; padding: 0 10px;
} }
.back-link {
margin-bottom: 0;
}
} }
h2 small { h2 small {
@ -1940,3 +1944,76 @@ a.sparkline {
} }
} }
} }
.admin {
&__terms-of-service {
&__container {
background: var(--surface-background-color);
border-radius: 8px;
border: 1px solid var(--background-border-color);
overflow: hidden;
&__header {
padding: 16px;
font-size: 14px;
line-height: 20px;
color: $secondary-text-color;
display: flex;
align-items: center;
gap: 12px;
}
&__body {
background: var(--background-color);
padding: 16px;
overflow-y: scroll;
height: 30vh;
}
}
&__history {
& > li {
border-bottom: 1px solid var(--background-border-color);
&:last-child {
border-bottom: 0;
}
}
&__item {
padding: 16px 0;
padding-bottom: 8px;
h5 {
font-size: 14px;
line-height: 20px;
font-weight: 600;
margin-bottom: 16px;
}
}
}
}
}
.dot-indicator {
display: inline-flex;
align-items: center;
gap: 8px;
font-weight: 500;
&__indicator {
display: inline-block;
width: 8px;
height: 8px;
border-radius: 50%;
background: $dark-text-color;
}
&.success {
color: $valid-value-color;
.dot-indicator__indicator {
background-color: $valid-value-color;
}
}
}

View File

@ -209,6 +209,16 @@ class UserMailer < Devise::Mailer
end end
end end
def terms_of_service_changed(user, terms_of_service)
@resource = user
@terms_of_service = terms_of_service
@markdown = Redcarpet::Markdown.new(Redcarpet::Render::HTML, escape_html: true, no_images: true)
I18n.with_locale(locale) do
mail subject: default_i18n_subject
end
end
private private
def default_devise_subject def default_devise_subject

View File

@ -57,6 +57,7 @@ class Admin::ActionLogFilter
enable_relay: { target_type: 'Relay', action: 'enable' }.freeze, enable_relay: { target_type: 'Relay', action: 'enable' }.freeze,
memorialize_account: { target_type: 'Account', action: 'memorialize' }.freeze, memorialize_account: { target_type: 'Account', action: 'memorialize' }.freeze,
promote_user: { target_type: 'User', action: 'promote' }.freeze, promote_user: { target_type: 'User', action: 'promote' }.freeze,
publish_terms_of_service: { target_type: 'TermsOfService', action: 'publish' }.freeze,
remove_avatar_user: { target_type: 'User', action: 'remove_avatar' }.freeze, remove_avatar_user: { target_type: 'User', action: 'remove_avatar' }.freeze,
reopen_report: { target_type: 'Report', action: 'reopen' }.freeze, reopen_report: { target_type: 'Report', action: 'reopen' }.freeze,
resend_user: { target_type: 'User', action: 'resend' }.freeze, resend_user: { target_type: 'User', action: 'resend' }.freeze,

View File

@ -0,0 +1,34 @@
# frozen_string_literal: true
# == Schema Information
#
# Table name: terms_of_services
#
# id :bigint(8) not null, primary key
# changelog :text default(""), not null
# notification_sent_at :datetime
# published_at :datetime
# text :text default(""), not null
# created_at :datetime not null
# updated_at :datetime not null
#
class TermsOfService < ApplicationRecord
scope :published, -> { where.not(published_at: nil).order(published_at: :desc) }
scope :live, -> { published.limit(1) }
scope :draft, -> { where(published_at: nil).order(id: :desc).limit(1) }
validates :text, presence: true
validates :changelog, presence: true, if: -> { published? }
def published?
published_at.present?
end
def notification_sent?
notification_sent_at.present?
end
def scope_for_notification
User.confirmed.joins(:account).merge(Account.without_suspended).where(created_at: (..published_at))
end
end

View File

@ -0,0 +1,25 @@
# frozen_string_literal: true
class TermsOfService::Generator
include ActiveModel::Model
TEMPLATE = Rails.root.join('config', 'templates', 'terms-of-service.md').read
VARIABLES = %i(
admin_email
arbitration_address
arbitration_website
dmca_address
dmca_email
domain
jurisdiction
).freeze
attr_accessor(*VARIABLES)
validates(*VARIABLES, presence: true)
def render
format(TEMPLATE, VARIABLES.index_with { |key| public_send(key) })
end
end

View File

@ -0,0 +1,23 @@
# frozen_string_literal: true
class TermsOfServicePolicy < ApplicationPolicy
def index?
role.can?(:manage_settings)
end
def create?
role.can?(:manage_settings)
end
def distribute?
record.published? && !record.notification_sent? && role.can?(:manage_settings)
end
def update?
!record.published? && role.can?(:manage_settings)
end
def destroy?
!record.published? && role.can?(:manage_settings)
end
end

View File

@ -109,6 +109,7 @@ class InitialStateSerializer < ActiveModel::Serializer
trends_as_landing_page: Setting.trends_as_landing_page, trends_as_landing_page: Setting.trends_as_landing_page,
trends_enabled: Setting.trends, trends_enabled: Setting.trends,
version: instance_presenter.version, version: instance_presenter.version,
terms_of_service_enabled: TermsOfService.live.exists?,
} }
end end

View File

@ -0,0 +1,6 @@
.content__heading__tabs
= render_navigation renderer: :links do |primary|
:ruby
primary.item :current, safe_join([material_symbol('description'), t('admin.terms_of_service.current')]), admin_terms_of_service_index_path
primary.item :draft, safe_join([material_symbol('description'), t('admin.terms_of_service.draft')]), admin_terms_of_service_draft_path
primary.item :previous, safe_join([material_symbol('history'), t('admin.terms_of_service.history')]), admin_terms_of_service_history_path

View File

@ -0,0 +1,19 @@
- content_for :page_title do
= t('admin.terms_of_service.title')
- content_for :heading do
%h2= t('admin.terms_of_service.title')
= render partial: 'admin/terms_of_service/links'
= simple_form_for @terms_of_service, url: admin_terms_of_service_draft_path, method: :put do |form|
= render 'shared/error_messages', object: @terms_of_service
.fields-group
= form.input :text, wrapper: :with_block_label, input_html: { rows: 8 }
.fields-group
= form.input :changelog, wrapper: :with_block_label, input_html: { rows: 8 }
.actions
= form.button :button, t('admin.terms_of_service.save_draft'), type: :submit, name: :action_type, value: :save_draft, class: 'button button-secondary'
= form.button :button, t('admin.terms_of_service.publish'), type: :submit, name: :action_type, value: :publish

View File

@ -0,0 +1,41 @@
- content_for :page_title do
= t('admin.terms_of_service.generates.title')
- content_for :heading_actions do
.back-link
= link_to admin_terms_of_service_index_path do
= material_symbol 'chevron_left'
= t('admin.terms_of_service.back')
%p.lead= t('admin.terms_of_service.generates.explanation_html')
%p.lead= t('admin.terms_of_service.generates.chance_to_review_html')
%hr.spacer/
= simple_form_for @generator, url: admin_terms_of_service_generate_path, method: :post do |form|
= render 'shared/error_messages', object: @generator
.fields-group
= form.input :domain, wrapper: :with_label
.fields-group
= form.input :jurisdiction, wrapper: :with_label
.fields-group
= form.input :admin_email, wrapper: :with_label
.fields-group
= form.input :dmca_email, wrapper: :with_label
.fields-group
= form.input :dmca_address, wrapper: :with_label
.fields-group
= form.input :arbitration_address, wrapper: :with_label
.fields-group
= form.input :arbitration_website, wrapper: :with_label
.actions
= form.button :button, t('admin.terms_of_service.generates.action'), type: :submit

View File

@ -0,0 +1,16 @@
- content_for :page_title do
= t('admin.terms_of_service.history')
- content_for :heading do
%h2= t('admin.terms_of_service.title')
= render partial: 'admin/terms_of_service/links'
- if @terms_of_service.empty?
%p= t('admin.terms_of_service.no_history')
- else
%ol.admin__terms-of-service__history
- @terms_of_service.each do |terms_of_service|
%li
.admin__terms-of-service__history__item
%h5= l(terms_of_service.published_at)
.prose= markdown(terms_of_service.changelog)

View File

@ -0,0 +1,39 @@
- content_for :page_title do
= t('admin.terms_of_service.title')
- content_for :heading do
%h2= t('admin.terms_of_service.title')
= render partial: 'links'
- if @terms_of_service.present?
.admin__terms-of-service__container
.admin__terms-of-service__container__header
.dot-indicator.success
.dot-indicator__indicator
%span= t('admin.terms_of_service.live')
·
%span
= t('admin.terms_of_service.published_on_html', date: tag.time(l(@terms_of_service.published_at.to_date), class: 'formatted', date: @terms_of_service.published_at.to_date.iso8601))
·
- if @terms_of_service.notification_sent?
%span
= t('admin.terms_of_service.notified_on_html', date: tag.time(l(@terms_of_service.notification_sent_at.to_date), class: 'formatted', date: @terms_of_service.notification_sent_at.to_date.iso8601))
- else
= link_to t('admin.terms_of_service.notify_users'), admin_terms_of_service_preview_path(@terms_of_service), class: 'link-button'
.admin__terms-of-service__container__body
.prose
= markdown(@terms_of_service.text)
%hr.spacer/
%h3= t('admin.terms_of_service.changelog')
.prose
= markdown(@terms_of_service.changelog)
- else
%p.lead= t('admin.terms_of_service.no_terms_of_service_html')
.content__heading__actions
= link_to t('admin.terms_of_service.create'), admin_terms_of_service_draft_path, class: 'button'
= link_to t('admin.terms_of_service.generate'), admin_terms_of_service_generate_path, class: 'button button-secondary'

View File

@ -0,0 +1,20 @@
- content_for :page_title do
= t('admin.terms_of_service.preview.title')
- content_for :heading_actions do
.back-link
= link_to admin_terms_of_service_index_path do
= material_symbol 'chevron_left'
= t('admin.terms_of_service.back')
%p.lead
= t('admin.terms_of_service.preview.explanation_html', count: @user_count, display_count: number_with_delimiter(@user_count), date: l(@terms_of_service.published_at.to_date))
.prose
= markdown(@terms_of_service.changelog)
%hr.spacer/
.content__heading__actions
= link_to t('admin.terms_of_service.preview.send_preview', email: current_user.email), admin_terms_of_service_test_path(@terms_of_service), method: :post, class: 'button button-secondary'
= link_to t('admin.terms_of_service.preview.send_to_all', count: @user_count, display_count: number_with_delimiter(@user_count)), admin_terms_of_service_distribution_path(@terms_of_service), method: :post, class: 'button', data: { confirm: t('admin.reports.are_you_sure') }

View File

@ -72,7 +72,7 @@
.fields-group .fields-group
= f.input :agreement, = f.input :agreement,
as: :boolean, as: :boolean,
label: t('auth.privacy_policy_agreement_html', rules_path: about_more_path, privacy_policy_path: privacy_policy_path), label: t('auth.user_agreement_html', privacy_policy_path: privacy_policy_path, terms_of_service_path: terms_of_service_path),
required: false, required: false,
wrapper: :with_label wrapper: :with_label

View File

@ -0,0 +1,6 @@
- content_for :page_title, t('terms_of_service.title')
- content_for :header_tags do
= render partial: 'shared/og'
= render 'shared/web_app'

View File

@ -0,0 +1,17 @@
= content_for :heading do
= render 'application/mailer/heading',
image_url: frontend_asset_url('images/mailer-new/heading/user.png'),
subtitle: t('user_mailer.terms_of_service_changed.subtitle', domain: site_hostname),
title: t('user_mailer.terms_of_service_changed.title')
%table.email-w-full{ cellspacing: 0, cellpadding: 0, border: 0, role: 'presentation' }
%tr
%td.email-body-padding-td
%table.email-inner-card-table{ cellspacing: 0, cellpadding: 0, border: 0, role: 'presentation' }
%tr
%td.email-inner-card-td.email-prose
%p= t('user_mailer.terms_of_service_changed.description_html', path: terms_of_service_url, domain: site_hostname)
%p
%strong= t('user_mailer.terms_of_service_changed.changelog')
= markdown(@terms_of_service.changelog)
%p= t('user_mailer.terms_of_service_changed.agreement', domain: site_hostname)
%p= t('user_mailer.terms_of_service_changed.sign_off', domain: site_hostname)

View File

@ -0,0 +1,14 @@
<%= t('user_mailer.terms_of_service_changed.title') %>
===
<%= t('user_mailer.terms_of_service_changed.description', domain: site_hostname) %>
=> <%= terms_of_service_url %>
<%= t('user_mailer.terms_of_service_changed.changelog') %>
<%= @terms_of_service.changelog %>
<%= t('user_mailer.terms_of_service_changed.agreement', domain: site_hostname) %>
<%= t('user_mailer.terms_of_service_changed.sign_off', domain: site_hostname) %>

View File

@ -0,0 +1,15 @@
# frozen_string_literal: true
class Admin::DistributeTermsOfServiceNotificationWorker
include Sidekiq::Worker
def perform(terms_of_service_id)
terms_of_service = TermsOfService.find(terms_of_service_id)
terms_of_service.scope_for_notification.find_each do |user|
UserMailer.terms_of_service_changed(user, terms_of_service).deliver_later!
end
rescue ActiveRecord::RecordNotFound
true
end
end

View File

@ -919,7 +919,6 @@ an:
migrate_account: Mudar-se a unatra cuenta migrate_account: Mudar-se a unatra cuenta
migrate_account_html: Si deseyas reendrezar esta cuenta a unatra distinta, puetz <a href="%{path}">configurar-lo aquí</a>. migrate_account_html: Si deseyas reendrezar esta cuenta a unatra distinta, puetz <a href="%{path}">configurar-lo aquí</a>.
or_log_in_with: U inicia sesión con or_log_in_with: U inicia sesión con
privacy_policy_agreement_html: He leyiu y accepto la <a href="%{privacy_policy_path}" target="_blank">politica de privacidat</a>
providers: providers:
cas: CAS cas: CAS
saml: SAML saml: SAML

View File

@ -1118,7 +1118,6 @@ ar:
migrate_account: الانتقال إلى حساب مختلف migrate_account: الانتقال إلى حساب مختلف
migrate_account_html: إن كنت ترغب في تحويل هذا الحساب نحو حساب آخَر، يُمكِنُك <a href="%{path}">إعداده هنا</a>. migrate_account_html: إن كنت ترغب في تحويل هذا الحساب نحو حساب آخَر، يُمكِنُك <a href="%{path}">إعداده هنا</a>.
or_log_in_with: أو قم بتسجيل الدخول بواسطة or_log_in_with: أو قم بتسجيل الدخول بواسطة
privacy_policy_agreement_html: لقد قرأتُ وأوافق على سياسة الخصوصية <a href="%{privacy_policy_path}" target="_blank"></a>
progress: progress:
confirm: تأكيد عنوان البريد الإلكتروني confirm: تأكيد عنوان البريد الإلكتروني
details: تفاصيلك details: تفاصيلك

View File

@ -459,7 +459,6 @@ ast:
logout: Zarrar la sesión logout: Zarrar la sesión
migrate_account: Cambéu de cuenta migrate_account: Cambéu de cuenta
migrate_account_html: Si quies redirixir esta cuenta a otra diferente, pues <a href="%{path}">configurar esta opción equí</a>. migrate_account_html: Si quies redirixir esta cuenta a otra diferente, pues <a href="%{path}">configurar esta opción equí</a>.
privacy_policy_agreement_html: Lleí y acepto la <a href="%{privacy_policy_path}" target="_blank">política de privacidá</a>
providers: providers:
cas: CAS cas: CAS
saml: SAML saml: SAML

View File

@ -1134,7 +1134,6 @@ be:
migrate_account: Пераехаць на іншы ўліковы запіс migrate_account: Пераехаць на іншы ўліковы запіс
migrate_account_html: Калі вы хочаце перанакіраваць гэты ўліковы запіс на іншы, то можаце <a href="%{path}">наладзіць яго тут</a>. migrate_account_html: Калі вы хочаце перанакіраваць гэты ўліковы запіс на іншы, то можаце <a href="%{path}">наладзіць яго тут</a>.
or_log_in_with: Або ўвайсці з дапамогай or_log_in_with: Або ўвайсці з дапамогай
privacy_policy_agreement_html: Я азнаёміўся і пагаджаюся з <a href="%{privacy_policy_path}" target="_blank">палітыкай канфідэнцыйнасці</a>
progress: progress:
confirm: Пацвердзіць email confirm: Пацвердзіць email
details: Вашы дадзеныя details: Вашы дадзеныя

View File

@ -1121,7 +1121,6 @@ bg:
migrate_account: Преместване в различен акаунт migrate_account: Преместване в различен акаунт
migrate_account_html: Ако желаете да пренасочите този акаунт към друг, можете да <a href="%{path}">настроите това тук</a>. migrate_account_html: Ако желаете да пренасочите този акаунт към друг, можете да <a href="%{path}">настроите това тук</a>.
or_log_in_with: Или влизане с помощта на or_log_in_with: Или влизане с помощта на
privacy_policy_agreement_html: Прочетох и има съгласието ми за <a href="%{privacy_policy_path}" target="_blank">политиката за поверителност</a>
progress: progress:
details: Вашите подробности details: Вашите подробности
review: Нашият преглед review: Нашият преглед

View File

@ -1132,7 +1132,6 @@ ca:
migrate_account: Mou a un compte diferent migrate_account: Mou a un compte diferent
migrate_account_html: Si vols redirigir aquest compte a un altre diferent, el pots <a href="%{path}">configurar aquí</a>. migrate_account_html: Si vols redirigir aquest compte a un altre diferent, el pots <a href="%{path}">configurar aquí</a>.
or_log_in_with: O inicia sessió amb or_log_in_with: O inicia sessió amb
privacy_policy_agreement_html: He llegit i estic d'acord amb la <a href="%{privacy_policy_path}" target="_blank">política de privacitat</a>
progress: progress:
confirm: Confirmar email confirm: Confirmar email
details: Els teus detalls details: Els teus detalls

View File

@ -1099,7 +1099,6 @@ cs:
migrate_account: Přesunout se na jiný účet migrate_account: Přesunout se na jiný účet
migrate_account_html: Zde můžete <a href="%{path}">nastavit přesměrování tohoto účtu na jiný</a>. migrate_account_html: Zde můžete <a href="%{path}">nastavit přesměrování tohoto účtu na jiný</a>.
or_log_in_with: Nebo se přihlaste pomocí or_log_in_with: Nebo se přihlaste pomocí
privacy_policy_agreement_html: Četl jsem a souhlasím se zásadami <a href="%{privacy_policy_path}" target="_blank">ochrany osobních údajů</a>
progress: progress:
details: Vaše údaje details: Vaše údaje
review: Naše hodnocení review: Naše hodnocení

View File

@ -1204,7 +1204,6 @@ cy:
migrate_account: Symud i gyfrif gwahanol migrate_account: Symud i gyfrif gwahanol
migrate_account_html: Os hoffech chi ailgyfeirio'r cyfrif hwn at un gwahanol, mae modd <a href="%{path}">ei ffurfweddu yma</a>. migrate_account_html: Os hoffech chi ailgyfeirio'r cyfrif hwn at un gwahanol, mae modd <a href="%{path}">ei ffurfweddu yma</a>.
or_log_in_with: Neu mewngofnodwch gyda or_log_in_with: Neu mewngofnodwch gyda
privacy_policy_agreement_html: Rwyf wedi darllen ac yn cytuno i'r <a href="%{privacy_policy_path}" target="_blank">polisi preifatrwydd</a>
progress: progress:
confirm: Cadarnhau'r e-bost confirm: Cadarnhau'r e-bost
details: Eich manylion details: Eich manylion

View File

@ -1132,7 +1132,6 @@ da:
migrate_account: Flyt til en anden konto migrate_account: Flyt til en anden konto
migrate_account_html: Ønsker du at omdirigere denne konto til en anden, kan du <a href="%{path}">opsætte dette hér</a>. migrate_account_html: Ønsker du at omdirigere denne konto til en anden, kan du <a href="%{path}">opsætte dette hér</a>.
or_log_in_with: Eller log ind med or_log_in_with: Eller log ind med
privacy_policy_agreement_html: Jeg accepterer <a href="%{privacy_policy_path}" target="_blank">privatlivspolitikken</a>
progress: progress:
confirm: Bekræft e-mail confirm: Bekræft e-mail
details: Dine detaljer details: Dine detaljer

View File

@ -1132,7 +1132,6 @@ de:
migrate_account: Zu einem anderen Konto umziehen migrate_account: Zu einem anderen Konto umziehen
migrate_account_html: Wenn du dieses Konto auf ein anderes weiterleiten möchtest, kannst du es <a href="%{path}">hier konfigurieren</a>. migrate_account_html: Wenn du dieses Konto auf ein anderes weiterleiten möchtest, kannst du es <a href="%{path}">hier konfigurieren</a>.
or_log_in_with: Oder anmelden mit or_log_in_with: Oder anmelden mit
privacy_policy_agreement_html: Ich habe die <a href="%{privacy_policy_path}" target="_blank">Datenschutzerklärung</a> gelesen und stimme ihr zu
progress: progress:
confirm: E-Mail bestätigen confirm: E-Mail bestätigen
details: Deine Daten details: Deine Daten

View File

@ -1132,7 +1132,6 @@ el:
migrate_account: Μεταφορά σε διαφορετικό λογαριασμό migrate_account: Μεταφορά σε διαφορετικό λογαριασμό
migrate_account_html: Αν θέλεις να ανακατευθύνεις αυτό τον λογαριασμό σε έναν διαφορετικό, μπορείς να το <a href="%{path}">διαμορφώσεις εδώ</a>. migrate_account_html: Αν θέλεις να ανακατευθύνεις αυτό τον λογαριασμό σε έναν διαφορετικό, μπορείς να το <a href="%{path}">διαμορφώσεις εδώ</a>.
or_log_in_with: Ή συνδέσου με or_log_in_with: Ή συνδέσου με
privacy_policy_agreement_html: Έχω διαβάσει και συμφωνώ με την <a href="%{privacy_policy_path}" target="_blank">πολιτική απορρήτου</a>
progress: progress:
confirm: Επιβεβαίωση email confirm: Επιβεβαίωση email
details: Τα στοιχεία σας details: Τα στοιχεία σας

View File

@ -1132,7 +1132,6 @@ en-GB:
migrate_account: Move to a different account migrate_account: Move to a different account
migrate_account_html: If you wish to redirect this account to a different one, you can <a href="%{path}">configure it here</a>. migrate_account_html: If you wish to redirect this account to a different one, you can <a href="%{path}">configure it here</a>.
or_log_in_with: Or log in with or_log_in_with: Or log in with
privacy_policy_agreement_html: I have read and agree to the <a href="%{privacy_policy_path}" target="_blank">privacy policy</a>
progress: progress:
confirm: Confirm email confirm: Confirm email
details: Your details details: Your details

View File

@ -214,6 +214,7 @@ en:
enable_user: Enable User enable_user: Enable User
memorialize_account: Memorialize Account memorialize_account: Memorialize Account
promote_user: Promote User promote_user: Promote User
publish_terms_of_service: Publish Terms of Service
reject_appeal: Reject Appeal reject_appeal: Reject Appeal
reject_user: Reject User reject_user: Reject User
remove_avatar_user: Remove Avatar remove_avatar_user: Remove Avatar
@ -278,6 +279,7 @@ en:
enable_user_html: "%{name} enabled login for user %{target}" enable_user_html: "%{name} enabled login for user %{target}"
memorialize_account_html: "%{name} turned %{target}'s account into a memoriam page" memorialize_account_html: "%{name} turned %{target}'s account into a memoriam page"
promote_user_html: "%{name} promoted user %{target}" promote_user_html: "%{name} promoted user %{target}"
publish_terms_of_service_html: "%{name} published updates to the terms of service"
reject_appeal_html: "%{name} rejected moderation decision appeal from %{target}" reject_appeal_html: "%{name} rejected moderation decision appeal from %{target}"
reject_user_html: "%{name} rejected sign-up from %{target}" reject_user_html: "%{name} rejected sign-up from %{target}"
remove_avatar_user_html: "%{name} removed %{target}'s avatar" remove_avatar_user_html: "%{name} removed %{target}'s avatar"
@ -925,6 +927,35 @@ en:
search: Search search: Search
title: Hashtags title: Hashtags
updated_msg: Hashtag settings updated successfully updated_msg: Hashtag settings updated successfully
terms_of_service:
back: Back to terms of service
changelog: What's changed
create: Use your own
current: Current
draft: Draft
generate: Use template
generates:
action: Generate
chance_to_review_html: "<strong>The generated terms of service will not be published automatically.</strong> You will have a chance to review the results. Please fill in the necessary details to proceed."
explanation_html: The terms of service template provided is for informational purposes only, and should not be construed as legal advice on any subject matter. Please consult with your own legal counsel on your situation and specific legal questions you have.
title: Terms of Service Setup
history: History
live: Live
no_history: There are no recorded changes of the terms of service yet.
no_terms_of_service_html: You don't currently have any terms of service configured. Terms of service are meant to provide clarity and protect you from potential liabilities in disputes with your users.
notified_on_html: Users notified on %{date}
notify_users: Notify users
preview:
explanation_html: 'The email will be sent to <strong>%{display_count} users</strong> who have signed up before %{date}. The following text will be included in the e-mail:'
send_preview: Send preview to %{email}
send_to_all:
one: Send %{display_count} email
other: Send %{display_count} emails
title: Preview terms of service notification
publish: Publish
published_on_html: Published on %{date}
save_draft: Save draft
title: Terms of Service
title: Administration title: Administration
trends: trends:
allow: Allow allow: Allow
@ -1132,7 +1163,6 @@ en:
migrate_account: Move to a different account migrate_account: Move to a different account
migrate_account_html: If you wish to redirect this account to a different one, you can <a href="%{path}">configure it here</a>. migrate_account_html: If you wish to redirect this account to a different one, you can <a href="%{path}">configure it here</a>.
or_log_in_with: Or log in with or_log_in_with: Or log in with
privacy_policy_agreement_html: I have read and agree to the <a href="%{privacy_policy_path}" target="_blank">privacy policy</a>
progress: progress:
confirm: Confirm email confirm: Confirm email
details: Your details details: Your details
@ -1178,6 +1208,7 @@ en:
view_strikes: View past strikes against your account view_strikes: View past strikes against your account
too_fast: Form submitted too fast, try again. too_fast: Form submitted too fast, try again.
use_security_key: Use security key use_security_key: Use security key
user_agreement_html: I have read and agree to the <a href="%{terms_of_service_path}" target="_blank">terms of service</a> and <a href="%{privacy_policy_path}" target="_blank">privacy policy</a>
author_attribution: author_attribution:
example_title: Sample text example_title: Sample text
hint_html: Are you writing news or blog articles outside of Mastodon? Control how you get credited when they are shared on Mastodon. hint_html: Are you writing news or blog articles outside of Mastodon? Control how you get credited when they are shared on Mastodon.
@ -1840,6 +1871,8 @@ en:
too_late: It is too late to appeal this strike too_late: It is too late to appeal this strike
tags: tags:
does_not_match_previous_name: does not match the previous name does_not_match_previous_name: does not match the previous name
terms_of_service:
title: Terms of Service
themes: themes:
contrast: Mastodon (High contrast) contrast: Mastodon (High contrast)
default: Mastodon (Dark) default: Mastodon (Dark)
@ -1900,6 +1933,15 @@ en:
further_actions_html: If this wasn't you, we recommend that you %{action} immediately and enable two-factor authentication to keep your account secure. further_actions_html: If this wasn't you, we recommend that you %{action} immediately and enable two-factor authentication to keep your account secure.
subject: Your account has been accessed from a new IP address subject: Your account has been accessed from a new IP address
title: A new sign-in title: A new sign-in
terms_of_service_changed:
agreement: By continuing to use %{domain}, you are agreeing to these terms. If you disagree with the updated terms, you may terminate your agreement with %{domain} at any time by deleting your account.
changelog: 'At a glance, here is what this update means for you:'
description: 'You are receiving this e-mail because we''re making some changes to our terms of service at %{domain}. We encourage you to review the updated terms in full here:'
description_html: You are receiving this e-mail because we're making some changes to our terms of service at %{domain}. We encourage you to review the <a href="%{path}" target="_blank">updated terms in full here</a>.
sign_off: The %{domain} team
subject: Updates to our terms of service
subtitle: The terms of service of %{domain} are changing
title: Important update
warning: warning:
appeal: Submit an appeal appeal: Submit an appeal
appeal_description: If you believe this is an error, you can submit an appeal to the staff of %{instance}. appeal_description: If you believe this is an error, you can submit an appeal to the staff of %{instance}.

View File

@ -1132,7 +1132,6 @@ eo:
migrate_account: Movi al alia konto migrate_account: Movi al alia konto
migrate_account_html: Se vi deziras alidirekti ĉi tiun konton al alia, vi povas <a href="%{path}">agordi ĝin ĉi tie</a>. migrate_account_html: Se vi deziras alidirekti ĉi tiun konton al alia, vi povas <a href="%{path}">agordi ĝin ĉi tie</a>.
or_log_in_with: Aŭ saluti per or_log_in_with: Aŭ saluti per
privacy_policy_agreement_html: Mi legis kaj konsentis pri <a href="%{privacy_policy_path}" target="_blank">privatpolitiko</a>
progress: progress:
confirm: Konfirmi retadreson confirm: Konfirmi retadreson
details: Viaj detaloj details: Viaj detaloj

View File

@ -1132,7 +1132,6 @@ es-AR:
migrate_account: Mudarse a otra cuenta migrate_account: Mudarse a otra cuenta
migrate_account_html: Si querés redireccionar esta cuenta a otra distinta, podés <a href="%{path}">configurar eso acá</a>. migrate_account_html: Si querés redireccionar esta cuenta a otra distinta, podés <a href="%{path}">configurar eso acá</a>.
or_log_in_with: O iniciar sesión con or_log_in_with: O iniciar sesión con
privacy_policy_agreement_html: Leí y acepto la <a href="%{privacy_policy_path}" target="_blank">política de privacidad</a>
progress: progress:
confirm: Confirmar correo electrónico confirm: Confirmar correo electrónico
details: Tus detalles details: Tus detalles

View File

@ -1132,7 +1132,6 @@ es-MX:
migrate_account: Mudarse a otra cuenta migrate_account: Mudarse a otra cuenta
migrate_account_html: Si deseas redireccionar esta cuenta a otra distinta, puedes <a href="%{path}">configurarlo aquí</a>. migrate_account_html: Si deseas redireccionar esta cuenta a otra distinta, puedes <a href="%{path}">configurarlo aquí</a>.
or_log_in_with: O inicia sesión con or_log_in_with: O inicia sesión con
privacy_policy_agreement_html: He leído y acepto la <a href="%{privacy_policy_path}" target="_blank">política de privacidad</a>
progress: progress:
confirm: Confirmar dirección de correo confirm: Confirmar dirección de correo
details: Tus detalles details: Tus detalles

View File

@ -1132,7 +1132,6 @@ es:
migrate_account: Mudarse a otra cuenta migrate_account: Mudarse a otra cuenta
migrate_account_html: Si deseas redireccionar esta cuenta a otra distinta, puedes <a href="%{path}">configurarlo aquí</a>. migrate_account_html: Si deseas redireccionar esta cuenta a otra distinta, puedes <a href="%{path}">configurarlo aquí</a>.
or_log_in_with: O inicia sesión con or_log_in_with: O inicia sesión con
privacy_policy_agreement_html: He leído y acepto la <a href="%{privacy_policy_path}" target="_blank">política de privacidad</a>
progress: progress:
confirm: Confirmar dirección de correo confirm: Confirmar dirección de correo
details: Tus detalles details: Tus detalles

View File

@ -1117,7 +1117,6 @@ et:
migrate_account: Teisele kontole ära kolimine migrate_account: Teisele kontole ära kolimine
migrate_account_html: Kui soovid konto siit ära kolida, <a href="%{path}">saad seda teha siin</a>. migrate_account_html: Kui soovid konto siit ära kolida, <a href="%{path}">saad seda teha siin</a>.
or_log_in_with: Või logi sisse koos or_log_in_with: Või logi sisse koos
privacy_policy_agreement_html: Olen tutvunud <a href="%{privacy_policy_path}" target="_blank">isikuandmete kaitse põhimõtetega</a> ja nõustun nendega
progress: progress:
confirm: E-posti kinnitamine confirm: E-posti kinnitamine
details: Sinu üksikasjad details: Sinu üksikasjad

View File

@ -1041,7 +1041,6 @@ eu:
migrate_account: Migratu beste kontu batera migrate_account: Migratu beste kontu batera
migrate_account_html: Kontu hau beste batera birbideratu nahi baduzu, <a href="%{path}">hemen konfiguratu</a> dezakezu. migrate_account_html: Kontu hau beste batera birbideratu nahi baduzu, <a href="%{path}">hemen konfiguratu</a> dezakezu.
or_log_in_with: Edo hasi saioa honekin or_log_in_with: Edo hasi saioa honekin
privacy_policy_agreement_html: <a href="%{privacy_policy_path}" target="_blank">Pribatutasun politika</a> irakurri dut eta ados nago
progress: progress:
details: Zure xehetasunak details: Zure xehetasunak
review: Gure berrikuspena review: Gure berrikuspena

View File

@ -978,7 +978,6 @@ fa:
migrate_account: نقل مکان به یک حساب دیگر migrate_account: نقل مکان به یک حساب دیگر
migrate_account_html: اگر می‌خواهید این حساب را به حساب دیگری منتقل کنید، <a href="%{path}">این‌جا را کلیک کنید</a>. migrate_account_html: اگر می‌خواهید این حساب را به حساب دیگری منتقل کنید، <a href="%{path}">این‌جا را کلیک کنید</a>.
or_log_in_with: یا ورود به وسیلهٔ or_log_in_with: یا ورود به وسیلهٔ
privacy_policy_agreement_html: <a href="%{privacy_policy_path}" target="_blank">سیاست محرمانگی</a> را خوانده و پذیرفته‌ام
progress: progress:
confirm: تأیید رایانامه confirm: تأیید رایانامه
details: جزئیات شما details: جزئیات شما

View File

@ -1132,7 +1132,6 @@ fi:
migrate_account: Muuta toiseen tiliin migrate_account: Muuta toiseen tiliin
migrate_account_html: Jos haluat ohjata tämän tilin toiseen, voit <a href="%{path}">asettaa toisen tilin tästä</a>. migrate_account_html: Jos haluat ohjata tämän tilin toiseen, voit <a href="%{path}">asettaa toisen tilin tästä</a>.
or_log_in_with: Tai käytä kirjautumiseen or_log_in_with: Tai käytä kirjautumiseen
privacy_policy_agreement_html: Olen lukenut ja hyväksyn <a href="%{privacy_policy_path}" target="_blank">tietosuojakäytännön</a>
progress: progress:
confirm: Vahvista sähköpostiosoite confirm: Vahvista sähköpostiosoite
details: Omat tietosi details: Omat tietosi

View File

@ -1132,7 +1132,6 @@ fo:
migrate_account: Flyt til eina aðra kontu migrate_account: Flyt til eina aðra kontu
migrate_account_html: Ynskir tú at víðaribeina hesa kontuna til eina aðra, so kanst tú <a href="%{path}">seta tað upp her</a>. migrate_account_html: Ynskir tú at víðaribeina hesa kontuna til eina aðra, so kanst tú <a href="%{path}">seta tað upp her</a>.
or_log_in_with: Ella innrita við or_log_in_with: Ella innrita við
privacy_policy_agreement_html: Eg havi lisið og taki undir við <a href="%{privacy_policy_path}" target="_blank">privatlívspolitikkinum</a>
progress: progress:
confirm: Vátta teldupost confirm: Vátta teldupost
details: Tínir smálutir details: Tínir smálutir

View File

@ -1135,7 +1135,6 @@ fr-CA:
migrate_account: Déménager vers un compte différent migrate_account: Déménager vers un compte différent
migrate_account_html: Si vous voulez rediriger ce compte vers un autre, vous pouvez le <a href="%{path}">configurer ici</a>. migrate_account_html: Si vous voulez rediriger ce compte vers un autre, vous pouvez le <a href="%{path}">configurer ici</a>.
or_log_in_with: Ou authentifiez-vous avec or_log_in_with: Ou authentifiez-vous avec
privacy_policy_agreement_html: Jai lu et jaccepte la <a href="%{privacy_policy_path}" target="_blank">politique de confidentialité</a>
progress: progress:
confirm: Confirmation de l'adresse mail confirm: Confirmation de l'adresse mail
details: Vos infos details: Vos infos

View File

@ -1135,7 +1135,6 @@ fr:
migrate_account: Déménager vers un compte différent migrate_account: Déménager vers un compte différent
migrate_account_html: Si vous voulez rediriger ce compte vers un autre, vous pouvez le <a href="%{path}">configurer ici</a>. migrate_account_html: Si vous voulez rediriger ce compte vers un autre, vous pouvez le <a href="%{path}">configurer ici</a>.
or_log_in_with: Ou authentifiez-vous avec or_log_in_with: Ou authentifiez-vous avec
privacy_policy_agreement_html: Jai lu et jaccepte la <a href="%{privacy_policy_path}" target="_blank">politique de confidentialité</a>
progress: progress:
confirm: Confirmation de l'adresse mail confirm: Confirmation de l'adresse mail
details: Vos infos details: Vos infos

View File

@ -1117,7 +1117,6 @@ fy:
migrate_account: Nei in oar account ferhúzje migrate_account: Nei in oar account ferhúzje
migrate_account_html: Wanneart jo dizze account nei in oare account trochferwize wolle, kinne jo <a href="%{path}">dit hjir ynstelle</a>. migrate_account_html: Wanneart jo dizze account nei in oare account trochferwize wolle, kinne jo <a href="%{path}">dit hjir ynstelle</a>.
or_log_in_with: Of oanmelde mei or_log_in_with: Of oanmelde mei
privacy_policy_agreement_html: Ik haw it <a href="%{privacy_policy_path}" target="_blank">privacybelied</a> lêzen en gean dêrmei akkoard
progress: progress:
confirm: E-mailadres werhelje confirm: E-mailadres werhelje
details: Jo gegevens details: Jo gegevens

View File

@ -1186,7 +1186,6 @@ ga:
migrate_account: Bog chuig cuntas eile migrate_account: Bog chuig cuntas eile
migrate_account_html: Más mian leat an cuntas seo a atreorú chuig ceann eile, is féidir leat <a href="%{path}">é a chumrú anseo</a>. migrate_account_html: Más mian leat an cuntas seo a atreorú chuig ceann eile, is féidir leat <a href="%{path}">é a chumrú anseo</a>.
or_log_in_with: Nó logáil isteach le or_log_in_with: Nó logáil isteach le
privacy_policy_agreement_html: Léigh mé agus aontaím leis an <a href="%{privacy_policy_path}" target="_blank">polasaí príobháideachais</a>
progress: progress:
confirm: Deimhnigh ríomhphost confirm: Deimhnigh ríomhphost
details: Do chuid sonraí details: Do chuid sonraí

View File

@ -1168,7 +1168,6 @@ gd:
migrate_account: Imrich gu cunntas eile migrate_account: Imrich gu cunntas eile
migrate_account_html: Nam bu mhiann leat an cunntas seo ath-stiùireadh gu fear eile, s urrainn dhut <a href="%{path}">a rèiteachadh an-seo</a>. migrate_account_html: Nam bu mhiann leat an cunntas seo ath-stiùireadh gu fear eile, s urrainn dhut <a href="%{path}">a rèiteachadh an-seo</a>.
or_log_in_with: No clàraich a-steach le or_log_in_with: No clàraich a-steach le
privacy_policy_agreement_html: Leugh mi is tha mi ag aontachadh ris a <a href="%{privacy_policy_path}" target="_blank">phoileasaidh prìobhaideachd</a>
progress: progress:
confirm: Dearbh am post-d confirm: Dearbh am post-d
details: Am fiosrachadh agad details: Am fiosrachadh agad

View File

@ -1132,7 +1132,6 @@ gl:
migrate_account: Mover a unha conta diferente migrate_account: Mover a unha conta diferente
migrate_account_html: Se queres redirixir esta conta hacia outra diferente, podes <a href="%{path}">facelo aquí</a>. migrate_account_html: Se queres redirixir esta conta hacia outra diferente, podes <a href="%{path}">facelo aquí</a>.
or_log_in_with: Ou accede con or_log_in_with: Ou accede con
privacy_policy_agreement_html: Lin e acepto a <a href="%{privacy_policy_path}" target="_blank">política de privacidade</a>
progress: progress:
confirm: Confirmar correo confirm: Confirmar correo
details: Detalles details: Detalles

View File

@ -1168,7 +1168,6 @@ he:
migrate_account: מעבר לחשבון אחר migrate_account: מעבר לחשבון אחר
migrate_account_html: אם ברצונך להכווין את החשבון לעבר חשבון אחר, ניתן <a href="%{path}">להגדיר זאת כאן</a>. migrate_account_html: אם ברצונך להכווין את החשבון לעבר חשבון אחר, ניתן <a href="%{path}">להגדיר זאת כאן</a>.
or_log_in_with: או התחבר באמצעות or_log_in_with: או התחבר באמצעות
privacy_policy_agreement_html: קראתי והסכמתי ל<a href="%{privacy_policy_path}" target="_blank">מדיניות הפרטיות</a>
progress: progress:
confirm: אימות כתובת הדואל confirm: אימות כתובת הדואל
details: הפרטים שלך details: הפרטים שלך

View File

@ -1132,7 +1132,6 @@ hu:
migrate_account: Felhasználói fiók költöztetése migrate_account: Felhasználói fiók költöztetése
migrate_account_html: Ha át szeretnéd irányítani ezt a fiókodat egy másikra, akkor <a href="%{path}">itt állíthatod be</a>. migrate_account_html: Ha át szeretnéd irányítani ezt a fiókodat egy másikra, akkor <a href="%{path}">itt állíthatod be</a>.
or_log_in_with: Vagy jelentkezz be ezzel or_log_in_with: Vagy jelentkezz be ezzel
privacy_policy_agreement_html: Elolvastam és egyetértek az <a href="%{privacy_policy_path}" target="_blank">adatvédemi nyilatkozattal</a>
progress: progress:
confirm: E-mail megerősítése confirm: E-mail megerősítése
details: Saját adatok details: Saját adatok

View File

@ -462,7 +462,6 @@ hy:
logout: Դուրս գալ logout: Դուրս գալ
migrate_account: Տեղափոխուել այլ հաշիւ migrate_account: Տեղափոխուել այլ հաշիւ
or_log_in_with: Կամ մուտք գործել օգտագործելով՝ or_log_in_with: Կամ մուտք գործել օգտագործելով՝
privacy_policy_agreement_html: Ես կարդացել եւ ընդունել եմ <a href="%{privacy_policy_path}" target="_blank">գաղնիութեան քաղաքականութիւնը</a>
progress: progress:
details: Ձեր տուեալները details: Ձեր տուեալները
review: Վաւերացում review: Վաւերացում

View File

@ -1132,7 +1132,6 @@ ia:
migrate_account: Migrar a un altere conto migrate_account: Migrar a un altere conto
migrate_account_html: Si tu vole rediriger iste conto a un altere, tu pote <a href="%{path}">configurar lo hic</a>. migrate_account_html: Si tu vole rediriger iste conto a un altere, tu pote <a href="%{path}">configurar lo hic</a>.
or_log_in_with: O aperi session con or_log_in_with: O aperi session con
privacy_policy_agreement_html: Io ha legite e accepta le <a href="%{privacy_policy_path}" target="_blank">politica de confidentialitate</a>
progress: progress:
confirm: Confirmar e-mail confirm: Confirmar e-mail
details: Tu detalios details: Tu detalios

View File

@ -903,7 +903,6 @@ id:
migrate_account: Pindah ke akun berbeda migrate_account: Pindah ke akun berbeda
migrate_account_html: Jika Anda ingin mengalihkan akun ini ke akun lain, Anda dapat <a href="%{path}">mengaturnya di sini</a>. migrate_account_html: Jika Anda ingin mengalihkan akun ini ke akun lain, Anda dapat <a href="%{path}">mengaturnya di sini</a>.
or_log_in_with: Atau masuk dengan or_log_in_with: Atau masuk dengan
privacy_policy_agreement_html: Saya telah membaca dan menerima <a href="%{privacy_policy_path}" target="_blank">kebijakan privasi</a>
providers: providers:
cas: CAS cas: CAS
saml: SAML saml: SAML

View File

@ -1039,7 +1039,6 @@ ie:
migrate_account: Mover te a un conto diferent migrate_account: Mover te a un conto diferent
migrate_account_html: Si tu vole redirecter ti-ci conto a un altri, tu posse <a href="%{path}">configurar it ci</a>. migrate_account_html: Si tu vole redirecter ti-ci conto a un altri, tu posse <a href="%{path}">configurar it ci</a>.
or_log_in_with: O intrar med or_log_in_with: O intrar med
privacy_policy_agreement_html: Yo leet e consenti li <a href="%{privacy_policy_path}" target="_blank">politica pri privatie</a>
progress: progress:
details: Tui detallies details: Tui detallies
review: Nor revise review: Nor revise

View File

@ -1014,7 +1014,6 @@ io:
migrate_account: Transferez a diferanta konto migrate_account: Transferez a diferanta konto
migrate_account_html: Se vu volas ridirektar ca konto a diferanto, vu povas <a href="%{path}">ajustar hike</a>. migrate_account_html: Se vu volas ridirektar ca konto a diferanto, vu povas <a href="%{path}">ajustar hike</a>.
or_log_in_with: O eniras per or_log_in_with: O eniras per
privacy_policy_agreement_html: Me lektis e konsentis <a href="%{privacy_policy_path}" target="_blank">privatesguidilo</a>
progress: progress:
details: Vua detali details: Vua detali
review: Nia revuo review: Nia revuo

View File

@ -1136,7 +1136,6 @@ is:
migrate_account: Færa á annan notandaaðgang migrate_account: Færa á annan notandaaðgang
migrate_account_html: Ef þú vilt endurbeina þessum aðgangi á einhvern annan, geturðu <a href="%{path}">stillt það hér</a>. migrate_account_html: Ef þú vilt endurbeina þessum aðgangi á einhvern annan, geturðu <a href="%{path}">stillt það hér</a>.
or_log_in_with: Eða skráðu inn með or_log_in_with: Eða skráðu inn með
privacy_policy_agreement_html: Ég hef lesið og samþykkt <a href="%{privacy_policy_path}" target="_blank">persónuverndarstefnuna</a>
progress: progress:
confirm: Staðfesta tölvupóstfang confirm: Staðfesta tölvupóstfang
details: Nánari upplýsingar þínar details: Nánari upplýsingar þínar

View File

@ -1134,7 +1134,6 @@ it:
migrate_account: Sposta ad un account differente migrate_account: Sposta ad un account differente
migrate_account_html: Se vuoi che questo account sia reindirizzato a uno diverso, puoi <a href="%{path}">configurarlo qui</a>. migrate_account_html: Se vuoi che questo account sia reindirizzato a uno diverso, puoi <a href="%{path}">configurarlo qui</a>.
or_log_in_with: Oppure accedi con or_log_in_with: Oppure accedi con
privacy_policy_agreement_html: Ho letto e accetto l'<a href="%{privacy_policy_path}" target="_blank">informativa sulla privacy</a>
progress: progress:
confirm: Conferma l'e-mail confirm: Conferma l'e-mail
details: I tuoi dettagli details: I tuoi dettagli

View File

@ -1114,7 +1114,6 @@ ja:
migrate_account: 別のアカウントに引っ越す migrate_account: 別のアカウントに引っ越す
migrate_account_html: 引っ越し先を明記したい場合は<a href="%{path}">こちら</a>で設定できます。 migrate_account_html: 引っ越し先を明記したい場合は<a href="%{path}">こちら</a>で設定できます。
or_log_in_with: または次のサービスでログイン or_log_in_with: または次のサービスでログイン
privacy_policy_agreement_html: <a href="%{privacy_policy_path}" target="_blank">プライバシーポリシー</a>を読み、同意します
progress: progress:
confirm: メールアドレスの確認 confirm: メールアドレスの確認
details: ユーザー情報 details: ユーザー情報

View File

@ -495,7 +495,6 @@ kab:
logout: Ffeɣ logout: Ffeɣ
migrate_account: Gujj ɣer umiḍan nniḍen migrate_account: Gujj ɣer umiḍan nniḍen
or_log_in_with: Neɣ eqqen s or_log_in_with: Neɣ eqqen s
privacy_policy_agreement_html: Ɣriɣ yerna qebleɣ <a href="%{privacy_policy_path}" target="_blank">tasertit n tbaḍnit</a>
progress: progress:
confirm: Sentem imayl confirm: Sentem imayl
details: Isalli-inek details: Isalli-inek

View File

@ -1116,7 +1116,6 @@ ko:
migrate_account: 계정 옮기기 migrate_account: 계정 옮기기
migrate_account_html: 이 계정을 다른 계정으로 리디렉션 하길 원하는 경우 <a href="%{path}">여기</a>에서 설정할 수 있습니다. migrate_account_html: 이 계정을 다른 계정으로 리디렉션 하길 원하는 경우 <a href="%{path}">여기</a>에서 설정할 수 있습니다.
or_log_in_with: 다른 방법으로 로그인 하려면 or_log_in_with: 다른 방법으로 로그인 하려면
privacy_policy_agreement_html: <a href="%{privacy_policy_path}" target="_blank">개인정보처리방침</a>을 읽고 동의합니다
progress: progress:
confirm: 이메일 확인 confirm: 이메일 확인
details: 세부사항 details: 세부사항

View File

@ -916,7 +916,6 @@ ku:
migrate_account: Livandin bo ajimêreke din migrate_account: Livandin bo ajimêreke din
migrate_account_html: Ku tu dixwazî ev ajimêr li ajimêreke cuda beralî bikî, tu dikarî <a href="%{path}">ji vir de saz bike</a>. migrate_account_html: Ku tu dixwazî ev ajimêr li ajimêreke cuda beralî bikî, tu dikarî <a href="%{path}">ji vir de saz bike</a>.
or_log_in_with: An têketinê bike bi riya or_log_in_with: An têketinê bike bi riya
privacy_policy_agreement_html: Min <a href="%{privacy_policy_path}" target="_blank">Politîka taybetiyê</a> xwend û dipejirînim
providers: providers:
cas: CAS cas: CAS
saml: SAML saml: SAML

View File

@ -1097,7 +1097,6 @@ lad:
migrate_account: Transferate a otro kuento migrate_account: Transferate a otro kuento
migrate_account_html: Si keres readresar este kuento a otra distinta, puedes <a href="%{path}">konfigurarlo aki</a>. migrate_account_html: Si keres readresar este kuento a otra distinta, puedes <a href="%{path}">konfigurarlo aki</a>.
or_log_in_with: O konektate kon tu kuento kon or_log_in_with: O konektate kon tu kuento kon
privacy_policy_agreement_html: Tengo meldado i acheto la <a href="%{privacy_policy_path}" target="_blank">politika de privasita</a>
progress: progress:
confirm: Konfirma posta confirm: Konfirma posta
details: Tus detalyos details: Tus detalyos

View File

@ -795,7 +795,6 @@ lt:
migrate_account: Persikelti prie kitos paskyros migrate_account: Persikelti prie kitos paskyros
migrate_account_html: Jei nori šią paskyrą nukreipti į kitą, gali <a href="%{path}">sukonfigūruoti ją čia</a>. migrate_account_html: Jei nori šią paskyrą nukreipti į kitą, gali <a href="%{path}">sukonfigūruoti ją čia</a>.
or_log_in_with: Arba prisijungti su or_log_in_with: Arba prisijungti su
privacy_policy_agreement_html: Perskaičiau ir sutinku su <a href="%{privacy_policy_path}" target="_blank">privatumo politika</a>
progress: progress:
details: Tavo duomenys details: Tavo duomenys
review: Mūsų peržiūra review: Mūsų peržiūra

View File

@ -1110,7 +1110,6 @@ lv:
migrate_account: Pāriešana uz citu kontu migrate_account: Pāriešana uz citu kontu
migrate_account_html: Ja vēlies novirzīt šo kontu uz citu, tu vari <a href="%{path}">to konfigurēt šeit</a>. migrate_account_html: Ja vēlies novirzīt šo kontu uz citu, tu vari <a href="%{path}">to konfigurēt šeit</a>.
or_log_in_with: Vai piesakies ar or_log_in_with: Vai piesakies ar
privacy_policy_agreement_html: Esmu izlasījis un piekrītu <a href="%{privacy_policy_path}" target="_blank">privātuma politikai</a>
progress: progress:
confirm: Apstiprināt e-pasta adresi confirm: Apstiprināt e-pasta adresi
details: Tavi dati details: Tavi dati

View File

@ -1001,7 +1001,6 @@ ms:
migrate_account: Pindah kepada akaun lain migrate_account: Pindah kepada akaun lain
migrate_account_html: Jika anda ingin mengubah hala akaun ini kepada akaun lain, anda boleh <a href="%{path}">konfigurasikannya di sini</a>. migrate_account_html: Jika anda ingin mengubah hala akaun ini kepada akaun lain, anda boleh <a href="%{path}">konfigurasikannya di sini</a>.
or_log_in_with: Atau daftar masuk dengan or_log_in_with: Atau daftar masuk dengan
privacy_policy_agreement_html: Saya telah membaca dan bersetuju menerima <a href="%{privacy_policy_path}" target="_blank">dasar privasi</a>
progress: progress:
details: Maklumat anda details: Maklumat anda
review: Ulasan kami review: Ulasan kami

View File

@ -994,7 +994,6 @@ my:
migrate_account: အခြားအကောင့်တစ်ခုသို့ ရွှေ့ရန် migrate_account: အခြားအကောင့်တစ်ခုသို့ ရွှေ့ရန်
migrate_account_html: ဤအကောင့်ကို အခြားအကောင့်သို့ ပြန်ညွှန်းလိုပါက <a href="%{path}">ဤနေရာတွင် စီစဉ်သတ်မှတ်နိုင်သည်</a>။ migrate_account_html: ဤအကောင့်ကို အခြားအကောင့်သို့ ပြန်ညွှန်းလိုပါက <a href="%{path}">ဤနေရာတွင် စီစဉ်သတ်မှတ်နိုင်သည်</a>။
or_log_in_with: သို့မဟုတ် အကောင့်ဖြင့် ဝင်ရောက်ပါ or_log_in_with: သို့မဟုတ် အကောင့်ဖြင့် ဝင်ရောက်ပါ
privacy_policy_agreement_html: <a href="%{privacy_policy_path}" target="_blank">ကိုယ်ရေးအချက်အလက်မူဝါဒ</a> ကို ဖတ်ပြီး သဘောတူလိုက်ပါပြီ
progress: progress:
details: သင့်အသေးစိတ်အချက်အလက်များ details: သင့်အသေးစိတ်အချက်အလက်များ
review: ကျွန်ုပ်တို့၏သုံးသပ်ချက် review: ကျွန်ုပ်တို့၏သုံးသပ်ချက်

View File

@ -1132,7 +1132,6 @@ nl:
migrate_account: Naar een ander account verhuizen migrate_account: Naar een ander account verhuizen
migrate_account_html: Wanneer je dit account naar een ander account wilt doorverwijzen, kun je <a href="%{path}">dit hier instellen</a>. migrate_account_html: Wanneer je dit account naar een ander account wilt doorverwijzen, kun je <a href="%{path}">dit hier instellen</a>.
or_log_in_with: Of inloggen met or_log_in_with: Of inloggen met
privacy_policy_agreement_html: Ik heb het <a href="%{privacy_policy_path}" target="_blank">privacybeleid</a> gelezen en ga daarmee akkoord
progress: progress:
confirm: E-mailadres bevestigen confirm: E-mailadres bevestigen
details: Jouw gegevens details: Jouw gegevens

View File

@ -1132,7 +1132,6 @@ nn:
migrate_account: Flytt til ein annan konto migrate_account: Flytt til ein annan konto
migrate_account_html: Om du vil visa denne kontoen til ein anna, kan du <a href="%{path}">skipe det her</a>. migrate_account_html: Om du vil visa denne kontoen til ein anna, kan du <a href="%{path}">skipe det her</a>.
or_log_in_with: Eller logg inn med or_log_in_with: Eller logg inn med
privacy_policy_agreement_html: Jeg har lest og godtar <a href="%{privacy_policy_path}" target="_blank">retningslinjer for personvern</a>
progress: progress:
confirm: Stadfest e-post confirm: Stadfest e-post
details: Opplysingane dine details: Opplysingane dine

View File

@ -1033,7 +1033,6 @@
migrate_account: Flytt til en annen konto migrate_account: Flytt til en annen konto
migrate_account_html: Hvis du ønsker å henvise denne kontoen til en annen, kan du <a href="%{path}">konfigurere det her</a>. migrate_account_html: Hvis du ønsker å henvise denne kontoen til en annen, kan du <a href="%{path}">konfigurere det her</a>.
or_log_in_with: Eller logg inn med or_log_in_with: Eller logg inn med
privacy_policy_agreement_html: Jeg har lest og godtar <a href="%{privacy_policy_path}" target="_blank">retningslinjer for personvern</a>
progress: progress:
details: Dine opplysninger details: Dine opplysninger
review: Vår gjennomgang review: Vår gjennomgang

View File

@ -481,7 +481,6 @@ oc:
migrate_account: Mudar endacòm mai migrate_account: Mudar endacòm mai
migrate_account_html: Se volètz mandar los visitors daqueste compte a un autre, podètz<a href="%{path}"> o configurar aquí</a>. migrate_account_html: Se volètz mandar los visitors daqueste compte a un autre, podètz<a href="%{path}"> o configurar aquí</a>.
or_log_in_with: O autentificatz-vos amb or_log_in_with: O autentificatz-vos amb
privacy_policy_agreement_html: Ai legit e accepti la <a href="%{privacy_policy_path}" target="_blank">politica de confidencialitat</a>
providers: providers:
cas: CAS cas: CAS
saml: SAML saml: SAML

View File

@ -1168,7 +1168,6 @@ pl:
migrate_account: Przenieś konto migrate_account: Przenieś konto
migrate_account_html: Jeżeli chcesz skonfigurować przekierowanie z obecnego konta na inne, możesz <a href="%{path}">zrobić to tutaj</a>. migrate_account_html: Jeżeli chcesz skonfigurować przekierowanie z obecnego konta na inne, możesz <a href="%{path}">zrobić to tutaj</a>.
or_log_in_with: Lub zaloguj się z użyciem or_log_in_with: Lub zaloguj się z użyciem
privacy_policy_agreement_html: Przeczytałem/am i akceptuję <a href="%{privacy_policy_path}" target="_blank">politykę prywatności</a>
progress: progress:
confirm: Potwierdź adres e-mail confirm: Potwierdź adres e-mail
details: Twoje dane details: Twoje dane

View File

@ -1132,7 +1132,6 @@ pt-BR:
migrate_account: Mudar-se para outra conta migrate_account: Mudar-se para outra conta
migrate_account_html: Se você quer redirecionar essa conta para uma outra você pode <a href="%{path}">configurar isso aqui</a>. migrate_account_html: Se você quer redirecionar essa conta para uma outra você pode <a href="%{path}">configurar isso aqui</a>.
or_log_in_with: Ou entre com or_log_in_with: Ou entre com
privacy_policy_agreement_html: Eu li e concordo com a <a href="%{privacy_policy_path}" target="_blank">política de privacidade</a>
progress: progress:
confirm: Confirmar e-mail confirm: Confirmar e-mail
details: Suas informações details: Suas informações

View File

@ -1113,7 +1113,6 @@ pt-PT:
migrate_account: Mudar para uma conta diferente migrate_account: Mudar para uma conta diferente
migrate_account_html: Se deseja redirecionar esta conta para uma outra pode <a href="%{path}">configurar isso aqui</a>. migrate_account_html: Se deseja redirecionar esta conta para uma outra pode <a href="%{path}">configurar isso aqui</a>.
or_log_in_with: Ou iniciar sessão com or_log_in_with: Ou iniciar sessão com
privacy_policy_agreement_html: Eu li e concordo com a <a href="%{privacy_policy_path}" target="_blank">política de privacidade</a>
progress: progress:
confirm: Confirmar e-mail confirm: Confirmar e-mail
details: Os seus dados details: Os seus dados

View File

@ -1168,7 +1168,6 @@ ru:
migrate_account: Перенос учётной записи migrate_account: Перенос учётной записи
migrate_account_html: Завели новую учётную запись? Перенаправьте подписчиков на неё — <a href="%{path}">настройте перенаправление тут</a>. migrate_account_html: Завели новую учётную запись? Перенаправьте подписчиков на неё — <a href="%{path}">настройте перенаправление тут</a>.
or_log_in_with: Или войти с помощью or_log_in_with: Или войти с помощью
privacy_policy_agreement_html: Мной прочитана и принята <a href="%{privacy_policy_path}" target="_blank">политика конфиденциальности</a>
progress: progress:
confirm: Подтвердите электронную почту confirm: Подтвердите электронную почту
details: Ваши данные details: Ваши данные

View File

@ -909,7 +909,6 @@ sco:
migrate_account: Uise a different accoont migrate_account: Uise a different accoont
migrate_account_html: Gin ye'r wantin fir tae redireck this accoont tae a different ane, ye kin <a href="%{path}">configure it here</a>. migrate_account_html: Gin ye'r wantin fir tae redireck this accoont tae a different ane, ye kin <a href="%{path}">configure it here</a>.
or_log_in_with: Or log in wi or_log_in_with: Or log in wi
privacy_policy_agreement_html: A'v read an A agree tae the <a href="%{privacy_policy_path}" target="_blank">privacy policy</a>
providers: providers:
cas: CAS cas: CAS
saml: SAML saml: SAML

View File

@ -130,6 +130,17 @@ en:
show_application: You will always be able to see which app published your post regardless. show_application: You will always be able to see which app published your post regardless.
tag: tag:
name: You can only change the casing of the letters, for example, to make it more readable name: You can only change the casing of the letters, for example, to make it more readable
terms_of_service:
changelog: Can be structured with Markdown syntax.
text: Can be structured with Markdown syntax.
terms_of_service_generator:
admin_email: Legal notices include counternotices, court orders, takedown requests, and law enforcement requests.
arbitration_address: Can be the same as Physical address above, or “N/A” if using email
arbitration_website: Can be a web form, or “N/A” if using email
dmca_address: For US operators, use the address registered in the DMCA Designated Agent Directory. A P.O. Box listing is available upon direct request, use the DMCA Designated Agent Post Office Box Waiver Request to email the Copyright Office and describe that you are a home-based content moderator who fears revenge or retribution for your actions and need to use a P.O. Box to remove your home address from public view.
dmca_email: Can be the same email used for “Email address for legal notices” above
domain: Unique identification of the online service you are providing.
jurisdiction: List the country where whoever pays the bills lives. If its a company or other entity, list the country where its incorporated, and the city, region, territory or state as appropriate.
user: user:
chosen_languages: When checked, only posts in selected languages will be displayed in public timelines chosen_languages: When checked, only posts in selected languages will be displayed in public timelines
role: The role controls which permissions the user has. role: The role controls which permissions the user has.
@ -319,6 +330,17 @@ en:
name: Hashtag name: Hashtag
trendable: Allow this hashtag to appear under trends trendable: Allow this hashtag to appear under trends
usable: Allow posts to use this hashtag locally usable: Allow posts to use this hashtag locally
terms_of_service:
changelog: What's changed?
text: Terms of Service
terms_of_service_generator:
admin_email: Email address for legal notices
arbitration_address: Physical address for arbitration notices
arbitration_website: Website for submitting arbitration notices
dmca_address: Physical address for DMCA/copyright notices
dmca_email: Email address for DMCA/copyright notices
domain: Domain
jurisdiction: Legal jurisdiction
user: user:
role: Role role: Role
time_zone: Time zone time_zone: Time zone

View File

@ -1141,7 +1141,6 @@ sl:
migrate_account: Premakni se na drug račun migrate_account: Premakni se na drug račun
migrate_account_html: Če želite ta račun preusmeriti na drugega, ga lahko <a href="%{path}">nastavite tukaj</a>. migrate_account_html: Če želite ta račun preusmeriti na drugega, ga lahko <a href="%{path}">nastavite tukaj</a>.
or_log_in_with: Ali se prijavite z or_log_in_with: Ali se prijavite z
privacy_policy_agreement_html: Prebral_a sem in se strinjam s <a href="%{privacy_policy_path}" target="_blank">pravilnikom o zasebnosti</a>.
progress: progress:
confirm: Potrdi e-pošto confirm: Potrdi e-pošto
details: Vaši podatki details: Vaši podatki

Some files were not shown because too many files have changed in this diff Show More