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 {UnavailableComponent} from './pages/unavailable/unavailable.component';
|
||||
import {NotfoundComponent} from './pages/notfound/notfound.component';
|
||||
import {UserComponent} from './pages/user/user.component'
|
||||
|
||||
const routes: Routes = [
|
||||
{path: '', redirectTo: "/account/info", pathMatch: 'full'},
|
||||
@ -44,7 +45,8 @@ const routes: Routes = [
|
||||
{path: 'register', component: RegisterComponent, canActivate: [AnonymousGuard]},
|
||||
{path: 'tokens', component: TokensComponent, canActivate: [AuthGuard]},
|
||||
{path: 'unavailable', component: UnavailableComponent},
|
||||
{path: '**', component: NotfoundComponent, pathMatch: 'full'},
|
||||
{path: 'p/:username', component: UserComponent, canActivate: [AuthUpdateGuard]},
|
||||
{path: '**', component: NotfoundComponent, pathMatch: 'full', canActivate: [AuthUpdateGuard]},
|
||||
];
|
||||
|
||||
@NgModule({
|
||||
|
@ -21,6 +21,11 @@ export class AppComponent {
|
||||
auth;
|
||||
|
||||
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.locales = this.i18n.getLocales();
|
||||
this.authService.auth.subscribe(data => {
|
||||
@ -29,10 +34,6 @@ export class AppComponent {
|
||||
|
||||
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;
|
||||
if(width < 768) {
|
||||
this.opened = false;
|
||||
|
@ -33,13 +33,15 @@ import {UsernameDialog} from './pages/register/username-dialog/username.dialog';
|
||||
import {UnavailableComponent} from './pages/unavailable/unavailable.component';
|
||||
import {NotfoundComponent} from './pages/notfound/notfound.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';
|
||||
|
||||
|
||||
export function init_app(i18n: I18nService) {
|
||||
return () => i18n.fetch(i18n.getLocale()).then(response => {}, error => {});
|
||||
return () => i18n.fetch().then(response => {}, error => {});
|
||||
}
|
||||
|
||||
@Injectable()
|
||||
@ -81,7 +83,9 @@ export class XhrInterceptor implements HttpInterceptor {
|
||||
UsernameDialog,
|
||||
UnavailableComponent,
|
||||
NotfoundComponent,
|
||||
HtmlComponent
|
||||
HtmlComponent,
|
||||
ConfirmDialog,
|
||||
UserComponent
|
||||
],
|
||||
imports: [
|
||||
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 { HttpClient } from '@angular/common/http';
|
||||
import { isEmpty } from 'rxjs/operators';
|
||||
import {Injectable} from '@angular/core';
|
||||
import {HttpClient} from '@angular/common/http';
|
||||
import { environment } from '../../environments/environment';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root',
|
||||
})
|
||||
export class I18nService {
|
||||
|
||||
locale: String;
|
||||
locales = ["de-informal"];
|
||||
locale: string;
|
||||
locales : any = ["de-informal"];
|
||||
i18n: any;
|
||||
|
||||
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() {
|
||||
@ -44,25 +27,44 @@ export class I18nService {
|
||||
this.locale = locale;
|
||||
}
|
||||
|
||||
async fetch(locale) {
|
||||
this.i18n = await this.http.get("./assets/i18n/" + locale + ".json").toPromise();
|
||||
async fetch() {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';
|
||||
}
|
||||
|
||||
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: any[]): String {
|
||||
get(key, args: string[]): string {
|
||||
return this.getInternal(key, args, this.i18n);
|
||||
}
|
||||
|
||||
getInternal(key, args: any[], from): String {
|
||||
if (!from) {
|
||||
getInternal(key, args: string[], from): string {
|
||||
if(!from) {
|
||||
return key;
|
||||
} else if (from[key]) {
|
||||
if (from[key]["."]) {
|
||||
} else if(from[key]) {
|
||||
if(from[key]["."]) {
|
||||
return this.insertArguments(from[key]["."], args);
|
||||
}
|
||||
return this.insertArguments(from[key], args);
|
||||
} else {
|
||||
let keys = key.split(".");
|
||||
if (from[keys[0]]) {
|
||||
if(from[keys[0]]) {
|
||||
key = keys.slice(1, keys.length).join(".");
|
||||
return this.getInternal(key, args, from[keys[0]])
|
||||
}
|
||||
@ -71,10 +73,10 @@ export class I18nService {
|
||||
return key;
|
||||
}
|
||||
|
||||
insertArguments(label: String, args: any[]) {
|
||||
if (args) {
|
||||
for (let index in args) {
|
||||
label = label.replace(`{${index}}`, args[index]);
|
||||
insertArguments(label: string, args: string[]) {
|
||||
if(args) {
|
||||
for(let index in args) {
|
||||
label = label.replace(`{${index}}`, this.get(args[index], []));
|
||||
}
|
||||
}
|
||||
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>
|
||||
<pre>
|
||||
{{profileField.blob}}
|
||||
|
@ -1,4 +1,4 @@
|
||||
<h1 mat-dialog-title></h1>
|
||||
<h1 mat-dialog-title>{{'profileField.name.' + profileField.name | i18n}}</h1>
|
||||
<mat-dialog-content>
|
||||
<form [formGroup]="form">
|
||||
<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 {I18nService} from '../../services/i18n.service';
|
||||
import {ProfileService} from '../../services/profile.service';
|
||||
import {ConfirmDialog} from '../confirm/confirm.component';
|
||||
|
||||
@Component({
|
||||
selector: 'app-profilefields',
|
||||
@ -55,7 +56,7 @@ export class ProfileFieldsComponent implements OnInit {
|
||||
|
||||
const dialogRef = this.dialog.open(ProfileFieldDialog, {
|
||||
data: profileField,
|
||||
minWidth : '400px'
|
||||
minWidth: '400px'
|
||||
});
|
||||
|
||||
|
||||
@ -74,16 +75,27 @@ export class ProfileFieldsComponent implements OnInit {
|
||||
}
|
||||
|
||||
confirmDelete(profileField) {
|
||||
this.profileService.delete(profileField.name).subscribe((result: any) => {
|
||||
this.profileFields.splice(this.profileFields.indexOf(profileField), 1);
|
||||
this.profileFields = [...this.profileFields];
|
||||
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.profileFields.splice(this.profileFields.indexOf(profileField), 1);
|
||||
this.profileFields = [...this.profileFields];
|
||||
})
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
openCreate() {
|
||||
const dialogRef = this.dialog.open(ProfileFieldDialog, {
|
||||
data: {"type": "TEXT", "visibility": "PRIVATE"},
|
||||
minWidth : '400px'
|
||||
minWidth: '400px'
|
||||
});
|
||||
|
||||
dialogRef.afterClosed().subscribe(result => {
|
||||
@ -100,7 +112,7 @@ export class ProfileFieldsComponent implements OnInit {
|
||||
openBlob(profileField) {
|
||||
this.dialog.open(ProfileFieldBlob, {
|
||||
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