Allow Exporting transaction history to a CSV file (#3230)

* Allow Exporting transaction history to a CSV file

* fix: improve safety for share dialog bounds and navigation pop
This commit is contained in:
Omar Hatem
2026-05-18 16:53:06 +02:00
committed by GitHub
parent 491a692cd6
commit 4125c5fe80
38 changed files with 538 additions and 48 deletions
+317
View File
@@ -0,0 +1,317 @@
import 'dart:io';
import 'package:cake_wallet/generated/i18n.dart';
import 'package:cake_wallet/src/screens/backup/backup_page.dart';
import 'package:cake_wallet/src/widgets/alert_with_two_actions.dart';
import 'package:cake_wallet/utils/share_util.dart';
import 'package:cake_wallet/utils/show_bar.dart';
import 'package:cake_wallet/utils/show_pop_up.dart';
import 'package:cake_wallet/view_model/dashboard/action_list_item.dart';
import 'package:cake_wallet/view_model/dashboard/anonpay_transaction_list_item.dart';
import 'package:cake_wallet/view_model/dashboard/date_section_item.dart';
import 'package:cake_wallet/view_model/dashboard/order_list_item.dart';
import 'package:cake_wallet/view_model/dashboard/payjoin_transaction_list_item.dart';
import 'package:cake_wallet/view_model/dashboard/trade_list_item.dart';
import 'package:cake_wallet/view_model/dashboard/transaction_list_item.dart';
import 'package:cw_core/transaction_direction.dart';
import 'package:file_picker/file_picker.dart';
import 'package:flutter/material.dart';
import 'package:intl/intl.dart';
import 'package:path_provider/path_provider.dart';
class CsvExportService {
static const _columns = [
'record_type',
'date_time',
'type',
'amount',
'currency',
'fee',
'tx_id',
'address',
'status',
'note',
'from_amount',
'from_currency',
'to_amount',
'to_currency',
'trade_id',
'provider',
'confirmations',
];
static const _utf8Bom = '';
String buildCsvContent(List<ActionListItem> items) {
final buf = StringBuffer();
buf.write(_utf8Bom);
buf.writeln(_columns.join(','));
for (final item in items) {
if (item is DateSectionItem) continue;
final row = _buildRow(item);
if (row != null) buf.writeln(row);
}
return buf.toString();
}
String? _buildRow(ActionListItem item) {
if (item is TransactionListItem) return _transactionRow(item);
if (item is TradeListItem) return _tradeRow(item);
if (item is OrderListItem) return _orderRow(item);
if (item is AnonpayTransactionListItem) return _anonpayRow(item);
if (item is PayjoinTransactionListItem) return _payjoinRow(item);
return null;
}
String _transactionRow(TransactionListItem item) {
final tx = item.transaction;
final type = tx.direction == TransactionDirection.incoming ? 'incoming' : 'outgoing';
final status = tx.isPending ? 'pending' : 'confirmed';
// Prefer tx.to/tx.from; fall back to address lists for chains that don't populate them.
final address = tx.direction == TransactionDirection.incoming
? (tx.from?.isNotEmpty == true
? tx.from!
: (tx.inputAddresses?.firstOrNull ?? ''))
: (tx.to?.isNotEmpty == true
? tx.to!
: (tx.outputAddresses?.firstOrNull ?? ''));
// Split "0.2769 LTC" → amount="0.2769", currency="LTC"
final (amount, currency) = _splitAmountCurrency(tx.amountFormatted());
// fee is stored as (inputAmount - totalOutputAmount) which is negative for incoming
// transactions — only include it when the raw value is a sensible positive fee.
final fee = tx.fee != null && tx.fee! > 0 ? (tx.feeFormatted() ?? '') : '';
final (feeAmount, _) = fee.isNotEmpty ? _splitAmountCurrency(fee) : ('', '');
return _row([
'transaction',
_isoDate(tx.date),
type,
amount,
currency,
feeAmount,
tx.id,
address,
status,
'',
'',
'',
'',
'',
'',
'',
tx.confirmations.toString(),
]);
}
/// Splits a formatted amount like "0.2769 LTC" into ("0.2769", "LTC").
/// If there is no trailing symbol the whole string is returned as the amount.
(String, String) _splitAmountCurrency(String formatted) {
final trimmed = formatted.trim();
final idx = trimmed.lastIndexOf(' ');
if (idx == -1) return (trimmed, '');
return (trimmed.substring(0, idx), trimmed.substring(idx + 1));
}
String _tradeRow(TradeListItem item) {
final trade = item.trade;
return _row([
'trade',
_isoDate(trade.createdAt ?? DateTime.fromMillisecondsSinceEpoch(0, isUtc: true)),
'swap',
'',
'',
trade.fee?.toString() ?? '',
trade.outputTransaction ?? '',
trade.payoutAddress ?? '',
trade.state.title,
trade.memo ?? '',
trade.amount,
trade.from?.name ?? '',
trade.receiveAmount ?? '',
trade.to?.name ?? '',
trade.id,
trade.provider.title,
'',
]);
}
String _orderRow(OrderListItem item) {
final order = item.order;
return _row([
'order',
_isoDate(order.createdAt),
order.source.title,
order.amountFormatted(),
order.from ?? '',
'',
order.transferId,
'',
order.state.title,
'',
order.amountFormatted(),
order.from ?? '',
order.receiveAmount ?? '',
order.to ?? '',
order.id,
order.providerTitle,
'',
]);
}
String _anonpayRow(AnonpayTransactionListItem item) {
final tx = item.transaction;
final amount = tx.fiatAmount?.toString() ?? tx.amountTo?.toString() ?? '';
final currency = tx.fiatEquiv ?? tx.coinTo;
return _row([
'anonpay',
_isoDate(tx.createdAt),
'anonymous_payment',
amount,
currency,
'',
tx.invoiceId,
tx.address,
tx.status,
'',
'',
'',
'',
'',
'',
tx.provider,
'',
]);
}
String _payjoinRow(PayjoinTransactionListItem item) {
final session = item.session;
final type = session.isSenderSession ? 'send' : 'receive';
final amount = session.rawAmount ?? '0';
return _row([
'payjoin',
_isoDate(session.inProgressSince ?? DateTime.fromMillisecondsSinceEpoch(0, isUtc: true)),
type,
amount,
'BTC',
'',
session.txId ?? '',
'',
item.status,
'',
'',
'',
'',
'',
'',
'',
'',
]);
}
String _row(List<String> fields) => fields.map(escapeField).join(',');
String escapeField(String field) {
if (field.contains(',') || field.contains('"') || field.contains('\n')) {
return '"${field.replaceAll('"', '""')}"';
}
return field;
}
String _isoDate(DateTime dt) => dt.toUtc().toIso8601String();
Future<void> exportToCsv(List<ActionListItem> items, BuildContext context) async {
final dataItems = items.whereType<ActionListItem>().where((e) => e is! DateSectionItem).toList();
if (dataItems.isEmpty) {
await showBar<void>(context, S.current.csv_nothing_to_export);
return;
}
final now = DateTime.now();
final fileName = 'cake_wallet_export_${DateFormat('yyyyMMdd_HHmmss').format(now)}.csv';
late File csvFile;
final exportFuture = Future(() async {
final content = buildCsvContent(items);
csvFile = await _writeTempFile(fileName, content);
});
showPersistentActionOverlay(context, exportFuture, text: S.current.generating_csv);
await exportFuture;
if (!context.mounted) return;
if (Platform.isAndroid) {
_showAndroidExportDialog(context, csvFile, fileName);
} else if (Platform.isIOS) {
await _shareFile(csvFile, fileName, context);
} else {
await _saveFileDesktop(csvFile, fileName);
}
}
void _showAndroidExportDialog(BuildContext context, File csvFile, String fileName) {
showPopUp<void>(
context: context,
builder: (dialogContext) {
return AlertWithTwoActions(
alertTitle: S.current.export_csv,
alertContent: S.current.select_destination,
rightButtonText: S.current.save_to_downloads,
leftButtonText: S.current.share,
actionRightButton: () async {
await _saveToDownloads(fileName, csvFile);
Navigator.of(dialogContext).pop();
await showBar<void>(context, S.current.file_saved);
await csvFile.delete();
},
actionLeftButton: () async {
Navigator.of(dialogContext).pop();
await _shareFile(csvFile, fileName, context);
},
);
},
);
}
Future<void> _shareFile(File file, String fileName, BuildContext context) async {
await ShareUtil.shareFile(filePath: file.path, fileName: fileName, context: context);
if (await file.exists()) await file.delete();
}
Future<void> _saveFileDesktop(File csvFile, String fileName) async {
final outputPath = await FilePicker.platform.saveFile(
dialogTitle: 'Save CSV export',
fileName: fileName,
lockParentWindow: true,
);
if (outputPath == null) return;
await csvFile.copy(outputPath);
await csvFile.delete();
}
Future<File> _writeTempFile(String fileName, String content) async {
final dir = await getApplicationDocumentsDirectory();
final file = File('${dir.path}/$fileName');
if (file.existsSync()) file.deleteSync();
await file.writeAsString(content, flush: true);
return file;
}
Future<void> _saveToDownloads(String fileName, File file) async {
if (!Platform.isAndroid) return;
const downloadsPath = '/storage/emulated/0/Download';
final dest = File('$downloadsPath/$fileName');
if (dest.existsSync()) dest.deleteSync();
await file.copy(dest.path);
}
}
+1 -1
View File
@@ -763,7 +763,7 @@ class _NewSendPageState extends State<NewSendPage> {
conditionToDetermineIfToUse2FA: check,
onAuthSuccess: (value) async {
if (value) {
if (!widget.mode.popOnConfirmation) {
if (!widget.mode.popOnConfirmation && Navigator.canPop(context)) {
Navigator.of(context, rootNavigator: true).pop();
}
showModalBottomSheet(
@@ -1,3 +1,4 @@
import 'package:cake_wallet/core/csv_export_service.dart';
import 'package:cake_wallet/generated/i18n.dart';
import 'package:cake_wallet/new-ui/widgets/line_tab_switcher.dart';
import 'package:cake_wallet/routes.dart';
@@ -24,6 +25,9 @@ class AssetsTopBar extends StatelessWidget {
Widget build(BuildContext context) {
final settingsButtonText = _getSettingsButtonText();
final hasTokenSettingsButton = settingsButtonText != null;
// Reuse the exact same detection logic as _getSettingsButtonText so the
// export button always matches whether the Filters button is visible.
final isHistoryTab = settingsButtonText == S.current.filters;
return SliverToBoxAdapter(
child: Padding(
@@ -39,8 +43,33 @@ class AssetsTopBar extends StatelessWidget {
selectedTab: selectedTab,
)
else SizedBox.shrink(),
Opacity(
opacity: hasTokenSettingsButton ? 1 : 0,
Row(
spacing: 8,
children: [
if (isHistoryTab)
GestureDetector(
onTap: () =>
CsvExportService().exportToCsv(dashboardViewModel.items, context),
child: Semantics(
label: S.of(context).export_csv,
button: true,
child: Container(
height: 36,
width: 36,
decoration: BoxDecoration(
shape: BoxShape.circle,
color: Theme.of(context).colorScheme.surfaceContainer,
),
child: Icon(
Icons.file_download_outlined,
color: Theme.of(context).colorScheme.onSurface,
size: 20,
),
),
),
),
Opacity(
opacity: hasTokenSettingsButton ? 1 : 0,
child: ElevatedButton(
onPressed: () {
if (tabs[selectedTab] == S.of(context).assets) {
@@ -48,40 +77,41 @@ class AssetsTopBar extends StatelessWidget {
Routes.homeSettings,
arguments: dashboardViewModel.balanceViewModel,
);
} else if(tabs[selectedTab] == S.of(context).history) {
} else if (tabs[selectedTab] == S.of(context).history) {
showPopUp<void>(
context: context,
builder: (context) => FilterWidget(filterItems: dashboardViewModel.filterItems),
builder: (context) =>
FilterWidget(filterItems: dashboardViewModel.filterItems),
);
}
},
style: ElevatedButton.styleFrom(
padding: EdgeInsets.zero,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(999999),
),
backgroundColor: Theme.of(
context,
).colorScheme.surfaceContainer,
),
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 12.0),
child: Row(
spacing: 6,
children: [
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(999999),
),
backgroundColor: Theme.of(context).colorScheme.surfaceContainer,
),
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 12.0),
child: Row(
spacing: 6,
children: [
CakeImageWidget(
imageUrl: "assets/new-ui/options_slider.svg",
colorFilter: ColorFilter.mode(
Theme.of(context).colorScheme.primary, BlendMode.srcIn)),
Text(
settingsButtonText??"",
style: TextStyle(color: Theme.of(context).colorScheme.primary),
)
],
),
),
settingsButtonText ?? "",
style: TextStyle(color: Theme.of(context).colorScheme.primary),
)
],
),
),
),
),
],
),
],
),
),
@@ -1,4 +1,5 @@
import 'package:cake_wallet/bitcoin/bitcoin.dart';
import 'package:cake_wallet/core/csv_export_service.dart';
import 'package:cake_wallet/entities/balance_display_mode.dart';
import 'package:cake_wallet/order/order_source_description.dart';
import 'package:cake_wallet/src/screens/dashboard/widgets/anonpay_transaction_row.dart';
@@ -65,6 +66,8 @@ class TransactionsPage extends StatelessWidget {
}),
HeaderRow(
dashboardViewModel: dashboardViewModel,
onExportCsv: () =>
CsvExportService().exportToCsv(dashboardViewModel.items, context),
key: ValueKey('transactions_page_header_row_key'),
),
Expanded(
@@ -5,9 +5,10 @@ import 'package:cake_wallet/generated/i18n.dart';
import 'package:cake_wallet/view_model/dashboard/dashboard_view_model.dart';
class HeaderRow extends StatelessWidget {
HeaderRow({required this.dashboardViewModel, super.key});
HeaderRow({required this.dashboardViewModel, this.onExportCsv, super.key});
final DashboardViewModel dashboardViewModel;
final VoidCallback? onExportCsv;
@override
Widget build(BuildContext context) {
@@ -28,31 +29,62 @@ class HeaderRow extends StatelessWidget {
fontWeight: FontWeight.w500,
color: Theme.of(context).colorScheme.onSurface),
),
Semantics(
container: true,
child: GestureDetector(
key: ValueKey('transactions_page_header_row_transaction_filter_button_key'),
onTap: () {
showPopUp<void>(
context: context,
builder: (context) => FilterWidget(filterItems: dashboardViewModel.filterItems),
);
},
child: Semantics(
label: 'Transaction Filter',
button: true,
enabled: true,
child: Container(
height: 36,
width: 36,
decoration: BoxDecoration(
shape: BoxShape.circle,
color: Theme.of(context).colorScheme.surfaceContainer,
Row(
children: [
if (onExportCsv != null)
Padding(
padding: const EdgeInsets.only(right: 8),
child: GestureDetector(
key: ValueKey('transactions_page_header_row_export_csv_button_key'),
onTap: onExportCsv,
child: Semantics(
label: S.of(context).export_csv,
button: true,
enabled: true,
child: Container(
height: 36,
width: 36,
decoration: BoxDecoration(
shape: BoxShape.circle,
color: Theme.of(context).colorScheme.surfaceContainer,
),
child: Icon(
Icons.file_download_outlined,
color: Theme.of(context).colorScheme.onSurface,
size: 20,
),
),
),
),
),
Semantics(
container: true,
child: GestureDetector(
key: ValueKey('transactions_page_header_row_transaction_filter_button_key'),
onTap: () {
showPopUp<void>(
context: context,
builder: (context) =>
FilterWidget(filterItems: dashboardViewModel.filterItems),
);
},
child: Semantics(
label: 'Transaction Filter',
button: true,
enabled: true,
child: Container(
height: 36,
width: 36,
decoration: BoxDecoration(
shape: BoxShape.circle,
color: Theme.of(context).colorScheme.surfaceContainer,
),
child: filterIcon,
),
),
child: filterIcon,
),
),
),
],
)
],
),
+14 -2
View File
@@ -33,8 +33,20 @@ class ShareUtil {
return Rect.zero;
}
final box = context.findRenderObject() as RenderBox?;
final renderObject = context.findRenderObject();
if (renderObject is! RenderBox) {
return Rect.zero;
}
return box!.localToGlobal(Offset.zero) & box.size;
final rect = renderObject.localToGlobal(Offset.zero) & renderObject.size;
// iOS requires sharePositionOrigin to lie fully within the source view's
// bounds; clip to the screen so an offset/oversized page rect doesn't spill
// past the edge and trigger a PlatformException on iPad.
final screen = Offset.zero & MediaQuery.of(context).size;
final clipped = rect.intersect(screen);
if (clipped.isEmpty) {
return Rect.zero;
}
return clipped;
}
}
+3
View File
@@ -453,11 +453,14 @@
"expires": "ينتهي",
"expiresOn": "تنتهي في",
"expiry_and_validity": "تاريخ الانتهاء والصلاحية",
"csv_nothing_to_export": "Nothing to export",
"export_backup": "تصدير النسخة الاحتياطية",
"export_csv": "Export CSV",
"export_lightning_logs": "تصدير سجلات Lightning",
"export_logs": "تصدير السجلات",
"export_outputs": "تصدير المخرجات",
"export_payjoin_logs": "تصدير سجلات Payjoin",
"generating_csv": "Generating CSV...",
"extend_session": "تمديد الجلسة",
"external": "خارجي",
"external_wallet": "محفظة خارجية",
+3
View File
@@ -453,11 +453,14 @@
"expires": "Изтича",
"expiresOn": "Изтича на",
"expiry_and_validity": "Срок на валидност и валидност",
"csv_nothing_to_export": "Nothing to export",
"export_backup": "Експортиране на резервно копие",
"export_csv": "Export CSV",
"export_lightning_logs": "Експортиране на Lightning логове",
"export_logs": "Експортиране на логове",
"export_outputs": "Експортиране на изходи",
"export_payjoin_logs": "Експортиране на Payjoin логове",
"generating_csv": "Generating CSV...",
"extend_session": "Удължи сесията",
"external": "Външен",
"external_wallet": "Външен портфейл",
+3
View File
@@ -453,11 +453,14 @@
"expires": "Vyprší",
"expiresOn": "Vyprší dne",
"expiry_and_validity": "Vypršení platnosti",
"csv_nothing_to_export": "Nothing to export",
"export_backup": "Exportovat zálohu",
"export_csv": "Export CSV",
"export_lightning_logs": "Exportovat protokoly Lightning",
"export_logs": "Exportovat protokoly",
"export_outputs": "Exportovat výstupy",
"export_payjoin_logs": "Exportovat protokoly Payjoin",
"generating_csv": "Generating CSV...",
"extend_session": "Prodloužit relaci",
"external": "Externí",
"external_wallet": "Externí peněženka",
+3
View File
@@ -453,11 +453,14 @@
"expires": "Läuft ab",
"expiresOn": "Läuft ab am",
"expiry_and_validity": "Ablauf und Gültigkeit",
"csv_nothing_to_export": "Nothing to export",
"export_backup": "Backup exportieren",
"export_csv": "Export CSV",
"export_lightning_logs": "Lightning-Logs exportieren",
"export_logs": "Protokolle exportieren",
"export_outputs": "Outputs exportieren",
"export_payjoin_logs": "Payjoin-Logs exportieren",
"generating_csv": "Generating CSV...",
"extend_session": "Sitzung verlängern",
"external": "Extern",
"external_wallet": "Externe Wallet",
+3
View File
@@ -455,11 +455,14 @@
"expires": "Expires",
"expiresOn": "Expires on",
"expiry_and_validity": "Expiry and Validity",
"csv_nothing_to_export": "Nothing to export",
"export_backup": "Export backup",
"export_csv": "Export CSV",
"export_lightning_logs": "Export Lightning logs",
"export_logs": "Export logs",
"export_outputs": "Export outputs",
"export_payjoin_logs": "Export Payjoin logs",
"generating_csv": "Generating CSV...",
"extend_session": "Extend Session",
"external": "External",
"external_wallet": "External wallet",
+3
View File
@@ -453,11 +453,14 @@
"expires": "Caduca",
"expiresOn": "Caduca el",
"expiry_and_validity": "Caducidad y validez",
"csv_nothing_to_export": "Nothing to export",
"export_backup": "Exportar copia de seguridad",
"export_csv": "Export CSV",
"export_lightning_logs": "Exportar registros de Lightning",
"export_logs": "Exportar registros",
"export_outputs": "Exportar salidas",
"export_payjoin_logs": "Exportar registros de Payjoin",
"generating_csv": "Generating CSV...",
"extend_session": "Extender sesión",
"external": "Externo",
"external_wallet": "Billetera externa",
+3
View File
@@ -451,11 +451,14 @@
"expires": "منقضی می‌شود",
"expiresOn": "انقضا در",
"expiry_and_validity": "انقضا و اعتبار",
"csv_nothing_to_export": "Nothing to export",
"export_backup": "صدور نسخه پشتیبان",
"export_csv": "Export CSV",
"export_lightning_logs": "خروجی گرفتن از گزارش‌های لایتنینگ",
"export_logs": "خروجی گرفتن از گزارش‌ها",
"export_outputs": "برون‌برد خروجی‌ها",
"export_payjoin_logs": "گزارش‌های Payjoin را صادر کنید",
"generating_csv": "Generating CSV...",
"extend_session": "تمدید جلسه",
"external": "خارجی",
"external_wallet": "کیف پول خارجی",
+3
View File
@@ -453,11 +453,14 @@
"expires": "Expire",
"expiresOn": "Expire le",
"expiry_and_validity": "Expiration et validité",
"csv_nothing_to_export": "Nothing to export",
"export_backup": "Exporter la sauvegarde",
"export_csv": "Export CSV",
"export_lightning_logs": "Exporter les logs Lightning",
"export_logs": "Exporter les journaux",
"export_outputs": "Exporter les sorties",
"export_payjoin_logs": "Exporter les journaux de Payjoin",
"generating_csv": "Generating CSV...",
"extend_session": "Prolonger la session",
"external": "Externe",
"external_wallet": "Portefeuille externe",
+3
View File
@@ -355,9 +355,12 @@
"expires": "Opa hag̃ua",
"expiresOn": "Opa hag̃ua",
"expiry_and_validity": "Opaha ára ha hekorã",
"csv_nothing_to_export": "Nothing to export",
"export_backup": "Emondo hag̃ua backup",
"export_csv": "Export CSV",
"export_lightning_logs": "Emondo Lightning rembiapokue",
"export_payjoin_logs": "Emondo okápe Payjoin registro-kuéra",
"generating_csv": "Generating CSV...",
"external": "Okápegua",
"external_wallet": "Billetera externa",
"extra_id": "ID extra:",
+3
View File
@@ -453,11 +453,14 @@
"expires": "Yana ƙarewa",
"expiresOn": "Yana ƙarewa a",
"expiry_and_validity": "Ranar ƙarewa da inganci",
"csv_nothing_to_export": "Nothing to export",
"export_backup": "Fitar da ajiyar baya",
"export_csv": "Export CSV",
"export_lightning_logs": "Fitar da log ɗin Lightning",
"export_logs": "Fitar da log",
"export_outputs": "Fitar da abubuwan fitarwa",
"export_payjoin_logs": "Fitar da log ɗin Payjoin",
"generating_csv": "Generating CSV...",
"extend_session": "Tsawaita Zama",
"external": "Na waje",
"external_wallet": "Wallet na waje",
+3
View File
@@ -453,11 +453,14 @@
"expires": "समाप्त होता है",
"expiresOn": "इस दिन समाप्त होता है",
"expiry_and_validity": "समाप्ति और वैधता",
"csv_nothing_to_export": "Nothing to export",
"export_backup": "बैकअप निर्यात करें",
"export_csv": "Export CSV",
"export_lightning_logs": "लाइटनिंग लॉग्स निर्यात करें",
"export_logs": "लॉग निर्यात करें",
"export_outputs": "आउटपुट निर्यात करें",
"export_payjoin_logs": "Payjoin लॉग एक्सपोर्ट करें",
"generating_csv": "Generating CSV...",
"extend_session": "सत्र बढ़ाएँ",
"external": "बाहरी",
"external_wallet": "बाहरी वॉलेट",
+3
View File
@@ -453,11 +453,14 @@
"expires": "Ističe",
"expiresOn": "Istječe",
"expiry_and_validity": "Istek i valjanost",
"csv_nothing_to_export": "Nothing to export",
"export_backup": "Izvezi sigurnosnu kopiju",
"export_csv": "Export CSV",
"export_lightning_logs": "Izvezi Lightning zapise",
"export_logs": "Izvezi zapise",
"export_outputs": "Izvoz izlaza",
"export_payjoin_logs": "Izvezi Payjoin zapise",
"generating_csv": "Generating CSV...",
"extend_session": "Produži sesiju",
"external": "Vanjski",
"external_wallet": "Vanjski novčanik",
+3
View File
@@ -453,11 +453,14 @@
"expires": "Լրանում է",
"expiresOn": "Լրանում է",
"expiry_and_validity": "Ժամկետ և վավերականություն",
"csv_nothing_to_export": "Nothing to export",
"export_backup": "Արտահանել պահուստային պատճենը",
"export_csv": "Export CSV",
"export_lightning_logs": "Արտահանել Lightning-ի տեղեկամատյանները",
"export_logs": "Արտահանել տեղեկամատյանները",
"export_outputs": "Արտահանել ելքերը",
"export_payjoin_logs": "Արտահանել Payjoin-ի մատյանները",
"generating_csv": "Generating CSV...",
"extend_session": "Երկարացնել սեսիան",
"external": "Արտաքին",
"external_wallet": "Արտաքին դրամապանակ",
+3
View File
@@ -453,11 +453,14 @@
"expires": "Kedaluwarsa",
"expiresOn": "Kedaluwarsa pada",
"expiry_and_validity": "Kedaluwarsa dan Validitas",
"csv_nothing_to_export": "Nothing to export",
"export_backup": "Ekspor cadangan",
"export_csv": "Export CSV",
"export_lightning_logs": "Ekspor log Lightning",
"export_logs": "Ekspor log",
"export_outputs": "Ekspor keluaran",
"export_payjoin_logs": "Ekspor log Payjoin",
"generating_csv": "Generating CSV...",
"extend_session": "Perpanjang Sesi",
"external": "Eksternal",
"external_wallet": "Dompet eksternal",
+3
View File
@@ -453,11 +453,14 @@
"expires": "Scade",
"expiresOn": "Scade il",
"expiry_and_validity": "Scadenza e validità",
"csv_nothing_to_export": "Nothing to export",
"export_backup": "Esporta backup",
"export_csv": "Export CSV",
"export_lightning_logs": "Esporta i log di Lightning",
"export_logs": "Esporta registri",
"export_outputs": "Esporta output",
"export_payjoin_logs": "Esporta i log Payjoin",
"generating_csv": "Generating CSV...",
"extend_session": "Estendi la sessione",
"external": "Esterno",
"external_wallet": "Portafoglio esterno",
+3
View File
@@ -453,11 +453,14 @@
"expires": "有効期限",
"expiresOn": "有効期限",
"expiry_and_validity": "有効期限と有効性",
"csv_nothing_to_export": "Nothing to export",
"export_backup": "バックアップをエクスポート",
"export_csv": "Export CSV",
"export_lightning_logs": "Lightningログをエクスポート",
"export_logs": "ログをエクスポート",
"export_outputs": "アウトプットをエクスポート",
"export_payjoin_logs": "Payjoinログをエクスポート",
"generating_csv": "Generating CSV...",
"extend_session": "セッションを延長",
"external": "外部",
"external_wallet": "外部ウォレット",
+3
View File
@@ -453,11 +453,14 @@
"expires": "만료됨",
"expiresOn": "만료일",
"expiry_and_validity": "만료 및 유효 기간",
"csv_nothing_to_export": "Nothing to export",
"export_backup": "백업 내보내기",
"export_csv": "Export CSV",
"export_lightning_logs": "Lightning 로그 내보내기",
"export_logs": "로그 내보내기",
"export_outputs": "출력 내보내기",
"export_payjoin_logs": "Payjoin 로그 내보내기",
"generating_csv": "Generating CSV...",
"extend_session": "세션 연장",
"external": "외부",
"external_wallet": "외부 지갑",
+3
View File
@@ -453,11 +453,14 @@
"expires": "သက်တမ်းကုန်ဆုံးသည်",
"expiresOn": "သက်တမ်းကုန်ဆုံးမည့်ရက်",
"expiry_and_validity": "သက်တမ်းကုန်ဆုံးရက်နှင့် အကျုံးဝင်မှု",
"csv_nothing_to_export": "Nothing to export",
"export_backup": "အရန်ကူးကို ထုတ်ယူရန်",
"export_csv": "Export CSV",
"export_lightning_logs": "Lightning မှတ်တမ်းများကို ထုတ်ယူပါ",
"export_logs": "မှတ်တမ်းများကို ထုတ်ယူရန်",
"export_outputs": "Outputs များကို ထုတ်ယူရန်",
"export_payjoin_logs": "Payjoin မှတ်တမ်းများကို တင်ပို့ပါ",
"generating_csv": "Generating CSV...",
"extend_session": "စက်ရှင် သက်တမ်းတိုးရန်",
"external": "ပြင်ပ",
"external_wallet": "ပြင်ပ Wallet",
+3
View File
@@ -451,11 +451,14 @@
"expires": "Verloopt",
"expiresOn": "Verloopt op",
"expiry_and_validity": "Vervaldatum en geldigheid",
"csv_nothing_to_export": "Nothing to export",
"export_backup": "Back-up exporteren",
"export_csv": "Export CSV",
"export_lightning_logs": "Lightning-logboeken exporteren",
"export_logs": "Exporteer logboeken",
"export_outputs": "Outputs exporteren",
"export_payjoin_logs": "Payjoin-logboeken exporteren",
"generating_csv": "Generating CSV...",
"extend_session": "Sessie verlengen",
"external": "Extern",
"external_wallet": "Externe wallet",
+3
View File
@@ -452,11 +452,14 @@
"expires": "Wygasa",
"expiresOn": "Wygasa",
"expiry_and_validity": "Termin ważności i ważność",
"csv_nothing_to_export": "Nothing to export",
"export_backup": "Eksportuj kopię zapasową",
"export_csv": "Export CSV",
"export_lightning_logs": "Eksportuj logi Lightning",
"export_logs": "Eksportuj logi",
"export_outputs": "Eksportuj wyjścia",
"export_payjoin_logs": "Eksportuj logi Payjoin",
"generating_csv": "Generating CSV...",
"extend_session": "Przedłuż sesję",
"external": "Zewnętrzny",
"external_wallet": "Zewnętrzny portfel",
+3
View File
@@ -453,11 +453,14 @@
"expires": "Expira",
"expiresOn": "Expira em",
"expiry_and_validity": "Expiração e validade",
"csv_nothing_to_export": "Nothing to export",
"export_backup": "Exportar backup",
"export_csv": "Export CSV",
"export_lightning_logs": "Exportar logs do Lightning",
"export_logs": "Exportar logs",
"export_outputs": "Exportar saídas",
"export_payjoin_logs": "Exportar logs do Payjoin",
"generating_csv": "Generating CSV...",
"extend_session": "Estender sessão",
"external": "Externo",
"external_wallet": "Carteira externa",
+3
View File
@@ -451,11 +451,14 @@
"expires": "Expira",
"expiresOn": "Expira em",
"expiry_and_validity": "Expiração e Validade",
"csv_nothing_to_export": "Nothing to export",
"export_backup": "Exportar backup",
"export_csv": "Export CSV",
"export_lightning_logs": "Exportar logs do Lightning",
"export_logs": "Exportar logs",
"export_outputs": "Exportar saídas",
"export_payjoin_logs": "Exportar logs do Payjoin",
"generating_csv": "Generating CSV...",
"extend_session": "Estender sessão",
"external": "Externo",
"external_wallet": "Carteira externa",
+3
View File
@@ -453,11 +453,14 @@
"expires": "Истекает",
"expiresOn": "Истекает",
"expiry_and_validity": "Срок действия и действительность",
"csv_nothing_to_export": "Nothing to export",
"export_backup": "Экспорт резервной копии",
"export_csv": "Export CSV",
"export_lightning_logs": "Экспорт логов Lightning",
"export_logs": "Экспорт журналов",
"export_outputs": "Экспорт выходов",
"export_payjoin_logs": "Экспорт журналов Payjoin",
"generating_csv": "Generating CSV...",
"extend_session": "Продлить сессию",
"external": "Внешний",
"external_wallet": "Внешний кошелёк",
+3
View File
@@ -453,11 +453,14 @@
"expires": "หมดอายุ",
"expiresOn": "หมดอายุวันที่",
"expiry_and_validity": "วันหมดอายุและระยะเวลาที่มีผล",
"csv_nothing_to_export": "Nothing to export",
"export_backup": "ส่งออกข้อมูลสำรอง",
"export_csv": "Export CSV",
"export_lightning_logs": "ส่งออกล็อก Lightning",
"export_logs": "ส่งออกบันทึก",
"export_outputs": "ส่งออกเอาต์พุต",
"export_payjoin_logs": "ส่งออกล็อก Payjoin",
"generating_csv": "Generating CSV...",
"extend_session": "ขยายเซสชัน",
"external": "ภายนอก",
"external_wallet": "กระเป๋าเงินภายนอก",
+3
View File
@@ -453,11 +453,14 @@
"expires": "Mag-e-expire",
"expiresOn": "Mag-e-expire sa",
"expiry_and_validity": "Pag-expire at Pagiging Balido",
"csv_nothing_to_export": "Nothing to export",
"export_backup": "I-export ang backup",
"export_csv": "Export CSV",
"export_lightning_logs": "I-export ang mga log ng Lightning",
"export_logs": "I-export ang mga log",
"export_outputs": "I-export ang mga output",
"export_payjoin_logs": "I-export ang mga Payjoin log",
"generating_csv": "Generating CSV...",
"extend_session": "Palawigin ang session",
"external": "Panlabas",
"external_wallet": "Panlabas na wallet",
+3
View File
@@ -453,11 +453,14 @@
"expires": "Sona erme tarihi",
"expiresOn": "Şu tarihte sona erer",
"expiry_and_validity": "Son Kullanma ve Geçerlilik",
"csv_nothing_to_export": "Nothing to export",
"export_backup": "Yedeklemeyi dışa aktar",
"export_csv": "Export CSV",
"export_lightning_logs": "Lightning günlüklerini dışa aktar",
"export_logs": "Günlükleri dışa aktar",
"export_outputs": "Çıktıları dışa aktar",
"export_payjoin_logs": "Payjoin günlüklerini dışa aktar",
"generating_csv": "Generating CSV...",
"extend_session": "Oturumu Uzat",
"external": "Harici",
"external_wallet": "Harici cüzdan",
+3
View File
@@ -453,11 +453,14 @@
"expires": "Термін дії закінчується",
"expiresOn": "Дійсний до",
"expiry_and_validity": "Термін дії та чинність",
"csv_nothing_to_export": "Nothing to export",
"export_backup": "Експортувати резервну копію",
"export_csv": "Export CSV",
"export_lightning_logs": "Експортувати логи Lightning",
"export_logs": "Експорт журналів",
"export_outputs": "Експорт виходів",
"export_payjoin_logs": "Експорт журналів Payjoin",
"generating_csv": "Generating CSV...",
"extend_session": "Подовжити сеанс",
"external": "Зовнішній",
"external_wallet": "Зовнішній гаманець",
+3
View File
@@ -453,11 +453,14 @@
"expires": "میعاد ختم ہوتا ہے",
"expiresOn": "میعاد ختم ہونے کی تاریخ",
"expiry_and_validity": "میعادِ ختم اور درستگی",
"csv_nothing_to_export": "Nothing to export",
"export_backup": "بیک اپ ایکسپورٹ کریں",
"export_csv": "Export CSV",
"export_lightning_logs": "لائٹننگ لاگز برآمد کریں",
"export_logs": "لاگز برآمد کریں",
"export_outputs": "آؤٹ پٹس ایکسپورٹ کریں",
"export_payjoin_logs": "Payjoin لاگز ایکسپورٹ کریں",
"generating_csv": "Generating CSV...",
"extend_session": "سیشن میں توسیع کریں",
"external": "بیرونی",
"external_wallet": "بیرونی والیٹ",
+3
View File
@@ -452,11 +452,14 @@
"expires": "Hết hạn",
"expiresOn": "Hết hạn vào",
"expiry_and_validity": "Thời hạn và hiệu lực",
"csv_nothing_to_export": "Nothing to export",
"export_backup": "Xuất bản sao lưu",
"export_csv": "Export CSV",
"export_lightning_logs": "Xuất nhật ký Lightning",
"export_logs": "Xuất nhật ký",
"export_outputs": "Xuất đầu ra",
"export_payjoin_logs": "Xuất nhật ký Payjoin",
"generating_csv": "Generating CSV...",
"extend_session": "Gia hạn phiên",
"external": "Bên ngoài",
"external_wallet": "Ví ngoài",
+3
View File
@@ -454,11 +454,14 @@
"expires": "Yóò parí",
"expiresOn": "Yóò parí ní",
"expiry_and_validity": "Ọjọ́ ìparí àti ìmúlò",
"csv_nothing_to_export": "Nothing to export",
"export_backup": "Gbé ẹ̀dà àfipamọ́ jáde",
"export_csv": "Export CSV",
"export_lightning_logs": "Gbe àwọn àkọọlẹ Lightning jáde",
"export_logs": "Gbe àwọn ìwé-àkọsílẹ̀ jáde",
"export_outputs": "Gbe àwọn output jáde",
"export_payjoin_logs": "Gbejade àwọn ìkọ̀ọ́lẹ̀ Payjoin",
"generating_csv": "Generating CSV...",
"extend_session": "Fa igba iṣẹ́ pọ̀ síi",
"external": "Ita",
"external_wallet": "Apamọwọ ita",
+3
View File
@@ -453,11 +453,14 @@
"expires": "到期",
"expiresOn": "到期于",
"expiry_and_validity": "有效期和有效性",
"csv_nothing_to_export": "Nothing to export",
"export_backup": "导出备份",
"export_csv": "Export CSV",
"export_lightning_logs": "导出 Lightning 日志",
"export_logs": "导出日志",
"export_outputs": "导出输出",
"export_payjoin_logs": "导出 Payjoin 日志",
"generating_csv": "Generating CSV...",
"extend_session": "延长会话",
"external": "外部",
"external_wallet": "外部钱包",
+3
View File
@@ -392,11 +392,14 @@
"expires": "到期",
"expiresOn": "到期日",
"expiry_and_validity": "到期與有效性",
"csv_nothing_to_export": "Nothing to export",
"export_backup": "匯出備份",
"export_csv": "Export CSV",
"export_lightning_logs": "匯出 Lightning 記錄",
"export_logs": "匯出記錄",
"export_outputs": "匯出輸出項",
"export_payjoin_logs": "匯出 Payjoin 日誌",
"generating_csv": "Generating CSV...",
"extend_session": "延長登入階段",
"extra_id": "額外 ID:",
"extracted_address_content": "您將發送資金至\n${recipient_name}",