diff --git a/package-lock.json b/package-lock.json index 8ffbe1a3..b6bc47cd 100644 --- a/package-lock.json +++ b/package-lock.json @@ -14,6 +14,7 @@ "@dcl/schemas": "^11.9.0", "@dcl/single-sign-on-client": "^0.1.0", "@dcl/ui-env": "^1.5.0", + "@reduxjs/toolkit": "^2.2.5", "@transak/transak-sdk": "^1.0.31", "@types/flat": "0.0.28", "@types/segment-analytics": "^0.0.38", @@ -4042,6 +4043,34 @@ "integrity": "sha512-afmTuJrylUU/0OtqzaRkbyYFFNgCF73Bvel/sw90pvGrWIZ+vyoIJqA6eMSoA6+nb443kTmulmBtC9NerXboNg==", "dev": true }, + "node_modules/@reduxjs/toolkit": { + "version": "2.2.5", + "resolved": "https://registry.npmjs.org/@reduxjs/toolkit/-/toolkit-2.2.5.tgz", + "integrity": "sha512-aeFA/s5NCG7NoJe/MhmwREJxRkDs0ZaSqt0MxhWUrwCf1UQXpwR87RROJEql0uAkLI6U7snBOYOcKw83ew3FPg==", + "dependencies": { + "immer": "^10.0.3", + "redux": "^5.0.1", + "redux-thunk": "^3.1.0", + "reselect": "^5.1.0" + }, + "peerDependencies": { + "react": "^16.9.0 || ^17.0.0 || ^18", + "react-redux": "^7.2.1 || ^8.1.3 || ^9.0.0" + }, + "peerDependenciesMeta": { + "react": { + "optional": true + }, + "react-redux": { + "optional": true + } + } + }, + "node_modules/@reduxjs/toolkit/node_modules/redux": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/redux/-/redux-5.0.1.tgz", + "integrity": "sha512-M9/ELqF6fy8FwmkpnF0S3YKOqMyoWJ4+CS5Efg2ct3oY9daQvd/Pc71FpGZsVsbl3Cpb+IIcjBDUnnyBdQbq4w==" + }, "node_modules/@scure/base": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/@scure/base/-/base-1.0.0.tgz", @@ -10090,6 +10119,15 @@ "resolved": "https://registry.npmjs.org/immediate/-/immediate-3.0.6.tgz", "integrity": "sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ==" }, + "node_modules/immer": { + "version": "10.1.1", + "resolved": "https://registry.npmjs.org/immer/-/immer-10.1.1.tgz", + "integrity": "sha512-s2MPrmjovJcoMaHtx6K11Ra7oD05NT97w1IC5zpMkT6Atjr7H8LjaDd81iIxUYpMKSRRNMJE703M1Fhr/TctHw==", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/immer" + } + }, "node_modules/impetus": { "version": "0.8.8", "resolved": "https://registry.npmjs.org/impetus/-/impetus-0.8.8.tgz", @@ -17886,6 +17924,14 @@ "lodash.merge": "^4.3.1" } }, + "node_modules/redux-thunk": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/redux-thunk/-/redux-thunk-3.1.0.tgz", + "integrity": "sha512-NW2r5T6ksUKXCabzhL9z+h206HQw/NJkcLm1GPImRQ8IzfXwRGqjVhKJGauHirT0DAuyy6hjdnMZaRoAcy0Klw==", + "peerDependencies": { + "redux": "^5.0.0" + } + }, "node_modules/regenerator-runtime": { "version": "0.14.1", "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz", @@ -17999,6 +18045,11 @@ "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==", "dev": true }, + "node_modules/reselect": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/reselect/-/reselect-5.1.1.tgz", + "integrity": "sha512-K/BG6eIky/SBpzfHZv/dd+9JBFiS4SWV7FIujVyJRux6e45+73RaUHXLmIR1f7WOMaQ0U1km6qwklRQxpJJY0w==" + }, "node_modules/resolve": { "version": "1.20.0", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.20.0.tgz", diff --git a/package.json b/package.json index 326f573f..c1c09d9a 100644 --- a/package.json +++ b/package.json @@ -13,6 +13,7 @@ "@dcl/schemas": "^11.9.0", "@dcl/single-sign-on-client": "^0.1.0", "@dcl/ui-env": "^1.5.0", + "@reduxjs/toolkit": "^2.2.5", "@transak/transak-sdk": "^1.0.31", "@types/flat": "0.0.28", "@types/segment-analytics": "^0.0.38", diff --git a/src/modules/index.ts b/src/modules/index.ts index e6f45bee..f35e9c9a 100644 --- a/src/modules/index.ts +++ b/src/modules/index.ts @@ -9,6 +9,7 @@ import * as profile from './profile' import * as toast from './toast' import * as transaction from './transaction' import * as translation from './translation' +import * as transactionV2 from './translation-v2' import * as wallet from './wallet' export { @@ -23,5 +24,6 @@ export { toast, transaction, translation, + transactionV2, wallet } diff --git a/src/modules/translation-v2/defaults/en.json b/src/modules/translation-v2/defaults/en.json new file mode 100644 index 00000000..ad1c70c8 --- /dev/null +++ b/src/modules/translation-v2/defaults/en.json @@ -0,0 +1,364 @@ +{ + "@dapps": { + "button": { + "network_not_supported": "You need to be connected to {expectedChainName} to perform this action" + }, + "footer": { + "dropdown": { + "en": "English", + "es": "Spanish", + "fr": "French", + "ja": "Japanese", + "ko": "Korean", + "zh": "Chinese" + }, + "links": { + "content": "Content Policy", + "ethics": "Code of Ethics", + "home": "Home", + "privacy": "Privacy Policy", + "terms": "Terms of Use", + "feature": "Feature Request" + } + }, + "navbar": { + "account": { + "connecting": "Connecting...", + "signIn": "Sign In" + }, + "menu": { + "avatars": "Avatars", + "agora": "Agora", + "blog": "Blog", + "docs": { + "main": "Docs", + "players": "Players", + "creators": "Content Creators", + "contributors": "Contributors", + "studios": "Studios" + }, + "marketplace": { + "main": "Marketplace", + "overview": "Overview", + "collectibles": "Collectibles", + "land": "LAND", + "names": "NAMEs", + "myAssets": "My Assets" + }, + "builder": { + "main": "Builder", + "overview": "Overview", + "collections": "Collections", + "scenes": "Scenes", + "land": "Land", + "names": "Names", + "worlds": "Worlds" + }, + "events": "Events", + "dao": { + "main": "DAO", + "overview": "Overview", + "governance": "Governance", + "transparency": "Transparency", + "grants": "Grants" + }, + "places": { + "main": "Places", + "overview": "Overview", + "places": "Genesis City", + "worlds": "Worlds", + "faq": "FAQ" + } + }, + "wrong_network": { + "header": "Wrong Network", + "message": "You need to be connected to {expectedChainName} to use this app, but you are currently connected to {currentChainName}.", + "message_unknown_network": "You need to be connected to {expectedChainName} to use this app, please switch your network to continue.", + "switch_button": "Switch to {chainName}", + "sign_out": "Sign Out" + } + }, + "sign_in": { + "connect": "Connect", + "connected": "Connected", + "connecting": "Connecting...", + "error": "Could not connect to wallet.", + "get_started": "Get Started", + "options": { + "connected": "You're already connected!", + "desktop": "You can use the {metamask_link} extension or your email account", + "mobile": "You can use mobile browsers such as {coinbase_link} or {imtoken_link}.", + "samsung": "You can use {samsung_link}." + } + }, + "login": { + "modal": { + "title": "Sign In", + "subtitle": "Choose how you want to connect to Ethereum.", + "error": "Could not connect to wallet.", + "supported_wallets": "Trezor and smart contract wallets like Dapper, Argent or Gnosis safe, do not work with Polygon. Read more about the Trezor support status {trezor_link}", + "trezor_link": "here" + }, + "option": { + "browser_extension": "Using a browser extension", + "email": "Using your email", + "mobile": "Using a mobile wallet", + "mobile_and_browser": "Using your mobile or browser extension", + "metamask_mobile": "Using the MetaMask app" + } + }, + "buyManaWithFiat": { + "modal": { + "title": "Buy MANA", + "subtitle": "Select what MANA you want to buy:", + "error": "Could not buy MANA." + }, + "feedback_modal": { + "pending": { + "title": "Buy {network} MANA", + "status_title": "The transaction is processing", + "description": "Wait a few minutes while the transaction is being processed", + "go_to_text": "Go to {gateway} tab" + }, + "success": { + "title": "{network} MANA purchase completed!", + "description": "The {network} MANA has been added to your account. If you still don't see it in your balance, refresh this page.", + "cta": "Done", + "view_transaction": "View Transaction in Exporer" + }, + "failure": { + "title": "Buy {network} MANA", + "description": "You can try again with {gateway} or select other provider", + "status_title": "The transaction failed", + "cta": "Try again", + "secondary_cta": "Select other provider" + } + }, + "network": { + "ethereum": { + "cta": "Ethereum MANA", + "ctaSubtitle": "Use it to buy LAND, names and specific wearables in Ethereum.", + "title": "Buy Ethereum MANA", + "error": "Could not buy Ethereum MANA", + "moonPay": { + "title": "Buy Ethereum MANA with MoonPay", + "subtitle": "You can buy with debit and credit cards, Apple Pay, Google Pay, or via bank transfer.", + "continueButtonText": "Continue with MoonPay", + "learnMoreText": "Learn More about MoonPay" + }, + "transak": { + "title": "Buy Ethereum MANA with Transak", + "subtitle": "You can buy with debit and credit cards, Apple Pay, Google Pay, or via bank transfer.", + "continueButtonText": "Continue with Transak", + "learnMoreText": "Learn More about Transak" + } + }, + "matic": { + "cta": "Polygon MANA", + "ctaSubtitle": "Use it to buy most wearables and emotes in Polygon.", + "title": "Buy Polygon MANA", + "error": "Could not buy Polygon MANA", + "moonPay": { + "title": "Buy Polygon MANA with MoonPay", + "subtitle": "You can buy with debit and credit cards, Apple Pay, Google Pay, or via bank transfer.", + "continueButtonText": "Continue with MoonPay", + "learnMoreText": "Learn More about MoonPay" + }, + "transak": { + "title": "Buy Polygon MANA with Transak", + "subtitle": "You can buy with debit and credit cards, Apple Pay, Google Pay, or via bank transfer.", + "continueButtonText": "Continue with Transak", + "learnMoreText": "Learn More about Transak" + } + } + } + }, + "user_menu": { + "guest": "Unnamed", + "my_lists": "My Lists", + "my_assets": "My Assets", + "account": "Account Settings", + "activity": "Activity", + "profile": "Profile", + "view_profile": "View Profile", + "sign_in": "Sign In", + "sign_out": "Sign out", + "marketplace_authorizations": "Marketplace Authorizations", + "jump_in": "Jump In" + }, + "toasts": { + "meta_transactions": { + "contract_account_error": { + "title": "Wallet not supported", + "body": "Smart contract wallets are not supported for meta-transactions. You can switch your network to Polygon and send a regular transaction." + }, + "invalid_address_error": { + "title": "Invalid address", + "body": "The contract address is not available for meta-transactions. You can switch your network to Polygon and send a regular transaction." + }, + "sale_price_too_low_error": { + "title": "Price too low", + "body": "The price is too low for this meta-transaction. You can switch your network to Polygon and send a regular transaction." + }, + "unknown_error": { + "title": "Something went wrong", + "body": "There was an unexpected error sending the meta-transaction. You can switch your network to Polygon and try sending a regular transaction." + }, + "high_congestion_error": { + "title": "High congestion", + "body": "Polygon Network gas prices are too high! Please wait and try again later, or switch your Network to Polygon and pay for the gas fee with MATIC." + } + }, + "switch_network_error": { + "title": "Network switch error", + "body": "There was an error switching to {network}." + }, + "switch_network": "Switch to {network}", + "learn_more": "Learn more" + }, + "network_alert": { + "title": "Your wallet is connected to Polygon", + "content": "Use this network to cover the gas of a transaction (like when buying items below 1 MANA). Switch back when you finish. Learn more", + "action": "Switch to Ethereum Mainnet" + }, + "authorization_modal": { + "close": "Close", + "waiting_wallet": "Confirm the transaction on your wallet", + "waiting_confirmation": "Processing authorization", + "done": "Done", + "title": "Complete your {action}", + "spending_cap_error": "Remember to set a cap equal to the item price {price} MANA or higher.", + "revoke_cap_error": "Remember to set a spending cap of 0 MANA in order to revoke your previous one.", + "generic_error": "Something went wrong", + "insufficient_amount_error": { + "message": "Your spending cap is not enough to cover the purchase amount of {price} MANA. To proceed, please adjust your spending cap equal or higher. Revoke the current spending cap and retry with an appropriate limit.", + "action": "Revoke" + }, + "authorize_mana": { + "title": "First, authorize the contract to operate MANA on your behalf in Decentraland. ", + "description": "Keep in mind that some wallets require setting a custom MANA spending limit. Enter the item price {price} MANA or a higher amount you're comfortable with for spending now or later. You can change the limit at any time.", + "action": "Authorize", + "message": "Remember to set a cap equal to the item price {price} MANA or higher." + }, + "authorize_nft": { + "title": "First, authorize the contract to operate your NFTs on your behalf in Decentraland", + "action": "Authorize" + }, + "confirm_transaction": { + "title": "Confirm transaction to {action} the item", + "action": "Confirm transaction" + }, + "revoke_cap": { + "title": "Revoke your current spending cap", + "description": "Your current spending cap is lower than {price} MANA. You'll have to revoke your current spending cap before making a new one.", + "action": "Authorize" + }, + "set_cap": { + "title": "Set a new spending cap", + "description": "Enter the item price {price} MANA or a higher amount you're comfortable with for spending now or later. You can change the limit at any time.", + "action": "Authorize" + }, + "action": "action", + "title_action": "action" + }, + "asset_card": { + "listings": "Listings", + "listing": "Listing", + "available_for_mint": "Buy directly from creator", + "available_listings_in_range": "Available listings in this range", + "cheapest_listing": "Cheapest Listing", + "not_for_sale": "Not for sale", + "owners": "Owners", + "owner": "Owner", + "cheapest_option": "Cheapest Option", + "cheapest_option_range": "Cheapest Option within range", + "most_expensive": "Most Expensive", + "most_expensive_range": "Most Expensive within range", + "also_minting": "Buy directly from the creator" + }, + "smart_wearables_filter": { + "title": "Smart", + "selected": "Only Smart" + }, + "rarities_filter": { + "title": "Rarity", + "tooltip": "The Rarity determines the total number of NFTs that can be minted", + "count_rarities": "{count} {count, plural, one {rarity} other {rarities}}", + "all_rarities": "All rarities" + }, + "rarities": { + "unique": "Unique", + "mythic": "Mythic", + "exotic": "Exotic", + "legendary": "Legendary", + "epic": "Epic", + "rare": "Rare", + "uncommon": "Uncommon", + "common": "Common" + }, + "rarities_description": { + "unique": "Grail-like: One-of-a-kind", + "mythic": "For the lucky few: max 10", + "exotic": "Limited supply: max 50", + "legendary": "Limited supply: max 100", + "epic": "Max supply: 1000", + "rare": "Max supply: 5000", + "uncommon": "Max supply: 10,000", + "common": "Max supply: 100,000" + }, + "asset_status_filter": { + "title": "Status", + "on_sale": "On Sale", + "on_sale_tooltip": "Includes items available for minting and/or with available listings.", + "only_minting": "Only Available For Minting", + "only_minting_tooltip": "Only includes items that are available for minting (buying directly from the creators).", + "only_listing": "Only Listings", + "only_listing_tooltip": "Only includes items that are being resold.", + "not_for_sale": "Not For Sale", + "not_for_sale_tooltip": "Includes all items that are not available for minting (buying directly from the creators) or have open listings." + }, + "back_to_top_button": { + "title": "Back to top" + }, + "nft_card": { + "category": { + "body_shape": "Body Shape", + "earring": "Earring", + "eyebrows": "Eyebrows", + "eyes": "Eyes", + "eyewear": "Eyewear", + "facial_hair": "Facial Hair", + "feet": "Feet", + "head": "Head", + "hair": "Hair", + "hat": "Hat", + "helmet": "Helmet", + "lower_body": "Lower Body", + "mask": "Mask", + "mouth": "Mouth", + "tiara": "Tiara", + "top_head": "Top Head", + "upper_body": "Upper Body", + "skin": "Skin", + "hands_wear": "Handwear" + }, + "with_sound": "With Sound", + "smart": "Smart", + "body_shape": { + "male": "Male", + "female": "Female", + "unisex": "Unisex" + }, + "play_mode": { + "simple": "Play once", + "loop": "Play loop" + } + }, + "chain_selector": { + "title": "Select a network", + "connected": "Connected", + "confirm_in_wallet": "Confirm in wallet", + "switching": "Switching..." + } + } +} diff --git a/src/modules/translation-v2/defaults/es.json b/src/modules/translation-v2/defaults/es.json new file mode 100644 index 00000000..2157e97c --- /dev/null +++ b/src/modules/translation-v2/defaults/es.json @@ -0,0 +1,363 @@ +{ + "@dapps": { + "button": { + "network_not_supported": "Debes conectarte a {expectedChainName} para realizar esta acción" + }, + "footer": { + "dropdown": { + "en": "Inglés", + "es": "Español", + "fr": "Francés", + "ja": "Japonés", + "ko": "Coreano", + "zh": "Chino" + }, + "links": { + "content": "Política de contenido", + "ethics": "Código de Ética", + "home": "Inicio", + "privacy": "Política de privacidad", + "terms": "Términos de Uso", + "feature": "Solicitud de funcionalidad" + } + }, + "navbar": { + "account": { + "connecting": "Conectando...", + "signIn": "Conectar" + }, + "menu": { + "avatars": "Avatars", + "agora": "Agora", + "blog": "Blog", + "docs": { + "main": "Docs", + "players": "Players", + "creators": "Content Creators", + "contributors": "Contributors", + "studios": "Studios" + }, + "marketplace": { + "main": "Marketplace", + "overview": "Overview", + "collectibles": "Collectibles", + "land": "LAND", + "names": "NAMEs", + "myAssets": "My Assets" + }, + "builder": { + "main": "Builder", + "overview": "Overview", + "collections": "Collections", + "scenes": "Scenes", + "land": "Land", + "names": "Names", + "worlds": "Worlds" + }, + "events": "Events", + "dao": { + "main": "DAO", + "overview": "Overview", + "governance": "Governance", + "transparency": "Transparency", + "grants": "Grants" + }, + "places": { + "main": "Places", + "overview": "Overview", + "places": "Genesis City", + "worlds": "Worlds", + "faq": "FAQ" + } + }, + "wrong_network": { + "header": "Red incorrecta", + "message": "Necesita conectarse a la Red {expectedChainName} para usar esta app, pero actualmente esta conectado a la Red {currentChainName}.", + "message_unknown_network": "Debes estar conectado a {expectedChainName} para usar esta aplicación, cambia tu red para continuar.", + "switch_button": "Cambiar a {chainName}", + "sign_out": "Desconectar" + } + }, + "sign_in": { + "connect": "Conectar", + "connected": "Conectado", + "connecting": "Conectando...", + "error": "No se pudo conectar a la billetera.", + "get_started": "Comenzar", + "options": { + "connected": "Conectado correctamente!", + "desktop": "Puedes usar la extensión {metamask_link} o tu cuenta de mail.", + "mobile": "Puedes utilizar navegadores móviles como {coinbase_link} o {imtoken_link}.", + "samsung": "Puedes utilizar {samsung_link}." + } + }, + "login": { + "modal": { + "title": "Conectar", + "subtitle": "Elige como quieres conectarte.", + "error": "No se pudo conectar a la billetera.", + "supported_wallets": "Los Trezor y billeteras basadas en smart contracts (como Dapper o Argent) no pueden interactuar con Polygon. Lea más sobre el soporte de Trezor {trezor_link}", + "trezor_link": "aquí" + }, + "option": { + "browser_extension": "Usando una extensión de navegador", + "email": "Usando tu cuenta de email", + "mobile": "Usando un navegador móvil", + "mobile_and_browser": "Usando tu móvil o extensión de navegador", + "metamask_mobile": "Usando la aplicación de MetaMask" + } + }, + "buyManaWithFiat": { + "modal": { + "title": "Comprar MANA", + "subtitle": "Selecciona que MANA quieres comprar:", + "error": "No se pudo comprar MANA." + }, + "feedback_modal": { + "pending": { + "title": "Compre {network} MANA", + "status_title": "La transacción está siendo procesada", + "description": "Espere unos minutos mientras la transacción está siendo procesada", + "go_to_text": "Ir a {gateway}" + }, + "success": { + "title": "¡La compra de {network} MANA ha sido completada!", + "description": "El {network} MANA comprado ha sido agregado a su cuenta. Si todavía no lo ve reflejado en su balande, recargue la página.", + "cta": "Listo", + "view_transaction": "Ver la transacción en el explorador" + }, + "failure": { + "title": "Compre {network} MANA", + "description": "Puede intentarlo de nuevo en {gateway} o seleccionar otro proveedor", + "status_title": "La transacción falló", + "cta": "Inténtelo de nuevo", + "secondary_cta": "Seleccione otro proveedor" + } + }, + "network": { + "ethereum": { + "cta": "Ethereum MANA", + "ctaSubtitle": "Úselo para comprar terrenos, nombres y wearables específicos en Ethereum.", + "title": "Compre Ethereum MANA", + "error": "No se pudo realizar la compre de Ethereum MANA", + "moonPay": { + "title": "Compre Ethereum MANA con MoonPay", + "subtitle": "Puedes comprar con tarjetas de débito y crédito, Apple Pay, Google Pay o mediante transferencia bancaria.", + "continueButtonText": "Continuar con MoonPay", + "learnMoreText": "Más información sobre MoonPay" + }, + "transak": { + "title": "Compre Ethereum MANA con Transak", + "subtitle": "Puedes comprar con tarjetas de débito y crédito, Apple Pay, Google Pay o mediante transferencia bancaria.", + "continueButtonText": "Continuar con Transak", + "learnMoreText": "Más información sobre Transak" + } + }, + "matic": { + "cta": "Maná polígono", + "ctaSubtitle": "Úselo para comprar la mayoría de los dispositivos portátiles y emotes en Polygon.", + "title": "Compra Polygon MANA", + "error": "No se pudo realizar la compra de Polygon MANA", + "moonPay": { + "title": "Compra Polygon MANA con MoonPay", + "subtitle": "Puedes comprar con tarjetas de débito y crédito, Apple Pay, Google Pay o mediante transferencia bancaria.", + "continueButtonText": "Continuar con MoonPay", + "learnMoreText": "Más información sobre MoonPay" + }, + "transak": { + "title": "Compra Polygon MANA con Transak", + "subtitle": "Puedes comprar con tarjetas de débito y crédito, Apple Pay, Google Pay o mediante transferencia bancaria.", + "continueButtonText": "Continuar con Transak", + "learnMoreText": "Más información sobre Transak" + } + } + } + }, + "user_menu": { + "guest": "Sin nombre", + "my_lists": "Mis listas", + "my_assets": "Mis activos", + "account": "Configuración de la cuenta", + "activity": "Actividad", + "profile": "Perfil", + "view_profile": "Ver perfil", + "sign_in": "Iniciar sesión", + "sign_out": "Cerrar sesión", + "marketplace_authorizations": "Autorizaciones de Marketplace", + "jump_in": "Entrar" + }, + "toasts": { + "meta_transactions": { + "contract_account_error": { + "title": "Billetera no soportada", + "body": "Las billeteras basadas en smart contracts no están soportadas para hacer meta-transacciones. Puedes cambiar la red a Polygon y enviar una transacción común." + }, + "invalid_address_error": { + "title": "Dirección inválida", + "body": "La dirección del contrato no está soportada para hacer meta-transacciones. Puedes cambiar la red a Polygon y enviar una transacción común." + }, + "sale_price_too_low_error": { + "title": "Precio muy bajo", + "body": "El precio es demasiado bajo para esta meta-transacción. Puedes cambiar la red a Polygon y enviar una transacción común." + }, + "unknown_error": { + "title": "Ha ocurrido un error", + "body": "Algo salio mal enviando la meta-transacción. Puedes cambiar la red a Polygon e intentar mandar una transacción común." + }, + "high_congestion_error": { + "title": "Alta demanda", + "body": "Los precios de las tarifas de transacción en la red de Polygon estan muy altos! Por favor espere un momento e intentelo nuevamente, o puede cambiar la red a Polygon y pagar la tarifa de la transacción con MATIC." + } + }, + "switch_network_error": { + "title": "Cambio de red fallido", + "body": "No se pudo cambiar a la red {network}." + }, + "switch_network": "Cambiar a {network}", + "learn_more": "Mas información" + }, + "network_alert": { + "title": "Su billetera está conectada a Polygon", + "content": "Use esta red para cubrir el gas de una transacción (como cuando compra artículos por debajo de 1 MANA). Vuelva a cambiar cuando termine. Ver más", + "action": "Cambiar a Ethereum Mainnet" + }, + "authorization_modal": { + "close": "Cerrar", + "waiting_wallet": "Confirme la transacción en su billetera", + "waiting_confirmation": "Autorización de procesamiento", + "done": "Hecho", + "title": "Completa tu {action}", + "spending_cap_error": "Recuerde establecer un límite igual al precio del artículo {price} MANA o superior.", + "revoke_cap_error": "Recuerde establecer un límite de gasto de 0 MANA para revocar su anterior.", + "generic_error": "Algo salió mal", + "insufficient_amount_error": { + "message": "Su límite de gasto actual no es suficiente para cubrir la cantidad de compra de {price} MANA. Para continuar, ajuste su limite a un valor igual o superior. Para continuar tendrá que revocar el límite de gasto actual y volver a intentarlo con un límite apropiado.", + "action": "Revocar" + }, + "authorize_mana": { + "title": "Primero, autorice el contrato para operar MANA en su nombre en Decentraland. ", + "description": "Tenga en cuenta que algunas billeteras requieren establecer un límite de gasto de MANA personalizado. Ingrese el precio del artículo {price} MANA o una cantidad más alta con la que se sienta cómodo para gastar ahora o más tarde. Puede cambiar el límite en cualquier momento.", + "action": "Autorizar", + "message": "Recuerde establecer un límite igual al precio del artículo {price} MANA o superior." + }, + "authorize_nft": { + "title": "Primero, autorice el contrato para operar NFT en su nombre en Decentraland", + "action": "Autorizar" + }, + "confirm_transaction": { + "title": "Confirmar la transacción a {action} el elemento", + "action": "Confirmar transacción" + }, + "revoke_cap": { + "title": "Revocar su límite de gasto actual", + "description": "Su límite de gasto actual es más bajo que {price} maná.Tendrá que revocar su límite de gasto actual antes de hacer uno nuevo.", + "action": "Autorizar" + }, + "set_cap": { + "title": "Establecer una nueva tapa de gasto", + "description": "Ingrese el precio del artículo {price} MANA o una cantidad más alta con la que se sienta cómodo para gastar ahora o más tarde. Puede cambiar el límite en cualquier momento.", + "action": "Autorizar" + }, + "action": "acción", + "title_action": "acción" + }, + "asset_card": { + "listings": "Collecionables", + "listing": "Collecionable", + "available_for_mint": "Compra directo al creador", + "cheapest_listing": "Coleccionable más barato", + "not_for_sale": "No disponible para la venta", + "owners": "Dueños", + "owner": "Dueño", + "cheapest_option": "Más barato", + "cheapest_option_range": "Más barato en el rango", + "most_expensive": "Más Caro", + "most_expensive_range": "Más Caro en el rango", + "also_minting": "Compra directo al creador" + }, + "smart_wearables_filter": { + "title": "Interactivas", + "selected": "Solo Interactivas" + }, + "rarities_filter": { + "title": "Rareza", + "tooltip": "La rareza determina la cantidad de NFTs que pueden ser minteados", + "all_rarities": "Todas las rarezas", + "count_rarities": "{count} {count, plural, one {rareza} other {rarezas}}" + }, + "rarities": { + "unique": "Único", + "mythic": "Mítico", + "exotic": "Exótico", + "legendary": "Legendario", + "epic": "Épico", + "rare": "Raro", + "uncommon": "Poco común", + "common": "Común" + }, + "rarity_description": { + "unique": "Único en su tipo: uno solo en existencia", + "mythic": "Para algunos pocos: máximo 10", + "exotic": "Edición limitada: máximo 50", + "legendary": "Edición limitada: máximo 100", + "epic": "Suministro máximo: 1000", + "rare": "Suministro máximo: 5000", + "uncommon": "Suministro máximo: 10.000", + "common": "Suministro máximo: 100.000" + }, + "asset_status_filter": { + "title": "Estado", + "on_sale": "En venta", + "on_sale_tooltip": "Incluye items disponible para mintear o publicaciones disponibles", + "only_minting": "Solo disponible para mintear", + "only_minting_tooltip": "Solo incluye items disponibles para mintear (comprando directamente al creador).", + "only_listing": "Solo publicaciones", + "only_listing_tooltip": "Solo incluye items que estan siendo re-vendidos", + "not_for_sale": "No a la venta", + "not_for_sale_tooltip": "Incluye todos los items que no están disponibles para mintear (comprando directamente al creador) o con publicaciones disponibles." + }, + "back_to_top_button": { + "title": "Volver arriba" + }, + "nft_card": { + "category": { + "body_shape": "Cuerpo", + "earring": "Aros", + "eyebrows": "Cejas", + "eyes": "Ojos", + "eyewear": "Gafas", + "facial_hair": "Barba", + "feet": "Pies", + "hair": "Cabello", + "head": "Cabeza", + "hat": "Sombrero", + "helmet": "Cazco", + "lower_body": "Piernas", + "mask": "Mascara", + "mouth": "Boca", + "tiara": "Tiara", + "top_head": "Cabeza", + "upper_body": "Torso", + "skin": "Skin", + "hands_wear": "Manos" + }, + "with_sound": "Con Sonido", + "smart": "Interactivo", + "body_shape": { + "male": "Hombre", + "female": "Mujer", + "unisex": "Unisex" + }, + "play_mode": { + "simple": "Play once", + "loop": "Play loop" + } + }, + "chain_selector": { + "title": "Selecciona una red", + "connected": "Conectado", + "confirm_in_wallet": "Confirma en tu billetera", + "switching": "Cambiando..." + } + } +} diff --git a/src/modules/translation-v2/defaults/fr.json b/src/modules/translation-v2/defaults/fr.json new file mode 100644 index 00000000..f4c045f7 --- /dev/null +++ b/src/modules/translation-v2/defaults/fr.json @@ -0,0 +1,272 @@ +{ + "@dapps": { + "footer": { + "button": { + "network_not_supported": "Vous devez être connecté à {expectedChainName} pour effectuer cette action" + }, + "dropdown": { + "en": "Anglais", + "es": "Espanol", + "fr": "Français", + "ja": "Japonais", + "ko": "Coréen", + "zh": "Chinois" + }, + "links": { + "content": "Contenu", + "ethics": "Code d'éthique", + "home": "Accueil", + "privacy": "Confidentialité", + "terms": "Conditions d'utilisation", + "feature": "Demande de fonctionnalité" + } + }, + "navbar": { + "account": { + "connecting": "De liaison...", + "signIn": "Se connecter" + }, + "menu": { + "avatars": "Avatars", + "agora": "Agora", + "blog": "Blog", + "docs": { + "main": "Docs", + "players": "Players", + "creators": "Content Creators", + "contributors": "Contributors", + "studios": "Studios" + }, + "marketplace": { + "main": "Marketplace", + "overview": "Overview", + "collectibles": "Collectibles", + "land": "LAND", + "names": "NAMEs", + "myAssets": "My Assets" + }, + "builder": { + "main": "Builder", + "overview": "Overview", + "collections": "Collections", + "scenes": "Scenes", + "land": "Land", + "names": "Names", + "worlds": "Worlds" + }, + "events": "Events", + "dao": { + "main": "DAO", + "overview": "Overview", + "governance": "Governance", + "transparency": "Transparency", + "grants": "Grants" + }, + "places": { + "main": "Places", + "overview": "Overview", + "places": "Genesis City", + "worlds": "Worlds", + "faq": "FAQ" + } + }, + "wrong_network": { + "header": "Mauvais réseau", + "message": "Vous devez être connecté au réseau {expectedChainName} pour utiliser cette application, mais vous êtes actuellement connecté au réseau {currentChainName}.", + "message_unknown_network": "Vous devez être connecté à {expectedChainName} pour utiliser cette application, veuillez changer de réseau pour continuer.", + "switch_button": "Passer à {chainName}" + } + }, + "sign_in": { + "connect": "Relier", + "connected": "Connecté", + "connecting": "De liaison...", + "error": "Impossible de se connecter au portefeuille.", + "get_started": "Commencer", + "options": { + "desktop": "Vous pouvez utiliser l'extension {metamask_link} ou un portefeuille matériel comme {ledger_nano_link}.", + "mobile": "Vous pouvez utiliser des navigateurs mobiles tels que {coinbase_link} ou {imtoken_link}.", + "samsung": "Vous pouvez utiliser {samsung_link}." + }, + "modal": { + "title": "Se connecter", + "subtitle": "Choisissez une méthode de connexion", + "using": { + "browser_extension": "Utiliser une extension de navigateur", + "email": "Utiliser votre email", + "mobile": "Utiliser votre portefeuille mobile", + "metamask_mobile": "Utilisation de l'application MetaMask" + } + } + }, + "user_menu": { + "guest": "Anonyme", + "my_lists": "Mes listes", + "my_assets": "Mes actifs", + "account": "Paramètres du compte", + "activity": "Activité", + "profile": "Profil", + "view_profile": "Voir le profil", + "sign_in": "Sign In", + "sign_out": "Sign out", + "marketplace_authorizations": "Autorisations de la Marketplace", + "jump_in": "Jump In" + }, + "toasts": { + "meta_transactions": { + "contract_account_error": { + "title": "Portefeuille non pris en charge", + "body": "Les portefeuilles de contrats intelligents ne sont pas pris en charge pour les méta-transations. Vous pouvez basculer votre réseau vers Polygon et envoyer une transaction régulière." + }, + "invalid_address_error": { + "title": "Adresse invalide", + "body": "L'adresse du contrat n'est pas disponible pour les méta-transactions. Vous pouvez basculer votre réseau vers Polygon et envoyer une transaction régulière." + }, + "sale_price_too_low_error": { + "title": "Prix trop bas", + "body": "Le prix est trop bas pour cette méta-transaction. Vous pouvez basculer votre réseau vers Polygon et envoyer une transaction régulière." + }, + "unknown_error": { + "title": "Quelque chose s'est mal passé", + "body": "Une erreur inattendue s'est produite lors de l'envoi de la méta-transaction. Vous pouvez basculer votre réseau vers Polygon et essayer d'envoyer une transaction normale." + }, + "high_congestion_error": { + "title": "Forte congestion", + "body": "Les prix du gaz du réseau Polygon sont trop élevés! Veuillez patienter et réessayer plus tard, ou basculez votre réseau vers Polygon et payez les frais de gaz avec MATIC." + } + }, + "switch_network": "Passer à {network}", + "learn_more": "En savoir plus" + }, + "network_alert": { + "title": "Votre portefeuille est connecté au Polygon", + "content": "Utilisez ce réseau pour couvrir le gaz d'une transaction (comme lors de l'achat d'articles inférieurs à 1 MANA). Revenez en arrière lorsque vous avez terminé. En savoir plus", + "action": "Passer à Ethereum Mainnet" + }, + "authorization_modal": { + "close": "Fermer", + "waiting_wallet": "Confirmez la transaction sur votre portefeuille", + "waiting_confirmation": "Autorisation de traitement", + "done": "Fait", + "title": "Complétez votre {action}", + "spending_cap_error": "N'oubliez pas de définir un plafond égal au prix de l'article {price} MANA ou plus.", + "revoke_cap_error": "N'oubliez pas de définir un plafond de dépenses de 0 MANA afin de révoquer votre précédent.", + "generic_error": "Quelque chose s'est mal passé", + "insufficient_amount_error": { + "message": "Votre plafond de dépenses n'est pas suffisant pour couvrir le montant d'achat de {price} MANA. Pour continuer, veuillez ajuster votre plafond de dépenses égal ou supérieur.Révoquez le plafond de dépenses actuel et réessayez avec une limite appropriée.", + "action": "Revoke" + }, + "authorize_mana": { + "title": "Tout d'abord, autorisez le Contrat pour opérer MANA en votre nom à Decentraland. ", + "description": "Gardez à l'esprit que certains portefeuilles nécessitent de définir une limite de dépenses de mana personnalisée.Entrez le prix de l'article{price} Mana ou une quantité plus élevée avec laquelle vous êtes à l'aise pour dépenser maintenant ou plus tard.Vous pouvez modifier la limite à tout moment.", + "action": "Autoriser", + "message": "N'oubliez pas de définir un plafond égal au prix de l'article {price} Mana ou plus." + }, + "authorize_nft": { + "title": "Tout d'abord, autorisez le Contrat pour exploiter NFT en votre nom à Decentraland", + "action": "Autoriser" + }, + "confirm_transaction": { + "title": "Confirmer la transaction à {action}l'articlem", + "action": "Confirmer la transaction" + }, + "revoke_cap": { + "title": "Révoquez votre plafond de dépenses actuel", + "description": "Votre plafond de dépenses actuel est inférieur à {price} mana.Vous devrez révoquer votre plafond de dépenses actuel avant d'en faire un nouveau.", + "action": "Autoriser" + }, + "set_cap": { + "title": "Définir un nouveau plafond de dépenses", + "description": "Entrez le prix de l'article {price} ou un montant plus élevé avec lequel vous êtes à l'aise pour dépenser maintenant ou plus tard.Vous pouvez modifier la limite à tout moment.", + "action": "Autoriser" + }, + "action": "action", + "title_action": "action" + }, + "asset_card": { + "listings": "Objets de collection", + "listing": "Objet de collection", + "available_for_mint": "Disponible à l'achat direct auprès du créateur", + "cheapest_listing": "Objet de collection le moins cher", + "not_for_sale": "Non disponible à la vente", + "owners": "Propriétaires", + "owner": "Propriétaire", + "cheapest_option": "Option la moins chère", + "cheapest_option_range": "Option la moins chère dans la fourchette", + "most_expensive": "Le plus cher", + "most_expensive_range": "Le plus cher dans la fourchette", + "also_minting": "Disponible à l'achat direct auprès du créateur" + }, + "rarities_filter": { + "title": "Rareté", + "tooltip": "La rareté détermine le nombre total de NFT qui peuvent être frappés", + "count_rarities": "{count} {count, plural, one {rareté} other {raretés}}", + "all_rarities": "Toutes les raretés" + }, + "rarities": { + "unique": "unique", + "mythic": "Mythique", + "exotic": "Exotique", + "legendary": "Légendaire", + "epic": "Epic", + "rare": "Rare", + "uncommon": "Peu commun", + "common": "Commun" + }, + "rarities_description": { + "unique": "Comme le Graal : unique en son genre", + "mythic": "Pour les plus chanceux : max 10", + "exotic": "Quantité limitée : max 50", + "legendary": "Quantité limitée : max 100", + "epic": "Approvisionnement maximum : 1000", + "rare": "Approvisionnement maximum : 5000", + "uncommon": "Approvisionnement maximum : 100 000", + "common": "Approvisionnement maximum : 100 000" + }, + "asset_status_filter": { + "title": "Statut", + "on_sale": "En soldes", + "on_sale_tooltip": "Comprend des articles disponibles pour la frappe et / ou avec les listes disponibles.", + "only_minting": "Seulement disponible pour la presse", + "only_minting_tooltip": "Ne comprend que des articles disponibles pour la frappe (acheter directement auprès des créateurs).", + "only_listing": "Uniquement les listes", + "only_listing_tooltip": "Inclut uniquement les articles qui sont en cours de revend.", + "not_for_sale": "Pas à vendre", + "not_for_sale_tooltip": "Comprend tous les articles qui ne sont pas disponibles pour la frappe (achetant directement auprès des créateurs) ou ont des listes ouvertes." + }, + "nft_card": { + "category": { + "body_shape": "Forme du corps", + "earring": "Boucle d'oreille", + "eyebrows": "Les sourcils", + "eyes": "Yeux", + "eyewear": "Lunettes", + "facial_hair": "Poils", + "feet": "Pieds", + "head": "Tête", + "hair": "Cheveux", + "hat": "Chapeau", + "helmet": "Casque", + "lower_body": "Bas du corps", + "mask": "Masque", + "mouth": "Bouche", + "tiara": "Tiare", + "top_head": "Tête supérieure", + "upper_body": "Haut du corps", + "skin": "Peau", + "hands_wear": "Vêtements à main" + }, + "with_sound": "Avec son", + "smart": "Interactive", + "body_shape": { + "male": "Femelle", + "female": "Femelle", + "unisex": "Unisexe" + }, + "play_mode": { + "simple": "Jouer une fois", + "loop": "Boucle de jeu" + } + } + } +} diff --git a/src/modules/translation-v2/defaults/index.ts b/src/modules/translation-v2/defaults/index.ts new file mode 100644 index 00000000..afd7a69e --- /dev/null +++ b/src/modules/translation-v2/defaults/index.ts @@ -0,0 +1,8 @@ +import en from './en.json'; +import es from './es.json'; +import fr from './fr.json'; +import ja from './ja.json'; +import ko from './ko.json'; +import zh from './zh.json'; + +export { en, es, fr, ja, ko, zh }; diff --git a/src/modules/translation-v2/defaults/ja.json b/src/modules/translation-v2/defaults/ja.json new file mode 100644 index 00000000..07061116 --- /dev/null +++ b/src/modules/translation-v2/defaults/ja.json @@ -0,0 +1,272 @@ +{ + "@dapps": { + "button": { + "network_not_supported": "このアクションを実行するには、{expectedChainName}に接続する必要があります" + }, + "footer": { + "dropdown": { + "en": "英語", + "es": "スペイン語", + "fr": "フランス語", + "ja": "日本語", + "ko": "韓国語", + "zh": "中国語" + }, + "links": { + "content": "コンテンツポリシー", + "ethics": "倫理規定", + "home": "ホーム", + "privacy": "個人情報保護方針", + "terms": "利用規約", + "feature": "機能リクエスト" + } + }, + "navbar": { + "account": { + "connecting": "接続中...", + "signIn": "サインイン" + }, + "menu": { + "avatars": "Avatars", + "agora": "Agora", + "blog": "Blog", + "docs": { + "main": "Docs", + "players": "Players", + "creators": "Content Creators", + "contributors": "Contributors", + "studios": "Studios" + }, + "marketplace": { + "main": "Marketplace", + "overview": "Overview", + "collectibles": "Collectibles", + "land": "LAND", + "names": "NAMEs", + "myAssets": "My Assets" + }, + "builder": { + "main": "Builder", + "overview": "Overview", + "collections": "Collections", + "scenes": "Scenes", + "land": "Land", + "names": "Names", + "worlds": "Worlds" + }, + "events": "Events", + "dao": { + "main": "DAO", + "overview": "Overview", + "governance": "Governance", + "transparency": "Transparency", + "grants": "Grants" + }, + "places": { + "main": "Places", + "overview": "Overview", + "places": "Genesis City", + "worlds": "Worlds", + "faq": "FAQ" + } + }, + "wrong_network": { + "header": "間違ったネットワーク", + "message": "このアプリを使用するには、{expectedChainName}ネットワークに接続する必要がありますが、現在は{currentChainName}ネットワークに接続しています。", + "message_unknown_network": "このアプリを使用するには、{expectedChainName}に接続する必要があります。続行するには、ネットワークを切り替えてください。", + "switch_button": "{chainName}に切り替えます" + } + }, + "sign_in": { + "connect": "接続する", + "connected": "接続済み", + "connecting": "接続中...", + "error": "ウォレットに接続できませんでした。", + "get_started": "開始する", + "options": { + "desktop": "{metamask_link}拡張や{ledger_nano_link}のようなハードウェアウォレットを使用できます。", + "mobile": "{coinbase_link}や{imtoken_link}などのモバイルブラウザを使用できます。", + "samsung": "{samsung_link}を使用できます。" + }, + "modal": { + "title": "サインイン", + "subtitle": "接続する方法を選択してください", + "using": { + "browser_extension": "ブラウザ拡張機能の使用", + "email": "メールを使用する", + "mobile": "モバイルウォレットの使用", + "metamask_mobile": "メタマスク アプリの使用" + } + } + }, + "user_menu": { + "guest": "名前なし", + "my_lists": "マイ・リスト", + "my_assets": "マイ資産", + "account": "「アカウント設定", + "activity": "「アクティビティ", + "profile": "「プロフィール", + "view_profile": "「プロフィールを見る", + "sign_in": "「サインイン", + "sign_out": "「サインアウト", + "marketplace_authorizations": "マーケットプレイスの承認", + "jump_in": "ジャンプイン" + }, + "toasts": { + "meta_transactions": { + "contract_account_error": { + "タイトル": "ウォレットはサポートされていません", + "body": "スマートコントラクトウォレットはメタトランザクションではサポートされていません。ネットワークをPolygonに切り替えて,通常のトランザクションを送信できます。" + }, + "invalid_address_error": { + "タイトル": "無効なアドレス", + "body": "契約アドレスはメタトランザクションには使用できません。ネットワークをPolygonに切り替えて,通常のトランザクションを送信できます。" + }, + "sale_price_too_low_error": { + "title": "価格も", + "body": "このメタトランザクションには価格が低すぎます。ネットワークをPolygonに切り替えて,通常のトランザクションを送信できます。" + }, + "unknown_error": { + "title": "「問題が発生しました」", + "body": "メタトランザクションの送信中に予期しないエラーが発生しました。ネットワークをPolygonに切り替えて,通常のトランザクションを送信してみてください。" + }, + "high_congestion_error": { + "title": "高い混雑", + "body": "ポリゴン ネットワークのガス価格が高すぎます! しばらく待ってからもう一度お試しいただくか、ネットワークを Polygon に切り替えてネットワーク料金を MATIC でお支払いください。" + } + }, + "switch_network": "{network}に切り替え", + "learn_more": "詳細" + }, + "network_alert": { + "title": "あなたのウォレットは Polygon に接続されています", + "content": "このネットワークを使用して、トランザクションのガスをカバーします (1 MANA 未満のアイテムを購入する場合など)。 終わったらスイッチバック。 詳細", + "action": "「イーサリアムメインネット」に切り替え" + }, + "authorization_modal": { + "close": "近い", + "waiting_wallet": "ウォレットのトランザクションを確認します", + "waiting_confirmation": "許可の処理", + "done": "終わり", + "title": "{アクション}を完成させる", + "spending_cap_error": "アイテム価格{price} MANA 以上に等しいキャップを設定することを忘れないでください。", + "revoke_cap_error": "前のマナを取り消すために、0マナの支出キャップを設定することを忘れないでください。", + "generic_error": "何かがうまくいかなかった", + "insufficient_amount_error": { + "message": "支出上限は、{price}マナの購入額をカバーするのに十分ではありません。続行するには、支出キャップを等しく調整してください。現在の支出キャップを取り消し、適切な制限で再試行します。", + "action": "取り消す" + }, + "authorize_mana": { + "title": "まず、 契約を承認して、Decentralandであなたに代わってManaを運用します。 ", + "description": "一部のウォレットには、カスタムマナの支出制限を設定する必要があることに注意してください。アイテム価格{price}マナまたはあなたが今またはそれ以降の支出に満足している量を入力してください。いつでも制限を変更できます。", + "action": "許可", + "message": "アイテム価格{price}マナ以上に等しいキャップを設定することを忘れないでください。" + }, + "authorize_nft": { + "title": "まず、<契約> 契約を承認して、Decentralandでお客様に代わってNFTを操作する", + "action": "許可" + }, + "confirm_transaction": { + "title": "{action}アイテムへのトランザクションを確認します", + "action": "トランザクションを確認します" + }, + "revoke_cap": { + "title": "現在の支出キャップを取り消します", + "description": "現在の支出キャップは{price}マナよりも低いです。新しいものを作成する前に、現在の支出キャップを取り消す必要があります。", + "action": "許可" + }, + "set_cap": { + "title": "新しい支出キャップを設定します", + "description": "アイテム価格{price}マナまたはあなたが今またはそれ以降の支出に満足している量を入力してください。いつでも制限を変更できます。", + "action": "許可" + }, + "action": "アクション", + "title_action": "アクション" + }, + "asset_card": { + "listings": "コレクションアイテム", + "listing": "コレクションアイテム", + "available_for_mint": "クリエイターによる直接購入可能", + "cheapest_listing": "最も安いコレクションアイテム", + "not_for_sale": "販売不可", + "owners": "所有者", + "owner": "所有者", + "cheapest_option": "最も安いオプション", + "cheapest_option_range": "範囲内の最も安いオプション", + "most_expensive": "最も高い価格", + "most_expensive_range": "範囲内の最も高い価格", + "also_minting": "クリエイターによる直接購入可能" + }, + "rarities_filter": { + "title": "珍しい", + "tooltip": "希少性により、鋳造できるNFTの総数が決まります", + "count_rarities": "{count} {count, plural, one {珍しい} other {珍しい}}", + "all_rarities": "すべての珍しい" + }, + "rarities": { + "unique": "個性的", + "mythic": "神話", + "exotic": "エキゾチック", + "legendary": "伝説", + "epic": "すごい", + "rare": "レア", + "uncommon": "珍しい", + "common": "一般" + }, + "rarities_description": { + "unique": "聖杯のようなもの: 唯一無二の", + "mythic": "幸運な少数の場合: 最大 10", + "exotic": "数量限定:最大50個", + "legendary": "数量限定:最大100個", + "epic": "最大供給量: 1000", + "rare": "最大供給数: 5000", + "uncommon": "最大供給数: 10,000", + "common": "最大供給量: 100,000" + }, + "asset_status_filter": { + "title": "状態", + "on_sale": "発売中", + "on_sale_tooltip": "造りや利用可能なリストを使用できるアイテムが含まれています。", + "only_minting": "造りにのみ利用できます", + "only_minting_tooltip": "メントに利用できるアイテムのみが含まれています(クリエイターから直接購入)。", + "only_listing": "リストのみ", + "only_listing_tooltip": "転売されているアイテムのみが含まれます。", + "not_for_sale": "非売品", + "not_for_sale_tooltip": "造りに使用できないすべてのアイテム(クリエイターから直接購入)またはオープンリスティングが含まれています。" + }, + "nft_card": { + "category": { + "body_shape": "体型", + "earring": "イヤリング", + "eyebrows": "眉毛", + "eyes": "目", + "eyewear": "アイウェア", + "facial_hair": "顔の毛", + "feet": "足", + "head": "頭", + "hair": "髪", + "hat": "帽子", + "helmet": "ヘルメット", + "lower_body": "下半身", + "mask": "マスク", + "mouth": "口", + "tiara": "ティアラ", + "top_head": "トップヘッド", + "upper_body": "上半身", + "skin": "肌", + "hands_wear": "ハンドウェア" + }, + "with_sound": "音で", + "smart": "Smart", + "body_shape": { + "male": "男", + "female": "女性", + "unisex": "ユニセックス" + }, + "play_mode": { + "simple": "Play once", + "loop": "Play loop" + } + } + } +} diff --git a/src/modules/translation-v2/defaults/ko.json b/src/modules/translation-v2/defaults/ko.json new file mode 100644 index 00000000..60ce64cb --- /dev/null +++ b/src/modules/translation-v2/defaults/ko.json @@ -0,0 +1,272 @@ +{ + "@dapps": { + "button": { + "network_not_supported": "이 작업을 수행하려면 {expectedChainName}에 연결해야 합니다." + }, + "footer": { + "dropdown": { + "en": "영어", + "es": "스페인 사람", + "fr": "프랑스 국민", + "ja": "일본어", + "ko": "한국어", + "zh": "중국말" + }, + "links": { + "content": "콘텐츠 정책", + "ethics": "윤리 강령", + "home": "집", + "privacy": "개인 정보 정책", + "terms": "이용 약관", + "feature": "기능 요청" + } + }, + "navbar": { + "account": { + "connecting": "연결 중 ...", + "signIn": "로그인" + }, + "menu": { + "avatars": "Avatars", + "agora": "Agora", + "blog": "Blog", + "docs": { + "main": "Docs", + "players": "Players", + "creators": "Content Creators", + "contributors": "Contributors", + "studios": "Studios" + }, + "marketplace": { + "main": "Marketplace", + "overview": "Overview", + "collectibles": "Collectibles", + "land": "LAND", + "names": "NAMEs", + "myAssets": "My Assets" + }, + "builder": { + "main": "Builder", + "overview": "Overview", + "collections": "Collections", + "scenes": "Scenes", + "land": "Land", + "names": "Names", + "worlds": "Worlds" + }, + "events": "Events", + "dao": { + "main": "DAO", + "overview": "Overview", + "governance": "Governance", + "transparency": "Transparency", + "grants": "Grants" + }, + "places": { + "main": "Places", + "overview": "Overview", + "places": "Genesis City", + "worlds": "Worlds", + "faq": "FAQ" + } + }, + "wrong_network": { + "header": "잘못된 네트워크", + "message": "이 앱을 사용하려면 {expectedChainName} 네트워크에 연결되어 있어야하지만 현재 {currentChainName} 네트워크에 연결되어 있습니다.", + "message_unknown_network": "이 앱을 사용하려면 {expectedChainName}에 연결해야 합니다. 계속하려면 네트워크를 전환하세요.", + "switch_button": "{chainName}(으)로 전환" + } + }, + "sign_in": { + "connect": "잇다", + "connected": "연결됨", + "connecting": "연결 중 ...", + "error": "지갑에 연결할 수 없습니다.", + "get_started": "시작하다", + "options": { + "desktop": "{metamask_link} 확장 또는 {ledger_nano_link}과 같은 하드웨어 지갑을 사용할 수 있습니다.", + "mobile": "{coinbase_link} 또는 {imtoken_link}과 같은 모바일 브라우저를 사용할 수 있습니다.", + "samsung": "{samsung_link}를 사용할 수 있습니다." + }, + "modal": { + "title": "로그인", + "subtitle": "연결할 방법 선택", + "using": { + "browser_extension": "브라우저 확장 사용", + "email": "이메일 사용", + "mobile": "모바일 지갑 사용", + "metamask_mobile": "메타마스크 앱 사용" + } + } + }, + "user_menu": { + "guest": "이름이 없습니다", + "my_lists": "내 목록", + "my_assets": "내 자산", + "account": "계정 설정", + "activity": "활동", + "profile": "프로필", + "view_profile": "프로필 보기", + "sign_in": "로그인", + "sign_out": "로그아웃", + "marketplace_authorizations": "마켓플레이스의 승인", + "jump_in": "점프 인" + }, + "toasts": { + "meta_transactions": { + "contract_account_error": { + "title": "지갑이 지원되지 않음", + "body": "스마트 계약 지갑은 메타 거래를 지원하지 않습니다. 네트워크를 Polygon으로 전환하고 일반 거래를 보낼 수 있습니다." + }, + "invalid_address_error": { + "제목": "잘못된 주소", + "body": "메타 트랜잭션에 사용할 수 있는 계약 주소가 없습니다. 네트워크를 Polygon으로 전환하고 일반 트랜잭션을 보낼 수 있습니다." + }, + "sale_price_too_low_error": { + "title": "가격이 너무 저렴하다", + "body": "이 메타 거래에 대한 가격이 너무 낮습니다. 네트워크를 Polygon으로 전환하고 일반 트랜잭션을 보낼 수 있습니다." + }, + "unknown_error": { + "title": "문제가 발생했습니다", + "body": "메타 트랜잭션을 보내는 동안 예기치 않은 오류가 발생했습니다. 네트워크를 Polygon으로 전환하고 일반 트랜잭션을 보내보십시오." + }, + "high_congestion_error": { + "title": "높은 혼잡", + "body": "Polygon Network 가스 가격이 너무 높습니다! 나중에 다시 시도하거나 네트워크를 Polygon으로 전환하고 MATIC으로 네트워크 수수료를 지불하십시오." + } + }, + "switch_network": "{네트워크}로 전환", + "learn_more": "자세히 알아보기" + }, + "network_alert": { + "title": "지갑이 Polygon에 연결되었습니다", + "content": "이 네트워크를 사용하여 거래의 가스를 처리합니다(예: 1 MANA 미만의 항목을 구매할 때). 끝나면 다시 전환하십시오. 자세히 알아보기", + "action": "이더리움 메인넷으로 전환" + }, + "authorization_modal": { + "close": "Close", + "waiting_wallet": "지갑의 거래를 확인하십시오", + "waiting_confirmation": "처리 승인", + "done": "완료", + "title": "당신을 완성하십시오 {action}", + "spending_cap_error": "품목 가격 {price} MANA 이상과 동일한 캡을 설정해야합니다.", + "revoke_cap_error": "이전 제품을 취소하기 위해 0 마나의 지출 한도를 설정해야합니다.", + "generic_error": "뭔가 잘못되었습니다", + "insufficient_amount_error": { + "message": "지출 한도는 {price} 마나의 구매 금액을 충당하기에 충분하지 않습니다.진행하려면 지출 한도를 동일하거나 더 높은 조정하십시오.현재 지출 한도를 취소하고 적절한 한도로 다시 시도하십시오.", + "action": "취소" + }, + "authorize_mana": { + "title": "먼저 승인하십시오 Decentraland에서 귀하를 대신하여 Mana를 운영하는 계약.", + "description": "일부 지갑에는 맞춤형 마나 지출 한도를 설정해야합니다.품목 가격 {price} mana 또는 지금 또는 나중에 지출하기에 편안한 금액을 입력하십시오.언제든지 한도를 변경할 수 있습니다.", + "action": "승인", + "message": "품목 가격 {price} 마나 이상과 동일한 캡을 설정해야합니다." + }, + "authorize_nft": { + "title": "먼저 승인하십시오 Decentraland에서 귀하를 대신하여 NFT를 운영하는 계약", + "action": "승인" + }, + "confirm_transaction": { + "title": "{action} 항목에 대한 트랜잭션을 확인하십시오", + "action": "거래 확인" + }, + "revoke_cap": { + "title": "현재 지출 한도를 취소하십시오", + "description": "현재 지출 한도는 {price} Mana보다 낮습니다.새로운 지출 한도를 만들기 전에 현재 지출 한도를 취소해야합니다.", + "action": "승인" + }, + "set_cap": { + "title": "새로운 지출 한도를 설정하십시오", + "description": "품목 가격 {price} mana 또는 지금 또는 나중에 지출하기에 편안한 금액을 입력하십시오.언제든지 한도를 변경할 수 있습니다.", + "action": "승인" + }, + "action": "행동", + "title_action": "행동" + }, + "asset_card": { + "listings": "컬렉션 아이템", + "listing": "컬렉션 아이템", + "available_for_mint": "제작자에게 직접 구매 가능", + "cheapest_listing": "가장 저렴한 컬렉션 아이템", + "not_for_sale": "판매 불가", + "owners": "소유자", + "owner": "소유자", + "cheapest_option": "가장 저렴한 옵션", + "cheapest_option_range": "범위 내 가장 저렴한 옵션", + "most_expensive": "가장 비싼 가격", + "most_expensive_range": "범위 내 가장 비싼 가격", + "also_minting": "제작자에게 직접 구매 가능" + }, + "rarities_filter": { + "title": "희박", + "tooltip": "Rarity는 민트를 사용할 수있는 총 NFT의 총 수를 결정합니다.", + "count_rarities": "{count} {count, plural, one {희박} other {희귀 성}}", + "all_rarities": "모든 희귀 성" + }, + "rarities": { + "unique": "고유한", + "mythic": "신화", + "exotic": "이국적인", + "legendary": "전설", + "epic": "서사시", + "rare": "희귀한", + "uncommon": "드문", + "common": "흔한" + }, + "rarities_description": { + "unique": "성배 같은: 독특한", + "mythic": "운이 좋은 소수의 경우: 최대 10", + "exotic": "한정 공급: 최대 50개", + "legendary": "한정 공급: 최대 100개", + "epic": "최대 공급량: 1000", + "rare": "최대 공급량: 5000", + "uncommon": "최대 공급량: 10,000", + "common": "최대 공급량: 100,000" + }, + "asset_status_filter": { + "title": "상태", + "on_sale": "판매 중", + "on_sale_tooltip": "마이닝 및/또는 사용 가능한 목록이있는 품목이 포함되어 있습니다.", + "only_minting": "마이닝에만 사용할 수 있습니다", + "only_minting_tooltip": "마이닝에 사용할 수있는 품목 만 포함합니다 (제작자로부터 직접 구매).", + "only_listing": "목록 만", + "only_listing_tooltip": "재판매중인 항목 만 포함합니다.", + "not_for_sale": "비매품", + "not_for_sale_tooltip": "마이닝 할 수없는 모든 품목 (제작자로부터 직접 구매) 또는 개방형 목록이 포함되어 있습니다." + }, + "nft_card": { + "category": { + "body_shape": "체형", + "earring": "귀걸이", + "eyebrows": "눈썹", + "eyes": "눈", + "eyewear": "안경", + "facial_hair": "얼굴 털", + "feet": "피트", + "head": "머리", + "hair": "머리카락", + "hat": "모자", + "helmet": "헬멧", + "lower_body": "하체", + "mask": "마스크", + "mouth": "입", + "tiara": "보석 달린 머리 장식", + "top_head": "상단 머리", + "upper_body": "상체", + "skin": "피부", + "hands_wear": "핸드웨어" + }, + "with_sound": "음악 들으면서", + "smart": "똑똑한", + "body_shape": { + "male": "남성", + "female": "여성", + "unisex": "유엔" + }, + "play_mode": { + "simple": "한 번 플레이하십시오", + "loop": "연주 루프" + } + } + } +} diff --git a/src/modules/translation-v2/defaults/zh.json b/src/modules/translation-v2/defaults/zh.json new file mode 100644 index 00000000..97eec205 --- /dev/null +++ b/src/modules/translation-v2/defaults/zh.json @@ -0,0 +1,362 @@ +{ + "@dapps": { + "button": { + "network_not_supported": "您需要连接到 {expectedChainName} 才能执行此操作" + }, + "footer": { + "dropdown": { + "en": "英语", + "es": "西班牙语", + "fr": "法语", + "ja": "日语", + "ko": "韩文", + "zh": "中文" + }, + "links": { + "content": "内容政策", + "ethics": "道德准则", + "home": "主页", + "privacy": "隐私政策", + "terms": "使用条款", + "feature": "功能要求" + } + }, + "navbar": { + "account": { + "connecting": "正在连接...", + "signIn": "登陆" + }, + "menu": { + "avatars": "Avatars", + "agora": "Agora", + "blog": "Blog", + "docs": { + "main": "Docs", + "players": "Players", + "creators": "Content Creators", + "contributors": "Contributors", + "studios": "Studios" + }, + "marketplace": { + "main": "Marketplace", + "overview": "Overview", + "collectibles": "Collectibles", + "land": "LAND", + "names": "NAMEs", + "myAssets": "My Assets" + }, + "builder": { + "main": "Builder", + "overview": "Overview", + "collections": "Collections", + "scenes": "Scenes", + "land": "Land", + "names": "Names", + "worlds": "Worlds" + }, + "events": "Events", + "dao": { + "main": "DAO", + "overview": "Overview", + "governance": "Governance", + "transparency": "Transparency", + "grants": "Grants" + }, + "places": { + "main": "Places", + "overview": "Overview", + "places": "Genesis City", + "worlds": "Worlds", + "faq": "FAQ" + } + }, + "wrong_network": { + "header": "网络错误", + "message": "您需要连接到{expectedChainName}网络才能使用此应用,但您当前已连接到{currentChainName}网络。", + "message_unknown_network": "您需要连接到 {expectedChainName} 才能使用此应用,请切换您的网络以继续。", + "switch_button": "切换到 {chainName}", + "sign_out": "登出" + } + }, + "sign_in": { + "connect": "连接", + "connected": "已连接", + "connecting": "连接中 ...", + "error": "无法连接到钱包。", + "get_started": "开始", + "options": { + "connected": "您已经连接!", + "desktop": "您可以使用{metamask_link}扩展名或您的电子邮件帐户", + "mobile": "您可以使用移动浏览器,如 {coinbase_link} 或 {imtoken_link}。", + "samsung": "您可使用{samsung_link}。" + } + }, + "login": { + "modal": { + "title": "登入", + "subtitle": "选择一种连接方式", + "error": "无法连接到钱包。", + "supported_wallets": "不支持 Contract 和 Trezor 钱包与 Polygon 交互。阅读有关 Trezor 集成的更多信息 {trezor_link}", + "trezor_link": "这里" + }, + "option": { + "browser_extension": "使用浏览器扩展", + "email": "使用您的电子邮件", + "mobile": "使用您的手机钱包", + "mobile_and_browser": "使用您的移动或浏览器扩展程序", + "metamask_mobile": "使用 MetaMask 應用程序" + } + }, + "buyManaWithFiat": { + "modal": { + "title": "购买法力值", + "subtitle": "选择您要购买的 MANA:", + "error": "无法购买 MANA。" + }, + "feedback_modal": { + "pending": { + "title": "购买 {network} MANA", + "status_title": "交易正在处理中", + "description": "在处理交易时等待几分钟", + "go_to_text": "转到{网关}标签" + }, + "success": { + "title": "{network} MANA 购买完成!", + "description": "{network} MANA 已添加到您的帐户。 如果您仍然没有在余额中看到它,请刷新此页面。", + "cta": "完毕", + "view_transaction": "在资源管理器中查看交易" + }, + "failure": { + "title": "购买 {network} MANA", + "description": "您可以使用{gateway} 重试或选择其他提供商", + "status_title": "交易失败", + "cta": "再试一次", + "secondary_cta": "选择其他供应商" + } + }, + "network": { + "ethereum": { + "cta": "以太坊 MANA", + "ctaSubtitle": "用它在以太坊中购买 LAND、名称和特定的可穿戴设备。", + "title": "购买以太坊 MANA", + "error": "无法购买以太坊 MANA", + "moonPay": { + "title": "使用 MoonPay 购买以太坊 MANA", + "subtitle": "您可以使用借记卡和信用卡、Apple Pay、Google Pay 或通过银行转帐进行购买。", + "continueButtonText": "继续使用 MoonPay", + "learnMoreText": "了解有关 MoonPay 的更多信息" + }, + "transak": { + "title": "使用 Transak 购买以太坊 MANA", + "subtitle": "您可以使用借记卡和信用卡、Apple Pay、Google Pay 或通过银行转帐进行购买。", + "continueButtonText": "继续 Transak", + "learnMoreText": "了解有关 Transak 的更多信息" + } + }, + "matic": { + "cta": "多边形 MANA", + "ctaSubtitle": "用它来购买 Polygon 中的大多数可穿戴设备和表情。", + "title": "购买多边形 MANA", + "error": "无法购买多边形 MANA", + "moonPay": { + "title": "使用 MoonPay 购买 Polygon MANA", + "subtitle": "您可以使用借记卡和信用卡、Apple Pay、Google Pay 或通过银行转帐进行购买。", + "continueButtonText": "继续使用 MoonPay", + "learnMoreText": "了解有关 MoonPay 的更多信息" + }, + "transak": { + "title": "使用 Transak 购买 Polygon MANA", + "subtitle": "您可以使用借记卡和信用卡、Apple Pay、Google Pay 或通过银行转帐进行购买。", + "continueButtonText": "继续 Transak", + "learnMoreText": "了解有关 Transak 的更多信息" + } + } + } + }, + "user_menu": { + "guest": "未命名", + "my_lists": "我的列表", + "my_assets": "我的资产", + "account": "账户设置", + "activity": "活动", + "profile": "配置文件", + "view_profile": "查看简介", + "sign_in": "登录", + "sign_out": "签出", + "marketplace_authorizations": "市场的授权", + "jump_in": "跳入" + }, + "toasts": { + "meta_transactions": { + "contract_account_error": { + "title": "不支持钱包", + "body": "元交易不支持智能合约钱包。您可以将网络切换到 Polygon 并发送常规交易。" + }, + "invalid_address_error": { + "title": "无效地址", + "body": "合约地址不可用于元交易。您可以将您的网络切换到 Polygon 并发送常规交易。" + }, + "sale_price_too_low_error": { + "title": "价格太低了", + "body": "这个元交易的价格太低了。您可以将您的网络切换到 Polygon 并发送常规交易。" + }, + "unknown_error": { + "title": "出了点问题", + "body": "发送元交易时出现意外错误。您可以将网络切换到 Polygon 并尝试发送常规交易。" + }, + "high_congestion_error": { + "title": "高度拥堵", + "body": "多边形网络 费用价格 太高!请稍后重试,或将您的网络切换到 Polygon 并使用 MATIC 支付费用。" + } + }, + "switch_network_error": { + "title": "网络交换机错误", + "body": "切换到 {network} 时出错。" + }, + "switch_network": "切换到 {network}", + "learn_more": "了解更多" + }, + "network_alert": { + "title": "您的钱包已连接到 Polygon", + "content": "使用此网络来支付交易的费用(例如购买低于 1 MANA 的物品时)。 完成后切换回去。 了解更多", + "action": "切换到以太坊主网" + }, + "authorization_modal": { + "close": "关闭", + "waiting_wallet": "确认钱包上的交易", + "waiting_confirmation": "处理授权", + "done": "完毕", + "title": "完成您的 {action}", + "spending_cap_error": "请记住,设置一个等于物品价格{price} MANA 或更高的帽子。", + "revoke_cap_error": "请记住,设置一个0法力的支出上限,以撤销您以前的支出。", + "generic_error": "出了些问题", + "insufficient_amount_error": { + "message": "请记住,设置一个等于物品价格 {price} MANA 或更高的帽子。在再次授权之前,您必须撤销当前的支出上限。", + "action": "撤销" + }, + "authorize_mana": { + "title": "首先,授权 合同运营 MANA 代表您在分权中。 ", + "description": "请记住,某些钱包需要设置自定义 MANA 支出限制.输入商品价格 {price} MANA 或您现在或以后花费更高的钱。您可以随时更改限制。", + "action": "授权", + "message": "切记设置一个等于物品价格的上限{price} MANA 或更高。" + }, + "authorize_nft": { + "title": "首先,授权 代表您在去居中的NFT的合同", + "action": "授权" + }, + "confirm_transaction": { + "title": "确认交易到 {action} 项目", + "action": "确认交易" + }, + "revoke_cap": { + "title": "撤销您当前的支出上限", + "description": "您目前的支出限额低于{price} MANA. 在制作新的支出之前,您必须撤销当前的支出上限。", + "action": "授权" + }, + "set_cap": { + "title": "设置新的支出帽", + "description": "输入商品价格{price} MANA 或您现在或以后花费更高的钱。您可以随时更改限制。", + "action": "授权" + }, + "action": "行动", + "title_action": "行动" + }, + "asset_card": { + "listings": "收藏品", + "listing": "收藏品", + "available_for_mint": "直接從創作者那裡購買", + "cheapest_listing": "最便宜的收藏品", + "not_for_sale": "不可出售", + "owners": "所有者", + "owner": "所有者", + "cheapest_option": "最便宜", + "cheapest_option_range": "范围内最便宜的选择", + "most_expensive": "最貴", + "most_expensive_range": "范围内最贵", + "also_minting": "直接從創作者那裡購買" + }, + "smart_wearables_filter": { + "title": "聪明的", + "selected": "唯智" + }, + "rarities_filter": { + "title": "稀有", + "tooltip": "稀有性决定了可以铸造的NFT的总数", + "count_rarities": "{count} {count, plural, one {稀有} other {稀有}}", + "all_rarities": "所有稀有物" + }, + "rarities": { + "unique": "独特的", + "mythic": "神话", + "exotic": "异国情调", + "legendary": "传奇的", + "epic": "史诗", + "rare": "稀有的", + "uncommon": "罕见", + "common": "常见的" + }, + "rarity_description": { + "unique": "像圣杯一样:独一无二", + "mythic": "给幸运的人:最多10个", + "exotic": "限量供应:最多50个", + "legendary": "限量供应:最多100个", + "epic": "最大供应量:1000个", + "rare": "最大供应量:5000个", + "uncommon": "最大供应量:10,000个", + "common": "最大供应量:100,000个" + }, + "asset_status_filter": { + "title": "地位", + "on_sale": "特价中", + "on_sale_tooltip": "包括可用于铸造和/或具有可用列表的项目。", + "only_minting": "仅可用于铸币", + "only_minting_tooltip": "仅包括可铸造的物品(直接从创作者处购买)。", + "only_listing": "仅列表", + "only_listing_tooltip": "仅包括正在转售的项目。", + "not_for_sale": "不作为产品销售", + "not_for_sale_tooltip": "包括所有不可用于铸造(直接从创建者购买)或有开放式列表的项目。" + }, + "back_to_top_button": { + "title": "回到顶部" + }, + "nft_card": { + "category": { + "body_shape": "身材", + "earring": "耳环", + "eyebrows": "眉毛", + "eyes": "眼睛", + "eyewear": "眼镜", + "facial_hair": "胡子", + "feet": "腿部", + "hair": "头发", + "hat": "帽子", + "helmet": "头盔", + "lower_body": "下半身", + "mask": "面具", + "mouth": "嘴巴", + "tiara": "头饰", + "top_head": "头顶", + "upper_body": "上半身", + "skin": "皮肤", + "hands_wear": "手" + }, + "with_sound": "有声音的", + "smart": "聪明的", + "body_shape": { + "male": "男性", + "female": "女性", + "unisex": "中性" + }, + "play_mode": { + "simple": "播放一次", + "loop": "循环播放" + } + }, + "chain_selector": { + "title": "选择网络", + "connected": "已连接", + "confirm_in_wallet": "请在您的钱包中确认", + "switching": "切换中..." + } + } +} diff --git a/src/modules/translation-v2/index.ts b/src/modules/translation-v2/index.ts new file mode 100644 index 00000000..08368c52 --- /dev/null +++ b/src/modules/translation-v2/index.ts @@ -0,0 +1,4 @@ +export * from './slice' +export * from './selectors' +export * from './types' +export * from './utils' diff --git a/src/modules/translation-v2/selectors.ts b/src/modules/translation-v2/selectors.ts new file mode 100644 index 00000000..4ad076cb --- /dev/null +++ b/src/modules/translation-v2/selectors.ts @@ -0,0 +1,34 @@ +import { Locale, TranslationKeys } from './types'; +import { getPreferredLocale } from './utils'; + +export function isLoading({ translation }: any) { + return translation.status === 'loading'; +} + +export function mapLocale({ translation }: any, locales: Locale[]) { + return translation.locale || getPreferredLocale(locales) || locales[0]; +} + +export function selectLocale( + state: any, + locales: Locale[], +): Locale | undefined { + return !isLoading(state) ? mapLocale(state, locales) : undefined; +} + +export function selectTranslations( + state: any, + locales: Locale[], +): { + locale?: Locale; + translations?: TranslationKeys; +} { + const { translation } = state; + const locale = selectLocale(state, locales); + if (locale) { + const translationsInState = translation.value[locale] || undefined; + return { locale, translations: translationsInState }; + } + + return { locale }; +} diff --git a/src/modules/translation-v2/slice.ts b/src/modules/translation-v2/slice.ts new file mode 100644 index 00000000..fdbd2ab3 --- /dev/null +++ b/src/modules/translation-v2/slice.ts @@ -0,0 +1,84 @@ +import { createAsyncThunk, createSlice, PayloadAction } from '@reduxjs/toolkit'; +import { flatten } from 'flat'; + +import { + Locale, + TranslationState, + Translation, + TranslationKeys, + TranslationFetcherOpts, +} from './types'; +import { mergeTranslations, setCurrentLocale } from './utils'; +import * as defaultTranslations from './defaults'; + +const INITIAL_STATE: TranslationState = { + value: {}, + locale: 'en', + status: 'idle', + error: null, +}; + +export function createTranslationFetcher({ + getTranslation, + translations, +}: TranslationFetcherOpts) { + return createAsyncThunk( + 'translation/fetchTranslations', + async function fetchTranslations( + locale: Locale, + ): Promise<{ translations: TranslationKeys; locale: Locale }> { + let result: Translation; + if (getTranslation) { + result = await getTranslation(locale); + } else if (translations) { + result = translations[locale]; + } else { + throw new Error('You must provide `translations` or `getTranslations`'); + } + + // merge translations and defaults + const allTransalations = mergeTranslations( + flatten(defaultTranslations[locale]), + flatten(result), + ); + + setCurrentLocale(locale, allTransalations); + + return { locale, translations: allTransalations }; + }, + ); +} + +export function createTranslationSlice({ + fetchTranslations, +}: { + fetchTranslations: ReturnType; +}) { + const { actions, reducer } = createSlice({ + name: 'translation', + initialState: INITIAL_STATE, + reducers: { + changeLocale(state, action: PayloadAction) { + state.locale = action.payload; + }, + }, + extraReducers: (builder) => { + builder + .addCase(fetchTranslations.pending, (state) => { + state.status = 'loading'; + }) + .addCase(fetchTranslations.fulfilled, (state, action) => { + const { locale } = action.payload; + state.status = 'succeeded'; + state.value[locale] = action.payload.translations; + state.locale = locale; + }) + .addCase(fetchTranslations.rejected, (state, action) => { + state.status = 'failed'; + state.error = action.error.message || 'Failed to fetch translations'; + }); + }, + }); + + return { reducer, actions: { ...actions, fetchTranslations } }; +} diff --git a/src/modules/translation-v2/types.ts b/src/modules/translation-v2/types.ts new file mode 100644 index 00000000..6130f65a --- /dev/null +++ b/src/modules/translation-v2/types.ts @@ -0,0 +1,23 @@ +export type Locale = 'en' | 'es' | 'zh'; + +export type Status = 'idle' | 'loading' | 'succeeded' | 'failed'; + +export interface TranslationKeys { + [key: string]: string; +} + +export interface Translation { + [locale: string]: TranslationKeys | null; +} + +export type TranslationState = { + value: Translation; + locale: Locale; + status: Status; + error: string | null; +}; + +export type TranslationFetcherOpts = { + getTranslation?: (locale: string) => Promise; + translations?: { [locale: string]: Translation }; +}; diff --git a/src/modules/translation-v2/utils.ts b/src/modules/translation-v2/utils.ts new file mode 100644 index 00000000..74d3d09b --- /dev/null +++ b/src/modules/translation-v2/utils.ts @@ -0,0 +1,80 @@ +import { + IntlProvider, + createIntl, + createIntlCache, + FormattedMessage, +} from 'react-intl'; +import { Locale } from './types'; + +const cache = createIntlCache(); +let currentLocale: ReturnType; + +export const I18nProvider = IntlProvider; + +export function getPreferredLocale(availableLocales: Locale[]): Locale | null { + if (!availableLocales) { + throw new Error('Failed to get preferred locale: Missing locale list'); + } + + const { navigator } = window; + + const navigatorLocale = + (navigator.languages && navigator.languages[0]) || navigator.language; + + const locale: Locale = navigatorLocale.slice(0, 2) as Locale; + + if (!availableLocales.includes(locale)) { + return null; + } + + return locale; +} + +export function setCurrentLocale( + localeName: Locale, + messages: Record, +) { + const locale = { + en: 'en-EN', + es: 'es-ES', + zh: 'zh-CN', + }[localeName]; + + currentLocale = createIntl({ locale, messages }, cache); +} + +export function getCurrentLocale() { + return currentLocale; +} + +export function t(id: string, values?: any) { + return currentLocale.formatMessage({ id }, values); +} + +export const T = FormattedMessage; + +// eslint-disable-next-line no-underscore-dangle +function _mergeTranslations( + target: T = {} as T, + source: T = {} as T, +) { + const merged: T = Object.keys(source).reduce((result: T, key: string) => { + // @ts-ignore + result[key] = + typeof source[key] === 'object' + ? _mergeTranslations(target[key] as T, source[key] as T) + : source[key]; + return result; + }, target); + return merged; +} + +export function mergeTranslations( + target: T = {} as T, + ...sources: (T | undefined)[] +) { + return [target, ...sources].reduce( + (result, obj) => _mergeTranslations(result, obj), + {} as T, + ); +} diff --git a/src/providers/TranslationProvider-v2/component.tsx b/src/providers/TranslationProvider-v2/component.tsx new file mode 100644 index 00000000..580bdf44 --- /dev/null +++ b/src/providers/TranslationProvider-v2/component.tsx @@ -0,0 +1,35 @@ +import React from 'react'; +import { useEffect, useState } from 'react'; +import { useDispatch, useSelector } from 'react-redux'; + +import { Props } from './types'; +import { I18nProvider } from '../../modules/translation-v2/utils'; +import { selectTranslations } from '../../modules/translation-v2/selectors'; +import { Locale } from '../../modules/translation-v2/types'; + +export function TranslationProvider({ + children, + locales, + fetchTranslations, +}: Props) { + const dispatch = useDispatch(); + const { locale, translations } = useSelector((state) => + selectTranslations(state, locales), + ); + const [_locale, setLocale] = useState(); + + useEffect(() => { + if (locale && _locale !== locale) { + dispatch(fetchTranslations(locale)); + setLocale(locale); + } + }, [locale, fetchTranslations]); + + return translations && locale ? ( + + {children} + + ) : ( + null + ); +} diff --git a/src/providers/TranslationProvider-v2/index.ts b/src/providers/TranslationProvider-v2/index.ts new file mode 100644 index 00000000..3f90b269 --- /dev/null +++ b/src/providers/TranslationProvider-v2/index.ts @@ -0,0 +1,3 @@ +import { TranslationProvider } from './component'; + +export { TranslationProvider }; diff --git a/src/providers/TranslationProvider-v2/types.ts b/src/providers/TranslationProvider-v2/types.ts new file mode 100644 index 00000000..bc0e553f --- /dev/null +++ b/src/providers/TranslationProvider-v2/types.ts @@ -0,0 +1,12 @@ +import { ReactNode } from 'react'; + +import { Locale } from '../../modules/translation-v2/types'; +import { createTranslationFetcher } from '../../modules/translation-v2/slice'; + +export type Props = { + fetchTranslations: ( + locale: Locale, + ) => ReturnType>; + locales: Locale[]; + children?: ReactNode; +}; diff --git a/src/providers/index.ts b/src/providers/index.ts index 5389bc41..0ece30f3 100644 --- a/src/providers/index.ts +++ b/src/providers/index.ts @@ -1,4 +1,5 @@ export { default as ModalProvider } from './ModalProvider' export { default as ToastProvider } from './ToastProvider' export { default as TranslationProvider } from './TranslationProvider' +export { TranslationProvider as TranslationProviderV2 } from './TranslationProvider-v2' export { default as WalletProvider } from './WalletProvider'