Skip to content
Merged
Show file tree
Hide file tree
Changes from 8 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 0 additions & 24 deletions public/locales/en/translation.json

This file was deleted.

7 changes: 5 additions & 2 deletions src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ import * as ChangeFramework from './blocks/utils/change_framework'
import { mutatorOpenListener } from './blocks/mrc_param_container'
import { TOOLBOX_UPDATE_EVENT } from './blocks/mrc_mechanism_component_holder';
import { antdThemeFromString } from './reactComponents/ThemeModal';
import { useTranslation } from 'react-i18next';

/** Storage key for shown toolbox categories. */
const SHOWN_TOOLBOX_CATEGORIES_KEY = 'shownPythonToolboxCategories';
Expand Down Expand Up @@ -86,6 +87,8 @@ const LAYOUT_BACKGROUND_COLOR = '#0F0';
* project management, and user interface layout.
*/
const App: React.FC = (): React.JSX.Element => {
const { t } = useTranslation();

const [alertErrorMessage, setAlertErrorMessage] = React.useState('');
const [storage, setStorage] = React.useState<commonStorage.Storage | null>(null);
const [currentModule, setCurrentModule] = React.useState<commonStorage.Module | null>(null);
Expand All @@ -101,7 +104,6 @@ const App: React.FC = (): React.JSX.Element => {
const [rightCollapsed, setRightCollapsed] = React.useState(false);
const [theme, setTheme] = React.useState('dark');


const blocksEditor = React.useRef<editor.Editor | null>(null);
const generatorContext = React.useRef<GeneratorContext | null>(null);
const blocklyComponent = React.useRef<BlocklyComponentType | null>(null);
Expand Down Expand Up @@ -290,7 +292,8 @@ const App: React.FC = (): React.JSX.Element => {
if (blocksEditor.current) {
blocksEditor.current.loadModuleBlocks(currentModule);
}
}, [currentModule]);
}, [currentModule]);


// Initialize Blockly workspace and editor when component and storage are ready
React.useEffect(() => {
Expand Down
12 changes: 7 additions & 5 deletions src/blocks/mrc_call_python_function.ts
Original file line number Diff line number Diff line change
Expand Up @@ -421,12 +421,14 @@ const CALL_PYTHON_FUNCTION = {
returnType: this.mrcReturnType,
args: [],
};
this.mrcArgs.forEach((arg) => {
extraState.args.push({
'name': arg.name,
'type': arg.type,
if (this.mrcArgs){
this.mrcArgs.forEach((arg) => {
extraState.args.push({
'name': arg.name,
'type': arg.type,
});
});
});
}
if (this.mrcTooltip) {
extraState.tooltip = this.mrcTooltip;
}
Expand Down
14 changes: 8 additions & 6 deletions src/blocks/mrc_component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ const COMPONENT = {
this.setStyle(MRC_STYLE_COMPONENTS);
this.appendDummyInput()
.appendField(new Blockly.FieldTextInput(''), FIELD_NAME)
.appendField('of type')
.appendField(Blockly.Msg.OF_TYPE)
.appendField(createFieldNonEditableText(''), FIELD_TYPE);
this.setPreviousStatement(true, OUTPUT_NAME);
this.setNextStatement(true, OUTPUT_NAME);
Expand All @@ -82,12 +82,14 @@ const COMPONENT = {
const extraState: ComponentExtraState = {
};
extraState.params = [];
this.mrcArgs.forEach((arg) => {
extraState.params!.push({
'name': arg.name,
'type': arg.type,
if (this.mrcArgs){
this.mrcArgs.forEach((arg) => {
extraState.params!.push({
'name': arg.name,
'type': arg.type,
});
});
});
}
if (this.mrcImportModule) {
extraState.importModule = this.mrcImportModule;
}
Expand Down
4 changes: 2 additions & 2 deletions src/blocks/mrc_event_handler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,11 +65,11 @@ const EVENT_HANDLER = {
*/
init(this: EventHandlerBlock): void {
this.appendDummyInput('TITLE')
.appendField('When')
.appendField(Blockly.Msg.WHEN)
.appendField(createFieldNonEditableText('sender'), 'SENDER')
.appendField(createFieldNonEditableText('eventName'), 'EVENT_NAME');
this.appendDummyInput('PARAMS')
.appendField('with');
.appendField(Blockly.Msg.WITH);
this.setOutput(false);
this.setStyle(MRC_STYLE_EVENT_HANDLER);
this.appendStatementInput('STACK').appendField('');
Expand Down
4 changes: 2 additions & 2 deletions src/blocks/mrc_get_parameter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ const GET_PARAMETER_BLOCK = {
init: function(this: GetParameterBlock): void {
this.setStyle(MRC_STYLE_VARIABLES);
this.appendDummyInput()
.appendField('parameter')
.appendField(Blockly.Msg.PARAMETER)
.appendField(createFieldNonEditableText('parameter'), 'PARAMETER_NAME');

this.setOutput(true, this.parameterType);
Expand Down Expand Up @@ -89,7 +89,7 @@ const GET_PARAMETER_BLOCK = {
}
// If we end up here it shouldn't be allowed
block.unplug(true);
blockBlock.setWarningText('Parameters can only go in their method\'s block.');
blockBlock.setWarningText(Blockly.Msg.PARAMETERS_CAN_ONLY_GO_IN_THEIR_METHODS_BLOCK);
}
},
};
Expand Down
2 changes: 1 addition & 1 deletion src/blocks/mrc_mechanism.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ const MECHANISM = {
this.setStyle(MRC_STYLE_MECHANISMS);
this.appendDummyInput()
.appendField(new Blockly.FieldTextInput('my_mech'), 'NAME')
.appendField('of type')
.appendField(Blockly.Msg.OF_TYPE)
.appendField(createFieldNonEditableText(''), 'TYPE');
this.setPreviousStatement(true, OUTPUT_NAME);
this.setNextStatement(true, OUTPUT_NAME);
Expand Down
6 changes: 3 additions & 3 deletions src/blocks/mrc_mechanism_component_holder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -72,9 +72,9 @@ const MECHANISM_COMPONENT_HOLDER = {
*/
init: function (this: MechanismComponentHolderBlock): void {
this.setInputsInline(false);
this.appendStatementInput('MECHANISMS').setCheck(MECHANISM_OUTPUT).appendField('Mechanisms');
this.appendStatementInput('COMPONENTS').setCheck(COMPONENT_OUTPUT).appendField('Components');
this.appendStatementInput('EVENTS').setCheck(EVENT_OUTPUT).appendField('Events');
this.appendStatementInput('MECHANISMS').setCheck(MECHANISM_OUTPUT).appendField(Blockly.Msg.MECHANISMS);
this.appendStatementInput('COMPONENTS').setCheck(COMPONENT_OUTPUT).appendField(Blockly.Msg.COMPONENTS);
this.appendStatementInput('EVENTS').setCheck(EVENT_OUTPUT).appendField(Blockly.Msg.EVENTS);


this.setOutput(false);
Expand Down
5 changes: 2 additions & 3 deletions src/blocks/mrc_misc_evaluate_but_ignore_result.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,14 +31,13 @@ export const setup = function() {
Blockly.Blocks[BLOCK_NAME] = {
init: function() {
this.appendValueInput('VALUE')
.appendField('evaluate but ignore result')
.appendField(Blockly.Msg.EVALUATE_BUT_IGNORE_RESULT)
.setAlign(Blockly.inputs.Align.RIGHT);
this.setPreviousStatement(true);
this.setNextStatement(true);
this.setStyle(MRC_STYLE_MISC);
this.setTooltip(
'Executes the connected block and ignores the result. ' +
'Allows you to call a function and ignore the return value.');
Blockly.Msg.EVALUATE_BUT_IGNORE_RESULT_TOOLTIP);
},
};
};
Expand Down
19 changes: 10 additions & 9 deletions src/blocks/mrc_opmode_details.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,23 +61,24 @@ const OPMODE_DETAILS = {
init: function (this: OpmodeDetailsBlock): void {
this.setStyle(MRC_STYLE_CLASS_BLOCKS);
this.appendDummyInput()
.appendField('Type')
.appendField(createFieldDropdown(['Auto', 'Teleop', 'Test']), 'TYPE')
.appendField(Blockly.Msg.TYPE)
// These aren't Blockly.Msg because they need to match the Python generator's expected values.
.appendField(createFieldDropdown(["Auto", "Teleop", "Test"]), 'TYPE')
.appendField(' ')
.appendField('Enabled')
.appendField(Blockly.Msg.ENABLED)
.appendField(new Blockly.FieldCheckbox(true), 'ENABLED');

this.appendDummyInput()
.appendField('Display Name')
.appendField(Blockly.Msg.DISPLAY_NAME)
.appendField(new Blockly.FieldTextInput(''), 'NAME')
this.appendDummyInput()
.appendField('Display Group')
.appendField(Blockly.Msg.DISPLAY_GROUP)
.appendField(new Blockly.FieldTextInput(''), 'GROUP');

this.getField('TYPE')?.setTooltip('What sort of OpMode this is');
this.getField('ENABLED')?.setTooltip('Whether the OpMode is shown on Driver Station');
this.getField('NAME')?.setTooltip('The name shown on the Driver Station. If blank will use the class name.');
this.getField('GROUP')?.setTooltip('An optional group to group OpModes on Driver Station');
this.getField('TYPE')?.setTooltip(Blockly.Msg.OPMODE_TYPE_TOOLTIP);
this.getField('ENABLED')?.setTooltip(Blockly.Msg.OPMODE_ENABLED_TOOLTIP);
this.getField('NAME')?.setTooltip(Blockly.Msg.OPMODE_NAME_TOOLTIP);
this.getField('GROUP')?.setTooltip(Blockly.Msg.OPMODE_GROUP_TOOLTIP);
},
}

Expand Down
31 changes: 31 additions & 0 deletions src/blocks/tokens.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import * as Blockly from 'blockly/core';
import { M } from 'vitest/dist/chunks/reporters.d.BFLkQcL6.js';

export const customTokens = (t: (key: string) => string): typeof Blockly.Msg => {
return {
ADD_COMMENT: t('BLOCKLY.ADD_COMMENT'),
REMOVE_COMMENT: t('BLOCKLY.REMOVE_COMMENT'),
DUPLICATE_COMMENT: t('BLOCKLY.DUPLICATE_COMMENT'),
OF_TYPE: t('BLOCKLY.OF_TYPE'),
WITH: t('BLOCKLY.WITH'),
WHEN: t('BLOCKLY.WHEN'),
PARAMETER: t('BLOCKLY.PARAMETER'),
PARAMETERS_CAN_ONLY_GO_IN_THEIR_METHODS_BLOCK: t('BLOCKLY.PARAMETERS_CAN_ONLY_GO_IN_THEIR_METHODS_BLOCK'),
MECHANISMS: t('BLOCKLY.MECHANISMS'),
COMPONENTS: t('BLOCKLY.COMPONENTS'),
EVENTS: t('BLOCKLY.EVENTS'),
EVALUATE_BUT_IGNORE_RESULT: t('BLOCKLY.EVALUATE_BUT_IGNORE_RESULT'),
EVALUATE_BUT_IGNORE_RESULT_TOOLTIP: t('BLOCKLY.EVALUATE_BUT_IGNORE_RESULT_TOOLTIP'),
AUTO: t('BLOCKLY.AUTO'),
TELEOP: t('BLOCKLY.TELEOP'),
TEST: t('BLOCKLY.TEST'),
TYPE: t('BLOCKLY.TYPE'),
ENABLED: t('BLOCKLY.ENABLED'),
DISPLAY_NAME: t('BLOCKLY.DISPLAY_NAME'),
DISPLAY_GROUP: t('BLOCKLY.DISPLAY_GROUP'),
OPMODE_TYPE_TOOLTIP: t('BLOCKLY.TOOLTIP.OPMODE_TYPE_TOOLTIP'),
OPMODE_ENABLED_TOOLTIP: t('BLOCKLY.TOOLTIP.OPMODE_ENABLED_TOOLTIP'),
OPMODE_NAME_TOOLTIP: t('BLOCKLY.TOOLTIP.OPMODE_NAME_TOOLTIP'),
OPMODE_GROUP_TOOLTIP: t('BLOCKLY.TOOLTIP.OPMODE_GROUP_TOOLTIP'),
};
};
59 changes: 59 additions & 0 deletions src/i18n/locales/en/translation.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
{
"mechanism_delete": "Delete Mechanism",
"mechanism_rename": "Rename Mechanism",
"mechanism_copy": "Copy Mechanism",
"opmode_delete": "Delete OpMode",
"opmode_rename": "Rename OpMode",
"opmode_copy": "Copy OpMode",
"project_delete": "Delete Project",
"project_rename": "Rename Project",
"project_copy": "Copy Project",
"fail_list_projects": "Failed to load the list of projects.",
"mechanism": "Mechanism",
"opmode": "OpMode",
"class_rule_description": "No spaces are allowed in the name. Each word in the name should start with a capital letter.",
"example_mechanism": "For example: GamePieceShooter",
"example_opmode": "For example: AutoParkAndShoot",
"example_project": "For example: WackyWheelerRobot",
"addTabDialog": {
"title": "Add Tab",
"newItemPlaceholder": "Add Module",
"search": "Search..."
},
"PROJECT": "Project",
"SAVE": "Save",
"DEPLOY": "Deploy",
"MANAGE": "Manage",
"EXPLORER": "Explorer",
"ROBOT": "Robot",
"SETTINGS": "Settings",
"WPI_TOOLBOX": "WPI Toolbox",
"THEME": "Theme",
"LANGUAGE": "Language",
"ENGLISH": "English",
"SPANISH": "Spanish",
"HELP": "Help",
"ABOUT": "About",
"BLOCKLY":{
"OF_TYPE": "of type",
"WITH": "with",
"WHEN": "when",
"PARAMETER": "parameter",
"PARAMETERS_CAN_ONLY_GO_IN_THEIR_METHODS_BLOCK": "Parameters can only go in their method's block",
"MECHANISMS": "Mechanisms",
"COMPONENTS": "Components",
"EVENTS": "Events",
"EVALUATE_BUT_IGNORE_RESULT": "evaluate but ignore result",
"TYPE": "Type",
"ENABLED": "Enabled",
"DISPLAY_NAME": "Display Name",
"DISPLAY_GROUP": "Display Group",
"TOOLTIP":{
"EVALUATE_BUT_IGNORE_RESULT": "Executes the connected block and ignores the result. Allows you to call a function and ignore the return value.",
"OPMODE_TYPE": "What sort of OpMode this is",
"OPMODE_ENABLED": "Whether the OpMode is shown on Driver Station",
"OPMODE_NAME": "The name shown on the Driver Station. If blank will use the class name.",
"OPMODE_GROUP": "An optional group to group OpModes on Driver Station"
}
}
}
59 changes: 59 additions & 0 deletions src/i18n/locales/es/translation.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
{
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Did you write these strings? Do you speak Spanish?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I had Copilot (Claude 4 Sonnet) translate for me.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you add a comment that says we should have a native Spanish speaker check these?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since JSON doesn't allow comments, I put a key:value pair at the top that was "TODO" and a note. How is that?

"mechanism_delete": "Eliminar Mecanismo",
"mechanism_rename": "Renombrar Mecanismo",
"mechanism_copy": "Copiar Mecanismo",
"opmode_delete": "Eliminar OpMode",
"opmode_rename": "Renombrar OpMode",
"opmode_copy": "Copiar OpMode",
"project_delete": "Eliminar Proyecto",
"project_rename": "Renombrar Proyecto",
"project_copy": "Copiar Proyecto",
"fail_list_projects": "Error al cargar la lista de proyectos.",
"mechanism": "Mecanismo",
"opmode": "OpMode",
"class_rule_description": "No se permiten espacios en el nombre. Cada palabra en el nombre debe comenzar con una letra mayúscula.",
"example_mechanism": "Por ejemplo: DisparadorDePiezas",
"example_opmode": "Por ejemplo: AutoEstacionarYDisparar",
"example_project": "Por ejemplo: RobotRuedasLocas",
"PROJECT": "Proyecto",
"SAVE": "Guardar",
"DEPLOY": "Desplegar",
"MANAGE": "Gestionar",
"EXPLORER": "Explorador",
"ROBOT": "Robot",
"SETTINGS": "Configuración",
"WPI_TOOLBOX": "Caja de Herramientas WPI",
"THEME": "Tema",
"LANGUAGE": "Idioma",
"ENGLISH": "Inglés",
"SPANISH": "Español",
"HELP": "Ayuda",
"ABOUT": "Acerca de",
"addTabDialog": {
"title": "Agregar Pestaña",
"newItemPlaceholder": "Agregar Módulo",
"search": "Buscar..."
},
"BLOCKLY":{
"OF_TYPE": "de tipo",
"WITH": "con",
"WHEN": "cuando",
"PARAMETER": "parámetro",
"PARAMETERS_CAN_ONLY_GO_IN_THEIR_METHODS_BLOCK": "Los parámetros solo pueden ir en el bloque de su método",
"MECHANISMS": "Mecanismos",
"COMPONENTS": "Componentes",
"EVENTS": "Eventos",
"EVALUATE_BUT_IGNORE_RESULT": "evaluar pero ignorar resultado",
"TYPE": "Tipo",
"ENABLED": "Habilitado",
"DISPLAY_NAME": "Nombre a Mostrar",
"DISPLAY_GROUP": "Grupo a Mostrar",
"TOOLTIP":{
"EVALUATE_BUT_IGNORE_RESULT": "Ejecuta el bloque conectado e ignora el resultado. Te permite llamar una función e ignorar el valor de retorno.",
"OPMODE_TYPE": "Qué tipo de OpMode es este",
"OPMODE_ENABLED": "Si el OpMode se muestra en la Estación del Conductor",
"OPMODE_NAME": "El nombre mostrado en la Estación del Conductor. Si está en blanco usará el nombre de la clase.",
"OPMODE_GROUP": "Un grupo opcional para agrupar OpModes en la Estación del Conductor"
}
}
}
Loading