diff --git a/client/src/components/elapsed-time.js b/client/src/components/elapsed-time.js
index 1ba42fa3..f0f1bbe9 100644
--- a/client/src/components/elapsed-time.js
+++ b/client/src/components/elapsed-time.js
@@ -3,7 +3,18 @@ const MINUTES_PER_DAY = 24 * 60;
const MINUTES_PER_YEAR = 365 * MINUTES_PER_DAY;
const MINUTES_PER_MONTH = MINUTES_PER_YEAR / 12;
-export const formatDuration = (durationMilliseconds, compact = false) => {
+const passthrough = (parts, ...values) =>
+ parts.reduce(
+ (result, part, index) =>
+ result + part + (index < values.length ? values[index] : ""),
+ "",
+ );
+
+export const formatDuration = (
+ durationMilliseconds,
+ compact = false,
+ t = passthrough,
+) => {
const diffMinutes = Math.max(
0,
Math.floor(durationMilliseconds / UPDATE_INTERVAL_MS),
@@ -15,16 +26,16 @@ export const formatDuration = (durationMilliseconds, compact = false) => {
minutesAfterYears - months * MINUTES_PER_MONTH,
);
const units = [
- ["YEAR", "YEARS", "y", years],
- ["MONTH", "MONTHS", "mo", months],
- ["DAY", "DAYS", "d", Math.floor(minutesAfterMonths / MINUTES_PER_DAY)],
+ [t`YEAR`, t`YEARS`, t`y`, years],
+ [t`MONTH`, t`MONTHS`, t`mo`, months],
+ [t`DAY`, t`DAYS`, t`d`, Math.floor(minutesAfterMonths / MINUTES_PER_DAY)],
[
- "HOUR",
- "HOURS",
- "h",
+ t`HOUR`,
+ t`HOURS`,
+ t`h`,
Math.floor((minutesAfterMonths % MINUTES_PER_DAY) / 60),
],
- ["MINUTE", "MINUTES", "m", minutesAfterMonths % 60],
+ [t`MINUTE`, t`MINUTES`, t`m`, minutesAfterMonths % 60],
];
const parts = units
.filter((unit) => unit[3] > 0)
@@ -35,31 +46,33 @@ export const formatDuration = (durationMilliseconds, compact = false) => {
: `${value} ${value === 1 ? singular : plural}`,
);
- if (compact) return parts.length ? parts.join(" ") : "< 1m";
+ if (compact) return parts.length ? parts.join(" ") : t`< 1m`;
- return parts.length ? parts.join(" ") : "< 1 MINUTE";
+ return parts.length ? parts.join(" ") : t`< 1 MINUTE`;
};
-const formatElapsedTime = (timestamp, compact) => {
+const formatElapsedTime = (timestamp, compact, t) => {
const fromDate =
timestamp < 1e12 ? new Date(timestamp * 1000) : new Date(timestamp);
- const duration = formatDuration(new Date() - fromDate, compact);
+ const duration = formatDuration(new Date() - fromDate, compact, t);
if (compact) return duration;
- return `${duration} AGO`;
+ return t`${duration} AGO`;
};
const updateElapsedTime = (element) => {
element.textContent = formatElapsedTime(
element.elapsedTimeTimestamp,
element.elapsedTimeCompact,
+ element.elapsedTimeTranslator,
);
};
-const startElapsedTime = (vnode, timestamp, compact) => {
+const startElapsedTime = (vnode, timestamp, compact, t) => {
vnode.elm.elapsedTimeTimestamp = timestamp;
vnode.elm.elapsedTimeCompact = compact;
+ vnode.elm.elapsedTimeTranslator = t;
updateElapsedTime(vnode.elm);
vnode.elm.elapsedTimeInterval = window.setInterval(
() => updateElapsedTime(vnode.elm),
@@ -67,9 +80,10 @@ const startElapsedTime = (vnode, timestamp, compact) => {
);
};
-const patchElapsedTime = (_, vnode, timestamp, compact) => {
+const patchElapsedTime = (_, vnode, timestamp, compact, t) => {
vnode.elm.elapsedTimeTimestamp = timestamp;
vnode.elm.elapsedTimeCompact = compact;
+ vnode.elm.elapsedTimeTranslator = t;
updateElapsedTime(vnode.elm);
};
@@ -77,14 +91,18 @@ const stopElapsedTime = (vnode) => {
window.clearInterval(vnode.elm.elapsedTimeInterval);
};
-export const ElapsedTime = ({ timestamp, compact = false } = {}) => (
+export const ElapsedTime = ({
+ timestamp,
+ compact = false,
+ t = passthrough,
+} = {}) => (
startElapsedTime(vnode, timestamp, compact)}
+ hook-insert={(vnode) => startElapsedTime(vnode, timestamp, compact, t)}
hook-postpatch={(oldVnode, vnode) =>
- patchElapsedTime(oldVnode, vnode, timestamp, compact)
+ patchElapsedTime(oldVnode, vnode, timestamp, compact, t)
}
hook-destroy={stopElapsedTime}
>
- {formatElapsedTime(timestamp, compact)}
+ {formatElapsedTime(timestamp, compact, t)}
);
diff --git a/client/src/components/high-value-assets.js b/client/src/components/high-value-assets.js
index 845d9660..1b98e6b7 100644
--- a/client/src/components/high-value-assets.js
+++ b/client/src/components/high-value-assets.js
@@ -55,7 +55,7 @@ export const highValueAssets = (t, assetData = {}) => {
{asset.name}
- {formatDollarAmount(dollarAmount)}
+ {formatDollarAmount(dollarAmount, t)}
);
diff --git a/client/src/lib/high-value-assets.js b/client/src/lib/high-value-assets.js
index a6328392..a977c5df 100644
--- a/client/src/lib/high-value-assets.js
+++ b/client/src/lib/high-value-assets.js
@@ -1,4 +1,5 @@
const value = n => n == null ? 0 : Number(n)
+ , passthrough = strings => strings[0]
export const getPriceFeedApiBase = (apiBase, fallbackOrigin) => {
let url
@@ -34,8 +35,8 @@ export const calculateCirculatingDollarAmount = (asset, price) => {
return Number.isFinite(dollarAmount) ? dollarAmount : null
}
-export const formatDollarAmount = amount => {
- if (!Number.isFinite(amount)) return 'N/A'
+export const formatDollarAmount = (amount, t=passthrough) => {
+ if (!Number.isFinite(amount)) return t`N/A`
const units = [
[ 1e12, 'T' ],
diff --git a/client/src/views/blocks.js b/client/src/views/blocks.js
index 81cab206..28afbbe1 100644
--- a/client/src/views/blocks.js
+++ b/client/src/views/blocks.js
@@ -77,7 +77,7 @@ export const blks = (blocks, viewMore, { t, ...S }) => {
@@ -95,12 +95,12 @@ export const blks = (blocks, viewMore, { t, ...S }) => {
className="table-copy-button code-button-btn"
type="button"
data-clipboardCopy={"" + b.height}
- aria-label={`Copy block number ${b.height}`}
+ aria-label={t`Copy block number ${b.height}`}
>
{index === 0 ? (
-
Latest
+
{t`Latest`}
) : (
""
)}
@@ -111,15 +111,15 @@ export const blks = (blocks, viewMore, { t, ...S }) => {
title={new Date(b.timestamp * 1000)}
>
- {formatRelativeTime(b.timestamp)?.toUpperCase()}
+ {formatRelativeTime(b.timestamp, t)?.toUpperCase()}
-
+
@@ -129,7 +129,7 @@ export const blks = (blocks, viewMore, { t, ...S }) => {
diff --git a/client/src/views/difficulty-adjustment.js b/client/src/views/difficulty-adjustment.js
index 0fa6413d..c49f01f3 100644
--- a/client/src/views/difficulty-adjustment.js
+++ b/client/src/views/difficulty-adjustment.js
@@ -8,16 +8,16 @@ const staticRoot = process.env.STATIC_ROOT || "";
const TARGET_BLOCK_SECONDS = 10 * 60;
const HASHES_PER_DIFFICULTY = 2 ** 32;
-const HASHRATE_UNITS = [
- [1e24, "YH/s", "Yottahashes per second"],
- [1e21, "ZH/s", "Zettahashes per second"],
- [1e18, "EH/s", "Exahashes per second"],
- [1e15, "PH/s", "Petahashes per second"],
- [1e12, "TH/s", "Terahashes per second"],
- [1e9, "GH/s", "Gigahashes per second"],
- [1e6, "MH/s", "Megahashes per second"],
- [1e3, "kH/s", "Kilohashes per second"],
- [1, "H/s", "Hashes per second"],
+const getHashrateUnits = (t) => [
+ [1e24, "YH/s", t`Yottahashes per second`],
+ [1e21, "ZH/s", t`Zettahashes per second`],
+ [1e18, "EH/s", t`Exahashes per second`],
+ [1e15, "PH/s", t`Petahashes per second`],
+ [1e12, "TH/s", t`Terahashes per second`],
+ [1e9, "GH/s", t`Gigahashes per second`],
+ [1e6, "MH/s", t`Megahashes per second`],
+ [1e3, "kH/s", t`Kilohashes per second`],
+ [1, "H/s", t`Hashes per second`],
];
const DIFFICULTY_UNITS = [
@@ -29,8 +29,8 @@ const DIFFICULTY_UNITS = [
[1, ""],
];
-const formatAdjustment = (value) => {
- if (!Number.isFinite(value)) return "N/A";
+const formatAdjustment = (value, unavailable) => {
+ if (!Number.isFinite(value)) return unavailable;
if (value === 0) return "0.00%";
return `${value > 0 ? "+" : ""}${value.toFixed(2)}%`;
@@ -100,33 +100,36 @@ const previousAdjustment = (latestBlock, previousBlock) => {
return (latestBlock.difficulty / previousBlock.difficulty - 1) * 100;
};
-const formatBlockTime = (seconds) => {
- if (!Number.isFinite(seconds)) return "N/A";
+const formatBlockTime = (seconds, unavailable, t) => {
+ if (!Number.isFinite(seconds)) return unavailable;
const totalSeconds = Math.max(1, Math.round(seconds));
const minutes = Math.floor(totalSeconds / 60);
const remainingSeconds = totalSeconds % 60;
- if (!minutes) return `${remainingSeconds}s`;
- if (remainingSeconds) return `${minutes}m ${remainingSeconds}s`;
+ if (!minutes) return `${remainingSeconds}${t`s`}`;
+ if (remainingSeconds) {
+ return `${minutes}${t`m`} ${remainingSeconds}${t`s`}`;
+ }
- return `${minutes}m`;
+ return `${minutes}${t`m`}`;
};
-const formatHashrate = (difficulty, averageBlockSeconds) => {
+const formatHashrate = (difficulty, averageBlockSeconds, t, unavailable) => {
if (
!Number.isFinite(difficulty) ||
difficulty < 0 ||
!Number.isFinite(averageBlockSeconds) ||
averageBlockSeconds <= 0
) {
- return { value: "N/A", footer: "Hashes per second" };
+ return { value: unavailable, footer: t`Hashes per second` };
}
const hashrate = (difficulty * HASHES_PER_DIFFICULTY) / averageBlockSeconds;
+ const hashrateUnits = getHashrateUnits(t);
const unit =
- HASHRATE_UNITS.find(([threshold]) => hashrate >= threshold) ||
- HASHRATE_UNITS[HASHRATE_UNITS.length - 1];
+ hashrateUnits.find(([threshold]) => hashrate >= threshold) ||
+ hashrateUnits[hashrateUnits.length - 1];
const [divisor, symbol, footer] = unit;
const value = (hashrate / divisor).toLocaleString("en-US", {
maximumSignificantDigits: 3,
@@ -135,8 +138,8 @@ const formatHashrate = (difficulty, averageBlockSeconds) => {
return { value: `${value} ${symbol}`, footer };
};
-const formatDifficulty = (difficulty) => {
- if (!Number.isFinite(difficulty) || difficulty < 0) return "N/A";
+const formatDifficulty = (difficulty, unavailable) => {
+ if (!Number.isFinite(difficulty) || difficulty < 0) return unavailable;
const unit =
DIFFICULTY_UNITS.find(([threshold]) => difficulty >= threshold) ||
@@ -156,21 +159,21 @@ const formatDifficulty = (difficulty) => {
})}${suffix}`;
};
-const formatAdjustmentDate = (timestamp) => {
- if (!Number.isFinite(timestamp)) return "N/A";
+const formatAdjustmentDate = (timestamp, locale, t, fallback = t`N/A`) => {
+ if (!Number.isFinite(timestamp)) return fallback;
const date = new Date(timestamp * 1000);
- const month = date.toLocaleString("en-US", { month: "long" });
+ const month = date.toLocaleString(locale, { month: "long" });
const day = date.getDate();
const minute = String(date.getMinutes()).padStart(2, "0");
- const period = date.getHours() >= 12 ? "pm" : "am";
+ const period = date.getHours() >= 12 ? t`pm` : t`am`;
const hour = String(date.getHours() % 12 || 12).padStart(2, "0");
return `${month} ${day} - ${hour}:${minute} ${period}`;
};
-const formatTimeUntil = (timestamp) => {
- if (!Number.isFinite(timestamp)) return "N/A";
+const formatTimeUntil = (timestamp, unavailable, t) => {
+ if (!Number.isFinite(timestamp)) return unavailable;
const totalMinutes = Math.max(
0,
@@ -183,13 +186,15 @@ const formatTimeUntil = (timestamp) => {
if (days >= 14) {
const weeks = Math.floor(days / 7);
const remainingDays = days % 7;
- return remainingDays ? `${weeks}w ${remainingDays}d` : `${weeks}w`;
+ return remainingDays
+ ? `${weeks}${t`w`} ${remainingDays}${t`d`}`
+ : `${weeks}${t`w`}`;
}
- if (days) return `${days}d ${hours}h`;
- if (hours) return `${hours}h ${minutes}m`;
+ if (days) return `${days}${t`d`} ${hours}${t`h`}`;
+ if (hours) return `${hours}${t`h`} ${minutes}${t`m`}`;
- return totalMinutes ? `${totalMinutes}m` : "< 1m";
+ return totalMinutes ? `${totalMinutes}${t`m`}` : t`< 1m`;
};
const adjustmentStat = (title, value, className = "") => (
@@ -207,7 +212,9 @@ export default ({
blocks,
dashboardEpochStartBlock,
dashboardPreviousDifficultyBlock,
+ t,
}) => {
+ const unavailable = t`N/A`;
const latestBlock = blocks && blocks[0];
const epochTiming = getEpochTiming(latestBlock, dashboardEpochStartBlock);
const expected = expectedAdjustment(epochTiming);
@@ -217,17 +224,25 @@ export default ({
);
const averageBlockTime = formatBlockTime(
epochTiming && epochTiming.averageBlockSeconds,
+ unavailable,
+ t,
);
const hashrate = formatHashrate(
latestBlock && latestBlock.difficulty,
epochTiming && epochTiming.averageBlockSeconds,
+ t,
+ unavailable,
);
const estimatedAdjustmentTimestamp =
epochTiming && epochTiming.estimatedAdjustmentTimestamp;
- const nextAdjustment = formatTimeUntil(estimatedAdjustmentTimestamp);
+ const nextAdjustment = formatTimeUntil(
+ estimatedAdjustmentTimestamp,
+ unavailable,
+ t,
+ );
const nextAdjustmentFooter = Number.isFinite(estimatedAdjustmentTimestamp)
- ? `Next adj. in ${nextAdjustment}`
- : "Next adjustment unavailable";
+ ? t`Next adj. in ${nextAdjustment}`
+ : t`Next adjustment unavailable`;
return (
@@ -236,33 +251,37 @@ export default ({
-
Difficulty Adjustment
+
{t`Difficulty Adjustment`}
- {adjustmentStat("AVERAGE BLOCK TIME", averageBlockTime)}
+ {adjustmentStat(t`AVERAGE BLOCK TIME`, averageBlockTime)}
{statDivider()}
{adjustmentStat(
- "EXPECTED ADJ",
- formatAdjustment(expected),
+ t`EXPECTED ADJ`,
+ formatAdjustment(expected, unavailable),
adjustmentClass(expected),
)}
{statDivider("difficulty-adjustment-stat-divider-middle")}
{adjustmentStat(
- "PREVIOUS ADJ",
- formatAdjustment(previous),
+ t`PREVIOUS ADJ`,
+ formatAdjustment(previous, unavailable),
adjustmentClass(previous),
)}
{statDivider()}
{adjustmentStat(
- "EXPECTED ADJ DATE",
- formatAdjustmentDate(estimatedAdjustmentTimestamp),
+ t`EXPECTED ADJ DATE`,
+ formatAdjustmentDate(
+ estimatedAdjustmentTimestamp,
+ t.lang_id || "en-US",
+ t,
+ ),
)}
@@ -270,18 +289,21 @@ export default ({
diff --git a/client/src/views/home.js b/client/src/views/home.js
index 826911ce..1da796eb 100644
--- a/client/src/views/home.js
+++ b/client/src/views/home.js
@@ -30,7 +30,7 @@ export const dashBoard = ({ t, blocks, dashboardState, loading, ...S }) => {
{!isBitcoinNetwork ? feeMarket({ t, ...S }) : ""}
{isBitcoinNetwork
- ? difficultyAdjustment({ blocks: dashblocks, ...S })
+ ? difficultyAdjustment({ blocks: dashblocks, t, ...S })
: ""}
{showHighValueAssets ? highValueAssets(t, highValueAssetData) : ""}
,
diff --git a/client/src/views/overview.js b/client/src/views/overview.js
index 3781b09b..596ef063 100644
--- a/client/src/views/overview.js
+++ b/client/src/views/overview.js
@@ -77,13 +77,15 @@ export const overview = ({
}
value={
latestBlock ? (
-
+
) : (
""
)
}
footer={
- latestBlock ? `BLOCK #${latestBlock.height.toLocaleString()}` : ""
+ latestBlock
+ ? t`BLOCK #${latestBlock.height.toLocaleString()}`
+ : ""
}
/>
@@ -118,7 +120,7 @@ export const overview = ({
}
diff --git a/client/src/views/pending-block-details-card.js b/client/src/views/pending-block-details-card.js
index 700b83bc..39bd3a6a 100644
--- a/client/src/views/pending-block-details-card.js
+++ b/client/src/views/pending-block-details-card.js
@@ -539,7 +539,7 @@ const PendingBlockDetailsCard = ({
"time-since-last-block",
t`Time Since Last Block`,
block ? (
-
+
) : (
"-"
),
diff --git a/client/src/views/transactions.js b/client/src/views/transactions.js
index b191098b..6deee79b 100644
--- a/client/src/views/transactions.js
+++ b/client/src/views/transactions.js
@@ -18,15 +18,15 @@ export const transactions = (txs, viewMore, { t, ...S }) => (
- Latest Transactions
+ {t`Latest Transactions`}
-
TRANSACTION ID
-
VALUE
-
SIZE
+
{t`TRANSACTION ID`}
+
{t`VALUE`}
+
{t`SIZE`}
- FEE
+ {t`FEE`}
@@ -46,7 +46,7 @@ export const transactions = (txs, viewMore, { t, ...S }) => (
role="button"
tabindex="0"
data-clipboardCopy={txOverview.txid}
- aria-label={`Copy transaction id ${txOverview.txid}`}
+ aria-label={t`Copy transaction id ${txOverview.txid}`}
>
diff --git a/client/src/views/util.js b/client/src/views/util.js
index d9dd5b0a..ee41ccf6 100644
--- a/client/src/views/util.js
+++ b/client/src/views/util.js
@@ -92,7 +92,18 @@ export const formatNumber = (s, precision=null) => {
return whole + (dec != null ? '.'+dec : '')
}
-export const formatRelativeTime = (fromDate, toDate = new Date()) => {
+export const formatRelativeTime = (fromDate, toDate = new Date(), t) => {
+ if (typeof toDate === 'function') {
+ t = toDate
+ toDate = new Date()
+ }
+
+ t = t || ((parts, ...values) => parts.reduce(
+ (result, part, index) =>
+ result + part + (index < values.length ? values[index] : ''),
+ '',
+ ))
+
if (typeof fromDate === 'number') {
fromDate = fromDate < 1e12
? new Date(fromDate * 1000)
@@ -101,21 +112,27 @@ export const formatRelativeTime = (fromDate, toDate = new Date()) => {
const diffSeconds = Math.floor((toDate - fromDate) / 1000)
- if (diffSeconds < 5) return 'just now'
- if (diffSeconds < 60) return `${diffSeconds} seconds ago`
+ if (diffSeconds < 5) return t`just now`
+ if (diffSeconds < 60) return t`${diffSeconds} seconds ago`
const diffMinutes = Math.floor(diffSeconds / 60)
if (diffMinutes < 60) {
- return diffMinutes === 1 ? '1 minute ago' : `${diffMinutes} minutes ago`
+ return diffMinutes === 1
+ ? t`1 minute ago`
+ : t`${diffMinutes} minutes ago`
}
const diffHours = Math.floor(diffMinutes / 60)
if (diffHours < 24) {
- return diffHours === 1 ? '1 hour ago' : `${diffHours} hours ago`
+ return diffHours === 1
+ ? t`1 hour ago`
+ : t`${diffHours} hours ago`
}
const diffDays = Math.floor(diffHours / 24)
- return diffDays === 1 ? '1 day ago' : `${diffDays} days ago`
+ return diffDays === 1
+ ? t`1 day ago`
+ : t`${diffDays} days ago`
}
export const getBlockPercentageUsed = blockWeight =>
diff --git a/lang/pt-pt.json b/lang/pt-pt.json
index 0087e983..8b27850c 100644
--- a/lang/pt-pt.json
+++ b/lang/pt-pt.json
@@ -4,7 +4,9 @@
"Block %s": "Bloco %0",
"Block #%s: %s": "Bloco #%0: %1",
"Confidential": "Confidencial",
+ "Confirmed": "Confirmada",
"Details": "Detalhes",
+ "Fee": "Taxa",
"Height": "Altura",
"In best chain (%s confirmations)": [
"Na melhor cadeia (1 Confirmação)",
@@ -16,6 +18,7 @@
"Loading...": "Carregando...",
"Load more": "Mais",
"Next": "Próximo",
+ "No recent transactions": "Sem transações recentes",
"No results found": "Nenhum resultado encontrado",
"Page Not Found": "Página Não Encontrada",
"Previous": "Anterior",
@@ -24,6 +27,7 @@
"%0 Confirmações"
],
"Search for block height, hash, transaction, or address": "Pesquise por altura do bloco, hash, transação ou endereço",
+ "Size": "Tamanho",
"Size (KB)": "Tamanho (KB)",
"%s of %s Transactions": "%0 de %1 Confirmações",
"Spent by": "Gasto por",
@@ -40,5 +44,156 @@
"Unconfirmed": "Não confirmada",
"Unspent": "Não gasto",
"Version": "Versão",
- "Weight (KWU)": "Peso (KWU)"
+ "Virtual size": "Tamanho virtual",
+ "Weight (KWU)": "Peso (KWU)",
+ "%s MINUTE PAST EXPECTED INTERVAL": "%0 MINUTO APÓS O INTERVALO PREVISTO",
+ "%s MINUTES PAST EXPECTED INTERVAL": "%0 MINUTOS APÓS O INTERVALO PREVISTO",
+ "%s SELECTED + COINBASE": "%0 SELECIONADAS + COINBASE",
+ "%s added since the last update": "%0 adicionadas desde a última atualização",
+ "%s days ago": "há %0 dias",
+ "%s hours ago": "há %0 horas",
+ "%s minutes ago": "há %0 minutos",
+ "%s removed since the last update": "%0 removidas desde a última atualização",
+ "%s seconds ago": "há %0 segundos",
+ "1 day ago": "há 1 dia",
+ "1 hour ago": "há 1 hora",
+ "1 minute ago": "há 1 minuto",
+ "< 1 MINUTE PAST EXPECTED INTERVAL": "< 1 MINUTO APÓS O INTERVALO PREVISTO",
+ "< 1m": "< 1min",
+ "A balanced fee rate estimated to confirm within %s blocks.": "Uma taxa de comissão equilibrada estimada para confirmação no prazo de %0 blocos.",
+ "A higher-priority fee rate estimated to confirm in the next block.": "Uma taxa de comissão de prioridade mais alta estimada para confirmação no próximo bloco.",
+ "A lower-priority fee rate estimated to confirm within %s blocks.": "Uma taxa de comissão de prioridade mais baixa estimada para confirmação no prazo de %0 blocos.",
+ "AMOUNT": "MONTANTE",
+ "AVERAGE BLOCK TIME": "TEMPO MÉDIO DO BLOCO",
+ "AVG FEE": "TAXA MÉDIA",
+ "All selected transactions are shown individually.": "Todas as transações selecionadas são apresentadas individualmente.",
+ "Assets vs Liabilities": "Ativos vs Passivos",
+ "Average": "Média",
+ "Average fee rate and transaction fee in the high-fee portion of this template.": "Taxa de comissão média e taxa de transação na parte de taxas altas deste modelo.",
+ "Average fee rate and transaction fee in the low-fee portion of this template.": "Taxa de comissão média e taxa de transação na parte de taxas baixas deste modelo.",
+ "Average fee rate and transaction fee in the middle-fee portion of this template.": "Taxa de comissão média e taxa de transação na parte de taxas médias deste modelo.",
+ "BLOCK": "BLOCO",
+ "BLOCK #%s": "BLOCO #%0",
+ "BLOCK FILLING": "PREENCHIMENTO DO BLOCO",
+ "Bitcoin price line chart": "Gráfico de linhas do preço do Bitcoin",
+ "Block #%s": "Bloco #%0",
+ "Block Weight": "Peso do Bloco",
+ "Block is %s% full": "O bloco está %0% preenchido",
+ "Block utilization unavailable": "Utilização do bloco indisponível",
+ "Blocks History": "Histórico de Blocos",
+ "Confirmed federation BTC holdings divided by circulating L-BTC supply.": "Reservas confirmadas de BTC da federação divididas pela oferta de L-BTC em circulação.",
+ "Confirmed peg-ins minus confirmed peg-outs.": "Peg-ins confirmados menos peg-outs confirmados.",
+ "Copy block number %s": "Copiar número do bloco %0",
+ "Copy transaction id %s": "Copiar ID da transação %0",
+ "Current template weight and serialized size compared with their block limits.": "Peso atual do modelo e tamanho serializado comparados com os respetivos limites do bloco.",
+ "Difficulty": "Dificuldade",
+ "Difficulty Adjustment": "Ajuste de Dificuldade",
+ "EXPECTED ADJ": "AJUSTE ESPERADO",
+ "EXPECTED ADJ DATE": "DATA DO AJUSTE ESPERADO",
+ "EXPECTED IN < 1 MINUTE": "PREVISTO EM < 1 MINUTO",
+ "EXPECTED IN ~%s MINUTE": "PREVISTO EM ~%0 MINUTO",
+ "EXPECTED IN ~%s MINUTES": "PREVISTO EM ~%0 MINUTOS",
+ "EXPECTED INTERVAL REACHED": "INTERVALO PREVISTO ATINGIDO",
+ "Elapsed time since the last block confirmed.": "Tempo decorrido desde a confirmação do último bloco.",
+ "Elapsed time since the last block confirmed. Bitcoin targets one every ~10 minutes.": "Tempo decorrido desde a confirmação do último bloco. A rede Bitcoin procura confirmar um bloco a cada ~10 minutos.",
+ "Elapsed time since the last block confirmed. Liquid targets one every ~1 minute.": "Tempo decorrido desde a confirmação do último bloco. A rede Liquid procura confirmar um bloco a cada ~1 minuto.",
+ "Estimated computing power securing the network.": "Poder computacional estimado que protege a rede.",
+ "Estimated time until the peg transaction is confirmed.": "Tempo estimado até à confirmação da transação de peg.",
+ "Exahashes per second": "Exahashes por segundo",
+ "FEE": "TAXA",
+ "Federation BTC Holdings": "Reservas de BTC da Federação",
+ "Fee Market": "Mercado de Taxas",
+ "Fee rate": "Taxa de comissão",
+ "Fee-rate estimates are unavailable; transactions use a neutral color.": "As estimativas das taxas de comissão estão indisponíveis; as transações utilizam uma cor neutra.",
+ "Gigahashes per second": "Gigahashes por segundo",
+ "HIGH": "ALTA",
+ "Hashes per second": "Hashes por segundo",
+ "Hashrate": "Taxa de Hash",
+ "High": "Alta",
+ "High-Value Assets": "Ativos de Alto Valor",
+ "How busy mempool activity is. More congestion means higher fees for quick confirmation.": "Nível de atividade da mempool. Mais congestionamento significa taxas mais altas para uma confirmação rápida.",
+ "How full this block is.": "Nível de preenchimento deste bloco.",
+ "How hard it is to find a valid block. Tracks hashrate.": "Dificuldade de encontrar um bloco válido. Acompanha a taxa de hash.",
+ "How hard it is to mine new blocks. Bitcoin retargets mining difficulty every 2,016 blocks to keep blocks near 10 minutes. Current is the projected next change; Previous was the last change.": "Dificuldade de minerar novos blocos. A rede Bitcoin reajusta a dificuldade de mineração a cada 2.016 blocos para manter o intervalo entre blocos próximo de 10 minutos. Atual é a próxima alteração projetada; Anterior foi a última alteração.",
+ "IN MEMPOOL": "NA MEMPOOL",
+ "Individually rendered transactions": "Transações apresentadas individualmente",
+ "Kilohashes per second": "Kilohashes por segundo",
+ "LOW": "BAIXA",
+ "Last change N/A": "Última alteração N/D",
+ "Last change on %s": "Última alteração em %0",
+ "Latest": "Mais Recente",
+ "Latest Blocks": "Blocos Mais Recentes",
+ "Latest Transactions": "Transações Mais Recentes",
+ "Legacy": "Legado",
+ "Live": "Em Direto",
+ "Loading block utilization": "A carregar utilização do bloco",
+ "Loading pending block transactions": "A carregar transações do bloco pendente",
+ "Low": "Baixa",
+ "Lower-fee transactions are summarized in the metrics because they do not fit at this resolution.": "As transações com taxas mais baixas são resumidas nas métricas porque não cabem nesta resolução.",
+ "Medium": "Média",
+ "Megahashes per second": "Megahashes por segundo",
+ "Mempool Congestion": "Congestionamento da Mempool",
+ "Moderate": "Moderada",
+ "N/A": "N/D",
+ "Next Block": "Próximo Bloco",
+ "Next adj. in %s": "Próx. ajuste em %0",
+ "Next adjustment unavailable": "Próximo ajuste indisponível",
+ "No recent blocks": "Sem blocos recentes",
+ "Overview": "Visão Geral",
+ "PREVIOUS ADJ": "AJUSTE ANTERIOR",
+ "Peg Information": "Informação de Peg",
+ "Peg data is currently unavailable.": "Os dados de peg estão atualmente indisponíveis.",
+ "Pending Transactions": "Transações Pendentes",
+ "Pending block transaction grid": "Grelha de transações do bloco pendente",
+ "Petahashes per second": "Petahashes por segundo",
+ "Proof of Reserves": "Prova de Reservas",
+ "Recent Peg-Ins/Outs": "Peg-Ins/Outs Recentes",
+ "Recommended Fee": "Taxa Recomendada",
+ "SIZE": "TAMANHO",
+ "See More": "Ver Mais",
+ "Share of selected transactions using SegWit or legacy serialization.": "Percentagem das transações selecionadas que utilizam serialização SegWit ou legada.",
+ "Suggested rate (sat/vB) to confirm in the next block or two.": "Taxa sugerida (sat/vB) para confirmação no próximo bloco ou nos próximos dois blocos.",
+ "TOTAL FEE COLLECTED": "TOTAL DE TAXAS COBRADAS",
+ "TRANSACTION ID": "ID DA TRANSAÇÃO",
+ "TRANSACTIONS": "TRANSAÇÕES",
+ "TX ID": "ID DA TX",
+ "TYPE": "TIPO",
+ "Terahashes per second": "Terahashes por segundo",
+ "This panel shows the circulating value of high-value assets on Liquid.": "Este painel apresenta o valor em circulação dos ativos de alto valor na Liquid.",
+ "Time Since Last Block": "Tempo Desde o Último Bloco",
+ "Total Fees Collected": "Total de Taxas Cobradas",
+ "Total transaction fees a miner would collect from the current template, shown in bitcoin and US dollars.": "Total de taxas de transação que um mineiro receberia do modelo atual, apresentado em bitcoin e dólares dos EUA.",
+ "Transaction Types": "Tipos de Transação",
+ "Transactions currently selected for the pending block, including the coinbase transaction.": "Transações atualmente selecionadas para o bloco pendente, incluindo a transação coinbase.",
+ "Transactions currently waiting in the node's mempool.": "Transações atualmente à espera na mempool do nó.",
+ "Unable to refresh — showing previous data.": "Não foi possível atualizar — a apresentar os dados anteriores.",
+ "Unknown": "Desconhecido",
+ "Use the arrow keys to inspect transactions and Enter to open one.": "Utilize as teclas de seta para inspecionar transações e Enter para abrir uma.",
+ "VALUE": "VALOR",
+ "VOLUME IN": "VOLUME DE ENTRADA",
+ "VOLUME OUT": "VOLUME DE SAÍDA",
+ "View block %s": "Ver bloco %0",
+ "Weight": "Peso",
+ "Yottahashes per second": "Yottahashes por segundo",
+ "Zettahashes per second": "Zettahashes por segundo",
+ "am": "a.m.",
+ "just now": "agora mesmo",
+ "m": "min",
+ "mo": "mês",
+ "pm": "p.m.",
+ "w": "sem",
+ "y": "a",
+ "~%s min": "~%0 min",
+ "%s AGO": "HÁ %0",
+ "< 1 MINUTE": "< 1 MINUTO",
+ "DAY": "DIA",
+ "DAYS": "DIAS",
+ "HOUR": "HORA",
+ "HOURS": "HORAS",
+ "MINUTE": "MINUTO",
+ "MINUTES": "MINUTOS",
+ "MONTH": "MÊS",
+ "MONTHS": "MESES",
+ "YEAR": "ANO",
+ "YEARS": "ANOS"
}
diff --git a/lang/pt-pt.po b/lang/pt-pt.po
index 499782d1..2ffa35db 100644
--- a/lang/pt-pt.po
+++ b/lang/pt-pt.po
@@ -82,7 +82,7 @@ msgid "Confidential"
msgstr "Confidencial"
msgid "Confirmed"
-msgstr ""
+msgstr "Confirmada"
msgid "Confirmed received"
msgstr ""
@@ -106,10 +106,10 @@ msgid "Esplora is currently unavailable, please try again later."
msgstr ""
msgid "ETA"
-msgstr ""
+msgstr "ETA"
msgid "Fee"
-msgstr ""
+msgstr "Taxa"
msgid "Go"
msgstr ""
@@ -195,7 +195,7 @@ msgid "No outputs"
msgstr ""
msgid "No recent transactions"
-msgstr ""
+msgstr "Sem transações recentes"
msgid "No reissuance"
msgstr ""
@@ -231,7 +231,7 @@ msgid "Page Not Found"
msgstr "Página Não Encontrada"
msgid "Peg-out"
-msgstr ""
+msgstr "Peg-out"
msgid "Peg-out address"
msgstr ""
@@ -329,7 +329,7 @@ msgid "%s from tip"
msgstr ""
msgid "Size"
-msgstr ""
+msgstr "Tamanho"
msgid "Size (KB)"
msgstr "Tamanho (KB)"
@@ -432,7 +432,7 @@ msgid "Transaction: %s"
msgstr "Transação: %0"
msgid "TXID"
-msgstr ""
+msgstr "TXID"
msgid "txid:vout"
msgstr ""
@@ -474,7 +474,7 @@ msgid "Version"
msgstr "Versão"
msgid "Virtual size"
-msgstr ""
+msgstr "Tamanho virtual"
msgid "We encountered an error. Please try again later."
msgstr ""
@@ -487,3 +487,480 @@ msgstr ""
msgid "Witness"
msgstr ""
+
+msgid "%s MINUTE PAST EXPECTED INTERVAL"
+msgstr "%0 MINUTO APÓS O INTERVALO PREVISTO"
+
+msgid "%s MINUTES PAST EXPECTED INTERVAL"
+msgstr "%0 MINUTOS APÓS O INTERVALO PREVISTO"
+
+msgid "%s SELECTED + COINBASE"
+msgstr "%0 SELECIONADAS + COINBASE"
+
+msgid "%s added since the last update"
+msgstr "%0 adicionadas desde a última atualização"
+
+msgid "%s days ago"
+msgstr "há %0 dias"
+
+msgid "%s hours ago"
+msgstr "há %0 horas"
+
+msgid "%s minutes ago"
+msgstr "há %0 minutos"
+
+msgid "%s removed since the last update"
+msgstr "%0 removidas desde a última atualização"
+
+msgid "%s seconds ago"
+msgstr "há %0 segundos"
+
+msgid "1 day ago"
+msgstr "há 1 dia"
+
+msgid "1 hour ago"
+msgstr "há 1 hora"
+
+msgid "1 minute ago"
+msgstr "há 1 minuto"
+
+msgid "< 1 MINUTE PAST EXPECTED INTERVAL"
+msgstr "< 1 MINUTO APÓS O INTERVALO PREVISTO"
+
+msgid "< 1 min"
+msgstr "< 1 min"
+
+msgid "< 1m"
+msgstr "< 1min"
+
+msgid "A balanced fee rate estimated to confirm within %s blocks."
+msgstr "Uma taxa de comissão equilibrada estimada para confirmação no prazo de %0 blocos."
+
+msgid "A higher-priority fee rate estimated to confirm in the next block."
+msgstr "Uma taxa de comissão de prioridade mais alta estimada para confirmação no próximo bloco."
+
+msgid "A lower-priority fee rate estimated to confirm within %s blocks."
+msgstr "Uma taxa de comissão de prioridade mais baixa estimada para confirmação no prazo de %0 blocos."
+
+msgid "AMOUNT"
+msgstr "MONTANTE"
+
+msgid "AVERAGE BLOCK TIME"
+msgstr "TEMPO MÉDIO DO BLOCO"
+
+msgid "AVG FEE"
+msgstr "TAXA MÉDIA"
+
+msgid "All selected transactions are shown individually."
+msgstr "Todas as transações selecionadas são apresentadas individualmente."
+
+msgid "Assets vs Liabilities"
+msgstr "Ativos vs Passivos"
+
+msgid "Average"
+msgstr "Média"
+
+msgid "Average fee rate and transaction fee in the high-fee portion of this template."
+msgstr "Taxa de comissão média e taxa de transação na parte de taxas altas deste modelo."
+
+msgid "Average fee rate and transaction fee in the low-fee portion of this template."
+msgstr "Taxa de comissão média e taxa de transação na parte de taxas baixas deste modelo."
+
+msgid "Average fee rate and transaction fee in the middle-fee portion of this template."
+msgstr "Taxa de comissão média e taxa de transação na parte de taxas médias deste modelo."
+
+msgid "BLOCK"
+msgstr "BLOCO"
+
+msgid "BLOCK #%s"
+msgstr "BLOCO #%0"
+
+msgid "BLOCK FILLING"
+msgstr "PREENCHIMENTO DO BLOCO"
+
+msgid "Bitcoin"
+msgstr "Bitcoin"
+
+msgid "Bitcoin price line chart"
+msgstr "Gráfico de linhas do preço do Bitcoin"
+
+msgid "Block #%s"
+msgstr "Bloco #%0"
+
+msgid "Block Weight"
+msgstr "Peso do Bloco"
+
+msgid "Block is %s% full"
+msgstr "O bloco está %0% preenchido"
+
+msgid "Block utilization unavailable"
+msgstr "Utilização do bloco indisponível"
+
+msgid "Blocks History"
+msgstr "Histórico de Blocos"
+
+msgid "Confirmed federation BTC holdings divided by circulating L-BTC supply."
+msgstr "Reservas confirmadas de BTC da federação divididas pela oferta de L-BTC em circulação."
+
+msgid "Confirmed peg-ins minus confirmed peg-outs."
+msgstr "Peg-ins confirmados menos peg-outs confirmados."
+
+msgid "Copy block number %s"
+msgstr "Copiar número do bloco %0"
+
+msgid "Copy transaction id %s"
+msgstr "Copiar ID da transação %0"
+
+msgid "Current template weight and serialized size compared with their block limits."
+msgstr "Peso atual do modelo e tamanho serializado comparados com os respetivos limites do bloco."
+
+msgid "Difficulty"
+msgstr "Dificuldade"
+
+msgid "Difficulty Adjustment"
+msgstr "Ajuste de Dificuldade"
+
+msgid "EXPECTED ADJ"
+msgstr "AJUSTE ESPERADO"
+
+msgid "EXPECTED ADJ DATE"
+msgstr "DATA DO AJUSTE ESPERADO"
+
+msgid "EXPECTED IN < 1 MINUTE"
+msgstr "PREVISTO EM < 1 MINUTO"
+
+msgid "EXPECTED IN ~%s MINUTE"
+msgstr "PREVISTO EM ~%0 MINUTO"
+
+msgid "EXPECTED IN ~%s MINUTES"
+msgstr "PREVISTO EM ~%0 MINUTOS"
+
+msgid "EXPECTED INTERVAL REACHED"
+msgstr "INTERVALO PREVISTO ATINGIDO"
+
+msgid "Elapsed time since the last block confirmed."
+msgstr "Tempo decorrido desde a confirmação do último bloco."
+
+msgid "Elapsed time since the last block confirmed. Bitcoin targets one every ~10 minutes."
+msgstr "Tempo decorrido desde a confirmação do último bloco. A rede Bitcoin procura confirmar um bloco a cada ~10 minutos."
+
+msgid "Elapsed time since the last block confirmed. Liquid targets one every ~1 minute."
+msgstr "Tempo decorrido desde a confirmação do último bloco. A rede Liquid procura confirmar um bloco a cada ~1 minuto."
+
+msgid "Estimated computing power securing the network."
+msgstr "Poder computacional estimado que protege a rede."
+
+msgid "Estimated time until the peg transaction is confirmed."
+msgstr "Tempo estimado até à confirmação da transação de peg."
+
+msgid "Exahashes per second"
+msgstr "Exahashes por segundo"
+
+msgid "FEE"
+msgstr "TAXA"
+
+msgid "Federation BTC Holdings"
+msgstr "Reservas de BTC da Federação"
+
+msgid "Fee Market"
+msgstr "Mercado de Taxas"
+
+msgid "Fee rate"
+msgstr "Taxa de comissão"
+
+msgid "Fee-rate estimates are unavailable; transactions use a neutral color."
+msgstr "As estimativas das taxas de comissão estão indisponíveis; as transações utilizam uma cor neutra."
+
+msgid "Gigahashes per second"
+msgstr "Gigahashes por segundo"
+
+msgid "HIGH"
+msgstr "ALTA"
+
+msgid "Hashes per second"
+msgstr "Hashes por segundo"
+
+msgid "Hashrate"
+msgstr "Taxa de Hash"
+
+msgid "High"
+msgstr "Alta"
+
+msgid "High-Value Assets"
+msgstr "Ativos de Alto Valor"
+
+msgid "How busy mempool activity is. More congestion means higher fees for quick confirmation."
+msgstr "Nível de atividade da mempool. Mais congestionamento significa taxas mais altas para uma confirmação rápida."
+
+msgid "How full this block is."
+msgstr "Nível de preenchimento deste bloco."
+
+msgid "How hard it is to find a valid block. Tracks hashrate."
+msgstr "Dificuldade de encontrar um bloco válido. Acompanha a taxa de hash."
+
+msgid "How hard it is to mine new blocks. Bitcoin retargets mining difficulty every 2,016 blocks to keep blocks near 10 minutes. Current is the projected next change; Previous was the last change."
+msgstr "Dificuldade de minerar novos blocos. A rede Bitcoin reajusta a dificuldade de mineração a cada 2.016 blocos para manter o intervalo entre blocos próximo de 10 minutos. Atual é a próxima alteração projetada; Anterior foi a última alteração."
+
+msgid "IN MEMPOOL"
+msgstr "NA MEMPOOL"
+
+msgid "Individually rendered transactions"
+msgstr "Transações apresentadas individualmente"
+
+msgid "Kilohashes per second"
+msgstr "Kilohashes por segundo"
+
+msgid "LOW"
+msgstr "BAIXA"
+
+msgid "Last change N/A"
+msgstr "Última alteração N/D"
+
+msgid "Last change on %s"
+msgstr "Última alteração em %0"
+
+msgid "Latest"
+msgstr "Mais Recente"
+
+msgid "Latest Blocks"
+msgstr "Blocos Mais Recentes"
+
+msgid "Latest Transactions"
+msgstr "Transações Mais Recentes"
+
+msgid "Legacy"
+msgstr "Legado"
+
+msgid "Live"
+msgstr "Em Direto"
+
+msgid "Loading block utilization"
+msgstr "A carregar utilização do bloco"
+
+msgid "Loading pending block transactions"
+msgstr "A carregar transações do bloco pendente"
+
+msgid "Low"
+msgstr "Baixa"
+
+msgid "Lower-fee transactions are summarized in the metrics because they do not fit at this resolution."
+msgstr "As transações com taxas mais baixas são resumidas nas métricas porque não cabem nesta resolução."
+
+msgid "Medium"
+msgstr "Média"
+
+msgid "Megahashes per second"
+msgstr "Megahashes por segundo"
+
+msgid "Mempool Congestion"
+msgstr "Congestionamento da Mempool"
+
+msgid "Moderate"
+msgstr "Moderada"
+
+msgid "N/A"
+msgstr "N/D"
+
+msgid "Next Block"
+msgstr "Próximo Bloco"
+
+msgid "Next adj. in %s"
+msgstr "Próx. ajuste em %0"
+
+msgid "Next adjustment unavailable"
+msgstr "Próximo ajuste indisponível"
+
+msgid "No recent blocks"
+msgstr "Sem blocos recentes"
+
+msgid "Overview"
+msgstr "Visão Geral"
+
+msgid "PEG-IN"
+msgstr "PEG-IN"
+
+msgid "PEG-OUT"
+msgstr "PEG-OUT"
+
+msgid "PREVIOUS ADJ"
+msgstr "AJUSTE ANTERIOR"
+
+msgid "Peg Information"
+msgstr "Informação de Peg"
+
+msgid "Peg data is currently unavailable."
+msgstr "Os dados de peg estão atualmente indisponíveis."
+
+msgid "Peg-in"
+msgstr "Peg-in"
+
+msgid "Pending Transactions"
+msgstr "Transações Pendentes"
+
+msgid "Pending block transaction grid"
+msgstr "Grelha de transações do bloco pendente"
+
+msgid "Petahashes per second"
+msgstr "Petahashes por segundo"
+
+msgid "Proof of Reserves"
+msgstr "Prova de Reservas"
+
+msgid "Recent Peg-Ins/Outs"
+msgstr "Peg-Ins/Outs Recentes"
+
+msgid "Recommended Fee"
+msgstr "Taxa Recomendada"
+
+msgid "SIZE"
+msgstr "TAMANHO"
+
+msgid "See More"
+msgstr "Ver Mais"
+
+msgid "SegWit"
+msgstr "SegWit"
+
+msgid "Share of selected transactions using SegWit or legacy serialization."
+msgstr "Percentagem das transações selecionadas que utilizam serialização SegWit ou legada."
+
+msgid "Suggested rate (sat/vB) to confirm in the next block or two."
+msgstr "Taxa sugerida (sat/vB) para confirmação no próximo bloco ou nos próximos dois blocos."
+
+msgid "TOTAL FEE COLLECTED"
+msgstr "TOTAL DE TAXAS COBRADAS"
+
+msgid "TRANSACTION ID"
+msgstr "ID DA TRANSAÇÃO"
+
+msgid "TRANSACTIONS"
+msgstr "TRANSAÇÕES"
+
+msgid "TX ID"
+msgstr "ID DA TX"
+
+msgid "TYPE"
+msgstr "TIPO"
+
+msgid "Terahashes per second"
+msgstr "Terahashes por segundo"
+
+msgid "This panel shows the circulating value of high-value assets on Liquid."
+msgstr "Este painel apresenta o valor em circulação dos ativos de alto valor na Liquid."
+
+msgid "Time Since Last Block"
+msgstr "Tempo Desde o Último Bloco"
+
+msgid "Total Fees Collected"
+msgstr "Total de Taxas Cobradas"
+
+msgid "Total transaction fees a miner would collect from the current template, shown in bitcoin and US dollars."
+msgstr "Total de taxas de transação que um mineiro receberia do modelo atual, apresentado em bitcoin e dólares dos EUA."
+
+msgid "Transaction Types"
+msgstr "Tipos de Transação"
+
+msgid "Transactions currently selected for the pending block, including the coinbase transaction."
+msgstr "Transações atualmente selecionadas para o bloco pendente, incluindo a transação coinbase."
+
+msgid "Transactions currently waiting in the node's mempool."
+msgstr "Transações atualmente à espera na mempool do nó."
+
+msgid "Unable to refresh — showing previous data."
+msgstr "Não foi possível atualizar — a apresentar os dados anteriores."
+
+msgid "Unknown"
+msgstr "Desconhecido"
+
+msgid "Use the arrow keys to inspect transactions and Enter to open one."
+msgstr "Utilize as teclas de seta para inspecionar transações e Enter para abrir uma."
+
+msgid "VALUE"
+msgstr "VALOR"
+
+msgid "VOLUME IN"
+msgstr "VOLUME DE ENTRADA"
+
+msgid "VOLUME OUT"
+msgstr "VOLUME DE SAÍDA"
+
+msgid "View block %s"
+msgstr "Ver bloco %0"
+
+msgid "Weight"
+msgstr "Peso"
+
+msgid "Yottahashes per second"
+msgstr "Yottahashes por segundo"
+
+msgid "Zettahashes per second"
+msgstr "Zettahashes por segundo"
+
+msgid "am"
+msgstr "a.m."
+
+msgid "d"
+msgstr "d"
+
+msgid "h"
+msgstr "h"
+
+msgid "just now"
+msgstr "agora mesmo"
+
+msgid "m"
+msgstr "min"
+
+msgid "mo"
+msgstr "mês"
+
+msgid "pm"
+msgstr "p.m."
+
+msgid "s"
+msgstr "s"
+
+msgid "w"
+msgstr "sem"
+
+msgid "y"
+msgstr "a"
+
+msgid "~%s min"
+msgstr "~%0 min"
+
+msgid "%s AGO"
+msgstr "HÁ %0"
+
+msgid "< 1 MINUTE"
+msgstr "< 1 MINUTO"
+
+msgid "DAY"
+msgstr "DIA"
+
+msgid "DAYS"
+msgstr "DIAS"
+
+msgid "HOUR"
+msgstr "HORA"
+
+msgid "HOURS"
+msgstr "HORAS"
+
+msgid "MINUTE"
+msgstr "MINUTO"
+
+msgid "MINUTES"
+msgstr "MINUTOS"
+
+msgid "MONTH"
+msgstr "MÊS"
+
+msgid "MONTHS"
+msgstr "MESES"
+
+msgid "YEAR"
+msgstr "ANO"
+
+msgid "YEARS"
+msgstr "ANOS"
diff --git a/lang/strings.txt b/lang/strings.txt
index ade01bcd..e02cc44f 100644
--- a/lang/strings.txt
+++ b/lang/strings.txt
@@ -229,3 +229,118 @@ Yes
< 1 MINUTE PAST EXPECTED INTERVAL
< 1 min
~%s min
+%s SELECTED + COINBASE
+%s added since the last update
+%s days ago
+%s hours ago
+%s minutes ago
+%s removed since the last update
+%s seconds ago
+1 day ago
+1 hour ago
+1 minute ago
+< 1m
+AVERAGE BLOCK TIME
+AVG FEE
+All selected transactions are shown individually.
+Average fee rate and transaction fee in the high-fee portion of this template.
+Average fee rate and transaction fee in the low-fee portion of this template.
+Average fee rate and transaction fee in the middle-fee portion of this template.
+BLOCK #%s
+Bitcoin
+Bitcoin price line chart
+Block is %s% full
+Block utilization unavailable
+Blocks History
+Copy block number %s
+Copy transaction id %s
+Current template weight and serialized size compared with their block limits.
+Difficulty
+Difficulty Adjustment
+EXPECTED ADJ
+EXPECTED ADJ DATE
+Elapsed time since the last block confirmed.
+Elapsed time since the last block confirmed. Bitcoin targets one every ~10 minutes.
+Elapsed time since the last block confirmed. Liquid targets one every ~1 minute.
+Estimated computing power securing the network.
+Exahashes per second
+FEE
+Fee rate
+Fee-rate estimates are unavailable; transactions use a neutral color.
+Gigahashes per second
+HIGH
+Hashes per second
+Hashrate
+High-Value Assets
+How busy mempool activity is. More congestion means higher fees for quick confirmation.
+How full this block is.
+How hard it is to find a valid block. Tracks hashrate.
+How hard it is to mine new blocks. Bitcoin retargets mining difficulty every 2,016 blocks to keep blocks near 10 minutes. Current is the projected next change; Previous was the last change.
+IN MEMPOOL
+Individually rendered transactions
+Kilohashes per second
+LOW
+Latest
+Latest Blocks
+Latest Transactions
+Legacy
+Live
+Loading block utilization
+Loading pending block transactions
+Lower-fee transactions are summarized in the metrics because they do not fit at this resolution.
+Medium
+Megahashes per second
+Mempool Congestion
+Moderate
+Next Block
+Next adj. in %s
+Next adjustment unavailable
+No recent blocks
+Overview
+PREVIOUS ADJ
+Pending Transactions
+Pending block transaction grid
+Petahashes per second
+Recommended Fee
+SIZE
+SegWit
+Share of selected transactions using SegWit or legacy serialization.
+Suggested rate (sat/vB) to confirm in the next block or two.
+TOTAL FEE COLLECTED
+TRANSACTION ID
+TRANSACTIONS
+TX ID
+Terahashes per second
+This panel shows the circulating value of high-value assets on Liquid.
+Total Fees Collected
+Total transaction fees a miner would collect from the current template, shown in bitcoin and US dollars.
+Transaction Types
+Transactions currently selected for the pending block, including the coinbase transaction.
+Transactions currently waiting in the node's mempool.
+Use the arrow keys to inspect transactions and Enter to open one.
+VALUE
+View block %s
+Yottahashes per second
+Zettahashes per second
+am
+d
+h
+just now
+m
+mo
+pm
+s
+w
+y
+%s AGO
+< 1 MINUTE
+DAY
+DAYS
+HOUR
+HOURS
+MINUTE
+MINUTES
+MONTH
+MONTHS
+YEAR
+YEARS
diff --git a/test/dashboard-localization.test.js b/test/dashboard-localization.test.js
new file mode 100644
index 00000000..3bdee741
--- /dev/null
+++ b/test/dashboard-localization.test.js
@@ -0,0 +1,140 @@
+const test = require("node:test");
+const assert = require("node:assert/strict");
+const render = require("snabbdom-to-html");
+
+const l10n = require("../client/src/l10n").default;
+const { blks } = require("../client/src/views/blocks");
+const {
+ ElapsedTime,
+ formatDuration,
+} = require("../client/src/components/elapsed-time");
+const {
+ highValueAssets,
+} = require("../client/src/components/high-value-assets");
+const difficultyAdjustment =
+ require("../client/src/views/difficulty-adjustment").default;
+const { overview } = require("../client/src/views/overview");
+const { transactions } = require("../client/src/views/transactions");
+const portuguese = require("../lang/pt-pt.json");
+
+const t = l10n["pt-pt"];
+
+test("localizes overview and recent block copy in Portuguese", () => {
+ const block = {
+ height: 123,
+ id: "block-id",
+ size: 1_000_000,
+ timestamp: Math.floor(Date.now() / 1000),
+ tx_count: 456,
+ weight: 2_000_000,
+ };
+ const overviewHtml = render(overview({
+ blocks: [block],
+ mempool: { vsize: 0 },
+ t,
+ }));
+ const blocksHtml = render(blks([block], false, { t }));
+
+ assert.match(overviewHtml, /Visão Geral/);
+ assert.match(overviewHtml, /Tempo Desde o Último Bloco/);
+ assert.match(overviewHtml, /BLOCO #123/);
+ assert.match(
+ overviewHtml,
+ /aria-label="Gráfico de linhas do preço do Bitcoin"/,
+ );
+ assert.match(blocksHtml, /Blocos Mais Recentes/);
+ assert.match(blocksHtml, /Mais Recente/);
+ assert.match(blocksHtml, /AGORA MESMO/);
+ assert.match(blocksHtml, /TRANSAÇÕES/);
+ assert.match(blocksHtml, /TAMANHO/);
+ assert.match(blocksHtml, /aria-label="Ver bloco 123"/);
+ assert.match(blocksHtml, /aria-label="Copiar número do bloco 123"/);
+});
+
+test("localizes recent transaction and difficulty copy in Portuguese", () => {
+ const txid = "a".repeat(64);
+ const transactionsHtml = render(transactions([{
+ fee: 100,
+ txid,
+ value: 100_000_000,
+ vsize: 100,
+ }], false, { t }));
+ const difficultyHtml = render(difficultyAdjustment({ blocks: [], t }));
+
+ assert.match(transactionsHtml, /Transações Mais Recentes/);
+ assert.match(transactionsHtml, /ID DA TRANSAÇÃO/);
+ assert.match(transactionsHtml, /VALOR/);
+ assert.match(transactionsHtml, /TAMANHO/);
+ assert.match(transactionsHtml, /TAXA/);
+ assert.match(
+ transactionsHtml,
+ new RegExp(`aria-label="Copiar ID da transação ${txid}"`),
+ );
+ assert.match(difficultyHtml, /Ajuste de Dificuldade/);
+ assert.match(difficultyHtml, /TEMPO MÉDIO DO BLOCO/);
+ assert.match(difficultyHtml, /AJUSTE ESPERADO/);
+ assert.match(difficultyHtml, /AJUSTE ANTERIOR/);
+ assert.match(difficultyHtml, /DATA DO AJUSTE ESPERADO/);
+ assert.match(difficultyHtml, /Taxa de Hash/);
+ assert.match(difficultyHtml, /Dificuldade/);
+ assert.match(difficultyHtml, /Próximo ajuste indisponível/);
+ assert.match(difficultyHtml, /N\/D/);
+});
+
+test("localizes elapsed times and formatter-owned fallbacks", () => {
+ const oneYear = 365 * 24 * 60 * 60 * 1000;
+ const elapsedHtml = render(ElapsedTime({
+ timestamp: Date.now() - 90 * 1000,
+ t,
+ }));
+ const highValueAssetsHtml = render(highValueAssets(t));
+
+ assert.equal(formatDuration(0, false, t), "< 1 MINUTO");
+ assert.equal(formatDuration(oneYear, false, t), "1 ANO");
+ assert.match(elapsedHtml, /HÁ 1 MINUTO/);
+ assert.match(highValueAssetsHtml, /N\/D/);
+});
+
+test("preserves all-caps dashboard label casing in Portuguese", () => {
+ [
+ "AMOUNT",
+ "AVERAGE BLOCK TIME",
+ "AVG FEE",
+ "%s AGO",
+ "BLOCK",
+ "BLOCK #%s",
+ "BLOCK FILLING",
+ "DAY",
+ "DAYS",
+ "EXPECTED ADJ",
+ "EXPECTED ADJ DATE",
+ "FEE",
+ "HIGH",
+ "HOUR",
+ "HOURS",
+ "IN MEMPOOL",
+ "LOW",
+ "MINUTE",
+ "MINUTES",
+ "MONTH",
+ "MONTHS",
+ "PEG-IN",
+ "PEG-OUT",
+ "PREVIOUS ADJ",
+ "SIZE",
+ "TOTAL FEE COLLECTED",
+ "TRANSACTION ID",
+ "TRANSACTIONS",
+ "TX ID",
+ "TXID",
+ "TYPE",
+ "VALUE",
+ "VOLUME IN",
+ "VOLUME OUT",
+ "YEAR",
+ "YEARS",
+ ].forEach((key) => {
+ const translated = portuguese[key] || key;
+ assert.equal(translated, translated.toUpperCase(), key);
+ });
+});
diff --git a/www/style.css b/www/style.css
index cedc867b..9f12b75d 100644
--- a/www/style.css
+++ b/www/style.css
@@ -3868,10 +3868,12 @@ a.back-link img{
justify-content: center;
background-color: rgba(23, 201, 100, 0.2);
color: rgba(23, 201, 100);
- width: 50px;
+ width: fit-content;
height: 18px;
+ padding: 0 8px;
font-weight: 400;
font-size: 11px;
+ white-space: nowrap;
border-radius: 18px;
}