i18n for remix-ui-editor

pull/5370/head
drafish 11 months ago committed by Aniket
parent 2b5c7379a8
commit e5f0d91cfb
  1. 31
      apps/remix-ide/src/app/tabs/locales/en/editor.json
  2. 97
      libs/remix-ui/editor/src/lib/remix-ui-editor.tsx

@ -0,0 +1,31 @@
{
"editor.keyboardShortcuts": "Keyboard Shortcuts",
"editor.keyboardShortcuts.text1": "Compile the current contract",
"editor.keyboardShortcuts.text2": "Open the File Explorer",
"editor.keyboardShortcuts.text3": "Open the Plugin Manager",
"editor.keyboardShortcuts.text4": "Compile the current contract & Run an associated script",
"editor.editorKeyboardShortcuts": "Editor Keyboard Shortcuts",
"editor.editorKeyboardShortcuts.text1": "Format the code in the current file",
"editor.importantLinks": "Important Links",
"editor.importantLinks.text1": "Official website about the Remix Project",
"editor.importantLinks.text2": "Official documentation",
"editor.title1": "Pasted Code Alert",
"editor.title1.message1": "You have just pasted a code snippet or contract in the editor.",
"editor.title1.message2": "Make sure you fully understand this code before deploying or interacting with it. Don't get scammed!",
"editor.title1.message3": "Running untrusted code can put your wallet <span> at risk </span>. In a worst-case scenario, you could <span>lose all your money</span>.",
"editor.title1.message4": "If you don't fully understand it, please don't run this code.",
"editor.title1.message5": "If you are not a smart contract developer, ask someone you trust who has the skills to determine if this code is safe to use.",
"editor.title1.message6": "See <a> these recommendations </a> for more information.",
"editor.zoomIn": "Zoom In",
"editor.zoomOut": "Zoom Out",
"editor.formatCode": "Format Code",
"editor.generateDocumentation": "Generate documentation for this function",
"editor.generateDocumentation2": "Generate documentation for the function \"{name}\"",
"editor.explainFunction": "Explain this function",
"editor.explainFunction2": "Explain the function \"{name}\"",
"editor.executeFreeFunction": "Run a free function",
"editor.executeFreeFunction2": "Run the free function \"{name}\"",
"editor.toastText1": "This can only execute free function",
"editor.toastText2": "Please go to Remix settings and activate the code editor features or wait that the current editor context is loaded.",
"editor.text": "The file is opened in <b>read-only</b> mode."
}

@ -1,7 +1,9 @@
import React, { useState, useRef, useEffect, useReducer } from 'react' // eslint-disable-line import React, { useState, useRef, useEffect, useReducer } from 'react' // eslint-disable-line
import { FormattedMessage, useIntl } from 'react-intl'
import { isArray } from 'lodash' import { isArray } from 'lodash'
import Editor, { loader, Monaco } from '@monaco-editor/react' import Editor, { loader, Monaco } from '@monaco-editor/react'
import { AlertModal } from '@remix-ui/app' import { AlertModal } from '@remix-ui/app'
import { QueryParams } from '@remix-project/remix-lib'
import { reducerActions, reducerListener, initialState } from './actions/editor' import { reducerActions, reducerListener, initialState } from './actions/editor'
import { solidityTokensProvider, solidityLanguageConfig } from './syntaxes/solidity' import { solidityTokensProvider, solidityLanguageConfig } from './syntaxes/solidity'
import { cairoTokensProvider, cairoLanguageConfig } from './syntaxes/cairo' import { cairoTokensProvider, cairoLanguageConfig } from './syntaxes/cairo'
@ -90,6 +92,18 @@ type errorMarker = {
loader.config({ paths: { vs: 'assets/js/monaco-editor/min/vs' } }) loader.config({ paths: { vs: 'assets/js/monaco-editor/min/vs' } })
const queryParams = new QueryParams()
// @ts-ignore
const queryLocale = queryParams.get().lang
const locales = {
zh: 'zh-cn',
en: '',
fr: 'fr',
it: 'it',
es: 'es'
}
loader.config({ "vs/nls": { availableLanguages: { "*": locales[queryLocale] || '' } } })
export type DecorationsReturn = { export type DecorationsReturn = {
currentDecorations: Array<string> currentDecorations: Array<string>
registeredDecorations?: Array<any> registeredDecorations?: Array<any>
@ -130,6 +144,7 @@ export interface EditorUIProps {
editorAPI: EditorAPIType editorAPI: EditorAPIType
} }
export const EditorUI = (props: EditorUIProps) => { export const EditorUI = (props: EditorUIProps) => {
const intl = useIntl()
const [, setCurrentBreakpoints] = useState({}) const [, setCurrentBreakpoints] = useState({})
const defaultEditorValue = ` const defaultEditorValue = `
\t\t\t\t\t\t\t ____ _____ __ __ ___ __ __ ___ ____ _____ \t\t\t\t\t\t\t ____ _____ __ __ ___ __ __ ___ ____ _____
@ -137,16 +152,16 @@ export const EditorUI = (props: EditorUIProps) => {
\t\t\t\t\t\t\t| |_) | | _| | |\\/| | | | \\ / | | | | | | | _| \t\t\t\t\t\t\t| |_) | | _| | |\\/| | | | \\ / | | | | | | | _|
\t\t\t\t\t\t\t| _ < | |___ | | | | | | / \\ | | | |_| | | |___ \t\t\t\t\t\t\t| _ < | |___ | | | | | | / \\ | | | |_| | | |___
\t\t\t\t\t\t\t|_| \\_\\ |_____| |_| |_| |___| /_/\\_\\ |___| |____/ |_____|\n\n \t\t\t\t\t\t\t|_| \\_\\ |_____| |_| |_| |___| /_/\\_\\ |___| |____/ |_____|\n\n
\t\t\t\t\t\t\tKeyboard Shortcuts:\n \t\t\t\t\t\t\t${intl.formatMessage({id: 'editor.keyboardShortcuts'})}:\n
\t\t\t\t\t\t\t\tCTRL + S: Compile the current contract\n \t\t\t\t\t\t\t\tCTRL + S: ${intl.formatMessage({id: 'editor.keyboardShortcuts.text1'})}\n
\t\t\t\t\t\t\t\tCTRL + Shift + F : Open the File Explorer\n \t\t\t\t\t\t\t\tCTRL + Shift + F : ${intl.formatMessage({id: 'editor.keyboardShortcuts.text2'})}\n
\t\t\t\t\t\t\t\tCTRL + Shift + A : Open the Plugin Manager\n \t\t\t\t\t\t\t\tCTRL + Shift + A : ${intl.formatMessage({id: 'editor.keyboardShortcuts.text3'})}\n
\t\t\t\t\t\t\t\tCTRL + SHIFT + S: Compile the current contract & Run an associated script\n \t\t\t\t\t\t\t\tCTRL + SHIFT + S: ${intl.formatMessage({id: 'editor.keyboardShortcuts.text4'})}\n
\t\t\t\t\t\t\tEditor Keyboard Shortcuts:\n \t\t\t\t\t\t\t${intl.formatMessage({id: 'editor.editorKeyboardShortcuts'})}:\n
\t\t\t\t\t\t\t\tCTRL + Alt + F : Format the code in the current file\n \t\t\t\t\t\t\t\tCTRL + Alt + F : ${intl.formatMessage({id: 'editor.editorKeyboardShortcuts.text1'})}\n
\t\t\t\t\t\t\tImportant Links:\n \t\t\t\t\t\t\t${intl.formatMessage({id: 'editor.importantLinks'})}:\n
\t\t\t\t\t\t\t\tOfficial website about the Remix Project: https://remix-project.org/\n \t\t\t\t\t\t\t\t${intl.formatMessage({id: 'editor.importantLinks.text1'})}: https://remix-project.org/\n
\t\t\t\t\t\t\t\tOfficial documentation: https://remix-ide.readthedocs.io/en/latest/\n \t\t\t\t\t\t\t\t${intl.formatMessage({id: 'editor.importantLinks.text2'})}: https://remix-ide.readthedocs.io/en/latest/\n
\t\t\t\t\t\t\t\tGithub: https://github.com/ethereum/remix-project\n \t\t\t\t\t\t\t\tGithub: https://github.com/ethereum/remix-project\n
\t\t\t\t\t\t\t\tGitter: https://gitter.im/ethereum/remix\n \t\t\t\t\t\t\t\tGitter: https://gitter.im/ethereum/remix\n
\t\t\t\t\t\t\t\tMedium: https://medium.com/remix-ide\n \t\t\t\t\t\t\t\tMedium: https://medium.com/remix-ide\n
@ -614,27 +629,34 @@ export const EditorUI = (props: EditorUIProps) => {
if (!pasteCodeRef.current && e && e.range && e.range.startLineNumber >= 0 && e.range.endLineNumber >= 0 && e.range.endLineNumber - e.range.startLineNumber > 10) { if (!pasteCodeRef.current && e && e.range && e.range.startLineNumber >= 0 && e.range.endLineNumber >= 0 && e.range.endLineNumber - e.range.startLineNumber > 10) {
const modalContent: AlertModal = { const modalContent: AlertModal = {
id: 'newCodePasted', id: 'newCodePasted',
title: 'Pasted Code Alert', title: intl.formatMessage({id: 'editor.title1'}),
message: ( message: (
<div> <div>
{' '} {' '}
<i className="fas fa-exclamation-triangle text-danger mr-1"></i> <i className="fas fa-exclamation-triangle text-danger mr-1"></i>
You have just pasted a code snippet or contract in the editor. <FormattedMessage id="editor.title1.message1" />
<div> <div>
Make sure you fully understand this code before deploying or interacting with it. Don't get scammed! <FormattedMessage id="editor.title1.message2" />
<div className="mt-2">
<FormattedMessage id="editor.title1.message3" values={{span: (chunks) => <span className="text-warning">{chunks}</span>}} />
</div>
<div className="text-warning mt-2">
<FormattedMessage id="editor.title1.message4" />
</div>
<div className="mt-2"> <div className="mt-2">
Running untrusted code can put your wallet <span className="text-warning"> at risk </span>. In a worst-case scenario, you could{' '} <FormattedMessage id="editor.title1.message5" />
<span className="text-warning">lose all your money</span>.
</div> </div>
<div className="text-warning mt-2">If you don't fully understand it, please don't run this code.</div>
<div className="mt-2">If you are not a smart contract developer, ask someone you trust who has the skills to determine if this code is safe to use.</div>
<div className="mt-2"> <div className="mt-2">
See{' '} <FormattedMessage
<a target="_blank" href="https://remix-ide.readthedocs.io/en/latest/security.html"> id="editor.title1.message6"
{' '} values={{
these recommendations{' '} a: (chunks) => (
</a>{' '} <a target="_blank" href="https://remix-ide.readthedocs.io/en/latest/security.html">
for more information. {chunks}
</a>
),
}}
/>
</div> </div>
</div> </div>
</div> </div>
@ -648,7 +670,7 @@ export const EditorUI = (props: EditorUIProps) => {
// add context menu items // add context menu items
const zoominAction = { const zoominAction = {
id: 'zoomIn', id: 'zoomIn',
label: 'Zoom In', label: intl.formatMessage({id: 'editor.zoomIn'}),
contextMenuOrder: 0, // choose the order contextMenuOrder: 0, // choose the order
contextMenuGroupId: 'zooming', // create a new grouping contextMenuGroupId: 'zooming', // create a new grouping
keybindings: [ keybindings: [
@ -661,7 +683,7 @@ export const EditorUI = (props: EditorUIProps) => {
} }
const zoomOutAction = { const zoomOutAction = {
id: 'zoomOut', id: 'zoomOut',
label: 'Zoom Out', label: intl.formatMessage({id: 'editor.zoomOut'}),
contextMenuOrder: 0, // choose the order contextMenuOrder: 0, // choose the order
contextMenuGroupId: 'zooming', // create a new grouping contextMenuGroupId: 'zooming', // create a new grouping
keybindings: [ keybindings: [
@ -674,7 +696,7 @@ export const EditorUI = (props: EditorUIProps) => {
} }
const formatAction = { const formatAction = {
id: 'autoFormat', id: 'autoFormat',
label: 'Format Code', label: intl.formatMessage({id: 'editor.formatCode'}),
contextMenuOrder: 0, // choose the order contextMenuOrder: 0, // choose the order
contextMenuGroupId: 'formatting', // create a new grouping contextMenuGroupId: 'formatting', // create a new grouping
keybindings: [ keybindings: [
@ -690,7 +712,7 @@ export const EditorUI = (props: EditorUIProps) => {
let gptGenerateDocumentationAction let gptGenerateDocumentationAction
const executeGptGenerateDocumentationAction = { const executeGptGenerateDocumentationAction = {
id: 'generateDocumentation', id: 'generateDocumentation',
label: 'Generate documentation for this function', label: intl.formatMessage({id: 'editor.generateDocumentation'}),
contextMenuOrder: 0, // choose the order contextMenuOrder: 0, // choose the order
contextMenuGroupId: 'gtp', // create a new grouping contextMenuGroupId: 'gtp', // create a new grouping
keybindings: [], keybindings: [],
@ -709,7 +731,7 @@ export const EditorUI = (props: EditorUIProps) => {
let gptExplainFunctionAction let gptExplainFunctionAction
const executegptExplainFunctionAction = { const executegptExplainFunctionAction = {
id: 'explainFunction', id: 'explainFunction',
label: 'Explain this function', label: intl.formatMessage({id: 'editor.explainFunction'}),
contextMenuOrder: 1, // choose the order contextMenuOrder: 1, // choose the order
contextMenuGroupId: 'gtp', // create a new grouping contextMenuGroupId: 'gtp', // create a new grouping
keybindings: [], keybindings: [],
@ -729,7 +751,7 @@ export const EditorUI = (props: EditorUIProps) => {
let freeFunctionAction let freeFunctionAction
const executeFreeFunctionAction = { const executeFreeFunctionAction = {
id: 'executeFreeFunction', id: 'executeFreeFunction',
label: 'Run a free function', label: intl.formatMessage({id: 'editor.executeFreeFunction'}),
contextMenuOrder: 0, // choose the order contextMenuOrder: 0, // choose the order
contextMenuGroupId: 'execute', // create a new grouping contextMenuGroupId: 'execute', // create a new grouping
precondition: 'freeFunctionCondition', precondition: 'freeFunctionCondition',
@ -746,10 +768,10 @@ export const EditorUI = (props: EditorUIProps) => {
const file = await props.plugin.call('fileManager', 'getCurrentFile') const file = await props.plugin.call('fileManager', 'getCurrentFile')
props.plugin.call('solidity-script', 'execute', file, freeFunctionNode.name) props.plugin.call('solidity-script', 'execute', file, freeFunctionNode.name)
} else { } else {
props.plugin.call('notification', 'toast', 'This can only execute free function') props.plugin.call('notification', 'toast', intl.formatMessage({id: 'editor.toastText1'}))
} }
} else { } else {
props.plugin.call('notification', 'toast', 'Please go to Remix settings and activate the code editor features or wait that the current editor context is loaded.') props.plugin.call('notification', 'toast', intl.formatMessage({id: 'editor.toastText2'}))
} }
}, },
} }
@ -787,15 +809,15 @@ export const EditorUI = (props: EditorUIProps) => {
const { nodesAtPosition } = await retrieveNodesAtPosition(props.editorAPI, props.plugin) const { nodesAtPosition } = await retrieveNodesAtPosition(props.editorAPI, props.plugin)
const freeFunctionNode = nodesAtPosition.find((node) => node.kind === 'freeFunction') const freeFunctionNode = nodesAtPosition.find((node) => node.kind === 'freeFunction')
if (freeFunctionNode) { if (freeFunctionNode) {
executeFreeFunctionAction.label = `Run the free function "${freeFunctionNode.name}"` executeFreeFunctionAction.label = intl.formatMessage({id: 'editor.executeFreeFunction2'}, {name: freeFunctionNode.name})
freeFunctionAction = editor.addAction(executeFreeFunctionAction) freeFunctionAction = editor.addAction(executeFreeFunctionAction)
} }
const functionImpl = nodesAtPosition.find((node) => node.kind === 'function') const functionImpl = nodesAtPosition.find((node) => node.kind === 'function')
if (functionImpl) { if (functionImpl) {
currentFunction.current = functionImpl.name currentFunction.current = functionImpl.name
executeGptGenerateDocumentationAction.label = `Generate documentation for the function "${functionImpl.name}"` executeGptGenerateDocumentationAction.label = intl.formatMessage({id: 'editor.generateDocumentation2'}, {name: functionImpl.name})
gptGenerateDocumentationAction = editor.addAction(executeGptGenerateDocumentationAction) gptGenerateDocumentationAction = editor.addAction(executeGptGenerateDocumentationAction)
executegptExplainFunctionAction.label = `Explain the function "${functionImpl.name}"` executegptExplainFunctionAction.label = intl.formatMessage({id: 'editor.explainFunction2'}, {name: functionImpl.name})
gptExplainFunctionAction = editor.addAction(executegptExplainFunctionAction) gptExplainFunctionAction = editor.addAction(executegptExplainFunctionAction)
} }
freeFunctionCondition.set(!!freeFunctionNode) freeFunctionCondition.set(!!freeFunctionNode)
@ -889,7 +911,12 @@ export const EditorUI = (props: EditorUIProps) => {
{editorModelsState[props.currentFile]?.readOnly && ( {editorModelsState[props.currentFile]?.readOnly && (
<span className="pl-4 h6 mb-0 w-100 alert-info position-absolute bottom-0 end-0"> <span className="pl-4 h6 mb-0 w-100 alert-info position-absolute bottom-0 end-0">
<i className="fas fa-lock-alt p-2"></i> <i className="fas fa-lock-alt p-2"></i>
The file is opened in <b>read-only</b> mode. <FormattedMessage
id="editor.text"
values={{
b: (chunks) => <b>{chunks}</b>,
}}
/>
</span> </span>
)} )}
</div> </div>

Loading…
Cancel
Save