From 4658b470075fb8ef62dbcfe023f0906ec7ee0640 Mon Sep 17 00:00:00 2001 From: wiz Date: Wed, 2 Dec 2020 04:19:33 +0900 Subject: [PATCH] Implement i18n support in frontend using Angular + Transifex + NGINX This PR adds basic i18n support into the mempool frontend, together with a smooth workflow for developers and translators to collaborate: * Using the existing @angular/localize module, developers add i18n metadata to any frontend strings their new features or changes modify * Using the new npm script `i18n-extract-from-source`, developers extract the i18n data from source code into `src/locale/messages.xlf` * After pushing the updated `src/locale/messages.xlf` to GitHub, the Transifex service will update its database from the new source data * Using the Transifex website UI, translators can work together to translate all the mempool frontend strings into their native languages * Using the new npm script `i18n-pull-from-transifex`, developers can pull in completed translations from Transifex, and commit them into git. This flow requires an API key from Transifex, which can be obtained at https://www.transifex.com/user/settings/api/ to be used with the python script installed by `pip install transifex-client` - after preparing these, run the npm script which will ask you for the API key the first time. When downloading is complete, you can test building the frontend, and if successful, commit the new strings files into git. This PR implements a new locale selector in the footer of the homepage dashboard, and includes WIP translations for the following languages: * Czech (cs) * German (de) * Japanese (ja) * Norwegian (nn) * Spanish (es) * Swedish (sv) * Ukrainian (uk) * Persian (fa) * Portugese (pt) * Turkish (tr) * Dutch (nl) * French (fr) * Chinese (zh) * Slovenian (sl) * Korean (ko) * Polish (pl) The user-agent's `Accept-Language` header is used to automatically detect their preferred language, which can be manually overriden by the pull-down selector, which saves their preference to a cookie, which is used by nginx to serve the correct HTML bundle to the user. Remaining tasks include adding i18n metadata for strings in the Bisq and Liquid frontend code, mouseover hover tooltip strings, hard-coded og metadata inside HTML templates, and many other places. This will be done in a separate PR. When upgrading to add i18n support, mempool instance operators must take care to install the new nginx.conf and nginx-mempool.conf files, and tweak for their specific site configuration. Fixes #81 --- frontend/.tx/config | 7 + frontend/angular.json | 62 +- frontend/frontend | 1 + frontend/package.json | 4 +- frontend/src/app/app.constants.ts | 55 + frontend/src/app/app.module.ts | 2 + .../app/components/about/about.component.html | 32 +- .../address-labels.component.html | 4 +- .../components/address/address.component.html | 14 +- .../components/amount/amount.component.html | 2 +- .../api-docs/api-docs.component.html | 130 +- .../app/components/asset/asset.component.html | 24 +- .../app/components/block/block.component.html | 30 +- .../blockchain-blocks.component.html | 8 +- .../blockchain/blockchain.component.html | 2 +- .../clipboard/clipboard.component.html | 2 +- .../fees-box/fees-box.component.html | 18 +- .../components/footer/footer.component.html | 10 +- .../latest-blocks.component.html | 12 +- .../master-page/master-page.component.html | 6 +- .../mempool-block.component.html | 12 +- .../mempool-blocks.component.html | 12 +- .../app/components/miner/miner.component.html | 2 +- .../search-form/search-form.component.html | 4 +- .../statistics/statistics.component.html | 7 +- .../television/television.component.html | 2 +- .../time-since/time-since.component.ts | 50 +- .../transaction/transaction.component.html | 62 +- .../transactions-list.component.html | 43 +- .../translation-strings.component.html | 22 + .../translation-strings.component.ts | 10 + .../tx-features/tx-features.component.html | 8 +- .../tx-fee-rating.component.html | 6 +- .../app/dashboard/dashboard.component.html | 52 +- .../src/app/dashboard/dashboard.component.ts | 31 +- frontend/src/index.html | 4 +- frontend/src/locale/messages.cs.xlf | 2224 ++++++++++++++++ frontend/src/locale/messages.de.xlf | 2224 ++++++++++++++++ frontend/src/locale/messages.en_US.xlf | 2016 +++++++++++++++ frontend/src/locale/messages.es.xlf | 2224 ++++++++++++++++ frontend/src/locale/messages.fa.xlf | 2217 ++++++++++++++++ frontend/src/locale/messages.fr.xlf | 2134 ++++++++++++++++ frontend/src/locale/messages.ja.xlf | 2224 ++++++++++++++++ frontend/src/locale/messages.ko.xlf | 2067 +++++++++++++++ frontend/src/locale/messages.nl.xlf | 2154 ++++++++++++++++ frontend/src/locale/messages.nn.xlf | 2224 ++++++++++++++++ frontend/src/locale/messages.pl.xlf | 2046 +++++++++++++++ frontend/src/locale/messages.pt.xlf | 2187 ++++++++++++++++ frontend/src/locale/messages.pt_BR.xlf | 2203 ++++++++++++++++ frontend/src/locale/messages.sl.xlf | 2113 ++++++++++++++++ frontend/src/locale/messages.sv.xlf | 2226 +++++++++++++++++ frontend/src/locale/messages.tr.xlf | 2167 ++++++++++++++++ frontend/src/locale/messages.uk.xlf | 2224 ++++++++++++++++ frontend/src/locale/messages.xlf | 2017 +++++++++++++++ frontend/src/locale/messages.zh.xlf | 2116 ++++++++++++++++ frontend/src/styles.scss | 9 + frontend/sync-assets.js | 2 +- production/nginx-mempool.conf | 195 ++ production/nginx.conf | 263 +- production/test-nginx | 49 + 60 files changed, 41826 insertions(+), 451 deletions(-) create mode 100644 frontend/.tx/config create mode 120000 frontend/frontend create mode 100644 frontend/src/app/components/translation-strings/translation-strings.component.html create mode 100644 frontend/src/app/components/translation-strings/translation-strings.component.ts create mode 100644 frontend/src/locale/messages.cs.xlf create mode 100644 frontend/src/locale/messages.de.xlf create mode 100644 frontend/src/locale/messages.en_US.xlf create mode 100644 frontend/src/locale/messages.es.xlf create mode 100644 frontend/src/locale/messages.fa.xlf create mode 100644 frontend/src/locale/messages.fr.xlf create mode 100644 frontend/src/locale/messages.ja.xlf create mode 100644 frontend/src/locale/messages.ko.xlf create mode 100644 frontend/src/locale/messages.nl.xlf create mode 100644 frontend/src/locale/messages.nn.xlf create mode 100644 frontend/src/locale/messages.pl.xlf create mode 100644 frontend/src/locale/messages.pt.xlf create mode 100644 frontend/src/locale/messages.pt_BR.xlf create mode 100644 frontend/src/locale/messages.sl.xlf create mode 100644 frontend/src/locale/messages.sv.xlf create mode 100644 frontend/src/locale/messages.tr.xlf create mode 100644 frontend/src/locale/messages.uk.xlf create mode 100644 frontend/src/locale/messages.xlf create mode 100644 frontend/src/locale/messages.zh.xlf create mode 100644 production/nginx-mempool.conf create mode 100755 production/test-nginx diff --git a/frontend/.tx/config b/frontend/.tx/config new file mode 100644 index 000000000..ec792e837 --- /dev/null +++ b/frontend/.tx/config @@ -0,0 +1,7 @@ +[main] +host = https://www.transifex.com + +[mempool.frontend-src-locale-messages-xlf--wiz-i18n] +file_filter = frontend/src/locale/messages..xlf +source_lang = en-US +type = XLIFF diff --git a/frontend/angular.json b/frontend/angular.json index 53573221f..0cb9e4539 100644 --- a/frontend/angular.json +++ b/frontend/angular.json @@ -13,6 +13,66 @@ "root": "", "sourceRoot": "src", "prefix": "app", + "i18n": { + "sourceLocale": { + "code":"en-US", + "baseHref":"/" + }, + "locales": { + "cs": { + "translation": "src/locale/messages.cs.xlf", + "baseHref": "/cs/" + }, + "de": { + "translation": "src/locale/messages.de.xlf", + "baseHref": "/de/" + }, + "es": { + "translation": "src/locale/messages.es.xlf", + "baseHref": "/es/" + }, + "fa": { + "translation": "src/locale/messages.fa.xlf", + "baseHref": "/fa/" + }, + "ja": { + "translation": "src/locale/messages.ja.xlf", + "baseHref": "/ja/" + }, + "nl": { + "translation": "src/locale/messages.nl.xlf", + "baseHref": "/nl/" + }, + "nn": { + "translation": "src/locale/messages.nn.xlf", + "baseHref": "/nn/" + }, + "pt": { + "translation": "src/locale/messages.pt.xlf", + "baseHref": "/pt/" + }, + "sv": { + "translation": "src/locale/messages.sv.xlf", + "baseHref": "/sv/" + }, + "sl": { + "translation": "src/locale/messages.sl.xlf", + "baseHref": "/sl/" + }, + "tr": { + "translation": "src/locale/messages.tr.xlf", + "baseHref": "/tr/" + }, + "uk": { + "translation": "src/locale/messages.uk.xlf", + "baseHref": "/uk/" + }, + "zh": { + "translation": "src/locale/messages.zh.xlf", + "baseHref": "/zh/" + } + } + }, "architect": { "build": { "builder": "@angular-devkit/build-angular:browser", @@ -127,4 +187,4 @@ } }}, "defaultProject": "mempool" -} \ No newline at end of file +} diff --git a/frontend/frontend b/frontend/frontend new file mode 120000 index 000000000..945c9b46d --- /dev/null +++ b/frontend/frontend @@ -0,0 +1 @@ +. \ No newline at end of file diff --git a/frontend/package.json b/frontend/package.json index a80dd0b87..55b25656c 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -22,9 +22,11 @@ "scripts": { "ng": "./node_modules/@angular/cli/bin/ng", "tsc": "./node_modules/typescript/bin/tsc", + "i18n-extract-from-source": "./node_modules/@angular/cli/bin/ng xi18n --ivy --out-file ./src/locale/messages.xlf", + "i18n-pull-from-transifex": "tx pull -a --parallel --minimum-perc 1", "serve": "ng serve --proxy-config proxy.conf.json", "start": "npm run generate-config && npm run sync-assets-dev && ng serve --proxy-config proxy.conf.json", - "build": "npm run generate-config && ng build --prod && npm run sync-assets", + "build": "npm run generate-config && ng build --prod --localize && npm run sync-assets", "sync-assets": "node sync-assets.js", "sync-assets-dev": "node sync-assets.js dev", "generate-config": "node generate-config.js", diff --git a/frontend/src/app/app.constants.ts b/frontend/src/app/app.constants.ts index 7e817d714..5c6919ec0 100644 --- a/frontend/src/app/app.constants.ts +++ b/frontend/src/app/app.constants.ts @@ -58,3 +58,58 @@ const browserWindow = window || {}; // @ts-ignore const browserWindowEnv = browserWindow.__env || {}; export const env: Env = Object.assign(defaultEnv, browserWindowEnv); + +export interface Language { + code: string; + name: string; +} + +export const languages: Language[] = [ +// { code: 'ar', name: 'العربية' }, // Arabic +// { code: 'bg', name: 'Български' }, // Bulgarian +// { code: 'bs', name: 'Bosanski' }, // Bosnian +// { code: 'ca', name: 'Català' }, // Catalan + { code: 'cs', name: 'Čeština' }, // Czech +// { code: 'da', name: 'Dansk' }, // Danish + { code: 'de', name: 'Deutsch' }, // German +// { code: 'et', name: 'Eesti' }, // Estonian +// { code: 'el', name: 'Ελληνικά' }, // Greek + { code: 'en', name: 'English' }, // English + { code: 'es', name: 'Español' }, // Spanish +// { code: 'eo', name: 'Esperanto' }, // Esperanto +// { code: 'eu', name: 'Euskara' }, // Basque + { code: 'fa', name: 'فارسی' }, // Persian +// { code: 'fr', name: 'Français' }, // French +// { code: 'gl', name: 'Galego' }, // Galician +// { code: 'ko', name: '한국어' }, // Korean +// { code: 'hr', name: 'Hrvatski' }, // Croatian +// { code: 'id', name: 'Bahasa Indonesia' },// Indonesian +// { code: 'it', name: 'Italiano' }, // Italian +// { code: 'he', name: 'עברית' }, // Hebrew +// { code: 'ka', name: 'ქართული' }, // Georgian +// { code: 'lv', name: 'Latviešu' }, // Latvian +// { code: 'lt', name: 'Lietuvių' }, // Lithuanian +// { code: 'hu', name: 'Magyar' }, // Hungarian +// { code: 'mk', name: 'Македонски' }, // Macedonian +// { code: 'ms', name: 'Bahasa Melayu' }, // Malay + { code: 'nl', name: 'Nederlands' }, // Dutch + { code: 'ja', name: '日本語' }, // Japanese +// { code: 'nb', name: 'Norsk bokmål' }, // Norwegian Bokmål + { code: 'nn', name: 'Norsk' }, // Norwegian Nynorsk +// { code: 'pl', name: 'Polski' }, // Polish + { code: 'pt', name: 'Português' }, // Portuguese +// { code: 'pt-BR', name: 'Português (Brazil)' }, // Portuguese (Brazil) +// { code: 'ro', name: 'Română' }, // Romanian +// { code: 'ru', name: 'Русский' }, // Russian +// { code: 'sk', name: 'Slovenčina' }, // Slovak + { code: 'sl', name: 'Slovenščina' }, // Slovenian +// { code: 'sr', name: 'Српски / srpski' }, // Serbian +// { code: 'sh', name: 'Srpskohrvatski / српскохрватски' },// Serbo-Croatian +// { code: 'fi', name: 'Suomi' }, // Finnish + { code: 'sv', name: 'Svenska' }, // Swedish +// { code: 'th', name: 'ไทย' }, // Thai + { code: 'tr', name: 'Türkçe' }, // Turkish + { code: 'uk', name: 'Українська' }, // Ukrainian +// { code: 'vi', name: 'Tiếng Việt' }, // Vietnamese + { code: 'zh', name: '中文' }, // Chinese +]; diff --git a/frontend/src/app/app.module.ts b/frontend/src/app/app.module.ts index 270143297..a80d81599 100644 --- a/frontend/src/app/app.module.ts +++ b/frontend/src/app/app.module.ts @@ -47,6 +47,7 @@ import { faAngleDoubleDown, faAngleDoubleUp, faAngleDown, faAngleUp, faBolt, faC faLink, faList, faSearch, faTachometerAlt, faThList, faTint, faTv } from '@fortawesome/free-solid-svg-icons'; import { ApiDocsComponent } from './components/api-docs/api-docs.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'; @NgModule({ @@ -82,6 +83,7 @@ import { StorageService } from './services/storage.service'; DashboardComponent, ApiDocsComponent, TermsOfServiceComponent, + TranslationStringsComponent, ], imports: [ BrowserModule, diff --git a/frontend/src/app/components/about/about.component.html b/frontend/src/app/components/about/about.component.html index 1cde15335..4924ab364 100644 --- a/frontend/src/app/components/about/about.component.html +++ b/frontend/src/app/components/about/about.component.html @@ -10,16 +10,16 @@
-

About the project

+

About the project

-

The mempool open-source project aims to implement a high quality explorer and visualization website for the entire Bitcoin ecosystem, without distractions like altcoins, advertising, or third-party trackers.

+

The mempool open-source project aims to implement a high quality explorer and visualization website for the entire Bitcoin ecosystem, without distractions like altcoins, advertising, or third-party trackers.


-

Maintainers

+

Maintainers

@@ -29,7 +29,7 @@ @softsimon_
- Development + Development
@@ -37,14 +37,14 @@ @wiz
- Operations + Operations


-

Sponsors ❤️

+

Sponsors ❤️


@@ -60,9 +60,9 @@

- +

- Navigate to https://mempool.space/about to sponsor + Navigate to https://mempool.space/about to sponsor

@@ -79,17 +79,17 @@
-
Amount required
-
Minimum amount is 0.001 BTC
+
Amount required
+
Minimum amount is 0.001 BTC
- +
- If you donate 0.01 BTC or more, your profile photo will be added to the list of sponsors above :) + If you donate 0.01 BTC or more, your profile photo will be added to the list of sponsors above :)
@@ -167,13 +167,13 @@

{{ donationObj.amount }} BTC

-

Waiting for transaction...

+

Waiting for transaction...

-

Donation confirmed!
Thank you!

-

If you specified a Twitter handle, the profile photo should now be visible on this page when you reload.

+

Donation confirmed!
Thank you!

+

If you specified a Twitter handle, the profile photo should now be visible on this page when you reload.





@@ -203,7 +203,7 @@

diff --git a/frontend/src/app/components/address-labels/address-labels.component.html b/frontend/src/app/components/address-labels/address-labels.component.html index 16deecabf..2b986aecf 100644 --- a/frontend/src/app/components/address-labels/address-labels.component.html +++ b/frontend/src/app/components/address-labels/address-labels.component.html @@ -1,2 +1,2 @@ -multisig {{ multisigM }} of {{ multisigN }} -Layer{{ network === 'liquid' ? '3' : '2' }} Peg-out +multisig {{ multisigM }} of {{ multisigN }} +Layer{{ network === 'liquid' ? '3' : '2' }} Peg-out diff --git a/frontend/src/app/components/address/address.component.html b/frontend/src/app/components/address/address.component.html index 4552f9214..7109c21e3 100644 --- a/frontend/src/app/components/address/address.component.html +++ b/frontend/src/app/components/address/address.component.html @@ -1,5 +1,5 @@
-

Address

+

Address

{{ addressString | shortenString : 24 }} {{ addressString }} @@ -17,15 +17,15 @@ - + - + - + @@ -43,7 +43,7 @@
-

{{ (transactions?.length | number) || '?' }} of {{ txCount | number }} transactions

+

{{ (transactions?.length | number) || '?' }} of {{ txCount | number }} transactions

@@ -98,7 +98,7 @@
- Error loading address data. + Error loading address data.
{{ error.error }}
@@ -109,5 +109,5 @@
-
+ diff --git a/frontend/src/app/components/amount/amount.component.html b/frontend/src/app/components/amount/amount.component.html index b453ce6d0..f3e1e1631 100644 --- a/frontend/src/app/components/amount/amount.component.html +++ b/frontend/src/app/components/amount/amount.component.html @@ -3,7 +3,7 @@ - Confidential + Confidential {{ satoshis / 100000000 | number : digitsInfo }} diff --git a/frontend/src/app/components/api-docs/api-docs.component.html b/frontend/src/app/components/api-docs/api-docs.component.html index 2f5730640..73013525c 100644 --- a/frontend/src/app/components/api-docs/api-docs.component.html +++ b/frontend/src/app/components/api-docs/api-docs.component.html @@ -6,17 +6,17 @@
Total receivedTotal received
Total sentTotal sent
BalanceBalance ()
ConfidentialConfidential
- - + + - +
EndpointDescriptionEndpointDescription
wss://{{ hostname }}{{ network.val === '' ? '' : '/' + network.val }}/api/v1/wsDefault push: {{ '{' }} action: 'want', data: ['blocks', ...] {{ '}' }} to express what you want pushed. Available: blocks, mempool-block, live-2h-chart, and stats.

Push transactions related to address: {{ '{' }} 'track-address': '3PbJ...bF9B' {{ '}' }} to receive all new transactions containing that address as input or output. Returns an array of transactions. address-transactions for new mempool transactions, and block-transactions for new block confirmed transactions.
Default push: {{ '{' }} action: 'want', data: ['blocks', ...] {{ '}' }} to express what you want pushed. Available: blocks, mempool-block, live-2h-chart, and stats.

Push transactions related to address: {{ '{' }} 'track-address': '3PbJ...bF9B' {{ '}' }} to receive all new transactions containing that address as input or output. Returns an array of transactions. address-transactions for new mempool transactions, and block-transactions for new block confirmed transactions.
@@ -24,21 +24,21 @@
  • - Fee Estimates + Fees - - + + - + - +
    EndpointDescriptionEndpointDescription
    GET {{ network.val === '' ? '' : '/' + network.val }}/api/v1/fees/recommendedReturns our currently suggested fees for new transactions.Returns our currently suggested fees for new transactions.
    GET {{ network.val === '' ? '' : '/' + network.val }}/api/v1/fees/mempool-blocksReturns current mempool as projected blocks.Returns current mempool as projected blocks.
    @@ -46,25 +46,25 @@
  • - Mempool + Mempool - - + + - + - + - +
    EndpointDescriptionEndpointDescription
    GET {{ network.val === '' ? '' : '/' + network.val }}/api/mempoolReturns current mempool backlog statistics.Returns current mempool backlog statistics.
    GET {{ network.val === '' ? '' : '/' + network.val }}/api/mempool/txidsGet the full list of txids in the mempool as an array. The order of the txids is arbitrary and does not match bitcoind.Get the full list of txids in the mempool as an array. The order of the txids is arbitrary and does not match bitcoind.
    GET {{ network.val === '' ? '' : '/' + network.val }}/api/mempool/recentGet a list of the last 10 transactions to enter the mempool. Each transaction object contains simplified overview data, with the following fields: txid, fee, vsize, and value.Get a list of the last 10 transactions to enter the mempool. Each transaction object contains simplified overview data, with the following fields: txid, fee, vsize, and value.
    @@ -72,53 +72,53 @@
  • - Blocks + Blocks - - + + - + - + - + - + - + - + - + - + - + - +
    EndpointDescriptionEndpointDescription
    GET {{ network.val === '' ? '' : '/' + network.val }}/api/block/:hashReturns details about a block. Available fields: id, height, version, timestamp, bits, nonce, merkle_root, tx_count, size, weight, proof, and previousblockhash.Returns details about a block. Available fields: id, height, version, timestamp, bits, nonce, merkle_root, tx_count, size, weight, proof, and previousblockhash.
    GET {{ network.val === '' ? '' : '/' + network.val }}/api/block/:hash/statusReturns the confirmation status of a block. Available fields: in_best_chain (boolean, false for orphaned blocks), next_best (the hash of the next block, only available for blocks in the best chain).Returns the confirmation status of a block. Available fields: in_best_chain (boolean, false for orphaned blocks), next_best (the hash of the next block, only available for blocks in the best chain).
    GET {{ network.val === '' ? '' : '/' + network.val }}/api/block/:hash/txs[/:start_index]Returns a list of transactions in the block (up to 25 transactions beginning at start_index). Transactions returned here do not have the status field, since all the transactions share the same block and confirmation status.Returns a list of transactions in the block (up to 25 transactions beginning at start_index). Transactions returned here do not have the status field, since all the transactions share the same block and confirmation status.
    GET {{ network.val === '' ? '' : '/' + network.val }}/api/block/:hash/txidsReturns a list of all txids in the block.Returns a list of all txids in the block.
    GET {{ network.val === '' ? '' : '/' + network.val }}/api/block/:hash/txid/:indexReturns the transaction at index :index within the specified block.Returns the transaction at index :index within the specified block.
    GET {{ network.val === '' ? '' : '/' + network.val }}/api/block/:hash/txid/rawReturns the raw block representation in binary.Returns the raw block representation in binary.
    GET {{ network.val === '' ? '' : '/' + network.val }}/api/block-height/:heightReturns the hash of the block currently at :height.Returns the hash of the block currently at :height.
    GET {{ network.val === '' ? '' : '/' + network.val }}/api/blocks[/:start_height]Returns the 10 newest blocks starting at the tip or at :start_height if specified.Returns the 10 newest blocks starting at the tip or at :start_height if specified.
    GET {{ network.val === '' ? '' : '/' + network.val }}/api/blocks/tip/heightReturns the height of the last block.Returns the height of the last block.
    GET {{ network.val === '' ? '' : '/' + network.val }}/api/blocks/tip/hashReturns the hash of the last block.Returns the hash of the last block.
    @@ -126,49 +126,49 @@
  • - Transactions + Transactions - - + + - + - + - + - + - + - + - + - + - +
    EndpointDescriptionEndpointDescription
    GET {{ network.val === '' ? '' : '/' + network.val }}/api/tx/:txidReturns details about a transaction. Available fields: txid, version, locktime, size, weight, fee, vin, vout, and status.Returns details about a transaction. Available fields: txid, version, locktime, size, weight, fee, vin, vout, and status.
    GET {{ network.val === '' ? '' : '/' + network.val }}/api/tx/:txid/statusReturns the confirmation status of a transaction. Available fields: confirmed (boolean), block_height (optional), and block_hash (optional).Returns the confirmation status of a transaction. Available fields: confirmed (boolean), block_height (optional), and block_hash (optional).
    GET {{ network.val === '' ? '' : '/' + network.val }}/api/tx/:txid/hexReturns a transaction serialized as hex.Returns a transaction serialized as hex.
    GET {{ network.val === '' ? '' : '/' + network.val }}/api/tx/:txid/rawReturns a transaction as binary data.Returns a transaction as binary data.
    GET {{ network.val === '' ? '' : '/' + network.val }}/api/tx/:txid/merkleblock-proofReturns a merkle inclusion proof for the transaction using bitcoind's merkleblock format.Returns a merkle inclusion proof for the transaction using bitcoind's merkleblock format.
    GET {{ network.val === '' ? '' : '/' + network.val }}/api/tx/:txid/merkle-proofReturns a merkle inclusion proof for the transaction using Electrum's blockchain.transaction.get_merkle format.Returns a merkle inclusion proof for the transaction using Electrum's blockchain.transaction.get_merkle format.
    GET {{ network.val === '' ? '' : '/' + network.val }}/api/tx/:txid/outspend/:voutReturns the spending status of a transaction output. Available fields: spent (boolean), txid (optional), vin (optional), and status (optional, the status of the spending tx).Returns the spending status of a transaction output. Available fields: spent (boolean), txid (optional), vin (optional), and status (optional, the status of the spending tx).
    GET {{ network.val === '' ? '' : '/' + network.val }}/api/tx/:txid/outspendsReturns the spending status of all transaction outputs.Returns the spending status of all transaction outputs.
    POST {{ network.val === '' ? '' : '/' + network.val }}/api/txBroadcast a raw transaction to the network. The transaction should be provided as hex in the request body. The txid will be returned on success.Broadcast a raw transaction to the network. The transaction should be provided as hex in the request body. The txid will be returned on success.
    @@ -176,33 +176,33 @@
  • - Addresses + Addresses - - + + - + - - + - + - +
    EndpointDescriptionEndpointDescription
    GET {{ network.val === '' ? '' : '/' + network.val }}/api/address/:addressReturns details about an address. Available fields: address, chain_stats, and mempool_stats. {{ '{' }}chain,mempool{{ '}' }}_stats each contain an object with tx_count, funded_txo_count, funded_txo_sum, spent_txo_count, and spent_txo_sum.Returns details about an address. Available fields: address, chain_stats, and mempool_stats. {{ '{' }}chain,mempool{{ '}' }}_stats each contain an object with tx_count, funded_txo_count, funded_txo_sum, spent_txo_count, and spent_txo_sum.
    GET {{ network.val === '' ? '' : '/' + network.val }}/api/address/:address/txsGet transaction history for the specified address/scripthash, sorted with newest first. Returns up to 50 mempool transactions plus the first 25 confirmed transactions. You can request more confirmed transactions using :last_seen_txid (see below). + Get transaction history for the specified address/scripthash, sorted with newest first. Returns up to 50 mempool transactions plus the first 25 confirmed transactions. You can request more confirmed transactions using :last_seen_txid (see below).
    GET {{ network.val === '' ? '' : '/' + network.val }}/api/address/:address/txs/chainGet confirmed transaction history for the specified address/scripthash, sorted with newest first. Returns 25 transactions per page. More can be requested by specifying the last txid seen by the previous query.Get confirmed transaction history for the specified address/scripthash, sorted with newest first. Returns 25 transactions per page. More can be requested by specifying the last txid seen by the previous query.
    GET {{ network.val === '' ? '' : '/' + network.val }}/api/address/:address/txs/mempoolGet unconfirmed transaction history for the specified address/scripthash. Returns up to 50 transactions (no paging).Get unconfirmed transaction history for the specified address/scripthash. Returns up to 50 transactions (no paging).
    GET {{ network.val === '' ? '' : '/' + network.val }}/api/address/:address/utxoGet the list of unspent transaction outputs associated with the address/scripthash. Available fields: txid, vout, value, and status (with the status of the funding tx).There is also a valuecommitment field that may appear in place of value, plus the following additional fields: asset/assetcommitment, nonce/noncecommitment, surjection_proof, and range_proof.Get the list of unspent transaction outputs associated with the address/scripthash. Available fields: txid, vout, value, and status (with the status of the funding tx).There is also a valuecommitment field that may appear in place of value, plus the following additional fields: asset/assetcommitment, nonce/noncecommitment, surjection_proof, and range_proof.
    @@ -210,66 +210,66 @@
  • - Assets + Assets - - + + - + - + - +
    EndpointDescriptionEndpointDescription
    GET /liquid/api/asset/:asset_idReturns information about a Liquid asset.Returns information about a Liquid asset.
    GET /liquid/api/asset/:asset_id/txs[/mempool|/chain]Returns transactions associated with the specified Liquid asset. For the network's native asset, returns a list of peg in, peg out, and burn transactions. For user-issued assets, returns a list of issuance, reissuance, and burn transactions. Does not include regular transactions transferring this asset.Returns transactions associated with the specified Liquid asset. For the network's native asset, returns a list of peg in, peg out, and burn transactions. For user-issued assets, returns a list of issuance, reissuance, and burn transactions. Does not include regular transactions transferring this asset.
    GET /liquid/api/asset/:asset_id/supply[/decimal]Get the current total supply of the specified asset. For the native asset (L-BTC), this is calculated as [chain,mempool]_stats.peg_in_amount - [chain,mempool]_stats.peg_out_amount - [chain,mempool]_stats.burned_amount. For issued assets, this is calculated as [chain,mempool]_stats.issued_amount - [chain,mempool]_stats.burned_amount. Not available for assets with blinded issuances. If /decimal is specified, returns the supply as a decimal according to the asset's divisibility. Otherwise, returned in base units.Get the current total supply of the specified asset. For the native asset (L-BTC), this is calculated as [chain,mempool]_stats.peg_in_amount - [chain,mempool]_stats.peg_out_amount - [chain,mempool]_stats.burned_amount. For issued assets, this is calculated as [chain,mempool]_stats.issued_amount - [chain,mempool]_stats.burned_amount. Not available for assets with blinded issuances. If /decimal is specified, returns the supply as a decimal according to the asset's divisibility. Otherwise, returned in base units.
  • - BSQ + BSQ - - + + - + - + - + - + - + - + - +
    EndpointDescriptionEndpointDescription
    GET /bisq/api/statsReturns statistics about all Bisq transactions.Returns statistics about all Bisq transactions.
    GET /bisq/api/tx/:txidReturns details about a Bisq transaction.Returns details about a Bisq transaction.
    GET /bisq/api/txs/:index/:lengthReturns :length of latest Bisq transactions, starting from :index.Returns :length of latest Bisq transactions, starting from :index.
    GET /bisq/api/block/:hashReturns all Bisq transactions that exist in a Bitcoin block.Returns all Bisq transactions that exist in a Bitcoin block.
    GET /bisq/api/blocks/:index/:lengthReturns :length Bitcoin blocks that contain Bisq transactions, starting from :index.Returns :length Bitcoin blocks that contain Bisq transactions, starting from :index.
    GET /bisq/api/blocks/tip/heightReturns the most recently processed Bitcoin block height processed by Bisq.Returns the most recently processed Bitcoin block height processed by Bisq.
    GET /bisq/api/address/:addressReturns all Bisq transactions belonging to a Bitcoin address, with 'B' prefixed in front of the address.Returns all Bisq transactions belonging to a Bitcoin address, with 'B' prefixed in front of the address.
    @@ -281,7 +281,7 @@
  • diff --git a/frontend/src/app/components/asset/asset.component.html b/frontend/src/app/components/asset/asset.component.html index 7f8703f72..e004c8be9 100644 --- a/frontend/src/app/components/asset/asset.component.html +++ b/frontend/src/app/components/asset/asset.component.html @@ -17,19 +17,19 @@ - + - + - + - + @@ -40,27 +40,27 @@
    NameName {{ assetContract[2] }} ({{ assetContract[1] }})
    PrecisionPrecision {{ assetContract[3] }}
    IssuerIssuer {{ assetContract[0] }}
    Issuance txIssuance TX {{ asset.issuance_txin.txid | shortenString : 13 }}
    - + - + - + - + - + - + @@ -129,7 +129,7 @@
    - Error loading asset data. + Error loading asset data.
    {{ error.error }}
    @@ -140,5 +140,5 @@
    -
    + diff --git a/frontend/src/app/components/block/block.component.html b/frontend/src/app/components/block/block.component.html index 7c93bad8b..194b6622f 100644 --- a/frontend/src/app/components/block/block.component.html +++ b/frontend/src/app/components/block/block.component.html @@ -1,7 +1,7 @@
    -

    Genesis Block {{ blockHeight }}

    +

    Genesis Block {{ blockHeight }}

    @@ -15,24 +15,24 @@
    Pegged inPegged in {{ formatAmount(asset.chain_stats.peg_in_amount, assetContract[3]) | number: '1.0-' + assetContract[3] }} {{ assetContract[1] }}
    Pegged outPegged out {{ formatAmount(asset.chain_stats.peg_out_amount, assetContract[3]) | number: '1.0-' + assetContract[3] }} {{ assetContract[1] }}
    Issued amountIssued amount {{ formatAmount(asset.chain_stats.issued_amount, assetContract[3]) | number: '1.0-' + assetContract[3] }} {{ assetContract[1] }}
    Burned amountBurned amount {{ formatAmount(asset.chain_stats.burned_amount, assetContract[3]) | number: '1.0-' + assetContract[3] }} {{ assetContract[1] }}
    Circulating amountCirculating amount {{ formatAmount(asset.chain_stats.issued_amount - asset.chain_stats.burned_amount, assetContract[3]) | number: '1.0-' + assetContract[3] }} {{ assetContract[1] }}
    Circulating amountCirculating amount {{ formatAmount(asset.chain_stats.peg_in_amount - asset.chain_stats.burned_amount - asset.chain_stats.peg_out_amount, assetContract[3]) | number: '1.0-' + assetContract[3] }} {{ assetContract[1] }}
    ConfidentialConfidential
    - + - + - + - + @@ -42,19 +42,19 @@
    HashHash {{ block.id | shortenString : 13 }}
    TimestampTimestamp {{ block.timestamp * 1000 | date:'yyyy-MM-dd HH:mm' }}
    - ( ago) + ()
    SizeSize {{ block.size | bytes: 2 }}
    WeightWeight {{ block.weight | wuBytes: 2 }}
    - - + + - + - + @@ -62,16 +62,16 @@ - + - + - + @@ -82,7 +82,7 @@
    -

    {{ block.tx_count | number }} transactions

    +

    {{ block.tx_count | number }} transactiontransactions

    @@ -162,7 +162,7 @@
    - Error loading block data. + Error loading block data.

    {{ error.error }}
    diff --git a/frontend/src/app/components/blockchain-blocks/blockchain-blocks.component.html b/frontend/src/app/components/blockchain-blocks/blockchain-blocks.component.html index 1df5c56e5..a6ee77c48 100644 --- a/frontend/src/app/components/blockchain-blocks/blockchain-blocks.component.html +++ b/frontend/src/app/components/blockchain-blocks/blockchain-blocks.component.html @@ -7,14 +7,14 @@
    - ~{{ block.medianFee | number:'1.0-0' }} sat/vB + ~{{ block.medianFee | number:'1.0-0' }} sat/vB
    - {{ block.feeRange[1] | number:'1.0-0' }} - {{ block.feeRange[block.feeRange.length - 1] | number:'1.0-0' }} sat/vB + {{ block.feeRange[1] | number:'1.0-0' }} - {{ block.feeRange[block.feeRange.length - 1] | number:'1.0-0' }} sat/vB
    {{ block.size | bytes: 2 }}
    -
    {{ block.tx_count | number }} transactions
    -
    ago
    +
    {{ block.tx_count | number }} transactiontransactions
    +
    diff --git a/frontend/src/app/components/blockchain/blockchain.component.html b/frontend/src/app/components/blockchain/blockchain.component.html index 7bfd20bc8..db0b44e6f 100644 --- a/frontend/src/app/components/blockchain/blockchain.component.html +++ b/frontend/src/app/components/blockchain/blockchain.component.html @@ -8,7 +8,7 @@
    -

    Waiting for blocks...

    +

    Waiting for blocks...

    diff --git a/frontend/src/app/components/clipboard/clipboard.component.html b/frontend/src/app/components/clipboard/clipboard.component.html index 7e7685607..3ee729ebc 100644 --- a/frontend/src/app/components/clipboard/clipboard.component.html +++ b/frontend/src/app/components/clipboard/clipboard.component.html @@ -2,4 +2,4 @@ - \ No newline at end of file + diff --git a/frontend/src/app/components/fees-box/fees-box.component.html b/frontend/src/app/components/fees-box/fees-box.component.html index f9db6d404..5fd3d3198 100644 --- a/frontend/src/app/components/fees-box/fees-box.component.html +++ b/frontend/src/app/components/fees-box/fees-box.component.html @@ -1,21 +1,21 @@
    Median fee~{{ block.medianFee | number:'1.0-0' }} sat/vB ()Median fee~{{ block.medianFee | number:'1.0-0' }} sat/vB ()
    Total feesTotal fees () {{ fees * 100000000 | number }} L-sat ()
    Subsidy + fees:Subsidy + fees: ()
    Total feesTotal fees
    Subsidy + fees:Subsidy + fees:
    MinerMiner
    @@ -24,15 +24,15 @@ diff --git a/frontend/src/app/components/footer/footer.component.html b/frontend/src/app/components/footer/footer.component.html index 0069d218f..47ec84d89 100644 --- a/frontend/src/app/components/footer/footer.component.html +++ b/frontend/src/app/components/footer/footer.component.html @@ -2,22 +2,22 @@
    - Tx vBytes per second: + Tx vBytes per second: -  Backend is synchronizing +  Backend is synchronizing
    -
    {{ mempoolInfoData.vBytesPerSecond | ceil | number }} vBytes/s
    +
    {{ mempoolInfoData.vBytesPerSecond | ceil | number }} vBytes/s
    - Unconfirmed transactions: + Unconfirmed transactions:
    {{ mempoolInfoData.memPoolInfo.size | number }}
    - Mempool size: + Mempool size:
    {{ mempoolBlocksData.size | bytes }} ({{ mempoolBlocksData.blocks }} blocks)
    diff --git a/frontend/src/app/components/latest-blocks/latest-blocks.component.html b/frontend/src/app/components/latest-blocks/latest-blocks.component.html index e6cafe69d..4a2032c41 100644 --- a/frontend/src/app/components/latest-blocks/latest-blocks.component.html +++ b/frontend/src/app/components/latest-blocks/latest-blocks.component.html @@ -6,17 +6,17 @@
    -
    Low priority
    +
    Low priority

    - {{ feeEstimations.hourFee }} sat/vB () + {{ feeEstimations.hourFee }} sat/vB ()

    -
    Medium priority
    +
    Medium priority

    - {{ feeEstimations.halfHourFee }} sat/vB () + {{ feeEstimations.halfHourFee }} sat/vB ()

    -
    High priority
    +
    High priority

    - {{ feeEstimations.fastestFee }} sat/vB () + {{ feeEstimations.fastestFee }} sat/vB ()

    -
    Low priority
    +
    Low priority

    -
    Medium priority
    +
    Medium priority

    -
    High priority
    +
    High priority

    - - - - - + + + + + - +
    HeightTimestampMinedTransactionsFilledHeightTimestampMinedTransactionsFilled
    {{ block.height }} {{ block.timestamp * 1000 | date:'yyyy-MM-dd HH:mm' }} ago {{ block.tx_count | number }}
    diff --git a/frontend/src/app/components/master-page/master-page.component.html b/frontend/src/app/components/master-page/master-page.component.html index 80ecd9e96..15e6ec3e5 100644 --- a/frontend/src/app/components/master-page/master-page.component.html +++ b/frontend/src/app/components/master-page/master-page.component.html @@ -4,8 +4,8 @@ -
    Offline
    -
    Reconnecting...
    +
    Offline
    +
    Reconnecting...
    @@ -16,7 +16,7 @@
    - +
    diff --git a/frontend/src/app/components/mempool-block/mempool-block.component.html b/frontend/src/app/components/mempool-block/mempool-block.component.html index 2c98e5bba..dee0f4c19 100644 --- a/frontend/src/app/components/mempool-block/mempool-block.component.html +++ b/frontend/src/app/components/mempool-block/mempool-block.component.html @@ -13,23 +13,23 @@ - + - + - + - + - +
    Median feeMedian fee ~{{ mempoolBlock.medianFee | number:'1.0-0' }} sat/vB ()
    Fee spanFee span {{ mempoolBlock.feeRange[0] | number:'1.0-0' }} - {{ mempoolBlock.feeRange[mempoolBlock.feeRange.length - 1] | number:'1.0-0' }} sat/vB
    Total feesTotal fees ()
    TransactionsTransactions {{ mempoolBlock.nTx }}
    FilledFilled
    @@ -48,4 +48,4 @@
    -
    \ No newline at end of file + diff --git a/frontend/src/app/components/mempool-blocks/mempool-blocks.component.html b/frontend/src/app/components/mempool-blocks/mempool-blocks.component.html index 5b740c7c4..0d6882ba5 100644 --- a/frontend/src/app/components/mempool-blocks/mempool-blocks.component.html +++ b/frontend/src/app/components/mempool-blocks/mempool-blocks.component.html @@ -5,23 +5,23 @@  
    - ~{{ projectedBlock.medianFee | number:'1.0-0' }} sat/vB + ~{{ projectedBlock.medianFee | number:'1.0-0' }} sat/vB
    - {{ projectedBlock.feeRange[0] | number:'1.0-0' }} - {{ projectedBlock.feeRange[projectedBlock.feeRange.length - 1] | number:'1.0-0' }} sat/vB + {{ projectedBlock.feeRange[0] | number:'1.0-0' }} - {{ projectedBlock.feeRange[projectedBlock.feeRange.length - 1] | number:'1.0-0' }} sat/vB
    {{ projectedBlock.blockSize | bytes: 2 }}
    -
    {{ projectedBlock.nTx | number }} transactions
    +
    {{ projectedBlock.nTx | number }} transactiontransactions
    - In < {{ 1 * i + 1 }} minute + In < {{ 1 * i + 1 }} minute - In ~{{ 10 * i + 10 }} minutes + In ~{{ 10 * i + 10 }} minutes
    -
    ({{ projectedBlock.blockVSize / 1000000 | ceil }} blocks)
    +
    ({{ projectedBlock.blockVSize / 1000000 | ceil }} blocks)
    diff --git a/frontend/src/app/components/miner/miner.component.html b/frontend/src/app/components/miner/miner.component.html index a214c1339..4a54fb4d0 100644 --- a/frontend/src/app/components/miner/miner.component.html +++ b/frontend/src/app/components/miner/miner.component.html @@ -7,6 +7,6 @@ {{ miner }} - Unknown + Unknown diff --git a/frontend/src/app/components/search-form/search-form.component.html b/frontend/src/app/components/search-form/search-form.component.html index f71ac0ec1..c16374917 100644 --- a/frontend/src/app/components/search-form/search-form.component.html +++ b/frontend/src/app/components/search-form/search-form.component.html @@ -1,10 +1,10 @@
    - +
    -
    \ No newline at end of file + diff --git a/frontend/src/app/components/statistics/statistics.component.html b/frontend/src/app/components/statistics/statistics.component.html index bc970fbeb..872b48e06 100644 --- a/frontend/src/app/components/statistics/statistics.component.html +++ b/frontend/src/app/components/statistics/statistics.component.html @@ -3,7 +3,7 @@
    -

    Loading graphs...

    +

    Loading graphs...


    @@ -13,7 +13,7 @@
    - Mempool by vBytes (sat/vByte) + Mempool by vBytes (sat/vByte)
    @@ -54,7 +54,8 @@
    - Transaction vBytes per second (vB/s)
    + Transaction vBytes per second (vB/s) +
    -
    \ No newline at end of file +
    diff --git a/frontend/src/app/components/time-since/time-since.component.ts b/frontend/src/app/components/time-since/time-since.component.ts index 1f4867f73..aa870e842 100644 --- a/frontend/src/app/components/time-since/time-since.component.ts +++ b/frontend/src/app/components/time-since/time-since.component.ts @@ -16,17 +16,6 @@ export class TimeSinceComponent implements OnInit, OnChanges, OnDestroy { constructor( private ref: ChangeDetectorRef ) { - if (document.body.clientWidth < 768) { - this.intervals = { - year: 31536000, - month: 2592000, - week: 604800, - day: 86400, - hour: 3600, - min: 60, - sec: 1 - }; - } else { this.intervals = { year: 31536000, month: 2592000, @@ -36,7 +25,6 @@ export class TimeSinceComponent implements OnInit, OnChanges, OnDestroy { minute: 60, second: 1 }; - } } ngOnInit() { @@ -58,7 +46,7 @@ export class TimeSinceComponent implements OnInit, OnChanges, OnDestroy { calculate() { const seconds = Math.floor((+new Date() - +new Date(this.time * 1000)) / 1000); if (seconds < 60) { - return '< 1 minute'; + return $localize`:@@time-since.just-now:Just now`; } let counter; for (const i in this.intervals) { @@ -66,9 +54,41 @@ export class TimeSinceComponent implements OnInit, OnChanges, OnDestroy { counter = Math.floor(seconds / this.intervals[i]); if (counter > 0) { if (counter === 1) { - return counter + ' ' + i; // singular (1 day ago) + switch (i) { // singular (1 day ago) + case 'year': return $localize`:@@time-since.year.ago:${counter}:INTERPOLATION: year ago`; break; + case 'month': return $localize`:@@time-since.month.ago:${counter}:INTERPOLATION: month ago`; break; + case 'week': return $localize`:@@time-since.week.ago:${counter}:INTERPOLATION: week ago`; break; + case 'day': return $localize`:@@time-since.day.ago:${counter}:INTERPOLATION: day ago`; break; + case 'hour': return $localize`:@@time-since.hour.ago:${counter}:INTERPOLATION: hour ago`; break; + case 'minute': + if (document.body.clientWidth < 768) { + return $localize`:@@time-since.min.ago:${counter}:INTERPOLATION: min ago`; + } + return $localize`:@@time-since.minute.ago:${counter}:INTERPOLATION: minute ago`; + case 'second': + if (document.body.clientWidth < 768) { + return $localize`:@@time-since.sec.ago:${counter}:INTERPOLATION: sec ago`; + } + return $localize`:@@time-since.second.ago:${counter}:INTERPOLATION: second ago`; + } } else { - return counter + ' ' + i + 's'; // plural (2 days ago) + switch (i) { // plural (2 days ago) + case 'year': return $localize`:@@time-since.years.ago:${counter}:INTERPOLATION: years ago`; break; + case 'month': return $localize`:@@time-since.months.ago:${counter}:INTERPOLATION: months ago`; break; + case 'week': return $localize`:@@time-since.weeks.ago:${counter}:INTERPOLATION: weeks ago`; break; + case 'day': return $localize`:@@time-since.days.ago:${counter}:INTERPOLATION: days ago`; break; + case 'hour': return $localize`:@@time-since.hours.ago:${counter}:INTERPOLATION: hours ago`; break; + case 'minute': + if (document.body.clientWidth < 768) { + return $localize`:@@time-since.mins.ago:${counter}:INTERPOLATION: mins ago`; + } + return $localize`:@@time-since.minutes.ago:${counter}:INTERPOLATION: minutes ago`; + case 'second': + if (document.body.clientWidth < 768) { + return $localize`:@@time-since.secs.ago:${counter}:INTERPOLATION: secs ago`; + } + return $localize`:@@time-since.seconds.ago:${counter}:INTERPOLATION: seconds ago`; + } } } } diff --git a/frontend/src/app/components/transaction/transaction.component.html b/frontend/src/app/components/transaction/transaction.component.html index 95369a2fe..9e40dbe5d 100644 --- a/frontend/src/app/components/transaction/transaction.component.html +++ b/frontend/src/app/components/transaction/transaction.component.html @@ -2,20 +2,20 @@
    -

    Transaction

    +

    Transaction

    - + - +
    @@ -39,28 +39,28 @@ - + - + - - + + - + @@ -72,13 +72,13 @@
    TimestampTimestamp {{ tx.status.block_time * 1000 | date:'yyyy-MM-dd HH:mm' }}
    - ( ago) + ()
    Included in blockIncluded in block {{ tx.status.block_height }}
    ConfirmedAfter ConfirmedAfter
    FeaturesFeatures
    - + - + @@ -106,35 +106,35 @@ - - + + - + - + @@ -146,12 +146,12 @@
    FeeFee {{ tx.fee | number }} sat ()
    Fee per vByteFee per vByte - {{ tx.fee / (tx.weight / 4) | number : '1.1-1' }} sat/vB + {{ tx.fee / (tx.weight / 4) | number : '1.1-1' }} sat/vB  
    First seen agoFirst seen
    ETAETA - In several hours (or more) + In several hours (or more) - < {{ 1 * txInBlockIndex + 1 }} minutes ({{ txInBlockIndex + 1 }} block{{ txInBlockIndex > 0 ? 's' : '' }}) + < {{ 1 * txInBlockIndex + 1 }} minutes ({{ txInBlockIndex + 1 }} block{{ txInBlockIndex > 0 ? 's' : '' }}) - ~{{ 10 * txInBlockIndex + 10 }} minutes ({{ txInBlockIndex + 1 }} block{{ txInBlockIndex > 0 ? 's' : '' }}) + ~{{ 10 * txInBlockIndex + 10 }} minutes ({{ txInBlockIndex + 1 }} block{{ txInBlockIndex > 0 ? 's' : '' }})
    FeaturesFeatures
    - - + + - - + +
    Fee{{ tx.fee | number }} sat ()Fee{{ tx.fee | number }} sat ()
    Fee per vByte{{ tx.fee / (tx.weight / 4) | number : '1.1-1' }} sat/vBFee per vByte{{ tx.fee / (tx.weight / 4) | number : '1.1-1' }} sat/vB
    @@ -162,24 +162,24 @@
    -

    Inputs & Outputs

    +

    Inputs & Outputs

    - +
    -

    Details

    +

    Details

    - + - + @@ -263,8 +263,8 @@
    -

    Transaction not found.

    -
    Waiting for it to appear in the mempool...
    +

    Transaction not found.

    +
    Waiting for it to appear in the mempool...
    diff --git a/frontend/src/app/components/transactions-list/transactions-list.component.html b/frontend/src/app/components/transactions-list/transactions-list.component.html index bf248e301..0db4eec8b 100644 --- a/frontend/src/app/components/transactions-list/transactions-list.component.html +++ b/frontend/src/app/components/transactions-list/transactions-list.component.html @@ -7,7 +7,7 @@
    {{ tx.status.block_time * 1000 | date:'yyyy-MM-dd HH:mm' }} - ago +
    @@ -36,9 +36,9 @@
    - + - + - + - + - + - + - + @@ -103,7 +103,7 @@ @@ -122,7 +122,8 @@ - Peg-out to + Peg-out to + {{ vout.pegout.scriptpubkey_address | shortenString : 16 }} {{ vout.pegout.scriptpubkey_address | shortenString : 35 }} @@ -160,19 +161,19 @@
    SizeSize {{ tx.size | bytes: 2 }}
    WeightWeight {{ tx.weight | wuBytes: 2 }}
    - Coinbase (Newly Generated Coins)
    {{ vin.scriptsig | hex2ascii }}
    + Coinbase (Newly Generated Coins)
    {{ vin.scriptsig | hex2ascii }}
    - Peg-in + Peg-in @@ -68,32 +68,32 @@
    ScriptSig (ASM)ScriptSig (ASM)
    ScriptSig (HEX)ScriptSig (HEX) {{ vin.scriptsig }}
    WitnessWitness {{ vin.witness.join(' ') }}
    P2SH redeem scriptP2SH redeem script
    P2WSH witness scriptP2WSH witness script
    nSequencenSequence {{ formatHex(vin.sequence) }}
    Previous output scriptPrevious output script {{ vin.prevout.scriptpubkey_type ? ('(' + vin.prevout.scriptpubkey_type + ')') : '' }}"
    - +
    - + - + - + - + @@ -182,7 +183,7 @@ @@ -192,19 +193,19 @@
    - {{ tx.fee / (tx.weight / 4) | number : '1.1-1' }} sat/vB – {{ tx.fee | number }} sat () + {{ tx.fee / (tx.weight / 4) | number : '1.1-1' }} sat/vB  – {{ tx.fee | number }} sat ()
    - + - +  
    TypeType {{ vout.scriptpubkey_type.toUpperCase() }}
    scriptPubKey (ASM)ScriptPubKey (ASM)
    scriptPubKey (HEX)ScriptPubKey (HEX) {{ vout.scriptpubkey }}
    OP_RETURN dataOP_RETURN data {{ vout.scriptpubkey_asm | hex2ascii }}
    - +
    - - - - + + + + - +
    HeightMinedTxsFilledHeightMinedTXsSize
    {{ block.height }} ago {{ block.tx_count | number }}
    @@ -94,27 +94,27 @@
    - +
    -
    Latest transactions
    +
    Latest transactions
    - - - - + + + + - +
    TXIDAmountUSDFeeTXIDAmountUSDFee
    {{ transaction.txid | shortenString : 10 }} {{ transaction.fee / (transaction.weight / 4) | number : '1.1-1' }} sat/vB{{ transaction.fee / (transaction.weight / 4) | number : '1.1-1' }} sat/vB
    @@ -133,8 +133,14 @@
    +
    + +
    +
    @@ -153,15 +159,15 @@ @@ -169,14 +175,14 @@ -
    Incoming transactions
    +
    Incoming transactions
    -  Backend is synchronizing +  Backend is synchronizing
    -
    {{ mempoolInfoData.value.vBytesPerSecond | ceil | number }} vB/s
    +
    {{ mempoolInfoData.value.vBytesPerSecond | ceil | number }} vB/s
    @@ -185,7 +191,7 @@
    -
    Difficulty adjustment
    +
    Difficulty adjustment
    +{{ epochData.change | number: '1.0-2' }}%
    @@ -193,4 +199,4 @@
    -
    \ No newline at end of file +
    diff --git a/frontend/src/app/dashboard/dashboard.component.ts b/frontend/src/app/dashboard/dashboard.component.ts index 879fc4262..a0ffc82d1 100644 --- a/frontend/src/app/dashboard/dashboard.component.ts +++ b/frontend/src/app/dashboard/dashboard.component.ts @@ -7,10 +7,12 @@ import { MempoolInfo, TransactionStripped } from '../interfaces/websocket.interf import { ApiService } from '../services/api.service'; import { StateService } from '../services/state.service'; import * as Chartist from '@mempool/chartist'; -import { formatDate } from '@angular/common'; +import { DOCUMENT, formatDate } from '@angular/common'; import { WebsocketService } from '../services/websocket.service'; import { SeoService } from '../services/seo.service'; import { StorageService } from '../services/storage.service'; +import { FormBuilder, FormGroup } from '@angular/forms'; +import { languages, Language } from '../app.constants'; interface MempoolBlocksData { blocks: number; @@ -55,6 +57,8 @@ export class DashboardComponent implements OnInit { mempoolTransactionsWeightPerSecondData: any; mempoolStats$: Observable; transactionsWeightPerSecondOptions: any; + languageForm: FormGroup; + languages: Language[]; constructor( @Inject(LOCALE_ID) private locale: string, @@ -63,14 +67,22 @@ export class DashboardComponent implements OnInit { private websocketService: WebsocketService, private seoService: SeoService, private storageService: StorageService, + private formBuilder: FormBuilder, + @Inject(DOCUMENT) private document: Document ) { } ngOnInit(): void { + this.languages = languages; this.seoService.resetTitle(); this.websocketService.want(['blocks', 'stats', 'mempool-blocks', 'live-2h-chart']); this.network$ = merge(of(''), this.stateService.networkChanged$); this.collapseLevel = this.storageService.getValue('dashboard-collapsed') || 'one'; + this.languageForm = this.formBuilder.group({ + language: [''] + }); + this.setLanguageFromUrl(); + this.mempoolInfoData$ = combineLatest([ this.stateService.mempoolInfo$, this.stateService.vbytesPerSecond$ @@ -232,4 +244,21 @@ export class DashboardComponent implements OnInit { } this.storageService.setValue('dashboard-collapsed', this.collapseLevel); } + + setLanguageFromUrl() { + const urlLanguage = this.document.location.pathname.split('/')[1]; + if (urlLanguage === '') { + this.languageForm.get('language').setValue('en'); + } else if (this.languages.map((lang) => lang.code).indexOf(urlLanguage) > -1) { + this.languageForm.get('language').setValue(urlLanguage); + } + } + + changeLanguage() { + const language = this.languageForm.get('language').value; + this.document.location.href = (language === 'en' ? '/' : '/' + language); + try { + document.cookie = `lang=${language}; expires=Thu, 18 Dec 2050 12:00:00 UTC; path=/`; + } catch (e) { } + } } diff --git a/frontend/src/index.html b/frontend/src/index.html index c0f30f182..0908fb07e 100644 --- a/frontend/src/index.html +++ b/frontend/src/index.html @@ -33,8 +33,8 @@
    -
    Mempool size
    +
    Mempool size

    - {{ mempoolBlocksData.size | bytes }} ({{ mempoolBlocksData.blocks }} blocks) + {{ mempoolBlocksData.size | bytes }} ({{ mempoolBlocksData.blocks }} blockblocks)

    -
    Unconfirmed
    +
    Unconfirmed

    - {{ mempoolInfoData.value.memPoolInfo.size | number }} TXs + {{ mempoolInfoData.value.memPoolInfo.size | number }} TXs