Merge branch 'main' into more-inbox-permissions
This commit is contained in:
commit
3db2536a1f
22 changed files with 109 additions and 52 deletions
2
ansible/VERSION
vendored
2
ansible/VERSION
vendored
|
@ -1 +1 @@
|
|||
v0.7.35
|
||||
v0.7.39
|
||||
|
|
3
ansible/templates/nginx.conf
vendored
3
ansible/templates/nginx.conf
vendored
|
@ -60,6 +60,9 @@ server {
|
|||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
|
||||
# Cuts off the trailing slash on URLs to make them valid
|
||||
rewrite ^(.+)/+$ $1 permanent;
|
||||
|
||||
# WebSocket support
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
|
|
9
docker/federation/nginx.conf
vendored
9
docker/federation/nginx.conf
vendored
|
@ -17,6 +17,9 @@ http {
|
|||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
|
||||
# Cuts off the trailing slash on URLs to make them valid
|
||||
rewrite ^(.+)/+$ $1 permanent;
|
||||
|
||||
# WebSocket support
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
|
@ -57,6 +60,9 @@ http {
|
|||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
|
||||
# Cuts off the trailing slash on URLs to make them valid
|
||||
rewrite ^(.+)/+$ $1 permanent;
|
||||
|
||||
# WebSocket support
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
|
@ -97,6 +103,9 @@ http {
|
|||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
|
||||
# Cuts off the trailing slash on URLs to make them valid
|
||||
rewrite ^(.+)/+$ $1 permanent;
|
||||
|
||||
# WebSocket support
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
|
|
2
docker/prod/docker-compose.yml
vendored
2
docker/prod/docker-compose.yml
vendored
|
@ -12,7 +12,7 @@ services:
|
|||
restart: always
|
||||
|
||||
lemmy:
|
||||
image: dessalines/lemmy:v0.7.35
|
||||
image: dessalines/lemmy:v0.7.39
|
||||
ports:
|
||||
- "127.0.0.1:8536:8536"
|
||||
restart: always
|
||||
|
|
4
docker/travis/docker_push.sh
vendored
4
docker/travis/docker_push.sh
vendored
|
@ -1,5 +1,5 @@
|
|||
#!/bin/sh
|
||||
echo "$DOCKER_PASSWORD" | docker login -u "$DOCKER_USERNAME" --password-stdin
|
||||
docker tag dessalines/lemmy:travis \
|
||||
dessalines/lemmy:v0.7.35
|
||||
docker push dessalines/lemmy:v0.7.35
|
||||
dessalines/lemmy:v0.7.39
|
||||
docker push dessalines/lemmy:v0.7.39
|
||||
|
|
2
docs/src/contributing_local_development.md
vendored
2
docs/src/contributing_local_development.md
vendored
|
@ -1,7 +1,7 @@
|
|||
### Install build requirements
|
||||
#### Ubuntu
|
||||
```
|
||||
sudo apt install git cargo libssl-dev pkg-config libpq-dev yarn curl gnupg2
|
||||
sudo apt install git cargo libssl-dev pkg-config libpq-dev yarn curl gnupg2 espeak
|
||||
# install yarn
|
||||
curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | sudo apt-key add -
|
||||
echo "deb https://dl.yarnpkg.com/debian/ stable main" | sudo tee /etc/apt/sources.list.d/yarn.list
|
||||
|
|
|
@ -1 +1 @@
|
|||
pub const VERSION: &str = "v0.7.35";
|
||||
pub const VERSION: &str = "v0.7.39";
|
||||
|
|
4
ui/assets/css/main.css
vendored
4
ui/assets/css/main.css
vendored
|
@ -87,6 +87,10 @@
|
|||
line-height: 1.0;
|
||||
}
|
||||
|
||||
.post-title a:visited {
|
||||
color: var(--gray) !important;
|
||||
}
|
||||
|
||||
.icon {
|
||||
display: inline-flex;
|
||||
width: 1em;
|
||||
|
|
3
ui/src/components/comment-form.tsx
vendored
3
ui/src/components/comment-form.tsx
vendored
|
@ -144,6 +144,9 @@ export class CommentForm extends Component<CommentFormProps, CommentFormState> {
|
|||
// This only finishes this form, if the randomly generated form_id matches the one received
|
||||
if (this.state.commentForm.form_id == data.form_id) {
|
||||
this.setState({ finished: true });
|
||||
|
||||
// Necessary because it broke tribute for some reaso
|
||||
this.setState({ finished: false });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
31
ui/src/components/inbox.tsx
vendored
31
ui/src/components/inbox.tsx
vendored
|
@ -275,21 +275,21 @@ export class Inbox extends Component<any, InboxState> {
|
|||
);
|
||||
}
|
||||
|
||||
combined(): Array<ReplyType> {
|
||||
return [
|
||||
...this.state.replies,
|
||||
...this.state.mentions,
|
||||
...this.state.messages,
|
||||
].sort((a, b) => b.published.localeCompare(a.published));
|
||||
}
|
||||
|
||||
all() {
|
||||
let combined: Array<ReplyType> = [];
|
||||
|
||||
combined.push(...this.state.replies);
|
||||
combined.push(...this.state.mentions);
|
||||
combined.push(...this.state.messages);
|
||||
|
||||
// Sort it
|
||||
combined.sort((a, b) => b.published.localeCompare(a.published));
|
||||
|
||||
return (
|
||||
<div>
|
||||
{combined.map(i =>
|
||||
{this.combined().map(i =>
|
||||
isCommentType(i) ? (
|
||||
<CommentNodes
|
||||
key={i.id}
|
||||
nodes={[{ comment: i }]}
|
||||
noIndent
|
||||
markable
|
||||
|
@ -298,7 +298,7 @@ export class Inbox extends Component<any, InboxState> {
|
|||
enableDownvotes={this.state.site.enable_downvotes}
|
||||
/>
|
||||
) : (
|
||||
<PrivateMessage privateMessage={i} />
|
||||
<PrivateMessage key={i.id} privateMessage={i} />
|
||||
)
|
||||
)}
|
||||
</div>
|
||||
|
@ -325,6 +325,7 @@ export class Inbox extends Component<any, InboxState> {
|
|||
<div>
|
||||
{this.state.mentions.map(mention => (
|
||||
<CommentNodes
|
||||
key={mention.id}
|
||||
nodes={[{ comment: mention }]}
|
||||
noIndent
|
||||
markable
|
||||
|
@ -341,7 +342,7 @@ export class Inbox extends Component<any, InboxState> {
|
|||
return (
|
||||
<div>
|
||||
{this.state.messages.map(message => (
|
||||
<PrivateMessage privateMessage={message} />
|
||||
<PrivateMessage key={message.id} privateMessage={message} />
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
|
@ -565,7 +566,6 @@ export class Inbox extends Component<any, InboxState> {
|
|||
} else if (data.comment.creator_id == UserService.Instance.user.id) {
|
||||
toast(i18n.t('reply_sent'));
|
||||
}
|
||||
this.setState(this.state);
|
||||
} else if (res.op == UserOperation.CreatePrivateMessage) {
|
||||
let data = res.data as PrivateMessageResponse;
|
||||
if (data.message.recipient_id == UserService.Instance.user.id) {
|
||||
|
@ -597,7 +597,10 @@ export class Inbox extends Component<any, InboxState> {
|
|||
this.state.replies.filter(r => !r.read).length +
|
||||
this.state.mentions.filter(r => !r.read).length +
|
||||
this.state.messages.filter(
|
||||
r => !r.read && r.creator_id !== UserService.Instance.user.id
|
||||
r =>
|
||||
UserService.Instance.user &&
|
||||
!r.read &&
|
||||
r.creator_id !== UserService.Instance.user.id
|
||||
).length
|
||||
);
|
||||
}
|
||||
|
|
8
ui/src/components/markdown-textarea.tsx
vendored
8
ui/src/components/markdown-textarea.tsx
vendored
|
@ -25,6 +25,7 @@ interface MarkdownTextAreaProps {
|
|||
onSubmit?(msg: { val: string; formId: string }): any;
|
||||
onContentChange?(val: string): any;
|
||||
onReplyCancel?(): any;
|
||||
hideNavigationWarnings?: boolean;
|
||||
}
|
||||
|
||||
interface MarkdownTextAreaState {
|
||||
|
@ -78,7 +79,7 @@ export class MarkdownTextArea extends Component<
|
|||
}
|
||||
|
||||
componentDidUpdate() {
|
||||
if (this.state.content) {
|
||||
if (!this.props.hideNavigationWarnings && this.state.content) {
|
||||
window.onbeforeunload = () => true;
|
||||
} else {
|
||||
window.onbeforeunload = undefined;
|
||||
|
@ -110,7 +111,10 @@ export class MarkdownTextArea extends Component<
|
|||
render() {
|
||||
return (
|
||||
<form id={this.formId} onSubmit={linkEvent(this, this.handleSubmit)}>
|
||||
<Prompt when={this.state.content} message={i18n.t('block_leaving')} />
|
||||
<Prompt
|
||||
when={!this.props.hideNavigationWarnings && this.state.content}
|
||||
message={i18n.t('block_leaving')}
|
||||
/>
|
||||
<div class="form-group row">
|
||||
<div className={`col-sm-12`}>
|
||||
<textarea
|
||||
|
|
1
ui/src/components/navbar.tsx
vendored
1
ui/src/components/navbar.tsx
vendored
|
@ -431,6 +431,7 @@ export class Navbar extends Component<any, NavbarState> {
|
|||
// The login
|
||||
if (data.my_user) {
|
||||
UserService.Instance.user = data.my_user;
|
||||
WebSocketService.Instance.userJoin();
|
||||
// On the first load, check the unreads
|
||||
if (this.state.isLoggedIn == false) {
|
||||
this.requestNotificationPermission();
|
||||
|
|
6
ui/src/components/post-listing.tsx
vendored
6
ui/src/components/post-listing.tsx
vendored
|
@ -315,7 +315,7 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
|
|||
<h5 className="mb-1 d-inline-block">
|
||||
{this.props.showBody && post.url ? (
|
||||
<a
|
||||
className="text-body"
|
||||
className={!post.stickied ? 'text-body' : 'text-primary'}
|
||||
href={post.url}
|
||||
target="_blank"
|
||||
title={post.url}
|
||||
|
@ -325,7 +325,7 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
|
|||
</a>
|
||||
) : (
|
||||
<Link
|
||||
className="text-body"
|
||||
className={!post.stickied ? 'text-body' : 'text-primary'}
|
||||
to={`/post/${post.id}`}
|
||||
title={i18n.t('comments')}
|
||||
>
|
||||
|
@ -419,7 +419,7 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
|
|||
className="unselectable pointer ml-2 text-muted font-italic"
|
||||
data-tippy-content={i18n.t('stickied')}
|
||||
>
|
||||
<svg class={`icon icon-inline text-success`}>
|
||||
<svg class={`icon icon-inline text-primary`}>
|
||||
<use xlinkHref="#icon-pin"></use>
|
||||
</svg>
|
||||
</small>
|
||||
|
|
13
ui/src/components/private-message.tsx
vendored
13
ui/src/components/private-message.tsx
vendored
|
@ -45,7 +45,10 @@ export class PrivateMessage extends Component<
|
|||
}
|
||||
|
||||
get mine(): boolean {
|
||||
return UserService.Instance.user.id == this.props.privateMessage.creator_id;
|
||||
return (
|
||||
UserService.Instance.user &&
|
||||
UserService.Instance.user.id == this.props.privateMessage.creator_id
|
||||
);
|
||||
}
|
||||
|
||||
render() {
|
||||
|
@ -113,6 +116,7 @@ export class PrivateMessage extends Component<
|
|||
<PrivateMessageForm
|
||||
privateMessage={message}
|
||||
onEdit={this.handlePrivateMessageEdit}
|
||||
onCreate={this.handlePrivateMessageCreate}
|
||||
onCancel={this.handleReplyCancel}
|
||||
/>
|
||||
)}
|
||||
|
@ -280,9 +284,14 @@ export class PrivateMessage extends Component<
|
|||
this.setState(this.state);
|
||||
}
|
||||
|
||||
handlePrivateMessageCreate() {
|
||||
handlePrivateMessageCreate(message: PrivateMessageI) {
|
||||
if (
|
||||
UserService.Instance.user &&
|
||||
message.creator_id == UserService.Instance.user.id
|
||||
) {
|
||||
this.state.showReply = false;
|
||||
this.setState(this.state);
|
||||
toast(i18n.t('message_sent'));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
2
ui/src/components/search.tsx
vendored
2
ui/src/components/search.tsx
vendored
|
@ -289,6 +289,7 @@ export class Search extends Component<any, SearchState> {
|
|||
<div class="col-12">
|
||||
{i.type_ == 'posts' && (
|
||||
<PostListing
|
||||
key={(i.data as Post).id}
|
||||
post={i.data as Post}
|
||||
showCommunity
|
||||
enableDownvotes={this.state.site.enable_downvotes}
|
||||
|
@ -297,6 +298,7 @@ export class Search extends Component<any, SearchState> {
|
|||
)}
|
||||
{i.type_ == 'comments' && (
|
||||
<CommentNodes
|
||||
key={(i.data as Comment).id}
|
||||
nodes={[{ comment: i.data as Comment }]}
|
||||
locked
|
||||
noIndent
|
||||
|
|
1
ui/src/components/site-form.tsx
vendored
1
ui/src/components/site-form.tsx
vendored
|
@ -111,6 +111,7 @@ export class SiteForm extends Component<SiteFormProps, SiteFormState> {
|
|||
<MarkdownTextArea
|
||||
initialContent={this.state.siteForm.description}
|
||||
onContentChange={this.handleSiteDescriptionChange}
|
||||
hideNavigationWarnings
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
|
2
ui/src/components/sort-select.tsx
vendored
2
ui/src/components/sort-select.tsx
vendored
|
@ -65,6 +65,6 @@ export class SortSelect extends Component<SortSelectProps, SortSelectState> {
|
|||
}
|
||||
|
||||
handleSortChange(i: SortSelect, event: any) {
|
||||
i.props.onChange(event.target.value);
|
||||
i.props.onChange(Number(event.target.value));
|
||||
}
|
||||
}
|
||||
|
|
2
ui/src/components/user-details.tsx
vendored
2
ui/src/components/user-details.tsx
vendored
|
@ -150,6 +150,7 @@ export class UserDetails extends Component<UserDetailsProps, UserDetailsState> {
|
|||
<div>
|
||||
{i.type === 'posts' ? (
|
||||
<PostListing
|
||||
key={(i.data as Post).id}
|
||||
post={i.data as Post}
|
||||
admins={this.props.admins}
|
||||
showCommunity
|
||||
|
@ -158,6 +159,7 @@ export class UserDetails extends Component<UserDetailsProps, UserDetailsState> {
|
|||
/>
|
||||
) : (
|
||||
<CommentNodes
|
||||
key={(i.data as Comment).id}
|
||||
nodes={[{ comment: i.data as Comment }]}
|
||||
admins={this.props.admins}
|
||||
noBorder
|
||||
|
|
6
ui/src/components/user.tsx
vendored
6
ui/src/components/user.tsx
vendored
|
@ -152,9 +152,6 @@ export class User extends Component<any, UserState> {
|
|||
this.handleUserSettingsListingTypeChange = this.handleUserSettingsListingTypeChange.bind(
|
||||
this
|
||||
);
|
||||
this.handleUserSettingsListingTypeChange = this.handleUserSettingsListingTypeChange.bind(
|
||||
this
|
||||
);
|
||||
this.handlePageChange = this.handlePageChange.bind(this);
|
||||
this.handleUserSettingsBioChange = this.handleUserSettingsBioChange.bind(
|
||||
this
|
||||
|
@ -384,12 +381,14 @@ export class User extends Component<any, UserState> {
|
|||
)}
|
||||
</ul>
|
||||
</h5>
|
||||
{user.bio && (
|
||||
<div className="d-flex align-items-center mb-2">
|
||||
<div
|
||||
className="md-div"
|
||||
dangerouslySetInnerHTML={mdToHtml(user.bio)}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
<div className="d-flex align-items-center mb-2">
|
||||
<svg class="icon">
|
||||
<use xlinkHref="#icon-cake"></use>
|
||||
|
@ -594,6 +593,7 @@ export class User extends Component<any, UserState> {
|
|||
initialContent={this.state.userSettingsForm.bio}
|
||||
onContentChange={this.handleUserSettingsBioChange}
|
||||
maxLength={300}
|
||||
hideNavigationWarnings
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
|
4
ui/src/services/WebSocketService.ts
vendored
4
ui/src/services/WebSocketService.ts
vendored
|
@ -82,10 +82,6 @@ export class WebSocketService {
|
|||
this.ws.onopen = () => {
|
||||
console.log(`Connected to ${wsUri}`);
|
||||
|
||||
if (UserService.Instance.user) {
|
||||
this.userJoin();
|
||||
}
|
||||
|
||||
if (!firstConnect) {
|
||||
let res: WebSocketJsonResponse = {
|
||||
reconnect: true,
|
||||
|
|
11
ui/src/utils.ts
vendored
11
ui/src/utils.ts
vendored
|
@ -588,6 +588,9 @@ export function messageToastify(
|
|||
|
||||
export function setupTribute(): Tribute {
|
||||
return new Tribute({
|
||||
noMatchTemplate: function () {
|
||||
return '';
|
||||
},
|
||||
collection: [
|
||||
// Emojis
|
||||
{
|
||||
|
@ -669,7 +672,7 @@ function userSearch(text: string, cb: any) {
|
|||
|
||||
WebSocketService.Instance.search(form);
|
||||
|
||||
this.userSub = WebSocketService.Instance.subject.subscribe(
|
||||
let userSub = WebSocketService.Instance.subject.subscribe(
|
||||
msg => {
|
||||
let res = wsJsonToRes(msg);
|
||||
if (res.op == UserOperation.Search) {
|
||||
|
@ -683,7 +686,7 @@ function userSearch(text: string, cb: any) {
|
|||
};
|
||||
});
|
||||
cb(users);
|
||||
this.userSub.unsubscribe();
|
||||
userSub.unsubscribe();
|
||||
}
|
||||
},
|
||||
err => console.error(err),
|
||||
|
@ -706,7 +709,7 @@ function communitySearch(text: string, cb: any) {
|
|||
|
||||
WebSocketService.Instance.search(form);
|
||||
|
||||
this.communitySub = WebSocketService.Instance.subject.subscribe(
|
||||
let communitySub = WebSocketService.Instance.subject.subscribe(
|
||||
msg => {
|
||||
let res = wsJsonToRes(msg);
|
||||
if (res.op == UserOperation.Search) {
|
||||
|
@ -720,7 +723,7 @@ function communitySearch(text: string, cb: any) {
|
|||
};
|
||||
});
|
||||
cb(communities);
|
||||
this.communitySub.unsubscribe();
|
||||
communitySub.unsubscribe();
|
||||
}
|
||||
},
|
||||
err => console.error(err),
|
||||
|
|
25
ui/translations/de.json
vendored
25
ui/translations/de.json
vendored
|
@ -14,7 +14,7 @@
|
|||
"number_of_comments": "{{count}} Kommentar",
|
||||
"number_of_comments_plural": "{{count}} Kommentare",
|
||||
"remove_comment": "Kommentar löschen",
|
||||
"communities": "Communitys",
|
||||
"communities": "Communities",
|
||||
"users": "Benutzer",
|
||||
"create_a_community": "Eine Community anlegen",
|
||||
"create_community": "Community erstellen",
|
||||
|
@ -168,7 +168,7 @@
|
|||
"yes": "Ja",
|
||||
"no": "Nein",
|
||||
"powered_by": "Bereitgestellt durch",
|
||||
"landing_0": "Lemmy ist ein <1>Link-Aggregator</1> / Reddit Alternative im <2>Fediverse</2>.<3></3>Es ist selbst-hostbar, hat live-updates von Kommentar-threads und ist winzig (<4>~80kB</4>). Federation in das ActivityPub Netzwerk ist geplant. <5></5>Dies ist eine <6>sehr frühe Beta Version</6>, und viele Features funktionieren zurzeit nicht richtig oder fehlen. <7></7>Schlage neue Features vor oder melde Bugs <8>hier.</8><9></9>Gebaut mit <10>Rust</10>, <11>Actix</11>, <12>Inferno</12>, <13>Typescript</13>.",
|
||||
"landing": "Lemmy ist ein <1>Link-Aggregator</1> / Reddit Alternative im <2>Fediverse</2>.<3></3>Es ist selbst-hostbar, hat live-updates von Kommentar-threads und ist winzig (<4>~80kB</4>). Federation in das ActivityPub Netzwerk ist geplant. <5></5>Dies ist eine <6>sehr frühe Beta Version</6>, und viele Features funktionieren zurzeit nicht richtig oder fehlen. <7></7>Schlage neue Features vor oder melde Bugs <8>hier.</8><9></9>Gebaut mit <10>Rust</10>, <11>Actix</11>, <12>Inferno</12>, <13>Typescript</13>. <14></14> <15>Vielen Dank an unsere Mitwirkenden: </15> dessalines, Nutomic, asonix, zacanger, and iav.",
|
||||
"not_logged_in": "Nicht eingeloggt.",
|
||||
"community_ban": "Du wurdest von dieser Community gebannt.",
|
||||
"site_ban": "Du wurdest von dieser Seite gebannt",
|
||||
|
@ -216,7 +216,7 @@
|
|||
"messages": "Nachrichten",
|
||||
"old_password": "Letztes Passwort",
|
||||
"matrix_user_id": "Matrix Benutzer",
|
||||
"private_message_disclaimer": "Achtung: Private Nachrichten sind in Lemmy nicht sicher. Bitte erstelle einen <1>Riot.im</1> Account für sicheren Nachrichtenverkehr.",
|
||||
"private_message_disclaimer": "Achtung: Private Nachrichten sind in Lemmy nicht verschlüsselt. Bitte erstelle einen<1>Element.io</1> Account für sicheren Nachrichtenverkehr.",
|
||||
"send_notifications_to_email": "Sende Benachrichtigungen per Email",
|
||||
"downvotes_disabled": "Downvotes deaktiviert",
|
||||
"enable_downvotes": "Aktiviere Downvotes",
|
||||
|
@ -256,5 +256,22 @@
|
|||
"click_to_delete_picture": "Klicke, um das Bild zu löschen.",
|
||||
"picture_deleted": "Bild gelöscht.",
|
||||
"select_a_community": "Wähle eine Community aus",
|
||||
"invalid_username": "Ungültiger Benutzername."
|
||||
"invalid_username": "Ungültiger Benutzername.",
|
||||
"bold": "fett",
|
||||
"italic": "kursiv",
|
||||
"subscript": "Tiefzeichen",
|
||||
"superscript": "Hochzeichen",
|
||||
"header": "Header",
|
||||
"strikethrough": "durchgestrichen",
|
||||
"quote": "Zitat",
|
||||
"spoiler": "Spoiler",
|
||||
"list": "Liste",
|
||||
"not_a_moderator": "Kein Moderator.",
|
||||
"invalid_url": "Ungültige URL.",
|
||||
"must_login": "Du musst <1>eingeloggt oder registriert</1> sein um zu Kommentieren.",
|
||||
"no_password_reset": "Du kannst dein Passwort ohne E-Mail nicht zurücksetzen.",
|
||||
"cake_day_info": "Heute ist {{ creator_name }}'s cake day!",
|
||||
"invalid_post_title": "Ungültiger Post Titel",
|
||||
"cake_day_title": "Cake day:",
|
||||
"what_is": "Was ist"
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue