Merge pull request #251 from mempool/simon/i18n-everything

i18n all the remaining strings.
This commit is contained in:
wiz 2020-12-04 23:40:35 +09:00 committed by GitHub
commit 1e8167212f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
42 changed files with 749 additions and 359 deletions

View File

@ -43,11 +43,10 @@ import { NgbTypeaheadModule } from '@ng-bootstrap/ng-bootstrap';
import { FeesBoxComponent } from './components/fees-box/fees-box.component'; import { FeesBoxComponent } from './components/fees-box/fees-box.component';
import { DashboardComponent } from './dashboard/dashboard.component'; import { DashboardComponent } from './dashboard/dashboard.component';
import { FontAwesomeModule, FaIconLibrary } from '@fortawesome/angular-fontawesome'; import { FontAwesomeModule, FaIconLibrary } from '@fortawesome/angular-fontawesome';
import { faAngleDoubleDown, faAngleDoubleUp, faAngleDown, faAngleUp, faBolt, faChartArea, faCogs, faCubes, faDatabase, faExchangeAlt, faInfoCircle, import { faAngleDown, faAngleUp, faBolt, faChartArea, faCogs, faCubes, faDatabase, faExchangeAlt, faInfoCircle,
faLink, faList, faSearch, faTachometerAlt, faThList, faTint, faTv } from '@fortawesome/free-solid-svg-icons'; faLink, faList, faSearch, faTachometerAlt, faThList, faTint, faTv } from '@fortawesome/free-solid-svg-icons';
import { ApiDocsComponent } from './components/api-docs/api-docs.component'; import { ApiDocsComponent } from './components/api-docs/api-docs.component';
import { TermsOfServiceComponent } from './components/terms-of-service/terms-of-service.component'; import { TermsOfServiceComponent } from './components/terms-of-service/terms-of-service.component';
import { TranslationStringsComponent } from './components/translation-strings/translation-strings.component';
import { StorageService } from './services/storage.service'; import { StorageService } from './services/storage.service';
@NgModule({ @NgModule({
@ -83,7 +82,6 @@ import { StorageService } from './services/storage.service';
DashboardComponent, DashboardComponent,
ApiDocsComponent, ApiDocsComponent,
TermsOfServiceComponent, TermsOfServiceComponent,
TranslationStringsComponent,
], ],
imports: [ imports: [
BrowserModule, BrowserModule,

View File

@ -6,6 +6,7 @@ import { distinctUntilChanged, map, filter, mergeMap, tap, take } from 'rxjs/ope
import { ActivatedRoute, Router } from '@angular/router'; import { ActivatedRoute, Router } from '@angular/router';
import { merge, combineLatest, Observable } from 'rxjs'; import { merge, combineLatest, Observable } from 'rxjs';
import { AssetExtended } from '../interfaces/electrs.interface'; import { AssetExtended } from '../interfaces/electrs.interface';
import { SeoService } from '../services/seo.service';
@Component({ @Component({
selector: 'app-assets', selector: 'app-assets',
@ -32,9 +33,11 @@ export class AssetsComponent implements OnInit {
private formBuilder: FormBuilder, private formBuilder: FormBuilder,
private route: ActivatedRoute, private route: ActivatedRoute,
private router: Router, private router: Router,
private seoService: SeoService,
) { } ) { }
ngOnInit() { ngOnInit() {
this.seoService.setTitle($localize`:@@ee8f8008bae6ce3a49840c4e1d39b4af23d4c263:Assets`);
this.itemsPerPage = Math.max(Math.round(this.contentSpace / this.fiveItemsPxSize) * 5, 10); this.itemsPerPage = Math.max(Math.round(this.contentSpace / this.fiveItemsPxSize) * 5, 10);
this.searchForm = this.formBuilder.group({ this.searchForm = this.formBuilder.group({

View File

@ -36,7 +36,7 @@ export class BisqAddressComponent implements OnInit, OnDestroy {
this.transactions = null; this.transactions = null;
document.body.scrollTo(0, 0); document.body.scrollTo(0, 0);
this.addressString = params.get('id') || ''; this.addressString = params.get('id') || '';
this.seoService.setTitle('Address: ' + this.addressString); this.seoService.setTitle($localize`:@@bisq-address.component.browser-title:Address: ${this.addressString}:INTERPOLATION:`);
return this.bisqApiService.getAddress$(this.addressString) return this.bisqApiService.getAddress$(this.addressString)
.pipe( .pipe(

View File

@ -82,7 +82,7 @@ export class BisqBlockComponent implements OnInit, OnDestroy {
} }
this.isLoading = false; this.isLoading = false;
this.blockHeight = block.height; this.blockHeight = block.height;
this.seoService.setTitle('Block: #' + block.height + ': ' + block.hash); this.seoService.setTitle($localize`:@@bisq-block.component.browser-title:Block ${block.height}:INTERPOLATION:: ${block.hash}:INTERPOLATION:`);
this.block = block; this.block = block;
}); });
} }

View File

@ -1,5 +1,5 @@
<div class="container-xl"> <div class="container-xl">
<h1 style="float: left;">Blocks</h1> <h1 style="float: left;" i18n="Bisq blocks header">Blocks</h1>
<br> <br>
<div class="clearfix"></div> <div class="clearfix"></div>
@ -9,15 +9,15 @@
<div class="table-responsive-sm"> <div class="table-responsive-sm">
<table class="table table-borderless table-striped"> <table class="table table-borderless table-striped">
<thead> <thead>
<th style="width: 25%;">Height</th> <th style="width: 25%;" i18n="Bisq block height header">Height</th>
<th style="width: 25%;">Confirmed</th> <th style="width: 25%;" i18="Bisq block confirmed time header">Confirmed</th>
<th style="width: 25%;">Total Sent</th> <th style="width: 25%;" i18="Bisq block total BSQ tokens sent header">Total sent</th>
<th class="d-none d-md-block" style="width: 25%;">Transactions</th> <th class="d-none d-md-block" style="width: 25%;" i18n="Bisq block transactions title">Transactions</th>
</thead> </thead>
<tbody *ngIf="blocks.value; else loadingTmpl"> <tbody *ngIf="blocks.value; else loadingTmpl">
<tr *ngFor="let block of blocks.value[0]; trackBy: trackByFn"> <tr *ngFor="let block of blocks.value[0]; trackBy: trackByFn">
<td><a [routerLink]="['/block/' | relativeUrl, block.hash]" [state]="{ data: { block: block } }">{{ block.height }}</a></td> <td><a [routerLink]="['/block/' | relativeUrl, block.hash]" [state]="{ data: { block: block } }">{{ block.height }}</a></td>
<td><app-time-since [time]="block.time / 1000" [fastRender]="true"></app-time-since> ago</td> <td><app-time-since [time]="block.time / 1000" [fastRender]="true"></app-time-since></td>
<td>{{ calculateTotalOutput(block) / 100 | number: '1.2-2' }}<span class="d-none d-md-inline"> BSQ</span></td> <td>{{ calculateTotalOutput(block) / 100 | number: '1.2-2' }}<span class="d-none d-md-inline"> BSQ</span></td>
<td class="d-none d-md-block">{{ block.txs.length }}</td> <td class="d-none d-md-block">{{ block.txs.length }}</td>
</tr> </tr>

View File

@ -32,7 +32,7 @@ export class BisqBlocksComponent implements OnInit {
) { } ) { }
ngOnInit(): void { ngOnInit(): void {
this.seoService.setTitle('Blocks'); this.seoService.setTitle($localize`:@@8a7b4bd44c0ac71b2e72de0398b303257f7d2f54:Blocks`);
this.itemsPerPage = Math.max(Math.round(this.contentSpace / this.fiveItemsPxSize) * 5, 10); this.itemsPerPage = Math.max(Math.round(this.contentSpace / this.fiveItemsPxSize) * 5, 10);
this.loadingItems = Array(this.itemsPerPage); this.loadingItems = Array(this.itemsPerPage);
if (document.body.clientWidth < 768) { if (document.body.clientWidth < 768) {

View File

@ -1,5 +1,5 @@
<div class="container-xl"> <div class="container-xl">
<h1 style="float: left;">BSQ Statistics</h1> <h1 style="float: left;" i18n="BSQ statistics header">BSQ statistics</h1>
<br> <br>
<div class="clearfix"></div> <div class="clearfix"></div>
@ -7,41 +7,37 @@
<div class="row"> <div class="row">
<div class="col-sm"> <div class="col-sm">
<table class="table table-borderless table-striped"> <table class="table table-borderless table-striped">
<thead>
<th>Property</th>
<th>Value</th>
</thead>
<tbody *ngIf="!isLoading; else loadingTemplate"> <tbody *ngIf="!isLoading; else loadingTemplate">
<tr> <tr>
<td class="td-width">Existing amount</td> <td class="td-width" i18n="BSQ existing amount">Existing amount</td>
<td>{{ (stats.minted - stats.burnt) / 100 | number: '1.2-2' }} BSQ</td> <td>{{ (stats.minted - stats.burnt) / 100 | number: '1.2-2' }} BSQ</td>
</tr> </tr>
<tr> <tr>
<td>Minted amount</td> <td i18n="BSQ minted amount">Minted amount</td>
<td>{{ stats.minted | number: '1.2-2' }} BSQ</td> <td>{{ stats.minted | number: '1.2-2' }} BSQ</td>
</tr> </tr>
<tr> <tr>
<td>Burnt amount</td> <td i18n="BSQ burnt amount">Burnt amount</td>
<td>{{ stats.burnt | number: '1.2-2' }} BSQ</td> <td>{{ stats.burnt | number: '1.2-2' }} BSQ</td>
</tr> </tr>
<tr> <tr>
<td>Addresses</td> <td i18n="BSQ addresses">Addresses</td>
<td>{{ stats.addresses | number }}</td> <td>{{ stats.addresses | number }}</td>
</tr> </tr>
<tr> <tr>
<td>Unspent TXOs</td> <td i18n="BSQ unspent transaction outputs">Unspent TXOs</td>
<td>{{ stats.unspent_txos | number }}</td> <td>{{ stats.unspent_txos | number }}</td>
</tr> </tr>
<tr> <tr>
<td>Spent TXOs</td> <td i18n="BSQ spent transaction outputs">Spent TXOs</td>
<td>{{ stats.spent_txos | number }}</td> <td>{{ stats.spent_txos | number }}</td>
</tr> </tr>
<tr> <tr>
<td>Price</td> <td i18n="BSQ token price">Price</td>
<td><app-fiat [value]="price"></app-fiat></td> <td><app-fiat [value]="price"></app-fiat></td>
</tr> </tr>
<tr> <tr>
<td>Market cap</td> <td i18n="BSQ token market cap">Market cap</td>
<td><app-fiat [value]="price * (stats.minted - stats.burnt) / 100"></app-fiat></td> <td><app-fiat [value]="price * (stats.minted - stats.burnt) / 100"></app-fiat></td>
</tr> </tr>
</tbody> </tbody>
@ -55,23 +51,23 @@
<ng-template #loadingTemplate> <ng-template #loadingTemplate>
<tbody> <tbody>
<tr> <tr>
<td class="td-width">Existing amount</td> <td class="td-width" i18n>Existing amount</td>
<td><span class="skeleton-loader"></span></td> <td><span class="skeleton-loader"></span></td>
</tr> </tr>
<tr> <tr>
<td>Minted amount</td> <td i18n>Minted amount</td>
<td><span class="skeleton-loader"></span></td> <td><span class="skeleton-loader"></span></td>
</tr> </tr>
<tr> <tr>
<td>Burnt amount</td> <td i18n>Burnt amount</td>
<td><span class="skeleton-loader"></span></td> <td><span class="skeleton-loader"></span></td>
</tr> </tr>
<tr> <tr>
<td>Addresses</td> <td i18n>Addresses</td>
<td><span class="skeleton-loader"></span></td> <td><span class="skeleton-loader"></span></td>
</tr> </tr>
<tr> <tr>
<td>Unspent TXOs</td> <td i18n>Unspent TXOs</td>
<td><span class="skeleton-loader"></span></td> <td><span class="skeleton-loader"></span></td>
</tr> </tr>
<tr> <tr>
@ -79,11 +75,11 @@
<td><span class="skeleton-loader"></span></td> <td><span class="skeleton-loader"></span></td>
</tr> </tr>
<tr> <tr>
<td>Price</td> <td i18n>Price</td>
<td><span class="skeleton-loader"></span></td> <td><span class="skeleton-loader"></span></td>
</tr> </tr>
<tr> <tr>
<td>Market cap</td> <td i18n>Market cap</td>
<td><span class="skeleton-loader"></span></td> <td><span class="skeleton-loader"></span></td>
</tr> </tr>
</tbody> </tbody>

View File

@ -21,8 +21,7 @@ export class BisqStatsComponent implements OnInit {
) { } ) { }
ngOnInit() { ngOnInit() {
this.seoService.setTitle('BSQ Statistics'); this.seoService.setTitle($localize`:@@2a30a4cdb123a03facc5ab8c5b3e6d8b8dbbc3d4:BSQ statistics`);
this.stateService.bsqPrice$ this.stateService.bsqPrice$
.subscribe((bsqPrice) => { .subscribe((bsqPrice) => {
this.price = bsqPrice; this.price = bsqPrice;

View File

@ -4,7 +4,7 @@
<ng-template [ngIf]="!isLoading && !error"> <ng-template [ngIf]="!isLoading && !error">
<button *ngIf="(latestBlock$ | async) as latestBlock" type="button" class="btn btn-sm btn-success float-right mr-2 mt-1 mt-md-3">{{ latestBlock.height - bisqTx.blockHeight + 1 }} confirmation<ng-container *ngIf="latestBlock.height - bisqTx.blockHeight + 1 > 1">s</ng-container></button> <button *ngIf="(latestBlock$ | async) as latestBlock" type="button" class="btn btn-sm btn-success float-right mr-2 mt-1 mt-md-3">{{ latestBlock.height - bisqTx.blockHeight + 1 }} <ng-container *ngIf="latestBlock.height - bisqTx.blockHeight + 1 == 1; else confirmationPlural" i18n="shared.confirmation-count.singular|Transaction singular confirmation count">confirmation</ng-container><ng-template #confirmationPlural i18n="shared.confirmation-count.plural|Transaction plural confirmation count">confirmations</ng-template></button>
<div> <div>
<a [routerLink]="['/bisq-tx' | relativeUrl, bisqTx.id]" style="line-height: 56px;"> <a [routerLink]="['/bisq-tx' | relativeUrl, bisqTx.id]" style="line-height: 56px;">

View File

@ -43,7 +43,7 @@ export class BisqTransactionComponent implements OnInit, OnDestroy {
this.error = null; this.error = null;
document.body.scrollTo(0, 0); document.body.scrollTo(0, 0);
this.txId = params.get('id') || ''; this.txId = params.get('id') || '';
this.seoService.setTitle('Transaction: ' + this.txId); this.seoService.setTitle($localize`:@@bisq.transaction.browser-title:Transaction: ${this.txId}:INTERPOLATION:`);
if (history.state.data) { if (history.state.data) {
return of(history.state.data); return of(history.state.data);
} }

View File

@ -1,5 +1,5 @@
<div class="container-xl"> <div class="container-xl">
<h1 style="float: left;">Transactions</h1> <h1 style="float: left;" i18n>Transactions</h1>
<div class="d-block float-right"> <div class="d-block float-right">
<form [formGroup]="radioGroupForm"> <form [formGroup]="radioGroupForm">
@ -15,11 +15,11 @@
<table class="table table-borderless table-striped"> <table class="table table-borderless table-striped">
<thead> <thead>
<th style="width: 20%;">Transaction</th> <th style="width: 20%;" i18n>Transaction</th>
<th class="d-none d-md-block" style="width: 100%;">Type</th> <th class="d-none d-md-block" style="width: 100%;" i18n>Type</th>
<th style="width: 20%;">Amount</th> <th style="width: 20%;" i18n>Amount</th>
<th style="width: 20%;">Confirmed</th> <th style="width: 20%;" i18n>Confirmed</th>
<th class="d-none d-md-block">Height</th> <th class="d-none d-md-block" i18n>Height</th>
</thead> </thead>
<tbody *ngIf="transactions.value; else loadingTmpl"> <tbody *ngIf="transactions.value; else loadingTmpl">
<tr *ngFor="let tx of transactions.value[0]; trackBy: trackByFn"> <tr *ngFor="let tx of transactions.value[0]; trackBy: trackByFn">
@ -37,7 +37,7 @@
{{ calculateTotalOutput(tx.outputs) / 100 | number: '1.2-2' }}<span class="d-none d-md-inline"> BSQ</span> {{ calculateTotalOutput(tx.outputs) / 100 | number: '1.2-2' }}<span class="d-none d-md-inline"> BSQ</span>
</ng-template> </ng-template>
</td> </td>
<td><app-time-since [time]="tx.time / 1000" [fastRender]="true"></app-time-since> ago</td> <td><app-time-since [time]="tx.time / 1000" [fastRender]="true"></app-time-since></td>
<td class="d-none d-md-block"><a [routerLink]="['/block/' | relativeUrl, tx.blockHash]" [state]="{ data: { blockHeight: tx.blockHeight } }">{{ tx.blockHeight }}</a></td> <td class="d-none d-md-block"><a [routerLink]="['/block/' | relativeUrl, tx.blockHash]" [state]="{ data: { blockHeight: tx.blockHeight } }">{{ tx.blockHeight }}</a></td>
</tr> </tr>
</tbody> </tbody>

View File

@ -52,7 +52,9 @@ export class BisqTransactionsComponent implements OnInit {
}; };
txTypeDropdownTexts: IMultiSelectTexts = { txTypeDropdownTexts: IMultiSelectTexts = {
defaultTitle: 'Filter', defaultTitle: $localize`:@@bisq-transactions.filter:Filter`,
checkAll: $localize`:@@bisq-transactions.selectall:Select all`,
uncheckAll: $localize`:@@bisq-transactions.unselectall:Unselect all`,
}; };
// @ts-ignore // @ts-ignore
@ -72,7 +74,7 @@ export class BisqTransactionsComponent implements OnInit {
) { } ) { }
ngOnInit(): void { ngOnInit(): void {
this.seoService.setTitle('Transactions'); this.seoService.setTitle($localize`:@@add4cd82e3e38a3110fe67b3c7df56e9602644ee:Transactions`);
this.radioGroupForm = this.formBuilder.group({ this.radioGroupForm = this.formBuilder.group({
txTypes: [this.txTypesDefaultChecked], txTypes: [this.txTypesDefaultChecked],

View File

@ -64,7 +64,9 @@
<div class="float-right"> <div class="float-right">
<span *ngIf="showConfirmations && latestBlock$ | async as latestBlock"> <span *ngIf="showConfirmations && latestBlock$ | async as latestBlock">
<button type="button" class="btn btn-sm btn-success mt-2">{{ latestBlock.height - tx.blockHeight + 1 }} confirmation<ng-container *ngIf="latestBlock.height - tx.blockHeight + 1 > 1">s</ng-container></button> <button type="button" class="btn btn-sm btn-success mt-2">
<ng-container *ngIf="latestBlock.height - tx.blockHeight + 1 == 1; else confirmationPlural" i18n="shared.confirmation-count.singular|Transaction singular confirmation count">confirmation</ng-container><ng-template #confirmationPlural i18n="shared.confirmation-count.plural|Transaction plural confirmation count">confirmations</ng-template>
</button>
&nbsp; &nbsp;
</span> </span>
<button type="button" class="btn btn-sm btn-primary mt-2" (click)="switchCurrency()"> <button type="button" class="btn btn-sm btn-primary mt-2" (click)="switchCurrency()">

View File

@ -35,7 +35,7 @@ export class AboutComponent implements OnInit {
ngOnInit() { ngOnInit() {
this.gitCommit$ = this.stateService.gitCommit$.pipe(map((str) => str.substr(0, 8))); this.gitCommit$ = this.stateService.gitCommit$.pipe(map((str) => str.substr(0, 8)));
this.seoService.setTitle('About'); this.seoService.setTitle($localize`:@@004b222ff9ef9dd4771b777950ca1d0e4cd4348a:About`);
this.websocketService.want(['blocks']); this.websocketService.want(['blocks']);
this.donationForm = this.formBuilder.group({ this.donationForm = this.formBuilder.group({

View File

@ -61,7 +61,7 @@ export class AddressComponent implements OnInit, OnDestroy {
this.transactions = null; this.transactions = null;
document.body.scrollTo(0, 0); document.body.scrollTo(0, 0);
this.addressString = params.get('id') || ''; this.addressString = params.get('id') || '';
this.seoService.setTitle('Address: ' + this.addressString); this.seoService.setTitle($localize`:@@address.component.browser-title:Address: ${this.addressString}:INTERPOLATION:`);
return merge( return merge(
of(true), of(true),

View File

@ -1,7 +1,7 @@
<ng-container *ngIf="{ val: network$ | async } as network"> <ng-container *ngIf="{ val: network$ | async } as network">
<div class="container-xl"> <div class="container-xl">
<div class="text-center"> <div class="text-center">
<h2>{{ network.val === '' ? 'Bitcoin' : network.val.charAt(0).toUpperCase() + network.val.slice(1) }} API Service</h2> <h2>{{ network.val === '' ? 'Bitcoin' : network.val.charAt(0).toUpperCase() + network.val.slice(1) }} <ng-container i18n="api-docs.title">API Service</ng-container></h2>
</div> </div>
<ul ngbNav #nav="ngbNav" [(activeId)]="active" class="nav-tabs"> <ul ngbNav #nav="ngbNav" [(activeId)]="active" class="nav-tabs">

View File

@ -2,6 +2,7 @@ import { Component, OnInit } from '@angular/core';
import { StateService } from 'src/app/services/state.service'; import { StateService } from 'src/app/services/state.service';
import { WebsocketService } from 'src/app/services/websocket.service'; import { WebsocketService } from 'src/app/services/websocket.service';
import { Observable, merge, of } from 'rxjs'; import { Observable, merge, of } from 'rxjs';
import { SeoService } from 'src/app/services/seo.service';
@Component({ @Component({
selector: 'app-api-docs', selector: 'app-api-docs',
@ -16,9 +17,11 @@ export class ApiDocsComponent implements OnInit {
constructor( constructor(
private stateService: StateService, private stateService: StateService,
private websocketService: WebsocketService, private websocketService: WebsocketService,
private seoService: SeoService,
) { } ) { }
ngOnInit(): void { ngOnInit(): void {
this.seoService.setTitle($localize`:@@e351b40b3869a5c7d19c3d4918cb1ac7aaab95c4:API`);
this.network$ = merge(of(''), this.stateService.networkChanged$); this.network$ = merge(of(''), this.stateService.networkChanged$);
this.websocketService.want(['blocks']); this.websocketService.want(['blocks']);

View File

@ -72,7 +72,7 @@
<br> <br>
<h2><ng-template [ngIf]="transactions?.length">{{ (transactions?.length | number) || '?' }} of </ng-template>{{ txCount | number }} <ng-template [ngIf]="isNativeAsset" [ngIfElse]="defaultAsset">Peg In/Out and Burn Transactions</ng-template><ng-template #defaultAsset>In/Out and Burn Transactions</ng-template></h2> <h2><ng-template [ngIf]="transactions?.length">{{ (transactions?.length | number) || '?' }} of </ng-template>{{ txCount | number }} <ng-template [ngIf]="isNativeAsset" [ngIfElse]="defaultAsset" i18n="Liquid native asset transactions title">Peg In/Out and Burn Transactions</ng-template><ng-template #defaultAsset i18n="Default asset transactions title">Issuance and Burn Transactions</ng-template></h2>
<app-transactions-list [transactions]="transactions" [showConfirmations]="true" (loadMore)="loadMore()"></app-transactions-list> <app-transactions-list [transactions]="transactions" [showConfirmations]="true" (loadMore)="loadMore()"></app-transactions-list>

View File

@ -70,7 +70,7 @@ export class AssetComponent implements OnInit, OnDestroy {
this.transactions = null; this.transactions = null;
document.body.scrollTo(0, 0); document.body.scrollTo(0, 0);
this.assetString = params.get('id') || ''; this.assetString = params.get('id') || '';
this.seoService.setTitle('Asset: ' + this.assetString); this.seoService.setTitle($localize`:@@asset.component.asset-browser-title:Asset: ${this.assetString}:INTERPOLATION:`);
return merge( return merge(
of(true), of(true),

View File

@ -43,7 +43,7 @@
<tbody> <tbody>
<tr *ngIf="block.medianFee !== undefined"> <tr *ngIf="block.medianFee !== undefined">
<td class="td-width" i18n="block.median-fee">Median fee</td> <td class="td-width" i18n="block.median-fee">Median fee</td>
<td>~{{ block.medianFee | number:'1.0-0' }} <span i18n="shared.sat-vbyte|sat/vB">sat/vB</span> (<app-fiat [value]="block.medianFee * 140" digitsInfo="1.2-2" ngbTooltip="Based on average native segwit transaction of 140 vBytes" placement="bottom"></app-fiat>)</td> <td>~{{ block.medianFee | number:'1.0-0' }} <span i18n="shared.sat-vbyte|sat/vB">sat/vB</span> (<app-fiat [value]="block.medianFee * 140" digitsInfo="1.2-2" i18n-ngbTooltip="Transaction fee tooltip" ngbTooltip="Based on average native segwit transaction of 140 vBytes" placement="bottom"></app-fiat>)</td>
</tr> </tr>
<ng-template [ngIf]="fees !== undefined" [ngIfElse]="loadingFees"> <ng-template [ngIf]="fees !== undefined" [ngIfElse]="loadingFees">
<tr> <tr>

View File

@ -95,7 +95,7 @@ export class BlockComponent implements OnInit, OnDestroy {
tap((block: Block) => { tap((block: Block) => {
this.block = block; this.block = block;
this.blockHeight = block.height; this.blockHeight = block.height;
this.seoService.setTitle('Block: #' + block.height + ': ' + block.id); this.seoService.setTitle($localize`:@@block.component.browser-title:Block ${block.height}:INTERPOLATION:: ${block.id}:INTERPOLATION:`);
this.isLoadingBlock = false; this.isLoadingBlock = false;
if (block.coinbaseTx) { if (block.coinbaseTx) {
this.coinbaseTx = block.coinbaseTx; this.coinbaseTx = block.coinbaseTx;

View File

@ -1,4 +1,4 @@
<span #buttonWrapper [attr.data-tlite]="'Copied!'" style="position: relative;"> <span #buttonWrapper [attr.data-tlite]="copiedMessage" style="position: relative;">
<button #btn class="btn btn-sm btn-link pt-0" style="line-height: 0.9;" [attr.data-clipboard-text]="text"> <button #btn class="btn btn-sm btn-link pt-0" style="line-height: 0.9;" [attr.data-clipboard-text]="text">
<img src="./resources/clippy.svg" width="13"> <img src="./resources/clippy.svg" width="13">
</button> </button>

View File

@ -1,4 +1,4 @@
import { Component, OnInit, ViewChild, ElementRef, AfterViewInit, Input, ChangeDetectionStrategy } from '@angular/core'; import { Component, ViewChild, ElementRef, AfterViewInit, Input, ChangeDetectionStrategy } from '@angular/core';
import * as ClipboardJS from 'clipboard'; import * as ClipboardJS from 'clipboard';
import * as tlite from 'tlite'; import * as tlite from 'tlite';
@ -12,6 +12,7 @@ export class ClipboardComponent implements AfterViewInit {
@ViewChild('btn') btn: ElementRef; @ViewChild('btn') btn: ElementRef;
@ViewChild('buttonWrapper') buttonWrapper: ElementRef; @ViewChild('buttonWrapper') buttonWrapper: ElementRef;
@Input() text: string; @Input() text: string;
copiedMessage: string = $localize`:@@clipboard.copied-message:Copied!`;
clipboard: any; clipboard: any;
@ -19,7 +20,7 @@ export class ClipboardComponent implements AfterViewInit {
ngAfterViewInit() { ngAfterViewInit() {
this.clipboard = new ClipboardJS(this.btn.nativeElement); this.clipboard = new ClipboardJS(this.btn.nativeElement);
this.clipboard.on('success', (e) => { this.clipboard.on('success', () => {
tlite.show(this.buttonWrapper.nativeElement); tlite.show(this.buttonWrapper.nativeElement);
setTimeout(() => { setTimeout(() => {
tlite.hide(this.buttonWrapper.nativeElement); tlite.hide(this.buttonWrapper.nativeElement);

View File

@ -3,19 +3,19 @@
<td class="d-none d-md-block"> <td class="d-none d-md-block">
<h5 class="card-title" i18n="fees-box.low-priority">Low priority</h5> <h5 class="card-title" i18n="fees-box.low-priority">Low priority</h5>
<p class="card-text"> <p class="card-text">
{{ feeEstimations.hourFee }} <span i18n="shared.sat-vbyte|sat/vB">sat/vB</span> (<app-fiat [value]="feeEstimations.hourFee * 140" ngbTooltip="Based on average native segwit transaction of 140 vBytes" placement="bottom"></app-fiat>) {{ feeEstimations.hourFee }} <span i18n="shared.sat-vbyte|sat/vB">sat/vB</span> (<app-fiat [value]="feeEstimations.hourFee * 140" i18n-ngbTooltip="Transaction fee tooltip" ngbTooltip="Based on average native segwit transaction of 140 vBytes" placement="bottom"></app-fiat>)
</p> </p>
</td> </td>
<td> <td>
<h5 class="card-title" i18n="fees-box.medium-priority">Medium priority</h5> <h5 class="card-title" i18n="fees-box.medium-priority">Medium priority</h5>
<p class="card-text"> <p class="card-text">
{{ feeEstimations.halfHourFee }} <span i18n="shared.sat-vbyte|sat/vB">sat/vB</span> (<app-fiat [value]="feeEstimations.halfHourFee * 140" ngbTooltip="Based on average native segwit transaction of 140 vBytes" placement="bottom"></app-fiat>) {{ feeEstimations.halfHourFee }} <span i18n="shared.sat-vbyte|sat/vB">sat/vB</span> (<app-fiat [value]="feeEstimations.halfHourFee * 140" i18n-ngbTooltip="Transaction fee tooltip" ngbTooltip="Based on average native segwit transaction of 140 vBytes" placement="bottom"></app-fiat>)
</p> </p>
</td> </td>
<td> <td>
<h5 class="card-title" i18n="fees-box.high-priority">High priority</h5> <h5 class="card-title" i18n="fees-box.high-priority">High priority</h5>
<p class="card-text"> <p class="card-text">
{{ feeEstimations.fastestFee }} <span i18n="shared.sat-vbyte|sat/vB">sat/vB</span> (<app-fiat [value]="feeEstimations.fastestFee * 140" ngbTooltip="Based on average native segwit transaction of 140 vBytes" placement="bottom"></app-fiat>) {{ feeEstimations.fastestFee }} <span i18n="shared.sat-vbyte|sat/vB">sat/vB</span> (<app-fiat [value]="feeEstimations.fastestFee * 140" i18n-ngbTooltip="Transaction fee tooltip" ngbTooltip="Based on average native segwit transaction of 140 vBytes" placement="bottom"></app-fiat>)
</p> </p>
</td> </td>
</tr> </tr>

View File

@ -1,5 +1,5 @@
<div class="container-xl"> <div class="container-xl">
<h1 style="float: left;">Blocks</h1> <h1 style="float: left;" i18n="latest-blocks.blocks">Blocks</h1>
<br> <br>
<div class="clearfix"></div> <div class="clearfix"></div>
@ -10,7 +10,7 @@
<th class="d-none d-md-block" style="width: 20%;" i18n="latest-blocks.timestamp">Timestamp</th> <th class="d-none d-md-block" style="width: 20%;" i18n="latest-blocks.timestamp">Timestamp</th>
<th style="width: 20%;" i18n="latest-blocks.mined">Mined</th> <th style="width: 20%;" i18n="latest-blocks.mined">Mined</th>
<th class="d-none d-lg-block" style="width: 15%;" i18n="latest-blocks.transactions">Transactions</th> <th class="d-none d-lg-block" style="width: 15%;" i18n="latest-blocks.transactions">Transactions</th>
<th style="width: 20%;" i18n="latest-blocks.filled">Filled</th> <th style="width: 20%;" i18n="latest-blocks.size">Size</th>
</thead> </thead>
<tbody> <tbody>
<tr *ngFor="let block of blocks; let i= index; trackBy: trackByBlock"> <tr *ngFor="let block of blocks; let i= index; trackBy: trackByBlock">

View File

@ -34,7 +34,7 @@ export class LatestBlocksComponent implements OnInit, OnDestroy {
) { } ) { }
ngOnInit() { ngOnInit() {
this.seoService.setTitle('Blocks'); this.seoService.setTitle($localize`:@@f4cba7faeb126346f09cc6af30124f9a343f7a28:Blocks`);
this.websocketService.want(['blocks']); this.websocketService.want(['blocks']);
this.network$ = merge(of(''), this.stateService.networkChanged$); this.network$ = merge(of(''), this.stateService.networkChanged$);

View File

@ -26,37 +26,37 @@
<ul class="navbar-nav mr-auto pt-2 pb-2 pb-md-0 pt-md-0 {{ network.val }}"> <ul class="navbar-nav mr-auto pt-2 pb-2 pb-md-0 pt-md-0 {{ network.val }}">
<ng-template [ngIf]="network.val === 'bisq'" [ngIfElse]="notBisq"> <ng-template [ngIf]="network.val === 'bisq'" [ngIfElse]="notBisq">
<li class="nav-item" routerLinkActive="active" [routerLinkActiveOptions]="{exact: true}"> <li class="nav-item" routerLinkActive="active" [routerLinkActiveOptions]="{exact: true}">
<a class="nav-link" [routerLink]="['/bisq']" (click)="collapse()"><fa-icon [icon]="['fas', 'list']" [fixedWidth]="true" title="Transactions"></fa-icon></a> <a class="nav-link" [routerLink]="['/bisq']" (click)="collapse()"><fa-icon [icon]="['fas', 'list']" [fixedWidth]="true" i18n-title="master-page.transactions" title="Transactions"></fa-icon></a>
</li> </li>
<li class="nav-item" routerLinkActive="active"> <li class="nav-item" routerLinkActive="active">
<a class="nav-link" [routerLink]="['/bisq/blocks']" (click)="collapse()"><fa-icon [icon]="['fas', 'cubes']" [fixedWidth]="true" title="Blocks"></fa-icon></a> <a class="nav-link" [routerLink]="['/bisq/blocks']" (click)="collapse()"><fa-icon [icon]="['fas', 'cubes']" [fixedWidth]="true" i18n-title="master-page.blocks" title="Blocks"></fa-icon></a>
</li> </li>
<li class="nav-item" routerLinkActive="active"> <li class="nav-item" routerLinkActive="active">
<a class="nav-link" [routerLink]="['/bisq/stats']" (click)="collapse()"><fa-icon [icon]="['fas', 'tachometer-alt']" [fixedWidth]="true" title="Stats"></fa-icon></a> <a class="nav-link" [routerLink]="['/bisq/stats']" (click)="collapse()"><fa-icon [icon]="['fas', 'tachometer-alt']" [fixedWidth]="true" i18n-title="master-page.stats" title="Stats"></fa-icon></a>
</li> </li>
</ng-template> </ng-template>
<ng-template #notBisq> <ng-template #notBisq>
<li class="nav-item" routerLinkActive="active" [routerLinkActiveOptions]="{exact: true}"> <li class="nav-item" routerLinkActive="active" [routerLinkActiveOptions]="{exact: true}">
<a class="nav-link" [routerLink]="['/' | relativeUrl]" (click)="collapse()"><fa-icon [icon]="['fas', 'tachometer-alt']" [fixedWidth]="true" title="Dashboard"></fa-icon></a> <a class="nav-link" [routerLink]="['/' | relativeUrl]" (click)="collapse()"><fa-icon [icon]="['fas', 'tachometer-alt']" [fixedWidth]="true" i18n-title="master-page.dashboard" title="Dashboard"></fa-icon></a>
</li> </li>
<li class="nav-item" routerLinkActive="active"> <li class="nav-item" routerLinkActive="active">
<a class="nav-link" [routerLink]="['/blocks' | relativeUrl]" (click)="collapse()"><fa-icon [icon]="['fas', 'cubes']" [fixedWidth]="true" title="Blocks"></fa-icon></a> <a class="nav-link" [routerLink]="['/blocks' | relativeUrl]" (click)="collapse()"><fa-icon [icon]="['fas', 'cubes']" [fixedWidth]="true" i18n-title="master-page.blocks" title="Blocks"></fa-icon></a>
</li> </li>
<li class="nav-item" routerLinkActive="active"> <li class="nav-item" routerLinkActive="active">
<a class="nav-link" [routerLink]="['/graphs' | relativeUrl]" (click)="collapse()"><fa-icon [icon]="['fas', 'chart-area']" [fixedWidth]="true" title="Graphs"></fa-icon></a> <a class="nav-link" [routerLink]="['/graphs' | relativeUrl]" (click)="collapse()"><fa-icon [icon]="['fas', 'chart-area']" [fixedWidth]="true" i18n-title="master-page.graphs" title="Graphs"></fa-icon></a>
</li> </li>
<li class="nav-item d-none d-sm-block" routerLinkActive="active"> <li class="nav-item d-none d-sm-block" routerLinkActive="active">
<a class="nav-link" [routerLink]="['/tv' | relativeUrl]" (click)="collapse()"><fa-icon [icon]="['fas', 'tv']" [fixedWidth]="true" title="Full screen TV view"></fa-icon></a> <a class="nav-link" [routerLink]="['/tv' | relativeUrl]" (click)="collapse()"><fa-icon [icon]="['fas', 'tv']" [fixedWidth]="true" i18n-title="master-page.tvview" title="TV view"></fa-icon></a>
</li> </li>
</ng-template> </ng-template>
<li *ngIf="network.val === 'liquid'" class="nav-item" routerLinkActive="active"> <li *ngIf="network.val === 'liquid'" class="nav-item" routerLinkActive="active">
<a class="nav-link" [routerLink]="['/liquid/assets']" (click)="collapse()"><fa-icon [icon]="['fas', 'database']" [fixedWidth]="true" title="Assets"></fa-icon></a> <a class="nav-link" [routerLink]="['/liquid/assets']" (click)="collapse()"><fa-icon [icon]="['fas', 'database']" [fixedWidth]="true" i18n-title="master-page.assets" title="Assets"></fa-icon></a>
</li> </li>
<li [hidden]="isMobile" class="nav-item mr-2" routerLinkActive="active"> <li [hidden]="isMobile" class="nav-item mr-2" routerLinkActive="active">
<a class="nav-link" [routerLink]="['/api' | relativeUrl]" (click)="collapse()"><fa-icon [icon]="['fas', 'cogs']" [fixedWidth]="true" title="API"></fa-icon></a> <a class="nav-link" [routerLink]="['/api' | relativeUrl]" (click)="collapse()"><fa-icon [icon]="['fas', 'cogs']" [fixedWidth]="true" i18n-title="master-page.api" title="API"></fa-icon></a>
</li> </li>
<li class="nav-item" routerLinkActive="active"> <li class="nav-item" routerLinkActive="active">
<a class="nav-link" [routerLink]="['/about']" (click)="collapse()"><fa-icon [icon]="['fas', 'info-circle']" [fixedWidth]="true" title="About"></fa-icon></a> <a class="nav-link" [routerLink]="['/about']" (click)="collapse()"><fa-icon [icon]="['fas', 'info-circle']" [fixedWidth]="true" i18n-title="master-page.api" title="About"></fa-icon></a>
</li> </li>
</ul> </ul>
<app-search-form location="top" (searchTriggered)="collapse()"></app-search-form> <app-search-form location="top" (searchTriggered)="collapse()"></app-search-form>

View File

@ -14,7 +14,7 @@
<tbody> <tbody>
<tr> <tr>
<td i18n="mempool-block.median-fee">Median fee</td> <td i18n="mempool-block.median-fee">Median fee</td>
<td>~{{ mempoolBlock.medianFee | number:'1.0-0' }} sat/vB (<app-fiat [value]="mempoolBlock.medianFee * 140" digitsInfo="1.2-2" ngbTooltip="Based on average native segwit transaction of 140 vBytes" placement="bottom"></app-fiat>)</td> <td>~{{ mempoolBlock.medianFee | number:'1.0-0' }} sat/vB (<app-fiat [value]="mempoolBlock.medianFee * 140" digitsInfo="1.2-2" i18n-ngbTooltip="Transaction fee tooltip" ngbTooltip="Based on average native segwit transaction of 140 vBytes" placement="bottom"></app-fiat>)</td>
</tr> </tr>
<tr> <tr>
<td i18n="mempool-block.fee-span">Fee span</td> <td i18n="mempool-block.fee-span">Fee span</td>
@ -29,7 +29,7 @@
<td>{{ mempoolBlock.nTx }}</td> <td>{{ mempoolBlock.nTx }}</td>
</tr> </tr>
<tr> <tr>
<td i18n="mempool-block.filled">Filled</td> <td i18n="mempool-block.size">Size</td>
<td> <td>
<div class="progress position-relative"> <div class="progress position-relative">
<div class="progress-bar progress-mempool {{ (network$ | async) }}" role="progressbar" [ngStyle]="{'width': (mempoolBlock.blockVSize / 1000000) * 100 + '%' }"></div> <div class="progress-bar progress-mempool {{ (network$ | async) }}" role="progressbar" [ngStyle]="{'width': (mempoolBlock.blockVSize / 1000000) * 100 + '%' }"></div>

View File

@ -69,13 +69,11 @@ export class MempoolBlockComponent implements OnInit, OnDestroy {
getOrdinal(mempoolBlock: MempoolBlock): string { getOrdinal(mempoolBlock: MempoolBlock): string {
const blocksInBlock = Math.ceil(mempoolBlock.blockVSize / 1000000); const blocksInBlock = Math.ceil(mempoolBlock.blockVSize / 1000000);
if (this.mempoolBlockIndex === 0) { if (this.mempoolBlockIndex === 0) {
return 'Next block'; return $localize`:@@mempool-block.next.block:Next block`;
} else if (this.mempoolBlockIndex === env.KEEP_BLOCKS_AMOUNT - 1 && blocksInBlock > 1 ) { } else if (this.mempoolBlockIndex === env.KEEP_BLOCKS_AMOUNT - 1 && blocksInBlock > 1 ) {
return `Stack of ${blocksInBlock} blocks`; return $localize`:@@mempool-block.stack.of.blocks:Stack of ${blocksInBlock}:INTERPOLATION: mempool blocks`;
} else { } else {
const s = ['th', 'st', 'nd', 'rd']; return $localize`:@@mempool-block.block.no:Mempool block ${this.mempoolBlockIndex + 1}:INTERPOLATION:`;
const v = this.mempoolBlockIndex + 1 % 100;
return this.mempoolBlockIndex + 1 + (s[(v - 20) % 10] || s[v] || s[0]) + ' next block';
} }
} }
} }

View File

@ -4,7 +4,7 @@
<input #instance="ngbTypeahead" [ngbTypeahead]="typeaheadSearch" (selectItem)="itemSelected()" (focus)="focus$.next($any($event).target.value)" (click)="click$.next($any($event).target.value)" formControlName="searchText" type="text" class="form-control" i18n-placeholder="search-form.searchbar-placeholder" placeholder="TXID, block height, hash or address"> <input #instance="ngbTypeahead" [ngbTypeahead]="typeaheadSearch" (selectItem)="itemSelected()" (focus)="focus$.next($any($event).target.value)" (click)="click$.next($any($event).target.value)" formControlName="searchText" type="text" class="form-control" i18n-placeholder="search-form.searchbar-placeholder" placeholder="TXID, block height, hash or address">
</div> </div>
<div> <div>
<button [disabled]="isSearching" type="submit" class="btn btn-block btn-primary"><fa-icon [icon]="['fas', 'search']" [fixedWidth]="true" title="Search"></fa-icon></button> <button [disabled]="isSearching" type="submit" class="btn btn-block btn-primary"><fa-icon [icon]="['fas', 'search']" [fixedWidth]="true" i18n-title="search-form.search-title" title="Search"></fa-icon></button>
</div> </div>
</div> </div>
</form> </form>

View File

@ -40,7 +40,7 @@
<input ngbButton type="radio" [value]="'1y'" [routerLink]="['/graphs' | relativeUrl]" fragment="1y"> 1Y <input ngbButton type="radio" [value]="'1y'" [routerLink]="['/graphs' | relativeUrl]" fragment="1y"> 1Y
</label> </label>
</div> </div>
<button (click)="invertGraph()" class="btn btn-primary btn-sm ml-2 d-none d-md-inline"><fa-icon [icon]="['fas', 'exchange-alt']" [rotate]="90" [fixedWidth]="true" title="Invert"></fa-icon></button> <button (click)="invertGraph()" class="btn btn-primary btn-sm ml-2 d-none d-md-inline"><fa-icon [icon]="['fas', 'exchange-alt']" [rotate]="90" [fixedWidth]="true" i18n-title="statistics.component-invert.title" title="Invert"></fa-icon></button>
</form> </form>
</div> </div>
<div class="card-body"> <div class="card-body">

View File

@ -52,7 +52,7 @@ export class StatisticsComponent implements OnInit {
} }
ngOnInit() { ngOnInit() {
this.seoService.setTitle('Graphs'); this.seoService.setTitle($localize`:@@5d4f792f048fcaa6df5948575d7cb325c9393383:Graphs`);
this.stateService.networkChanged$.subscribe((network) => this.network = network); this.stateService.networkChanged$.subscribe((network) => this.network = network);
this.inverted = this.storageService.getValue('inverted-graph') === 'true'; this.inverted = this.storageService.getValue('inverted-graph') === 'true';
const isMobile = window.innerWidth <= 767.98; const isMobile = window.innerWidth <= 767.98;

View File

@ -24,7 +24,7 @@ export class TelevisionComponent implements OnInit {
) { } ) { }
ngOnInit() { ngOnInit() {
this.seoService.setTitle('TV view'); this.seoService.setTitle($localize`:@@46ce8155c9ab953edeec97e8950b5a21e67d7c4e:TV view`);
this.websocketService.want(['blocks', 'live-2h-chart', 'mempool-blocks']); this.websocketService.want(['blocks', 'live-2h-chart', 'mempool-blocks']);
this.apiService.list2HStatistics$() this.apiService.list2HStatistics$()

View File

@ -123,10 +123,10 @@
</ng-template> </ng-template>
<ng-template #belowBlockLimit> <ng-template #belowBlockLimit>
<ng-template [ngIf]="network === 'liquid'" [ngIfElse]="timeEstimateDefault"> <ng-template [ngIf]="network === 'liquid'" [ngIfElse]="timeEstimateDefault">
&lt; {{ 1 * txInBlockIndex + 1 }}&nbsp;<span i18n="transaction.minutes|Transaction Minutes">minutes</span>&nbsp;<i>({{ txInBlockIndex + 1 }} <span i18n="transaction.eta.block|Transaction ETA (X blocks)">block</span>{{ txInBlockIndex > 0 ? 's' : '' }})</i> &lt; {{ 1 * txInBlockIndex + 1 }}&nbsp;<span i18n="transaction.minutes|Transaction Minutes">minutes</span>&nbsp;<i>(<ng-template [ngIf]="txInBlockIndex === 0" [ngIfElse]="blocksPlural" i18n="shared.block">{{ txInBlockIndex + 1 }} block</ng-template>)</i>
</ng-template> </ng-template>
<ng-template #timeEstimateDefault> <ng-template #timeEstimateDefault>
~{{ 10 * txInBlockIndex + 10 }}&nbsp;<span i18n="transaction.minutes|Transaction Minutes">minutes</span>&nbsp;<i>({{ txInBlockIndex + 1 }} <span i18n="transaction.eta.block|Transaction ETA (X blocks)">block</span>{{ txInBlockIndex > 0 ? 's' : '' }})</i> ~{{ 10 * txInBlockIndex + 10 }}&nbsp;<span i18n="transaction.minutes|Transaction Minutes">minutes</span>&nbsp;<i>(<ng-template [ngIf]="txInBlockIndex === 0" [ngIfElse]="blocksPlural" i18n="shared.block">{{ txInBlockIndex + 1 }} block</ng-template>)</i>
</ng-template> </ng-template>
</ng-template> </ng-template>
</ng-template> </ng-template>
@ -285,3 +285,5 @@
</div> </div>
<br> <br>
<ng-template #blocksPlural i18n="shared.blocks">{{ txInBlockIndex + 1 }} blocks</ng-template>

View File

@ -45,7 +45,7 @@ export class TransactionComponent implements OnInit, OnDestroy {
this.subscription = this.route.paramMap.pipe( this.subscription = this.route.paramMap.pipe(
switchMap((params: ParamMap) => { switchMap((params: ParamMap) => {
this.txId = params.get('id') || ''; this.txId = params.get('id') || '';
this.seoService.setTitle('Transaction: ' + this.txId); this.seoService.setTitle($localize`:@@bisq.transaction.browser-title:Transaction: ${this.txId}:INTERPOLATION:`);
this.resetTransaction(); this.resetTransaction();
return merge( return merge(
of(true), of(true),

View File

@ -1,22 +0,0 @@
<!-- this component is only used for the angular string extractor -->{{counter}}
<div>
<span i18n="@@time-since.just-now">Just now</span>
<span i18n="@@time-since.sec.ago">{{counter}} sec ago</span>
<span i18n="@@time-since.secs.ago">{{counter}} secs ago</span>
<span i18n="@@time-since.second.ago">{{counter}} second ago</span>
<span i18n="@@time-since.seconds.ago">{{counter}} seconds ago</span>
<span i18n="@@time-since.min.ago">{{counter}} min ago</span>
<span i18n="@@time-since.mins.ago">{{counter}} mins ago</span>
<span i18n="@@time-since.minute.ago">{{counter}} minute ago</span>
<span i18n="@@time-since.minutes.ago">{{counter}} minutes ago</span>
<span i18n="@@time-since.hour.ago">{{counter}} hour ago</span>
<span i18n="@@time-since.hours.ago">{{counter}} hours ago</span>
<span i18n="@@time-since.day.ago">{{counter}} day ago</span>
<span i18n="@@time-since.days.ago">{{counter}} days ago</span>
<span i18n="@@time-since.week.ago">{{counter}} week ago</span>
<span i18n="@@time-since.weeks.ago">{{counter}} weeks ago</span>
<span i18n="@@time-since.month.ago">{{counter}} month ago</span>
<span i18n="@@time-since.months.ago">{{counter}} months ago</span>
<span i18n="@@time-since.year.ago">{{counter}} year ago</span>
<span i18n="@@time-since.years.ago">{{counter}} years ago</span>
</div>

View File

@ -1,10 +0,0 @@
import { Component } from '@angular/core';
@Component({
selector: 'app-translation-strings',
templateUrl: './translation-strings.component.html'
})
export class TranslationStringsComponent {
counter: string;
constructor() { }
}

View File

@ -1,8 +1,8 @@
<span *ngIf="segwitGains.realizedGains && !segwitGains.potentialBech32Gains; else segwitTwo" class="badge badge-success mr-1" ngbTooltip="This transaction saved {{ segwitGains.realizedGains * 100 | number: '1.0-0' }}% on fees by using native SegWit-Bech32" placement="bottom" i18n="tx-features.tag.segwit|SegWit">SegWit</span> <span *ngIf="segwitGains.realizedGains && !segwitGains.potentialBech32Gains; else segwitTwo" class="badge badge-success mr-1" i18n-ngbTooltip="ngbTooltip about segwit gains" ngbTooltip="This transaction saved {{ segwitGains.realizedGains * 100 | number: '1.0-0' }}% on fees by using native SegWit-Bech32" placement="bottom" i18n="tx-features.tag.segwit|SegWit">SegWit</span>
<ng-template #segwitTwo> <ng-template #segwitTwo>
<span *ngIf="segwitGains.realizedGains && segwitGains.potentialBech32Gains else potentialP2shGains" class="badge badge-warning mr-1" ngbTooltip="This transaction saved {{ segwitGains.realizedGains * 100 | number: '1.0-0' }}% on fees by using SegWit and could save {{ segwitGains.potentialBech32Gains * 100 | number : '1.0-0' }}% more by fully upgrading to native SegWit-Bech32" placement="bottom" i18n="tx-features.tag.segwit|SegWit">SegWit</span> <span *ngIf="segwitGains.realizedGains && segwitGains.potentialBech32Gains else potentialP2shGains" class="badge badge-warning mr-1" i18n-ngbTooltip="ngbTooltip about double segwit gains" ngbTooltip="This transaction saved {{ segwitGains.realizedGains * 100 | number: '1.0-0' }}% on fees by using SegWit and could save {{ segwitGains.potentialBech32Gains * 100 | number : '1.0-0' }}% more by fully upgrading to native SegWit-Bech32" placement="bottom" i18n="tx-features.tag.segwit|SegWit">SegWit</span>
<ng-template #potentialP2shGains> <ng-template #potentialP2shGains>
<span *ngIf="segwitGains.potentialP2shGains" class="badge badge-danger mr-1" ngbTooltip="This transaction could save {{ segwitGains.potentialBech32Gains * 100 | number : '1.0-0' }}% on fees by upgrading to native SegWit-Bech32 or {{ segwitGains.potentialP2shGains * 100 | number: '1.0-0' }}% by upgrading to SegWit-P2SH" placement="bottom"><del i18n="tx-features.tag.segwit|SegWit">SegWit</del></span> <span *ngIf="segwitGains.potentialP2shGains" class="badge badge-danger mr-1" i18n-ngbTooltip="ngbTooltip about missed out gains" ngbTooltip="This transaction could save {{ segwitGains.potentialBech32Gains * 100 | number : '1.0-0' }}% on fees by upgrading to native SegWit-Bech32 or {{ segwitGains.potentialP2shGains * 100 | number: '1.0-0' }}% by upgrading to SegWit-P2SH" placement="bottom"><del i18n="tx-features.tag.segwit|SegWit">SegWit</del></span>
</ng-template> </ng-template>
</ng-template> </ng-template>
<span *ngIf="isRbfTransaction" class="badge badge-success" ngbTooltip="This transaction support Replace-By-Fee (RBF) allowing fee bumping" placement="bottom" i18n="tx-features.tag.rbf|RBF">RBF</span> <span *ngIf="isRbfTransaction" class="badge badge-success" i18n-ngbTooltip="RBF tooltip" ngbTooltip="This transaction support Replace-By-Fee (RBF) allowing fee bumping" placement="bottom" i18n="tx-features.tag.rbf|RBF">RBF</span>

View File

@ -1,3 +1,3 @@
<span *ngIf="feeRating === 1" class="badge badge-success" i18n="tx-fee-rating.optimal|TX Fee Rating is Optimal">Optimal</span> <span *ngIf="feeRating === 1" class="badge badge-success" i18n="tx-fee-rating.optimal|TX Fee Rating is Optimal">Optimal</span>
<span *ngIf="feeRating === 2" class="badge badge-warning" title="Only ~{{ medianFeeNeeded }} sat/vB was needed to get into this block" i18n="tx-fee-rating.overpaid.warning|TX Fee Rating is Warning">Overpaid {{ overpaidTimes }}x</span> <span *ngIf="feeRating === 2" class="badge badge-warning" placement="bottom" i18n-ngbTooltip="tx-fee-rating.warning-tooltip" ngbTooltip="Only ~{{ medianFeeNeeded }} sat/vB was needed to get into this block" i18n="tx-fee-rating.overpaid.warning|TX Fee Rating is Warning">Overpaid {{ overpaidTimes }}x</span>
<span *ngIf="feeRating === 3" class="badge badge-danger" title="Only ~{{ medianFeeNeeded }} sat/vB was needed to get into this block" i18n="tx-fee-rating.overpaid.danger|TX Fee Rating is Danger">Overpaid {{ overpaidTimes }}x</span> <span *ngIf="feeRating === 3" class="badge badge-danger" placement="bottom" i18n-ngbTooltip="tx-fee-rating.danger-tooltip" ngbTooltip="Only ~{{ medianFeeNeeded }} sat/vB was needed to get into this block" i18n="tx-fee-rating.overpaid.danger|TX Fee Rating is Danger">Overpaid {{ overpaidTimes }}x</span>

View File

@ -128,8 +128,8 @@
<button type="button" class="btn btn-secondary btn-sm d-block mx-auto" (click)="toggleCollapsed()"> <button type="button" class="btn btn-secondary btn-sm d-block mx-auto" (click)="toggleCollapsed()">
<div [ngSwitch]="collapseLevel"> <div [ngSwitch]="collapseLevel">
<fa-icon *ngSwitchCase="'three'" [icon]="['fas', 'angle-down']" [fixedWidth]="true" title="Collapse"></fa-icon> <fa-icon *ngSwitchCase="'three'" [icon]="['fas', 'angle-down']" [fixedWidth]="true" i18n-title="dashboard.collapse" title="Collapse"></fa-icon>
<fa-icon *ngSwitchDefault [icon]="['fas', 'angle-up']" [fixedWidth]="true" title="Expand"></fa-icon> <fa-icon *ngSwitchDefault [icon]="['fas', 'angle-up']" [fixedWidth]="true" i18n-title="dashboard.expand" title="Expand"></fa-icon>
</div> </div>
</button> </button>
@ -161,7 +161,7 @@
<td> <td>
<h5 class="card-title" i18n="dashboard.mempool-size|Mempool size">Mempool size</h5> <h5 class="card-title" i18n="dashboard.mempool-size|Mempool size">Mempool size</h5>
<p class="card-text" *ngIf="(mempoolBlocksData$ | async) as mempoolBlocksData; else loading"> <p class="card-text" *ngIf="(mempoolBlocksData$ | async) as mempoolBlocksData; else loading">
{{ mempoolBlocksData.size | bytes }} ({{ mempoolBlocksData.blocks }} <span [hidden]="mempoolBlocksData.blocks == 1" i18n="dashboard.block">block</span><span [hidden]="mempoolBlocksData.blocks != 1">blocks</span>) {{ mempoolBlocksData.size | bytes }} (<ng-template [ngIf]="mempoolBlocksData.blocks === 1" [ngIfElse]="blocksPlural" i18n="shared.block">{{ mempoolBlocksData.blocks }} block</ng-template><ng-template i18n="shared.blocks" #blocksPlural>{{ mempoolBlocksData.blocks }} blocks</ng-template>)
</p> </p>
</td> </td>
<td> <td>
@ -182,7 +182,7 @@
</span> </span>
<ng-template #inSync> <ng-template #inSync>
<div class="progress sub-text" style="max-width: 250px;"> <div class="progress sub-text" style="max-width: 250px;">
<div class="progress-bar {{ mempoolInfoData.value.progressClass }}" style="padding: 4px;" role="progressbar" [ngStyle]="{'width': mempoolInfoData.value.progressWidth}">{{ mempoolInfoData.value.vBytesPerSecond | ceil | number }} <ng-template i18n="shared.vbytes-per-second|vB/s">vB/s</ng-template></div> <div class="progress-bar {{ mempoolInfoData.value.progressClass }}" style="padding: 4px;" role="progressbar" [ngStyle]="{'width': mempoolInfoData.value.progressWidth}">{{ mempoolInfoData.value.vBytesPerSecond | ceil | number }} <ng-container i18n="shared.vbytes-per-second|vB/s">vB/s</ng-container></div>
</div> </div>
</ng-template> </ng-template>
</ng-template> </ng-template>

View File

@ -256,9 +256,9 @@ export class DashboardComponent implements OnInit {
changeLanguage() { changeLanguage() {
const language = this.languageForm.get('language').value; const language = this.languageForm.get('language').value;
this.document.location.href = (language === 'en' ? '/' : '/' + language);
try { try {
document.cookie = `lang=${language}; expires=Thu, 18 Dec 2050 12:00:00 UTC; path=/`; document.cookie = `lang=${language}; expires=Thu, 18 Dec 2050 12:00:00 UTC; path=/`;
} catch (e) { } } catch (e) { }
this.document.location.href = (language === 'en' ? '/' : '/' + language);
} }
} }

File diff suppressed because it is too large Load Diff