commit
798988597b
@ -0,0 +1,202 @@ |
|||||||
|
version: 2 |
||||||
|
|
||||||
|
workflows: |
||||||
|
version: 2 |
||||||
|
full_test: |
||||||
|
jobs: |
||||||
|
- prep-deps-npm |
||||||
|
- prep-deps-firefox |
||||||
|
- prep-scss: |
||||||
|
requires: |
||||||
|
- prep-deps-npm |
||||||
|
- test-lint: |
||||||
|
requires: |
||||||
|
- prep-deps-npm |
||||||
|
- test-unit: |
||||||
|
requires: |
||||||
|
- prep-deps-npm |
||||||
|
- test-integration-mascara-chrome: |
||||||
|
requires: |
||||||
|
- prep-deps-npm |
||||||
|
- prep-scss |
||||||
|
- test-integration-mascara-firefox: |
||||||
|
requires: |
||||||
|
- prep-deps-npm |
||||||
|
- prep-deps-firefox |
||||||
|
- prep-scss |
||||||
|
- test-integration-flat-chrome: |
||||||
|
requires: |
||||||
|
- prep-deps-npm |
||||||
|
- prep-scss |
||||||
|
- test-integration-flat-firefox: |
||||||
|
requires: |
||||||
|
- prep-deps-npm |
||||||
|
- prep-deps-firefox |
||||||
|
- prep-scss |
||||||
|
|
||||||
|
jobs: |
||||||
|
prep-deps-npm: |
||||||
|
docker: |
||||||
|
- image: circleci/node:8-browsers |
||||||
|
steps: |
||||||
|
- checkout |
||||||
|
- restore_cache: |
||||||
|
key: dependency-cache-{{ checksum "package-lock.json" }} |
||||||
|
- run: |
||||||
|
name: Install deps via npm |
||||||
|
command: npm install |
||||||
|
- save_cache: |
||||||
|
key: dependency-cache-{{ checksum "package-lock.json" }} |
||||||
|
paths: |
||||||
|
- node_modules |
||||||
|
|
||||||
|
prep-deps-firefox: |
||||||
|
docker: |
||||||
|
- image: circleci/node:8-browsers |
||||||
|
steps: |
||||||
|
- checkout |
||||||
|
- run: |
||||||
|
name: Download Firefox |
||||||
|
command: > |
||||||
|
wget https://ftp.mozilla.org/pub/firefox/releases/58.0/linux-x86_64/en-US/firefox-58.0.tar.bz2 |
||||||
|
&& tar xjf firefox-58.0.tar.bz2 |
||||||
|
- save_cache: |
||||||
|
key: dependency-cache-firefox-{{ .Revision }} |
||||||
|
paths: |
||||||
|
- firefox |
||||||
|
|
||||||
|
|
||||||
|
prep-scss: |
||||||
|
docker: |
||||||
|
- image: circleci/node:8-browsers |
||||||
|
steps: |
||||||
|
- checkout |
||||||
|
- restore_cache: |
||||||
|
key: dependency-cache-{{ checksum "package-lock.json" }} |
||||||
|
- run: |
||||||
|
name: Get Scss Cache key |
||||||
|
# this allows us to checksum against a whole directory |
||||||
|
command: find ui/app/css -type f -exec md5sum {} \; | sort -k 2 > scss_checksum |
||||||
|
- run: |
||||||
|
name: Build for integration tests |
||||||
|
command: npm run test:integration:build |
||||||
|
- save_cache: |
||||||
|
key: scss-cache-{{ checksum "scss_checksum" }} |
||||||
|
paths: |
||||||
|
- ui/app/css/output |
||||||
|
|
||||||
|
test-lint: |
||||||
|
docker: |
||||||
|
- image: circleci/node:8-browsers |
||||||
|
steps: |
||||||
|
- checkout |
||||||
|
- restore_cache: |
||||||
|
key: dependency-cache-{{ checksum "package-lock.json" }} |
||||||
|
- run: |
||||||
|
name: Test |
||||||
|
command: npm run lint |
||||||
|
|
||||||
|
test-unit: |
||||||
|
docker: |
||||||
|
- image: circleci/node:8-browsers |
||||||
|
steps: |
||||||
|
- checkout |
||||||
|
- restore_cache: |
||||||
|
key: dependency-cache-{{ checksum "package-lock.json" }} |
||||||
|
- run: |
||||||
|
name: test:coverage |
||||||
|
command: npm run test:coverage |
||||||
|
|
||||||
|
test-integration-flat-firefox: |
||||||
|
environment: |
||||||
|
browsers: '["Firefox"]' |
||||||
|
docker: |
||||||
|
- image: circleci/node:8-browsers |
||||||
|
steps: |
||||||
|
- checkout |
||||||
|
- restore_cache: |
||||||
|
key: dependency-cache-firefox-{{ .Revision }} |
||||||
|
- run: |
||||||
|
name: Install firefox |
||||||
|
command: > |
||||||
|
sudo rm -r /opt/firefox |
||||||
|
&& sudo mv firefox /opt/firefox58 |
||||||
|
&& sudo mv /usr/bin/firefox /usr/bin/firefox-old |
||||||
|
&& sudo ln -s /opt/firefox58/firefox /usr/bin/firefox |
||||||
|
- restore_cache: |
||||||
|
key: dependency-cache-{{ checksum "package-lock.json" }} |
||||||
|
- run: |
||||||
|
name: Get Scss Cache key |
||||||
|
# this allows us to checksum against a whole directory |
||||||
|
command: find ui/app/css -type f -exec md5sum {} \; | sort -k 2 > scss_checksum |
||||||
|
- restore_cache: |
||||||
|
key: scss-cache-{{ checksum "scss_checksum" }} |
||||||
|
- run: |
||||||
|
name: test:integration:flat |
||||||
|
command: npm run test:flat |
||||||
|
|
||||||
|
test-integration-flat-chrome: |
||||||
|
environment: |
||||||
|
browsers: '["Chrome"]' |
||||||
|
docker: |
||||||
|
- image: circleci/node:8-browsers |
||||||
|
steps: |
||||||
|
- checkout |
||||||
|
- restore_cache: |
||||||
|
key: dependency-cache-{{ checksum "package-lock.json" }} |
||||||
|
- run: |
||||||
|
name: Get Scss Cache key |
||||||
|
# this allows us to checksum against a whole directory |
||||||
|
command: find ui/app/css -type f -exec md5sum {} \; | sort -k 2 > scss_checksum |
||||||
|
- restore_cache: |
||||||
|
key: scss-cache-{{ checksum "scss_checksum" }} |
||||||
|
- run: |
||||||
|
name: test:integration:flat |
||||||
|
command: npm run test:flat |
||||||
|
|
||||||
|
test-integration-mascara-firefox: |
||||||
|
environment: |
||||||
|
browsers: '["Firefox"]' |
||||||
|
docker: |
||||||
|
- image: circleci/node:8-browsers |
||||||
|
steps: |
||||||
|
- checkout |
||||||
|
- restore_cache: |
||||||
|
key: dependency-cache-firefox-{{ .Revision }} |
||||||
|
- run: |
||||||
|
name: Install firefox |
||||||
|
command: > |
||||||
|
sudo rm -r /opt/firefox |
||||||
|
&& sudo mv firefox /opt/firefox58 |
||||||
|
&& sudo mv /usr/bin/firefox /usr/bin/firefox-old |
||||||
|
&& sudo ln -s /opt/firefox58/firefox /usr/bin/firefox |
||||||
|
- restore_cache: |
||||||
|
key: dependency-cache-{{ checksum "package-lock.json" }} |
||||||
|
- run: |
||||||
|
name: Get Scss Cache key |
||||||
|
# this allows us to checksum against a whole directory |
||||||
|
command: find ui/app/css -type f -exec md5sum {} \; | sort -k 2 > scss_checksum |
||||||
|
- restore_cache: |
||||||
|
key: scss-cache-{{ checksum "scss_checksum" }} |
||||||
|
- run: |
||||||
|
name: test:integration:mascara |
||||||
|
command: npm run test:mascara |
||||||
|
|
||||||
|
test-integration-mascara-chrome: |
||||||
|
environment: |
||||||
|
browsers: '["Chrome"]' |
||||||
|
docker: |
||||||
|
- image: circleci/node:8-browsers |
||||||
|
steps: |
||||||
|
- checkout |
||||||
|
- restore_cache: |
||||||
|
key: dependency-cache-{{ checksum "package-lock.json" }} |
||||||
|
- run: |
||||||
|
name: Get Scss Cache key |
||||||
|
# this allows us to checksum against a whole directory |
||||||
|
command: find ui/app/css -type f -exec md5sum {} \; | sort -k 2 > scss_checksum |
||||||
|
- restore_cache: |
||||||
|
key: scss-cache-{{ checksum "scss_checksum" }} |
||||||
|
- run: |
||||||
|
name: test:integration:mascara |
||||||
|
command: npm run test:mascara |
@ -0,0 +1,3 @@ |
|||||||
|
{ |
||||||
|
"exceptions": ["https://nodesecurity.io/advisories/566"] |
||||||
|
} |
@ -1,10 +1,609 @@ |
|||||||
{ |
{ |
||||||
|
"accept": { |
||||||
|
"message": "Accept" |
||||||
|
}, |
||||||
|
"account": { |
||||||
|
"message": "Account" |
||||||
|
}, |
||||||
|
"accountDetails": { |
||||||
|
"message": "Account Details" |
||||||
|
}, |
||||||
|
"accountName": { |
||||||
|
"message": "Account Name" |
||||||
|
}, |
||||||
|
"address": { |
||||||
|
"message": "Address" |
||||||
|
}, |
||||||
|
"addToken": { |
||||||
|
"message": "Add Token" |
||||||
|
}, |
||||||
|
"amount": { |
||||||
|
"message": "Amount" |
||||||
|
}, |
||||||
|
"amountPlusGas": { |
||||||
|
"message": "Amount + Gas" |
||||||
|
}, |
||||||
|
"appDescription": { |
||||||
|
"message": "Ethereum Browser Extension", |
||||||
|
"description": "The description of the application" |
||||||
|
}, |
||||||
"appName": { |
"appName": { |
||||||
"message": "MetaMask", |
"message": "MetaMask", |
||||||
"description": "The name of the application" |
"description": "The name of the application" |
||||||
}, |
}, |
||||||
"appDescription": { |
"attemptingConnect": { |
||||||
"message": "Ethereum Identity Management", |
"message": "Attempting to connect to blockchain." |
||||||
"description": "The description of the application" |
}, |
||||||
|
"available": { |
||||||
|
"message": "Available" |
||||||
|
}, |
||||||
|
"back": { |
||||||
|
"message": "Back" |
||||||
|
}, |
||||||
|
"balance": { |
||||||
|
"message": "Balance:" |
||||||
|
}, |
||||||
|
"balanceIsInsufficientGas": { |
||||||
|
"message": "Insufficient balance for current gas total" |
||||||
|
}, |
||||||
|
"beta": { |
||||||
|
"message": "BETA" |
||||||
|
}, |
||||||
|
"betweenMinAndMax": { |
||||||
|
"message": "must be greater than or equal to $1 and less than or equal to $2.", |
||||||
|
"description": "helper for inputting hex as decimal input" |
||||||
|
}, |
||||||
|
"borrowDharma": { |
||||||
|
"message": "Borrow With Dharma (Beta)" |
||||||
|
}, |
||||||
|
"buy": { |
||||||
|
"message": "Buy" |
||||||
|
}, |
||||||
|
"buyCoinbase": { |
||||||
|
"message": "Buy on Coinbase" |
||||||
|
}, |
||||||
|
"buyCoinbaseExplainer": { |
||||||
|
"message": "Coinbase is the world’s most popular way to buy and sell bitcoin, ethereum, and litecoin." |
||||||
|
}, |
||||||
|
"cancel": { |
||||||
|
"message": "Cancel" |
||||||
|
}, |
||||||
|
"clickCopy": { |
||||||
|
"message": "Click to Copy" |
||||||
|
}, |
||||||
|
"confirm": { |
||||||
|
"message": "Confirm" |
||||||
|
}, |
||||||
|
"confirmContract": { |
||||||
|
"message": "Confirm Contract" |
||||||
|
}, |
||||||
|
"confirmPassword": { |
||||||
|
"message": "Confirm Password" |
||||||
|
}, |
||||||
|
"confirmTransaction": { |
||||||
|
"message": "Confirm Transaction" |
||||||
|
}, |
||||||
|
"continueToCoinbase": { |
||||||
|
"message": "Continue to Coinbase" |
||||||
|
}, |
||||||
|
"contractDeployment": { |
||||||
|
"message": "Contract Deployment" |
||||||
|
}, |
||||||
|
"conversionProgress": { |
||||||
|
"message": "Conversion in progress" |
||||||
|
}, |
||||||
|
"copiedButton": { |
||||||
|
"message": "Copied" |
||||||
|
}, |
||||||
|
"copiedClipboard": { |
||||||
|
"message": "Copied to Clipboard" |
||||||
|
}, |
||||||
|
"copiedExclamation": { |
||||||
|
"message": "Copied!" |
||||||
|
}, |
||||||
|
"copy": { |
||||||
|
"message": "Copy" |
||||||
|
}, |
||||||
|
"copyToClipboard": { |
||||||
|
"message": "Copy to clipboard" |
||||||
|
}, |
||||||
|
"copyButton": { |
||||||
|
"message": " Copy " |
||||||
|
}, |
||||||
|
"copyPrivateKey": { |
||||||
|
"message": "This is your private key (click to copy)" |
||||||
|
}, |
||||||
|
"create": { |
||||||
|
"message": "Create" |
||||||
|
}, |
||||||
|
"createAccount": { |
||||||
|
"message": "Create Account" |
||||||
|
}, |
||||||
|
"createDen": { |
||||||
|
"message": "Create" |
||||||
|
}, |
||||||
|
"crypto": { |
||||||
|
"message": "Crypto", |
||||||
|
"description": "Exchange type (cryptocurrencies)" |
||||||
|
}, |
||||||
|
"customGas": { |
||||||
|
"message": "Customize Gas" |
||||||
|
}, |
||||||
|
"customize": { |
||||||
|
"message": "Customize" |
||||||
|
}, |
||||||
|
"customRPC": { |
||||||
|
"message": "Custom RPC" |
||||||
|
}, |
||||||
|
"defaultNetwork": { |
||||||
|
"message": "The default network for Ether transactions is Main Net." |
||||||
|
}, |
||||||
|
"denExplainer": { |
||||||
|
"message": "Your DEN is your password-encrypted storage within MetaMask." |
||||||
|
}, |
||||||
|
"deposit": { |
||||||
|
"message": "Deposit" |
||||||
|
}, |
||||||
|
"depositBTC": { |
||||||
|
"message": "Deposit your BTC to the address below:" |
||||||
|
}, |
||||||
|
"depositCoin": { |
||||||
|
"message": "Deposit your $1 to the address below", |
||||||
|
"description": "Tells the user what coin they have selected to deposit with shapeshift" |
||||||
|
}, |
||||||
|
"depositEth": { |
||||||
|
"message": "Deposit Eth" |
||||||
|
}, |
||||||
|
"depositEther": { |
||||||
|
"message": "Deposit Ether" |
||||||
|
}, |
||||||
|
"depositFiat": { |
||||||
|
"message": "Deposit with Fiat" |
||||||
|
}, |
||||||
|
"depositFromAccount": { |
||||||
|
"message": "Deposit from another account" |
||||||
|
}, |
||||||
|
"depositShapeShift": { |
||||||
|
"message": "Deposit with ShapeShift" |
||||||
|
}, |
||||||
|
"depositShapeShiftExplainer": { |
||||||
|
"message": "If you own other cryptocurrencies, you can trade and deposit Ether directly into your MetaMask wallet. No Account Needed." |
||||||
|
}, |
||||||
|
"details": { |
||||||
|
"message": "Details" |
||||||
|
}, |
||||||
|
"directDeposit": { |
||||||
|
"message": "Direct Deposit" |
||||||
|
}, |
||||||
|
"directDepositEther": { |
||||||
|
"message": "Directly Deposit Ether" |
||||||
|
}, |
||||||
|
"directDepositEtherExplainer": { |
||||||
|
"message": "If you already have some Ether, the quickest way to get Ether in your new wallet by direct deposit." |
||||||
|
}, |
||||||
|
"done": { |
||||||
|
"message": "Done" |
||||||
|
}, |
||||||
|
"edit": { |
||||||
|
"message": "Edit" |
||||||
|
}, |
||||||
|
"editAccountName": { |
||||||
|
"message": "Edit Account Name" |
||||||
|
}, |
||||||
|
"encryptNewDen": { |
||||||
|
"message": "Encrypt your new DEN" |
||||||
|
}, |
||||||
|
"enterPassword": { |
||||||
|
"message": "Enter password" |
||||||
|
}, |
||||||
|
"etherscanView": { |
||||||
|
"message": "View account on Etherscan" |
||||||
|
}, |
||||||
|
"exchangeRate": { |
||||||
|
"message": "Exchange Rate" |
||||||
|
}, |
||||||
|
"exportPrivateKey": { |
||||||
|
"message": "Export Private Key" |
||||||
|
}, |
||||||
|
"exportPrivateKeyWarning": { |
||||||
|
"message": "Export private keys at your own risk." |
||||||
|
}, |
||||||
|
"failed": { |
||||||
|
"message": "Failed" |
||||||
|
}, |
||||||
|
"fiat": { |
||||||
|
"message": "FIAT", |
||||||
|
"description": "Exchange type" |
||||||
|
}, |
||||||
|
"fileImportFail": { |
||||||
|
"message": "File import not working? Click here!", |
||||||
|
"description": "Helps user import their account from a JSON file" |
||||||
|
}, |
||||||
|
"from": { |
||||||
|
"message": "From" |
||||||
|
}, |
||||||
|
"fromShapeShift": { |
||||||
|
"message": "From ShapeShift" |
||||||
|
}, |
||||||
|
"gas": { |
||||||
|
"message": "Gas", |
||||||
|
"description": "Short indication of gas cost" |
||||||
|
}, |
||||||
|
"gasFee": { |
||||||
|
"message": "Gas Fee" |
||||||
|
}, |
||||||
|
"gasLimit": { |
||||||
|
"message": "Gas Limit" |
||||||
|
}, |
||||||
|
"gasLimitCalculation": { |
||||||
|
"message": "We calculate the suggested gas limit based on network success rates." |
||||||
|
}, |
||||||
|
"gasLimitRequired": { |
||||||
|
"message": "Gas Limit Required" |
||||||
|
}, |
||||||
|
"gasLimitTooLow": { |
||||||
|
"message": "Gas limit must be at least 21000" |
||||||
|
}, |
||||||
|
"gasPrice": { |
||||||
|
"message": "Gas Price (GWEI)" |
||||||
|
}, |
||||||
|
"gasPriceCalculation": { |
||||||
|
"message": "We calculate the suggested gas prices based on network success rates." |
||||||
|
}, |
||||||
|
"gasPriceRequired": { |
||||||
|
"message": "Gas Price Required" |
||||||
|
}, |
||||||
|
"getEther": { |
||||||
|
"message": "Get Ether" |
||||||
|
}, |
||||||
|
"getEtherFromFaucet": { |
||||||
|
"message": "Get Ether from a faucet for the $1", |
||||||
|
"description": "Displays network name for Ether faucet" |
||||||
|
}, |
||||||
|
"greaterThanMin": { |
||||||
|
"message": "must be greater than or equal to $1.", |
||||||
|
"description": "helper for inputting hex as decimal input" |
||||||
|
}, |
||||||
|
"here": { |
||||||
|
"message": "here", |
||||||
|
"description": "as in -click here- for more information (goes with troubleTokenBalances)" |
||||||
|
}, |
||||||
|
"hide": { |
||||||
|
"message": "Hide" |
||||||
|
}, |
||||||
|
"hideToken": { |
||||||
|
"message": "Hide Token" |
||||||
|
}, |
||||||
|
"hideTokenPrompt": { |
||||||
|
"message": "Hide Token?" |
||||||
|
}, |
||||||
|
"howToDeposit": { |
||||||
|
"message": "How would you like to deposit Ether?" |
||||||
|
}, |
||||||
|
"import": { |
||||||
|
"message": "Import", |
||||||
|
"description": "Button to import an account from a selected file" |
||||||
|
}, |
||||||
|
"importAccount": { |
||||||
|
"message": "Import Account" |
||||||
|
}, |
||||||
|
"importAnAccount": { |
||||||
|
"message": "Import an account" |
||||||
|
}, |
||||||
|
"importDen": { |
||||||
|
"message": "Import Existing DEN" |
||||||
|
}, |
||||||
|
"imported": { |
||||||
|
"message": "Imported", |
||||||
|
"description": "status showing that an account has been fully loaded into the keyring" |
||||||
|
}, |
||||||
|
"infoHelp": { |
||||||
|
"message": "Info & Help" |
||||||
|
}, |
||||||
|
"invalidAddress": { |
||||||
|
"message": "Invalid address" |
||||||
|
}, |
||||||
|
"invalidGasParams": { |
||||||
|
"message": "Invalid Gas Parameters" |
||||||
|
}, |
||||||
|
"invalidInput": { |
||||||
|
"message": "Invalid input." |
||||||
|
}, |
||||||
|
"invalidRequest": { |
||||||
|
"message": "Invalid Request" |
||||||
|
}, |
||||||
|
"jsonFile": { |
||||||
|
"message": "JSON File", |
||||||
|
"description": "format for importing an account" |
||||||
|
}, |
||||||
|
"kovan": { |
||||||
|
"message": "Kovan Test Network" |
||||||
|
}, |
||||||
|
"lessThanMax": { |
||||||
|
"message": "must be less than or equal to $1.", |
||||||
|
"description": "helper for inputting hex as decimal input" |
||||||
|
}, |
||||||
|
"limit": { |
||||||
|
"message": "Limit" |
||||||
|
}, |
||||||
|
"loading": { |
||||||
|
"message": "Loading..." |
||||||
|
}, |
||||||
|
"loadingTokens": { |
||||||
|
"message": "Loading Tokens..." |
||||||
|
}, |
||||||
|
"localhost": { |
||||||
|
"message": "Localhost 8545" |
||||||
|
}, |
||||||
|
"logout": { |
||||||
|
"message": "Log out" |
||||||
|
}, |
||||||
|
"loose": { |
||||||
|
"message": "Loose" |
||||||
|
}, |
||||||
|
"mainnet": { |
||||||
|
"message": "Main Ethereum Network" |
||||||
|
}, |
||||||
|
"message": { |
||||||
|
"message": "Message" |
||||||
|
}, |
||||||
|
"min": { |
||||||
|
"message": "Minimum" |
||||||
|
}, |
||||||
|
"myAccounts": { |
||||||
|
"message": "My Accounts" |
||||||
|
}, |
||||||
|
"needEtherInWallet": { |
||||||
|
"message": "To interact with decentralized applications using MetaMask, you’ll need Ether in your wallet." |
||||||
|
}, |
||||||
|
"needImportFile": { |
||||||
|
"message": "You must select a file to import.", |
||||||
|
"description": "User is important an account and needs to add a file to continue" |
||||||
|
}, |
||||||
|
"needImportPassword": { |
||||||
|
"message": "You must enter a password for the selected file.", |
||||||
|
"description": "Password and file needed to import an account" |
||||||
|
}, |
||||||
|
"networks": { |
||||||
|
"message": "Networks" |
||||||
|
}, |
||||||
|
"newAccount": { |
||||||
|
"message": "New Account" |
||||||
|
}, |
||||||
|
"newAccountNumberName": { |
||||||
|
"message": "Account $1", |
||||||
|
"description": "Default name of next account to be created on create account screen" |
||||||
|
}, |
||||||
|
"newContract": { |
||||||
|
"message": "New Contract" |
||||||
|
}, |
||||||
|
"newPassword": { |
||||||
|
"message": "New Password (min 8 chars)" |
||||||
|
}, |
||||||
|
"newRecipient": { |
||||||
|
"message": "New Recipient" |
||||||
|
}, |
||||||
|
"next": { |
||||||
|
"message": "Next" |
||||||
|
}, |
||||||
|
"noAddressForName": { |
||||||
|
"message": "No address has been set for this name." |
||||||
|
}, |
||||||
|
"noDeposits": { |
||||||
|
"message": "No deposits received" |
||||||
|
}, |
||||||
|
"noTransactionHistory": { |
||||||
|
"message": "No transaction history." |
||||||
|
}, |
||||||
|
"noTransactions": { |
||||||
|
"message": "No Transactions" |
||||||
|
}, |
||||||
|
"notStarted": { |
||||||
|
"message": "Not Started" |
||||||
|
}, |
||||||
|
"oldUI": { |
||||||
|
"message": "Old UI" |
||||||
|
}, |
||||||
|
"oldUIMessage": { |
||||||
|
"message": "You have returned to the old UI. You can switch back to the New UI through the option in the top right dropdown menu." |
||||||
|
}, |
||||||
|
"or": { |
||||||
|
"message": "or", |
||||||
|
"description": "choice between creating or importing a new account" |
||||||
|
}, |
||||||
|
"passwordMismatch": { |
||||||
|
"message": "passwords don't match", |
||||||
|
"description": "in password creation process, the two new password fields did not match" |
||||||
|
}, |
||||||
|
"passwordShort": { |
||||||
|
"message": "password not long enough", |
||||||
|
"description": "in password creation process, the password is not long enough to be secure" |
||||||
|
}, |
||||||
|
"pastePrivateKey": { |
||||||
|
"message": "Paste your private key string here:", |
||||||
|
"description": "For importing an account from a private key" |
||||||
|
}, |
||||||
|
"pasteSeed": { |
||||||
|
"message": "Paste your seed phrase here!" |
||||||
|
}, |
||||||
|
"pleaseReviewTransaction": { |
||||||
|
"message": "Please review your transaction." |
||||||
|
}, |
||||||
|
"privateKey": { |
||||||
|
"message": "Private Key", |
||||||
|
"description": "select this type of file to use to import an account" |
||||||
|
}, |
||||||
|
"privateKeyWarning": { |
||||||
|
"message": "Warning: Never disclose this key. Anyone with your private keys can take steal any assets held in your account." |
||||||
|
}, |
||||||
|
"privateNetwork": { |
||||||
|
"message": "Private Network" |
||||||
|
}, |
||||||
|
"qrCode": { |
||||||
|
"message": "Show QR Code" |
||||||
|
}, |
||||||
|
"readdToken": { |
||||||
|
"message": "You can add this token back in the future by going go to “Add token” in your accounts options menu." |
||||||
|
}, |
||||||
|
"readMore": { |
||||||
|
"message": "Read more here." |
||||||
|
}, |
||||||
|
"receive": { |
||||||
|
"message": "Receive" |
||||||
|
}, |
||||||
|
"recipientAddress": { |
||||||
|
"message": "Recipient Address" |
||||||
|
}, |
||||||
|
"refundAddress": { |
||||||
|
"message": "Your Refund Address" |
||||||
|
}, |
||||||
|
"rejected": { |
||||||
|
"message": "Rejected" |
||||||
|
}, |
||||||
|
"required": { |
||||||
|
"message": "Required" |
||||||
|
}, |
||||||
|
"retryWithMoreGas": { |
||||||
|
"message": "Retry with a higher gas price here" |
||||||
|
}, |
||||||
|
"revert": { |
||||||
|
"message": "Revert" |
||||||
|
}, |
||||||
|
"rinkeby": { |
||||||
|
"message": "Rinkeby Test Network" |
||||||
|
}, |
||||||
|
"ropsten": { |
||||||
|
"message": "Ropsten Test Network" |
||||||
|
}, |
||||||
|
"sampleAccountName": { |
||||||
|
"message": "E.g. My new account", |
||||||
|
"description": "Help user understand concept of adding a human-readable name to their account" |
||||||
|
}, |
||||||
|
"save": { |
||||||
|
"message": "Save" |
||||||
|
}, |
||||||
|
"saveAsFile": { |
||||||
|
"message": "Save as File", |
||||||
|
"description": "Account export process" |
||||||
|
}, |
||||||
|
"selectService": { |
||||||
|
"message": "Select Service" |
||||||
|
}, |
||||||
|
"send": { |
||||||
|
"message": "Send" |
||||||
|
}, |
||||||
|
"sendTokens": { |
||||||
|
"message": "Send Tokens" |
||||||
|
}, |
||||||
|
"sendTokensAnywhere": { |
||||||
|
"message": "Send Tokens to anyone with an Ethereum account" |
||||||
|
}, |
||||||
|
"settings": { |
||||||
|
"message": "Settings" |
||||||
|
}, |
||||||
|
"shapeshiftBuy": { |
||||||
|
"message": "Buy with Shapeshift" |
||||||
|
}, |
||||||
|
"showPrivateKeys": { |
||||||
|
"message": "Show Private Keys" |
||||||
|
}, |
||||||
|
"showQRCode": { |
||||||
|
"message": "Show QR Code" |
||||||
|
}, |
||||||
|
"sign": { |
||||||
|
"message": "Sign" |
||||||
|
}, |
||||||
|
"signMessage": { |
||||||
|
"message": "Sign Message" |
||||||
|
}, |
||||||
|
"signNotice": { |
||||||
|
"message": "Signing this message can have \ndangerous side effects. Only sign messages from \nsites you fully trust with your entire account.\n This dangerous method will be removed in a future version. " |
||||||
|
}, |
||||||
|
"sigRequest": { |
||||||
|
"message": "Signature Request" |
||||||
|
}, |
||||||
|
"sigRequested": { |
||||||
|
"message": "Signature Requested" |
||||||
|
}, |
||||||
|
"status": { |
||||||
|
"message": "Status" |
||||||
|
}, |
||||||
|
"submit": { |
||||||
|
"message": "Submit" |
||||||
|
}, |
||||||
|
"takesTooLong": { |
||||||
|
"message": "Taking too long?" |
||||||
|
}, |
||||||
|
"testFaucet": { |
||||||
|
"message": "Test Faucet" |
||||||
|
}, |
||||||
|
"to": { |
||||||
|
"message": "To" |
||||||
|
}, |
||||||
|
"toETHviaShapeShift": { |
||||||
|
"message": "$1 to ETH via ShapeShift", |
||||||
|
"description": "system will fill in deposit type in start of message" |
||||||
|
}, |
||||||
|
"tokenBalance": { |
||||||
|
"message": "Your Token Balance is:" |
||||||
|
}, |
||||||
|
"total": { |
||||||
|
"message": "Total" |
||||||
|
}, |
||||||
|
"transactionMemo": { |
||||||
|
"message": "Transaction memo (optional)" |
||||||
|
}, |
||||||
|
"transactionNumber": { |
||||||
|
"message": "Transaction Number" |
||||||
|
}, |
||||||
|
"transfers": { |
||||||
|
"message": "Transfers" |
||||||
|
}, |
||||||
|
"troubleTokenBalances": { |
||||||
|
"message": "We had trouble loading your token balances. You can view them ", |
||||||
|
"description": "Followed by a link (here) to view token balances" |
||||||
|
}, |
||||||
|
"typePassword": { |
||||||
|
"message": "Type Your Password" |
||||||
|
}, |
||||||
|
"uiWelcome": { |
||||||
|
"message": "Welcome to the New UI (Beta)" |
||||||
|
}, |
||||||
|
"uiWelcomeMessage": { |
||||||
|
"message": "You are now using the new Metamask UI. Take a look around, try out new features like sending tokens, and let us know if you have any issues." |
||||||
|
}, |
||||||
|
"unavailable": { |
||||||
|
"message": "Unavailable" |
||||||
|
}, |
||||||
|
"unknown": { |
||||||
|
"message": "Unknown" |
||||||
|
}, |
||||||
|
"unknownNetwork": { |
||||||
|
"message": "Unknown Private Network" |
||||||
|
}, |
||||||
|
"unknownNetworkId": { |
||||||
|
"message": "Unknown network ID" |
||||||
|
}, |
||||||
|
"usaOnly": { |
||||||
|
"message": "USA only", |
||||||
|
"description": "Using this exchange is limited to people inside the USA" |
||||||
|
}, |
||||||
|
"usedByClients": { |
||||||
|
"message": "Used by a variety of different clients" |
||||||
|
}, |
||||||
|
"viewAccount": { |
||||||
|
"message": "View Account" |
||||||
|
}, |
||||||
|
"warning": { |
||||||
|
"message": "Warning" |
||||||
|
}, |
||||||
|
"whatsThis": { |
||||||
|
"message": "What's this?" |
||||||
|
}, |
||||||
|
"yourSigRequested": { |
||||||
|
"message": "Your signature is being requested" |
||||||
|
}, |
||||||
|
"youSign": { |
||||||
|
"message": "You are signing" |
||||||
} |
} |
||||||
} |
} |
||||||
|
@ -0,0 +1,38 @@ |
|||||||
|
// We should not rely on local storage in an extension!
|
||||||
|
// We should use this instead!
|
||||||
|
// https://developer.mozilla.org/en-US/Add-ons/WebExtensions/API/storage/local
|
||||||
|
|
||||||
|
const extension = require('extensionizer') |
||||||
|
const { promisify } = require('util').promisify |
||||||
|
|
||||||
|
module.exports = class ExtensionStore { |
||||||
|
constructor() { |
||||||
|
this.isSupported = !!(extension.storage.local) |
||||||
|
if (!this.isSupported) { |
||||||
|
log.error('Storage local API not available.') |
||||||
|
} |
||||||
|
const local = extension.storage.local |
||||||
|
this._get = promisify(local.get).bind(local) |
||||||
|
this._set = promisify(local.set).bind(local) |
||||||
|
} |
||||||
|
|
||||||
|
async get() { |
||||||
|
if (!this.isSupported) return undefined |
||||||
|
const result = await this._get() |
||||||
|
// extension.storage.local always returns an obj
|
||||||
|
// if the object is empty, treat it as undefined
|
||||||
|
if (isEmpty(result)) { |
||||||
|
return undefined |
||||||
|
} else { |
||||||
|
return result |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
async set(state) { |
||||||
|
return this._set(state) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
function isEmpty(obj) { |
||||||
|
return Object.keys(obj).length === 0 |
||||||
|
} |
@ -1,17 +0,0 @@ |
|||||||
machine: |
|
||||||
node: |
|
||||||
version: 8.1.4 |
|
||||||
test: |
|
||||||
override: |
|
||||||
- "npm test" |
|
||||||
dependencies: |
|
||||||
pre: |
|
||||||
- sudo apt-get update |
|
||||||
# get latest stable firefox |
|
||||||
- sudo apt-get install firefox |
|
||||||
- firefox_cmd=`which firefox`; sudo rm -f $firefox_cmd; sudo ln -s `which firefox.ubuntu` $firefox_cmd |
|
||||||
# get latest stable chrome |
|
||||||
- wget -q -O - https://dl-ssl.google.com/linux/linux_signing_key.pub | sudo apt-key add - |
|
||||||
- sudo sh -c 'echo "deb [arch=amd64] http://dl.google.com/linux/chrome/deb/ stable main" >> /etc/apt/sources.list.d/google.list' |
|
||||||
- sudo apt-get update |
|
||||||
- sudo apt-get install google-chrome-stable |
|
@ -1,18 +1,21 @@ |
|||||||
const fs = require('fs') |
const fs = require('fs') |
||||||
const path = require('path') |
const path = require('path') |
||||||
|
const { promisify } = require('util') |
||||||
|
|
||||||
const statesPath = path.join(__dirname, 'states') |
start().catch(console.error) |
||||||
const stateNames = fs.readdirSync(statesPath) |
|
||||||
|
|
||||||
const states = stateNames.reduce((result, stateFileName) => { |
async function start () { |
||||||
const statePath = path.join(__dirname, 'states', stateFileName) |
const statesPath = path.join(__dirname, 'states') |
||||||
const stateFile = fs.readFileSync(statePath).toString() |
const stateFilesNames = await promisify(fs.readdir)(statesPath) |
||||||
const state = JSON.parse(stateFile) |
const states = {} |
||||||
result[stateFileName.split('.')[0].replace(/-/g, ' ', 'g')] = state |
await Promise.all(stateFilesNames.map(async (stateFileName) => { |
||||||
return result |
const stateFilePath = path.join(__dirname, 'states', stateFileName) |
||||||
}, {}) |
const stateFileContent = await promisify(fs.readFile)(stateFilePath, 'utf8') |
||||||
|
const state = JSON.parse(stateFileContent) |
||||||
const result = `module.exports = ${JSON.stringify(states)}` |
const stateName = stateFileName.split('.')[0].replace(/-/g, ' ', 'g') |
||||||
|
states[stateName] = state |
||||||
const statesJsonPath = path.join(__dirname, 'states.js') |
})) |
||||||
fs.writeFileSync(statesJsonPath, result) |
const generatedFileContent = `module.exports = ${JSON.stringify(states)}` |
||||||
|
const generatedFilePath = path.join(__dirname, 'states.js') |
||||||
|
await promisify(fs.writeFile)(generatedFilePath, generatedFileContent) |
||||||
|
} |
||||||
|
@ -0,0 +1,18 @@ |
|||||||
|
# MetaMask Translation Guide |
||||||
|
|
||||||
|
The MetaMask browser extension supports new translations added in the form of new locales files added in `app/_locales`. |
||||||
|
|
||||||
|
- [The MDN Guide to Internationalizing Extensions](https://developer.mozilla.org/en-US/Add-ons/WebExtensions/Internationalization) |
||||||
|
|
||||||
|
## Adding a new Language |
||||||
|
|
||||||
|
Each supported language is represented by a folder in `app/_locales` whose name is that language's subtag ([look up a language subtag using this tool](https://r12a.github.io/app-subtags/)). |
||||||
|
|
||||||
|
Inside that folder there should be a `messages.json` file that follows the specified format. An easy way to start your translation is to first duplicate `app/_locales/en/messages.json` (the english translation), and then update the `message` key for each in-app message. |
||||||
|
|
||||||
|
That's it! When MetaMask is loaded on a computer with that language set as the system language, they will see your translation instead of the default one. |
||||||
|
|
||||||
|
## Testing |
||||||
|
|
||||||
|
To verify that your translation works, you will need to [build a local copy](https://github.com/MetaMask/metamask-extension#building-locally) of MetaMask. |
||||||
|
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,53 @@ |
|||||||
|
module.exports = { |
||||||
|
timeout, |
||||||
|
queryAsync, |
||||||
|
findAsync, |
||||||
|
pollUntilTruthy, |
||||||
|
} |
||||||
|
|
||||||
|
function timeout (time) { |
||||||
|
return new Promise((resolve, reject) => { |
||||||
|
setTimeout(resolve, time || 1500) |
||||||
|
}) |
||||||
|
} |
||||||
|
|
||||||
|
async function findAsync(container, selector, opts) { |
||||||
|
try { |
||||||
|
return await pollUntilTruthy(() => { |
||||||
|
const result = container.find(selector) |
||||||
|
if (result.length > 0) return result |
||||||
|
}, opts) |
||||||
|
} catch (err) { |
||||||
|
throw new Error(`Failed to find element within interval: "${selector}"`) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
async function queryAsync(jQuery, selector, opts) { |
||||||
|
try { |
||||||
|
return await pollUntilTruthy(() => { |
||||||
|
const result = jQuery(selector) |
||||||
|
if (result.length > 0) return result |
||||||
|
}, opts) |
||||||
|
} catch (err) { |
||||||
|
throw new Error(`Failed to find element within interval: "${selector}"`) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
async function pollUntilTruthy(fn, opts = {}){ |
||||||
|
const pollingInterval = opts.pollingInterval || 100 |
||||||
|
const timeoutInterval = opts.timeoutInterval || 5000 |
||||||
|
const start = Date.now() |
||||||
|
let result |
||||||
|
while (!result) { |
||||||
|
// check if timedout
|
||||||
|
const now = Date.now() |
||||||
|
if ((now - start) > timeoutInterval) { |
||||||
|
throw new Error(`pollUntilTruthy - failed to return truthy within interval`) |
||||||
|
} |
||||||
|
// check for result
|
||||||
|
result = fn() |
||||||
|
// run again after timeout
|
||||||
|
await timeout(pollingInterval, timeoutInterval) |
||||||
|
} |
||||||
|
return result |
||||||
|
} |
@ -0,0 +1,59 @@ |
|||||||
|
.welcome-screen { |
||||||
|
display: flex; |
||||||
|
flex-flow: column; |
||||||
|
justify-content: center; |
||||||
|
align-items: center; |
||||||
|
font-family: Roboto; |
||||||
|
font-weight: 400; |
||||||
|
width: 100%; |
||||||
|
flex: 1 0 auto; |
||||||
|
padding: 70px 0; |
||||||
|
background: $white; |
||||||
|
|
||||||
|
@media screen and (max-width: 575px) { |
||||||
|
padding: 0; |
||||||
|
} |
||||||
|
|
||||||
|
&__info { |
||||||
|
display: flex; |
||||||
|
flex-flow: column; |
||||||
|
width: 100%; |
||||||
|
height: 100%; |
||||||
|
align-items: center; |
||||||
|
|
||||||
|
&__header { |
||||||
|
font-size: 1.65em; |
||||||
|
margin-bottom: 14px; |
||||||
|
|
||||||
|
@media screen and (max-width: 575px) { |
||||||
|
font-size: 1.5em; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
&__copy { |
||||||
|
font-size: 1em; |
||||||
|
width: 400px; |
||||||
|
max-width: 90vw; |
||||||
|
text-align: center; |
||||||
|
|
||||||
|
@media screen and (max-width: 575px) { |
||||||
|
font-size: 0.9em; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
&__button { |
||||||
|
height: 54px; |
||||||
|
width: 198px; |
||||||
|
box-shadow: 0 2px 4px 0 rgba(0,0,0,0.14); |
||||||
|
color: #FFFFFF; |
||||||
|
font-size: 20px; |
||||||
|
font-weight: 500; |
||||||
|
line-height: 26px; |
||||||
|
text-align: center; |
||||||
|
text-transform: uppercase; |
||||||
|
margin: 35px 0 14px; |
||||||
|
transition: 200ms ease-in-out; |
||||||
|
background-color: rgba(247, 134, 28, 0.9); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,56 @@ |
|||||||
|
import EventEmitter from 'events' |
||||||
|
import h from 'react-hyperscript' |
||||||
|
import { Component } from 'react' |
||||||
|
import PropTypes from 'prop-types' |
||||||
|
import {connect} from 'react-redux' |
||||||
|
import {closeWelcomeScreen} from './actions' |
||||||
|
import Mascot from './components/mascot' |
||||||
|
|
||||||
|
class WelcomeScreen extends Component { |
||||||
|
static propTypes = { |
||||||
|
closeWelcomeScreen: PropTypes.func.isRequired, |
||||||
|
} |
||||||
|
|
||||||
|
constructor(props) { |
||||||
|
super(props) |
||||||
|
this.animationEventEmitter = new EventEmitter() |
||||||
|
} |
||||||
|
|
||||||
|
initiateAccountCreation = () => { |
||||||
|
this.props.closeWelcomeScreen() |
||||||
|
} |
||||||
|
|
||||||
|
render () { |
||||||
|
return h('div.welcome-screen', [ |
||||||
|
|
||||||
|
h('div.welcome-screen__info', [ |
||||||
|
|
||||||
|
h(Mascot, { |
||||||
|
animationEventEmitter: this.animationEventEmitter, |
||||||
|
width: '225', |
||||||
|
height: '225', |
||||||
|
}), |
||||||
|
|
||||||
|
h('div.welcome-screen__info__header', 'Welcome to MetaMask Beta'), |
||||||
|
|
||||||
|
h('div.welcome-screen__info__copy', 'MetaMask is a secure identity vault for Ethereum.'), |
||||||
|
|
||||||
|
h('div.welcome-screen__info__copy', `It allows you to hold ether & tokens,
|
||||||
|
and serves as your bridge to decentralized applications.`),
|
||||||
|
|
||||||
|
h('button.welcome-screen__button', { |
||||||
|
onClick: this.initiateAccountCreation, |
||||||
|
}, 'Continue'), |
||||||
|
|
||||||
|
]), |
||||||
|
|
||||||
|
]) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
export default connect( |
||||||
|
null, |
||||||
|
dispatch => ({ |
||||||
|
closeWelcomeScreen: () => dispatch(closeWelcomeScreen()), |
||||||
|
}) |
||||||
|
)(WelcomeScreen) |
@ -0,0 +1,33 @@ |
|||||||
|
|
||||||
|
// cross-browser connection to extension i18n API
|
||||||
|
|
||||||
|
const chrome = chrome || null |
||||||
|
const browser = browser || null |
||||||
|
const extension = require('extensionizer') |
||||||
|
var log = require('loglevel') |
||||||
|
window.log = log |
||||||
|
let getMessage |
||||||
|
|
||||||
|
if (extension.i18n && extension.i18n.getMessage) { |
||||||
|
getMessage = extension.i18n.getMessage |
||||||
|
} else { |
||||||
|
// fallback function
|
||||||
|
log.warn('browser.i18n API not available, calling back to english.') |
||||||
|
const msg = require('../app/_locales/en/messages.json') |
||||||
|
getMessage = function (key, substitutions) { |
||||||
|
if (!msg[key]) { |
||||||
|
log.error(key) |
||||||
|
throw new Error(key) |
||||||
|
} |
||||||
|
let phrase = msg[key].message |
||||||
|
if (substitutions && substitutions.length) { |
||||||
|
phrase = phrase.replace(/\$1/g, substitutions[0]) |
||||||
|
if (substitutions.length > 1) { |
||||||
|
phrase = phrase.replace(/\$2/g, substitutions[1]) |
||||||
|
} |
||||||
|
} |
||||||
|
return phrase |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
module.exports = getMessage |
Loading…
Reference in new issue