Browse Source

feat(admin-ui): Add default language/currency to Channel detail

Michael Bromley 2 years ago
parent
commit
8ba910eb53
36 changed files with 392 additions and 141 deletions
  1. 34 34
      packages/admin-ui/i18n-coverage.json
  2. 2 2
      packages/admin-ui/src/lib/catalog/src/components/assign-products-to-channel-dialog/assign-products-to-channel-dialog.component.html
  3. 1 1
      packages/admin-ui/src/lib/catalog/src/components/generate-product-variants/generate-product-variants.component.ts
  4. 1 1
      packages/admin-ui/src/lib/catalog/src/components/product-variants-editor/product-variants-editor.component.ts
  5. 13 9
      packages/admin-ui/src/lib/core/src/common/generated-types.ts
  6. 3 1
      packages/admin-ui/src/lib/core/src/data/definitions/settings-definitions.ts
  7. 0 0
      packages/admin-ui/src/lib/core/src/shared/components/currency-code-selector/currency-code-selector.component.css
  8. 16 0
      packages/admin-ui/src/lib/core/src/shared/components/currency-code-selector/currency-code-selector.component.html
  9. 64 0
      packages/admin-ui/src/lib/core/src/shared/components/currency-code-selector/currency-code-selector.component.ts
  10. 1 8
      packages/admin-ui/src/lib/core/src/shared/components/form-field/form-field.component.scss
  11. 0 0
      packages/admin-ui/src/lib/core/src/shared/components/language-code-selector/language-code-selector.component.css
  12. 17 0
      packages/admin-ui/src/lib/core/src/shared/components/language-code-selector/language-code-selector.component.html
  13. 80 0
      packages/admin-ui/src/lib/core/src/shared/components/language-code-selector/language-code-selector.component.ts
  14. 1 1
      packages/admin-ui/src/lib/core/src/shared/dynamic-form-inputs/currency-form-input/currency-form-input.component.ts
  15. 4 6
      packages/admin-ui/src/lib/core/src/shared/pipes/locale-currency-name.pipe.ts
  16. 4 0
      packages/admin-ui/src/lib/core/src/shared/shared.module.ts
  17. 1 1
      packages/admin-ui/src/lib/dashboard/src/widgets/order-chart-widget/order-chart-widget.component.ts
  18. 1 1
      packages/admin-ui/src/lib/dashboard/src/widgets/order-summary-widget/order-summary-widget.component.ts
  19. 68 32
      packages/admin-ui/src/lib/settings/src/components/channel-detail/channel-detail.component.html
  20. 14 7
      packages/admin-ui/src/lib/settings/src/components/channel-detail/channel-detail.component.ts
  21. 8 22
      packages/admin-ui/src/lib/settings/src/components/global-settings/global-settings.component.html
  22. 1 1
      packages/admin-ui/src/lib/settings/src/components/test-order-builder/test-order-builder.component.ts
  23. 6 1
      packages/admin-ui/src/lib/settings/src/settings.module.ts
  24. 4 1
      packages/admin-ui/src/lib/static/i18n-messages/cs.json
  25. 4 1
      packages/admin-ui/src/lib/static/i18n-messages/de.json
  26. 4 1
      packages/admin-ui/src/lib/static/i18n-messages/en.json
  27. 4 1
      packages/admin-ui/src/lib/static/i18n-messages/es.json
  28. 4 1
      packages/admin-ui/src/lib/static/i18n-messages/fr.json
  29. 4 1
      packages/admin-ui/src/lib/static/i18n-messages/it.json
  30. 4 1
      packages/admin-ui/src/lib/static/i18n-messages/pl.json
  31. 4 1
      packages/admin-ui/src/lib/static/i18n-messages/pt_BR.json
  32. 4 1
      packages/admin-ui/src/lib/static/i18n-messages/pt_PT.json
  33. 4 1
      packages/admin-ui/src/lib/static/i18n-messages/ru.json
  34. 4 1
      packages/admin-ui/src/lib/static/i18n-messages/uk.json
  35. 4 1
      packages/admin-ui/src/lib/static/i18n-messages/zh_Hans.json
  36. 4 1
      packages/admin-ui/src/lib/static/i18n-messages/zh_Hant.json

+ 34 - 34
packages/admin-ui/i18n-coverage.json

@@ -1,71 +1,71 @@
 {
-  "generatedOn": "2023-06-02T10:15:42.053Z",
-  "lastCommit": "7e5e5d5db56a57946f8ba699311680cb3defc85c",
+  "generatedOn": "2023-06-02T14:07:46.839Z",
+  "lastCommit": "686dbcbe221581232110f06f8016eadeda55a59d",
   "translationStatus": {
     "cs": {
-      "tokenCount": 725,
-      "translatedCount": 547,
+      "tokenCount": 728,
+      "translatedCount": 546,
       "percentage": 75
     },
     "de": {
-      "tokenCount": 725,
-      "translatedCount": 530,
+      "tokenCount": 728,
+      "translatedCount": 529,
       "percentage": 73
     },
     "en": {
-      "tokenCount": 725,
-      "translatedCount": 723,
+      "tokenCount": 728,
+      "translatedCount": 727,
       "percentage": 100
     },
     "es": {
-      "tokenCount": 725,
-      "translatedCount": 572,
-      "percentage": 79
+      "tokenCount": 728,
+      "translatedCount": 571,
+      "percentage": 78
     },
     "fr": {
-      "tokenCount": 725,
-      "translatedCount": 567,
+      "tokenCount": 728,
+      "translatedCount": 566,
       "percentage": 78
     },
     "it": {
-      "tokenCount": 725,
-      "translatedCount": 571,
-      "percentage": 79
+      "tokenCount": 728,
+      "translatedCount": 570,
+      "percentage": 78
     },
     "pl": {
-      "tokenCount": 725,
-      "translatedCount": 381,
-      "percentage": 53
+      "tokenCount": 728,
+      "translatedCount": 380,
+      "percentage": 52
     },
     "pt_BR": {
-      "tokenCount": 725,
-      "translatedCount": 545,
+      "tokenCount": 728,
+      "translatedCount": 544,
       "percentage": 75
     },
     "pt_PT": {
-      "tokenCount": 725,
-      "translatedCount": 580,
+      "tokenCount": 728,
+      "translatedCount": 579,
       "percentage": 80
     },
     "ru": {
-      "tokenCount": 725,
-      "translatedCount": 570,
-      "percentage": 79
+      "tokenCount": 728,
+      "translatedCount": 569,
+      "percentage": 78
     },
     "uk": {
-      "tokenCount": 725,
-      "translatedCount": 570,
-      "percentage": 79
+      "tokenCount": 728,
+      "translatedCount": 569,
+      "percentage": 78
     },
     "zh_Hans": {
-      "tokenCount": 725,
-      "translatedCount": 516,
+      "tokenCount": 728,
+      "translatedCount": 515,
       "percentage": 71
     },
     "zh_Hant": {
-      "tokenCount": 725,
-      "translatedCount": 361,
-      "percentage": 50
+      "tokenCount": 728,
+      "translatedCount": 360,
+      "percentage": 49
     }
   }
 }

+ 2 - 2
packages/admin-ui/src/lib/catalog/src/components/assign-products-to-channel-dialog/assign-products-to-channel-dialog.component.html

@@ -48,10 +48,10 @@
         <tbody>
             <tr *ngFor="let row of variantsPreview$ | async">
                 <td>{{ row.name }}</td>
-                <td>{{ row.price | localeCurrency: currentChannel?.currencyCode }}</td>
+                <td>{{ row.price | localeCurrency: currentChannel?.defaultCurrencyCode }}</td>
                 <td>
                     <ng-template [ngIf]="selectedChannel" [ngIfElse]="noChannelSelected">
-                        {{ row.pricePreview | localeCurrency: selectedChannel?.currencyCode }}
+                        {{ row.pricePreview | localeCurrency: selectedChannel?.defaultCurrencyCode }}
                     </ng-template>
                     <ng-template #noChannelSelected> - </ng-template>
                 </td>

+ 1 - 1
packages/admin-ui/src/lib/catalog/src/components/generate-product-variants/generate-product-variants.component.ts

@@ -42,7 +42,7 @@ export class GenerateProductVariantsComponent implements OnInit {
 
     ngOnInit() {
         this.dataService.settings.getActiveChannel().single$.subscribe(data => {
-            this.currencyCode = data.activeChannel.currencyCode;
+            this.currencyCode = data.activeChannel.defaultCurrencyCode;
         });
 
         this.generateVariants();

+ 1 - 1
packages/admin-ui/src/lib/catalog/src/components/product-variants-editor/product-variants-editor.component.ts

@@ -93,7 +93,7 @@ export class ProductVariantsEditorComponent implements OnInit, DeactivateAware {
         this.languageCode =
             (this.route.snapshot.paramMap.get('lang') as LanguageCode) || getDefaultUiLanguage();
         this.dataService.settings.getActiveChannel().single$.subscribe(data => {
-            this.currencyCode = data.activeChannel.currencyCode;
+            this.currencyCode = data.activeChannel.defaultCurrencyCode;
         });
 
         const product$ = this.refresh$.pipe(

File diff suppressed because it is too large
+ 13 - 9
packages/admin-ui/src/lib/core/src/common/generated-types.ts


+ 3 - 1
packages/admin-ui/src/lib/core/src/data/definitions/settings-definitions.ts

@@ -296,7 +296,9 @@ export const CHANNEL_FRAGMENT = gql`
         code
         token
         pricesIncludeTax
-        currencyCode
+        availableCurrencyCodes
+        availableLanguageCodes
+        defaultCurrencyCode
         defaultLanguageCode
         defaultShippingZone {
             id

+ 0 - 0
packages/admin-ui/src/lib/core/src/shared/components/currency-code-selector/currency-code-selector.component.css


+ 16 - 0
packages/admin-ui/src/lib/core/src/shared/components/currency-code-selector/currency-code-selector.component.html

@@ -0,0 +1,16 @@
+<ng-select
+    [items]="currencyCodes"
+    [addTag]="false"
+    [hideSelected]="true"
+    [searchFn]="searchCurrencyCodes"
+    multiple="true"
+    appendTo="body"
+    [(ngModel)]="value"
+    (ngModelChange)="onChangeFn($event)"
+>
+    <ng-template ng-label-tmp let-item="item" let-clear="clear">
+        <span class="ng-value-icon left" (click)="clear.call(null, item)" aria-hidden="true"> × </span>
+        <span class="ng-value-label">{{ item | localeCurrencyName }}</span>
+    </ng-template>
+    <ng-template ng-option-tmp let-item="item">{{ item | localeCurrencyName }}</ng-template>
+</ng-select>

+ 64 - 0
packages/admin-ui/src/lib/core/src/shared/components/currency-code-selector/currency-code-selector.component.ts

@@ -0,0 +1,64 @@
+import { ChangeDetectionStrategy, ChangeDetectorRef, Component, forwardRef, OnDestroy } from '@angular/core';
+import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';
+import { CurrencyCode, DataService } from '@vendure/admin-ui/core';
+import { Subscription } from 'rxjs';
+
+@Component({
+    selector: 'vdr-currency-code-selector',
+    templateUrl: './currency-code-selector.component.html',
+    styleUrls: ['./currency-code-selector.component.css'],
+    changeDetection: ChangeDetectionStrategy.OnPush,
+    providers: [
+        {
+            provide: NG_VALUE_ACCESSOR,
+            useExisting: forwardRef(() => CurrencyCodeSelectorComponent),
+            multi: true,
+        },
+    ],
+})
+export class CurrencyCodeSelectorComponent implements ControlValueAccessor, OnDestroy {
+    currencyCodes = Object.values(CurrencyCode);
+    private subscription: Subscription;
+    private locale: string;
+    protected value: string | undefined;
+    onChangeFn: (value: any) => void;
+    onTouchFn: (value: any) => void;
+
+    searchCurrencyCodes = (term: string, item: CurrencyCode) => {
+        const currencyCodeName = new Intl.DisplayNames([this.locale], {
+            type: 'currency',
+        }).of(item);
+        return currencyCodeName?.toLowerCase().includes(term.toLowerCase());
+    };
+
+    constructor(dataService?: DataService, changeDetectorRef?: ChangeDetectorRef) {
+        if (dataService && changeDetectorRef) {
+            this.subscription = dataService.client
+                .uiState()
+                .mapStream(data => data.uiState)
+                .subscribe(({ language, locale }) => {
+                    this.locale = language.replace(/_/g, '-');
+                    if (locale) {
+                        this.locale += `-${locale}`;
+                    }
+                    changeDetectorRef.markForCheck();
+                });
+        }
+    }
+
+    writeValue(obj: any): void {
+        this.value = obj;
+    }
+    registerOnChange(fn: any): void {
+        this.onChangeFn = fn;
+    }
+    registerOnTouched(fn: any): void {
+        this.onTouchFn = fn;
+    }
+
+    ngOnDestroy(): void {
+        if (this.subscription) {
+            this.subscription.unsubscribe();
+        }
+    }
+}

+ 1 - 8
packages/admin-ui/src/lib/core/src/shared/components/form-field/form-field.component.scss

@@ -2,14 +2,6 @@
     display: block;
 }
 
-//::ng-deep vdr-form-field + vdr-form-field {
-//    margin-top: calc(var(--space-unit) * 2);
-//}
-//
-//::ng-deep vdr-form-field + vdr-form-item {
-//    margin-top: calc(var(--space-unit) * 2);
-//}
-
 .form-group {
     label {
         font-size: var(--font-size-sm);
@@ -21,6 +13,7 @@
 .tooltip-text {
     font-size: var(--font-size-xs);
     line-height: var(--font-size-sm);
+    margin-bottom: 4px;
 }
 .input-row {
     display: flex;

+ 0 - 0
packages/admin-ui/src/lib/core/src/shared/components/language-code-selector/language-code-selector.component.css


+ 17 - 0
packages/admin-ui/src/lib/core/src/shared/components/language-code-selector/language-code-selector.component.html

@@ -0,0 +1,17 @@
+<ng-select
+    [items]="languageCodes"
+    [addTag]="false"
+    [hideSelected]="true"
+    [searchFn]="searchLanguageCodes"
+    multiple="true"
+    appendTo="body"
+    [(ngModel)]="value"
+    (ngModelChange)="onChangeFn($event)"
+>
+    <ng-template ng-label-tmp let-item="item" let-clear="clear">
+        <span class="ng-value-icon left" (click)="clear.call(null, item)" aria-hidden="true"> × </span>
+        <span class="ng-value-label">{{ item | localeLanguageName }} ({{ item }})</span>
+    </ng-template>
+    <ng-template ng-option-tmp let-item="item">{{ item | localeLanguageName }} ({{ item }})</ng-template>
+</ng-select>
+

+ 80 - 0
packages/admin-ui/src/lib/core/src/shared/components/language-code-selector/language-code-selector.component.ts

@@ -0,0 +1,80 @@
+import {
+    ChangeDetectionStrategy,
+    ChangeDetectorRef,
+    Component,
+    forwardRef,
+    Input,
+    OnDestroy,
+} from '@angular/core';
+import { ControlValueAccessor, FormControl, NG_VALUE_ACCESSOR } from '@angular/forms';
+import { CurrencyCode, DataService } from '@vendure/admin-ui/core';
+import { Subscription } from 'rxjs';
+
+@Component({
+    selector: 'vdr-language-code-selector',
+    templateUrl: './language-code-selector.component.html',
+    styleUrls: ['./language-code-selector.component.css'],
+    changeDetection: ChangeDetectionStrategy.OnPush,
+    providers: [
+        {
+            provide: NG_VALUE_ACCESSOR,
+            useExisting: forwardRef(() => LanguageCodeSelectorComponent),
+            multi: true,
+        },
+    ],
+})
+export class LanguageCodeSelectorComponent implements ControlValueAccessor, OnDestroy {
+    @Input() languageCodes: string[];
+    private subscription: Subscription;
+    private locale: string;
+    protected value: string | undefined;
+    onChangeFn: (value: any) => void;
+    onTouchFn: (value: any) => void;
+
+    searchLanguageCodes = (term: string, item: string) => {
+        let languageCodeName = item;
+        const languagePart = item.split('_')[0];
+        try {
+            languageCodeName =
+                new Intl.DisplayNames([this.locale], {
+                    type: 'language',
+                }).of(languagePart) ?? item;
+        } catch (e) {
+            // ignore
+        }
+        return languageCodeName?.toLowerCase().includes(term.toLowerCase());
+    };
+
+    constructor(dataService?: DataService, changeDetectorRef?: ChangeDetectorRef) {
+        if (dataService && changeDetectorRef) {
+            this.subscription = dataService.client
+                .uiState()
+                .mapStream(data => data.uiState)
+                .subscribe(({ language, locale }) => {
+                    this.locale = language.replace(/_/g, '-');
+                    if (locale) {
+                        this.locale += `-${locale}`;
+                    }
+                    changeDetectorRef.markForCheck();
+                });
+        }
+    }
+
+    writeValue(obj: any): void {
+        this.value = obj;
+    }
+
+    registerOnChange(fn: any): void {
+        this.onChangeFn = fn;
+    }
+
+    registerOnTouched(fn: any): void {
+        this.onTouchFn = fn;
+    }
+
+    ngOnDestroy(): void {
+        if (this.subscription) {
+            this.subscription.unsubscribe();
+        }
+    }
+}

+ 1 - 1
packages/admin-ui/src/lib/core/src/shared/dynamic-form-inputs/currency-form-input/currency-form-input.component.ts

@@ -30,6 +30,6 @@ export class CurrencyFormInputComponent implements FormInputComponent {
     constructor(private dataService: DataService) {
         this.currencyCode$ = this.dataService.settings
             .getActiveChannel()
-            .mapStream(data => data.activeChannel.currencyCode);
+            .mapStream(data => data.activeChannel.defaultCurrencyCode);
     }
 }

+ 4 - 6
packages/admin-ui/src/lib/core/src/shared/pipes/locale-currency-name.pipe.ts

@@ -34,13 +34,11 @@ export class LocaleCurrencyNamePipe extends LocaleBasePipe implements PipeTransf
         let symbol = '';
         const activeLocale = this.getActiveLocale(locale);
 
-        // Awaiting TS types for this API: https://github.com/microsoft/TypeScript/pull/44022/files
-        const DisplayNames = (Intl as any).DisplayNames;
-
         if (display === 'full' || display === 'name') {
-            name = new DisplayNames([activeLocale], {
-                type: 'currency',
-            }).of(value);
+            name =
+                new Intl.DisplayNames([activeLocale], {
+                    type: 'currency',
+                }).of(value) ?? '';
         }
         if (display === 'full' || display === 'symbol') {
             const parts = (

+ 4 - 0
packages/admin-ui/src/lib/core/src/shared/shared.module.ts

@@ -168,6 +168,8 @@ import { CanDeactivateDetailGuard } from './providers/routing/can-deactivate-det
 import { CardComponent, CardControlsDirective } from './components/card/card.component';
 import { ZoneSelectorComponent } from './components/zone-selector/zone-selector.component';
 import { ChartComponent } from './components/chart/chart.component';
+import { CurrencyCodeSelectorComponent } from './components/currency-code-selector/currency-code-selector.component';
+import { LanguageCodeSelectorComponent } from './components/language-code-selector/language-code-selector.component';
 
 const IMPORTS = [
     ClarityModule,
@@ -308,6 +310,8 @@ const DECLARATIONS = [
     ZoneSelectorComponent,
     ChartComponent,
     AssignToChannelDialogComponent,
+    CurrencyCodeSelectorComponent,
+    LanguageCodeSelectorComponent,
 ];
 
 const DYNAMIC_FORM_INPUTS = [

+ 1 - 1
packages/admin-ui/src/lib/dashboard/src/widgets/order-chart-widget/order-chart-widget.component.ts

@@ -40,7 +40,7 @@ export class OrderChartWidgetComponent implements OnInit {
         const currencyCode$ = this.dataService.settings
             .getActiveChannel()
             .refetchOnChannelChange()
-            .mapStream(data => data.activeChannel.currencyCode || undefined);
+            .mapStream(data => data.activeChannel.defaultCurrencyCode || undefined);
         const uiState$ = this.dataService.client.uiState().mapStream(data => data.uiState);
 
         this.metrics$ = combineLatest(this.refresh$, this.metricType$, currencyCode$, uiState$).pipe(

+ 1 - 1
packages/admin-ui/src/lib/dashboard/src/widgets/order-summary-widget/order-summary-widget.component.ts

@@ -65,7 +65,7 @@ export class OrderSummaryWidgetComponent implements OnInit {
         this.currencyCode$ = this.dataService.settings
             .getActiveChannel()
             .refetchOnChannelChange()
-            .mapStream(data => data.activeChannel.currencyCode || undefined);
+            .mapStream(data => data.activeChannel.defaultCurrencyCode || undefined);
     }
 }
 

+ 68 - 32
packages/admin-ui/src/lib/settings/src/components/channel-detail/channel-detail.component.html

@@ -36,7 +36,12 @@
         <vdr-page-block>
             <vdr-card>
                 <div class="form-grid">
-                    <vdr-form-field [label]="'common.code' | translate" for="code">
+                    <vdr-form-field
+                        class="form-grid-span"
+                        *ngIf="entity?.code !== DEFAULT_CHANNEL_CODE"
+                        [label]="'common.code' | translate"
+                        for="code"
+                    >
                         <input
                             id="code"
                             type="text"
@@ -44,6 +49,13 @@
                             formControlName="code"
                         />
                     </vdr-form-field>
+                    <vdr-form-item
+                        class="form-grid-span"
+                        *ngIf="entity?.code === DEFAULT_CHANNEL_CODE"
+                        [label]="'common.code' | translate"
+                    >
+                        {{ entity?.code | channelCodeToLabel | translate }}
+                    </vdr-form-item>
                     <vdr-form-field [label]="'settings.channel-token' | translate" for="token">
                         <input
                             id="token"
@@ -52,13 +64,50 @@
                             formControlName="token"
                         />
                     </vdr-form-field>
-                    <vdr-form-field [label]="'settings.currency' | translate" for="defaultTaxZoneId">
+
+                    <vdr-form-field [label]="'common.seller' | translate" for="sellerId">
                         <select
-                            name="currencyCode"
-                            formControlName="currencyCode"
+                            name="sellerId"
+                            formControlName="sellerId"
                             [vdrDisabled]="!(updatePermission | hasPermission)"
                         >
-                            <option *ngFor="let code of currencyCodes" [value]="code">
+                            <option selected value style="display: none"></option>
+                            <option *ngFor="let seller of sellers$ | async" [value]="seller.id">
+                                {{ seller.name }}
+                            </option>
+                        </select>
+                    </vdr-form-field>
+                    <vdr-form-field
+                        [label]="'common.available-languages' | translate"
+                        for="availableLanguageCodes"
+                    >
+                        <vdr-language-code-selector
+                            formControlName="availableLanguageCodes"
+                            [languageCodes]="availableLanguageCodes$ | async"
+                        ></vdr-language-code-selector>
+                    </vdr-form-field>
+                    <vdr-form-field
+                        [label]="'common.available-currencies' | translate"
+                        for="availableCurrencyCodes"
+                    >
+                        <vdr-currency-code-selector
+                            formControlName="availableCurrencyCodes"
+                        ></vdr-currency-code-selector>
+                    </vdr-form-field>
+                </div>
+            </vdr-card>
+            <vdr-card [title]="'settings.defaults' | translate">
+                <div class="form-grid">
+                    <vdr-form-field [label]="'settings.default-currency' | translate" for="defaultTaxZoneId">
+                        <select
+                            name="defaultCurrencyCode"
+                            formControlName="defaultCurrencyCode"
+                            [vdrDisabled]="!(updatePermission | hasPermission)"
+                        >
+                            <option
+                                *ngFor="let code of detailForm.value.availableCurrencyCodes"
+                                [value]="code"
+                            >
                                 {{ code | localeCurrencyName }}
                             </option>
                         </select>
@@ -70,27 +119,13 @@
                             [vdrDisabled]="!(updatePermission | hasPermission)"
                         >
                             <option
-                                *ngFor="let languageCode of availableLanguageCodes$ | async"
+                                *ngFor="let languageCode of detailForm.value.availableLanguageCodes"
                                 [value]="languageCode"
                             >
                                 {{ languageCode | localeLanguageName }} ({{ languageCode | uppercase }})
                             </option>
                         </select>
                     </vdr-form-field>
-                    <vdr-form-field
-                        [label]="'settings.prices-include-tax' | translate"
-                        for="pricesIncludeTax"
-                    >
-                        <clr-toggle-wrapper>
-                            <input
-                                type="checkbox"
-                                clrToggle
-                                id="pricesIncludeTax"
-                                formControlName="pricesIncludeTax"
-                                [vdrDisabled]="!(updatePermission | hasPermission)"
-                            />
-                        </clr-toggle-wrapper>
-                    </vdr-form-field>
                     <div>
                         <vdr-form-field
                             [label]="'settings.default-tax-zone' | translate"
@@ -137,18 +172,19 @@
                             </clr-alert-item>
                         </clr-alert>
                     </div>
-
-                    <vdr-form-field [label]="'common.seller' | translate" for="sellerId">
-                        <select
-                            name="sellerId"
-                            formControlName="sellerId"
-                            [vdrDisabled]="!(updatePermission | hasPermission)"
-                        >
-                            <option selected value style="display: none"></option>
-                            <option *ngFor="let seller of sellers$ | async" [value]="seller.id">
-                                {{ seller.name }}
-                            </option>
-                        </select>
+                    <vdr-form-field
+                        [label]="'settings.prices-include-tax' | translate"
+                        for="pricesIncludeTax"
+                    >
+                        <clr-toggle-wrapper>
+                            <input
+                                type="checkbox"
+                                clrToggle
+                                id="pricesIncludeTax"
+                                formControlName="pricesIncludeTax"
+                                [vdrDisabled]="!(updatePermission | hasPermission)"
+                            />
+                        </clr-toggle-wrapper>
                     </vdr-form-field>
                 </div>
             </vdr-card>

+ 14 - 7
packages/admin-ui/src/lib/settings/src/components/channel-detail/channel-detail.component.ts

@@ -45,6 +45,7 @@ export class ChannelDetailComponent
     extends TypedBaseDetailComponent<typeof GetChannelDetailDocument, 'channel'>
     implements OnInit, OnDestroy
 {
+    DEFAULT_CHANNEL_CODE = DEFAULT_CHANNEL_CODE;
     customFields = this.getCustomFieldConfig('Channel');
     // zones$: Observable<Array<ItemOf<GetZoneListQuery, 'zones'>>>;
     sellers$: Observable<GetSellersQuery['sellers']['items']>;
@@ -52,7 +53,9 @@ export class ChannelDetailComponent
         code: ['', Validators.required],
         token: ['', Validators.required],
         pricesIncludeTax: [false],
-        currencyCode: ['' as CurrencyCode],
+        availableLanguageCodes: [[] as string[]],
+        availableCurrencyCodes: [[] as string[]],
+        defaultCurrencyCode: ['' as CurrencyCode],
         defaultShippingZoneId: ['', Validators.required],
         defaultLanguageCode: [undefined as LanguageCode | undefined],
         defaultTaxZoneId: ['', Validators.required],
@@ -61,7 +64,7 @@ export class ChannelDetailComponent
             this.customFields.reduce((hash, field) => ({ ...hash, [field.name]: '' }), {}),
         ),
     });
-    currencyCodes = Object.values(CurrencyCode);
+
     availableLanguageCodes$: Observable<LanguageCode[]>;
     readonly updatePermission = [Permission.SuperAdmin, Permission.UpdateChannel, Permission.CreateChannel];
 
@@ -100,7 +103,7 @@ export class ChannelDetailComponent
             token,
             defaultLanguageCode,
             pricesIncludeTax,
-            currencyCode,
+            defaultCurrencyCode,
             defaultShippingZoneId,
             defaultTaxZoneId,
             customFields,
@@ -111,7 +114,7 @@ export class ChannelDetailComponent
             !token ||
             !defaultLanguageCode ||
             !pricesIncludeTax ||
-            !currencyCode ||
+            !defaultCurrencyCode ||
             !defaultShippingZoneId ||
             !defaultTaxZoneId
         ) {
@@ -122,7 +125,7 @@ export class ChannelDetailComponent
             token,
             defaultLanguageCode,
             pricesIncludeTax,
-            currencyCode,
+            defaultCurrencyCode,
             defaultShippingZoneId,
             defaultTaxZoneId,
             customFields,
@@ -175,7 +178,9 @@ export class ChannelDetailComponent
                         code: formValue.code,
                         token: formValue.token,
                         pricesIncludeTax: formValue.pricesIncludeTax,
-                        currencyCode: formValue.currencyCode,
+                        availableLanguageCodes: formValue.availableLanguageCodes,
+                        availableCurrencyCodes: formValue.availableCurrencyCodes,
+                        defaultCurrencyCode: formValue.defaultCurrencyCode,
                         defaultShippingZoneId: formValue.defaultShippingZoneId,
                         defaultLanguageCode: formValue.defaultLanguageCode,
                         defaultTaxZoneId: formValue.defaultTaxZoneId,
@@ -208,7 +213,9 @@ export class ChannelDetailComponent
             code: entity.code,
             token: entity.token || this.generateToken(),
             pricesIncludeTax: entity.pricesIncludeTax,
-            currencyCode: entity.currencyCode,
+            availableLanguageCodes: entity.availableLanguageCodes,
+            availableCurrencyCodes: entity.availableCurrencyCodes,
+            defaultCurrencyCode: entity.defaultCurrencyCode,
             defaultShippingZoneId: entity.defaultShippingZone?.id ?? '',
             defaultLanguageCode: entity.defaultLanguageCode,
             defaultTaxZoneId: entity.defaultTaxZone?.id ?? '',

+ 8 - 22
packages/admin-ui/src/lib/settings/src/components/global-settings/global-settings.component.html

@@ -18,29 +18,15 @@
     <vdr-page-block>
         <vdr-card>
             <div class="form-grid">
-                <vdr-form-field [label]="'common.available-languages' | translate" for="availableLanguages">
-                    <ng-select
-                        [items]="languageCodes"
-                        [addTag]="false"
-                        [hideSelected]="true"
-                        multiple="true"
-                        appendTo="body"
+                <vdr-form-field
+                    [label]="'common.available-languages' | translate"
+                    for="availableLanguages"
+                    [tooltip]="'settings.global-available-languages-tooltip' | translate"
+                >
+                    <vdr-language-code-selector
                         formControlName="availableLanguages"
-                    >
-                        <ng-template ng-label-tmp let-item="item" let-clear="clear">
-                            <span
-                                class="ng-value-icon left"
-                                (click)="clear.call(null, item)"
-                                aria-hidden="true"
-                            >
-                                ×
-                            </span>
-                            <span class="ng-value-label">{{ item | localeLanguageName }} ({{ item }})</span>
-                        </ng-template>
-                        <ng-template ng-option-tmp let-item="item">
-                            {{ item | localeLanguageName }} ({{ item }})
-                        </ng-template>
-                    </ng-select>
+                        [languageCodes]="languageCodes"
+                    ></vdr-language-code-selector>
                 </vdr-form-field>
                 <vdr-form-field
                     [label]="'settings.global-out-of-stock-threshold' | translate"

+ 1 - 1
packages/admin-ui/src/lib/settings/src/components/test-order-builder/test-order-builder.component.ts

@@ -39,7 +39,7 @@ export class TestOrderBuilderComponent implements OnInit {
             this.orderLinesChange.emit(this.lines);
         }
         this.dataService.settings.getActiveChannel('cache-first').single$.subscribe(result => {
-            this.currencyCode = result.activeChannel.currencyCode;
+            this.currencyCode = result.activeChannel.defaultCurrencyCode;
         });
     }
 

+ 6 - 1
packages/admin-ui/src/lib/settings/src/settings.module.ts

@@ -18,6 +18,7 @@ import {
     PageService,
     SharedModule,
 } from '@vendure/admin-ui/core';
+import { DEFAULT_CHANNEL_CODE } from '@vendure/common/lib/shared-constants';
 
 import { AddCountryToZoneDialogComponent } from './components/add-country-to-zone-dialog/add-country-to-zone-dialog.component';
 import { AdminDetailComponent } from './components/admin-detail/admin-detail.component';
@@ -183,7 +184,11 @@ export class SettingsModule {
                 entityKey: 'channel',
                 getBreadcrumbs: entity => [
                     {
-                        label: entity ? entity.code : _('settings.create-new-channel'),
+                        label: entity
+                            ? entity.code === DEFAULT_CHANNEL_CODE
+                                ? 'common.default-channel'
+                                : entity.code
+                            : _('settings.create-new-channel'),
                         link: [entity?.id],
                     },
                 ],

+ 4 - 1
packages/admin-ui/src/lib/static/i18n-messages/cs.json

@@ -191,6 +191,7 @@
     "add-note": "Přidat poznámku",
     "apply": "",
     "assign-to-channel": "",
+    "available-currencies": "",
     "available-languages": "Dostupné jazyky",
     "boolean-and": "",
     "boolean-false": "",
@@ -677,15 +678,17 @@
     "create-new-tax-category": "Vytvořit daňovou kategorii",
     "create-new-tax-rate": "Vytvořit daňovou sazbu",
     "create-new-zone": "Vytvořit zónu",
-    "currency": "Měna",
+    "default-currency": "",
     "default-role-label": "Toto je výchozí role a nemůže být změněna.",
     "default-shipping-zone": "Výchozí dodací zóna",
     "default-tax-zone": "Výchozí daňová zóna",
+    "defaults": "",
     "eligible": "Způsobilé",
     "email-address": "E-mailová adresa",
     "email-address-or-identifier": "",
     "first-name": "Jméno",
     "fulfillment-handler": "Způsob zpracování",
+    "global-available-languages-tooltip": "",
     "global-out-of-stock-threshold": "Globální prahová hodnota pro vyprodání zásob",
     "global-out-of-stock-threshold-tooltip": "Nastaví hodnotu skladu, při které je tato varianta považována za vyprodanou. Použití záporné hodnoty umožňuje objednávat \"na objednávku\". Lze přepsat u jednotlivých variant produktu.",
     "last-name": "Příjmení",

+ 4 - 1
packages/admin-ui/src/lib/static/i18n-messages/de.json

@@ -191,6 +191,7 @@
     "add-note": "Notiz hinzufügen",
     "apply": "",
     "assign-to-channel": "",
+    "available-currencies": "",
     "available-languages": "Verfügbare Sprachen",
     "boolean-and": "",
     "boolean-false": "",
@@ -677,15 +678,17 @@
     "create-new-tax-category": "Neue Steuerkategorie erstellen",
     "create-new-tax-rate": "Neuen Steuersatz erstellen",
     "create-new-zone": "Neue Zone erstellen",
-    "currency": "Währung",
+    "default-currency": "",
     "default-role-label": "Dies ist eine Standardrolle und kann nicht geändert werden.",
     "default-shipping-zone": "Standard-Versandzone",
     "default-tax-zone": "Standard-Steuerzone",
+    "defaults": "",
     "eligible": "Verfügbar",
     "email-address": "E-Mail-Adresse",
     "email-address-or-identifier": "",
     "first-name": "Vorname",
     "fulfillment-handler": "Abwicklung über",
+    "global-available-languages-tooltip": "",
     "global-out-of-stock-threshold": "Globale ausverkauft-Grenze",
     "global-out-of-stock-threshold-tooltip": "Legt fest, ab welcher Untergrenze ein Produkt als ausverkauft angezeigt wird. Ein negativer Wert kann verwendet werden, um mit einer Fehlmenge zu arbeiten. Kann von den Produktvarianten überschrieben werden.",
     "last-name": "Nachname",

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

@@ -191,6 +191,7 @@
     "add-note": "Add note",
     "apply": "Apply",
     "assign-to-channel": "Assign to channel",
+    "available-currencies": "Available currencies",
     "available-languages": "Available languages",
     "boolean-and": "and",
     "boolean-false": "false",
@@ -677,15 +678,17 @@
     "create-new-tax-category": "Create tax category",
     "create-new-tax-rate": "Create new tax rate",
     "create-new-zone": "Create new zone",
-    "currency": "Currency",
+    "default-currency": "Default currency",
     "default-role-label": "This is a default Role and cannot be modified",
     "default-shipping-zone": "Default shipping zone",
     "default-tax-zone": "Default tax zone",
+    "defaults": "Defaults",
     "eligible": "Eligible",
     "email-address": "Email address",
     "email-address-or-identifier": "Email address or identifier",
     "first-name": "First name",
     "fulfillment-handler": "Fulfillment handler",
+    "global-available-languages-tooltip": "Sets the languages that are available for all channels. Individual channels can then support a subset of these languages.",
     "global-out-of-stock-threshold": "Global out-of-stock threshold",
     "global-out-of-stock-threshold-tooltip": "Sets the stock level at which this a variant is considered to be out of stock. Using a negative value enables backorder support. Can be overridden by product variants.",
     "last-name": "Last name",

+ 4 - 1
packages/admin-ui/src/lib/static/i18n-messages/es.json

@@ -191,6 +191,7 @@
     "add-note": "Añadir nota",
     "apply": "",
     "assign-to-channel": "",
+    "available-currencies": "",
     "available-languages": "Idiomas disponibles",
     "boolean-and": "",
     "boolean-false": "",
@@ -677,15 +678,17 @@
     "create-new-tax-category": "Crear categoría de impuestos",
     "create-new-tax-rate": "Crear nueva tasa de impuestos",
     "create-new-zone": "Crear nueva zona",
-    "currency": "Moneda",
+    "default-currency": "",
     "default-role-label": "Este es un Rol por defecto y no puede ser modificado",
     "default-shipping-zone": "Zona de envío por defecto",
     "default-tax-zone": "Zona de impuestos por defecto",
+    "defaults": "",
     "eligible": "Disponible",
     "email-address": "Dirección de email",
     "email-address-or-identifier": "",
     "first-name": "Nombre",
     "fulfillment-handler": "Gestor de ejecución de pedidos",
+    "global-available-languages-tooltip": "",
     "global-out-of-stock-threshold": "Límite agotamiento de existencias",
     "global-out-of-stock-threshold-tooltip": "Establece el límite de existencias a partir del cual se considera que esta variante está agotada. El uso de un valor negativo permite el soporte de pedidos pendientes. Puede ser anulado por las variantes del producto.",
     "last-name": "Apellidos",

+ 4 - 1
packages/admin-ui/src/lib/static/i18n-messages/fr.json

@@ -191,6 +191,7 @@
     "add-note": "Ajouter une note",
     "apply": "",
     "assign-to-channel": "",
+    "available-currencies": "",
     "available-languages": "Langues disponibles",
     "boolean-and": "",
     "boolean-false": "",
@@ -677,15 +678,17 @@
     "create-new-tax-category": "Créer catégorie de taxe",
     "create-new-tax-rate": "Créer nouveau taux de taxe",
     "create-new-zone": "Créer nouvelle zone",
-    "currency": "Devise",
+    "default-currency": "",
     "default-role-label": "Ceci est le role par défaut et ne peut pas être modifié",
     "default-shipping-zone": "Zone de livraison par défaut",
     "default-tax-zone": "Zone de taxe par défaut",
+    "defaults": "",
     "eligible": "Eligible",
     "email-address": "Adresse email",
     "email-address-or-identifier": "",
     "first-name": "Prénom",
     "fulfillment-handler": "Gestionnaire de remplissage",
+    "global-available-languages-tooltip": "",
     "global-out-of-stock-threshold": "Limite de rupture de stock globale",
     "global-out-of-stock-threshold-tooltip": "Régler le niveau de stock à partir duquel la variante est considéré en rupture de stock. Renseigner une valeur négative permet d'accepter des commandes en attente. La valeur peut être régler individuellement par variante de produit.",
     "last-name": "Nom",

+ 4 - 1
packages/admin-ui/src/lib/static/i18n-messages/it.json

@@ -191,6 +191,7 @@
     "add-note": "Aggiungi nota",
     "apply": "",
     "assign-to-channel": "",
+    "available-currencies": "",
     "available-languages": "Lingue disponibili",
     "boolean-and": "",
     "boolean-false": "",
@@ -677,15 +678,17 @@
     "create-new-tax-category": "Crea categoria tassa",
     "create-new-tax-rate": "Crea nuovo tasso fiscale",
     "create-new-zone": "Crea nuova zona",
-    "currency": "Valuta",
+    "default-currency": "",
     "default-role-label": "Questo è un ruolo predefinito e non può essere modificato",
     "default-shipping-zone": "Zona di spedizione predefinita",
     "default-tax-zone": "Zona di tassazione predefinita",
+    "defaults": "",
     "eligible": "Compatibile",
     "email-address": "Indirizzo email",
     "email-address-or-identifier": "",
     "first-name": "Nome",
     "fulfillment-handler": "Gestore spedizione",
+    "global-available-languages-tooltip": "",
     "global-out-of-stock-threshold": "Soglia globale di indisponibilità",
     "global-out-of-stock-threshold-tooltip": "Imposta il livello di scorte al quale questa variante viene considerata esaurita. Usando un valore negativo si abilitano gli ordini in riapprovvigionamento. Può essere modificato per le singole varianti.",
     "last-name": "Cognome",

+ 4 - 1
packages/admin-ui/src/lib/static/i18n-messages/pl.json

@@ -191,6 +191,7 @@
     "add-note": "",
     "apply": "",
     "assign-to-channel": "",
+    "available-currencies": "",
     "available-languages": "Dostępne języki",
     "boolean-and": "",
     "boolean-false": "",
@@ -677,15 +678,17 @@
     "create-new-tax-category": "Utwórz nową kategorię podatkową",
     "create-new-tax-rate": "Utwórz nową stawkę podatkową",
     "create-new-zone": "",
-    "currency": "Waluta",
+    "default-currency": "",
     "default-role-label": "To jest domyślna rola i nie może być zmieniana",
     "default-shipping-zone": "Domyślna strefa zakupowa",
     "default-tax-zone": "Domyślna strefa podatkowa",
+    "defaults": "",
     "eligible": "Wybieralny",
     "email-address": "Email",
     "email-address-or-identifier": "",
     "first-name": "Imię",
     "fulfillment-handler": "",
+    "global-available-languages-tooltip": "",
     "global-out-of-stock-threshold": "",
     "global-out-of-stock-threshold-tooltip": "",
     "last-name": "Nazwisko",

+ 4 - 1
packages/admin-ui/src/lib/static/i18n-messages/pt_BR.json

@@ -191,6 +191,7 @@
     "add-note": "Adicionar nota",
     "apply": "",
     "assign-to-channel": "",
+    "available-currencies": "",
     "available-languages": "Idiomas disponíveis",
     "boolean-and": "",
     "boolean-false": "",
@@ -677,15 +678,17 @@
     "create-new-tax-category": "Criar categoria de imposto",
     "create-new-tax-rate": "Criar nova taxa de imposto",
     "create-new-zone": "Criar nova zona",
-    "currency": "Moeda",
+    "default-currency": "",
     "default-role-label": "Esta é uma regra padrão e não pode ser modificada",
     "default-shipping-zone": "Zona de envio padrão",
     "default-tax-zone": "Zona de imposto padrão",
+    "defaults": "",
     "eligible": "Elegível",
     "email-address": "Email",
     "email-address-or-identifier": "",
     "first-name": "Nome",
     "fulfillment-handler": "Manipulador de preenchimento",
+    "global-available-languages-tooltip": "",
     "global-out-of-stock-threshold": "Limite global de falta de estoque",
     "global-out-of-stock-threshold-tooltip": "Define o nível de estoque no qual esta variação é considerada em falta. Usar um valor negativo ativa o suporte a pedidos em espera. Pode ser substituído por variações do produto.",
     "last-name": "Sobrenome",

+ 4 - 1
packages/admin-ui/src/lib/static/i18n-messages/pt_PT.json

@@ -191,6 +191,7 @@
     "add-note": "Adicionar nota",
     "apply": "",
     "assign-to-channel": "",
+    "available-currencies": "",
     "available-languages": "Idiomas disponíveis",
     "boolean-and": "",
     "boolean-false": "",
@@ -677,15 +678,17 @@
     "create-new-tax-category": "Criar categoria de imposto",
     "create-new-tax-rate": "Criar nova taxa de imposto",
     "create-new-zone": "Criar nova região",
-    "currency": "Moeda",
+    "default-currency": "",
     "default-role-label": "Esta é uma regra padrão e não pode ser modificada",
     "default-shipping-zone": "Região de envio padrão",
     "default-tax-zone": "Região de imposto padrão",
+    "defaults": "",
     "eligible": "Elegível",
     "email-address": "E-mail",
     "email-address-or-identifier": "",
     "first-name": "Nome",
     "fulfillment-handler": "Manipulador para a execução de envio",
+    "global-available-languages-tooltip": "",
     "global-out-of-stock-threshold": "Limite globalpara fora de estoque",
     "global-out-of-stock-threshold-tooltip": "Define o limite para a variante ser considerada sem estoque. Usar um valor negativo activa o suporte a pedidos pendentes. Pode ser substituído pela variante do produto.",
     "last-name": "Apelido",

+ 4 - 1
packages/admin-ui/src/lib/static/i18n-messages/ru.json

@@ -191,6 +191,7 @@
     "add-note": "Добавить заметку",
     "apply": "",
     "assign-to-channel": "",
+    "available-currencies": "",
     "available-languages": "Доступные языки",
     "boolean-and": "",
     "boolean-false": "",
@@ -677,15 +678,17 @@
     "create-new-tax-category": "Создать новую налоговую категорию",
     "create-new-tax-rate": "Создать новую налоговую ставку",
     "create-new-zone": "Создать новую зону",
-    "currency": "Валюта",
+    "default-currency": "",
     "default-role-label": "Это роль по умолчанию, которую невозможно изменить.",
     "default-shipping-zone": "Зона доставки по умолчанию",
     "default-tax-zone": "Налоговая зона по умолчанию",
+    "defaults": "",
     "eligible": "Имеющий право",
     "email-address": "Адрес электронной почты",
     "email-address-or-identifier": "",
     "first-name": "Имя",
     "fulfillment-handler": "Обработчик выполнения",
+    "global-available-languages-tooltip": "",
     "global-out-of-stock-threshold": "Глобальный порог отсутствия на складе",
     "global-out-of-stock-threshold-tooltip": "Устанавливает уровень запаса, при котором этот вариант считается отсутствующим. Использование отрицательного значения включает поддержку отложенного заказа. Может быть отменено вариантами товара.",
     "last-name": "Фамилия",

+ 4 - 1
packages/admin-ui/src/lib/static/i18n-messages/uk.json

@@ -191,6 +191,7 @@
     "add-note": "Додати замітку",
     "apply": "",
     "assign-to-channel": "",
+    "available-currencies": "",
     "available-languages": "Доступні мови",
     "boolean-and": "",
     "boolean-false": "",
@@ -677,15 +678,17 @@
     "create-new-tax-category": "Створити нову податкову категорію",
     "create-new-tax-rate": "Створити нову податкову ставку",
     "create-new-zone": "Створити нову зону",
-    "currency": "Валюта",
+    "default-currency": "",
     "default-role-label": "Це роль за замовчуванням, яку неможливо змінити.",
     "default-shipping-zone": "Зона доставки за замовчуванням",
     "default-tax-zone": "Податкова зона за замовчуванням",
+    "defaults": "",
     "eligible": "Який має право",
     "email-address": "Адреса електронної пошти",
     "email-address-or-identifier": "",
     "first-name": "Ім'я",
     "fulfillment-handler": "Обробник виконання",
+    "global-available-languages-tooltip": "",
     "global-out-of-stock-threshold": "Глобальний поріг відсутності на складі",
     "global-out-of-stock-threshold-tooltip": "Встановлює рівень запасу, при якому цей варіант вважається відсутнім. Використання від'ємного значення включає підтримку відкладеного замовлення. Може бути скасовано варіантами товару.",
     "last-name": "Прізвище",

+ 4 - 1
packages/admin-ui/src/lib/static/i18n-messages/zh_Hans.json

@@ -191,6 +191,7 @@
     "add-note": "添加注释",
     "apply": "",
     "assign-to-channel": "",
+    "available-currencies": "",
     "available-languages": "可用语言",
     "boolean-and": "",
     "boolean-false": "",
@@ -677,15 +678,17 @@
     "create-new-tax-category": "创建税表分类",
     "create-new-tax-rate": "添加税率",
     "create-new-zone": "",
-    "currency": "币种",
+    "default-currency": "",
     "default-role-label": "默认角色不可修改",
     "default-shipping-zone": "默认配送区域",
     "default-tax-zone": "默认销售区域",
+    "defaults": "",
     "eligible": "符合条件",
     "email-address": "电子邮件",
     "email-address-or-identifier": "",
     "first-name": "名",
     "fulfillment-handler": "",
+    "global-available-languages-tooltip": "",
     "global-out-of-stock-threshold": "默认售空限制",
     "global-out-of-stock-threshold-tooltip": "当此规格产品库存值低于此限制时,产品将为售空状态。设置为负数设置此规格产品为缺货状态。可以在产品页面更改默认限制",
     "last-name": "姓",

+ 4 - 1
packages/admin-ui/src/lib/static/i18n-messages/zh_Hant.json

@@ -191,6 +191,7 @@
     "add-note": "",
     "apply": "",
     "assign-to-channel": "",
+    "available-currencies": "",
     "available-languages": "可用語言",
     "boolean-and": "",
     "boolean-false": "",
@@ -677,15 +678,17 @@
     "create-new-tax-category": "建立税表分類",
     "create-new-tax-rate": "新增税率",
     "create-new-zone": "",
-    "currency": "幣種",
+    "default-currency": "",
     "default-role-label": "默認角色不可修改",
     "default-shipping-zone": "默認配送區域",
     "default-tax-zone": "默認銷售區域",
+    "defaults": "",
     "eligible": "符合條件",
     "email-address": "電子郵件",
     "email-address-or-identifier": "",
     "first-name": "名",
     "fulfillment-handler": "",
+    "global-available-languages-tooltip": "",
     "global-out-of-stock-threshold": "",
     "global-out-of-stock-threshold-tooltip": "",
     "last-name": "姓",

Some files were not shown because too many files changed in this diff