From 7c97e9032439d39bc70c0a4f86fcf1c034b4d151 Mon Sep 17 00:00:00 2001 From: KraXen72 Date: Mon, 22 Apr 2024 21:47:43 +0200 Subject: [PATCH] I18n improvements (#63) Co-authored-by: minibits-cash Co-authored-by: deerwhisper2310 <142937144+deerwhisper2310@users.noreply.github.com> --- README.md | 2 +- src/i18n/en.ts | 109 ++++- src/i18n/translate.ts | 35 +- src/screens/BackupScreen.tsx | 3 +- src/screens/Contacts/OwnName.tsx | 39 +- src/screens/Contacts/PrivateContacts.tsx | 245 +++++----- src/screens/Contacts/ProfileHeader.tsx | 3 +- src/screens/Contacts/PublicContacts.tsx | 41 +- src/screens/Contacts/RandomName.tsx | 239 +++++----- .../PaymentRequests/IncomingRequests.tsx | 2 +- .../PaymentRequests/OutgoingRequests.tsx | 17 +- .../PaymentRequestListItem.tsx | 445 +++++++++++------- .../Transactions/TransactionListItem.tsx | 419 ++++++++++------- src/screens/Wallet/FeeBadge.tsx | 87 ++-- 14 files changed, 1015 insertions(+), 671 deletions(-) diff --git a/README.md b/README.md index b988fbe9..49fc80b6 100644 --- a/README.md +++ b/README.md @@ -137,7 +137,7 @@ Minibits wallet is in early beta and available as of now only for Android device Minibits is a bare React Native app written in Typescript. The project structure and code itself are intentionally verbose to support readability. Critical wallet code is reasonably documented. However, there is vast space for existing code improvements, refactoring, and bug fixing. This is an early beta software and the author does not code for a living. -The code is derived from Ignite template, however with many libraries, notably Expo, stripped down to achieve fast startup times. Performance bottleneck on some Android devices is react-native-keychain. To overcome this, it has been patched not to warm-up on startup, caching for wallet operatoions is in place and its use to encrypt storage is opt-in. +The code is derived from Ignite template, however with many libraries, notably Expo, stripped down to achieve fast startup times. Performance bottleneck on some Android devices is react-native-keychain. To overcome this, it has been patched not to warm-up on startup, caching for wallet operations is in place and its use to encrypt storage is opt-in. Wallet state is managed by mobx-state-tree and persisted in fast MMKV storage. Only the basic mobx concepts are in place, whole model could be improved. All critical wallet code is in services/walletService.ts and all ecash state changes are in models/ProofsStore.ts. Wallet communication with the mints is in services/cashuMintClient.ts and uses [cashu-ts](https://github.com/cashubtc/cashu-ts) library. diff --git a/src/i18n/en.ts b/src/i18n/en.ts index 3f2f824d..26370082 100644 --- a/src/i18n/en.ts +++ b/src/i18n/en.ts @@ -7,11 +7,47 @@ const en = { paste: "Paste", scan: "Scan", copy: "Copy", + copyFailParam: "Couldn't copy %{param}", confirm: "Confirm", save: "Save", add: "Add", + success: "Success!", offline: "Offline", + qr: "QR Code", + sats: "SATS", + notCreated: 'Not yet created', + resetDefault: 'Reset to default', + share: "Share", }, + paymentCommon: { + pay: "Pay", + payMe: 'Pay me', + paySatsAmountTo: "Pay %{amount} SATS to", + payFromWallet: 'Pay from wallet', + receiveInPerson: "Receive in person" + }, + transactionCommon: { + from: "From %{sender}", + receivedFrom: "Received from %{sender}", + sentTo: "Sent to %{receiver}", + paidTo: "Paid to %{receiver}", + youReceived: 'You received', + youSent: 'You sent', + youPaid: 'You paid', + unknown: 'Unknown transaction', + status: { + completedFee: 'Completed %{fee}', + draft: 'Draft', + error: 'Error', + pending: 'Pending', + prepared: 'Prepared', + reverted: 'Reverted', + blocked: 'Blocked', + expired: 'Expired' + }, + tapToRedeem: 'Tap to redeem', + redeemOnline: 'Redeem online' + }, welcomeScreen: { page1: { heading: "Welcome", @@ -48,6 +84,10 @@ const en = { topUpWalletSubText: "Top up your balance by paying Bitcoin lightning invoice from another wallet", transferFromWallet: "Transfer from wallet", transferFromWalletSubText: "Debit your balance by paying Bitcoin lightning invoice from this wallet", + feeBadge: { + final: "+ final fee %{fee} SATS", + upto: "+ fee up to %{fee} SATS" + } }, receiveScreen: { title: "Receive", @@ -112,8 +152,75 @@ const en = { contactsScreen: { new: "New", scan: "Scan", - newTitle: "Add new contact", + newTitle: "Add new contact", + getInvoice: "Get invoice", + ownName: { + donationSuccess: "Thank you! Donation for %{receiver} has been successfully paid.", + tooShort: 'Write your wallet profile name to the text box, use min 2 characters.', + illegalChar: 'Do not use . or - characters at the beginning or the end of name.', + profileExists: 'This wallet name is already in use, choose another one.', + chooseOwnName: 'Choose your own name', + chooseOwnNameFooter: 'Use lowercase letters, numbers and .-_', + available: "%{name} is available!", + payToGetOwnName: "Pay the following lightning invoice and get your %{name} wallet name.", + ctaPay: "Pay from wallet", + insufficient: 'Your wallet balance is not enough to pay this invoice amount but you can still pay it from another wallet.', + betaWarning: 'Please accept this is an early beta software. Your data can still be lost due to a bug or unexpected data loss.' + }, + privateContacts: { + selectSendPaymentRequest: 'Select contact to send your payment request to.', + selectSendToken: 'Select contact to send your ecash to.', + selectSendLnURL: 'Select contact to send Lightning payment to.', + saveNewFormat: "Please enter a wallet address in name@domain.xyz format", + profileNotFound: "Profile name %{name} could not be found. Make sure the name is correct.", + noLightningAddress: 'This contact does not have a Lightning address, send ecash instead.', + explainerText: "Private contacts", + explainerSubText: "Add other Minibits users as your private contacts. Every user gets sharable @minibits.cash wallet address. You can pay privately to your contacts anytime even if they are offline.", + switchName: "Switch your wallet name and picture?", + switchNameSubText: 'Get cooler wallet name or profile picture. Select from an array of random names and images or opt for your own @minibits.cash wallet name.', + bottomModal: "Private contacts are unique identifiers of other Minibits wallets. You can use them to send or request ecash and you can safely share your own with others.", + domainMinibits: "Use minibits.cash domain", + domainExternal: "Use another domain" + }, + publicContacts: { + npubPasteError: 'Copy your NPUB key first, then paste', + relayurlPasteError: 'Copy your relay URL key first, then paste', + relayExists: 'Relay already exists.', + missingLightningAddress: 'This contact does not have a Lightning address, send ecash instead.', + nostrTip: 'Tip the people you follow', + nostrTipSubText: 'Add your NOSTR social network public key (npub) and tip or donate to your favourite people and projects directly from the minibits wallet.', + nostrSetPublicKey: 'Set your public key', + nostrSetPublicKeySubText: 'Add or change your NOSTR social network public key (npub).', + nostrSetRelay: 'Set relay', + nostrSetRelaySubText: 'Add or change your own relay if your profile and follows are not hosted on the default relays.', + nostrRemovePub: 'Remove your public key', + nostrRemovePubSubText: 'Remove your npub key and stop loading public contacts.', + addNpub: 'Add your npub key', + pasteDemoKey: 'Paste demo key', + setOwnRelay: 'Set your own relay' + }, + randomName: { + selectOneOfUsernames: 'Select one of the usernames' + } }, + paymentRequestScreen: { + incoming: { + noRequests: 'There are no incoming payment requests to be paid or they have already expired.' + }, + outgoing: { + noRequests: 'There are no outgoing payment requests to be paid or they have already expired.', + invoiceShared: 'Lightning invoice has been shared, waiting to be paid by receiver.', + sharingCancelled: 'Sharing cancelled', + scanAndPay: 'Scan and pay to top-up' + }, + // might move this to common later if it gets used in other screens + listItem: { + expires: "Expires %{datetime}", + expired: "Expired %{datetime}", + requestPaymentSuccess: 'Request has been paid' + } + }, + profileScreen: { changeAvatar: "Change picture", changeAvatarSubtext: "Select one from randomly generated pictures.", diff --git a/src/i18n/translate.ts b/src/i18n/translate.ts index ae6aebab..2a82e8fe 100644 --- a/src/i18n/translate.ts +++ b/src/i18n/translate.ts @@ -1,7 +1,6 @@ - -import { I18nOptions } from "i18n-js" -import { i18n } from "./i18n" -import { TxKeyPath } from "./i18n" +import {I18nOptions} from 'i18n-js' +import {i18n} from './i18n' +import {TxKeyPath} from './i18n' /** * Translates text. @@ -12,21 +11,29 @@ import { TxKeyPath } from "./i18n" * * @example * Translations: - * - * ```en.ts + * ```ts + * // en.ts * { - * "hello": "Hello, {{name}}!" + * "heading": "Welcome to the app!", + * "buttonText": "Donate", + * "greeting": "Hello, %{name}!" // parameter * } * ``` - * * Usage: - * ```ts - * import { translate } from "i18n-js" + * ```tsx + * import { translate } from "../../i18n"; + * // or whatever the path is, let it auto-import * - * translate("common.ok", { name: "world" }) - * // => "Hello world!" + * translate("heading") // => Welcome to the app! + * translate("greeting", { name: "world" }) // => Hello world! + *