Implement i18n 2/9. Add site description

This commit is contained in:
Reckless_Satoshi 2022-04-03 14:34:12 -07:00
parent 4c2ec14a2f
commit 243147686f
No known key found for this signature in database
GPG Key ID: 9C4585B561315571
23 changed files with 3477 additions and 442 deletions

View File

@ -27,7 +27,7 @@ services:
build: ./frontend
container_name: npm-dev
restart: always
command: npm run build
command: npm run dev
volumes:
- ./frontend:/usr/src/frontend

View File

@ -2657,9 +2657,9 @@
}
},
"ansi-regex": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz",
"integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg=="
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.1.tgz",
"integrity": "sha512-ILlv4k/3f6vfQ4OoP2AGvirOktlQ98ZEL1k9FaQjxa3L1abBgbuTDAdPOpvbGncC0BTVQrl+OM8xZGK6tWXt7g=="
},
"ansi-styles": {
"version": "3.2.1",
@ -2966,9 +2966,9 @@
}
},
"bplist-parser": {
"version": "0.3.0",
"resolved": "https://registry.npmjs.org/bplist-parser/-/bplist-parser-0.3.0.tgz",
"integrity": "sha512-zgmaRvT6AN1JpPPV+S0a1/FAtoxSreYDccZGIqEMSvZl9DMe70mJ7MFzpxa1X+gHVdkToE2haRUHHMiW1OdejA==",
"version": "0.3.1",
"resolved": "https://registry.npmjs.org/bplist-parser/-/bplist-parser-0.3.1.tgz",
"integrity": "sha512-PyJxiNtA5T2PlLIeBot4lbp7rj4OadzjnMZD/G5zuBNt8ei/yCU7+wW0h2bag9vr8c+/WuRWmSxbqAl9hL1rBA==",
"requires": {
"big-integer": "1.6.x"
}
@ -3415,14 +3415,15 @@
"integrity": "sha1-aiw3NEkoYYYxxUvTPO3TAdoYvqA="
},
"css-select": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/css-select/-/css-select-2.1.0.tgz",
"integrity": "sha512-Dqk7LQKpwLoH3VovzZnkzegqNSuAziQyNZUcrdDM401iY+R5NkGBXGmtO05/yaXQziALuPogeG0b7UAgjnTJTQ==",
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/css-select/-/css-select-4.3.0.tgz",
"integrity": "sha512-wPpOYtnsVontu2mODhA19JrqWxNsfdatRKd64kmpRbQgh1KtItko5sTnEpPdpSaJszTOhEMlF/RPz28qj4HqhQ==",
"requires": {
"boolbase": "^1.0.0",
"css-what": "^3.2.1",
"domutils": "^1.7.0",
"nth-check": "^1.0.2"
"css-what": "^6.0.1",
"domhandler": "^4.3.1",
"domutils": "^2.8.0",
"nth-check": "^2.0.1"
}
},
"css-tree": {
@ -3444,9 +3445,9 @@
}
},
"css-what": {
"version": "3.4.2",
"resolved": "https://registry.npmjs.org/css-what/-/css-what-3.4.2.tgz",
"integrity": "sha512-ACUm3L0/jiZTqfzRM3Hi9Q8eZqd6IK37mMWPLz9PJxkLWllYeRf+EHUSHYEtFop2Eqytaq1FizFVh7XfBnXCDQ=="
"version": "6.1.0",
"resolved": "https://registry.npmjs.org/css-what/-/css-what-6.1.0.tgz",
"integrity": "sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw=="
},
"csstype": {
"version": "2.6.19",
@ -3580,33 +3581,36 @@
}
},
"dom-serializer": {
"version": "0.2.2",
"resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.2.2.tgz",
"integrity": "sha512-2/xPb3ORsQ42nHYiSunXkDjPLBaEj/xTwUO4B7XCZQTRk7EBtTOPaygh10YAAh2OI1Qrp6NWfpAhzswj0ydt9g==",
"version": "1.3.2",
"resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.3.2.tgz",
"integrity": "sha512-5c54Bk5Dw4qAxNOI1pFEizPSjVsx5+bpJKmL2kPn8JhBUq2q09tTCa3mjijun2NfK78NMouDYNMBkOrPZiS+ig==",
"requires": {
"domelementtype": "^2.0.1",
"domhandler": "^4.2.0",
"entities": "^2.0.0"
},
"dependencies": {
"domelementtype": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.2.0.tgz",
"integrity": "sha512-DtBMo82pv1dFtUmHyr48beiuq792Sxohr+8Hm9zoxklYPfa6n0Z3Byjj2IV7bmr2IyqClnqEQhfgHJJ5QF0R5A=="
}
}
},
"domelementtype": {
"version": "1.3.1",
"resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.3.1.tgz",
"integrity": "sha512-BSKB+TSpMpFI/HOxCNr1O8aMOTZ8hT3pM3GQ0w/mWRmkhEDSFJkkyzz4XQsBV44BChwGkrDfMyjVD0eA2aFV3w=="
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.2.0.tgz",
"integrity": "sha512-DtBMo82pv1dFtUmHyr48beiuq792Sxohr+8Hm9zoxklYPfa6n0Z3Byjj2IV7bmr2IyqClnqEQhfgHJJ5QF0R5A=="
},
"domhandler": {
"version": "4.3.1",
"resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.3.1.tgz",
"integrity": "sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ==",
"requires": {
"domelementtype": "^2.2.0"
}
},
"domutils": {
"version": "1.7.0",
"resolved": "https://registry.npmjs.org/domutils/-/domutils-1.7.0.tgz",
"integrity": "sha512-Lgd2XcJ/NjEw+7tFvfKxOzCYKZsdct5lczQ2ZaQY8Djz7pfAD3Gbp8ySJWtreII/vDlMVmxwa6pHmdxIYgttDg==",
"version": "2.8.0",
"resolved": "https://registry.npmjs.org/domutils/-/domutils-2.8.0.tgz",
"integrity": "sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==",
"requires": {
"dom-serializer": "0",
"domelementtype": "1"
"dom-serializer": "^1.0.1",
"domelementtype": "^2.2.0",
"domhandler": "^4.2.0"
}
},
"ee-first": {
@ -5798,9 +5802,9 @@
}
},
"minimist": {
"version": "1.2.5",
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz",
"integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw=="
"version": "1.2.6",
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz",
"integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q=="
},
"mixin-deep": {
"version": "1.3.2",
@ -5886,9 +5890,9 @@
}
},
"node-fetch": {
"version": "2.6.6",
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.6.tgz",
"integrity": "sha512-Z8/6vRlTUChSdIgMa51jxQ4lrw/Jy5SOW10ObaA47/RElsAN2c5Pn8bTgFGWn/ibwzXTE8qwr1Yzx28vsecXEA==",
"version": "2.6.7",
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz",
"integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==",
"requires": {
"whatwg-url": "^5.0.0"
}
@ -5928,11 +5932,11 @@
}
},
"nth-check": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/nth-check/-/nth-check-1.0.2.tgz",
"integrity": "sha512-WeBOdju8SnzPN5vTUJYxYUxLeXpCaVP5i5e0LF8fg7WORF2Wd7wFX/pk0tYZk7s8T+J7VLy0Da6J1+wCT0AtHg==",
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.0.1.tgz",
"integrity": "sha512-it1vE95zF6dTT9lBsYbxvqh0Soy4SPowchj0UBGj/V6cTPnXXtQOPUbhZ6CmGzAD/rW22LQK6E96pcdJXk4A4w==",
"requires": {
"boolbase": "~1.0.0"
"boolbase": "^1.0.0"
}
},
"nullthrows": {
@ -6190,9 +6194,9 @@
}
},
"plist": {
"version": "3.0.4",
"resolved": "https://registry.npmjs.org/plist/-/plist-3.0.4.tgz",
"integrity": "sha512-ksrr8y9+nXOxQB2osVNqrgvX/XQPOXaU4BQMKjYq8PvaY1U18mo+fKgBSwzK+luSyinOuPae956lSVcBwxlAMg==",
"version": "3.0.5",
"resolved": "https://registry.npmjs.org/plist/-/plist-3.0.5.tgz",
"integrity": "sha512-83vX4eYdQp3vP9SxuYgEM/G/pJQqLUz/V/xzPrzruLs7fz7jxGQ1msZ/mg1nwZxUSuOp4sb+/bEIbRrbzZRxDA==",
"requires": {
"base64-js": "^1.5.1",
"xmlbuilder": "^9.0.7"
@ -6658,11 +6662,11 @@
}
},
"react-native-svg": {
"version": "12.1.1",
"resolved": "https://registry.npmjs.org/react-native-svg/-/react-native-svg-12.1.1.tgz",
"integrity": "sha512-NIAJ8jCnXGCqGWXkkJ1GTzO4a3Md5at5sagYV8Vh4MXYnL4z5Rh428Wahjhh+LIjx40EE5xM5YtwyJBqOIba2Q==",
"version": "12.3.0",
"resolved": "https://registry.npmjs.org/react-native-svg/-/react-native-svg-12.3.0.tgz",
"integrity": "sha512-ESG1g1j7/WLD7X3XRFTQHVv0r6DpbHNNcdusngAODIxG88wpTWUZkhcM3A2HJTb+BbXTFDamHv7FwtRKWQ/ALg==",
"requires": {
"css-select": "^2.1.0",
"css-select": "^4.2.1",
"css-tree": "^1.0.0-alpha.39"
}
},
@ -7402,13 +7406,24 @@
"integrity": "sha512-sDl4qMFpijcGw22U5w63KmD3cZJfBuFlVNbVMKje2keoKML7X2UzWbc4XrmEbDwg0NXJc3yv4/ox7b+JWb57kQ=="
},
"simple-plist": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/simple-plist/-/simple-plist-1.3.0.tgz",
"integrity": "sha512-uYWpeGFtZtVt2NhG4AHgpwx323zxD85x42heMJBan1qAiqqozIlaGrwrEt6kRjXWRWIXsuV1VLCvVmZan2B5dg==",
"version": "1.3.1",
"resolved": "https://registry.npmjs.org/simple-plist/-/simple-plist-1.3.1.tgz",
"integrity": "sha512-iMSw5i0XseMnrhtIzRb7XpQEXepa9xhWxGUojHBL43SIpQuDQkh3Wpy67ZbDzZVr6EKxvwVChnVpdl8hEVLDiw==",
"requires": {
"bplist-creator": "0.1.0",
"bplist-parser": "0.3.0",
"plist": "^3.0.4"
"bplist-parser": "0.3.1",
"plist": "^3.0.5"
},
"dependencies": {
"plist": {
"version": "3.0.5",
"resolved": "https://registry.npmjs.org/plist/-/plist-3.0.5.tgz",
"integrity": "sha512-83vX4eYdQp3vP9SxuYgEM/G/pJQqLUz/V/xzPrzruLs7fz7jxGQ1msZ/mg1nwZxUSuOp4sb+/bEIbRrbzZRxDA==",
"requires": {
"base64-js": "^1.5.1",
"xmlbuilder": "^9.0.7"
}
}
}
},
"sisteransi": {

View File

@ -40,13 +40,14 @@
"react-countdown": "^2.3.2",
"react-i18next": "^11.16.2",
"react-native": "^0.66.4",
"react-native-svg": "^12.1.1",
"react-native-svg": "^12.3.0",
"react-qr-code": "^2.0.3",
"react-qr-reader": "^2.2.1",
"react-responsive": "^9.0.0-beta.6",
"react-router-dom": "^5.2.0",
"react-world-flags": "^1.4.0",
"reconnecting-websocket": "^4.4.0",
"simple-plist": "^1.3.1",
"websocket": "^1.0.34"
}
}

View File

@ -16,14 +16,9 @@ export default class App extends Component {
super(props);
this.state = {
dark: false,
lang: 'en',
}
}
setLang=(newLang)=>{
this.setState({lang:newLang})
}
lightTheme = createTheme({});
darkTheme = createTheme({
@ -44,7 +39,7 @@ export default class App extends Component {
{this.state.dark ? <LightModeIcon/>:<DarkModeIcon/>}
</IconButton>
<UnsafeAlert className="unsafeAlert"/>
<HomePage changeLang={i18n.changeLanguage}/>
<HomePage/>
</ThemeProvider>
</I18nextProvider>
);

View File

@ -1,4 +1,5 @@
import React, { Component , useState } from "react";
import React, { Component } from "react";
import { withTranslation, Trans} from "react-i18next";
import { Badge, Tooltip, Paper, Button, ListItemButton, Typography, Grid, Select, MenuItem, FormControl, FormHelperText, ListItemText, ListItemAvatar, IconButton} from "@mui/material";
import { Link } from 'react-router-dom'
import { DataGrid } from '@mui/x-data-grid';
@ -9,7 +10,7 @@ import Image from 'material-ui-image'
import getFlags from './getFlags'
import PaymentText from './PaymentText'
export default class BookPage extends Component {
class BookPage extends Component {
constructor(props) {
super(props);
this.state = {
@ -347,4 +348,6 @@ export default class BookPage extends Component {
</Grid>
);
};
}
}
export default withTranslation()(BookPage);

View File

@ -1,5 +1,5 @@
import React, { Component } from 'react'
import { withTranslation } from "react-i18next";
import { withTranslation, Trans} from "react-i18next";
import {FormControlLabel, Link, Switch, CircularProgress, Badge, Tooltip, TextField, ListItemAvatar, Button, Avatar,Paper, Grid, IconButton, Typography, Select, MenuItem, List, ListItemText, ListItem, ListItemIcon, ListItemButton, Divider, Dialog, DialogContent} from "@mui/material";
import MediaQuery from 'react-responsive'
import { Link as LinkRouter } from 'react-router-dom'
@ -27,7 +27,6 @@ import PersonAddAltIcon from '@mui/icons-material/PersonAddAlt';
import EmojiEventsIcon from '@mui/icons-material/EmojiEvents';
import AmbossIcon from "./icons/AmbossIcon";
import FavoriteIcon from '@mui/icons-material/Favorite';
import { t } from 'i18next';
// pretty numbers
function pn(x) {
@ -592,7 +591,7 @@ bottomBarDesktop =()=>{
return(
<Select
size = 'small'
value = {i18n.resolvedLanguage}
value = {i18n.resolvedLanguage.substring(0,2)}
inputProps={{
style: {textAlign:"center"}
}}

View File

@ -1,8 +1,9 @@
import React, { Component } from 'react';
import { withTranslation, Trans} from "react-i18next";
import {Button, Link, Badge, TextField, Grid, Container, Card, CardHeader, Paper, Avatar, FormHelperText, Typography} from "@mui/material";
import ReconnectingWebSocket from 'reconnecting-websocket';
export default class Chat extends Component {
class Chat extends Component {
constructor(props) {
super(props);
}
@ -166,3 +167,5 @@ export default class Chat extends Component {
)
}
}
export default withTranslation()(Chat);

View File

@ -41,7 +41,7 @@ export default class HomePage extends Component {
</Switch>
</div>
<div className='bottomBar'>
<BottomBar changeLang={this.props.changeLang} redirectTo={this.redirectTo} {...this.state} setAppState={this.setAppState} />
<BottomBar redirectTo={this.redirectTo} {...this.state} setAppState={this.setAppState} />
</div>
</Router>
);

View File

@ -1,10 +1,10 @@
import {Typography, Link, DialogActions, DialogContent, Button, Grid} from "@mui/material"
import React, { Component } from 'react'
import { withTranslation, Trans} from "react-i18next";
import {Typography, Link, DialogActions, DialogContent, Button, Grid} from "@mui/material"
import Image from 'material-ui-image'
import MediaQuery from 'react-responsive'
export default class InfoDialog extends Component {
class InfoDialog extends Component {
render() {
return (
<div>
@ -161,4 +161,6 @@ export default class InfoDialog extends Component {
</div>
)
}
}
}
export default withTranslation()(InfoDialog);

View File

@ -1,11 +1,15 @@
import React, { Component } from 'react';
import { withTranslation, Trans} from "react-i18next";
import { InputAdornment, LinearProgress, Link, Checkbox, Slider, Box, Tab, Tabs, SliderThumb, Tooltip, Paper, Button , Grid, Typography, TextField, Select, FormHelperText, MenuItem, FormControl, Radio, FormControlLabel, RadioGroup} from "@mui/material"
import { LocalizationProvider, TimePicker} from '@mui/lab';
import DateFnsUtils from "@date-io/date-fns";
import { Link as LinkRouter } from 'react-router-dom'
import { styled } from '@mui/material/styles';
import getFlags from './getFlags';
import AutocompletePayments from './autocompletePayments';
import LockIcon from '@mui/icons-material/Lock';
import HourglassTopIcon from '@mui/icons-material/HourglassTop';
import currencyDict from '../../static/assets/currencies.json';
@ -37,7 +41,7 @@ function pn(x) {
return parts.join(".");
}
export default class MakerPage extends Component {
class MakerPage extends Component {
defaultCurrency = 1;
defaultCurrencyCode = 'USD';
defaultPaymentMethod = "not specified";
@ -319,6 +323,8 @@ export default class MakerPage extends Component {
error={this.state.badPaymentMethod}
helperText={this.state.badPaymentMethod ? "Must be shorter than 65 characters":""}
label={this.state.currency==1000 ? "Swap Destination(s)" : "Fiat Payment Method(s)"}
listHeaderText={"You can add any method"}
addNewButtonText={"Add New"}
/>
</Tooltip>
</Grid>
@ -708,4 +714,6 @@ export default class MakerPage extends Component {
</Grid>
);
}
}
}
export default withTranslation()(MakerPage);

View File

@ -1,4 +1,5 @@
import React, { Component } from "react";
import { withTranslation, Trans} from "react-i18next";
import {TextField,Chip, Tooltip, Badge, Tab, Tabs, Alert, Paper, CircularProgress, Button , Grid, Typography, List, ListItem, ListItemIcon, ListItemText, ListItemAvatar, Avatar, Divider, Box, LinearProgress, Dialog, DialogActions, DialogContent, DialogContentText, DialogTitle} from "@mui/material"
import Countdown, { zeroPad, calcTimeDelta } from 'react-countdown';
import MediaQuery from 'react-responsive'
@ -39,7 +40,7 @@ function pn(x) {
return parts.join(".");
}
export default class OrderPage extends Component {
class OrderPage extends Component {
constructor(props) {
super(props);
this.state = {
@ -739,3 +740,5 @@ export default class OrderPage extends Component {
);
}
}
export default withTranslation()(OrderPage);

View File

@ -1,4 +1,3 @@
import { TextField } from '@mui/material';
import React, { Component } from 'react';
import DashboardCustomizeIcon from '@mui/icons-material/DashboardCustomize';

View File

@ -1,7 +1,6 @@
import PaymentIcon from './PaymentIcons'
import React, { Component } from 'react'
import PaymentIcon from './PaymentIcons'
import {Tooltip} from "@mui/material"
import { intlFormat } from 'date-fns';
const someMethods = [
{name: "Revolut",icon:'revolut'},

View File

@ -1,4 +1,5 @@
import React, { Component } from "react";
import { withTranslation, Trans} from "react-i18next";
import { IconButton, Box, Link, Paper, Rating, Button, Tooltip, CircularProgress, Grid, Typography, TextField, List, ListItem, ListItemText, Divider, ListItemIcon, Dialog, DialogActions, DialogContent, DialogContentText, DialogTitle} from "@mui/material"
import QRCode from "react-qr-code";
import Countdown, { zeroPad} from 'react-countdown';
@ -40,7 +41,7 @@ function pn(x) {
return parts.join(".");
}
export default class TradeBox extends Component {
class TradeBox extends Component {
constructor(props) {
super(props);
this.state = {
@ -53,6 +54,8 @@ export default class TradeBox extends Component {
}
}
Sound = ({soundFileName}) => (
// Four filenames: "locked-invoice", "taker-found", "open-chat", "successful"
<audio autoPlay src={`/static/assets/sounds/${soundFileName}.mp3`} />
@ -195,21 +198,28 @@ export default class TradeBox extends Component {
}
showQRInvoice=()=>{
const { t } = this.props;
return (
<Grid container spacing={1}>
<Grid item xs={12} align="center">
<Typography component="body2" variant="body2">
Robots show commitment to their peers
{t("Robots show commitment to their peers")}
</Typography>
</Grid>
<Grid item xs={12} align="center">
{this.props.data.is_maker ?
<Typography color="primary" component="subtitle1" variant="subtitle1">
<b>Lock {pn(this.props.data.bond_satoshis)} Sats to PUBLISH order </b> {" " + this.stepXofY()}
<b><Trans i18nKey="lock_to_publish">
Lock {{amount_sats: pn(this.props.data.bond_satoshis)}} Sats to PUBLISH order
</Trans>
</b> {" " + this.stepXofY()}
</Typography>
:
<Typography color="primary" component="subtitle1" variant="subtitle1">
<b>Lock {pn(this.props.data.bond_satoshis)} Sats to TAKE the order </b> {" " + this.stepXofY()}
<b><Trans i18nKey="lock_to_take">
Lock {{amount_sats: pn(this.props.data.bond_satoshis)}} Sats to TAKE the order
</Trans>
</b> {" " + this.stepXofY()}
</Typography>
}
</Grid>
@ -217,8 +227,8 @@ export default class TradeBox extends Component {
<Box sx={{bgcolor:'#ffffff', width:'315px', position:'relative', left:'-5px'}} >
<QRCode value={this.props.data.bond_invoice} size={305} style={{position:'relative', top:'3px'}}/>
</Box>
<Tooltip disableHoverListener enterTouchDelay="0" title="Copied!">
<Button size="small" color="inherit" onClick={() => {navigator.clipboard.writeText(this.props.data.bond_invoice)}} align="center"> <ContentCopy/> Copy to clipboard</Button>
<Tooltip disableHoverListener enterTouchDelay="0" title={t("Copied!")}>
<Button size="small" color="inherit" onClick={() => {navigator.clipboard.writeText(this.props.data.bond_invoice)}} align="center"> <ContentCopy/>{t("Copy to clipboard")}</Button>
</Tooltip>
</Grid>
<Grid item xs={12} align="center">
@ -228,7 +238,7 @@ export default class TradeBox extends Component {
size="small"
defaultValue={this.props.data.bond_invoice}
disabled="true"
helperText="This is a hold invoice, it will freeze in your wallet. It will be charged only if you cancel or lose a dispute."
helperText={t("This is a hold invoice, it will freeze in your wallet. It will be charged only if you cancel or lose a dispute.")}
color = "secondary"
/>
</Grid>
@ -237,12 +247,13 @@ export default class TradeBox extends Component {
}
showBondIsLocked=()=>{
const {t} = this.props
return (
<Grid item xs={12} align="center">
<Typography color="primary" component="subtitle1" variant="subtitle1" align="center">
<div style={{display:'flex', alignItems:'center', justifyContent:'center', flexWrap:'wrap'}}>
<LockIcon/>
{" Your " + (this.props.data.is_maker ? 'maker' : 'taker')+" bond is locked"}
{this.props.data.is_maker ? t("Your maker bond is locked") : t("Your taker bond is locked")}
</div>
</Typography>
</Grid>
@ -255,7 +266,7 @@ export default class TradeBox extends Component {
<Typography color="error" component="subtitle1" variant="subtitle1" align="center">
<div style={{display:'flex',alignItems:'center', justifyContent:'center', flexWrap:'wrap', align:"center"}} align="center">
<BalanceIcon/>
{" Your " + (this.props.data.is_maker ? 'maker' : 'taker')+" bond was settled"}
{this.props.data.is_maker ? t("Your maker bond was settled") : t("Your taker bond was settled")}
</div>
</Typography>
</Grid>
@ -268,7 +279,7 @@ export default class TradeBox extends Component {
<Typography color="green" component="subtitle1" variant="subtitle1" align="center">
<div style={{display:'flex',alignItems:'center', justifyContent:'center', flexWrap:'wrap'}}>
<LockOpenIcon/>
{" Your " + (this.props.data.is_maker ? 'maker' : 'taker')+" bond was unlocked"}
{this.props.data.is_maker ? t("Your maker bond was unlock") : t("Your taker bond was unlocked")}
</div>
</Typography>
</Grid>
@ -282,7 +293,10 @@ export default class TradeBox extends Component {
<this.Sound soundFileName="locked-invoice"/>
<Grid item xs={12} align="center">
<Typography color="green" component="subtitle1" variant="subtitle1">
<b>Lock {pn(this.props.data.escrow_satoshis)} Sats as collateral </b> {" " + this.stepXofY()}
<b><Trans i18nKey="lock_escrow" >
Lock {{amount_sats:pn(this.props.data.escrow_satoshis)}} Sats as collateral
</Trans>
</b> {" " + this.stepXofY()}
</Typography>
</Grid>
<Grid item xs={12} align="center">
@ -300,7 +314,7 @@ export default class TradeBox extends Component {
size="small"
defaultValue={this.props.data.escrow_invoice}
disabled="true"
helperText={"This is a hold invoice, it will freeze in your wallet. It will be released to the buyer once you confirm to have received the "+this.props.data.currencyCode+"."}
helperText={<Trans i18nKey="hold_escrow_invoice_explanation">This is a hold invoice, it will freeze in your wallet. It will be released to the buyer once you confirm to have received the {{currencyCode: this.props.data.currencyCode}}.</Trans>}
color = "secondary"
/>
</Grid>
@ -310,21 +324,20 @@ export default class TradeBox extends Component {
}
showTakerFound=()=>{
const { t } = this.props;
return (
<Grid container spacing={1}>
{/* Make bell sound when taker is found */}
<this.Sound soundFileName="taker-found"/>
<Grid item xs={12} align="center">
<Typography component="subtitle1" variant="subtitle1">
<b>A taker has been found! </b> {" " + this.stepXofY()}
<b>{t("A taker has been found!")}</b> {" " + this.stepXofY()}
</Typography>
</Grid>
<Divider/>
<Grid item xs={12} align="center">
<Typography component="body2" variant="body2">
Please wait for the taker to lock a bond.
If the taker does not lock a bond in time, the order will be made
public again.
{t("Please wait for the taker to lock a bond. If the taker does not lock a bond in time, the order will be made public again.")}
</Typography>
</Grid>
{this.showBondIsLocked()}
@ -345,6 +358,7 @@ export default class TradeBox extends Component {
};
EnableTelegramDialog =() =>{
const { t } = this.props;
return(
<Dialog
open={this.state.openEnableTelegram}
@ -353,24 +367,23 @@ export default class TradeBox extends Component {
aria-describedby="enable-telegram-dialog-description"
>
<DialogTitle id="open-dispute-dialog-title">
Enable TG Notifications
{t("Enable TG Notifications")}
</DialogTitle>
<DialogContent>
<DialogContentText id="alert-dialog-description">
You will be taken to a conversation with RoboSats telegram bot.
Simply open the chat and press "Start". Note that by enabling
telegram notifications you might lower your level of anonymity.
{t("You will be taken to a conversation with RoboSats telegram bot. Simply open the chat and press Start. Note that by enabling telegram notifications you might lower your level of anonymity.")}
</DialogContentText>
</DialogContent>
<DialogActions>
<Button onClick={this.handleClickCloseEnableTelegramDialog}>Go back</Button>
<Button onClick={this.handleClickEnableTelegram} autoFocus> Enable </Button>
<Button onClick={this.handleClickCloseEnableTelegramDialog}> {t("Go back")} </Button>
<Button onClick={this.handleClickEnableTelegram} autoFocus> {t("Enable")} </Button>
</DialogActions>
</Dialog>
)
}
showMakerWait=()=>{
const { t } = this.props;
return (
<Grid container spacing={1}>
{/* Make confirmation sound for HTLC received. */}
@ -378,7 +391,7 @@ export default class TradeBox extends Component {
<this.EnableTelegramDialog/>
<Grid item xs={12} align="center">
<Typography component="subtitle1" variant="subtitle1">
<b> Your order is public </b> {" " + this.stepXofY()}
<b> {t("Your order is public")} </b> {" " + this.stepXofY()}
</Typography>
</Grid>
<Grid item xs={12} align="center">
@ -387,19 +400,16 @@ export default class TradeBox extends Component {
<Divider/>
<ListItem>
<Typography component="body2" variant="body2" align="left">
<p>Be patient while robots check the book.
It might take some time. This box will ring 🔊 once a robot takes your order. </p>
<p>Please note that if your premium is excessive or your currency or payment
methods are not popular, your order might expire untaken. Your bond will
return to you (no action needed).</p>
<p>{t("Be patient while robots check the book. It might take some time. This box will ring 🔊 once a robot takes your order.")} </p>
<p>{t("Please note that if your premium is excessive or your currency or payment methods are not popular, your order might expire untaken. Your bond will return to you (no action needed).")}</p>
</Typography>
</ListItem>
<Grid item xs={12} align="center">
{this.props.data.tg_enabled ?
<Typography color='primary' component="h6" variant="h6" align="center"> Telegram enabled</Typography>
<Typography color='primary' component="h6" variant="h6" align="center">{t("Telegram enabled")}</Typography>
:
<Button color="primary" onClick={this.handleClickOpenTelegramDialog}>
<SendIcon/>Enable Telegram Notifications
<SendIcon/>{t("Enable Telegram Notifications")}
</Button>
}
</Grid>
@ -408,7 +418,7 @@ export default class TradeBox extends Component {
<ListItemIcon>
<BookIcon/>
</ListItemIcon>
<ListItemText primary={this.props.data.num_similar_orders} secondary={"Public orders for " + this.props.data.currencyCode}/>
<ListItemText primary={this.props.data.num_similar_orders} secondary={<Trans i18n="public_order_num_subtitle">Public orders for {{currencyCode: this.props.data.currencyCode}} </Trans>}/>
</ListItem>
<Divider/>
@ -416,8 +426,8 @@ export default class TradeBox extends Component {
<ListItemIcon>
<PercentIcon/>
</ListItemIcon>
<ListItemText primary={"Premium rank " + this.props.data.premium_percentile*100+"%"}
secondary={"Among public " + this.props.data.currencyCode + " orders (higher is cheaper)"} />
<ListItemText primary={t("Premium rank") +" "+this.props.data.premium_percentile*100+"%"}
secondary={<Trans i18n="among_public"> Among public {{ currencyCode: this.props.data.currencyCode }} orders (higher is cheaper)</Trans>} />
</ListItem>
<Divider/>
@ -1087,4 +1097,6 @@ handleRatingRobosatsChange=(e)=>{
</Grid>
);
}
}
}
export default withTranslation()(TradeBox);

View File

@ -1,9 +1,9 @@
import {Paper, Alert, AlertTitle, Button, Link} from "@mui/material"
import React, { Component } from 'react'
import { withTranslation, Trans} from "react-i18next";
import {Paper, Alert, AlertTitle, Button, Link} from "@mui/material"
import MediaQuery from 'react-responsive'
export default class UnsafeAlert extends Component {
class UnsafeAlert extends Component {
constructor(props) {
super(props);
}
@ -23,31 +23,36 @@ export default class UnsafeAlert extends Component {
]
render() {
const { t, i18n} = this.props;
return (
(!this.safe_urls.includes(this.getHost()) & this.state.show) ?
<div>
<MediaQuery minWidth={800}>
<Paper elevation={6} className="alertUnsafe">
<Alert severity="warning" sx={{maxHeight:"100px"}}
action={<Button onClick={() => this.setState({show:false})}>Hide</Button>}
action={<Button onClick={() => this.setState({show:false})}>{t("Hide")}</Button>}
>
<AlertTitle>You are not using RoboSats privately</AlertTitle>
Some features are disabled for your protection (e.g. chat) and you will not be able to complete a
trade without them. To protect your privacy and fully enable RoboSats, use <Link href='https://www.torproject.org/download/' target="_blank">Tor Browser</Link> and visit the <Link chref='http://robosats6tkf3eva7x2voqso3a5wcorsnw34jveyxfqi2fu7oyheasid.onion' target="_blank">Onion</Link> site.
</Alert>
<AlertTitle>{t("You are not using RoboSats privately")}</AlertTitle>
<Trans i18nKey="desktop_unsafe_alert">
Some features are disabled for your protection (e.g. chat) and you will not be able to complete a
trade without them. To protect your privacy and fully enable RoboSats, use <Link href='https://www.torproject.org/download/' target="_blank">Tor Browser</Link> and visit the <Link href='http://robosats6tkf3eva7x2voqso3a5wcorsnw34jveyxfqi2fu7oyheasid.onion' target="_blank">Onion</Link> site.
</Trans>
</Alert>
</Paper>
</MediaQuery>
<MediaQuery maxWidth={799}>
<Paper elevation={6} className="alertUnsafe">
<Alert severity="warning" sx={{maxHeight:"120px"}}>
<AlertTitle>You are not using RoboSats privately</AlertTitle>
You will not be able to complete a
trade. Use <Link href='https://www.torproject.org/download/' target="_blank">Tor Browser</Link> and visit the <Link href='http://robosats6tkf3eva7x2voqso3a5wcorsnw34jveyxfqi2fu7oyheasid.onion' target="_blank">Onion</Link> site.
<AlertTitle>{t("You are not using RoboSats privately")}</AlertTitle>
<Trans i18nKey="phone_unsafe_alert">
You will not be able to complete a
trade. Use <Link href='https://www.torproject.org/download/' target="_blank">Tor Browser</Link> and visit the <Link href='http://robosats6tkf3eva7x2voqso3a5wcorsnw34jveyxfqi2fu7oyheasid.onion' target="_blank">Onion</Link> site.
</Trans>
<div style={{width: '100%'}}>
</div>
<div align="center">
<Button className="hideAlertButton" onClick={() => this.setState({show:false})}>Hide</Button>
<Button className="hideAlertButton" onClick={() => this.setState({show:false})}>{t("Hide")}</Button>
</div>
</Alert>
</Paper>
@ -57,4 +62,6 @@ export default class UnsafeAlert extends Component {
null
)
}
}
}
export default withTranslation()(UnsafeAlert);

View File

@ -187,7 +187,7 @@ class UserGenPage extends Component {
this.state.found ?
<Grid item xs={12} align="center">
<Typography component="subtitle2" variant="subtitle2" color='primary'>
{this.state.found}<br/>
{this.state.found ? t("A robot avatar was found, welcome back!"):null}<br/>
</Typography>
</Grid>
:
@ -196,18 +196,13 @@ class UserGenPage extends Component {
<Grid container align="center">
<Grid item xs={12} align="center">
<TextField sx={{maxWidth: 280}}
//sx={{ input: { color: 'purple' } }}
// InputLabelProps={{
// style: { color: 'green' },
// }}
error={this.state.bad_request}
label={"Store your token safely"}
label={t("Store your token safely")}
required='true'
value={this.state.token}
variant='standard'
helperText={this.state.bad_request}
size='small'
// multiline = {true}
onChange={this.handleChangeToken}
onKeyPress={(e) => {
if (e.key === 'Enter') {
@ -216,13 +211,13 @@ class UserGenPage extends Component {
}}
InputProps={{
startAdornment:
<Tooltip disableHoverListener open={this.state.copied} enterTouchDelay="0" title="Copied!">
<Tooltip disableHoverListener open={this.state.copied} enterTouchDelay="0" title={t("Copied!")}>
<IconButton onClick= {()=> (navigator.clipboard.writeText(this.state.token) & this.setState({copied:true}))}>
<ContentCopy color={this.props.avatarLoaded & !this.state.copied & !this.state.bad_request ? 'primary' : 'inherit' } sx={{width:18, height:18}}/>
</IconButton>
</Tooltip>,
endAdornment:
<Tooltip enterTouchDelay="250" title="Generate a new token">
<Tooltip enterTouchDelay="250" title={t("Generate a new token")}>
<IconButton onClick={this.handleClickNewRandomToken}><CasinoIcon/></IconButton>
</Tooltip>,
}}
@ -233,14 +228,14 @@ class UserGenPage extends Component {
{this.state.tokenHasChanged ?
<Button type="submit" size='small' onClick= {this.handleClickSubmitToken}>
<SmartToyIcon sx={{width:18, height:18}} />
<span> Generate Robot</span>
<span> {t("Generate Robot")}</span>
</Button>
:
<Tooltip enterTouchDelay="0" enterDelay="500" enterNextDelay="2000" title="You must enter a new token first">
<Tooltip enterTouchDelay="0" enterDelay="500" enterNextDelay="2000" title={t("You must enter a new token first")}>
<div>
<Button disabled={true} type="submit" size='small' >
<SmartToyIcon sx={{width:18, height:18}} />
<span> Generate Robot</span>
<span>{t("Generate Robot")}</span>
</Button>
</div>
</Tooltip>
@ -248,10 +243,10 @@ class UserGenPage extends Component {
</Grid>
<Grid item xs={12} align="center">
<ButtonGroup variant="contained" aria-label="outlined primary button group">
<Button disabled={this.state.loadingRobot} color='primary' to='/make/' component={Link}>Make Order</Button>
<Button color='inherit' onClick={this.handleClickOpenInfo}>Info</Button>
<Button disabled={this.state.loadingRobot} color='primary' to='/make/' component={Link}>{t("Make Order")}</Button>
<Button color='inherit' onClick={this.handleClickOpenInfo}>{t("Info")}</Button>
<this.InfoDialog/>
<Button disabled={this.state.loadingRobot} color='secondary' to='/book/' component={Link}>View Book</Button>
<Button disabled={this.state.loadingRobot} color='secondary' to='/book/' component={Link}>{t("View Book")}</Button>
</ButtonGroup>
</Grid>

View File

@ -247,7 +247,7 @@ export default function AutocompletePayments(props) {
{groupedOptions.length > 0 ? (
<Listbox {...getListboxProps()}>
<div style={{position:'fixed', minHeight:'20px', marginLeft: '53px', marginTop: '-13px'}}>
<ListHeader><i>You can add any method </i></ListHeader>
<ListHeader><i>{props.listHeaderText}</i></ListHeader>
</div>
{groupedOptions.map((option, index) => (
<li {...getOptionProps({ option, index })}>
@ -262,7 +262,7 @@ export default function AutocompletePayments(props) {
))}
{val != null?
(val.length > 2 ?
<Button size="small" fullWidth={true} onClick={() => handleAddNew(getInputProps())}><DashboardCustomizeIcon sx={{width:18,height:18}}/>Add New</Button>
<Button size="small" fullWidth={true} onClick={() => handleAddNew(getInputProps())}><DashboardCustomizeIcon sx={{width:18,height:18}}/>{props.addNewButtonText}</Button>
:null)
:null}
</Listbox>
@ -270,7 +270,7 @@ export default function AutocompletePayments(props) {
//Here goes what happens if there is no groupedOptions
(getInputProps().value.length > 0 ?
<Listbox {...getListboxProps()}>
<Button fullWidth={true} onClick={() => handleAddNew(getInputProps())}><DashboardCustomizeIcon sx={{width:20,height:20}}/>Add New</Button>
<Button fullWidth={true} onClick={() => handleAddNew(getInputProps())}><DashboardCustomizeIcon sx={{width:20,height:20}}/>{props.addNewButtonText}</Button>
</Listbox>
:null)
}

View File

@ -15,59 +15,14 @@ i18n
.use(initReactI18next)
.init({
resources: {
en: {
translations: translationEN
},
es: {
translations: translationES
},
ru: {
translations: {
Introduction: "प्रस्तावना",
"is an internationalization-framework which offers a complete solution to localize your product from web to mobile and desktop":
"एक अंतर्राष्ट्रीयकरण - ढांचा है जो आपके उत्पाद को वेब से मोबाइल और डेस्कटॉप पर स्थानांतरित करने का एक संपूर्ण समाधान प्रदान करता है",
"Plugins to detect the user language":
"उपयोगकर्ता भाषा का पता लगाने के लिए प्लगइन्स",
"Plugins to load translations": "अनुवाद लोड करने के लिए प्लगइन्स",
"Optionally cache the translations": "वैकल्पिक रूप से अनुवाद कैश करें",
Advantages: "लाभ",
"Flexibility to use other packages":
"अन्य पैकेजों का उपयोग करने के लिए लचीलापन"
}
},
de: {
translations: {
Introduction: "Einführung",
"is an internationalization-framework which offers a complete solution to localize your product from web to mobile and desktop":
"ist ein Internationalisierungs-Framework, das eine Komplettlösung für die Lokalisierung Ihres Produkts vom Web auf das Handy und den Desktop bietet",
"Plugins to detect the user language":
"Plugins zur Erkennung der Benutzersprache",
"Plugins to load translations": "Plugins zum Laden von Übersetzungen",
"Optionally cache the translations":
"Optional die Übersetzungen zwischenspeichern",
Advantages: "Vorteile",
"Flexibility to use other packages":
"Flexibilität zur Verwendung anderer Pakete"
}
},
cn: {
translations: {
Introduction: "Introduction",
"is an internationalization-framework which offers a complete solution to localize your product from web to mobile and desktop":
"est un cadre d'internationalisation qui offre une solution complète pour localiser votre produit du Web au mobile et au bureau",
"Plugins to detect the user language":
"Plugins pour détecter la langue de l'utilisateur",
"Plugins to load translations": "Plugins pour charger les traductions",
"Optionally cache the translations":
"Cachez éventuellement les traductions",
Advantages: "Les avantages",
"Flexibility to use other packages":
"Flexibilité d'utiliser d'autres packages"
}
}
en: {translations: translationEN},
'en-US': {translations: translationEN},
es: {translations: translationES},
ru: {translations: translationRU},
de: {translations: translationDE},
cn: {translations: translationCN},
},
fallbackLng: "en",
debug: true,
@ -84,7 +39,7 @@ i18n
react: {
wait: true,
useSuspense: true
useSuspense: false,
}
});

View File

@ -1,4 +1,52 @@
{
"UserGenPage": "User Generation Page and Landing Page",
"Simple and Private LN P2P Exchange": "Simple and Private LN P2P Exchange"
"UNSAFE ALERT - UnsafeAlert.js": "Alert that shows on top when browsing from the unsafe clearnet sites",
"You are not using RoboSats privately": "You are not using RoboSats privately",
"desktop_unsafe_alert": "Some features are disabled for your protection (e.g. chat) and you will not be able to complete a trade without them. To protect your privacy and fully enable RoboSats, use <1>Tor Browser</1> and visit the <3>Onion</3> site.",
"phone_unsafe_alert": "You will not be able to complete a trade. Use <1>Tor Browser</1> and visit the <3>Onion</3> site.",
"Hide":"Hide",
"USER GENERATION PAGE - UserGenPage.js": "Landing Page and User Generation",
"Simple and Private LN P2P Exchange": "Simple and Private LN P2P Exchange",
"This is your trading avatar":"This is your trading avatar",
"Store your token safely":"Store your token safely",
"A robot avatar was found, welcome back!":"A robot avatar was found, welcome back!",
"Copied!":"Copied!",
"Generate a new token":"Generate a new token",
"Generate Robot":"Generate Robot",
"You must enter a new token first":"You must enter a new token first",
"Make Order":"Make Order",
"Info":"Info",
"View Book":"View Book",
"CONTRACT BOX - TradeBox.js": "The Contract Box that guides users trough the whole trade pipeline",
"Robots show commitment to their peers": "Robots show commitment to their peers",
"lock_to_publish": "Lock {{amount_sats}} Sats to PUBLISH order ",
"lock_to_take": "Lock {{amount_sats}} Sats to TAKE the order ",
"lock_escrow": "Lock {{amount_sats}} Sats as collateral",
"Copy to clipboard":"Copy to clipboard",
"This is a hold invoice, it will freeze in your wallet. It will be charged only if you cancel or lose a dispute.":"This is a hold invoice, it will freeze in your wallet. It will be charged only if you cancel or lose a dispute.",
"hold_escrow_invoice_explanation":"This is a hold invoice, it will freeze in your wallet. It will be released to the buyer once you confirm to have received the {{currencyCode}}.",
"Your maker bond is locked":"Your maker bond is locked",
"Your taker bond is locked":"Your taker bond is locked",
"Your maker bond was settled":"Your maker bond was settled",
"Your taker bond was settled":"Your taker bond was settled",
"Your maker bond was unlock":"Your maker bond was unlock",
"Your taker bond was unlocked":"Your taker bond was unlocked",
"Your order is public":"Your order is public",
"Be patient while robots check the book. It might take some time. This box will ring 🔊 once a robot takes your order.":"Be patient while robots check the book. It might take some time. This box will ring 🔊 once a robot takes your order.",
"Please note that if your premium is excessive or your currency or payment methods are not popular, your order might expire untaken. Your bond will return to you (no action needed).":"Please note that if your premium is excessive or your currency or payment methods are not popular, your order might expire untaken. Your bond will return to you (no action needed).",
"Enable Telegram Notifications":"Enable Telegram Notifications",
"Enable TG Notifications":"Enable TG Notifications",
"You will be taken to a conversation with RoboSats telegram bot. Simply open the chat and press Start. Note that by enabling telegram notifications you might lower your level of anonymity.":"You will be taken to a conversation with RoboSats telegram bot. Simply open the chat and press Start. Note that by enabling telegram notifications you might lower your level of anonymity.",
"Go back":"Go back",
"Enable":"Enable",
"Telegram enabled":"Telegram enabled",
"public_order_num_subtitle": "Public orders for {{currencyCode}}",
"Premium rank": "Premium rank",
"among_public": "Among public {{currencyCode}} orders (higher is cheaper)",
"A taker has been found!":"A taker has been found!",
"Please wait for the taker to lock a bond. If the taker does not lock a bond in time, the order will be made public again.":"Please wait for the taker to lock a bond. If the taker does not lock a bond in time, the order will be made public again."
}

View File

@ -1,10 +1,11 @@
{
"UNSAFE-ALERT": "Alert that shows on top when browsing from the unsafe clearnet sites",
"You are not using RoboSats privately": "No estás usando RoboSats de forma privada",
"desktop_unsafe_alert": "Some features are disabled for your protection (e.g. chat) and you will not be able to complete a trade without them. To protect your privacy and fully enable RoboSats, use <1>Tor Browser</1> and visit the <3>Onion</3> site.",
"phone_unsafe_alert": "You will not be able to complete a trade. Use <1>Tor Browser</1> and visit the <3>Onion</3> site.",
"Hide":"Hide",
"UserGenPage": "User Generation Page and Landing Page",
"Simple and Private LN P2P Exchange":"Intercambio LN P2P Fácil y Privado",
"This is your trading avatar":"Este es tu avatar de compraventa",
"Plugins to detect the user language":"ユーザー言語を検出するためのプラグイン",
"Plugins to load translations": "翻訳をロードするためのプラグイン",
"Optionally cache the translations": "必要に応じて翻訳をキャッシュする",
"Advantages": "利点",
"Flexibility to use other packages": "他のパッケージを使用する柔軟性"
"This is your trading avatar":"Este es tu avatar de compraventa"
}

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

View File

@ -9,6 +9,8 @@
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="description" content="A simple and private way to exchange bitcoin for national currencies. Robosats simplifies the peer-to-peer user experience and uses lightning hold invoices to minimize custody and trust requirements. No user registration required.">
<title>RoboSats - Simple and Private Bitcoin Exchange</title>
{% load static %}
<link rel="stylesheet" href="{% static "css/fonts.css" %}"/>