Просмотр исходного кода

feat(admin-ui): Enable ui language config & selection

Relates to #264
Michael Bromley 5 лет назад
Родитель
Сommit
aa4452ec23
29 измененных файлов с 193 добавлено и 168 удалено
  1. 1 1
      packages/admin-ui/package.json
  2. 0 3
      packages/admin-ui/src/lib/core/src/app.config.ts
  3. 0 5
      packages/admin-ui/src/lib/core/src/common/utilities/get-default-currency.ts
  4. 2 2
      packages/admin-ui/src/lib/core/src/common/utilities/get-default-language.ts
  5. 5 2
      packages/admin-ui/src/lib/core/src/components/app-shell/app-shell.component.html
  6. 3 0
      packages/admin-ui/src/lib/core/src/components/app-shell/app-shell.component.scss
  7. 0 25
      packages/admin-ui/src/lib/core/src/components/app-shell/app-shell.component.spec.ts
  8. 43 3
      packages/admin-ui/src/lib/core/src/components/app-shell/app-shell.component.ts
  9. 6 0
      packages/admin-ui/src/lib/core/src/components/ui-language-switcher-dialog/ui-language-switcher-dialog.component.html
  10. 3 0
      packages/admin-ui/src/lib/core/src/components/ui-language-switcher-dialog/ui-language-switcher-dialog.component.scss
  11. 20 0
      packages/admin-ui/src/lib/core/src/components/ui-language-switcher-dialog/ui-language-switcher-dialog.component.ts
  12. 0 8
      packages/admin-ui/src/lib/core/src/components/ui-language-switcher/ui-language-switcher.component.html
  13. 0 16
      packages/admin-ui/src/lib/core/src/components/ui-language-switcher/ui-language-switcher.component.scss
  14. 0 30
      packages/admin-ui/src/lib/core/src/components/ui-language-switcher/ui-language-switcher.component.ts
  15. 12 1
      packages/admin-ui/src/lib/core/src/components/user-menu/user-menu.component.html
  16. 0 25
      packages/admin-ui/src/lib/core/src/components/user-menu/user-menu.component.spec.ts
  17. 6 2
      packages/admin-ui/src/lib/core/src/components/user-menu/user-menu.component.ts
  18. 25 6
      packages/admin-ui/src/lib/core/src/core.module.ts
  19. 23 19
      packages/admin-ui/src/lib/core/src/data/client-state/client-defaults.ts
  20. 4 3
      packages/admin-ui/src/lib/core/src/data/data.module.ts
  21. 7 0
      packages/admin-ui/src/lib/core/src/providers/i18n/i18n.service.mock.ts
  22. 13 0
      packages/admin-ui/src/lib/core/src/providers/i18n/i18n.service.ts
  23. 1 1
      packages/admin-ui/src/lib/core/src/providers/local-storage/local-storage.service.ts
  24. 1 2
      packages/admin-ui/src/lib/core/src/public_api.ts
  25. 1 3
      packages/admin-ui/src/lib/core/src/shared/components/affixed-input/percentage-suffix-input.component.ts
  26. 1 4
      packages/admin-ui/src/lib/core/src/shared/components/currency-input/currency-input.component.ts
  27. 2 1
      packages/admin-ui/src/lib/static/i18n-messages/en.json
  28. 3 1
      packages/admin-ui/src/lib/static/vendure-ui-config.json
  29. 11 5
      packages/common/src/shared-types.ts

+ 1 - 1
packages/admin-ui/package.json

@@ -10,7 +10,7 @@
     "watch": "ng build --watch=true",
     "test": "ng test --watch=false --browsers=ChromeHeadlessCI --progress=false",
     "lint": "tslint --fix",
-    "extract-translations": "ngx-translate-extract --input ./src/lib --output ./src/lib/static/i18n-messages/en.json --clean --sort --format namespaced-json --format-indentation \"  \" -m _",
+    "extract-translations": "ngx-translate-extract --input ./src --output ./src/lib/static/i18n-messages/en.json --clean --sort --format namespaced-json --format-indentation \"  \" -m _",
     "ngcc": "ngcc --properties es2015 browser module main --first-only --create-ivy-entry-points"
   },
   "publishConfig": {

+ 0 - 3
packages/admin-ui/src/lib/core/src/app.config.ts

@@ -2,9 +2,6 @@ import { AdminUiConfig } from '@vendure/common/lib/shared-types';
 
 import { LanguageCode } from './common/generated-types';
 
-export const DEFAULT_LANGUAGE: LanguageCode = LanguageCode.en;
-export const DEFAULT_CURRENCY = '£';
-
 let vendureUiConfig: AdminUiConfig | undefined;
 
 export function loadAppConfig(): Promise<void> {

+ 0 - 5
packages/admin-ui/src/lib/core/src/common/utilities/get-default-currency.ts

@@ -1,5 +0,0 @@
-import { DEFAULT_CURRENCY } from '../../app.config';
-
-export function getDefaultCurrency(): string {
-    return DEFAULT_CURRENCY;
-}

+ 2 - 2
packages/admin-ui/src/lib/core/src/common/utilities/get-default-language.ts

@@ -1,6 +1,6 @@
-import { DEFAULT_LANGUAGE } from '../../app.config';
+import { getAppConfig } from '../../app.config';
 import { LanguageCode } from '../generated-types';
 
 export function getDefaultLanguage(): LanguageCode {
-    return DEFAULT_LANGUAGE;
+    return getAppConfig().defaultLanguage;
 }

+ 5 - 2
packages/admin-ui/src/lib/core/src/components/app-shell/app-shell.component.html

@@ -5,9 +5,12 @@
         </div>
         <div class="header-nav"></div>
         <div class="header-actions">
-            <!-- <vdr-ui-language-switcher></vdr-ui-language-switcher> -->
             <vdr-channel-switcher *vdrIfMultichannel></vdr-channel-switcher>
-            <vdr-user-menu [userName]="userName$ | async" (logOut)="logOut()"></vdr-user-menu>
+            <vdr-user-menu [userName]="userName$ | async"
+                           [uiLanguage]="uiLanguage$ | async"
+                           [availableLanguages]="availableLanguages"
+                           (selectUiLanguage)="selectUiLanguage()"
+                           (logOut)="logOut()"></vdr-user-menu>
         </div>
     </clr-header>
     <nav class="subnav"><vdr-breadcrumb></vdr-breadcrumb></nav>

+ 3 - 0
packages/admin-ui/src/lib/core/src/components/app-shell/app-shell.component.scss

@@ -11,6 +11,9 @@ vdr-breadcrumb {
         margin-left: 10.8rem;
     }
 }
+.header-actions {
+    align-items: center;
+}
 .content-area {
     position: relative;
 }

+ 0 - 25
packages/admin-ui/src/lib/core/src/components/app-shell/app-shell.component.spec.ts

@@ -1,25 +0,0 @@
-import { async, ComponentFixture, TestBed } from '@angular/core/testing';
-
-import { AppShellComponent } from './app-shell.component';
-
-describe('AppShellComponent', () => {
-    /*let component: AppShellComponent;
-    let fixture: ComponentFixture<AppShellComponent>;
-
-    beforeEach(async(() => {
-        TestBed.configureTestingModule({
-            declarations: [ AppShellComponent ]
-        })
-            .compileComponents();
-    }));
-
-    beforeEach(() => {
-        fixture = TestBed.createComponent(AppShellComponent);
-        component = fixture.componentInstance;
-        fixture.detectChanges();
-    });
-
-    it('should create', () => {
-        expect(component).toBeTruthy();
-    });*/
-});

+ 43 - 3
packages/admin-ui/src/lib/core/src/components/app-shell/app-shell.component.ts

@@ -1,10 +1,15 @@
 import { Component, OnInit } from '@angular/core';
 import { Router } from '@angular/router';
-import { Observable } from 'rxjs';
-import { map } from 'rxjs/operators';
+import { EMPTY, Observable } from 'rxjs';
+import { map, switchMap, take } from 'rxjs/operators';
 
+import { LanguageCode } from '../../common/generated-types';
 import { DataService } from '../../data/providers/data.service';
 import { AuthService } from '../../providers/auth/auth.service';
+import { I18nService } from '../../providers/i18n/i18n.service';
+import { LocalStorageService } from '../../providers/local-storage/local-storage.service';
+import { ModalService } from '../../providers/modal/modal.service';
+import { UiLanguageSwitcherDialogComponent } from '../ui-language-switcher-dialog/ui-language-switcher-dialog.component';
 
 @Component({
     selector: 'vdr-app-shell',
@@ -13,13 +18,48 @@ import { AuthService } from '../../providers/auth/auth.service';
 })
 export class AppShellComponent implements OnInit {
     userName$: Observable<string>;
+    uiLanguage$: Observable<LanguageCode>;
+    availableLanguages: LanguageCode[] = [];
 
-    constructor(private authService: AuthService, private dataService: DataService, private router: Router) {}
+    constructor(
+        private authService: AuthService,
+        private dataService: DataService,
+        private router: Router,
+        private i18nService: I18nService,
+        private modalService: ModalService,
+        private localStorageService: LocalStorageService,
+    ) {}
 
     ngOnInit() {
         this.userName$ = this.dataService.client
             .userStatus()
             .single$.pipe(map(data => data.userStatus.username));
+        this.uiLanguage$ = this.dataService.client.uiState().stream$.pipe(map(data => data.uiState.language));
+        this.availableLanguages = this.i18nService.availableLanguages;
+    }
+
+    selectUiLanguage() {
+        this.uiLanguage$
+            .pipe(
+                take(1),
+                switchMap(currentLanguage =>
+                    this.modalService.fromComponent(UiLanguageSwitcherDialogComponent, {
+                        closable: true,
+                        size: 'sm',
+                        locals: {
+                            availableLanguages: this.availableLanguages,
+                            currentLanguage,
+                        },
+                    }),
+                ),
+                switchMap(value => (value ? this.dataService.client.setUiLanguage(value) : EMPTY)),
+            )
+            .subscribe(result => {
+                if (result.setUiLanguage) {
+                    this.i18nService.setLanguage(result.setUiLanguage);
+                    this.localStorageService.set('uiLanguageCode', result.setUiLanguage);
+                }
+            });
     }
 
     logOut() {

+ 6 - 0
packages/admin-ui/src/lib/core/src/components/ui-language-switcher-dialog/ui-language-switcher-dialog.component.html

@@ -0,0 +1,6 @@
+<ng-template vdrDialogTitle>{{ 'common.select-display-language' | translate }}</ng-template>
+
+<button *ngFor="let code of availableLanguages" class="btn btn-link btn-sm" (click)="setLanguage(code)">
+    <clr-icon [attr.shape]="code === currentLanguage ? 'dot-circle' : 'circle'"></clr-icon>
+    {{ code | uppercase }} ({{ 'lang.' + code | translate }})
+</button>

+ 3 - 0
packages/admin-ui/src/lib/core/src/components/ui-language-switcher-dialog/ui-language-switcher-dialog.component.scss

@@ -0,0 +1,3 @@
+:host {
+}
+

+ 20 - 0
packages/admin-ui/src/lib/core/src/components/ui-language-switcher-dialog/ui-language-switcher-dialog.component.ts

@@ -0,0 +1,20 @@
+import { ChangeDetectionStrategy, Component } from '@angular/core';
+
+import { LanguageCode } from '../../common/generated-types';
+import { Dialog } from '../../providers/modal/modal.service';
+
+@Component({
+    selector: 'vdr-ui-language-switcher',
+    templateUrl: './ui-language-switcher-dialog.component.html',
+    styleUrls: ['./ui-language-switcher-dialog.component.scss'],
+    changeDetection: ChangeDetectionStrategy.OnPush,
+})
+export class UiLanguageSwitcherDialogComponent implements Dialog<LanguageCode> {
+    resolveWith: (result?: LanguageCode) => void;
+    currentLanguage: LanguageCode;
+    availableLanguages: LanguageCode[] = [];
+
+    setLanguage(languageCode: LanguageCode) {
+        this.resolveWith(languageCode);
+    }
+}

+ 0 - 8
packages/admin-ui/src/lib/core/src/components/ui-language-switcher/ui-language-switcher.component.html

@@ -1,8 +0,0 @@
-<vdr-dropdown>
-    <span class="user-name">{{ uiLanguage$ | async }}</span>
-    <span class="trigger" vdrDropdownTrigger><clr-icon shape="caret down"></clr-icon></span>
-    <vdr-dropdown-menu vdrPosition="bottom-right">
-        <button type="button" vdrDropdownItem (click)="setLanguage('en')">EN</button>
-        <button type="button" vdrDropdownItem (click)="setLanguage('de')">DE</button>
-    </vdr-dropdown-menu>
-</vdr-dropdown>

+ 0 - 16
packages/admin-ui/src/lib/core/src/components/ui-language-switcher/ui-language-switcher.component.scss

@@ -1,16 +0,0 @@
-:host {
-    display: flex;
-    align-items: center;
-    margin: 0 0.5rem;
-    height: 2.5rem;
-}
-
-.user-name {
-    color: lightgrey;
-    margin-right: 12px;
-}
-
-.trigger clr-icon {
-    color: white;
-}
-

+ 0 - 30
packages/admin-ui/src/lib/core/src/components/ui-language-switcher/ui-language-switcher.component.ts

@@ -1,30 +0,0 @@
-import { ChangeDetectionStrategy, Component, OnInit } from '@angular/core';
-import { Observable } from 'rxjs';
-import { map, tap } from 'rxjs/operators';
-
-import { LanguageCode } from '../../common/generated-types';
-import { DataService } from '../../data/providers/data.service';
-import { I18nService } from '../../providers/i18n/i18n.service';
-
-@Component({
-    selector: 'vdr-ui-language-switcher',
-    templateUrl: './ui-language-switcher.component.html',
-    styleUrls: ['./ui-language-switcher.component.scss'],
-    changeDetection: ChangeDetectionStrategy.OnPush,
-})
-export class UiLanguageSwitcherComponent implements OnInit {
-    uiLanguage$: Observable<LanguageCode>;
-
-    constructor(private dataService: DataService, private i18nService: I18nService) {}
-
-    ngOnInit() {
-        this.uiLanguage$ = this.dataService.client.uiState().stream$.pipe(
-            map(data => data.uiState.language),
-            tap(languageCode => this.i18nService.setLanguage(languageCode)),
-        );
-    }
-
-    setLanguage(languageCode: string) {
-        this.dataService.client.setUiLanguage(languageCode as LanguageCode).subscribe();
-    }
-}

+ 12 - 1
packages/admin-ui/src/lib/core/src/components/user-menu/user-menu.component.html

@@ -5,8 +5,19 @@
         <clr-icon shape="caret down"></clr-icon>
     </button>
     <vdr-dropdown-menu vdrPosition="bottom-right">
+        <ng-container *ngIf="1 < availableLanguages.length">
+            <button
+                type="button"
+                vdrDropdownItem
+                (click)="selectUiLanguage.emit()"
+                [title]="'common.select-display-language' | translate"
+            >
+                <clr-icon shape="language"></clr-icon> {{ 'lang.' + uiLanguage | translate }}
+            </button>
+            <div class="dropdown-divider"></div>
+        </ng-container>
         <button type="button" vdrDropdownItem (click)="logOut.emit()">
-            {{ 'common.log-out' | translate }}
+            <clr-icon shape="logout"></clr-icon> {{ 'common.log-out' | translate }}
         </button>
     </vdr-dropdown-menu>
 </vdr-dropdown>

+ 0 - 25
packages/admin-ui/src/lib/core/src/components/user-menu/user-menu.component.spec.ts

@@ -1,25 +0,0 @@
-import { async, ComponentFixture, TestBed } from '@angular/core/testing';
-
-import { UserMenuComponent } from './user-menu.component';
-
-describe('UserMenuComponent', () => {
-    /*let component: UserMenuComponent;
-    let fixture: ComponentFixture<UserMenuComponent>;
-
-    beforeEach(async(() => {
-        TestBed.configureTestingModule({
-            declarations: [ UserMenuComponent ]
-        })
-            .compileComponents();
-    }));
-
-    beforeEach(() => {
-        fixture = TestBed.createComponent(UserMenuComponent);
-        component = fixture.componentInstance;
-        fixture.detectChanges();
-    });
-
-    it('should create', () => {
-        expect(component).toBeTruthy();
-    });*/
-});

+ 6 - 2
packages/admin-ui/src/lib/core/src/components/user-menu/user-menu.component.ts

@@ -1,4 +1,6 @@
-import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core';
+import { Component, EventEmitter, Input, Output } from '@angular/core';
+
+import { LanguageCode } from '../../common/generated-types';
 
 @Component({
     selector: 'vdr-user-menu',
@@ -7,6 +9,8 @@ import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core';
 })
 export class UserMenuComponent {
     @Input() userName = '';
-
+    @Input() availableLanguages: LanguageCode[] = [];
+    @Input() uiLanguage: LanguageCode;
     @Output() logOut = new EventEmitter<void>();
+    @Output() selectUiLanguage = new EventEmitter<void>();
 }

+ 25 - 6
packages/admin-ui/src/lib/core/src/core.module.ts

@@ -5,6 +5,7 @@ import { BrowserModule } from '@angular/platform-browser';
 import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
 import { TranslateCompiler, TranslateLoader, TranslateModule } from '@ngx-translate/core';
 
+import { getAppConfig } from './app.config';
 import { getDefaultLanguage } from './common/utilities/get-default-language';
 import { AppShellComponent } from './components/app-shell/app-shell.component';
 import { BreadcrumbComponent } from './components/breadcrumb/breadcrumb.component';
@@ -13,13 +14,13 @@ import { JobListComponent } from './components/job-list/job-list.component';
 import { MainNavComponent } from './components/main-nav/main-nav.component';
 import { NotificationComponent } from './components/notification/notification.component';
 import { OverlayHostComponent } from './components/overlay-host/overlay-host.component';
-import { UiLanguageSwitcherComponent } from './components/ui-language-switcher/ui-language-switcher.component';
+import { UiLanguageSwitcherDialogComponent } from './components/ui-language-switcher-dialog/ui-language-switcher-dialog.component';
 import { UserMenuComponent } from './components/user-menu/user-menu.component';
 import { DataModule } from './data/data.module';
-import { DataService } from './data/providers/data.service';
 import { CustomHttpTranslationLoader } from './providers/i18n/custom-http-loader';
 import { InjectableTranslateMessageFormatCompiler } from './providers/i18n/custom-message-format-compiler';
 import { I18nService } from './providers/i18n/i18n.service';
+import { LocalStorageService } from './providers/local-storage/local-storage.service';
 import { SharedModule } from './shared/shared.module';
 
 @NgModule({
@@ -45,15 +46,33 @@ import { SharedModule } from './shared/shared.module';
         BreadcrumbComponent,
         OverlayHostComponent,
         NotificationComponent,
-        UiLanguageSwitcherComponent,
+        UiLanguageSwitcherDialogComponent,
         JobListComponent,
         ChannelSwitcherComponent,
     ],
 })
 export class CoreModule {
-    constructor(private dataService: DataService, private i18nService: I18nService) {
-        this.dataService.client.setUiLanguage(getDefaultLanguage());
-        this.i18nService.setDefaultLanguage(getDefaultLanguage());
+    constructor(private i18nService: I18nService, private localStorageService: LocalStorageService) {
+        this.initUiLanguages();
+    }
+
+    private initUiLanguages() {
+        const defaultLanguage = getDefaultLanguage();
+        const lastLanguage = this.localStorageService.get('uiLanguageCode');
+        const availableLanguages = getAppConfig().availableLanguages;
+
+        if (!availableLanguages.includes(defaultLanguage)) {
+            throw new Error(
+                `The defaultLanguage "${defaultLanguage}" must be one of the availableLanguages [${availableLanguages
+                    .map(l => `"${l}"`)
+                    .join(', ')}]`,
+            );
+        }
+        const uiLanguage = availableLanguages.includes(lastLanguage) ? lastLanguage : defaultLanguage;
+        this.localStorageService.set('uiLanguageCode', uiLanguage);
+        this.i18nService.setLanguage(uiLanguage);
+        this.i18nService.setDefaultLanguage(defaultLanguage);
+        this.i18nService.setAvailableLanguages(availableLanguages || [defaultLanguage]);
     }
 }
 

+ 23 - 19
packages/admin-ui/src/lib/core/src/data/client-state/client-defaults.ts

@@ -1,22 +1,26 @@
 import { GetNetworkStatus, GetUiState, GetUserStatus } from '../../common/generated-types';
 import { getDefaultLanguage } from '../../common/utilities/get-default-language';
+import { LocalStorageService } from '../../providers/local-storage/local-storage.service';
 
-export const clientDefaults = {
-    networkStatus: {
-        inFlightRequests: 0,
-        __typename: 'NetworkStatus',
-    } as GetNetworkStatus.NetworkStatus,
-    userStatus: {
-        username: '',
-        isLoggedIn: false,
-        loginTime: '',
-        activeChannelId: null,
-        permissions: [],
-        channels: [],
-        __typename: 'UserStatus',
-    } as GetUserStatus.UserStatus,
-    uiState: {
-        language: getDefaultLanguage(),
-        __typename: 'UiState',
-    } as GetUiState.UiState,
-};
+export function getClientDefaults(localStorageService: LocalStorageService) {
+    const currentLanguage = localStorageService.get('uiLanguageCode') || getDefaultLanguage();
+    return {
+        networkStatus: {
+            inFlightRequests: 0,
+            __typename: 'NetworkStatus',
+        } as GetNetworkStatus.NetworkStatus,
+        userStatus: {
+            username: '',
+            isLoggedIn: false,
+            loginTime: '',
+            activeChannelId: null,
+            permissions: [],
+            channels: [],
+            __typename: 'UserStatus',
+        } as GetUserStatus.UserStatus,
+        uiState: {
+            language: currentLanguage,
+            __typename: 'UiState',
+        } as GetUiState.UiState,
+    };
+}

+ 4 - 3
packages/admin-ui/src/lib/core/src/data/data.module.ts

@@ -12,7 +12,7 @@ import { introspectionResult } from '../common/introspection-result-wrapper';
 import { LocalStorageService } from '../providers/local-storage/local-storage.service';
 
 import { CheckJobsLink } from './check-jobs-link';
-import { clientDefaults } from './client-state/client-defaults';
+import { getClientDefaults } from './client-state/client-defaults';
 import { clientResolvers } from './client-state/client-resolvers';
 import { OmitTypenameLink } from './omit-typename-link';
 import { BaseDataService } from './providers/base-data.service';
@@ -41,10 +41,11 @@ export function createApollo(
         }),
     });
     apolloCache.writeData({
-        data: clientDefaults,
+        data: getClientDefaults(localStorageService),
     });
 
-    if (!false) { // TODO: enable only for dev mode
+    if (!false) {
+        // TODO: enable only for dev mode
         // make the Apollo Cache inspectable in the console for debug purposes
         (window as any)['apolloCache'] = apolloCache;
     }

+ 7 - 0
packages/admin-ui/src/lib/core/src/providers/i18n/i18n.service.mock.ts

@@ -1,3 +1,5 @@
+import { TranslateService } from '@ngx-translate/core';
+
 import { MockOf } from '../../../../../testing/testing-types';
 import { LanguageCode } from '../../common/generated-types';
 
@@ -15,4 +17,9 @@ export class MockI18nService implements MockOf<I18nService> {
     translate(key: string | string[], params?: any) {
         return key as string;
     }
+
+    availableLanguages: LanguageCode[];
+    setAvailableLanguages: (languages: LanguageCode[]) => void;
+    _availableLanguages: LanguageCode[];
+    ngxTranslate: TranslateService;
 }

+ 13 - 0
packages/admin-ui/src/lib/core/src/providers/i18n/i18n.service.ts

@@ -7,6 +7,12 @@ import { LanguageCode } from '../../common/generated-types';
     providedIn: 'root',
 })
 export class I18nService {
+    _availableLanguages: LanguageCode[] = [];
+
+    get availableLanguages(): LanguageCode[] {
+        return [...this._availableLanguages];
+    }
+
     constructor(private ngxTranslate: TranslateService) {}
 
     /**
@@ -23,6 +29,13 @@ export class I18nService {
         this.ngxTranslate.use(language);
     }
 
+    /**
+     * Set the available UI languages
+     */
+    setAvailableLanguages(languages: LanguageCode[]) {
+        this._availableLanguages = languages;
+    }
+
     /**
      * Translate the given key.
      */

+ 1 - 1
packages/admin-ui/src/lib/core/src/providers/local-storage/local-storage.service.ts

@@ -1,7 +1,7 @@
 import { Location } from '@angular/common';
 import { Injectable } from '@angular/core';
 
-export type LocalStorageKey = 'activeChannelToken' | 'authToken';
+export type LocalStorageKey = 'activeChannelToken' | 'authToken' | 'uiLanguageCode';
 export type LocalStorageLocationBasedKey = 'shippingTestOrder' | 'shippingTestAddress';
 const PREFIX = 'vnd_';
 

+ 1 - 2
packages/admin-ui/src/lib/core/src/public_api.ts

@@ -14,7 +14,6 @@ export * from './common/language-translation-strings';
 export * from './common/utilities/create-updated-translatable';
 export * from './common/utilities/flatten-facet-values';
 export * from './common/utilities/get-default-config-arg-value';
-export * from './common/utilities/get-default-currency';
 export * from './common/utilities/get-default-language';
 export * from './common/utilities/interpolate-description';
 export * from './common/utilities/string-to-color';
@@ -26,7 +25,7 @@ export * from './components/job-list/job-list.component';
 export * from './components/main-nav/main-nav.component';
 export * from './components/notification/notification.component';
 export * from './components/overlay-host/overlay-host.component';
-export * from './components/ui-language-switcher/ui-language-switcher.component';
+export * from './components/ui-language-switcher-dialog/ui-language-switcher-dialog.component';
 export * from './components/user-menu/user-menu.component';
 export * from './core.module';
 export * from './data/check-jobs-link';

+ 1 - 3
packages/admin-ui/src/lib/core/src/shared/components/affixed-input/percentage-suffix-input.component.ts

@@ -1,8 +1,6 @@
-import { Component, Input, OnChanges, OnInit, SimpleChanges } from '@angular/core';
+import { Component, Input, OnChanges, SimpleChanges } from '@angular/core';
 import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';
 
-import { getDefaultCurrency } from '../../../common/utilities/get-default-currency';
-
 /**
  * A form input control which displays a number input with a percentage sign suffix.
  */

+ 1 - 4
packages/admin-ui/src/lib/core/src/shared/components/currency-input/currency-input.component.ts

@@ -1,8 +1,6 @@
-import { Component, Input, OnChanges, OnInit, SimpleChanges } from '@angular/core';
+import { Component, Input, OnChanges, SimpleChanges } from '@angular/core';
 import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';
 
-import { getDefaultCurrency } from '../../../common/utilities/get-default-currency';
-
 /**
  * A form input control which displays currency in decimal format, whilst working
  * with the intege cent value in the background.
@@ -27,7 +25,6 @@ export class CurrencyInputComponent implements ControlValueAccessor, OnChanges {
     onChange: (val: any) => void;
     onTouch: () => void;
     _decimalValue: string;
-    readonly currencySymbol = getDefaultCurrency();
 
     ngOnChanges(changes: SimpleChanges) {
         if ('value' in changes) {

+ 2 - 1
packages/admin-ui/src/lib/static/i18n-messages/en.json

@@ -178,6 +178,7 @@
     "remove": "Remove",
     "results-count": "{ count } {count, plural, one {result} other {results}}",
     "select": "Select...",
+    "select-display-language": "Select display language",
     "select-today": "Select today",
     "there-are-unsaved-changes": "There are unsaved changes. Navigating away will cause these changes to be lost.",
     "update": "Update",
@@ -628,4 +629,4 @@
     "update": "Update",
     "zone": "Zone"
   }
-}
+}

+ 3 - 1
packages/admin-ui/src/lib/static/vendure-ui-config.json

@@ -3,5 +3,7 @@
   "apiPort": "3000",
   "adminApiPath": "admin-api",
   "tokenMethod": "cookie",
-  "authTokenHeaderKey": "vendure-auth-token"
+  "authTokenHeaderKey": "vendure-auth-token",
+  "defaultLanguage": "en",
+  "availableLanguages": ["en", "es"]
 }

+ 11 - 5
packages/common/src/shared-types.ts

@@ -1,15 +1,19 @@
 // tslint:disable:no-shadowed-variable
 // prettier-ignore
+import { LanguageCode } from './generated-types';
+
 /**
  * A recursive implementation of the Partial<T> type.
  * Source: https://stackoverflow.com/a/49936686/772859
  */
 export type DeepPartial<T> = {
-    [P in keyof T]?: null | (T[P] extends Array<infer U>
-    ? Array<DeepPartial<U>>
-    : T[P] extends ReadonlyArray<infer U>
-        ? ReadonlyArray<DeepPartial<U>>
-        : DeepPartial<T[P]>)
+    [P in keyof T]?:
+        | null
+        | (T[P] extends Array<infer U>
+              ? Array<DeepPartial<U>>
+              : T[P] extends ReadonlyArray<infer U>
+              ? ReadonlyArray<DeepPartial<U>>
+              : DeepPartial<T[P]>)
 };
 // tslint:enable:no-shadowed-variable
 
@@ -101,6 +105,8 @@ export interface AdminUiConfig {
     adminApiPath: string;
     tokenMethod: 'cookie' | 'bearer';
     authTokenHeaderKey: string;
+    defaultLanguage: LanguageCode;
+    availableLanguages: LanguageCode[];
 }
 
 /**