profile + i18n
This commit is contained in:
parent
0b4fe16b8e
commit
3e26f43177
@ -19,6 +19,7 @@ import {VoucherComponent} from './pages/account/voucher/voucher.component';
|
|||||||
import {SecurityComponent} from './pages/account/security/security.component';
|
import {SecurityComponent} from './pages/account/security/security.component';
|
||||||
import {UnavailableComponent} from './pages/unavailable/unavailable.component';
|
import {UnavailableComponent} from './pages/unavailable/unavailable.component';
|
||||||
import {NotfoundComponent} from './pages/notfound/notfound.component';
|
import {NotfoundComponent} from './pages/notfound/notfound.component';
|
||||||
|
import {UserComponent} from './pages/user/user.component'
|
||||||
|
|
||||||
const routes: Routes = [
|
const routes: Routes = [
|
||||||
{path: '', redirectTo: "/account/info", pathMatch: 'full'},
|
{path: '', redirectTo: "/account/info", pathMatch: 'full'},
|
||||||
@ -44,7 +45,8 @@ const routes: Routes = [
|
|||||||
{path: 'register', component: RegisterComponent, canActivate: [AnonymousGuard]},
|
{path: 'register', component: RegisterComponent, canActivate: [AnonymousGuard]},
|
||||||
{path: 'tokens', component: TokensComponent, canActivate: [AuthGuard]},
|
{path: 'tokens', component: TokensComponent, canActivate: [AuthGuard]},
|
||||||
{path: 'unavailable', component: UnavailableComponent},
|
{path: 'unavailable', component: UnavailableComponent},
|
||||||
{path: '**', component: NotfoundComponent, pathMatch: 'full'},
|
{path: 'p/:username', component: UserComponent, canActivate: [AuthUpdateGuard]},
|
||||||
|
{path: '**', component: NotfoundComponent, pathMatch: 'full', canActivate: [AuthUpdateGuard]},
|
||||||
];
|
];
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
|
@ -21,6 +21,11 @@ export class AppComponent {
|
|||||||
auth;
|
auth;
|
||||||
|
|
||||||
constructor(private i18n: I18nService, private authService: AuthService, private router: Router, private iconRegistry: MatIconRegistry, private sanitizer: DomSanitizer, private _adapter: DateAdapter<any>) {
|
constructor(private i18n: I18nService, private authService: AuthService, private router: Router, private iconRegistry: MatIconRegistry, private sanitizer: DomSanitizer, private _adapter: DateAdapter<any>) {
|
||||||
|
iconRegistry.addSvgIcon('logo', sanitizer.bypassSecurityTrustResourceUrl('assets/icons/logo.svg'));
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnInit() {
|
||||||
|
|
||||||
this.currentLocale = this.i18n.getLocale();
|
this.currentLocale = this.i18n.getLocale();
|
||||||
this.locales = this.i18n.getLocales();
|
this.locales = this.i18n.getLocales();
|
||||||
this.authService.auth.subscribe(data => {
|
this.authService.auth.subscribe(data => {
|
||||||
@ -29,10 +34,6 @@ export class AppComponent {
|
|||||||
|
|
||||||
this._adapter.setLocale(this.currentLocale);
|
this._adapter.setLocale(this.currentLocale);
|
||||||
|
|
||||||
iconRegistry.addSvgIcon('logo', sanitizer.bypassSecurityTrustResourceUrl('assets/icons/logo.svg'));
|
|
||||||
}
|
|
||||||
|
|
||||||
ngOnInit() {
|
|
||||||
const width = window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth;
|
const width = window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth;
|
||||||
if(width < 768) {
|
if(width < 768) {
|
||||||
this.opened = false;
|
this.opened = false;
|
||||||
|
@ -33,13 +33,15 @@ import {UsernameDialog} from './pages/register/username-dialog/username.dialog';
|
|||||||
import {UnavailableComponent} from './pages/unavailable/unavailable.component';
|
import {UnavailableComponent} from './pages/unavailable/unavailable.component';
|
||||||
import {NotfoundComponent} from './pages/notfound/notfound.component';
|
import {NotfoundComponent} from './pages/notfound/notfound.component';
|
||||||
import {HtmlComponent} from './utils/html/html.component';
|
import {HtmlComponent} from './utils/html/html.component';
|
||||||
|
import {ConfirmDialog} from './ui/confirm/confirm.component'
|
||||||
|
import {UserComponent} from './pages/user/user.component'
|
||||||
|
|
||||||
|
|
||||||
import {I18nService} from './services/i18n.service';
|
import {I18nService} from './services/i18n.service';
|
||||||
|
|
||||||
|
|
||||||
export function init_app(i18n: I18nService) {
|
export function init_app(i18n: I18nService) {
|
||||||
return () => i18n.fetch(i18n.getLocale()).then(response => {}, error => {});
|
return () => i18n.fetch().then(response => {}, error => {});
|
||||||
}
|
}
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
@ -81,7 +83,9 @@ export class XhrInterceptor implements HttpInterceptor {
|
|||||||
UsernameDialog,
|
UsernameDialog,
|
||||||
UnavailableComponent,
|
UnavailableComponent,
|
||||||
NotfoundComponent,
|
NotfoundComponent,
|
||||||
HtmlComponent
|
HtmlComponent,
|
||||||
|
ConfirmDialog,
|
||||||
|
UserComponent
|
||||||
],
|
],
|
||||||
imports: [
|
imports: [
|
||||||
BrowserModule,
|
BrowserModule,
|
||||||
|
19
src/app/pages/user/user.component.html
Normal file
19
src/app/pages/user/user.component.html
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
<br>
|
||||||
|
<mat-progress-bar *ngIf="!success && !error" mode="indeterminate"></mat-progress-bar>
|
||||||
|
|
||||||
|
<div *ngIf="success">
|
||||||
|
<h3>{{username}}</h3>
|
||||||
|
<app-profilefields [profileFields]="profileFields"></app-profilefields>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<mat-card *ngIf="error">
|
||||||
|
<mat-card-header>
|
||||||
|
<mat-card-title>{{error.status}}</mat-card-title>
|
||||||
|
<mat-card-subtitle>{{'user.unavailable' | i18n}}</mat-card-subtitle>
|
||||||
|
</mat-card-header>
|
||||||
|
<mat-card-content>
|
||||||
|
<p>
|
||||||
|
{{'user.unavailable.text' | i18n}}
|
||||||
|
</p>
|
||||||
|
</mat-card-content>
|
||||||
|
</mat-card>
|
3
src/app/pages/user/user.component.scss
Normal file
3
src/app/pages/user/user.component.scss
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
h3 {
|
||||||
|
text-transform: uppercase;
|
||||||
|
}
|
25
src/app/pages/user/user.component.spec.ts
Normal file
25
src/app/pages/user/user.component.spec.ts
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
|
import { UserComponent } from './user.component';
|
||||||
|
|
||||||
|
describe('UserComponent', () => {
|
||||||
|
let component: UserComponent;
|
||||||
|
let fixture: ComponentFixture<UserComponent>;
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
await TestBed.configureTestingModule({
|
||||||
|
declarations: [ UserComponent ]
|
||||||
|
})
|
||||||
|
.compileComponents();
|
||||||
|
});
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
fixture = TestBed.createComponent(UserComponent);
|
||||||
|
component = fixture.componentInstance;
|
||||||
|
fixture.detectChanges();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create', () => {
|
||||||
|
expect(component).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
35
src/app/pages/user/user.component.ts
Normal file
35
src/app/pages/user/user.component.ts
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
import {Component, OnInit} from '@angular/core';
|
||||||
|
|
||||||
|
import {ActivatedRoute, Router, ParamMap} from '@angular/router';
|
||||||
|
|
||||||
|
import {ProfileService} from '../../services/profile.service';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-user',
|
||||||
|
templateUrl: './user.component.html',
|
||||||
|
styleUrls: ['./user.component.scss']
|
||||||
|
})
|
||||||
|
export class UserComponent implements OnInit {
|
||||||
|
|
||||||
|
username;
|
||||||
|
profileFields = [];
|
||||||
|
error = false;
|
||||||
|
success = false;
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
private profileService: ProfileService,
|
||||||
|
private router: Router,
|
||||||
|
private route: ActivatedRoute) {}
|
||||||
|
|
||||||
|
async ngOnInit() {
|
||||||
|
this.username = this.route.snapshot.paramMap.get('username');
|
||||||
|
this.profileService.getAllForUser(this.username).subscribe((data: any) => {
|
||||||
|
this.profileFields = data;
|
||||||
|
this.success = true;
|
||||||
|
}, error => {
|
||||||
|
this.error = error;
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
@ -1,35 +1,18 @@
|
|||||||
import { Injectable } from '@angular/core';
|
import {Injectable} from '@angular/core';
|
||||||
import { HttpClient } from '@angular/common/http';
|
import {HttpClient} from '@angular/common/http';
|
||||||
import { isEmpty } from 'rxjs/operators';
|
import { environment } from '../../environments/environment';
|
||||||
|
|
||||||
@Injectable({
|
@Injectable({
|
||||||
providedIn: 'root',
|
providedIn: 'root',
|
||||||
})
|
})
|
||||||
export class I18nService {
|
export class I18nService {
|
||||||
|
|
||||||
locale: String;
|
locale: string;
|
||||||
locales = ["de-informal"];
|
locales : any = ["de-informal"];
|
||||||
i18n: any;
|
i18n: any;
|
||||||
|
|
||||||
constructor(private http: HttpClient) {
|
constructor(private http: HttpClient) {
|
||||||
let browserLocale = navigator.language;
|
|
||||||
|
|
||||||
if (browserLocale.indexOf("-") != -1) {
|
|
||||||
browserLocale = browserLocale.split("-")[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
let locale = localStorage.getItem("bstly.locale") || browserLocale || this.locales[0];
|
|
||||||
|
|
||||||
if (locale == 'de') {
|
|
||||||
locale = 'de-informal';
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.locales.indexOf(locale) == -1) {
|
|
||||||
locale = this.locales[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
this.setLocale(locale);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
getLocales() {
|
getLocales() {
|
||||||
@ -44,25 +27,44 @@ export class I18nService {
|
|||||||
this.locale = locale;
|
this.locale = locale;
|
||||||
}
|
}
|
||||||
|
|
||||||
async fetch(locale) {
|
async fetch() {let browserLocale = navigator.language;
|
||||||
this.i18n = await this.http.get("./assets/i18n/" + locale + ".json").toPromise();
|
|
||||||
|
if(browserLocale.indexOf("-") != -1) {
|
||||||
|
browserLocale = browserLocale.split("-")[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
get(key, args: any[]): String {
|
let locale = localStorage.getItem("bstly.locale") || browserLocale || this.locales[0];
|
||||||
|
|
||||||
|
if(locale == 'de') {
|
||||||
|
locale = 'de-informal';
|
||||||
|
}
|
||||||
|
|
||||||
|
this.locales = await this.http.get(environment.apiUrl + "/i18n").toPromise();
|
||||||
|
|
||||||
|
if(this.locales.indexOf(locale) == -1) {
|
||||||
|
locale = this.locales[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
this.i18n = await this.http.get(environment.apiUrl + "/i18n/" + locale).toPromise();
|
||||||
|
|
||||||
|
this.setLocale(locale);
|
||||||
|
}
|
||||||
|
|
||||||
|
get(key, args: string[]): string {
|
||||||
return this.getInternal(key, args, this.i18n);
|
return this.getInternal(key, args, this.i18n);
|
||||||
}
|
}
|
||||||
|
|
||||||
getInternal(key, args: any[], from): String {
|
getInternal(key, args: string[], from): string {
|
||||||
if (!from) {
|
if(!from) {
|
||||||
return key;
|
return key;
|
||||||
} else if (from[key]) {
|
} else if(from[key]) {
|
||||||
if (from[key]["."]) {
|
if(from[key]["."]) {
|
||||||
return this.insertArguments(from[key]["."], args);
|
return this.insertArguments(from[key]["."], args);
|
||||||
}
|
}
|
||||||
return this.insertArguments(from[key], args);
|
return this.insertArguments(from[key], args);
|
||||||
} else {
|
} else {
|
||||||
let keys = key.split(".");
|
let keys = key.split(".");
|
||||||
if (from[keys[0]]) {
|
if(from[keys[0]]) {
|
||||||
key = keys.slice(1, keys.length).join(".");
|
key = keys.slice(1, keys.length).join(".");
|
||||||
return this.getInternal(key, args, from[keys[0]])
|
return this.getInternal(key, args, from[keys[0]])
|
||||||
}
|
}
|
||||||
@ -71,10 +73,10 @@ export class I18nService {
|
|||||||
return key;
|
return key;
|
||||||
}
|
}
|
||||||
|
|
||||||
insertArguments(label: String, args: any[]) {
|
insertArguments(label: string, args: string[]) {
|
||||||
if (args) {
|
if(args) {
|
||||||
for (let index in args) {
|
for(let index in args) {
|
||||||
label = label.replace(`{${index}}`, args[index]);
|
label = label.replace(`{${index}}`, this.get(args[index], []));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return label;
|
return label;
|
||||||
|
7
src/app/ui/confirm/confirm.component.html
Normal file
7
src/app/ui/confirm/confirm.component.html
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
<mat-dialog-content>
|
||||||
|
{{text}}
|
||||||
|
</mat-dialog-content>
|
||||||
|
<mat-dialog-actions>
|
||||||
|
<button mat-button [mat-dialog-close]="false">{{'cancel' | i18n}}</button>
|
||||||
|
<button mat-raised-button [mat-dialog-close]="true" color="accent">{{'confirm' | i18n}}</button>
|
||||||
|
</mat-dialog-actions>
|
3
src/app/ui/confirm/confirm.component.scss
Normal file
3
src/app/ui/confirm/confirm.component.scss
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
mat-form-field {
|
||||||
|
display: block;
|
||||||
|
}
|
21
src/app/ui/confirm/confirm.component.ts
Normal file
21
src/app/ui/confirm/confirm.component.ts
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
import {Component, Inject} from '@angular/core';
|
||||||
|
import {MatDialogRef, MAT_DIALOG_DATA} from '@angular/material/dialog';
|
||||||
|
import {I18nService} from '../../services/i18n.service';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
templateUrl: 'confirm.component.html',
|
||||||
|
styleUrls: ['./confirm.component.scss']
|
||||||
|
})
|
||||||
|
export class ConfirmDialog {
|
||||||
|
|
||||||
|
|
||||||
|
text;
|
||||||
|
|
||||||
|
constructor(private i18nService: I18nService,
|
||||||
|
public dialogRef: MatDialogRef<ConfirmDialog>,
|
||||||
|
@Inject(MAT_DIALOG_DATA) public data: any) {
|
||||||
|
this.text = i18nService.get(data.label, data.args);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -1,4 +1,4 @@
|
|||||||
<h1 mat-dialog-title></h1>
|
<h1 mat-dialog-title>{{'profileField.name.' + profileField.name | i18n}}</h1>
|
||||||
<mat-dialog-content>
|
<mat-dialog-content>
|
||||||
<pre>
|
<pre>
|
||||||
{{profileField.blob}}
|
{{profileField.blob}}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
<h1 mat-dialog-title></h1>
|
<h1 mat-dialog-title>{{'profileField.name.' + profileField.name | i18n}}</h1>
|
||||||
<mat-dialog-content>
|
<mat-dialog-content>
|
||||||
<form [formGroup]="form">
|
<form [formGroup]="form">
|
||||||
<mat-form-field>
|
<mat-form-field>
|
||||||
|
@ -4,6 +4,7 @@ import {FormBuilder, FormGroup, Validators} from '@angular/forms';
|
|||||||
import {MatDialog, MatDialogRef, MAT_DIALOG_DATA} from '@angular/material/dialog';
|
import {MatDialog, MatDialogRef, MAT_DIALOG_DATA} from '@angular/material/dialog';
|
||||||
import {I18nService} from '../../services/i18n.service';
|
import {I18nService} from '../../services/i18n.service';
|
||||||
import {ProfileService} from '../../services/profile.service';
|
import {ProfileService} from '../../services/profile.service';
|
||||||
|
import {ConfirmDialog} from '../confirm/confirm.component';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-profilefields',
|
selector: 'app-profilefields',
|
||||||
@ -55,7 +56,7 @@ export class ProfileFieldsComponent implements OnInit {
|
|||||||
|
|
||||||
const dialogRef = this.dialog.open(ProfileFieldDialog, {
|
const dialogRef = this.dialog.open(ProfileFieldDialog, {
|
||||||
data: profileField,
|
data: profileField,
|
||||||
minWidth : '400px'
|
minWidth: '400px'
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
@ -74,16 +75,27 @@ export class ProfileFieldsComponent implements OnInit {
|
|||||||
}
|
}
|
||||||
|
|
||||||
confirmDelete(profileField) {
|
confirmDelete(profileField) {
|
||||||
|
const dialogRef = this.dialog.open(ConfirmDialog, {
|
||||||
|
data: {
|
||||||
|
'label': 'profileField.confirmDelete',
|
||||||
|
'args': ['profileField.name.' + profileField.name]
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
dialogRef.afterClosed().subscribe(result => {
|
||||||
|
if(result) {
|
||||||
this.profileService.delete(profileField.name).subscribe((result: any) => {
|
this.profileService.delete(profileField.name).subscribe((result: any) => {
|
||||||
this.profileFields.splice(this.profileFields.indexOf(profileField), 1);
|
this.profileFields.splice(this.profileFields.indexOf(profileField), 1);
|
||||||
this.profileFields = [...this.profileFields];
|
this.profileFields = [...this.profileFields];
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
openCreate() {
|
openCreate() {
|
||||||
const dialogRef = this.dialog.open(ProfileFieldDialog, {
|
const dialogRef = this.dialog.open(ProfileFieldDialog, {
|
||||||
data: {"type": "TEXT", "visibility": "PRIVATE"},
|
data: {"type": "TEXT", "visibility": "PRIVATE"},
|
||||||
minWidth : '400px'
|
minWidth: '400px'
|
||||||
});
|
});
|
||||||
|
|
||||||
dialogRef.afterClosed().subscribe(result => {
|
dialogRef.afterClosed().subscribe(result => {
|
||||||
@ -100,7 +112,7 @@ export class ProfileFieldsComponent implements OnInit {
|
|||||||
openBlob(profileField) {
|
openBlob(profileField) {
|
||||||
this.dialog.open(ProfileFieldBlob, {
|
this.dialog.open(ProfileFieldBlob, {
|
||||||
data: profileField,
|
data: profileField,
|
||||||
minWidth : '400px'
|
minWidth: '400px'
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,298 +0,0 @@
|
|||||||
{
|
|
||||||
"account": "Account",
|
|
||||||
"cancel": "Abbrechen",
|
|
||||||
"close": "Schliessen",
|
|
||||||
"date-time-format": "dd.MM.yyyy HH:mm:ss",
|
|
||||||
"email": {
|
|
||||||
".": "E-Mail Adresse",
|
|
||||||
"invalid": "ungültige E-Mail Adresse",
|
|
||||||
"primary": "primäre E-Mail Adresse"
|
|
||||||
},
|
|
||||||
"greet": "Hallo {0}",
|
|
||||||
"home": {
|
|
||||||
".": "Über we.bstly",
|
|
||||||
"club": {
|
|
||||||
".": "Verein",
|
|
||||||
"about": "Über den Verein",
|
|
||||||
"charter": "Satzung (Entwurf)",
|
|
||||||
"membership": "Mitgliedschaft"
|
|
||||||
},
|
|
||||||
"general": {
|
|
||||||
".": "Über we.bstly",
|
|
||||||
"we": "Was unser Ziel ist",
|
|
||||||
"what": "Was wir machen",
|
|
||||||
"you": "Was du machen kannst"
|
|
||||||
},
|
|
||||||
"privacy": {
|
|
||||||
".": "Datenschutz",
|
|
||||||
"design": "Privacy By Design",
|
|
||||||
"pretix": "Shop System (Pretix)",
|
|
||||||
"services": "Aktuelle Services",
|
|
||||||
"we-bstly": "we.bstly"
|
|
||||||
},
|
|
||||||
"services": {
|
|
||||||
".": "Services",
|
|
||||||
"active": "Aktive Services",
|
|
||||||
"email": "E-Mail Postfach",
|
|
||||||
"legend": {
|
|
||||||
".": "Legende",
|
|
||||||
"not-available": "⚠️ noch nicht konkret/technische Hürden",
|
|
||||||
"not-ready": "❔ noch nicht fertig",
|
|
||||||
"ready": "✅ fertig, benötigt nur Finanzierung"
|
|
||||||
},
|
|
||||||
"planned": "Geplante Services"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"homepage": "Homepage",
|
|
||||||
"i18n.test.replace": "Wat!?! {0} {1} {2}",
|
|
||||||
"imprint": "Impressum",
|
|
||||||
"info": {
|
|
||||||
".": "Info"
|
|
||||||
},
|
|
||||||
"locale": {
|
|
||||||
"de-informal": {
|
|
||||||
"long": "Deutsch",
|
|
||||||
"short": "DE"
|
|
||||||
},
|
|
||||||
"en": {
|
|
||||||
"long": "English",
|
|
||||||
"short": "EN"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"login": {
|
|
||||||
".": "Login",
|
|
||||||
"external": "Login",
|
|
||||||
"invalid": "Falscher Username oder Passwort.",
|
|
||||||
"keepSession": "Eingelogged bleiben"
|
|
||||||
},
|
|
||||||
"logout": "Logout",
|
|
||||||
"not-found": {
|
|
||||||
".": "Nicht gefunden",
|
|
||||||
"text": "Was geht ab!?"
|
|
||||||
},
|
|
||||||
"ok": "Ok",
|
|
||||||
"password": {
|
|
||||||
".": "Passwort",
|
|
||||||
"change": "Passwort ändern",
|
|
||||||
"changed": "Passwort erfolgreich geändert",
|
|
||||||
"confirm": "Passwort bestätigen",
|
|
||||||
"current": "Akutelles Passwort",
|
|
||||||
"error": {
|
|
||||||
"ILLEGAL_WHITESPACE": "Bitte keine Leerzeichen verwenden.",
|
|
||||||
"INSUFFICIENT_DIGIT": "Bitte mindestens eine Zahl eingeben.",
|
|
||||||
"INSUFFICIENT_LOWERCASE": "Bitte mindestens einen Kleinbuchstaben eingeben.",
|
|
||||||
"INSUFFICIENT_SPECIAL": "Bitte mindestens ein Sonderzeichen eingeben.",
|
|
||||||
"INSUFFICIENT_UPPERCASE": "Bitte mindestens einen Großbuchstaben eingeben.",
|
|
||||||
"TOO_SHORT": "Bitte ein längeres Passwort wählen."
|
|
||||||
},
|
|
||||||
"forgot": "Passwort vergessen",
|
|
||||||
"invalid": {
|
|
||||||
"hint": "Bitte gebe das Passwort in einem gültigen Format an."
|
|
||||||
},
|
|
||||||
"not-match": "Passwörter stimmen nicht überein.",
|
|
||||||
"request": "Neues Passwort anfordern",
|
|
||||||
"reset": {
|
|
||||||
".": "Passwort setzen",
|
|
||||||
"login": "Zum Login",
|
|
||||||
"success": {
|
|
||||||
"text": "Dein neues Passwort wurde übernommen. Du kannst dich nun mit deinem neuen Passwort einloggen.",
|
|
||||||
"title": "Passwort erfolgreich geändert"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"permissions": {
|
|
||||||
".": "Berechtigungen",
|
|
||||||
"expires": "Gültig bis",
|
|
||||||
"name": "Name",
|
|
||||||
"starts": "Gültig ab"
|
|
||||||
},
|
|
||||||
"pgp": {
|
|
||||||
".": "PGP",
|
|
||||||
"privateKey": {
|
|
||||||
".": "Privater PGP Schlüssel",
|
|
||||||
"confirmStore": "Ich habe meinen privaten Schlüssel sicher gespeichert!",
|
|
||||||
"downloadKey": "Privaten Schlüssel herunterladen"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"privacy-policy": "Datenschutzerklärung",
|
|
||||||
"profile": "Profil",
|
|
||||||
"profileField": {
|
|
||||||
".": "Profilfeld",
|
|
||||||
"create": "Neues Profilfeld hinzufügen",
|
|
||||||
"delete": "Löschen",
|
|
||||||
"edit": "Bearbeiten",
|
|
||||||
"index": "Index",
|
|
||||||
"name": {
|
|
||||||
".": "Name"
|
|
||||||
},
|
|
||||||
"openBlob": "Anzeigen",
|
|
||||||
"type": {
|
|
||||||
".": "Typ",
|
|
||||||
"BOOL": {
|
|
||||||
".": "Boolean"
|
|
||||||
},
|
|
||||||
"DATE": {
|
|
||||||
".": "Datum"
|
|
||||||
},
|
|
||||||
"EMAIL": {
|
|
||||||
".": "E-Mail"
|
|
||||||
},
|
|
||||||
"NUMBER": {
|
|
||||||
".": "Numerisch"
|
|
||||||
},
|
|
||||||
"TEXT": {
|
|
||||||
".": "Textfeld"
|
|
||||||
},
|
|
||||||
"URL": {
|
|
||||||
".": "URL"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"value": "Wert",
|
|
||||||
"visibility": {
|
|
||||||
".": "Sichtbarkeit",
|
|
||||||
"PRIVATE": {
|
|
||||||
".": "Privat"
|
|
||||||
},
|
|
||||||
"PROTECTED": {
|
|
||||||
".": "Geschützt"
|
|
||||||
},
|
|
||||||
"PUBLIC": {
|
|
||||||
".": "Öffentlich"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"quotas": {
|
|
||||||
".": "Quotas",
|
|
||||||
"name": "Name",
|
|
||||||
"unit": {
|
|
||||||
"#": "# (Anzahl)",
|
|
||||||
".": "Einheit",
|
|
||||||
"G": "GB (Gigabyte)"
|
|
||||||
},
|
|
||||||
"value": "Quota"
|
|
||||||
},
|
|
||||||
"register": {
|
|
||||||
".": "Registrierung",
|
|
||||||
"login": "Zum Login",
|
|
||||||
"success": {
|
|
||||||
"text": "Deine Registrierung war erfolgreich. Du kannst dich nun einloggen!",
|
|
||||||
"title": "Registrierung abgeschlossen"
|
|
||||||
},
|
|
||||||
"token.missing": "Du benötigst leider ein gültiges Token!"
|
|
||||||
},
|
|
||||||
"save": "Speichern",
|
|
||||||
"security": {
|
|
||||||
".": "Sicherheit",
|
|
||||||
"2fa": {
|
|
||||||
".": "Zwei-Faktor-Authentifierung (2FA)",
|
|
||||||
"info": "Du kannst hier einen zweiten Faktor zusätzlich zu deinem Passwort hinzufügen. Beachte, dass dies nur den Login in deinen we.bstly-Account betrifft. 2FA gilt nicht für deinen E-Mail Account. Aktuell wird nur TOTP (bekannt als Google Authenticator) unterstützt.",
|
|
||||||
"totp": {
|
|
||||||
".": "2FA (TOTP)",
|
|
||||||
"activate": "Um TOTP als 2FA zu aktivieren, gebe bitte deinen aktuellen Code ein.",
|
|
||||||
"code": "TOTP Code",
|
|
||||||
"create": "2FA (TOTP) einrichten",
|
|
||||||
"enable": "Aktiviere 2FA (TOTP)",
|
|
||||||
"external": "2FA (TOTP)",
|
|
||||||
"hint": "Um TOTP als zweiten Faktor beim Login zu verwenden, scanne den QRCode mit deiner TOTP App.",
|
|
||||||
"invalid": "TOTP Code ist ungültig",
|
|
||||||
"keepSession": "2FA (TOTP) für dieses Gerät merken",
|
|
||||||
"login": "Code verfizieren",
|
|
||||||
"missing": "Bitte TOTP Code eingeben",
|
|
||||||
"remove": "2FA (TOTP) deaktivieren"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"service-unavailable": {
|
|
||||||
".": "Service nicht erreichbar",
|
|
||||||
"text": "Zurzeit scheint der Service nicht erreichbar zu sein. Wenn diese Meldung länger besteht, melde dich bitte unter admin@bstly.de!"
|
|
||||||
},
|
|
||||||
"services": {
|
|
||||||
".": "Dienste",
|
|
||||||
"gitea": {
|
|
||||||
"icon": "code",
|
|
||||||
"subtitle": "Git-Repositories",
|
|
||||||
"text": "Alternative zu Diensten wie GitHub, Source Code von bstly-Entwicklungen",
|
|
||||||
"title": "Gitea"
|
|
||||||
},
|
|
||||||
"goto": "Zum Dienst",
|
|
||||||
"mail": {
|
|
||||||
"icon": "email",
|
|
||||||
"subtitle": "E-Mail Konto",
|
|
||||||
"text": "Catch-All an @{username}.we.bstly.de, lernender Spam-Filter und PGP Verschlüsselung.",
|
|
||||||
"title": "E-Mail Postfach"
|
|
||||||
},
|
|
||||||
"matrix": {
|
|
||||||
"icon": "question_answer",
|
|
||||||
"subtitle": "Messenger Plattform",
|
|
||||||
"text": "mit anderen Austauschen, sich Informieren oder einfach quatschen.",
|
|
||||||
"title": "Matrix"
|
|
||||||
},
|
|
||||||
"nextcloud": {
|
|
||||||
"icon": "cloud",
|
|
||||||
"subtitle": "Cloud Plattform",
|
|
||||||
"text": "Dateiverwaltung, Kalendar, Aufgabenmanagement, Kontaktmanagement, Abstimmungen und mehr.",
|
|
||||||
"title": "Nextcloud"
|
|
||||||
},
|
|
||||||
"partey": {
|
|
||||||
"icon": "celebration",
|
|
||||||
"subtitle": "Virtuelles Vereinsheim",
|
|
||||||
"text": "Digitaler Treffpunkt für Veranstaltungen oder einfach zum Abhängen.",
|
|
||||||
"title": "Partey"
|
|
||||||
},
|
|
||||||
"registration_vouchers": {
|
|
||||||
"icon": "card_giftcard",
|
|
||||||
"subtitle": "Gutschein Code für Registrierungs-Token",
|
|
||||||
"text": "Einladung um die Services des Bastelei e. V. zu nutzen",
|
|
||||||
"title": "Registrierungs-Gutscheincodes"
|
|
||||||
},
|
|
||||||
"ROLE_MEMBER": {
|
|
||||||
"icon": "loyalty",
|
|
||||||
"subtitle": "Mitgliedschaft im Bastelei e. V.",
|
|
||||||
"text": "Reguläres Mitglied im Bastelei e. V.",
|
|
||||||
"title": "Vereinsmitgliedschaft"
|
|
||||||
},
|
|
||||||
"wikijs": {
|
|
||||||
"icon": "school",
|
|
||||||
"subtitle": "Informationen, Dokumentation, Anleitungen",
|
|
||||||
"text": "Alle Information rund um Bastelei e. V. und den angebotenen Diensten, sowie Anleitungen für einzelne Dienste und Funktionen",
|
|
||||||
"title": "Wiki"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"software": "Software",
|
|
||||||
"sourcecode": "Quellcode",
|
|
||||||
"token": "Token",
|
|
||||||
"tokens": {
|
|
||||||
".": "Tokens",
|
|
||||||
"enter": "Token einlösen",
|
|
||||||
"get": "Mitgliedschaft",
|
|
||||||
"invalid": "Das Token ist leider nicht gültig.",
|
|
||||||
"provide-valid": "Bitte gebe ein gültiges Token ein.",
|
|
||||||
"redeem": "Tokens einlösen",
|
|
||||||
"redeemed": "Das Token wurde bereits eingelöst.",
|
|
||||||
"validate": "Prüfen"
|
|
||||||
},
|
|
||||||
"username": {
|
|
||||||
".": "Username",
|
|
||||||
"error": "Bitte wähle einen anderen Usernamen aus.",
|
|
||||||
"missing": "Bitte gebe einen Usernamen an."
|
|
||||||
},
|
|
||||||
"voucher": {
|
|
||||||
".": "Gutscheincode",
|
|
||||||
"code": "Code",
|
|
||||||
"type": "Typ"
|
|
||||||
},
|
|
||||||
"vouchers": {
|
|
||||||
".": "Gutscheincodes",
|
|
||||||
"add-on": "Add-On",
|
|
||||||
"info": "Hier kannst du Gutscheincodes für Add-Ons und Registrierung generieren.",
|
|
||||||
"registration": "Registrierung",
|
|
||||||
"stored-safely": {
|
|
||||||
".": "Da wir keine Verbindungen von Gutscheincodes zu deinem Account speichern, speichere diesen Code bitte selber sicher ab. Falls du die Seite verlässt oder neuläds ist der Code nicht mehr verfügbar!",
|
|
||||||
"confirm": "Ich habe den Code sicher abgespeicher!"
|
|
||||||
},
|
|
||||||
"temp": {
|
|
||||||
".": "Temporäre Gutscheincodes",
|
|
||||||
"info": "Hier werden deine aktuell angefragten Gutscheincodes angezeigt. Bitte speichere diese sicher ab, da wir diese Codes nicht für dich speichern!"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1 +0,0 @@
|
|||||||
{}
|
|
Loading…
Reference in New Issue
Block a user