diff options
author | Fabio Berger <me@fabioberger.com> | 2018-02-22 09:09:33 +0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2018-02-22 09:09:33 +0800 |
commit | dfe2579eebdaf348bb2e5690f901ca717c5f6392 (patch) | |
tree | 59a0d97371fd69f79a54f6dd4f6c602561f04115 /packages | |
parent | be19316dfb45600b2ce264a90dde7ace460fd0ac (diff) | |
parent | 1b3a9102f1d9c83ca6675a0e95cea6c4ceab01eb (diff) | |
download | dexon-sol-tools-dfe2579eebdaf348bb2e5690f901ca717c5f6392.tar dexon-sol-tools-dfe2579eebdaf348bb2e5690f901ca717c5f6392.tar.gz dexon-sol-tools-dfe2579eebdaf348bb2e5690f901ca717c5f6392.tar.bz2 dexon-sol-tools-dfe2579eebdaf348bb2e5690f901ca717c5f6392.tar.lz dexon-sol-tools-dfe2579eebdaf348bb2e5690f901ca717c5f6392.tar.xz dexon-sol-tools-dfe2579eebdaf348bb2e5690f901ca717c5f6392.tar.zst dexon-sol-tools-dfe2579eebdaf348bb2e5690f901ca717c5f6392.zip |
Merge pull request #410 from 0xProject/translateHomepage
Translate Landing Page
Diffstat (limited to 'packages')
32 files changed, 1071 insertions, 341 deletions
diff --git a/packages/website/package.json b/packages/website/package.json index 1643cf0bd..1d313390a 100644 --- a/packages/website/package.json +++ b/packages/website/package.json @@ -60,7 +60,6 @@ "semver-sort": "0.0.4", "thenby": "^1.2.3", "truffle-contract": "2.0.1", - "tslint-config-0xproject": "^0.0.2", "web3": "^0.20.0", "web3-provider-engine": "^13.0.1", "whatwg-fetch": "^2.0.3", @@ -97,6 +96,7 @@ "source-map-loader": "^0.1.6", "style-loader": "0.13.x", "tslint": "5.8.0", + "tslint-config-0xproject": "^0.0.2", "typescript": "2.7.1", "web3-typescript-typings": "^0.9.11", "webpack": "^3.1.0", diff --git a/packages/website/public/css/basscss_responsive_custom.css b/packages/website/public/css/basscss_responsive_custom.css index c2e802125..5f8bd9117 100644 --- a/packages/website/public/css/basscss_responsive_custom.css +++ b/packages/website/public/css/basscss_responsive_custom.css @@ -4,12 +4,21 @@ .sm-center { text-align: center; } + .sm-align-middle { + vertical-align: middle; + } + .sm-align-top { + vertical-align: top; + } .sm-left-align { text-align: left; } .sm-right-align { text-align: right; } + .sm-table-cell { + display: table-cell; + } .sm-mx-auto { margin-left: auto; margin-right: auto; @@ -23,12 +32,21 @@ .md-center { text-align: center; } + .md-align-middle { + vertical-align: middle; + } + .md-align-top { + vertical-align: top; + } .md-left-align { text-align: left; } .md-right-align { text-align: right; } + .md-table-cell { + display: table-cell; + } .md-mx-auto { margin-left: auto; margin-right: auto; @@ -42,12 +60,21 @@ .lg-center { text-align: center; } + .lg-align-middle { + vertical-align: middle; + } + .lg-align-top { + vertical-align: top; + } .lg-left-align { text-align: left; } .lg-right-align { text-align: right; } + .lg-table-cell { + display: table-cell; + } .lg-mx-auto { margin-left: auto; margin-right: auto; diff --git a/packages/website/public/index.html b/packages/website/public/index.html index 3072ff03d..75ca9a4ed 100644 --- a/packages/website/public/index.html +++ b/packages/website/public/index.html @@ -58,63 +58,6 @@ })(document, 'script', 'twitter-wjs'); </script> <!-- End Twitter SDK --> - <!-- Segment.io --> - <script> - !(function() { - var analytics = (window.analytics = window.analytics || []); - if (!analytics.initialize) - if (analytics.invoked) window.console && console.error && console.error('Segment snippet included twice.'); - else { - analytics.invoked = !0; - analytics.methods = [ - 'trackSubmit', - 'trackClick', - 'trackLink', - 'trackForm', - 'pageview', - 'identify', - 'reset', - 'group', - 'track', - 'ready', - 'alias', - 'debug', - 'page', - 'once', - 'off', - 'on', - ]; - analytics.factory = function(t) { - return function() { - var e = Array.prototype.slice.call(arguments); - e.unshift(t); - analytics.push(e); - return analytics; - }; - }; - for (var t = 0; t < analytics.methods.length; t++) { - var e = analytics.methods[t]; - analytics[e] = analytics.factory(e); - } - analytics.load = function(t) { - var e = document.createElement('script'); - e.type = 'text/javascript'; - e.async = !0; - e.src = - ('https:' === document.location.protocol ? 'https://' : 'http://') + - 'cdn.segment.com/analytics.js/v1/' + - t + - '/analytics.min.js'; - var n = document.getElementsByTagName('script')[0]; - n.parentNode.insertBefore(e, n); - }; - analytics.SNIPPET_VERSION = '4.0.0'; - analytics.load('T6jtT2F2iMrw9FDJ8exE9Uu1mLN5qd8n'); - analytics.page(); - } -})(); -</script> - <!-- End Segment.io --> <!-- Main --> <script type="text/javascript" crossorigin="anonymous" src="/bundle.js" charset="utf-8"></script> diff --git a/packages/website/translations/chinese.json b/packages/website/translations/chinese.json new file mode 100644 index 000000000..f5f906d6c --- /dev/null +++ b/packages/website/translations/chinese.json @@ -0,0 +1,72 @@ +{ + "TOP_HEADER": "去中心化交易的驱动者", + "TOP_TAGLINE": "0x 是一个无需许可的开源协议,用于促进以太坊区块链中 ERC20 代币的交易。", + "BUILD_CALL_TO_ACTION": "基于 0x 构建", + "COMMUNITY_CALL_TO_ACTION": "加入社区", + "PROJECTS_HEADER": "基于 0X 协议构建的项目", + "FULL_LIST_PROMPT": "查看", + "FULL_LIST_LINK": "完整列表", + "TOKENIZED_SECTION_HEADER": "世界正走向代币化时代", + "TOKENIZED_SECTION_DESCRIPTION": + "以太坊区块链是一种开源的金融服务系统,全网无边界,统一使用加密代币充当各类资产。在未来,大多数数字资产和商品都将实现代币化。", + "CURRENCY": "货币", + "TRADITIONAL_ASSETS": "传统资产", + "DIGITAL_GOODS": "数字商品", + "OFFCHAIN_ORDER_RELAY": "链下订单中继", + "OONCHAIN_SETTLEMENT": "链上最终结算", + "OFFCHAIN_ONCHAIN_DESCRIPTION": + "在 0x 协议中,所有订单都通过链下传输,大幅削减了损耗成本,能够有效避免区块链膨胀。任何人都可以构建中继方,由中继方广播订单,每促成一笔交易,就可以收取一笔交易费。", + "RELAYERS_HEADER": "基于 0X 协议构建的中继方", + "BENEFITS_HEADER": "0x 的好處", + "BENEFIT_ONE_TITLE": "去信任化的交易机制", + "BENEFIT_ONE_DESCRIPTION": + "基于以太坊的分布式网络构建,去除中心体系单点故障,保证无间断运营,每笔交易都自动操作进行结算,完全解除交易对手风险。", + "BENEFIT_TWO_TITLE": "共享流动性", + "BENEFIT_TWO_DESCRIPTION": + "通过共享标准 API,让中继方轻松聚集流动池,随着越来越多的中继方纷纷上线,将形成充裕的流动性,创造网络效应。", + "BENEFIT_THREE_TITLE": "开源优势", + "BENEFIT_THREE_DESCRIPTION": + "0x 是一种开源协议,全网无边界,可供免费使用。用户可以直接联系已知的交易对象进行免费交易,还可以支付一定数额的 ZRX 代币,以访问中继方的流动池。", + "BUILDING_BLOCK_SECTION_HEADER": "去中心化应用的构建块", + "BUILDING_BLOCK_SECTION_DESCRIPTION": + "0x 协议是需要交易功能的去中心化应用的可插构建块。如今许多开发人员都在使用 0x 协议构建 Web 应用程序和智能合约,赶快加入这一行列吧!", + "DEV_TOOLS_PROMPT": "了解具体的构建方法,请参见", + "SMART_CONTRACT": "智能合约 的文档", + "DOCS": "", + "AND": "和", + "DECENTRALIZED_GOVERNANCE": "去中心化的治理", + "DECENTRALIZED_GOVERNANCE_DESCRIPTION": + "去中心化组织使用代币代表所有权,指引其治理逻辑。去中心化组织利用 0x 协议,可以无缝安全地进行启动资金所有权的交易。", + "PREDICTION_MARKETS": "预测市场", + "PREDICTION_MARKETS_DESCRIPTION": + "去中心化预测市场平台会根据现实世界中发生的事件,按照其中包含的金融风险生成代币集合。使用 0x 协议,允许这些代币即刻交易。", + "STABLE_TOKENS": "稳定代币", + "STABLE_TOKENS_DESCRIPTION": + "StableCoins 等新型经济结构的成功建设有赖于高效的流动性市场的支持。0x 协议能有效促进底层经济机制,利于代币保持稳定。", + "DECENTRALIZED_LOANS": "去中心化的借贷模式", + "DECENTRALIZED_LOANS_DESCRIPTION": + "高效借贷需要流动性市场的支持,为投资者提供方便购买、转卖借贷商品的平台。使用 0x 协议能够为借款方搭建一个自组织的生态系统,高效地针对所有未偿贷款确定市场价格。", + "FUND_MANAGEMENT": "基金管理", + "FUND_MANAGEMENT_DESCRIPTION": + "去中心化基金管理通过划分需事先商定的资产类别,有效限制基金经理的投资行为。向基金管理智能合约中嵌入 0x 协议,可确保其遵守安全约束。", + "FINAL_CALL_TO_ACTION": "开始构建去中心化的未来", + "DOCUMENTATION": "文档", + "COMMUNITY": "社区", + "ORGANIZATION": "组织介绍", + "ABOUT": "关于我们", + "CAREERS": "人才招聘", + "CONTACT": "联系方式", + "BLOG": "博客", + "FORUM": "论坛", + "CONNECT": "0x 连接", + "WHITEPAPER": "白皮书", + "WIKI": "维基", + "FAQ": "FAQ", + "SMART_CONTRACTS": "0x 智能合约", + "STANDARD_RELAYER_API": "中继方标准API", + "PORTAL_DAPP": "去中心化应用门户", + "WEBSITE": "网站", + "DEVELOPERS": "首页", + "HOME": "Rocket.chat", + "ROCKETCHAT": "开发人员" +} diff --git a/packages/website/translations/english.json b/packages/website/translations/english.json new file mode 100644 index 000000000..8aebe1848 --- /dev/null +++ b/packages/website/translations/english.json @@ -0,0 +1,73 @@ +{ + "TOP_HEADER": "powering decentralized exchange", + "TOP_TAGLINE": + "0x is an open, permissionless protocol allowing for ERC20 tokens to be traded on the Ethereum blockchain.", + "BUILD_CALL_TO_ACTION": "build on 0x", + "COMMUNITY_CALL_TO_ACTION": "join the community", + "PROJECTS_HEADER": "projects building on 0x", + "FULL_LIST_PROMPT": "view the", + "FULL_LIST_LINK": "full list", + "TOKENIZED_SECTION_HEADER": "the world's value is becoming tokenized", + "TOKENIZED_SECTION_DESCRIPTION": + "the Ethereum blockchain is an open, borderless financial system that represents a wide variety of assets as cryptographic tokens. In the future, most digital assets and goods will be tokenized.", + "CURRENCY": "currency", + "TRADITIONAL_ASSETS": "traditional assets", + "DIGITAL_GOODS": "digital goods", + "OFFCHAIN_ORDER_RELAY": "off-chain order relay", + "OONCHAIN_SETTLEMENT": "on-chain settlement", + "OFFCHAIN_ONCHAIN_DESCRIPTION": + "in 0x protocol, orders are transported off-chain, massively reducing gas costs and eliminating blockchain bloat. Relayers help broadcast orders and collect a fee each time they facilitate a trade. Anyone can build a relayer.", + "RELAYERS_HEADER": "relayers building on 0x", + "BENEFITS_HEADER": "benefits of 0x", + "BENEFIT_ONE_TITLE": "trustless exchange", + "BENEFIT_ONE_DESCRIPTION": + "built on Ethereum's distributed network with no centralized point of failure and no down time, each trade is settled atomically and without counterparty risk.", + "BENEFIT_TWO_TITLE": "shared liquidity", + "BENEFIT_TWO_DESCRIPTION": + "by sharing a standard API, relayers can easily aggregate liquidity pools, creating network effects around liquidity that compound as more relayers come online.", + "BENEFIT_THREE_TITLE": "open source", + "BENEFIT_THREE_DESCRIPTION": + "0x is open source, permissionless and free to use. Trade directly with a known counterparty for free or pay a relayer some ZRX tokens to access their liquidity pool.", + "BUILDING_BLOCK_SECTION_HEADER": "a building block for dApps", + "BUILDING_BLOCK_SECTION_DESCRIPTION": + "0x protocol is a pluggable building block for dApps that require exchange functionality. Join the many developers that are already using 0x in their web applications and smart contracts.", + "DEV_TOOLS_PROMPT": "learn how in our", + "SMART_CONTRACT": "smart contract", + "DOCS": "docs", + "AND": "and", + "DECENTRALIZED_GOVERNANCE": "decentralized governance", + "DECENTRALIZED_GOVERNANCE_DESCRIPTION": + "Decentralized organizations use tokens to represent ownership and guide their governance logic. 0x allows decentralized organizations to seamlessly and safely trade ownership for startup capital.", + "PREDICTION_MARKETS": "prediction markets", + "PREDICTION_MARKETS_DESCRIPTION": + "decentralized prediction market platforms generate sets of tokens that represent a financial stake in the outcomes of real-world events. 0x allows these tokens to be instantly tradable.", + "STABLE_TOKENS": "stable tokens", + "STABLE_TOKENS_DESCRIPTION": + "Novel economic constructs such as stable coins require efficient, liquid markets to succeed. 0x will facilitate the underlying economic mechanisms that allow these tokens to remain stable.", + "DECENTRALIZED_LOANS": "decentralized loans", + "DECENTRALIZED_LOANS_DESCRIPTION": + "Efficient lending requires liquid markets where investors can buy and re-sell loans. 0x enables an ecosystem of lenders to self-organize and efficiently determine market prices for all outstanding loans.", + "FUND_MANAGEMENT": "fund management", + "FUND_MANAGEMENT_DESCRIPTION": + "Decentralized fund management limits fund managers to investing in pre-agreed upon asset classes. Embedding 0x into fund management smart contracts enables them to enforce these security constraints.", + "FINAL_CALL_TO_ACTION": "get started on building the decentralized future", + "DOCUMENTATION": "documentation", + "COMMUNITY": "community", + "ORGANIZATION": "organization", + "ABOUT": "about", + "CAREERS": "careers", + "CONTACT": "contact", + "BLOG": "blog", + "FORUM": "forum", + "CONNECT": "0x Connect", + "WHITEPAPER": "whitepaper", + "WIKI": "wiki", + "FAQ": "FAQ", + "SMART_CONTRACTS": "0x smart contracts", + "STANDARD_RELAYER_API": "standard relayer API", + "PORTAL_DAPP": "portal dApp", + "WEBSITE": "website", + "DEVELOPERS": "home", + "HOME": "rocket.chat", + "ROCKETCHAT": "developers" +} diff --git a/packages/website/translations/korean.json b/packages/website/translations/korean.json new file mode 100644 index 000000000..9a9ae715c --- /dev/null +++ b/packages/website/translations/korean.json @@ -0,0 +1,72 @@ +{ + "TOP_HEADER": "탈중앙화된 거래소를 가능하게 하는 원동력", + "TOP_TAGLINE": "0x는 이더리움 블록체인에서 ERC20 토큰을 거래할 수 있게 해 주는 무허가형 개방 프로토콜입니다.", + "BUILD_CALL_TO_ACTION": "0x 기반", + "COMMUNITY_CALL_TO_ACTION": "커뮤니티 참여", + "PROJECTS_HEADER": "0x 기반 프로젝트", + "FULL_LIST_PROMPT": "보기", + "FULL_LIST_LINK": "전체 목록", + "TOKENIZED_SECTION_HEADER": "전 세계의 가치가 토큰으로 변환되고 있음", + "TOKENIZED_SECTION_DESCRIPTION": + "이더리움 블록체인은 국경이 없는 개방형 결제 시스템으로, 다양한 자산을 암호화 토큰으로 나타내 줍니다. 앞으로는 디지털 자산과 상품 대부분이 토큰으로 바뀔 것입니다.", + "CURRENCY": "통화", + "TRADITIONAL_ASSETS": "전통적 자산", + "DIGITAL_GOODS": "디지털 상품", + "OFFCHAIN_ORDER_RELAY": "오프체인 주문 릴레이", + "OONCHAIN_SETTLEMENT": "온체인 정산", + "OFFCHAIN_ONCHAIN_DESCRIPTION": + "0x 프로토콜에서 주문은 오프체인으로 전달되므로, 가스 비용이 대폭 줄고 블록체인이 불필요하게 커지지 않습니다. Relayer는 주문을 브로드캐스팅할 수 있게 해 주고, 주문에서 거래가 진행될 때마다 수수료를 받을 수 있습니다. 누구든지 Relayer를 생성할 수 있습니다.", + "RELAYERS_HEADER": "0x 기반 Relayer", + "BENEFITS_HEADER": "모두 보기", + "BENEFIT_ONE_TITLE": "신뢰할 수 없는 거래소", + "BENEFIT_ONE_DESCRIPTION": + "중앙화된 오류 지점과 중단 시간이 없는 이더리움의 분산 네트워크를 바탕으로 구축되므로, 각 거래가 개별 단위로 정산되며 거래 상대방으로 인한 위험도 없습니다.", + "BENEFIT_TWO_TITLE": "공유 유동 자금", + "BENEFIT_TWO_DESCRIPTION": + "표준 API를 공유하므로 Relayer는 유동 자금 풀을 쉽게 취합할 수 있습니다. 따라서 더 많은 Relayer가 온라인 상태가 되면 유동 자금을 바탕으로 한 복합적인 네트워크 효과를 만들 수 있습니다.", + "BENEFIT_THREE_TITLE": "오픈 소스", + "BENEFIT_THREE_DESCRIPTION": + "0x는 무허가형 오프 소스이며, 무료로 사용할 수 있습니다. 이미 알고 있는 상대방과 직접 무료로 거래하거나, Relayer에 약간의 ZRX 토큰을 지불하여 해당 유동 자금 풀에 액세스할 수 있습니다.", + "BUILDING_BLOCK_SECTION_HEADER": "dApp을 위한 기본 구성 요소", + "BUILDING_BLOCK_SECTION_DESCRIPTION": + "0x 프로토콜은 거래소 기능이 필요한 dApp을 위한 연결 가능한 기본 구성 요소입니다. 웹 애플리케이션과 스마트 계약에서 이미 0x를 사용하고 있는 여러 개발자 대열에 동참해 보세요.", + "DEV_TOOLS_PROMPT": "수행하는 방법 알아보기", + "SMART_CONTRACT": "스마트 계약 문서에 ", + "DOCS": "", + "AND": "및", + "DECENTRALIZED_GOVERNANCE": "탈중앙화된 거버넌스", + "DECENTRALIZED_GOVERNANCE_DESCRIPTION": + "탈중앙화된 조직은 토큰을 사용하여 소유권을 나타내며 거버넌스 로직의 방향을 정합니다. 0x를 사용하면 탈중앙화된 조직이 안전하고 원활하게 스타트업 자금의 소유권을 주고받을 수 있습니다.", + "PREDICTION_MARKETS": "예측 시장", + "PREDICTION_MARKETS_DESCRIPTION": + "탈중앙화된 예측 시장 플랫폼은 실제 이벤트 결과에서의 금전적인 지분을 나타내는 토큰 세트를 생성합니다. 0x를 사용하면 이러한 토큰을 즉시 거래할 수 있습니다.", + "STABLE_TOKENS": "안정적인 토큰", + "STABLE_TOKENS_DESCRIPTION": + "안정적인 코인과 같은 새롭게 등장한 경제 개념은 효율성이 높은 유동 시장에 적용해야 성공할 수 있습니다. 0x는 이러한 토큰이 안정적인 상태를 유지할 수 있게 하는 기반 경제 메커니즘을 가능하게 합니다.", + "DECENTRALIZED_LOANS": "탈중앙화된 대출", + "DECENTRALIZED_LOANS_DESCRIPTION": + "대출이 효율적으로 이루어지려면 투자자가 대출 상품을 사고 다시 파는 유동 시장이 있어야 합니다. 0x를 통해 전체 미상환 대출이 자체 구성되고 이러한 대출의 시장 가격을 효율적으로 결정할 수 있는 대출 기관 생태계가 가능해집니다.", + "FUND_MANAGEMENT": "자금 관리", + "FUND_MANAGEMENT_DESCRIPTION": + "탈중앙화된 자금 관리로 자금 운용 관리자가 사전 합의된 자산 등급에 투자하는 것이 제한됩니다. 자금 관리 스마트 계약에 0x를 포함시키면 자금 운용 담당자가 보안 관련 제한 사항을 강화할 수 있습니다.", + "FINAL_CALL_TO_ACTION": "탈중앙화된 미래 구축하기", + "DOCUMENTATION": "문서", + "COMMUNITY": "커뮤니티", + "ORGANIZATION": "조직", + "ABOUT": "기업 정보", + "CAREERS": "채용", + "CONTACT": "문의", + "BLOG": "블로그", + "FORUM": "포럼", + "CONNECT": "0x Connect", + "WHITEPAPER": "백서", + "WIKI": "위키", + "FAQ": "FAQ", + "SMART_CONTRACTS": "0x 스마트 계약", + "STANDARD_RELAYER_API": "Standard Relayer API", + "PORTAL_DAPP": "포털 dApp", + "WEBSITE": "Website", + "DEVELOPERS": "홈", + "HOME": "Rocket.chat", + "ROCKETCHAT": "개발자" +} diff --git a/packages/website/translations/russian.json b/packages/website/translations/russian.json new file mode 100644 index 000000000..a4e47264b --- /dev/null +++ b/packages/website/translations/russian.json @@ -0,0 +1,72 @@ +{ + "TOP_HEADER": "Стимулирование децентрализованного обмена", + "TOP_TAGLINE": "0x — это протокол с открытым кодом, позволяющий торговать токенами ERC20, на блокчейне Ethereum.", + "BUILD_CALL_TO_ACTION": "Разрабатывайте на 0x", + "COMMUNITY_CALL_TO_ACTION": "Сообщество", + "PROJECTS_HEADER": "Прожкты разработанные на 0х", + "FULL_LIST_PROMPT": "Просмотреть", + "FULL_LIST_LINK": "полный список", + "TOKENIZED_SECTION_HEADER": "Сегодняшний мир движется к токенизации ценности", + "TOKENIZED_SECTION_DESCRIPTION": + "Блокчейн Ethereum — это открытая, безграничная финансовая система, большое количество активов которой представлено в виде криптографических токенов. В будущем большая часть цифровых активов и товаров будет токенизирована.", + "CURRENCY": "Валюта", + "TRADITIONAL_ASSETS": "Традиционные активы", + "DIGITAL_GOODS": "Цифровые товары", + "OFFCHAIN_ORDER_RELAY": "Офчейн-ордер", + "OONCHAIN_SETTLEMENT": "Ончейн-транзакция", + "OFFCHAIN_ONCHAIN_DESCRIPTION": + "При использовании протокола 0x ордера проводятся вне блокчейна, что сокращает расходы на газ (топливо) и предотвращает раздувание блокчейна. Релейеры помогают провести ордера и берут комиссию каждый раз, когда способствуют торгам. Любой может создать релейера.", + "RELAYERS_HEADER": "РЕЛЕЙЕРЫ, РАЗРАБОТАННЫЕ НА 0X", + "BENEFITS_HEADER": "Просмотреть все", + "BENEFIT_ONE_TITLE": "Обмен, не требующий доверия", + "BENEFIT_ONE_DESCRIPTION": + "Каждая сделка, основанная на распределенной сети Ethereum без единой точки отказа и с нулевым временем простоя, является атомарной операцией и проводится без риска для контрагента.", + "BENEFIT_TWO_TITLE": "Общая ликвидность", + "BENEFIT_TWO_DESCRIPTION": + "При обмене стандартным API релейеры могут легко объединять пулы ликвидности, создавая сетевые эффекты вокруг ликвидности, которые усложняются с появлением новых релейеров в сети.", + "BENEFIT_THREE_TITLE": "Открытый исходный код", + "BENEFIT_THREE_DESCRIPTION": + "0x — это бесплатный и доступный протокол с открытым кодом. Торгуйте напрямую с известными контрагентами бесплатно или заплатите релейеру несколько ZRX-токенов, чтобы получить доступ к его пулу ликвидности.", + "BUILDING_BLOCK_SECTION_HEADER": "Строительный блок для dApp", + "BUILDING_BLOCK_SECTION_DESCRIPTION": + "Протокол 0x — это подключаемый строительный блок для dApp, нуждающихся в функционале обмена. Присоединяйтесь к разработчикам, которые уже используют 0x в своих веб-приложениях и смарт-контрактах.", + "DEV_TOOLS_PROMPT": "Узнайте как это сделать в документации к", + "SMART_CONTRACT": "смарт-контрактам", + "DOCS": "", + "AND": "и", + "DECENTRALIZED_GOVERNANCE": "Децентрализированное управление", + "DECENTRALIZED_GOVERNANCE_DESCRIPTION": + "Децентрализованные организации используют токены для представления собственности и внедрения своей логики управления. Протокол 0x позволяет децентрализованным организациям беспрепятственно и безопасно торговать собственностью для стартового капитала.", + "PREDICTION_MARKETS": "Рынки предсказаний", + "PREDICTION_MARKETS_DESCRIPTION": + "Платформы для децентрализованных рынков предсказаний генерируют множество токенов, которые представляют собой финансовую долю в результате реальных событий. Протокол 0x позволяет мгновенно торговать эти токены.", + "STABLE_TOKENS": "Стабильные токены", + "STABLE_TOKENS_DESCRIPTION": + "Новые экономические конструкции, например стабильные токены, требуют наличия успешных и эффективных ликвидных рынков. Протокол 0x призван облегчить основные экономические механизмы, которые позволят этим токенам оставаться стабильными.", + "DECENTRALIZED_LOANS": "Децентрализированные займы", + "DECENTRALIZED_LOANS_DESCRIPTION": + "Эффективное кредитование требует наличия ликвидных рынков, где инвесторы могут купить и перепродать займы. Протокол 0x позволяет экосистеме кредиторов самоорганизовываться и эффективно определять рыночные цены для всех невыплаченных займов.", + "FUND_MANAGEMENT": "Управление средствами", + "FUND_MANAGEMENT_DESCRIPTION": + "Децентрализованное управление средствами ограничивает управляющих средствами путем определения предварительно согласованных классов активов для инвестиций. Встраивание протокола 0x в смарт-контракты для управления средствами позволяет им обеспечить исполнение этих ограничений безопасности.", + "FINAL_CALL_TO_ACTION": "Начните создавать децентрализованное будущее", + "DOCUMENTATION": "Документация", + "COMMUNITY": "Сообщество", + "ORGANIZATION": "Организация", + "ABOUT": "Kоманда", + "CAREERS": "Карьера", + "CONTACT": "Связаться с нами", + "BLOG": "Блог", + "FORUM": "Форум", + "CONNECT": "0x Connect", + "WHITEPAPER": "Whitepaper", + "WIKI": "Вики", + "FAQ": "Документация", + "SMART_CONTRACTS": "0x Смарт-контракты ", + "STANDARD_RELAYER_API": "standard relayer API", + "PORTAL_DAPP": "DApp-портал", + "WEBSITE": "Веб-сайт", + "DEVELOPERS": "Домашняя страница", + "HOME": "Rocket.chat", + "ROCKETCHAT": "Для разработчиков" +} diff --git a/packages/website/translations/spanish.json b/packages/website/translations/spanish.json new file mode 100644 index 000000000..c2aaf384c --- /dev/null +++ b/packages/website/translations/spanish.json @@ -0,0 +1,73 @@ +{ + "TOP_HEADER": "potenciar el intercambio descentralizado", + "TOP_TAGLINE": + "0x es un protocolo abierto y sin restricciones que permite el intercambio de tokens ERC20 en la cadena de bloques Ethereum.", + "BUILD_CALL_TO_ACTION": "crear en 0x", + "COMMUNITY_CALL_TO_ACTION": "unirse a la comunidad", + "PROJECTS_HEADER": "proyectos creados en 0x", + "FULL_LIST_PROMPT": "ver la", + "FULL_LIST_LINK": "lista completa", + "TOKENIZED_SECTION_HEADER": "el valor del mundo se está tokenizando", + "TOKENIZED_SECTION_DESCRIPTION": + "la cadena de bloques Ethereum es un sistema financiero abierto y sin fronteras que representa una amplia variedad de activos como tokens criptográficos. En el futuro, la mayoría de los activos y bienes digitales estarán tokenizados.", + "CURRENCY": "moneda", + "TRADITIONAL_ASSETS": "activos tradicionales", + "DIGITAL_GOODS": "bienes digitales", + "OFFCHAIN_ORDER_RELAY": "orden retransmisión fuera de cadena", + "OONCHAIN_SETTLEMENT": "liquidación en cadena", + "OFFCHAIN_ONCHAIN_DESCRIPTION": + "en el protocolo 0x, las órdenes se transportan fuera de la cadena, lo que reduce enormemente los costos de combustible y elimina el sobredimensionamiento de la cadena de bloques. Los transmisores ayudan a emitir órdenes y a cobrar un cargo cada vez que facilitan un intercambio. Cualquier persona puede crear un transmisor.", + "RELAYERS_HEADER": "transmisores creados en 0x", + "BENEFITS_HEADER": "beneficios de 0x", + "BENEFIT_ONE_TITLE": "intercambio confiable", + "BENEFIT_ONE_DESCRIPTION": + "creado en la red distribuida de Ethereum sin ningún punto de error centralizado y sin tiempo de inactividad; cada intercambio se concreta atómicamente y sin riesgos para la contraparte.", + "BENEFIT_TWO_TITLE": "liquidez compartida", + "BENEFIT_TWO_DESCRIPTION": + "al compartir un API estándar, los transmisores pueden acumular fácilmente fondos de liquidez, lo que crea efectos de red en torno a la liquidez que se forma a medida que más transmisores se conectan.", + "BENEFIT_THREE_TITLE": "código abierto", + "BENEFIT_THREE_DESCRIPTION": + "0x es código abierto, su uso es gratuito. Negocie directamente con una contraparte conocida sin costo o páguele a un transmisor con algunos para acceder a su fondo de liquidez.", + "BUILDING_BLOCK_SECTION_HEADER": "un bloque de creación para dApps", + "BUILDING_BLOCK_SECTION_DESCRIPTION": + "el protocolo 0x es un bloque de creación acoplable para dApps que requiere una funcionalidad de intercambio. Únase a los numerosos desarrolladores que ya utilizan 0x en sus aplicaciones web y contratos inteligentes.", + "DEV_TOOLS_PROMPT": "aprenda cómo hacerlo en nuestros documentos de", + "SMART_CONTRACT": "contratos inteligentes", + "DOCS": "", + "AND": "y", + "DECENTRALIZED_GOVERNANCE": "gobierno descentralizado", + "DECENTRALIZED_GOVERNANCE_DESCRIPTION": + "las organizaciones descentralizadas utilizan tokens para representar la titularidad y guiar su lógica de gobierno. 0x les permite a las organizaciones descentralizadas intercambiar titularidad por capital inicial sin problemas y de forma segura.", + "PREDICTION_MARKETS": "mercados de predicción", + "PREDICTION_MARKETS_DESCRIPTION": + "las plataformas del mercado de predicción descentralizado generan conjuntos de tokens que representan un interés financiero en los resultados de los sucesos del mundo real. 0x permite que estos tokens se negocien de manera instantánea.", + "STABLE_TOKENS": "tokens estables", + "STABLE_TOKENS_DESCRIPTION": + "las construcciones económicas novedosas, como las monedas estables, requieren mercados eficientes y con liquidez para tener éxito. 0x facilitará los mecanismos económicos subyacentes que permiten que estos tokens continúen siendo estables.", + "DECENTRALIZED_LOANS": "préstamos descentralizados", + "DECENTRALIZED_LOANS_DESCRIPTION": + "los préstamos eficientes requieren mercados con liquidez donde los inversores pueden comprar y revender préstamos. 0x facilita un ecosistema de prestamistas que se organizan ellos mismos y determinan, de forma eficaz, los precios del mercado para todos los préstamos pendientes.", + "FUND_MANAGEMENT": "administración de fondos", + "FUND_MANAGEMENT_DESCRIPTION": + "la administración descentralizada de fondos limita a los administradores de fondos a invertir en clases de activos preacordadas. Integrar 0x a los contratos inteligentes de la administración de fondos les permite imponer esas restricciones de seguridad.", + "FINAL_CALL_TO_ACTION": "comience a crear el futuro descentralizado", + "DOCUMENTATION": "documentación", + "COMMUNITY": "comunidad", + "ORGANIZATION": "organización", + "ABOUT": "equipo", + "CAREERS": "empleo", + "CONTACT": "contacto", + "BLOG": "blog", + "FORUM": "foro", + "CONNECT": "0x Connect", + "WHITEPAPER": "documento técnico", + "WIKI": "wiki", + "FAQ": "preguntas frecuentes", + "SMART_CONTRACTS": "0x contratos inteligentes", + "STANDARD_RELAYER_API": "API de transmisión estándar", + "PORTAL_DAPP": "portal dApp", + "WEBSITE": "website", + "DEVELOPERS": "inicio", + "HOME": "rocket.chat", + "ROCKETCHAT": "desarrolladores" +} diff --git a/packages/website/ts/components/footer.tsx b/packages/website/ts/components/footer.tsx index a0f1a0c96..de20d074d 100644 --- a/packages/website/ts/components/footer.tsx +++ b/packages/website/ts/components/footer.tsx @@ -1,9 +1,13 @@ import * as _ from 'lodash'; +import DropDownMenu from 'material-ui/DropDownMenu'; +import MenuItem from 'material-ui/MenuItem'; import * as React from 'react'; import { Link } from 'react-router-dom'; -import { WebsitePaths } from 'ts/types'; +import { Dispatcher } from 'ts/redux/dispatcher'; +import { Deco, Key, Language, WebsitePaths } from 'ts/types'; import { colors } from 'ts/utils/colors'; import { constants } from 'ts/utils/constants'; +import { Translate } from 'ts/utils/translate'; interface MenuItemsBySection { [sectionName: string]: FooterMenuItem[]; @@ -15,105 +19,114 @@ interface FooterMenuItem { isExternal?: boolean; } -enum Sections { - Documentation = 'Documentation', - Community = 'Community', - Organization = 'Organization', -} - const ICON_DIMENSION = 16; -const menuItemsBySection: MenuItemsBySection = { - Documentation: [ - { - title: '0x.js', - path: WebsitePaths.ZeroExJs, - }, - { - title: '0x Smart Contracts', - path: WebsitePaths.SmartContracts, - }, - { - title: '0x Connect', - path: WebsitePaths.Connect, - }, - { - title: 'Whitepaper', - path: WebsitePaths.Whitepaper, - isExternal: true, - }, - { - title: 'Wiki', - path: WebsitePaths.Wiki, - }, - { - title: 'FAQ', - path: WebsitePaths.FAQ, - }, - ], - Community: [ - { - title: 'Rocket.chat', - isExternal: true, - path: constants.URL_ZEROEX_CHAT, - }, - { - title: 'Blog', - isExternal: true, - path: constants.URL_BLOG, - }, - { - title: 'Twitter', - isExternal: true, - path: constants.URL_TWITTER, - }, - { - title: 'Reddit', - isExternal: true, - path: constants.URL_REDDIT, - }, - { - title: 'Forum', - isExternal: true, - path: constants.URL_DISCOURSE_FORUM, - }, - ], - Organization: [ - { - title: 'About', - isExternal: false, - path: WebsitePaths.About, - }, - { - title: 'Careers', - isExternal: true, - path: constants.URL_ANGELLIST, - }, - { - title: 'Contact', - isExternal: true, - path: 'mailto:team@0xproject.com', - }, - ], -}; + const linkStyle = { color: colors.white, cursor: 'pointer', }; -const titleToIcon: { [title: string]: string } = { - 'Rocket.chat': 'rocketchat.png', - Blog: 'medium.png', - Twitter: 'twitter.png', - Reddit: 'reddit.png', - Forum: 'discourse.png', +const languageToMenuTitle = { + [Language.English]: 'English', + [Language.Russian]: 'Русский', + [Language.Spanish]: 'Español', + [Language.Korean]: '한국어', + [Language.Chinese]: '中文', }; -export interface FooterProps {} +export interface FooterProps { + translate: Translate; + dispatcher: Dispatcher; +} -interface FooterState {} +interface FooterState { + selectedLanguage: Language; +} export class Footer extends React.Component<FooterProps, FooterState> { + constructor(props: FooterProps) { + super(); + this.state = { + selectedLanguage: props.translate.getLanguage(), + }; + } public render() { + const menuItemsBySection: MenuItemsBySection = { + [Key.Documentation]: [ + { + title: '0x.js', + path: WebsitePaths.ZeroExJs, + }, + { + title: this.props.translate.get(Key.SmartContracts, Deco.Cap), + path: WebsitePaths.SmartContracts, + }, + { + title: this.props.translate.get(Key.Connect, Deco.Cap), + path: WebsitePaths.Connect, + }, + { + title: this.props.translate.get(Key.Whitepaper, Deco.Cap), + path: WebsitePaths.Whitepaper, + isExternal: true, + }, + { + title: this.props.translate.get(Key.Wiki, Deco.Cap), + path: WebsitePaths.Wiki, + }, + { + title: this.props.translate.get(Key.Faq, Deco.Cap), + path: WebsitePaths.FAQ, + }, + ], + [Key.Community]: [ + { + title: this.props.translate.get(Key.RocketChat, Deco.Cap), + isExternal: true, + path: constants.URL_ZEROEX_CHAT, + }, + { + title: this.props.translate.get(Key.Blog, Deco.Cap), + isExternal: true, + path: constants.URL_BLOG, + }, + { + title: 'Twitter', + isExternal: true, + path: constants.URL_TWITTER, + }, + { + title: 'Reddit', + isExternal: true, + path: constants.URL_REDDIT, + }, + { + title: this.props.translate.get(Key.Forum, Deco.Cap), + isExternal: true, + path: constants.URL_DISCOURSE_FORUM, + }, + ], + [Key.Organization]: [ + { + title: this.props.translate.get(Key.About, Deco.Cap), + isExternal: false, + path: WebsitePaths.About, + }, + { + title: this.props.translate.get(Key.Careers, Deco.Cap), + isExternal: true, + path: constants.URL_ANGELLIST, + }, + { + title: this.props.translate.get(Key.Contact, Deco.Cap), + isExternal: true, + path: 'mailto:team@0xproject.com', + }, + ], + }; + const languageMenuItems = _.map(languageToMenuTitle, (menuTitle: string, language: Language) => { + return <MenuItem key={menuTitle} value={language} primaryText={menuTitle} />; + }); return ( <div className="relative pb4 pt2" style={{ backgroundColor: colors.darkerGrey }}> <div className="mx-auto max-width-4 md-px2 lg-px0 py4 clearfix" style={{ color: colors.white }}> @@ -132,25 +145,34 @@ export class Footer extends React.Component<FooterProps, FooterState> { > © ZeroEx, Intl. </div> + <div className="pt4 center"> + <DropDownMenu + labelStyle={{ color: colors.white }} + value={this.state.selectedLanguage} + onChange={this._updateLanguage.bind(this)} + > + {languageMenuItems} + </DropDownMenu> + </div> </div> </div> <div className="col lg-col-8 md-col-8 col-12 lg-pl4 md-pl4"> <div className="col lg-col-4 md-col-4 col-12"> <div className="lg-right md-right sm-center"> - {this._renderHeader(Sections.Documentation)} - {_.map(menuItemsBySection[Sections.Documentation], this._renderMenuItem.bind(this))} + {this._renderHeader(Key.Documentation)} + {_.map(menuItemsBySection[Key.Documentation], this._renderMenuItem.bind(this))} </div> </div> <div className="col lg-col-4 md-col-4 col-12 lg-pr2 md-pr2"> <div className="lg-right md-right sm-center"> - {this._renderHeader(Sections.Community)} - {_.map(menuItemsBySection[Sections.Community], this._renderMenuItem.bind(this))} + {this._renderHeader(Key.Community)} + {_.map(menuItemsBySection[Key.Community], this._renderMenuItem.bind(this))} </div> </div> <div className="col lg-col-4 md-col-4 col-12"> <div className="lg-right md-right sm-center"> - {this._renderHeader(Sections.Organization)} - {_.map(menuItemsBySection[Sections.Organization], this._renderMenuItem.bind(this))} + {this._renderHeader(Key.Organization)} + {_.map(menuItemsBySection[Key.Organization], this._renderMenuItem.bind(this))} </div> </div> </div> @@ -166,6 +188,13 @@ export class Footer extends React.Component<FooterProps, FooterState> { ); } private _renderMenuItem(item: FooterMenuItem) { + const titleToIcon: { [title: string]: string } = { + [this.props.translate.get(Key.RocketChat, Deco.Cap)]: 'rocketchat.png', + [this.props.translate.get(Key.Blog, Deco.Cap)]: 'medium.png', + Twitter: 'twitter.png', + Reddit: 'reddit.png', + [this.props.translate.get(Key.Forum, Deco.Cap)]: 'discourse.png', + }; const iconIfExists = titleToIcon[item.title]; return ( <div key={item.title} className="sm-center" style={{ fontSize: 13, paddingTop: 25 }}> @@ -195,9 +224,8 @@ export class Footer extends React.Component<FooterProps, FooterState> { </div> ); } - private _renderHeader(title: string) { + private _renderHeader(key: Key) { const headerStyle = { - textTransform: 'uppercase', color: colors.grey400, letterSpacing: 2, fontFamily: 'Roboto Mono', @@ -205,8 +233,14 @@ export class Footer extends React.Component<FooterProps, FooterState> { }; return ( <div className="lg-pb2 md-pb2 sm-pt4" style={headerStyle}> - {title} + {this.props.translate.get(key, Deco.Upper)} </div> ); } + private _updateLanguage(e: any, index: number, value: Language) { + this.setState({ + selectedLanguage: value, + }); + this.props.dispatcher.updateSelectedLanguage(value); + } } diff --git a/packages/website/ts/components/portal.tsx b/packages/website/ts/components/portal.tsx index 0409f28c0..4871997ac 100644 --- a/packages/website/ts/components/portal.tsx +++ b/packages/website/ts/components/portal.tsx @@ -27,6 +27,7 @@ import { BlockchainErrs, HashData, Order, ProviderType, ScreenWidths, TokenByAdd import { colors } from 'ts/utils/colors'; import { configs } from 'ts/utils/configs'; import { constants } from 'ts/utils/constants'; +import { Translate } from 'ts/utils/translate'; import { utils } from 'ts/utils/utils'; const THROTTLE_TIMEOUT = 100; @@ -52,6 +53,7 @@ export interface PortalAllProps { location: Location; flashMessage?: string | React.ReactNode; lastForceTokenStateRefetch: number; + translate: Translate; } interface PortalAllState { @@ -166,6 +168,7 @@ export class Portal extends React.Component<PortalAllProps, PortalAllState> { blockchainIsLoaded={this.props.blockchainIsLoaded} location={this.props.location} blockchain={this._blockchain} + translate={this.props.translate} /> <div id="portal" className="mx-auto max-width-4" style={{ width: '100%' }}> <Paper className="mb3 mt2"> @@ -259,7 +262,7 @@ export class Portal extends React.Component<PortalAllProps, PortalAllState> { /> )} </div> - <Footer />; + <Footer translate={this.props.translate} dispatcher={this.props.dispatcher} /> </div> ); } diff --git a/packages/website/ts/components/top_bar/top_bar.tsx b/packages/website/ts/components/top_bar/top_bar.tsx index a412007f2..2723c2218 100644 --- a/packages/website/ts/components/top_bar/top_bar.tsx +++ b/packages/website/ts/components/top_bar/top_bar.tsx @@ -14,9 +14,10 @@ import { Identicon } from 'ts/components/ui/identicon'; import { DocsInfo } from 'ts/pages/documentation/docs_info'; import { NestedSidebarMenu } from 'ts/pages/shared/nested_sidebar_menu'; import { Dispatcher } from 'ts/redux/dispatcher'; -import { DocsMenu, MenuSubsectionsBySection, ProviderType, Styles, WebsitePaths } from 'ts/types'; +import { Deco, DocsMenu, Key, MenuSubsectionsBySection, ProviderType, Styles, WebsitePaths } from 'ts/types'; import { colors } from 'ts/utils/colors'; import { constants } from 'ts/utils/constants'; +import { Translate } from 'ts/utils/translate'; interface TopBarProps { userAddress?: string; @@ -28,6 +29,7 @@ interface TopBarProps { dispatcher?: Dispatcher; blockchainIsLoaded: boolean; location: Location; + translate: Translate; docsVersion?: string; availableDocVersions?: string[]; menu?: DocsMenu; @@ -95,10 +97,16 @@ export class TopBar extends React.Component<TopBarProps, TopBarState> { <MenuItem style={{ fontSize: styles.menuItem.fontSize }} primaryText="0x.js" /> </Link>, <Link key="subMenuItem-smartContracts" to={WebsitePaths.SmartContracts} className="text-decoration-none"> - <MenuItem style={{ fontSize: styles.menuItem.fontSize }} primaryText="Smart Contracts" /> + <MenuItem + style={{ fontSize: styles.menuItem.fontSize }} + primaryText={this.props.translate.get(Key.SmartContract, Deco.CapWords)} + /> </Link>, <Link key="subMenuItem-0xconnect" to={WebsitePaths.Connect} className="text-decoration-none"> - <MenuItem style={{ fontSize: styles.menuItem.fontSize }} primaryText="0x Connect" /> + <MenuItem + style={{ fontSize: styles.menuItem.fontSize }} + primaryText={this.props.translate.get(Key.Connect, Deco.CapWords)} + /> </Link>, <a key="subMenuItem-standard-relayer-api" @@ -106,7 +114,10 @@ export class TopBar extends React.Component<TopBarProps, TopBarState> { className="text-decoration-none" href={constants.URL_STANDARD_RELAYER_API_GITHUB} > - <MenuItem style={{ fontSize: styles.menuItem.fontSize }} primaryText="Standard Relayer API" /> + <MenuItem + style={{ fontSize: styles.menuItem.fontSize }} + primaryText={this.props.translate.get(Key.StandardRelayerApi, Deco.CapWords)} + /> </a>, <a key="subMenuItem-github" @@ -122,7 +133,10 @@ export class TopBar extends React.Component<TopBarProps, TopBarState> { className="text-decoration-none" href={`${WebsitePaths.Whitepaper}`} > - <MenuItem style={{ fontSize: styles.menuItem.fontSize }} primaryText="Whitepaper" /> + <MenuItem + style={{ fontSize: styles.menuItem.fontSize }} + primaryText={this.props.translate.get(Key.Whitepaper, Deco.CapWords)} + /> </a>, ]; const bottomBorderStyle = this._shouldDisplayBottomBar() ? styles.bottomBar : {}; @@ -137,7 +151,7 @@ export class TopBar extends React.Component<TopBarProps, TopBarState> { }; const hoverActiveNode = ( <div className="flex relative" style={{ color: menuIconStyle.color }}> - <div style={{ paddingRight: 10 }}>Developers</div> + <div style={{ paddingRight: 10 }}>{this.props.translate.get(Key.Developers, Deco.Cap)}</div> <div className="absolute" style={{ paddingLeft: 3, right: 3, top: -2 }}> <i className="zmdi zmdi-caret-right" style={{ fontSize: 22 }} /> </div> @@ -165,28 +179,28 @@ export class TopBar extends React.Component<TopBarProps, TopBarState> { style={styles.menuItem} /> <TopBarMenuItem - title="Wiki" + title={this.props.translate.get(Key.Wiki, Deco.Cap)} path={`${WebsitePaths.Wiki}`} style={styles.menuItem} isNightVersion={isNightVersion} isExternal={false} /> <TopBarMenuItem - title="Blog" + title={this.props.translate.get(Key.Blog, Deco.Cap)} path={constants.URL_BLOG} style={styles.menuItem} isNightVersion={isNightVersion} isExternal={true} /> <TopBarMenuItem - title="About" + title={this.props.translate.get(Key.About, Deco.Cap)} path={`${WebsitePaths.About}`} style={styles.menuItem} isNightVersion={isNightVersion} isExternal={false} /> <TopBarMenuItem - title="Portal DApp" + title={this.props.translate.get(Key.PortalDApp, Deco.CapWords)} path={`${WebsitePaths.Portal}`} isPrimary={true} style={styles.menuItem} @@ -233,46 +247,54 @@ export class TopBar extends React.Component<TopBarProps, TopBarState> { {this._renderDocsMenu()} {this._renderWiki()} <div className="pl1 py1 mt3" style={{ backgroundColor: colors.lightGrey }}> - Website + {this.props.translate.get(Key.Website, Deco.Cap)} </div> <Link to={WebsitePaths.Home} className="text-decoration-none"> - <MenuItem className="py2">Home</MenuItem> + <MenuItem className="py2">{this.props.translate.get(Key.Home, Deco.Cap)}</MenuItem> </Link> <Link to={`${WebsitePaths.Wiki}`} className="text-decoration-none"> - <MenuItem className="py2">Wiki</MenuItem> + <MenuItem className="py2">{this.props.translate.get(Key.Wiki, Deco.Cap)}</MenuItem> </Link> {!this._isViewing0xjsDocs() && ( <Link to={WebsitePaths.ZeroExJs} className="text-decoration-none"> - <MenuItem className="py2">0x.js Docs</MenuItem> + <MenuItem className="py2">0x.js {this.props.translate.get(Key.Docs, Deco.Cap)}</MenuItem> </Link> )} {!this._isViewingConnectDocs() && ( <Link to={WebsitePaths.Connect} className="text-decoration-none"> - <MenuItem className="py2">0x Connect Docs</MenuItem> + <MenuItem className="py2"> + {this.props.translate.get(Key.Connect, Deco.Cap)}{' '} + {this.props.translate.get(Key.Docs, Deco.Cap)} + </MenuItem> </Link> )} {!this._isViewingSmartContractsDocs() && ( <Link to={WebsitePaths.SmartContracts} className="text-decoration-none"> - <MenuItem className="py2">Smart Contract Docs</MenuItem> + <MenuItem className="py2"> + {this.props.translate.get(Key.SmartContract, Deco.Cap)}{' '} + {this.props.translate.get(Key.Docs, Deco.Cap)} + </MenuItem> </Link> )} {!this._isViewingPortal() && ( <Link to={`${WebsitePaths.Portal}`} className="text-decoration-none"> - <MenuItem className="py2">Portal DApp</MenuItem> + <MenuItem className="py2"> + {this.props.translate.get(Key.PortalDApp, Deco.CapWords)} + </MenuItem> </Link> )} <a className="text-decoration-none" target="_blank" href={`${WebsitePaths.Whitepaper}`}> - <MenuItem className="py2">Whitepaper</MenuItem> + <MenuItem className="py2">{this.props.translate.get(Key.Whitepaper, Deco.Cap)}</MenuItem> </a> <Link to={`${WebsitePaths.About}`} className="text-decoration-none"> - <MenuItem className="py2">About</MenuItem> + <MenuItem className="py2">{this.props.translate.get(Key.About, Deco.Cap)}</MenuItem> </Link> <a className="text-decoration-none" target="_blank" href={constants.URL_BLOG}> - <MenuItem className="py2">Blog</MenuItem> + <MenuItem className="py2">{this.props.translate.get(Key.Blog, Deco.Cap)}</MenuItem> </a> <Link to={`${WebsitePaths.FAQ}`} className="text-decoration-none"> <MenuItem className="py2" onTouchTap={this._onMenuButtonClick.bind(this)}> - FAQ + {this.props.translate.get(Key.Faq, Deco.Cap)} </MenuItem> </Link> </div> @@ -313,7 +335,7 @@ export class TopBar extends React.Component<TopBarProps, TopBarState> { <NestedSidebarMenu topLevelMenu={this.props.menuSubsectionsBySection} menuSubsectionsBySection={this.props.menuSubsectionsBySection} - title="Wiki" + title={this.props.translate.get(Key.Wiki, Deco.Cap)} shouldDisplaySectionHeaders={false} onMenuItemClick={this._onMenuButtonClick.bind(this)} /> @@ -328,7 +350,7 @@ export class TopBar extends React.Component<TopBarProps, TopBarState> { return ( <div className="lg-hide md-hide"> <div className="pl1 py1" style={{ backgroundColor: colors.lightGrey }}> - Portal DApp + {this.props.translate.get(Key.PortalDApp, Deco.CapWords)} </div> <PortalMenu menuItemStyle={{ color: 'black' }} onClick={this._onMenuButtonClick.bind(this)} /> </div> diff --git a/packages/website/ts/components/top_bar/top_bar_menu_item.tsx b/packages/website/ts/components/top_bar/top_bar_menu_item.tsx index 983050abc..e70381456 100644 --- a/packages/website/ts/components/top_bar/top_bar_menu_item.tsx +++ b/packages/website/ts/components/top_bar/top_bar_menu_item.tsx @@ -34,7 +34,7 @@ export class TopBarMenuItem extends React.Component<TopBarMenuItemProps, TopBarM marginTop: 15, paddingLeft: 9, paddingRight: 9, - width: 77, + minWidth: 77, } : {}; const menuItemColor = this.props.isNightVersion ? 'white' : this.props.style.color; diff --git a/packages/website/ts/containers/about.tsx b/packages/website/ts/containers/about.tsx new file mode 100644 index 000000000..ce8fd3afb --- /dev/null +++ b/packages/website/ts/containers/about.tsx @@ -0,0 +1,26 @@ +import * as _ from 'lodash'; +import * as React from 'react'; +import { connect } from 'react-redux'; +import { Dispatch } from 'redux'; +import { About as AboutComponent, AboutProps } from 'ts/pages/about/about'; +import { Dispatcher } from 'ts/redux/dispatcher'; +import { State } from 'ts/redux/reducer'; +import { Translate } from 'ts/utils/translate'; + +interface ConnectedState { + translate: Translate; +} + +interface ConnectedDispatch { + dispatcher: Dispatcher; +} + +const mapStateToProps = (state: State, ownProps: AboutProps): ConnectedState => ({ + translate: state.translate, +}); + +const mapDispatchToProps = (dispatch: Dispatch<State>): ConnectedDispatch => ({ + dispatcher: new Dispatcher(dispatch), +}); + +export const About: React.ComponentClass<AboutProps> = connect(mapStateToProps, mapDispatchToProps)(AboutComponent); diff --git a/packages/website/ts/containers/connect_documentation.tsx b/packages/website/ts/containers/connect_documentation.tsx index 79eafa431..5c5d26b44 100644 --- a/packages/website/ts/containers/connect_documentation.tsx +++ b/packages/website/ts/containers/connect_documentation.tsx @@ -9,6 +9,7 @@ import { State } from 'ts/redux/reducer'; import { DocsInfoConfig, Environments, WebsitePaths } from 'ts/types'; import { configs } from 'ts/utils/configs'; import { constants } from 'ts/utils/constants'; +import { Translate } from 'ts/utils/translate'; import { typeDocUtils } from 'ts/utils/typedoc_utils'; /* tslint:disable:no-var-requires */ @@ -84,6 +85,7 @@ interface ConnectedState { docsVersion: string; availableDocVersions: string[]; docsInfo: DocsInfo; + translate: Translate; } interface ConnectedDispatch { @@ -93,6 +95,7 @@ interface ConnectedDispatch { const mapStateToProps = (state: State, ownProps: DocumentationAllProps): ConnectedState => ({ docsVersion: state.docsVersion, availableDocVersions: state.availableDocVersions, + translate: state.translate, docsInfo, }); diff --git a/packages/website/ts/containers/faq.tsx b/packages/website/ts/containers/faq.tsx new file mode 100644 index 000000000..b539e33c9 --- /dev/null +++ b/packages/website/ts/containers/faq.tsx @@ -0,0 +1,26 @@ +import * as _ from 'lodash'; +import * as React from 'react'; +import { connect } from 'react-redux'; +import { Dispatch } from 'redux'; +import { FAQ as FAQComponent, FAQProps } from 'ts/pages/faq/faq'; +import { Dispatcher } from 'ts/redux/dispatcher'; +import { State } from 'ts/redux/reducer'; +import { Translate } from 'ts/utils/translate'; + +interface ConnectedState { + translate: Translate; +} + +interface ConnectedDispatch { + dispatcher: Dispatcher; +} + +const mapStateToProps = (state: State, ownProps: FAQProps): ConnectedState => ({ + translate: state.translate, +}); + +const mapDispatchToProps = (dispatch: Dispatch<State>): ConnectedDispatch => ({ + dispatcher: new Dispatcher(dispatch), +}); + +export const FAQ: React.ComponentClass<FAQProps> = connect(mapStateToProps, mapDispatchToProps)(FAQComponent); diff --git a/packages/website/ts/containers/landing.tsx b/packages/website/ts/containers/landing.tsx new file mode 100644 index 000000000..a620bb12e --- /dev/null +++ b/packages/website/ts/containers/landing.tsx @@ -0,0 +1,28 @@ +import * as _ from 'lodash'; +import * as React from 'react'; +import { connect } from 'react-redux'; +import { Dispatch } from 'redux'; +import { Landing as LandingComponent, LandingProps } from 'ts/pages/landing/landing'; +import { Dispatcher } from 'ts/redux/dispatcher'; +import { State } from 'ts/redux/reducer'; +import { Translate } from 'ts/utils/translate'; + +interface ConnectedState { + translate: Translate; +} + +interface ConnectedDispatch { + dispatcher: Dispatcher; +} + +const mapStateToProps = (state: State, ownProps: LandingProps): ConnectedState => ({ + translate: state.translate, +}); + +const mapDispatchToProps = (dispatch: Dispatch<State>): ConnectedDispatch => ({ + dispatcher: new Dispatcher(dispatch), +}); + +export const Landing: React.ComponentClass<LandingProps> = connect(mapStateToProps, mapDispatchToProps)( + LandingComponent, +); diff --git a/packages/website/ts/containers/not_found.tsx b/packages/website/ts/containers/not_found.tsx new file mode 100644 index 000000000..dd151e2c8 --- /dev/null +++ b/packages/website/ts/containers/not_found.tsx @@ -0,0 +1,28 @@ +import * as _ from 'lodash'; +import * as React from 'react'; +import { connect } from 'react-redux'; +import { Dispatch } from 'redux'; +import { NotFound as NotFoundComponent, NotFoundProps } from 'ts/pages/not_found'; +import { Dispatcher } from 'ts/redux/dispatcher'; +import { State } from 'ts/redux/reducer'; +import { Translate } from 'ts/utils/translate'; + +interface ConnectedState { + translate: Translate; +} + +interface ConnectedDispatch { + dispatcher: Dispatcher; +} + +const mapStateToProps = (state: State, ownProps: NotFoundProps): ConnectedState => ({ + translate: state.translate, +}); + +const mapDispatchToProps = (dispatch: Dispatch<State>): ConnectedDispatch => ({ + dispatcher: new Dispatcher(dispatch), +}); + +export const NotFound: React.ComponentClass<NotFoundProps> = connect(mapStateToProps, mapDispatchToProps)( + NotFoundComponent, +); diff --git a/packages/website/ts/containers/portal.tsx b/packages/website/ts/containers/portal.tsx index bcca0d70f..befa16bdb 100644 --- a/packages/website/ts/containers/portal.tsx +++ b/packages/website/ts/containers/portal.tsx @@ -8,6 +8,7 @@ import { Dispatcher } from 'ts/redux/dispatcher'; import { State } from 'ts/redux/reducer'; import { BlockchainErrs, HashData, Order, ProviderType, ScreenWidths, Side, TokenByAddress } from 'ts/types'; import { constants } from 'ts/utils/constants'; +import { Translate } from 'ts/utils/translate'; interface ConnectedState { blockchainErr: BlockchainErrs; @@ -26,6 +27,7 @@ interface ConnectedState { userAddress: string; userSuppliedOrderCache: Order; flashMessage?: string | React.ReactNode; + translate: Translate; } interface ConnectedDispatch { @@ -73,6 +75,7 @@ const mapStateToProps = (state: State, ownProps: PortalComponentAllProps): Conne userEtherBalance: state.userEtherBalance, userSuppliedOrderCache: state.userSuppliedOrderCache, flashMessage: state.flashMessage, + translate: state.translate, }; }; diff --git a/packages/website/ts/containers/smart_contracts_documentation.tsx b/packages/website/ts/containers/smart_contracts_documentation.tsx index 8be33b546..c4731f929 100644 --- a/packages/website/ts/containers/smart_contracts_documentation.tsx +++ b/packages/website/ts/containers/smart_contracts_documentation.tsx @@ -8,6 +8,7 @@ import { Dispatcher } from 'ts/redux/dispatcher'; import { State } from 'ts/redux/reducer'; import { DocsInfoConfig, SmartContractDocSections as Sections, WebsitePaths } from 'ts/types'; import { doxityUtils } from 'ts/utils/doxity_utils'; +import { Translate } from 'ts/utils/translate'; /* tslint:disable:no-var-requires */ const IntroMarkdown = require('md/docs/smart_contracts/introduction'); @@ -40,6 +41,7 @@ const docsInfo = new DocsInfo(docsInfoConfig); interface ConnectedState { docsVersion: string; availableDocVersions: string[]; + translate: Translate; } interface ConnectedDispatch { @@ -50,6 +52,7 @@ interface ConnectedDispatch { const mapStateToProps = (state: State, ownProps: DocumentationAllProps): ConnectedState => ({ docsVersion: state.docsVersion, availableDocVersions: state.availableDocVersions, + translate: state.translate, }); const mapDispatchToProps = (dispatch: Dispatch<State>): ConnectedDispatch => ({ diff --git a/packages/website/ts/containers/wiki.tsx b/packages/website/ts/containers/wiki.tsx new file mode 100644 index 000000000..2cb87d0a1 --- /dev/null +++ b/packages/website/ts/containers/wiki.tsx @@ -0,0 +1,26 @@ +import * as _ from 'lodash'; +import * as React from 'react'; +import { connect } from 'react-redux'; +import { Dispatch } from 'redux'; +import { Wiki as WikiComponent, WikiProps } from 'ts/pages/wiki/wiki'; +import { Dispatcher } from 'ts/redux/dispatcher'; +import { State } from 'ts/redux/reducer'; +import { Translate } from 'ts/utils/translate'; + +interface ConnectedState { + translate: Translate; +} + +interface ConnectedDispatch { + dispatcher: Dispatcher; +} + +const mapStateToProps = (state: State, ownProps: WikiProps): ConnectedState => ({ + translate: state.translate, +}); + +const mapDispatchToProps = (dispatch: Dispatch<State>): ConnectedDispatch => ({ + dispatcher: new Dispatcher(dispatch), +}); + +export const Wiki: React.ComponentClass<WikiProps> = connect(mapStateToProps, mapDispatchToProps)(WikiComponent); diff --git a/packages/website/ts/containers/zero_ex_js_documentation.tsx b/packages/website/ts/containers/zero_ex_js_documentation.tsx index eee2c7cc8..a32a87f7f 100644 --- a/packages/website/ts/containers/zero_ex_js_documentation.tsx +++ b/packages/website/ts/containers/zero_ex_js_documentation.tsx @@ -9,6 +9,7 @@ import { State } from 'ts/redux/reducer'; import { DocsInfoConfig, Environments, WebsitePaths } from 'ts/types'; import { configs } from 'ts/utils/configs'; import { constants } from 'ts/utils/constants'; +import { Translate } from 'ts/utils/translate'; import { typeDocUtils } from 'ts/utils/typedoc_utils'; /* tslint:disable:no-var-requires */ @@ -154,6 +155,7 @@ interface ConnectedState { docsVersion: string; availableDocVersions: string[]; docsInfo: DocsInfo; + translate: Translate; } interface ConnectedDispatch { @@ -164,6 +166,7 @@ const mapStateToProps = (state: State, ownProps: DocumentationAllProps): Connect docsVersion: state.docsVersion, availableDocVersions: state.availableDocVersions, docsInfo, + translate: state.translate, }); const mapDispatchToProps = (dispatch: Dispatch<State>): ConnectedDispatch => ({ diff --git a/packages/website/ts/index.tsx b/packages/website/ts/index.tsx index bc4e0b472..c0539c6d0 100644 --- a/packages/website/ts/index.tsx +++ b/packages/website/ts/index.tsx @@ -7,14 +7,14 @@ import { Provider } from 'react-redux'; import { BrowserRouter as Router, Redirect, Route, Switch } from 'react-router-dom'; import * as injectTapEventPlugin from 'react-tap-event-plugin'; import { createStore, Store as ReduxStore } from 'redux'; +import { About } from 'ts/containers/about'; +import { FAQ } from 'ts/containers/faq'; +import { Landing } from 'ts/containers/landing'; +import { NotFound } from 'ts/containers/not_found'; +import { Wiki } from 'ts/containers/wiki'; import { createLazyComponent } from 'ts/lazy_component'; import { trackedTokenStorage } from 'ts/local_storage/tracked_token_storage'; import { tradeHistoryStorage } from 'ts/local_storage/trade_history_storage'; -import { About } from 'ts/pages/about/about'; -import { FAQ } from 'ts/pages/faq/faq'; -import { Landing } from 'ts/pages/landing/landing'; -import { NotFound } from 'ts/pages/not_found'; -import { Wiki } from 'ts/pages/wiki/wiki'; import { reducer, State } from 'ts/redux/reducer'; import { WebsitePaths } from 'ts/types'; import { muiTheme } from 'ts/utils/mui_theme'; diff --git a/packages/website/ts/pages/about/about.tsx b/packages/website/ts/pages/about/about.tsx index 0889e79f3..b99dc34ab 100644 --- a/packages/website/ts/pages/about/about.tsx +++ b/packages/website/ts/pages/about/about.tsx @@ -4,9 +4,11 @@ import * as DocumentTitle from 'react-document-title'; import { Footer } from 'ts/components/footer'; import { TopBar } from 'ts/components/top_bar/top_bar'; import { Profile } from 'ts/pages/about/profile'; +import { Dispatcher } from 'ts/redux/dispatcher'; import { ProfileInfo, Styles } from 'ts/types'; import { colors } from 'ts/utils/colors'; import { constants } from 'ts/utils/constants'; +import { Translate } from 'ts/utils/translate'; import { utils } from 'ts/utils/utils'; const teamRow1: ProfileInfo[] = [ @@ -143,6 +145,8 @@ const advisors: ProfileInfo[] = [ export interface AboutProps { source: string; location: Location; + translate: Translate; + dispatcher: Dispatcher; } interface AboutState {} @@ -174,6 +178,7 @@ export class About extends React.Component<AboutProps, AboutState> { blockchainIsLoaded={false} location={this.props.location} style={{ backgroundColor: colors.lightestGrey }} + translate={this.props.translate} /> <div id="about" className="mx-auto max-width-4 py4" style={{ color: colors.grey800 }}> <div className="mx-auto pb4 sm-px3" style={{ maxWidth: 435 }}> @@ -230,7 +235,7 @@ export class About extends React.Component<AboutProps, AboutState> { </div> </div> </div> - <Footer /> + <Footer translate={this.props.translate} dispatcher={this.props.dispatcher} /> </div> ); } diff --git a/packages/website/ts/pages/documentation/documentation.tsx b/packages/website/ts/pages/documentation/documentation.tsx index da3728a60..285471166 100644 --- a/packages/website/ts/pages/documentation/documentation.tsx +++ b/packages/website/ts/pages/documentation/documentation.tsx @@ -35,6 +35,7 @@ import { colors } from 'ts/utils/colors'; import { configs } from 'ts/utils/configs'; import { constants } from 'ts/utils/constants'; import { docUtils } from 'ts/utils/doc_utils'; +import { Translate } from 'ts/utils/translate'; import { utils } from 'ts/utils/utils'; const TOP_BAR_HEIGHT = 60; @@ -54,6 +55,7 @@ export interface DocumentationAllProps { docsVersion: string; availableDocVersions: string[]; docsInfo: DocsInfo; + translate: Translate; } interface DocumentationState { @@ -114,6 +116,7 @@ export class Documentation extends React.Component<DocumentationAllProps, Docume menu={this.props.docsInfo.getMenu(this.props.docsVersion)} menuSubsectionsBySection={menuSubsectionsBySection} docsInfo={this.props.docsInfo} + translate={this.props.translate} /> {_.isUndefined(this.state.docAgnosticFormat) ? ( <div className="col col-12" style={styles.mainContainers}> diff --git a/packages/website/ts/pages/faq/faq.tsx b/packages/website/ts/pages/faq/faq.tsx index 0a7eecc2d..34175abdc 100644 --- a/packages/website/ts/pages/faq/faq.tsx +++ b/packages/website/ts/pages/faq/faq.tsx @@ -4,14 +4,18 @@ import * as DocumentTitle from 'react-document-title'; import { Footer } from 'ts/components/footer'; import { TopBar } from 'ts/components/top_bar/top_bar'; import { Question } from 'ts/pages/faq/question'; +import { Dispatcher } from 'ts/redux/dispatcher'; import { FAQQuestion, FAQSection, Styles, WebsitePaths } from 'ts/types'; import { colors } from 'ts/utils/colors'; import { configs } from 'ts/utils/configs'; import { constants } from 'ts/utils/constants'; +import { Translate } from 'ts/utils/translate'; export interface FAQProps { source: string; location: Location; + translate: Translate; + dispatcher: Dispatcher; } interface FAQState {} @@ -407,14 +411,14 @@ export class FAQ extends React.Component<FAQProps, FAQState> { return ( <div> <DocumentTitle title="0x FAQ" /> - <TopBar blockchainIsLoaded={false} location={this.props.location} /> + <TopBar blockchainIsLoaded={false} location={this.props.location} translate={this.props.translate} /> <div id="faq" className="mx-auto max-width-4 pt4" style={{ color: colors.grey800 }}> <h1 className="center" style={{ ...styles.thin }}> 0x FAQ </h1> <div className="sm-px2 md-px2 lg-px0 pb4">{this._renderSections()}</div> </div> - <Footer /> + <Footer translate={this.props.translate} dispatcher={this.props.dispatcher} /> </div> ); } diff --git a/packages/website/ts/pages/landing/landing.tsx b/packages/website/ts/pages/landing/landing.tsx index d4c934459..044f0b41f 100644 --- a/packages/website/ts/pages/landing/landing.tsx +++ b/packages/website/ts/pages/landing/landing.tsx @@ -5,9 +5,11 @@ import DocumentTitle = require('react-document-title'); import { Link } from 'react-router-dom'; import { Footer } from 'ts/components/footer'; import { TopBar } from 'ts/components/top_bar/top_bar'; -import { ScreenWidths, WebsitePaths } from 'ts/types'; +import { Dispatcher } from 'ts/redux/dispatcher'; +import { Deco, Key, Language, ScreenWidths, WebsitePaths } from 'ts/types'; import { colors } from 'ts/utils/colors'; import { constants } from 'ts/utils/constants'; +import { Translate } from 'ts/utils/translate'; import { utils } from 'ts/utils/utils'; interface BoxContent { @@ -36,35 +38,6 @@ interface Project { const THROTTLE_TIMEOUT = 100; -const boxContents: BoxContent[] = [ - { - title: 'Trustless exchange', - description: - "Built on Ethereum's distributed network with no centralized \ - point of failure and no down time, each trade is settled atomically \ - and without counterparty risk.", - imageUrl: '/images/landing/distributed_network.png', - classNames: '', - }, - { - title: 'Shared liquidity', - description: - 'By sharing a standard API, relayers can easily aggregate liquidity pools, \ - creating network effects around liquidity that compound as more relayers come online.', - imageUrl: '/images/landing/liquidity.png', - classNames: 'mx-auto', - }, - { - title: 'Open source', - description: - '0x is open source, permissionless and free to use. Trade directly with a known \ - counterparty for free or pay a relayer some ZRX tokens to access their liquidity \ - pool.', - imageUrl: '/images/landing/open_source.png', - classNames: 'right', - }, -]; - const relayersAndDappProjects: Project[] = [ { logoFileName: 'ethfinex.png', @@ -185,6 +158,8 @@ const relayerProjects: Project[] = [ export interface LandingProps { location: Location; + translate: Translate; + dispatcher: Dispatcher; } interface LandingState { @@ -216,17 +191,28 @@ export class Landing extends React.Component<LandingProps, LandingState> { location={this.props.location} isNightVersion={true} style={{ backgroundColor: colors.heroGrey, position: 'relative' }} + translate={this.props.translate} /> {this._renderHero()} - {this._renderProjects(relayersAndDappProjects, 'Projects building on 0x', colors.projectsGrey, false)} + {this._renderProjects( + relayersAndDappProjects, + this.props.translate.get(Key.ProjectsHeader, Deco.Upper), + colors.projectsGrey, + false, + )} {this._renderTokenizationSection()} {this._renderProtocolSection()} - {this._renderProjects(relayerProjects, 'Relayers building on 0x', colors.heroGrey, true)} + {this._renderProjects( + relayerProjects, + this.props.translate.get(Key.RelayersHeader, Deco.Upper), + colors.heroGrey, + true, + )} {this._renderInfoBoxes()} {this._renderBuildingBlocksSection()} {this._renderUseCases()} {this._renderCallToAction()} - <Footer /> + <Footer translate={this.props.translate} dispatcher={this.props.dispatcher} /> </div> ); } @@ -243,7 +229,7 @@ export class Landing extends React.Component<LandingProps, LandingState> { lineHeight: '33px', height: 38, }; - const left = 'col lg-col-7 md-col-7 col-12 lg-pt4 md-pt4 sm-pt0 mt1 lg-pl4 md-pl4 sm-pl0 sm-px3 sm-center'; + const left = 'col lg-col-7 md-col-7 col-12 lg-pl4 md-pl4 sm-pl0 sm-px3 sm-center'; return ( <div className="clearfix py4" style={{ backgroundColor: colors.heroGrey }}> <div className="mx-auto max-width-4 clearfix"> @@ -251,8 +237,14 @@ export class Landing extends React.Component<LandingProps, LandingState> { <div className="col lg-col-5 md-col-5 col-12 sm-center"> <img src="/images/landing/hero_chip_image.png" height={isSmallScreen ? 300 : 395} /> </div> - <div className={left} style={{ color: colors.white }}> - <div style={{ paddingLeft: isSmallScreen ? 0 : 12 }}> + <div className={left} style={{ color: colors.white, height: 390, lineHeight: '390px' }}> + <div + className="inline-block lg-align-middle md-align-middle sm-align-top" + style={{ + paddingLeft: isSmallScreen ? 0 : 12, + lineHeight: '36px', + }} + > <div className="sm-pb2" style={{ @@ -260,7 +252,7 @@ export class Landing extends React.Component<LandingProps, LandingState> { fontSize: isSmallScreen ? 26 : 34, }} > - Powering decentralized exchange + {this.props.translate.get(Key.TopHeader, Deco.Cap)} </div> <div className="pt2 h5 sm-mx-auto" @@ -271,17 +263,16 @@ export class Landing extends React.Component<LandingProps, LandingState> { fontWeight: 300, }} > - 0x is an open, permissionless protocol allowing for ERC20 tokens to be traded on the - Ethereum blockchain. + {this.props.translate.get(Key.TopTagline)} </div> - <div className="pt3 clearfix sm-mx-auto" style={{ maxWidth: 342 }}> + <div className="pt3 clearfix sm-mx-auto" style={{ maxWidth: 389 }}> <div className="lg-pr2 md-pr2 col col-6 sm-center"> <Link to={WebsitePaths.ZeroExJs} className="text-decoration-none"> <RaisedButton style={{ borderRadius: 6, minWidth: 157.36 }} buttonStyle={{ borderRadius: 6 }} labelStyle={buttonLabelStyle} - label="Build on 0x" + label={this.props.translate.get(Key.BuildCallToAction, Deco.Cap)} onClick={_.noop} /> </Link> @@ -298,7 +289,7 @@ export class Landing extends React.Component<LandingProps, LandingState> { labelColor="white" backgroundColor={colors.heroGrey} labelStyle={buttonLabelStyle} - label="Join the community" + label={this.props.translate.get(Key.CommunityCallToAction, Deco.Cap)} onClick={_.noop} /> </a> @@ -313,7 +304,6 @@ export class Landing extends React.Component<LandingProps, LandingState> { } private _renderProjects(projects: Project[], title: string, backgroundColor: string, isTitleCenter: boolean) { const isSmallScreen = this.state.screenWidth === ScreenWidths.Sm; - const isMediumScreen = this.state.screenWidth === ScreenWidths.Md; const projectList = _.map(projects, (project: Project, i: number) => { const isRelayersOnly = projects.length === 12; let colWidth: number; @@ -346,7 +336,6 @@ export class Landing extends React.Component<LandingProps, LandingState> { const titleStyle: React.CSSProperties = { fontFamily: 'Roboto Mono', color: colors.grey, - textTransform: 'uppercase', fontWeight: 300, letterSpacing: 3, }; @@ -366,13 +355,13 @@ export class Landing extends React.Component<LandingProps, LandingState> { fontSize: 14, }} > - view the{' '} + {this.props.translate.get(Key.FullListPrompt)}{' '} <Link to={`${WebsitePaths.Wiki}#List-of-Projects-Using-0x-Protocol`} className="text-decoration-none underline" style={{ color: colors.landingLinkGrey }} > - full list + {this.props.translate.get(Key.FullListLink)} </Link> </div> </div> @@ -385,33 +374,22 @@ export class Landing extends React.Component<LandingProps, LandingState> { <div className="clearfix lg-py4 md-py4 sm-pb4 sm-pt2" style={{ backgroundColor: colors.grey100 }}> <div className="mx-auto max-width-4 py4 clearfix"> {isSmallScreen && this._renderTokenCloud()} - <div className="col lg-col-6 md-col-6 col-12" style={{ color: colors.darkestGrey }}> - <div className="mx-auto" style={{ maxWidth: 385, paddingTop: 7 }}> + <div + className="col lg-col-6 md-col-6 col-12 center" + style={{ color: colors.darkestGrey, height: 364, lineHeight: '364px' }} + > + <div + className="mx-auto inline-block lg-align-middle md-align-middle sm-align-top" + style={{ maxWidth: 385, lineHeight: '44px', textAlign: 'left' }} + > <div className="lg-h1 md-h1 sm-h2 sm-center sm-pt3" style={{ fontFamily: 'Roboto Mono' }}> - The world's value is becoming tokenized + {this.props.translate.get(Key.TokenizedSectionHeader, Deco.Cap)} </div> <div className="pb2 lg-pt2 md-pt2 sm-pt3 sm-px3 h5 sm-center" - style={{ fontFamily: 'Roboto Mono', lineHeight: 1.7 }} + style={{ fontFamily: 'Roboto Mono', lineHeight: 1.7, maxWidth: 370 }} > - {isSmallScreen ? ( - <span> - The Ethereum blockchain is an open, borderless financial system that represents - a wide variety of assets as cryptographic tokens. In the future, most digital - assets and goods will be tokenized. - </span> - ) : ( - <div> - <div> - The Ethereum blockchain is an open, borderless financial system that - represents - </div> - <div> - a wide variety of assets as cryptographic tokens. In the future, most - digital assets and goods will be tokenized. - </div> - </div> - )} + {this.props.translate.get(Key.TokenizedSectionDescription, Deco.Cap)} </div> <div className="flex pt1 sm-px3">{this._renderAssetTypes()}</div> </div> @@ -430,28 +408,36 @@ export class Landing extends React.Component<LandingProps, LandingState> { <img src="/images/landing/relayer_diagram.png" height={isSmallScreen ? 326 : 426} /> </div> <div - className="col lg-col-6 md-col-6 col-12 lg-pr3 md-pr3 sm-mx-auto lg-pt4 md-pt4 lg-mt3 md-mt3" + className="col lg-col-6 md-col-6 col-12 lg-pr3 md-pr3 sm-mx-auto" style={{ color: colors.beigeWhite, maxWidth: isSmallScreen ? 'none' : 445, + height: 430, + lineHeight: '430px', }} > - <div className="lg-h1 md-h1 sm-h2 pb1 sm-pt3 sm-center" style={{ fontFamily: 'Roboto Mono' }}> - <div>Off-chain order relay</div> - <div>On-chain settlement</div> - </div> <div - className="pb2 pt2 h5 sm-center sm-px3 sm-mx-auto" - style={{ - fontFamily: 'Roboto Mono', - lineHeight: 1.7, - fontWeight: 300, - maxWidth: 445, - }} + className="inline-block lg-align-middle md-align-middle sm-align-top" + style={{ lineHeight: '43px' }} > - In 0x protocol, orders are transported off-chain, massively reducing gas costs and - eliminating blockchain bloat. Relayers help broadcast orders and collect a fee each time - they facilitate a trade. Anyone can build a relayer. + <div + className="lg-h1 md-h1 sm-h2 pb1 sm-pt3 sm-center" + style={{ fontFamily: 'Roboto Mono' }} + > + <div>{this.props.translate.get(Key.OffChainOrderRelay, Deco.Cap)}</div> + <div> {this.props.translate.get(Key.OonChainSettlement, Deco.Cap)}</div> + </div> + <div + className="pb2 pt2 h5 sm-center sm-px3 sm-mx-auto" + style={{ + fontFamily: 'Roboto Mono', + lineHeight: 1.7, + fontWeight: 300, + maxWidth: 445, + }} + > + {this.props.translate.get(Key.OffChainOnChainDescription, Deco.Cap)} + </div> </div> </div> </div> @@ -485,15 +471,13 @@ export class Landing extends React.Component<LandingProps, LandingState> { className="pb1 lg-pt4 md-pt4 sm-pt3 lg-h1 md-h1 sm-h2 sm-px3 sm-center" style={{ fontFamily: 'Roboto Mono' }} > - A building block for dApps + {this.props.translate.get(Key.BuildingBlockSectionHeader, Deco.Cap)} </div> <div className="pb3 pt2 sm-mx-auto sm-center" style={descriptionStyle}> - 0x protocol is a pluggable building block for dApps that require exchange functionality. - Join the many developers that are already using 0x in their web applications and smart - contracts. + {this.props.translate.get(Key.BuildingBlockSectionDescription, Deco.Cap)} </div> <div className="sm-mx-auto sm-center" style={callToActionStyle}> - Learn how in our{' '} + {this.props.translate.get(Key.DevToolsPrompt, Deco.Cap)}{' '} <Link to={WebsitePaths.ZeroExJs} className="text-decoration-none underline" @@ -501,15 +485,15 @@ export class Landing extends React.Component<LandingProps, LandingState> { > 0x.js </Link>{' '} - and{' '} + {this.props.translate.get(Key.And)}{' '} <Link to={WebsitePaths.SmartContracts} className="text-decoration-none underline" style={{ color: colors.beigeWhite, fontFamily: 'Roboto Mono' }} > - smart contract + {this.props.translate.get(Key.SmartContract)} </Link>{' '} - docs + {this.props.translate.get(Key.Docs)} </div> </div> {!isSmallScreen && this._renderBlockChipImage()} @@ -537,11 +521,11 @@ export class Landing extends React.Component<LandingProps, LandingState> { const isSmallScreen = this.state.screenWidth === ScreenWidths.Sm; const assetTypes: AssetType[] = [ { - title: 'Currency', + title: this.props.translate.get(Key.Currency, Deco.Cap), imageUrl: '/images/landing/currency.png', }, { - title: 'Traditional assets', + title: this.props.translate.get(Key.TraditionalAssets, Deco.Cap), imageUrl: '/images/landing/stocks.png', style: { paddingLeft: isSmallScreen ? 41 : 56, @@ -549,7 +533,7 @@ export class Landing extends React.Component<LandingProps, LandingState> { }, }, { - title: 'Digital goods', + title: this.props.translate.get(Key.DigitalGoods, Deco.Cap), imageUrl: '/images/landing/digital_goods.png', }, ]; @@ -566,6 +550,7 @@ export class Landing extends React.Component<LandingProps, LandingState> { fontSize: 13.5, fontWeight: 400, color: colors.darkestGrey, + lineHeight: 1.4, }} > {assetType.title} @@ -578,12 +563,32 @@ export class Landing extends React.Component<LandingProps, LandingState> { private _renderInfoBoxes() { const isSmallScreen = this.state.screenWidth === ScreenWidths.Sm; const boxStyle: React.CSSProperties = { - maxWidth: 252, - height: 386, + maxWidth: 253, + height: 402, backgroundColor: colors.grey50, borderRadius: 5, padding: '10px 24px 24px', }; + const boxContents: BoxContent[] = [ + { + title: this.props.translate.get(Key.BenefitOneTitle, Deco.Cap), + description: this.props.translate.get(Key.BenefitOneDescription, Deco.Cap), + imageUrl: '/images/landing/distributed_network.png', + classNames: '', + }, + { + title: this.props.translate.get(Key.BenefitTwoTitle, Deco.Cap), + description: this.props.translate.get(Key.BenefitTwoDescription, Deco.Cap), + imageUrl: '/images/landing/liquidity.png', + classNames: 'mx-auto', + }, + { + title: this.props.translate.get(Key.BenefitThreeTitle, Deco.Cap), + description: this.props.translate.get(Key.BenefitThreeDescription, Deco.Cap), + imageUrl: '/images/landing/open_source.png', + classNames: 'right', + }, + ]; const boxes = _.map(boxContents, (boxContent: BoxContent) => { return ( <div key={`box-${boxContent.title}`} className="col lg-col-4 md-col-4 col-12 sm-pb4"> @@ -604,14 +609,13 @@ export class Landing extends React.Component<LandingProps, LandingState> { const titleStyle: React.CSSProperties = { fontFamily: 'Roboto Mono', color: colors.grey, - textTransform: 'uppercase', fontWeight: 300, letterSpacing: 3, }; return ( <div className="clearfix" style={{ backgroundColor: colors.heroGrey }}> <div className="center pb3 pt4" style={titleStyle}> - Benefits of 0x + {this.props.translate.get(Key.BenefitsHeader, Deco.Upper)} </div> <div className="mx-auto pb4 sm-mt2 clearfix" style={{ maxWidth: '60em' }}> {boxes} @@ -625,41 +629,29 @@ export class Landing extends React.Component<LandingProps, LandingState> { const useCases: UseCase[] = [ { imageUrl: '/images/landing/governance_icon.png', - type: 'Decentralized governance', - description: - 'Decentralized organizations use tokens to represent ownership and \ - guide their governance logic. 0x allows decentralized organizations \ - to seamlessly and safely trade ownership for startup capital.', + type: this.props.translate.get(Key.DecentralizedGovernance, Deco.Upper), + description: this.props.translate.get(Key.DecentralizedGovernanceDescription, Deco.Cap), projectIconUrls: ['/images/landing/aragon.png'], classNames: 'lg-px2 md-px2', }, { imageUrl: '/images/landing/prediction_market_icon.png', - type: 'Prediction markets', - description: - 'Decentralized prediction market platforms generate sets of tokens that \ - represent a financial stake in the outcomes of real-world events. 0x allows \ - these tokens to be instantly tradable.', + type: this.props.translate.get(Key.PredictionMarkets, Deco.Upper), + description: this.props.translate.get(Key.PredictionMarketsDescription, Deco.Cap), projectIconUrls: ['/images/landing/augur.png'], classNames: 'lg-px2 md-px2', }, { imageUrl: '/images/landing/stable_tokens_icon.png', - type: 'Stable tokens', - description: - 'Novel economic constructs such as stable coins require efficient, liquid \ - markets to succeed. 0x will facilitate the underlying economic mechanisms \ - that allow these tokens to remain stable.', + type: this.props.translate.get(Key.StableTokens, Deco.Upper), + description: this.props.translate.get(Key.StableTokensDescription, Deco.Cap), projectIconUrls: ['/images/landing/maker.png'], classNames: 'lg-px2 md-px2', }, { imageUrl: '/images/landing/loans_icon.png', - type: 'Decentralized loans', - description: - 'Efficient lending requires liquid markets where investors can buy and re-sell loans. \ - 0x enables an ecosystem of lenders to self-organize and efficiently determine \ - market prices for all outstanding loans.', + type: this.props.translate.get(Key.DecentralizedLoans, Deco.Upper), + description: this.props.translate.get(Key.DecentralizedLoansDescription, Deco.Cap), projectIconUrls: ['/images/landing/dharma.png', '/images/landing/lendroid.png'], classNames: 'lg-pr2 md-pr2 lg-col-6 md-col-6', style: { @@ -670,11 +662,8 @@ export class Landing extends React.Component<LandingProps, LandingState> { }, { imageUrl: '/images/landing/fund_management_icon.png', - type: 'Fund management', - description: - 'Decentralized fund management limits fund managers to investing in pre-agreed \ - upon asset classes. Embedding 0x into fund management smart contracts enables \ - them to enforce these security constraints.', + type: this.props.translate.get(Key.FundManagement, Deco.Upper), + description: this.props.translate.get(Key.FundManagementDescription, Deco.Cap), projectIconUrls: ['/images/landing/melonport.png'], classNames: 'lg-pl2 md-pl2 lg-col-6 md-col-6', style: { width: 291, marginTop: !isSmallScreen ? 38 : 0 }, @@ -685,7 +674,7 @@ export class Landing extends React.Component<LandingProps, LandingState> { const style = _.isUndefined(useCase.style) || isSmallScreen ? {} : useCase.style; const useCaseBoxStyle = { color: colors.grey, - border: '1px solid #565656', + border: `1px solid ${colors.grey750}`, borderRadius: 4, maxWidth: isSmallScreen ? 375 : 'none', ...style, @@ -741,38 +730,39 @@ export class Landing extends React.Component<LandingProps, LandingState> { }; const lightButtonStyle: React.CSSProperties = { borderRadius: 6, - border: '1px solid #a0a0a0', + border: `1px solid ${colors.grey500}`, lineHeight: '33px', height: 49, }; const callToActionClassNames = - 'col lg-col-8 md-col-8 col-12 lg-pr3 md-pr3 \ - lg-right-align md-right-align sm-center sm-px3 h4'; + 'lg-pr3 md-pr3 lg-right-align md-right-align sm-center sm-px3 h4 lg-table-cell md-table-cell'; return ( <div className="clearfix pb4" style={{ backgroundColor: colors.heroGrey }}> - <div className="mx-auto max-width-4 pb4 mb3 clearfix"> - <div - className={callToActionClassNames} - style={{ - fontFamily: 'Roboto Mono', - color: colors.white, - lineHeight: isSmallScreen ? 1.7 : 3, - }} - > - Get started on building the decentralized future - </div> - <div className="col lg-col-4 md-col-4 col-12 sm-center sm-pt2"> - <Link to={WebsitePaths.ZeroExJs} className="text-decoration-none"> - <RaisedButton - style={{ borderRadius: 6, minWidth: 150 }} - buttonStyle={lightButtonStyle} - labelColor={colors.white} - backgroundColor={colors.heroGrey} - labelStyle={buttonLabelStyle} - label="Build on 0x" - onClick={_.noop} - /> - </Link> + <div className="mx-auto max-width-4 pb4 mb3 clearfix center"> + <div className="center inline-block" style={{ textAlign: 'left' }}> + <div + className={callToActionClassNames} + style={{ + fontFamily: 'Roboto Mono', + color: colors.white, + lineHeight: isSmallScreen ? 1.7 : 3, + }} + > + {this.props.translate.get(Key.FinalCallToAction, Deco.Cap)} + </div> + <div className="sm-center sm-pt2 lg-table-cell md-table-cell"> + <Link to={WebsitePaths.ZeroExJs} className="text-decoration-none"> + <RaisedButton + style={{ borderRadius: 6, minWidth: 150 }} + buttonStyle={lightButtonStyle} + labelColor={colors.white} + backgroundColor={colors.heroGrey} + labelStyle={buttonLabelStyle} + label={this.props.translate.get(Key.BuildCallToAction, Deco.Cap)} + onClick={_.noop} + /> + </Link> + </div> </div> </div> </div> @@ -786,4 +776,7 @@ export class Landing extends React.Component<LandingProps, LandingState> { }); } } + private _onLanguageSelected(language: Language) { + this.props.dispatcher.updateSelectedLanguage(language); + } } // tslint:disable:max-file-line-count diff --git a/packages/website/ts/pages/not_found.tsx b/packages/website/ts/pages/not_found.tsx index 0a6ec071c..ad37f6242 100644 --- a/packages/website/ts/pages/not_found.tsx +++ b/packages/website/ts/pages/not_found.tsx @@ -2,10 +2,14 @@ import * as _ from 'lodash'; import * as React from 'react'; import { Footer } from 'ts/components/footer'; import { TopBar } from 'ts/components/top_bar/top_bar'; +import { Dispatcher } from 'ts/redux/dispatcher'; import { Styles } from 'ts/types'; +import { Translate } from 'ts/utils/translate'; export interface NotFoundProps { location: Location; + translate: Translate; + dispatcher: Dispatcher; } interface NotFoundState {} @@ -20,7 +24,7 @@ export class NotFound extends React.Component<NotFoundProps, NotFoundState> { public render() { return ( <div> - <TopBar blockchainIsLoaded={false} location={this.props.location} /> + <TopBar blockchainIsLoaded={false} location={this.props.location} translate={this.props.translate} /> <div className="mx-auto max-width-4 py4"> <div className="center py4"> <div className="py4"> @@ -35,7 +39,7 @@ export class NotFound extends React.Component<NotFoundProps, NotFoundState> { </div> </div> </div> - <Footer /> + <Footer translate={this.props.translate} dispatcher={this.props.dispatcher} /> </div> ); } diff --git a/packages/website/ts/pages/wiki/wiki.tsx b/packages/website/ts/pages/wiki/wiki.tsx index bbbda6eee..56c3be0fe 100644 --- a/packages/website/ts/pages/wiki/wiki.tsx +++ b/packages/website/ts/pages/wiki/wiki.tsx @@ -8,10 +8,12 @@ import { TopBar } from 'ts/components/top_bar/top_bar'; import { MarkdownSection } from 'ts/pages/shared/markdown_section'; import { NestedSidebarMenu } from 'ts/pages/shared/nested_sidebar_menu'; import { SectionHeader } from 'ts/pages/shared/section_header'; +import { Dispatcher } from 'ts/redux/dispatcher'; import { Article, ArticlesBySection, HeaderSizes, Styles, WebsitePaths } from 'ts/types'; import { colors } from 'ts/utils/colors'; import { configs } from 'ts/utils/configs'; import { constants } from 'ts/utils/constants'; +import { Translate } from 'ts/utils/translate'; import { utils } from 'ts/utils/utils'; const TOP_BAR_HEIGHT = 60; @@ -20,6 +22,8 @@ const WIKI_NOT_READY_BACKOUT_TIMEOUT_MS = 5000; export interface WikiProps { source: string; location: Location; + dispatcher: Dispatcher; + translate: Translate; } interface WikiState { @@ -79,6 +83,7 @@ export class Wiki extends React.Component<WikiProps, WikiState> { blockchainIsLoaded={false} location={this.props.location} menuSubsectionsBySection={menuSubsectionsBySection} + translate={this.props.translate} /> {_.isUndefined(this.state.articlesBySection) ? ( <div className="col col-12" style={mainContainersStyle}> diff --git a/packages/website/ts/redux/dispatcher.ts b/packages/website/ts/redux/dispatcher.ts index 925f2aa29..5c40ded2c 100644 --- a/packages/website/ts/redux/dispatcher.ts +++ b/packages/website/ts/redux/dispatcher.ts @@ -6,6 +6,7 @@ import { ActionTypes, AssetToken, BlockchainErrs, + Language, Order, ProviderType, ScreenWidths, @@ -211,4 +212,10 @@ export class Dispatcher { data: injectedProviderName, }); } + public updateSelectedLanguage(language: Language) { + this._dispatch({ + type: ActionTypes.UpdateSelectedLanguage, + data: language, + }); + } } diff --git a/packages/website/ts/redux/reducer.ts b/packages/website/ts/redux/reducer.ts index c2a21dc07..1f489db85 100644 --- a/packages/website/ts/redux/reducer.ts +++ b/packages/website/ts/redux/reducer.ts @@ -13,6 +13,7 @@ import { SideToAssetToken, TokenByAddress, } from 'ts/types'; +import { Translate } from 'ts/utils/translate'; import { utils } from 'ts/utils/utils'; // Instead of defaulting the docs version to an empty string, we pre-populate it with @@ -49,6 +50,7 @@ export interface State { flashMessage: string | React.ReactNode; providerType: ProviderType; injectedProviderName: string; + translate: Translate; } const INITIAL_STATE: State = { @@ -86,13 +88,17 @@ const INITIAL_STATE: State = { flashMessage: undefined, providerType: ProviderType.Injected, injectedProviderName: '', + translate: new Translate(), }; export function reducer(state: State = INITIAL_STATE, action: Action) { switch (action.type) { // Portal case ActionTypes.ResetState: - return INITIAL_STATE; + return { + ...INITIAL_STATE, + translate: state.translate, + }; case ActionTypes.UpdateOrderSalt: { return { @@ -101,6 +107,13 @@ export function reducer(state: State = INITIAL_STATE, action: Action) { }; } + case ActionTypes.UpdateSelectedLanguage: { + return { + ...state, + translate: new Translate(action.data), + }; + } + case ActionTypes.UpdateNodeVersion: { return { ...state, diff --git a/packages/website/ts/types.ts b/packages/website/ts/types.ts index 645c9cc11..f6413eec5 100644 --- a/packages/website/ts/types.ts +++ b/packages/website/ts/types.ts @@ -140,6 +140,7 @@ export enum ActionTypes { HideFlashMessage = 'HIDE_FLASH_MESSAGE', UpdateProviderType = 'UPDATE_PROVIDER_TYPE', UpdateInjectedProviderName = 'UPDATE_INJECTED_PROVIDER_NAME', + UpdateSelectedLanguage = 'UPDATE_SELECTED_LANGUAGE', } export interface Action { @@ -667,4 +668,79 @@ export interface MaterialUIPosition { horizontal: 'left' | 'middle' | 'right'; } +export enum Language { + English = 'EN', + Spanish = 'ES', + Chinese = 'ZH', + Korean = 'KO', + Russian = 'RU', +} + +export enum Key { + TopHeader = 'TOP_HEADER', + TopTagline = 'TOP_TAGLINE', + BuildCallToAction = 'BUILD_CALL_TO_ACTION', + CommunityCallToAction = 'COMMUNITY_CALL_TO_ACTION', + ProjectsHeader = 'PROJECTS_HEADER', + FullListPrompt = 'FULL_LIST_PROMPT', + FullListLink = 'FULL_LIST_LINK', + TokenizedSectionHeader = 'TOKENIZED_SECTION_HEADER', + TokenizedSectionDescription = 'TOKENIZED_SECTION_DESCRIPTION', + Currency = 'CURRENCY', + TraditionalAssets = 'TRADITIONAL_ASSETS', + DigitalGoods = 'DIGITAL_GOODS', + OffChainOrderRelay = 'OFFCHAIN_ORDER_RELAY', + OonChainSettlement = 'OONCHAIN_SETTLEMENT', + OffChainOnChainDescription = 'OFFCHAIN_ONCHAIN_DESCRIPTION', + RelayersHeader = 'RELAYERS_HEADER', + BenefitsHeader = 'BENEFITS_HEADER', + BenefitOneTitle = 'BENEFIT_ONE_TITLE', + BenefitOneDescription = 'BENEFIT_ONE_DESCRIPTION', + BenefitTwoTitle = 'BENEFIT_TWO_TITLE', + BenefitTwoDescription = 'BENEFIT_TWO_DESCRIPTION', + BenefitThreeTitle = 'BENEFIT_THREE_TITLE', + BenefitThreeDescription = 'BENEFIT_THREE_DESCRIPTION', + BuildingBlockSectionHeader = 'BUILDING_BLOCK_SECTION_HEADER', + BuildingBlockSectionDescription = 'BUILDING_BLOCK_SECTION_DESCRIPTION', + DevToolsPrompt = 'DEV_TOOLS_PROMPT', + SmartContract = 'SMART_CONTRACT', + Docs = 'DOCS', + DecentralizedGovernance = 'DECENTRALIZED_GOVERNANCE', + DecentralizedGovernanceDescription = 'DECENTRALIZED_GOVERNANCE_DESCRIPTION', + PredictionMarkets = 'PREDICTION_MARKETS', + PredictionMarketsDescription = 'PREDICTION_MARKETS_DESCRIPTION', + StableTokens = 'STABLE_TOKENS', + StableTokensDescription = 'STABLE_TOKENS_DESCRIPTION', + DecentralizedLoans = 'DECENTRALIZED_LOANS', + DecentralizedLoansDescription = 'DECENTRALIZED_LOANS_DESCRIPTION', + FundManagement = 'FUND_MANAGEMENT', + FundManagementDescription = 'FUND_MANAGEMENT_DESCRIPTION', + FinalCallToAction = 'FINAL_CALL_TO_ACTION', + Documentation = 'DOCUMENTATION', + Community = 'COMMUNITY', + Organization = 'ORGANIZATION', + About = 'ABOUT', + Careers = 'CAREERS', + Contact = 'CONTACT', + Blog = 'BLOG', + Forum = 'FORUM', + Connect = 'CONNECT', + Whitepaper = 'WHITEPAPER', + Wiki = 'WIKI', + And = 'AND', + Faq = 'FAQ', + SmartContracts = 'SMART_CONTRACTS', + StandardRelayerApi = 'STANDARD_RELAYER_API', + PortalDApp = 'PORTAL_DAPP', + Website = 'WEBSITE', + Developers = 'DEVELOPERS', + Home = 'HOME', + RocketChat = 'ROCKETCHAT', +} + +export enum Deco { + Cap, + CapWords, + Upper, +} // tslint:disable:max-file-line-count diff --git a/packages/website/ts/utils/translate.ts b/packages/website/ts/utils/translate.ts new file mode 100644 index 000000000..5148e48ad --- /dev/null +++ b/packages/website/ts/utils/translate.ts @@ -0,0 +1,83 @@ +import * as _ from 'lodash'; +import { Deco, Key, Language } from 'ts/types'; + +import * as chinese from '../../translations/chinese.json'; +import * as english from '../../translations/english.json'; +import * as korean from '../../translations/korean.json'; +import * as russian from '../../translations/russian.json'; +import * as spanish from '../../translations/spanish.json'; + +const languageToTranslations = { + [Language.English]: english, + [Language.Spanish]: spanish, + [Language.Chinese]: chinese, + [Language.Korean]: korean, + [Language.Russian]: russian, +}; + +const languagesWithoutCaps = [Language.Chinese, Language.Korean]; + +interface Translation { + [key: string]: string; +} + +export class Translate { + private _selectedLanguage: Language; + private _translation: Translation; + constructor(desiredLanguage?: Language) { + if (!_.isUndefined(desiredLanguage)) { + this.setLanguage(desiredLanguage); + return; + } + const browserLanguage = (window.navigator as any).userLanguage || window.navigator.language || 'en-US'; + let language = Language.English; + if (_.includes(browserLanguage, 'es-')) { + language = Language.Spanish; + } else if (_.includes(browserLanguage, 'zh-')) { + language = Language.Chinese; + } else if (_.includes(browserLanguage, 'ko-')) { + language = Language.Korean; + } else if (_.includes(browserLanguage, 'ru-')) { + language = Language.Russian; + } + this.setLanguage(language); + } + public getLanguage() { + return this._selectedLanguage; + } + public setLanguage(language: Language) { + const isLanguageSupported = !_.isUndefined(languageToTranslations[language]); + if (!isLanguageSupported) { + throw new Error(`${language} not supported`); + } + this._selectedLanguage = language; + this._translation = languageToTranslations[language]; + } + public get(key: Key, decoration?: Deco) { + let text = this._translation[key]; + if (!_.isUndefined(decoration) && !_.includes(languagesWithoutCaps, this._selectedLanguage)) { + switch (decoration) { + case Deco.Cap: + text = this._capitalize(text); + break; + + case Deco.Upper: + text = text.toUpperCase(); + break; + + case Deco.CapWords: + const words = text.split(' '); + const capitalizedWords = _.map(words, w => this._capitalize(w)); + text = capitalizedWords.join(' '); + break; + + default: + throw new Error(`Unrecognized decoration: ${decoration}`); + } + } + return text; + } + private _capitalize(text: string) { + return `${text.charAt(0).toUpperCase()}${text.slice(1)}`; + } +} |