Layout and translation fixes

This commit is contained in:
Sean Engelhardt 2018-08-03 15:16:40 +02:00 committed by FinnStutzenstein
parent c5b38cc430
commit b64b49cc2e
18 changed files with 224 additions and 65 deletions

View File

@ -44,3 +44,10 @@ A running OpenSlides (2.2 or higher) instance is expected on port 8000.
Start OpenSlides as usual using Start OpenSlides as usual using
`python manage.py start --no-browser --host 0.0.0.0` `python manage.py start --no-browser --host 0.0.0.0`
### Translation
We are using ngx-translate for translation purposes.
Use `npm run extract` to extract strings and update elements an with translation functions.
Language files can be found in `/src/assets/i18n`.

View File

@ -1,6 +1,6 @@
import { Injector } from '@angular/core';
import { Title } from '@angular/platform-browser'; import { Title } from '@angular/platform-browser';
import { OpenSlidesComponent } from './openslides.component'; import { OpenSlidesComponent } from './openslides.component';
import { TranslateService } from '@ngx-translate/core';
/** /**
* Provides functionalities that will be used by most components * Provides functionalities that will be used by most components
@ -20,7 +20,7 @@ export abstract class BaseComponent extends OpenSlidesComponent {
/** /**
* Child constructor that implements the titleServices and calls Super from OpenSlidesComponent * Child constructor that implements the titleServices and calls Super from OpenSlidesComponent
*/ */
constructor(protected titleService?: Title) { constructor(protected titleService?: Title, protected translate?: TranslateService) {
super(); super();
} }
@ -30,6 +30,7 @@ export abstract class BaseComponent extends OpenSlidesComponent {
* TODO Might translate the prefix here? * TODO Might translate the prefix here?
*/ */
setTitle(prefix: string): void { setTitle(prefix: string): void {
this.titleService.setTitle(prefix + this.titleSuffix); const translatedPrefix = this.translate.instant(prefix);
this.titleService.setTitle(translatedPrefix + this.titleSuffix);
} }
} }

View File

@ -1,6 +1,7 @@
import { Component, OnInit } from '@angular/core'; import { Component, OnInit } from '@angular/core';
import { Title } from '@angular/platform-browser'; import { Title } from '@angular/platform-browser';
import { BaseComponent } from 'app/base.component'; import { BaseComponent } from 'app/base.component';
import { TranslateService } from '@ngx-translate/core';
@Component({ @Component({
selector: 'app-agenda-list', selector: 'app-agenda-list',
@ -8,12 +9,11 @@ import { BaseComponent } from 'app/base.component';
styleUrls: ['./agenda-list.component.css'] styleUrls: ['./agenda-list.component.css']
}) })
export class AgendaListComponent extends BaseComponent implements OnInit { export class AgendaListComponent extends BaseComponent implements OnInit {
constructor(titleService: Title) { constructor(titleService: Title, protected translate: TranslateService) {
super(titleService); super(titleService, translate);
} }
ngOnInit() { ngOnInit() {
//TODO translate
super.setTitle('Agenda'); super.setTitle('Agenda');
} }

View File

@ -1,14 +1,21 @@
import { Component, OnInit } from '@angular/core'; import { Component, OnInit } from '@angular/core';
import { BaseComponent } from '../../../base.component';
import { TranslateService } from '@ngx-translate/core';
import { Title } from '@angular/platform-browser';
@Component({ @Component({
selector: 'app-assignment-list', selector: 'app-assignment-list',
templateUrl: './assignment-list.component.html', templateUrl: './assignment-list.component.html',
styleUrls: ['./assignment-list.component.css'] styleUrls: ['./assignment-list.component.css']
}) })
export class AssignmentListComponent implements OnInit { export class AssignmentListComponent extends BaseComponent implements OnInit {
constructor() {} constructor(titleService: Title, protected translate: TranslateService) {
super(titleService, translate);
}
ngOnInit() {} ngOnInit() {
super.setTitle('Assignments');
}
downloadAssignmentButton(): void { downloadAssignmentButton(): void {
console.log('Hello World'); console.log('Hello World');

View File

@ -7,6 +7,7 @@ import { AuthService } from 'app/core/services/auth.service';
import { OperatorService } from 'app/core/services/operator.service'; import { OperatorService } from 'app/core/services/operator.service';
import { ErrorStateMatcher } from '@angular/material'; import { ErrorStateMatcher } from '@angular/material';
import { FormControl, FormGroupDirective, NgForm, FormGroup, Validators, FormBuilder } from '@angular/forms'; import { FormControl, FormGroupDirective, NgForm, FormGroup, Validators, FormBuilder } from '@angular/forms';
import { TranslateService } from '@ngx-translate/core';
/** /**
* Custom error states. Might become part of the shared module later. * Custom error states. Might become part of the shared module later.
@ -64,6 +65,7 @@ export class LoginComponent extends BaseComponent implements OnInit {
inProcess = false; inProcess = false;
/** /**
* Constructor for the login component
* *
* @param titleService Setting the title * @param titleService Setting the title
* @param authService Authenticating the user * @param authService Authenticating the user
@ -72,13 +74,14 @@ export class LoginComponent extends BaseComponent implements OnInit {
* @param formBuilder To build the form and validate * @param formBuilder To build the form and validate
*/ */
constructor( constructor(
titleService: Title, protected titleService: Title,
protected translate: TranslateService,
private authService: AuthService, private authService: AuthService,
private operator: OperatorService, private operator: OperatorService,
private router: Router, private router: Router,
private formBuilder: FormBuilder private formBuilder: FormBuilder
) { ) {
super(titleService); super(titleService, translate);
this.createForm(); this.createForm();
} }
@ -89,6 +92,8 @@ export class LoginComponent extends BaseComponent implements OnInit {
* Observes the operator, if a user was already logged in, recreate to user and skip the login * Observes the operator, if a user was already logged in, recreate to user and skip the login
*/ */
ngOnInit() { ngOnInit() {
//this is necessary since the HTML document never uses the word "Log In"
const loginWord = this.translate.instant('Log In');
super.setTitle('Log In'); super.setTitle('Log In');
// if there is stored login information, try to login directly. // if there is stored login information, try to login directly.

View File

@ -1,12 +1,19 @@
import { Component, OnInit } from '@angular/core'; import { Component, OnInit } from '@angular/core';
import { Title } from '@angular/platform-browser';
import { TranslateService } from '@ngx-translate/core';
import { BaseComponent } from '../../../base.component';
@Component({ @Component({
selector: 'app-mediafile-list', selector: 'app-mediafile-list',
templateUrl: './mediafile-list.component.html', templateUrl: './mediafile-list.component.html',
styleUrls: ['./mediafile-list.component.css'] styleUrls: ['./mediafile-list.component.css']
}) })
export class MediafileListComponent implements OnInit { export class MediafileListComponent extends BaseComponent implements OnInit {
constructor() {} constructor(titleService: Title, protected translate: TranslateService) {
super(titleService, translate);
}
ngOnInit() {} ngOnInit() {
super.setTitle('Files');
}
} }

View File

@ -39,3 +39,103 @@
Motion Works Motion Works
</div> </div>
</mat-card> </mat-card>
<mat-card class="os-card card-plus-distance">
<div class="app-content">
Motion Works
</div>
</mat-card>
<mat-card class="os-card card-plus-distance">
<div class="app-content">
Motion Works
</div>
</mat-card>
<mat-card class="os-card card-plus-distance">
<div class="app-content">
Motion Works
</div>
</mat-card>
<mat-card class="os-card card-plus-distance">
<div class="app-content">
Motion Works
</div>
</mat-card>
<mat-card class="os-card card-plus-distance">
<div class="app-content">
Motion Works
</div>
</mat-card>
<mat-card class="os-card card-plus-distance">
<div class="app-content">
Motion Works
</div>
</mat-card>
<mat-card class="os-card card-plus-distance">
<div class="app-content">
Motion Works
</div>
</mat-card>
<mat-card class="os-card card-plus-distance">
<div class="app-content">
Motion Works
</div>
</mat-card>
<mat-card class="os-card card-plus-distance">
<div class="app-content">
Motion Works
</div>
</mat-card>
<mat-card class="os-card card-plus-distance">
<div class="app-content">
Motion Works
</div>
</mat-card>
<mat-card class="os-card card-plus-distance">
<div class="app-content">
Motion Works
</div>
</mat-card>
<mat-card class="os-card card-plus-distance">
<div class="app-content">
Motion Works
</div>
</mat-card>
<mat-card class="os-card card-plus-distance">
<div class="app-content">
Motion Works
</div>
</mat-card>
<mat-card class="os-card card-plus-distance">
<div class="app-content">
Motion Works
</div>
</mat-card>
<mat-card class="os-card card-plus-distance">
<div class="app-content">
Motion Works
</div>
</mat-card>
<mat-card class="os-card card-plus-distance">
<div class="app-content">
Motion Works
</div>
</mat-card>
<mat-card class="os-card card-plus-distance">
<div class="app-content">
Motion Works
</div>
</mat-card>
<mat-card class="os-card card-plus-distance">
<div class="app-content">
Motion Works
</div>
</mat-card>
<mat-card class="os-card card-plus-distance">
<div class="app-content">
Motion Works
</div>
</mat-card>
<mat-card class="os-card card-plus-distance">
<div class="app-content">
Motion Works
</div>
</mat-card>

View File

@ -1,6 +1,7 @@
import { Component, OnInit } from '@angular/core'; import { Component, OnInit } from '@angular/core';
import { Title } from '@angular/platform-browser'; import { Title } from '@angular/platform-browser';
import { BaseComponent } from 'app/base.component'; import { BaseComponent } from 'app/base.component';
import { TranslateService } from '@ngx-translate/core';
@Component({ @Component({
selector: 'app-motion-list', selector: 'app-motion-list',
@ -8,8 +9,8 @@ import { BaseComponent } from 'app/base.component';
styleUrls: ['./motion-list.component.css'] styleUrls: ['./motion-list.component.css']
}) })
export class MotionListComponent extends BaseComponent implements OnInit { export class MotionListComponent extends BaseComponent implements OnInit {
constructor(titleService: Title) { constructor(titleService: Title, protected translate: TranslateService) {
super(titleService); super(titleService, translate);
} }
ngOnInit() { ngOnInit() {

View File

@ -1,12 +1,19 @@
import { Component, OnInit } from '@angular/core'; import { Component, OnInit } from '@angular/core';
import { Title } from '@angular/platform-browser';
import { TranslateService } from '@ngx-translate/core';
import { BaseComponent } from '../../../base.component';
@Component({ @Component({
selector: 'app-settings-list', selector: 'app-settings-list',
templateUrl: './settings-list.component.html', templateUrl: './settings-list.component.html',
styleUrls: ['./settings-list.component.css'] styleUrls: ['./settings-list.component.css']
}) })
export class SettingsListComponent implements OnInit { export class SettingsListComponent extends BaseComponent implements OnInit {
constructor() {} constructor(titleService: Title, protected translate: TranslateService) {
super(titleService, translate);
}
ngOnInit() {} ngOnInit() {
super.setTitle('Settings');
}
} }

View File

@ -1,10 +1,8 @@
<mat-sidenav-container autosize class='main-container'> <mat-sidenav-container autosize class='main-container'>
<mat-sidenav #sideNav [mode]="isMobile ? 'push' : 'side'" [opened]='!isMobile' disableClose='!isMobile' class="side-panel"> <mat-sidenav #sideNav [mode]="isMobile ? 'push' : 'side'" [opened]='!isMobile' disableClose='!isMobile' class="side-panel">
<mat-toolbar class='nav-toolbar'> <mat-toolbar class='nav-toolbar'>
<!-- logo --> <!-- logo -->
<mat-toolbar-row class='os-logo-container'> <mat-toolbar-row class='os-logo-container'>
<!-- <img src='/assets/img/openslides-logo-h-dark-transparent.svg' alt='OpenSlides-logo'> -->
</mat-toolbar-row> </mat-toolbar-row>
</mat-toolbar> </mat-toolbar>
@ -16,7 +14,6 @@
</mat-expansion-panel-header> </mat-expansion-panel-header>
<mat-nav-list> <mat-nav-list>
<!-- <mat-list-item> --> <!-- <mat-list-item> -->
<a (click)='logOutButton()' mat-list-item> <a (click)='logOutButton()' mat-list-item>
<fa-icon icon='user-cog'></fa-icon> <fa-icon icon='user-cog'></fa-icon>
<span translate>Edit Profile</span> <span translate>Edit Profile</span>
@ -30,24 +27,7 @@
<fa-icon icon='sign-out-alt'></fa-icon> <fa-icon icon='sign-out-alt'></fa-icon>
<span translate>Logout</span> <span translate>Logout</span>
</a> </a>
<!-- <button (click)='logOutButton()' mat-button>
<fa-icon icon='user-cog'></fa-icon> Edit Profile</button> -->
<!-- </mat-list-item>
<mat-list-item>
<button (click)='logOutButton()' mat-button>
<fa-icon icon='key'></fa-icon> Change Password</button>
</mat-list-item>
<mat-list-item>
<button (click)='logOutButton()' mat-button>
<fa-icon icon='sign-out-alt'> </fa-icon>Logout</button>
</mat-list-item> -->
</mat-nav-list> </mat-nav-list>
<!-- TODO translate -->
</mat-expansion-panel> </mat-expansion-panel>
<!-- navigation --> <!-- navigation -->
@ -87,9 +67,12 @@
<footer> <footer>
<!-- TODO Translate --> <button mat-button (click)='openLegalNotice()'>
<button mat-button (click)='openLegalNotice()'>Legal Notice</button> <span translate>Legal Notice</span>
<button mat-button (click)='openPrivacyPolicy()'>Privacy Policy</button> </button>
<button mat-button (click)='openPrivacyPolicy()'>
<span translate>Privacy Policy</span>
</button>
<br> <br>
<span align="center">© Copyright by <span align="center">© Copyright by
<a href='https://openslides.org/'>OpenSlides</a> <a href='https://openslides.org/'>OpenSlides</a>
@ -98,11 +81,10 @@
</mat-sidenav> </mat-sidenav>
<!-- the first toolbar row is (still) a global element <!-- the first toolbar row is (still) a global element
the second one shall be handled by the apps --> the second one shall be handled by the apps -->
<mat-toolbar color='primary'> <mat-toolbar color='primary'>
<!-- show/hide menu button --> <!-- show/hide menu button -->
<!-- <button mat-icon-button (click)='sideNav.toggle()'> -->
<button mat-icon-button *ngIf="isMobile" (click)='sideNav.toggle()'> <button mat-icon-button *ngIf="isMobile" (click)='sideNav.toggle()'>
<fa-icon icon='bars'></fa-icon> <fa-icon icon='bars'></fa-icon>
</button> </button>

View File

@ -1,11 +1,16 @@
mat-sidenav-container { mat-sidenav-container {
height: 100%; height: 100%;
main {
flex: 1;
position: relative;
}
} }
.projector-button { .projector-button {
position: absolute; position: fixed;
bottom: 10px; bottom: 10px;
right: 10px; right: 20px;
} }
.os-logo-container { .os-logo-container {

View File

@ -1,4 +1,4 @@
import { Component, OnInit } from '@angular/core'; import { Component, OnInit, HostBinding } from '@angular/core';
import { Router } from '@angular/router'; import { Router } from '@angular/router';
import { BreakpointObserver, Breakpoints, BreakpointState } from '@angular/cdk/layout'; import { BreakpointObserver, Breakpoints, BreakpointState } from '@angular/cdk/layout';
@ -29,7 +29,6 @@ export class SiteComponent extends BaseComponent implements OnInit {
* True if Viewport equals mobile or small resolution. Set by breakpointObserver. * True if Viewport equals mobile or small resolution. Set by breakpointObserver.
*/ */
isMobile = false; isMobile = false;
/** /**
* Constructor * Constructor
* *
@ -47,7 +46,7 @@ export class SiteComponent extends BaseComponent implements OnInit {
private operator: OperatorService, private operator: OperatorService,
private router: Router, private router: Router,
private breakpointObserver: BreakpointObserver, private breakpointObserver: BreakpointObserver,
private translate: TranslateService, protected translate: TranslateService,
public dialog: MatDialog public dialog: MatDialog
) { ) {
super(); super();

View File

@ -17,12 +17,12 @@ export class StartComponent extends BaseComponent implements OnInit {
//useage of translation with variables in code and view //useage of translation with variables in code and view
username = { user: this.operator.username }; username = { user: this.operator.username };
constructor(titleService: Title, private translate: TranslateService, private operator: OperatorService) { constructor(titleService: Title, protected translate: TranslateService, private operator: OperatorService) {
super(titleService); super(titleService, translate);
} }
ngOnInit() { ngOnInit() {
super.setTitle('Start page'); //TODO translate super.setTitle('Home');
} }
//quick testing of some data store functions //quick testing of some data store functions

View File

@ -1,12 +1,19 @@
import { Component, OnInit } from '@angular/core'; import { Component, OnInit } from '@angular/core';
import { Title } from '@angular/platform-browser';
import { TranslateService } from '@ngx-translate/core';
import { BaseComponent } from '../../../base.component';
@Component({ @Component({
selector: 'app-user-list', selector: 'app-user-list',
templateUrl: './user-list.component.html', templateUrl: './user-list.component.html',
styleUrls: ['./user-list.component.css'] styleUrls: ['./user-list.component.css']
}) })
export class UserListComponent implements OnInit { export class UserListComponent extends BaseComponent implements OnInit {
constructor() {} constructor(titleService: Title, protected translate: TranslateService) {
super(titleService, translate);
}
ngOnInit() {} ngOnInit() {
super.setTitle('Users');
}
} }

View File

@ -1,10 +1,21 @@
{ {
"Agenda": "Tagesordnung", "Agenda": "Tagesordnung",
"Assignments": "Wahlen",
"Change Password": "Passwort ändern",
"Edit Profile": "Profil bearbeiten",
"English": "Englisch", "English": "Englisch",
"French": "", "Files": "Dateien",
"French": "Französisch",
"German": "Deutsch", "German": "Deutsch",
"Hello user": "Hallo {{user}}", "Hello user": "Hallo {{user}}",
"Home": "Startseite", "Home": "Startseite",
"Legal Notice": "Impressum",
"Log In": "Anmelden",
"Logout": "Abmelden",
"Motions": "Anträge", "Motions": "Anträge",
"Participants": "Teilnehmer",
"Privacy Policy": "Datenschutz",
"Settings": "Einstellungen",
"Users": "Benutzer",
"Welcome to OpenSlides": "Willkommen bei OpenSlides" "Welcome to OpenSlides": "Willkommen bei OpenSlides"
} }

View File

@ -1,10 +1,21 @@
{ {
"Agenda": "Agenda", "Agenda": "",
"English": "English", "Assignments": "",
"Change Password": "",
"Edit Profile": "",
"English": "",
"Files": "",
"French": "", "French": "",
"German": "German", "German": "",
"Hello user": "Hello {{user}}", "Hello user": "Hello {{user}}",
"Home": "Home", "Home": "",
"Motions": "Motions", "Legal Notice": "",
"Welcome to OpenSlides": "Welcome to OpenSlides" "Log In": "",
"Logout": "",
"Motions": "",
"Participants": "",
"Privacy Policy": "",
"Settings": "",
"Users": "",
"Welcome to OpenSlides": ""
} }

View File

@ -1,10 +1,21 @@
{ {
"Agenda": "", "Agenda": "",
"Assignments": "",
"Change Password": "",
"Edit Profile": "",
"English": "", "English": "",
"Files": "",
"French": "", "French": "",
"German": "", "German": "",
"Hello user": "", "Hello user": "",
"Home": "", "Home": "",
"Legal Notice": "",
"Log In": "",
"Logout": "",
"Motions": "", "Motions": "",
"Participants": "",
"Privacy Policy": "",
"Settings": "",
"Users": "",
"Welcome to OpenSlides": "" "Welcome to OpenSlides": ""
} }

View File

@ -27,7 +27,6 @@ body {
right: 0; right: 0;
margin: 0; margin: 0;
padding: 0; padding: 0;
overflow: hidden !important;
height: 100% !important; height: 100% !important;
} }
@ -39,9 +38,8 @@ body {
router-outlet ~ * { router-outlet ~ * {
position: absolute; position: absolute;
height: 100%; height: 100% !important;
width: 100%; width: 100%;
overflow: hidden !important;
} }
/**the plus button in Motion, Agenda, etc*/ /**the plus button in Motion, Agenda, etc*/