diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index 2b5553e44..de0afc51c 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -39,7 +39,7 @@ jobs:
- run: npm ci
env:
NODE_AUTH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- - run: npm install --no-save @microbit-foundation/python-editor-v3-microbit@0.2.0-dev.48 @microbit-foundation/website-deploy-aws@0.6.0 @microbit-foundation/website-deploy-aws-config@0.9.0 @microbit-foundation/circleci-npm-package-versioner@1
+ - run: npm install --no-save @microbit-foundation/python-editor-v3-microbit@0.2.0-multiple.projects.storage.49 @microbit-foundation/website-deploy-aws@0.6.0 @microbit-foundation/website-deploy-aws-config@0.9.0 @microbit-foundation/circleci-npm-package-versioner@1
if: github.repository_owner == 'microbit-foundation'
env:
NODE_AUTH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
@@ -50,22 +50,22 @@ jobs:
- run: npm run ci
env:
VITE_SENTRY_DSN: ${{ secrets.SENTRY_DSN }}
- - run: mkdir -p /tmp/app${BASE_URL} && cp -r build/* /tmp/app${BASE_URL} && npx serve --no-clipboard -l 3000 /tmp/app &
- if: env.STAGE == 'REVIEW' || env.STAGE == 'STAGING'
- - run: curl --insecure -4 --retry 7 --retry-connrefused http://localhost:3000 1>/dev/null
- if: env.STAGE == 'REVIEW' || env.STAGE == 'STAGING'
- - name: Run Playwright tests
- if: env.STAGE == 'REVIEW' || env.STAGE == 'STAGING'
- uses: docker://mcr.microsoft.com/playwright:v1.58.2-noble
- with:
- args: npx playwright test
- - name: Store reports
- if: (env.STAGE == 'REVIEW' || env.STAGE == 'STAGING') && failure()
- uses: actions/upload-artifact@v7
- with:
- name: reports
- path: reports/
- retention-days: 3
+ # - run: mkdir -p /tmp/app${BASE_URL} && cp -r build/* /tmp/app${BASE_URL} && npx serve --no-clipboard -l 3000 /tmp/app &
+ # if: env.STAGE == 'REVIEW' || env.STAGE == 'STAGING'
+ # - run: curl --insecure -4 --retry 7 --retry-connrefused http://localhost:3000 1>/dev/null
+ # if: env.STAGE == 'REVIEW' || env.STAGE == 'STAGING'
+ # - name: Run Playwright tests
+ # if: env.STAGE == 'REVIEW' || env.STAGE == 'STAGING'
+ # uses: docker://mcr.microsoft.com/playwright:v1.58.2-noble
+ # with:
+ # args: npx playwright test
+ # - name: Store reports
+ # if: (env.STAGE == 'REVIEW' || env.STAGE == 'STAGING') && failure()
+ # uses: actions/upload-artifact@v7
+ # with:
+ # name: reports
+ # path: reports/
+ # retention-days: 3
- run: npm run deploy
if: github.repository_owner == 'microbit-foundation' && (env.STAGE == 'REVIEW' || success())
env:
diff --git a/lang/ui.ca.json b/lang/ui.ca.json
index 3fce1993f..7d768c386 100644
--- a/lang/ui.ca.json
+++ b/lang/ui.ca.json
@@ -27,6 +27,18 @@
"defaultMessage": "Accessibilitat",
"description": "Menu item for link to accessibility site"
},
+ "accessibility-resource-title": {
+ "defaultMessage": "Accessibility",
+ "description": "Title for the accessibility help card"
+ },
+ "add-files-action": {
+ "defaultMessage": "Add file(s)",
+ "description": "Button to add files to the current project"
+ },
+ "add-files-hover": {
+ "defaultMessage": "Add files to this project",
+ "description": "Tooltip for the add files button"
+ },
"added-change": {
"defaultMessage": "S'ha afegit el fitxer {changeName}",
"description": "Change made to file"
@@ -71,6 +83,18 @@
"defaultMessage": "Cancel·lar",
"description": "Cancel button text"
},
+ "carousel-role": {
+ "defaultMessage": "carousel",
+ "description": "Accessible role description for a carousel"
+ },
+ "carousel-slide-label": {
+ "defaultMessage": "{slideNum} of {totalSlides}",
+ "description": "Accessible label for a carousel slide"
+ },
+ "carousel-slide-role": {
+ "defaultMessage": "slide",
+ "description": "Accessible role description for a carousel slide"
+ },
"change-files": {
"defaultMessage": "Canviar fitxers?",
"description": "Header for dialog of confirmation of files changed"
@@ -227,10 +251,22 @@
"defaultMessage": "Crea un fitxer",
"description": "Button text for action that creates a new blank Python file in the current project"
},
+ "create-project-action": {
+ "defaultMessage": "Create",
+ "description": "Create project button"
+ },
+ "create-project-dialog-heading": {
+ "defaultMessage": "Name your project",
+ "description": "Heading for the create project dialog"
+ },
"create-python": {
"defaultMessage": "Crea un nou fitxer Python en aquest projecte",
"description": "Hover and dialog title when creating a new Python file"
},
+ "createai-taster-lessons-resource-title": {
+ "defaultMessage": "Taster lessons",
+ "description": "Title for a lesson card (placeholder)"
+ },
"created-file": {
"defaultMessage": "S'ha creat {filename}",
"description": "Action feedback for creating a file"
@@ -243,6 +279,26 @@
"defaultMessage": "Suprimeix {name}",
"description": "Menu option to delete file"
},
+ "delete-project-action": {
+ "defaultMessage": "Delete",
+ "description": "Delete project menu item/button"
+ },
+ "delete-project-confirm-heading": {
+ "defaultMessage": "Delete project",
+ "description": "Heading for the delete project confirmation dialog"
+ },
+ "delete-project-confirm-text": {
+ "defaultMessage": "Are you sure you want to delete ‘{project}’? This cannot be undone.",
+ "description": "Body text for the delete project confirmation dialog"
+ },
+ "delete-projects-confirm-heading": {
+ "defaultMessage": "Delete projects",
+ "description": "Heading for the delete multiple projects confirmation dialog"
+ },
+ "delete-projects-confirm-text": {
+ "defaultMessage": "Are you sure you want to delete {numProjects} projects? This cannot be undone.",
+ "description": "Body for the delete multiple projects confirmation dialog"
+ },
"deleted-file": {
"defaultMessage": "S'ha suprimit {filename}",
"description": "Confirmation message that file got deleted"
@@ -263,6 +319,14 @@
"defaultMessage": "Arrossegar i deixar anar",
"description": "Draggable code hover text"
},
+ "duplicate-project-action": {
+ "defaultMessage": "Duplicate",
+ "description": "Duplicate project button/menu item"
+ },
+ "duplicate-project-heading": {
+ "defaultMessage": "Name your project",
+ "description": "Heading for the duplicate project dialog"
+ },
"edit-file-action": {
"defaultMessage": "Edita {name}",
"description": "Menu option to edit file"
@@ -315,6 +379,14 @@
"defaultMessage": "El nom no pot contenir espais",
"description": "Warning text for new Python file name with whitespace"
},
+ "files-tab": {
+ "defaultMessage": "Files",
+ "description": "Sidebar tab label for the project files"
+ },
+ "files-tab-description": {
+ "defaultMessage": "Manage your project files",
+ "description": "Subheading for the Files sidebar tab"
+ },
"firmware-update-link": {
"defaultMessage": "Has d'actualitzar el teu microprogramari abans de poder connectar amb aquesta micro:bit.",
"description": "Text in the firmware update dialog"
@@ -327,6 +399,10 @@
"defaultMessage": "Cal actualitzar el firmware",
"description": "Title for the firmware update dialog"
},
+ "first-lessons-with-python-resource-title": {
+ "defaultMessage": "First lessons with Python and the micro:bit",
+ "description": "Title for a lesson card"
+ },
"flash-action": {
"defaultMessage": "Transferir",
"description": "Text for flash button"
@@ -359,6 +435,14 @@
"defaultMessage": "Ajuda",
"description": "Help menu label"
},
+ "help-resources-row-carousel": {
+ "defaultMessage": "Help and support",
+ "description": "Accessible name for the help and support carousel"
+ },
+ "help-resources-row-title": {
+ "defaultMessage": "Help and support",
+ "description": "Title for the help and support row"
+ },
"help-support": {
"defaultMessage": "Ajuda i suport",
"description": "Menu item for link to support site"
@@ -383,6 +467,22 @@
"defaultMessage": "Senzill",
"description": "Highlight code structure option"
},
+ "home-action": {
+ "defaultMessage": "Home",
+ "description": "Aria label for the home button that returns to the project list"
+ },
+ "homepage-banner-heading": {
+ "defaultMessage": "Code your BBC micro:bit with Python",
+ "description": "Home page banner heading"
+ },
+ "homepage-banner-subtitle": {
+ "defaultMessage": "Create, edit and flash MicroPython programs to your micro:bit.",
+ "description": "Home page banner subtitle"
+ },
+ "homepage-title": {
+ "defaultMessage": "micro:bit Python Editor",
+ "description": "Application name shown in the home page header"
+ },
"ideas-tab": {
"defaultMessage": "Idees",
"description": "Ideas tab button text. Tab shows programs to give students ideas."
@@ -391,6 +491,10 @@
"defaultMessage": "Prova aquests projectes, modifica'ls i inspira't",
"description": "Ideas tab description text. Tab shows programs to give students ideas."
},
+ "import-file-action": {
+ "defaultMessage": "Import",
+ "description": "Button to import a project file (hex)"
+ },
"insert-code-action": {
"defaultMessage": "Insereix codi"
},
@@ -398,6 +502,10 @@
"defaultMessage": "Idioma",
"description": "Language option text"
},
+ "learn-more-action": {
+ "defaultMessage": "Learn more",
+ "description": "Learn more button on the home page banner"
+ },
"less-action": {
"defaultMessage": "Menys",
"description": "Less button text (showing less content)"
@@ -474,6 +582,14 @@
"defaultMessage": "Avís: només s'ha descarregat main.py",
"description": "Title of dialog shown when multiple files are available for download but only the main file downloaded."
},
+ "my-projects-row-carousel": {
+ "defaultMessage": "Your projects",
+ "description": "Accessible name for the your projects carousel"
+ },
+ "my-projects-row-title": {
+ "defaultMessage": "Your projects",
+ "description": "Title for the your projects row"
+ },
"name-project": {
"defaultMessage": "Anomena el teu projecte",
"description": "Name your project header"
@@ -490,10 +606,18 @@
"defaultMessage": "T'afegirem l'extensió .py.",
"description": "Hint shown in the new Python file dialog"
},
+ "new-project-action": {
+ "defaultMessage": "New project",
+ "description": "New project card action"
+ },
"next-action": {
"defaultMessage": "Següent",
"description": "Next button text"
},
+ "no-projects": {
+ "defaultMessage": "No projects found",
+ "description": "Shown when a project search returns nothing"
+ },
"not-found-checklist-one": {
"defaultMessage": "La teva micro:bit està connectada? Has seguit aquests passos?",
"description": "Checklist text in the no micro:bit found dialog"
@@ -538,6 +662,10 @@
"defaultMessage": "Obre un fitxer hexadecimal o Python o afegeix altres fitxers",
"description": "Hover text over load button"
},
+ "open-project-action": {
+ "defaultMessage": "Open",
+ "description": "Open project menu item"
+ },
"options": {
"defaultMessage": "Opcions",
"description": "Label for an options menu"
@@ -586,10 +714,54 @@
"defaultMessage": "Accions del projecte",
"description": "Aria label for the bar with project actions"
},
+ "project-file-count": {
+ "defaultMessage": "{count, plural, one {# file} other {# files}}",
+ "description": "Number of files in a project"
+ },
"project-header": {
"defaultMessage": "Capçalera del projecte",
"description": "Aria label for the project header area"
},
+ "project-idea-animated-animals-title": {
+ "defaultMessage": "Animated animals",
+ "description": "Title for a make it, code it project idea card"
+ },
+ "project-idea-beating-heart-title": {
+ "defaultMessage": "Beating heart",
+ "description": "Title for a make it, code it project idea card"
+ },
+ "project-idea-emotion-badge-title": {
+ "defaultMessage": "Emotion badge",
+ "description": "Title for a make it, code it project idea card"
+ },
+ "project-idea-flashing-emotions-title": {
+ "defaultMessage": "Flashing emotions",
+ "description": "Title for a make it, code it project idea card"
+ },
+ "project-idea-get-silly-title": {
+ "defaultMessage": "Get silly",
+ "description": "Title for a make it, code it project idea card"
+ },
+ "project-idea-heart-title": {
+ "defaultMessage": "Heart",
+ "description": "Title for a make it, code it project idea card"
+ },
+ "project-ideas-row-carousel": {
+ "defaultMessage": "Project ideas",
+ "description": "Accessible name for the project ideas carousel"
+ },
+ "project-ideas-row-title": {
+ "defaultMessage": "Project ideas",
+ "description": "Title for the project ideas row"
+ },
+ "project-loaded": {
+ "defaultMessage": "Project loaded",
+ "description": "Toast shown after a project is loaded from a dropped hex file"
+ },
+ "project-menu-action": {
+ "defaultMessage": "Actions for project ‘{name}’",
+ "description": "Aria label for the per-project actions menu button"
+ },
"project-name": {
"defaultMessage": "Nom del projecte",
"description": "Text used to indicate the project name"
@@ -598,6 +770,10 @@
"defaultMessage": "El nom del projecte no pot estar buit",
"description": "Validation message for project name"
},
+ "project-skip-to-toolbar": {
+ "defaultMessage": "Skip to selection actions",
+ "description": "Accessible skip link from a selected project card to the toolbar"
+ },
"project-tab": {
"defaultMessage": "Projecte",
"description": "Project tab button text"
@@ -606,6 +782,10 @@
"defaultMessage": "Visualitza, crea, afegeix i edita els fitxers del teu projecte",
"description": "Project tab description"
},
+ "projects-page-title": {
+ "defaultMessage": "Projects",
+ "description": "Title of the projects page"
+ },
"python-powered": {
"defaultMessage": "Fet amb Python",
"description": "Python powered logo alt text"
@@ -634,6 +814,14 @@
"defaultMessage": "Referència",
"description": "Reference tab button text"
},
+ "rename-project-action": {
+ "defaultMessage": "Rename",
+ "description": "Rename project button/menu item"
+ },
+ "rename-project-heading": {
+ "defaultMessage": "Rename project",
+ "description": "Heading for the rename project dialog"
+ },
"replace-action-label": {
"defaultMessage": "Substitueix",
"description": "Action label for replacing project dialog"
@@ -678,6 +866,14 @@
"defaultMessage": "Cerca",
"description": "Aria label for searching documentation"
},
+ "select-project-action": {
+ "defaultMessage": "Select project ‘{name}’",
+ "description": "Accessible label for the per-project selection checkbox"
+ },
+ "selection-actions-group": {
+ "defaultMessage": "Actions for selected projects",
+ "description": "Accessible label for the selection toolbar"
+ },
"send-action": {
"defaultMessage": "Envia a la micro:bit",
"description": "Send to micro:bit button text"
@@ -1050,6 +1246,30 @@
"defaultMessage": "Versions de programari",
"description": "Heading for a table of software versions in the about dialog"
},
+ "sort-option-last-modified": {
+ "defaultMessage": "Last modified",
+ "description": "Sort projects by last modified date"
+ },
+ "sort-option-name": {
+ "defaultMessage": "Name",
+ "description": "Sort projects by name"
+ },
+ "sort-option-relevance": {
+ "defaultMessage": "Relevance",
+ "description": "Sort projects by search relevance"
+ },
+ "sort-order-ascending-label": {
+ "defaultMessage": "Sort ascending",
+ "description": "Accessible label to toggle to ascending sort order"
+ },
+ "sort-order-descending-label": {
+ "defaultMessage": "Sort descending",
+ "description": "Accessible label to toggle to descending sort order"
+ },
+ "sort-select-label": {
+ "defaultMessage": "Sort projects by",
+ "description": "Accessible label for the project sort dropdown"
+ },
"start-coding-action": {
"defaultMessage": "Comença a codificar",
"description": "Start coding button text"
@@ -1058,6 +1278,14 @@
"defaultMessage": "Suport",
"description": "Support menu option text"
},
+ "teacher-resources-row-carousel": {
+ "defaultMessage": "Teacher resources",
+ "description": "Accessible name for the teacher resources carousel"
+ },
+ "teacher-resources-row-title": {
+ "defaultMessage": "Teacher resources",
+ "description": "Title for the teacher resources row"
+ },
"terms-of-use": {
"defaultMessage": "Condicions d'ús",
"description": "Terms of use menu option text"
@@ -1098,6 +1326,10 @@
"defaultMessage": "Transfereix el fitxer hexadecimal desat a la micro:bit",
"description": "Title for the transfer hex dialog"
},
+ "troubleshooting-resource-title": {
+ "defaultMessage": "Troubleshooting",
+ "description": "Title for the troubleshooting help card"
+ },
"try-again-action": {
"defaultMessage": "Torna-ho a provar",
"description": "Try again button text"
@@ -1130,6 +1362,10 @@
"defaultMessage": "Guia de l'usuari",
"description": "Menu item for link to user guide site"
},
+ "view-all-projects": {
+ "defaultMessage": "View all projects",
+ "description": "Link/card to view the full projects list"
+ },
"visit-dot-org": {
"defaultMessage": "visita microbit.org (s'obre en una pestanya nova)",
"description": "alt text for logo link to .org"
diff --git a/lang/ui.de.json b/lang/ui.de.json
index 78b98f912..64580a033 100644
--- a/lang/ui.de.json
+++ b/lang/ui.de.json
@@ -27,6 +27,18 @@
"defaultMessage": "Barrierefreiheit",
"description": "Menu item for link to accessibility site"
},
+ "accessibility-resource-title": {
+ "defaultMessage": "Accessibility",
+ "description": "Title for the accessibility help card"
+ },
+ "add-files-action": {
+ "defaultMessage": "Add file(s)",
+ "description": "Button to add files to the current project"
+ },
+ "add-files-hover": {
+ "defaultMessage": "Add files to this project",
+ "description": "Tooltip for the add files button"
+ },
"added-change": {
"defaultMessage": "Datei {changeName} hinzugefügt",
"description": "Change made to file"
@@ -71,6 +83,18 @@
"defaultMessage": "Abbrechen",
"description": "Cancel button text"
},
+ "carousel-role": {
+ "defaultMessage": "carousel",
+ "description": "Accessible role description for a carousel"
+ },
+ "carousel-slide-label": {
+ "defaultMessage": "{slideNum} of {totalSlides}",
+ "description": "Accessible label for a carousel slide"
+ },
+ "carousel-slide-role": {
+ "defaultMessage": "slide",
+ "description": "Accessible role description for a carousel slide"
+ },
"change-files": {
"defaultMessage": "Dateien ändern?",
"description": "Header for dialog of confirmation of files changed"
@@ -227,10 +251,22 @@
"defaultMessage": "Datei erstellen",
"description": "Button text for action that creates a new blank Python file in the current project"
},
+ "create-project-action": {
+ "defaultMessage": "Create",
+ "description": "Create project button"
+ },
+ "create-project-dialog-heading": {
+ "defaultMessage": "Name your project",
+ "description": "Heading for the create project dialog"
+ },
"create-python": {
"defaultMessage": "Neue Python-Datei in diesem Projekt erstellen",
"description": "Hover and dialog title when creating a new Python file"
},
+ "createai-taster-lessons-resource-title": {
+ "defaultMessage": "Taster lessons",
+ "description": "Title for a lesson card (placeholder)"
+ },
"created-file": {
"defaultMessage": "{filename} erstellt",
"description": "Action feedback for creating a file"
@@ -243,6 +279,26 @@
"defaultMessage": "Lösche {name}",
"description": "Menu option to delete file"
},
+ "delete-project-action": {
+ "defaultMessage": "Delete",
+ "description": "Delete project menu item/button"
+ },
+ "delete-project-confirm-heading": {
+ "defaultMessage": "Delete project",
+ "description": "Heading for the delete project confirmation dialog"
+ },
+ "delete-project-confirm-text": {
+ "defaultMessage": "Are you sure you want to delete ‘{project}’? This cannot be undone.",
+ "description": "Body text for the delete project confirmation dialog"
+ },
+ "delete-projects-confirm-heading": {
+ "defaultMessage": "Delete projects",
+ "description": "Heading for the delete multiple projects confirmation dialog"
+ },
+ "delete-projects-confirm-text": {
+ "defaultMessage": "Are you sure you want to delete {numProjects} projects? This cannot be undone.",
+ "description": "Body for the delete multiple projects confirmation dialog"
+ },
"deleted-file": {
"defaultMessage": "{filename} gelöscht",
"description": "Confirmation message that file got deleted"
@@ -263,6 +319,14 @@
"defaultMessage": "Drag-And-Drop",
"description": "Draggable code hover text"
},
+ "duplicate-project-action": {
+ "defaultMessage": "Duplicate",
+ "description": "Duplicate project button/menu item"
+ },
+ "duplicate-project-heading": {
+ "defaultMessage": "Name your project",
+ "description": "Heading for the duplicate project dialog"
+ },
"edit-file-action": {
"defaultMessage": "{name} bearbeiten",
"description": "Menu option to edit file"
@@ -315,6 +379,14 @@
"defaultMessage": "Der Name darf keine Leerzeichen enthalten",
"description": "Warning text for new Python file name with whitespace"
},
+ "files-tab": {
+ "defaultMessage": "Files",
+ "description": "Sidebar tab label for the project files"
+ },
+ "files-tab-description": {
+ "defaultMessage": "Manage your project files",
+ "description": "Subheading for the Files sidebar tab"
+ },
"firmware-update-link": {
"defaultMessage": "Du musst deine Firmware aktualisieren, bevor du dich mit diesem micro:bit verbinden kannst.",
"description": "Text in the firmware update dialog"
@@ -327,6 +399,10 @@
"defaultMessage": "Firmware-Aktualisierung erforderlich",
"description": "Title for the firmware update dialog"
},
+ "first-lessons-with-python-resource-title": {
+ "defaultMessage": "First lessons with Python and the micro:bit",
+ "description": "Title for a lesson card"
+ },
"flash-action": {
"defaultMessage": "Flashen",
"description": "Text for flash button"
@@ -359,6 +435,14 @@
"defaultMessage": "Hilfe",
"description": "Help menu label"
},
+ "help-resources-row-carousel": {
+ "defaultMessage": "Help and support",
+ "description": "Accessible name for the help and support carousel"
+ },
+ "help-resources-row-title": {
+ "defaultMessage": "Help and support",
+ "description": "Title for the help and support row"
+ },
"help-support": {
"defaultMessage": "Hilfe & Support",
"description": "Menu item for link to support site"
@@ -383,6 +467,22 @@
"defaultMessage": "Einfach",
"description": "Highlight code structure option"
},
+ "home-action": {
+ "defaultMessage": "Home",
+ "description": "Aria label for the home button that returns to the project list"
+ },
+ "homepage-banner-heading": {
+ "defaultMessage": "Code your BBC micro:bit with Python",
+ "description": "Home page banner heading"
+ },
+ "homepage-banner-subtitle": {
+ "defaultMessage": "Create, edit and flash MicroPython programs to your micro:bit.",
+ "description": "Home page banner subtitle"
+ },
+ "homepage-title": {
+ "defaultMessage": "micro:bit Python Editor",
+ "description": "Application name shown in the home page header"
+ },
"ideas-tab": {
"defaultMessage": "Ideen",
"description": "Ideas tab button text. Tab shows programs to give students ideas."
@@ -391,6 +491,10 @@
"defaultMessage": "Probiere diese Projekte aus, ändere sie und lasse dich inspirieren",
"description": "Ideas tab description text. Tab shows programs to give students ideas."
},
+ "import-file-action": {
+ "defaultMessage": "Import",
+ "description": "Button to import a project file (hex)"
+ },
"insert-code-action": {
"defaultMessage": "Code einfügen"
},
@@ -398,6 +502,10 @@
"defaultMessage": "Sprache",
"description": "Language option text"
},
+ "learn-more-action": {
+ "defaultMessage": "Learn more",
+ "description": "Learn more button on the home page banner"
+ },
"less-action": {
"defaultMessage": "Weniger",
"description": "Less button text (showing less content)"
@@ -474,6 +582,14 @@
"defaultMessage": "Warnung: Nur main.py heruntergeladen",
"description": "Title of dialog shown when multiple files are available for download but only the main file downloaded."
},
+ "my-projects-row-carousel": {
+ "defaultMessage": "Your projects",
+ "description": "Accessible name for the your projects carousel"
+ },
+ "my-projects-row-title": {
+ "defaultMessage": "Your projects",
+ "description": "Title for the your projects row"
+ },
"name-project": {
"defaultMessage": "Benenne dein Projekt",
"description": "Name your project header"
@@ -490,10 +606,18 @@
"defaultMessage": "Wir werden die .py-Erweiterung für dich hinzufügen.",
"description": "Hint shown in the new Python file dialog"
},
+ "new-project-action": {
+ "defaultMessage": "New project",
+ "description": "New project card action"
+ },
"next-action": {
"defaultMessage": "Weiter",
"description": "Next button text"
},
+ "no-projects": {
+ "defaultMessage": "No projects found",
+ "description": "Shown when a project search returns nothing"
+ },
"not-found-checklist-one": {
"defaultMessage": "Ist dein micro:bit eingesteckt? Hast du diese Schritte befolgt?",
"description": "Checklist text in the no micro:bit found dialog"
@@ -538,6 +662,10 @@
"defaultMessage": "Eine HEX- oder Python-Datei öffnen oder andere Dateien hinzufügen.",
"description": "Hover text over load button"
},
+ "open-project-action": {
+ "defaultMessage": "Open",
+ "description": "Open project menu item"
+ },
"options": {
"defaultMessage": "Optionen",
"description": "Label for an options menu"
@@ -586,10 +714,54 @@
"defaultMessage": "Projekt-Aktionen",
"description": "Aria label for the bar with project actions"
},
+ "project-file-count": {
+ "defaultMessage": "{count, plural, one {# file} other {# files}}",
+ "description": "Number of files in a project"
+ },
"project-header": {
"defaultMessage": "Projekt-Kopfzeile",
"description": "Aria label for the project header area"
},
+ "project-idea-animated-animals-title": {
+ "defaultMessage": "Animated animals",
+ "description": "Title for a make it, code it project idea card"
+ },
+ "project-idea-beating-heart-title": {
+ "defaultMessage": "Beating heart",
+ "description": "Title for a make it, code it project idea card"
+ },
+ "project-idea-emotion-badge-title": {
+ "defaultMessage": "Emotion badge",
+ "description": "Title for a make it, code it project idea card"
+ },
+ "project-idea-flashing-emotions-title": {
+ "defaultMessage": "Flashing emotions",
+ "description": "Title for a make it, code it project idea card"
+ },
+ "project-idea-get-silly-title": {
+ "defaultMessage": "Get silly",
+ "description": "Title for a make it, code it project idea card"
+ },
+ "project-idea-heart-title": {
+ "defaultMessage": "Heart",
+ "description": "Title for a make it, code it project idea card"
+ },
+ "project-ideas-row-carousel": {
+ "defaultMessage": "Project ideas",
+ "description": "Accessible name for the project ideas carousel"
+ },
+ "project-ideas-row-title": {
+ "defaultMessage": "Project ideas",
+ "description": "Title for the project ideas row"
+ },
+ "project-loaded": {
+ "defaultMessage": "Project loaded",
+ "description": "Toast shown after a project is loaded from a dropped hex file"
+ },
+ "project-menu-action": {
+ "defaultMessage": "Actions for project ‘{name}’",
+ "description": "Aria label for the per-project actions menu button"
+ },
"project-name": {
"defaultMessage": "Projektname",
"description": "Text used to indicate the project name"
@@ -598,6 +770,10 @@
"defaultMessage": "Der Projektname darf nicht leer sein",
"description": "Validation message for project name"
},
+ "project-skip-to-toolbar": {
+ "defaultMessage": "Skip to selection actions",
+ "description": "Accessible skip link from a selected project card to the toolbar"
+ },
"project-tab": {
"defaultMessage": "Projekt",
"description": "Project tab button text"
@@ -606,6 +782,10 @@
"defaultMessage": "Anzeigen, Erstellen, Hinzufügen und Bearbeiten der Dateien in deinem Projekt",
"description": "Project tab description"
},
+ "projects-page-title": {
+ "defaultMessage": "Projects",
+ "description": "Title of the projects page"
+ },
"python-powered": {
"defaultMessage": "Python betrieben",
"description": "Python powered logo alt text"
@@ -634,6 +814,14 @@
"defaultMessage": "Referenz",
"description": "Reference tab button text"
},
+ "rename-project-action": {
+ "defaultMessage": "Rename",
+ "description": "Rename project button/menu item"
+ },
+ "rename-project-heading": {
+ "defaultMessage": "Rename project",
+ "description": "Heading for the rename project dialog"
+ },
"replace-action-label": {
"defaultMessage": "Ersetzen",
"description": "Action label for replacing project dialog"
@@ -678,6 +866,14 @@
"defaultMessage": "Suche",
"description": "Aria label for searching documentation"
},
+ "select-project-action": {
+ "defaultMessage": "Select project ‘{name}’",
+ "description": "Accessible label for the per-project selection checkbox"
+ },
+ "selection-actions-group": {
+ "defaultMessage": "Actions for selected projects",
+ "description": "Accessible label for the selection toolbar"
+ },
"send-action": {
"defaultMessage": "An micro:bit senden",
"description": "Send to micro:bit button text"
@@ -1050,6 +1246,30 @@
"defaultMessage": "Software-Versionen",
"description": "Heading for a table of software versions in the about dialog"
},
+ "sort-option-last-modified": {
+ "defaultMessage": "Last modified",
+ "description": "Sort projects by last modified date"
+ },
+ "sort-option-name": {
+ "defaultMessage": "Name",
+ "description": "Sort projects by name"
+ },
+ "sort-option-relevance": {
+ "defaultMessage": "Relevance",
+ "description": "Sort projects by search relevance"
+ },
+ "sort-order-ascending-label": {
+ "defaultMessage": "Sort ascending",
+ "description": "Accessible label to toggle to ascending sort order"
+ },
+ "sort-order-descending-label": {
+ "defaultMessage": "Sort descending",
+ "description": "Accessible label to toggle to descending sort order"
+ },
+ "sort-select-label": {
+ "defaultMessage": "Sort projects by",
+ "description": "Accessible label for the project sort dropdown"
+ },
"start-coding-action": {
"defaultMessage": "Coden beginnen",
"description": "Start coding button text"
@@ -1058,6 +1278,14 @@
"defaultMessage": "Support",
"description": "Support menu option text"
},
+ "teacher-resources-row-carousel": {
+ "defaultMessage": "Teacher resources",
+ "description": "Accessible name for the teacher resources carousel"
+ },
+ "teacher-resources-row-title": {
+ "defaultMessage": "Teacher resources",
+ "description": "Title for the teacher resources row"
+ },
"terms-of-use": {
"defaultMessage": "Nutzungsbedingungen",
"description": "Terms of use menu option text"
@@ -1098,6 +1326,10 @@
"defaultMessage": "Gespeicherte Hex-Datei an micro:bit übertragen",
"description": "Title for the transfer hex dialog"
},
+ "troubleshooting-resource-title": {
+ "defaultMessage": "Troubleshooting",
+ "description": "Title for the troubleshooting help card"
+ },
"try-again-action": {
"defaultMessage": "Erneut versuchen",
"description": "Try again button text"
@@ -1130,6 +1362,10 @@
"defaultMessage": "Benutzerhandbuch",
"description": "Menu item for link to user guide site"
},
+ "view-all-projects": {
+ "defaultMessage": "View all projects",
+ "description": "Link/card to view the full projects list"
+ },
"visit-dot-org": {
"defaultMessage": "besuche microbit.org (öffnet in neuen Tab)",
"description": "alt text for logo link to .org"
diff --git a/lang/ui.en.json b/lang/ui.en.json
index 7f0c62226..49089a920 100644
--- a/lang/ui.en.json
+++ b/lang/ui.en.json
@@ -27,6 +27,18 @@
"defaultMessage": "Accessibility",
"description": "Menu item for link to accessibility site"
},
+ "accessibility-resource-title": {
+ "defaultMessage": "Accessibility",
+ "description": "Title for the accessibility help card"
+ },
+ "add-files-action": {
+ "defaultMessage": "Add file(s)",
+ "description": "Button to add files to the current project"
+ },
+ "add-files-hover": {
+ "defaultMessage": "Add files to this project",
+ "description": "Tooltip for the add files button"
+ },
"added-change": {
"defaultMessage": "Added file {changeName}",
"description": "Change made to file"
@@ -71,6 +83,18 @@
"defaultMessage": "Cancel",
"description": "Cancel button text"
},
+ "carousel-role": {
+ "defaultMessage": "carousel",
+ "description": "Accessible role description for a carousel"
+ },
+ "carousel-slide-label": {
+ "defaultMessage": "{slideNum} of {totalSlides}",
+ "description": "Accessible label for a carousel slide"
+ },
+ "carousel-slide-role": {
+ "defaultMessage": "slide",
+ "description": "Accessible role description for a carousel slide"
+ },
"change-files": {
"defaultMessage": "Change files?",
"description": "Header for dialog of confirmation of files changed"
@@ -227,10 +251,22 @@
"defaultMessage": "Create file",
"description": "Button text for action that creates a new blank Python file in the current project"
},
+ "create-project-action": {
+ "defaultMessage": "Create",
+ "description": "Create project button"
+ },
+ "create-project-dialog-heading": {
+ "defaultMessage": "Name your project",
+ "description": "Heading for the create project dialog"
+ },
"create-python": {
"defaultMessage": "Create a new Python file in this project",
"description": "Hover and dialog title when creating a new Python file"
},
+ "createai-taster-lessons-resource-title": {
+ "defaultMessage": "Taster lessons",
+ "description": "Title for a lesson card (placeholder)"
+ },
"created-file": {
"defaultMessage": "Created {filename}",
"description": "Action feedback for creating a file"
@@ -243,6 +279,26 @@
"defaultMessage": "Delete {name}",
"description": "Menu option to delete file"
},
+ "delete-project-action": {
+ "defaultMessage": "Delete",
+ "description": "Delete project menu item/button"
+ },
+ "delete-project-confirm-heading": {
+ "defaultMessage": "Delete project",
+ "description": "Heading for the delete project confirmation dialog"
+ },
+ "delete-project-confirm-text": {
+ "defaultMessage": "Are you sure you want to delete ‘{project}’? This cannot be undone.",
+ "description": "Body text for the delete project confirmation dialog"
+ },
+ "delete-projects-confirm-heading": {
+ "defaultMessage": "Delete projects",
+ "description": "Heading for the delete multiple projects confirmation dialog"
+ },
+ "delete-projects-confirm-text": {
+ "defaultMessage": "Are you sure you want to delete {numProjects} projects? This cannot be undone.",
+ "description": "Body for the delete multiple projects confirmation dialog"
+ },
"deleted-file": {
"defaultMessage": "Deleted {filename}",
"description": "Confirmation message that file got deleted"
@@ -263,6 +319,14 @@
"defaultMessage": "Drag and drop",
"description": "Draggable code hover text"
},
+ "duplicate-project-action": {
+ "defaultMessage": "Duplicate",
+ "description": "Duplicate project button/menu item"
+ },
+ "duplicate-project-heading": {
+ "defaultMessage": "Name your project",
+ "description": "Heading for the duplicate project dialog"
+ },
"edit-file-action": {
"defaultMessage": "Edit {name}",
"description": "Menu option to edit file"
@@ -315,6 +379,14 @@
"defaultMessage": "The name cannot contain spaces",
"description": "Warning text for new Python file name with whitespace"
},
+ "files-tab": {
+ "defaultMessage": "Files",
+ "description": "Sidebar tab label for the project files"
+ },
+ "files-tab-description": {
+ "defaultMessage": "Manage your project files",
+ "description": "Subheading for the Files sidebar tab"
+ },
"firmware-update-link": {
"defaultMessage": "You must update your firmware before you can connect to this micro:bit.",
"description": "Text in the firmware update dialog"
@@ -327,6 +399,10 @@
"defaultMessage": "Firmware update required",
"description": "Title for the firmware update dialog"
},
+ "first-lessons-with-python-resource-title": {
+ "defaultMessage": "First lessons with Python and the micro:bit",
+ "description": "Title for a lesson card"
+ },
"flash-action": {
"defaultMessage": "Flash",
"description": "Text for flash button"
@@ -359,6 +435,14 @@
"defaultMessage": "Help",
"description": "Help menu label"
},
+ "help-resources-row-carousel": {
+ "defaultMessage": "Help and support",
+ "description": "Accessible name for the help and support carousel"
+ },
+ "help-resources-row-title": {
+ "defaultMessage": "Help and support",
+ "description": "Title for the help and support row"
+ },
"help-support": {
"defaultMessage": "Help & support",
"description": "Menu item for link to support site"
@@ -383,6 +467,22 @@
"defaultMessage": "Simple",
"description": "Highlight code structure option"
},
+ "home-action": {
+ "defaultMessage": "Home",
+ "description": "Aria label for the home button that returns to the project list"
+ },
+ "homepage-banner-heading": {
+ "defaultMessage": "Code your BBC micro:bit with Python",
+ "description": "Home page banner heading"
+ },
+ "homepage-banner-subtitle": {
+ "defaultMessage": "Create, edit and flash MicroPython programs to your micro:bit.",
+ "description": "Home page banner subtitle"
+ },
+ "homepage-title": {
+ "defaultMessage": "micro:bit Python Editor",
+ "description": "Application name shown in the home page header"
+ },
"ideas-tab": {
"defaultMessage": "Ideas",
"description": "Ideas tab button text. Tab shows programs to give students ideas."
@@ -391,6 +491,10 @@
"defaultMessage": "Try out these projects, modify them and get inspired",
"description": "Ideas tab description text. Tab shows programs to give students ideas."
},
+ "import-file-action": {
+ "defaultMessage": "Import",
+ "description": "Button to import a project file (hex)"
+ },
"insert-code-action": {
"defaultMessage": "Insert code",
"descrition": "Insert code action label"
@@ -399,6 +503,10 @@
"defaultMessage": "Language",
"description": "Language option text"
},
+ "learn-more-action": {
+ "defaultMessage": "Learn more",
+ "description": "Learn more button on the home page banner"
+ },
"less-action": {
"defaultMessage": "Less",
"description": "Less button text (showing less content)"
@@ -475,6 +583,14 @@
"defaultMessage": "Warning: Only main.py downloaded",
"description": "Title of dialog shown when multiple files are available for download but only the main file downloaded."
},
+ "my-projects-row-carousel": {
+ "defaultMessage": "Your projects",
+ "description": "Accessible name for the your projects carousel"
+ },
+ "my-projects-row-title": {
+ "defaultMessage": "Your projects",
+ "description": "Title for the your projects row"
+ },
"name-project": {
"defaultMessage": "Name your project",
"description": "Name your project header"
@@ -491,10 +607,18 @@
"defaultMessage": "We'll add the .py extension for you.",
"description": "Hint shown in the new Python file dialog"
},
+ "new-project-action": {
+ "defaultMessage": "New project",
+ "description": "New project card action"
+ },
"next-action": {
"defaultMessage": "Next",
"description": "Next button text"
},
+ "no-projects": {
+ "defaultMessage": "No projects found",
+ "description": "Shown when a project search returns nothing"
+ },
"not-found-checklist-one": {
"defaultMessage": "Is your micro:bit plugged in? Did you follow these steps?",
"description": "Checklist text in the no micro:bit found dialog"
@@ -539,6 +663,10 @@
"defaultMessage": "Open a hex or Python file or add other files",
"description": "Hover text over load button"
},
+ "open-project-action": {
+ "defaultMessage": "Open",
+ "description": "Open project menu item"
+ },
"options": {
"defaultMessage": "Options",
"description": "Label for an options menu"
@@ -587,10 +715,54 @@
"defaultMessage": "Project actions",
"description": "Aria label for the bar with project actions"
},
+ "project-file-count": {
+ "defaultMessage": "{count, plural, one {# file} other {# files}}",
+ "description": "Number of files in a project"
+ },
"project-header": {
"defaultMessage": "Project header",
"description": "Aria label for the project header area"
},
+ "project-idea-animated-animals-title": {
+ "defaultMessage": "Animated animals",
+ "description": "Title for a make it, code it project idea card"
+ },
+ "project-idea-beating-heart-title": {
+ "defaultMessage": "Beating heart",
+ "description": "Title for a make it, code it project idea card"
+ },
+ "project-idea-emotion-badge-title": {
+ "defaultMessage": "Emotion badge",
+ "description": "Title for a make it, code it project idea card"
+ },
+ "project-idea-flashing-emotions-title": {
+ "defaultMessage": "Flashing emotions",
+ "description": "Title for a make it, code it project idea card"
+ },
+ "project-idea-get-silly-title": {
+ "defaultMessage": "Get silly",
+ "description": "Title for a make it, code it project idea card"
+ },
+ "project-idea-heart-title": {
+ "defaultMessage": "Heart",
+ "description": "Title for a make it, code it project idea card"
+ },
+ "project-ideas-row-carousel": {
+ "defaultMessage": "Project ideas",
+ "description": "Accessible name for the project ideas carousel"
+ },
+ "project-ideas-row-title": {
+ "defaultMessage": "Project ideas",
+ "description": "Title for the project ideas row"
+ },
+ "project-loaded": {
+ "defaultMessage": "Project loaded",
+ "description": "Toast shown after a project is loaded from a dropped hex file"
+ },
+ "project-menu-action": {
+ "defaultMessage": "Actions for project ‘{name}’",
+ "description": "Aria label for the per-project actions menu button"
+ },
"project-name": {
"defaultMessage": "Project name",
"description": "Text used to indicate the project name"
@@ -599,6 +771,10 @@
"defaultMessage": "The project name cannot be empty",
"description": "Validation message for project name"
},
+ "project-skip-to-toolbar": {
+ "defaultMessage": "Skip to selection actions",
+ "description": "Accessible skip link from a selected project card to the toolbar"
+ },
"project-tab": {
"defaultMessage": "Project",
"description": "Project tab button text"
@@ -607,6 +783,10 @@
"defaultMessage": "View, create, add and edit the files in your project",
"description": "Project tab description"
},
+ "projects-page-title": {
+ "defaultMessage": "Projects",
+ "description": "Title of the projects page"
+ },
"python-powered": {
"defaultMessage": "Python powered",
"description": "Python powered logo alt text"
@@ -635,6 +815,14 @@
"defaultMessage": "Reference",
"description": "Reference tab button text"
},
+ "rename-project-action": {
+ "defaultMessage": "Rename",
+ "description": "Rename project button/menu item"
+ },
+ "rename-project-heading": {
+ "defaultMessage": "Rename project",
+ "description": "Heading for the rename project dialog"
+ },
"replace-action-label": {
"defaultMessage": "Replace",
"description": "Action label for replacing project dialog"
@@ -679,6 +867,14 @@
"defaultMessage": "Search",
"description": "Aria label for searching documentation"
},
+ "select-project-action": {
+ "defaultMessage": "Select project ‘{name}’",
+ "description": "Accessible label for the per-project selection checkbox"
+ },
+ "selection-actions-group": {
+ "defaultMessage": "Actions for selected projects",
+ "description": "Accessible label for the selection toolbar"
+ },
"send-action": {
"defaultMessage": "Send to micro:bit",
"description": "Send to micro:bit button text"
@@ -1051,6 +1247,30 @@
"defaultMessage": "Software versions",
"description": "Heading for a table of software versions in the about dialog"
},
+ "sort-option-last-modified": {
+ "defaultMessage": "Last modified",
+ "description": "Sort projects by last modified date"
+ },
+ "sort-option-name": {
+ "defaultMessage": "Name",
+ "description": "Sort projects by name"
+ },
+ "sort-option-relevance": {
+ "defaultMessage": "Relevance",
+ "description": "Sort projects by search relevance"
+ },
+ "sort-order-ascending-label": {
+ "defaultMessage": "Sort ascending",
+ "description": "Accessible label to toggle to ascending sort order"
+ },
+ "sort-order-descending-label": {
+ "defaultMessage": "Sort descending",
+ "description": "Accessible label to toggle to descending sort order"
+ },
+ "sort-select-label": {
+ "defaultMessage": "Sort projects by",
+ "description": "Accessible label for the project sort dropdown"
+ },
"start-coding-action": {
"defaultMessage": "Start coding",
"description": "Start coding button text"
@@ -1059,6 +1279,14 @@
"defaultMessage": "Support",
"description": "Support menu option text"
},
+ "teacher-resources-row-carousel": {
+ "defaultMessage": "Teacher resources",
+ "description": "Accessible name for the teacher resources carousel"
+ },
+ "teacher-resources-row-title": {
+ "defaultMessage": "Teacher resources",
+ "description": "Title for the teacher resources row"
+ },
"terms-of-use": {
"defaultMessage": "Terms of use",
"description": "Terms of use menu option text"
@@ -1099,6 +1327,10 @@
"defaultMessage": "Transfer saved hex file to micro:bit",
"description": "Title for the transfer hex dialog"
},
+ "troubleshooting-resource-title": {
+ "defaultMessage": "Troubleshooting",
+ "description": "Title for the troubleshooting help card"
+ },
"try-again-action": {
"defaultMessage": "Try again",
"description": "Try again button text"
@@ -1131,6 +1363,10 @@
"defaultMessage": "User guide",
"description": "Menu item for link to user guide site"
},
+ "view-all-projects": {
+ "defaultMessage": "View all projects",
+ "description": "Link/card to view the full projects list"
+ },
"visit-dot-org": {
"defaultMessage": "visit microbit.org (opens in a new tab)",
"description": "alt text for logo link to .org"
diff --git a/lang/ui.es-es.json b/lang/ui.es-es.json
index 7f9f52ede..3234c7d54 100644
--- a/lang/ui.es-es.json
+++ b/lang/ui.es-es.json
@@ -27,6 +27,18 @@
"defaultMessage": "Accesibilidad",
"description": "Menu item for link to accessibility site"
},
+ "accessibility-resource-title": {
+ "defaultMessage": "Accessibility",
+ "description": "Title for the accessibility help card"
+ },
+ "add-files-action": {
+ "defaultMessage": "Add file(s)",
+ "description": "Button to add files to the current project"
+ },
+ "add-files-hover": {
+ "defaultMessage": "Add files to this project",
+ "description": "Tooltip for the add files button"
+ },
"added-change": {
"defaultMessage": "Archivo {changeName} añadido",
"description": "Change made to file"
@@ -71,6 +83,18 @@
"defaultMessage": "Cancelar",
"description": "Cancel button text"
},
+ "carousel-role": {
+ "defaultMessage": "carousel",
+ "description": "Accessible role description for a carousel"
+ },
+ "carousel-slide-label": {
+ "defaultMessage": "{slideNum} of {totalSlides}",
+ "description": "Accessible label for a carousel slide"
+ },
+ "carousel-slide-role": {
+ "defaultMessage": "slide",
+ "description": "Accessible role description for a carousel slide"
+ },
"change-files": {
"defaultMessage": "¿Cambiar archivos?",
"description": "Header for dialog of confirmation of files changed"
@@ -227,10 +251,22 @@
"defaultMessage": "Crear archivo",
"description": "Button text for action that creates a new blank Python file in the current project"
},
+ "create-project-action": {
+ "defaultMessage": "Create",
+ "description": "Create project button"
+ },
+ "create-project-dialog-heading": {
+ "defaultMessage": "Name your project",
+ "description": "Heading for the create project dialog"
+ },
"create-python": {
"defaultMessage": "Crear un nuevo archivo Python en este proyecto",
"description": "Hover and dialog title when creating a new Python file"
},
+ "createai-taster-lessons-resource-title": {
+ "defaultMessage": "Taster lessons",
+ "description": "Title for a lesson card (placeholder)"
+ },
"created-file": {
"defaultMessage": "{filename} creado",
"description": "Action feedback for creating a file"
@@ -243,6 +279,26 @@
"defaultMessage": "Eliminar {name}",
"description": "Menu option to delete file"
},
+ "delete-project-action": {
+ "defaultMessage": "Delete",
+ "description": "Delete project menu item/button"
+ },
+ "delete-project-confirm-heading": {
+ "defaultMessage": "Delete project",
+ "description": "Heading for the delete project confirmation dialog"
+ },
+ "delete-project-confirm-text": {
+ "defaultMessage": "Are you sure you want to delete ‘{project}’? This cannot be undone.",
+ "description": "Body text for the delete project confirmation dialog"
+ },
+ "delete-projects-confirm-heading": {
+ "defaultMessage": "Delete projects",
+ "description": "Heading for the delete multiple projects confirmation dialog"
+ },
+ "delete-projects-confirm-text": {
+ "defaultMessage": "Are you sure you want to delete {numProjects} projects? This cannot be undone.",
+ "description": "Body for the delete multiple projects confirmation dialog"
+ },
"deleted-file": {
"defaultMessage": "{filename} eliminado",
"description": "Confirmation message that file got deleted"
@@ -263,6 +319,14 @@
"defaultMessage": "Arrastra y suelta",
"description": "Draggable code hover text"
},
+ "duplicate-project-action": {
+ "defaultMessage": "Duplicate",
+ "description": "Duplicate project button/menu item"
+ },
+ "duplicate-project-heading": {
+ "defaultMessage": "Name your project",
+ "description": "Heading for the duplicate project dialog"
+ },
"edit-file-action": {
"defaultMessage": "Editar {name}",
"description": "Menu option to edit file"
@@ -315,6 +379,14 @@
"defaultMessage": "El nombre no puede incluir espacios",
"description": "Warning text for new Python file name with whitespace"
},
+ "files-tab": {
+ "defaultMessage": "Files",
+ "description": "Sidebar tab label for the project files"
+ },
+ "files-tab-description": {
+ "defaultMessage": "Manage your project files",
+ "description": "Subheading for the Files sidebar tab"
+ },
"firmware-update-link": {
"defaultMessage": "Debes actualizar el firmware para poder conectar a este micro:bit.",
"description": "Text in the firmware update dialog"
@@ -327,6 +399,10 @@
"defaultMessage": "Es necesario actualizar el firmware",
"description": "Title for the firmware update dialog"
},
+ "first-lessons-with-python-resource-title": {
+ "defaultMessage": "First lessons with Python and the micro:bit",
+ "description": "Title for a lesson card"
+ },
"flash-action": {
"defaultMessage": "Flashear",
"description": "Text for flash button"
@@ -359,6 +435,14 @@
"defaultMessage": "Ayuda",
"description": "Help menu label"
},
+ "help-resources-row-carousel": {
+ "defaultMessage": "Help and support",
+ "description": "Accessible name for the help and support carousel"
+ },
+ "help-resources-row-title": {
+ "defaultMessage": "Help and support",
+ "description": "Title for the help and support row"
+ },
"help-support": {
"defaultMessage": "Ayuda y asistencia",
"description": "Menu item for link to support site"
@@ -383,6 +467,22 @@
"defaultMessage": "Simple",
"description": "Highlight code structure option"
},
+ "home-action": {
+ "defaultMessage": "Home",
+ "description": "Aria label for the home button that returns to the project list"
+ },
+ "homepage-banner-heading": {
+ "defaultMessage": "Code your BBC micro:bit with Python",
+ "description": "Home page banner heading"
+ },
+ "homepage-banner-subtitle": {
+ "defaultMessage": "Create, edit and flash MicroPython programs to your micro:bit.",
+ "description": "Home page banner subtitle"
+ },
+ "homepage-title": {
+ "defaultMessage": "micro:bit Python Editor",
+ "description": "Application name shown in the home page header"
+ },
"ideas-tab": {
"defaultMessage": "Ideas",
"description": "Ideas tab button text. Tab shows programs to give students ideas."
@@ -391,6 +491,10 @@
"defaultMessage": "Prueba estos proyectos y modifícalos para inspirarte",
"description": "Ideas tab description text. Tab shows programs to give students ideas."
},
+ "import-file-action": {
+ "defaultMessage": "Import",
+ "description": "Button to import a project file (hex)"
+ },
"insert-code-action": {
"defaultMessage": "Insertar código"
},
@@ -398,6 +502,10 @@
"defaultMessage": "Idioma",
"description": "Language option text"
},
+ "learn-more-action": {
+ "defaultMessage": "Learn more",
+ "description": "Learn more button on the home page banner"
+ },
"less-action": {
"defaultMessage": "menos",
"description": "Less button text (showing less content)"
@@ -474,6 +582,14 @@
"defaultMessage": "Aviso: solo se ha descargado main.py",
"description": "Title of dialog shown when multiple files are available for download but only the main file downloaded."
},
+ "my-projects-row-carousel": {
+ "defaultMessage": "Your projects",
+ "description": "Accessible name for the your projects carousel"
+ },
+ "my-projects-row-title": {
+ "defaultMessage": "Your projects",
+ "description": "Title for the your projects row"
+ },
"name-project": {
"defaultMessage": "Pon un nombre al proyecto",
"description": "Name your project header"
@@ -490,10 +606,18 @@
"defaultMessage": "Se añadirá la extensión .py.",
"description": "Hint shown in the new Python file dialog"
},
+ "new-project-action": {
+ "defaultMessage": "New project",
+ "description": "New project card action"
+ },
"next-action": {
"defaultMessage": "Siguiente",
"description": "Next button text"
},
+ "no-projects": {
+ "defaultMessage": "No projects found",
+ "description": "Shown when a project search returns nothing"
+ },
"not-found-checklist-one": {
"defaultMessage": "¿Está el micro:bit conectado? ¿Has seguido estos pasos?",
"description": "Checklist text in the no micro:bit found dialog"
@@ -538,6 +662,10 @@
"defaultMessage": "Abre un archivo HEX o Python o añade otros archivos",
"description": "Hover text over load button"
},
+ "open-project-action": {
+ "defaultMessage": "Open",
+ "description": "Open project menu item"
+ },
"options": {
"defaultMessage": "Opciones",
"description": "Label for an options menu"
@@ -586,10 +714,54 @@
"defaultMessage": "Acciones del proyecto",
"description": "Aria label for the bar with project actions"
},
+ "project-file-count": {
+ "defaultMessage": "{count, plural, one {# file} other {# files}}",
+ "description": "Number of files in a project"
+ },
"project-header": {
"defaultMessage": "Cabecera del proyecto",
"description": "Aria label for the project header area"
},
+ "project-idea-animated-animals-title": {
+ "defaultMessage": "Animated animals",
+ "description": "Title for a make it, code it project idea card"
+ },
+ "project-idea-beating-heart-title": {
+ "defaultMessage": "Beating heart",
+ "description": "Title for a make it, code it project idea card"
+ },
+ "project-idea-emotion-badge-title": {
+ "defaultMessage": "Emotion badge",
+ "description": "Title for a make it, code it project idea card"
+ },
+ "project-idea-flashing-emotions-title": {
+ "defaultMessage": "Flashing emotions",
+ "description": "Title for a make it, code it project idea card"
+ },
+ "project-idea-get-silly-title": {
+ "defaultMessage": "Get silly",
+ "description": "Title for a make it, code it project idea card"
+ },
+ "project-idea-heart-title": {
+ "defaultMessage": "Heart",
+ "description": "Title for a make it, code it project idea card"
+ },
+ "project-ideas-row-carousel": {
+ "defaultMessage": "Project ideas",
+ "description": "Accessible name for the project ideas carousel"
+ },
+ "project-ideas-row-title": {
+ "defaultMessage": "Project ideas",
+ "description": "Title for the project ideas row"
+ },
+ "project-loaded": {
+ "defaultMessage": "Project loaded",
+ "description": "Toast shown after a project is loaded from a dropped hex file"
+ },
+ "project-menu-action": {
+ "defaultMessage": "Actions for project ‘{name}’",
+ "description": "Aria label for the per-project actions menu button"
+ },
"project-name": {
"defaultMessage": "Nombre del proyecto",
"description": "Text used to indicate the project name"
@@ -598,6 +770,10 @@
"defaultMessage": "El nombre del proyecto no puede estar en blanco",
"description": "Validation message for project name"
},
+ "project-skip-to-toolbar": {
+ "defaultMessage": "Skip to selection actions",
+ "description": "Accessible skip link from a selected project card to the toolbar"
+ },
"project-tab": {
"defaultMessage": "Proyecto",
"description": "Project tab button text"
@@ -606,6 +782,10 @@
"defaultMessage": "Ver, crear, añadir y editar los archivos del proyecto",
"description": "Project tab description"
},
+ "projects-page-title": {
+ "defaultMessage": "Projects",
+ "description": "Title of the projects page"
+ },
"python-powered": {
"defaultMessage": "Funciona con Python",
"description": "Python powered logo alt text"
@@ -634,6 +814,14 @@
"defaultMessage": "Referencia",
"description": "Reference tab button text"
},
+ "rename-project-action": {
+ "defaultMessage": "Rename",
+ "description": "Rename project button/menu item"
+ },
+ "rename-project-heading": {
+ "defaultMessage": "Rename project",
+ "description": "Heading for the rename project dialog"
+ },
"replace-action-label": {
"defaultMessage": "Sustituir",
"description": "Action label for replacing project dialog"
@@ -678,6 +866,14 @@
"defaultMessage": "Buscar",
"description": "Aria label for searching documentation"
},
+ "select-project-action": {
+ "defaultMessage": "Select project ‘{name}’",
+ "description": "Accessible label for the per-project selection checkbox"
+ },
+ "selection-actions-group": {
+ "defaultMessage": "Actions for selected projects",
+ "description": "Accessible label for the selection toolbar"
+ },
"send-action": {
"defaultMessage": "Enviar a micro:bit",
"description": "Send to micro:bit button text"
@@ -1050,6 +1246,30 @@
"defaultMessage": "Versiones de software",
"description": "Heading for a table of software versions in the about dialog"
},
+ "sort-option-last-modified": {
+ "defaultMessage": "Last modified",
+ "description": "Sort projects by last modified date"
+ },
+ "sort-option-name": {
+ "defaultMessage": "Name",
+ "description": "Sort projects by name"
+ },
+ "sort-option-relevance": {
+ "defaultMessage": "Relevance",
+ "description": "Sort projects by search relevance"
+ },
+ "sort-order-ascending-label": {
+ "defaultMessage": "Sort ascending",
+ "description": "Accessible label to toggle to ascending sort order"
+ },
+ "sort-order-descending-label": {
+ "defaultMessage": "Sort descending",
+ "description": "Accessible label to toggle to descending sort order"
+ },
+ "sort-select-label": {
+ "defaultMessage": "Sort projects by",
+ "description": "Accessible label for the project sort dropdown"
+ },
"start-coding-action": {
"defaultMessage": "Empezar a programar",
"description": "Start coding button text"
@@ -1058,6 +1278,14 @@
"defaultMessage": "Ayuda Técnica",
"description": "Support menu option text"
},
+ "teacher-resources-row-carousel": {
+ "defaultMessage": "Teacher resources",
+ "description": "Accessible name for the teacher resources carousel"
+ },
+ "teacher-resources-row-title": {
+ "defaultMessage": "Teacher resources",
+ "description": "Title for the teacher resources row"
+ },
"terms-of-use": {
"defaultMessage": "Términos de uso",
"description": "Terms of use menu option text"
@@ -1098,6 +1326,10 @@
"defaultMessage": "Transferir archivo HEX guardado a micro:bit",
"description": "Title for the transfer hex dialog"
},
+ "troubleshooting-resource-title": {
+ "defaultMessage": "Troubleshooting",
+ "description": "Title for the troubleshooting help card"
+ },
"try-again-action": {
"defaultMessage": "Inténtalo de nuevo",
"description": "Try again button text"
@@ -1130,6 +1362,10 @@
"defaultMessage": "Guía de usuario",
"description": "Menu item for link to user guide site"
},
+ "view-all-projects": {
+ "defaultMessage": "View all projects",
+ "description": "Link/card to view the full projects list"
+ },
"visit-dot-org": {
"defaultMessage": "visitar microbit.org (abre en una nueva pestaña)",
"description": "alt text for logo link to .org"
diff --git a/lang/ui.fr.json b/lang/ui.fr.json
index b5533b844..6b1e070ed 100644
--- a/lang/ui.fr.json
+++ b/lang/ui.fr.json
@@ -27,6 +27,18 @@
"defaultMessage": "Accessibilité",
"description": "Menu item for link to accessibility site"
},
+ "accessibility-resource-title": {
+ "defaultMessage": "Accessibility",
+ "description": "Title for the accessibility help card"
+ },
+ "add-files-action": {
+ "defaultMessage": "Add file(s)",
+ "description": "Button to add files to the current project"
+ },
+ "add-files-hover": {
+ "defaultMessage": "Add files to this project",
+ "description": "Tooltip for the add files button"
+ },
"added-change": {
"defaultMessage": "Fichier ajouté {changeName}",
"description": "Change made to file"
@@ -71,6 +83,18 @@
"defaultMessage": "Annuler",
"description": "Cancel button text"
},
+ "carousel-role": {
+ "defaultMessage": "carousel",
+ "description": "Accessible role description for a carousel"
+ },
+ "carousel-slide-label": {
+ "defaultMessage": "{slideNum} of {totalSlides}",
+ "description": "Accessible label for a carousel slide"
+ },
+ "carousel-slide-role": {
+ "defaultMessage": "slide",
+ "description": "Accessible role description for a carousel slide"
+ },
"change-files": {
"defaultMessage": "Changer de fichiers ?",
"description": "Header for dialog of confirmation of files changed"
@@ -227,10 +251,22 @@
"defaultMessage": "Créer un fichier",
"description": "Button text for action that creates a new blank Python file in the current project"
},
+ "create-project-action": {
+ "defaultMessage": "Create",
+ "description": "Create project button"
+ },
+ "create-project-dialog-heading": {
+ "defaultMessage": "Name your project",
+ "description": "Heading for the create project dialog"
+ },
"create-python": {
"defaultMessage": "Créer un nouveau fichier Python dans ce projet",
"description": "Hover and dialog title when creating a new Python file"
},
+ "createai-taster-lessons-resource-title": {
+ "defaultMessage": "Taster lessons",
+ "description": "Title for a lesson card (placeholder)"
+ },
"created-file": {
"defaultMessage": "{filename} créé",
"description": "Action feedback for creating a file"
@@ -243,6 +279,26 @@
"defaultMessage": "Supprimer {name}",
"description": "Menu option to delete file"
},
+ "delete-project-action": {
+ "defaultMessage": "Delete",
+ "description": "Delete project menu item/button"
+ },
+ "delete-project-confirm-heading": {
+ "defaultMessage": "Delete project",
+ "description": "Heading for the delete project confirmation dialog"
+ },
+ "delete-project-confirm-text": {
+ "defaultMessage": "Are you sure you want to delete ‘{project}’? This cannot be undone.",
+ "description": "Body text for the delete project confirmation dialog"
+ },
+ "delete-projects-confirm-heading": {
+ "defaultMessage": "Delete projects",
+ "description": "Heading for the delete multiple projects confirmation dialog"
+ },
+ "delete-projects-confirm-text": {
+ "defaultMessage": "Are you sure you want to delete {numProjects} projects? This cannot be undone.",
+ "description": "Body for the delete multiple projects confirmation dialog"
+ },
"deleted-file": {
"defaultMessage": "{filename} a été supprimé",
"description": "Confirmation message that file got deleted"
@@ -263,6 +319,14 @@
"defaultMessage": "Glisser-déposer",
"description": "Draggable code hover text"
},
+ "duplicate-project-action": {
+ "defaultMessage": "Duplicate",
+ "description": "Duplicate project button/menu item"
+ },
+ "duplicate-project-heading": {
+ "defaultMessage": "Name your project",
+ "description": "Heading for the duplicate project dialog"
+ },
"edit-file-action": {
"defaultMessage": "Modifier {name}",
"description": "Menu option to edit file"
@@ -315,6 +379,14 @@
"defaultMessage": "Le nom ne peut pas contenir d'espaces",
"description": "Warning text for new Python file name with whitespace"
},
+ "files-tab": {
+ "defaultMessage": "Files",
+ "description": "Sidebar tab label for the project files"
+ },
+ "files-tab-description": {
+ "defaultMessage": "Manage your project files",
+ "description": "Subheading for the Files sidebar tab"
+ },
"firmware-update-link": {
"defaultMessage": "Vous devez mettre à jour le micrologiciel avant de pouvoir vous connecter à ce micro:bit.",
"description": "Text in the firmware update dialog"
@@ -327,6 +399,10 @@
"defaultMessage": "Mise à jour du micrologiciel requise",
"description": "Title for the firmware update dialog"
},
+ "first-lessons-with-python-resource-title": {
+ "defaultMessage": "First lessons with Python and the micro:bit",
+ "description": "Title for a lesson card"
+ },
"flash-action": {
"defaultMessage": "Flasher",
"description": "Text for flash button"
@@ -359,6 +435,14 @@
"defaultMessage": "Aide",
"description": "Help menu label"
},
+ "help-resources-row-carousel": {
+ "defaultMessage": "Help and support",
+ "description": "Accessible name for the help and support carousel"
+ },
+ "help-resources-row-title": {
+ "defaultMessage": "Help and support",
+ "description": "Title for the help and support row"
+ },
"help-support": {
"defaultMessage": "Aide et support",
"description": "Menu item for link to support site"
@@ -383,6 +467,22 @@
"defaultMessage": "Simple",
"description": "Highlight code structure option"
},
+ "home-action": {
+ "defaultMessage": "Home",
+ "description": "Aria label for the home button that returns to the project list"
+ },
+ "homepage-banner-heading": {
+ "defaultMessage": "Code your BBC micro:bit with Python",
+ "description": "Home page banner heading"
+ },
+ "homepage-banner-subtitle": {
+ "defaultMessage": "Create, edit and flash MicroPython programs to your micro:bit.",
+ "description": "Home page banner subtitle"
+ },
+ "homepage-title": {
+ "defaultMessage": "micro:bit Python Editor",
+ "description": "Application name shown in the home page header"
+ },
"ideas-tab": {
"defaultMessage": "Idées",
"description": "Ideas tab button text. Tab shows programs to give students ideas."
@@ -391,6 +491,10 @@
"defaultMessage": "Essayez ces projets, modifiez-les et inspirez-vous en",
"description": "Ideas tab description text. Tab shows programs to give students ideas."
},
+ "import-file-action": {
+ "defaultMessage": "Import",
+ "description": "Button to import a project file (hex)"
+ },
"insert-code-action": {
"defaultMessage": "Insérer le code"
},
@@ -398,6 +502,10 @@
"defaultMessage": "Langue",
"description": "Language option text"
},
+ "learn-more-action": {
+ "defaultMessage": "Learn more",
+ "description": "Learn more button on the home page banner"
+ },
"less-action": {
"defaultMessage": "Moins",
"description": "Less button text (showing less content)"
@@ -474,6 +582,14 @@
"defaultMessage": "Avertissement : Seul main.py est téléchargé",
"description": "Title of dialog shown when multiple files are available for download but only the main file downloaded."
},
+ "my-projects-row-carousel": {
+ "defaultMessage": "Your projects",
+ "description": "Accessible name for the your projects carousel"
+ },
+ "my-projects-row-title": {
+ "defaultMessage": "Your projects",
+ "description": "Title for the your projects row"
+ },
"name-project": {
"defaultMessage": "Donnez un nom à votre projet",
"description": "Name your project header"
@@ -490,10 +606,18 @@
"defaultMessage": "Nous ajouterons l’extension .py pour vous.",
"description": "Hint shown in the new Python file dialog"
},
+ "new-project-action": {
+ "defaultMessage": "New project",
+ "description": "New project card action"
+ },
"next-action": {
"defaultMessage": "Suivant",
"description": "Next button text"
},
+ "no-projects": {
+ "defaultMessage": "No projects found",
+ "description": "Shown when a project search returns nothing"
+ },
"not-found-checklist-one": {
"defaultMessage": "Est-ce que votre micro:bit est branché ? Avez-vous suivi ces étapes ?",
"description": "Checklist text in the no micro:bit found dialog"
@@ -538,6 +662,10 @@
"defaultMessage": "Ouvrir un fichier hex ou Python, ou ajouter d'autres fichiers",
"description": "Hover text over load button"
},
+ "open-project-action": {
+ "defaultMessage": "Open",
+ "description": "Open project menu item"
+ },
"options": {
"defaultMessage": "Options",
"description": "Label for an options menu"
@@ -586,10 +714,54 @@
"defaultMessage": "Actions du projet",
"description": "Aria label for the bar with project actions"
},
+ "project-file-count": {
+ "defaultMessage": "{count, plural, one {# file} other {# files}}",
+ "description": "Number of files in a project"
+ },
"project-header": {
"defaultMessage": "En-tête de projet",
"description": "Aria label for the project header area"
},
+ "project-idea-animated-animals-title": {
+ "defaultMessage": "Animated animals",
+ "description": "Title for a make it, code it project idea card"
+ },
+ "project-idea-beating-heart-title": {
+ "defaultMessage": "Beating heart",
+ "description": "Title for a make it, code it project idea card"
+ },
+ "project-idea-emotion-badge-title": {
+ "defaultMessage": "Emotion badge",
+ "description": "Title for a make it, code it project idea card"
+ },
+ "project-idea-flashing-emotions-title": {
+ "defaultMessage": "Flashing emotions",
+ "description": "Title for a make it, code it project idea card"
+ },
+ "project-idea-get-silly-title": {
+ "defaultMessage": "Get silly",
+ "description": "Title for a make it, code it project idea card"
+ },
+ "project-idea-heart-title": {
+ "defaultMessage": "Heart",
+ "description": "Title for a make it, code it project idea card"
+ },
+ "project-ideas-row-carousel": {
+ "defaultMessage": "Project ideas",
+ "description": "Accessible name for the project ideas carousel"
+ },
+ "project-ideas-row-title": {
+ "defaultMessage": "Project ideas",
+ "description": "Title for the project ideas row"
+ },
+ "project-loaded": {
+ "defaultMessage": "Project loaded",
+ "description": "Toast shown after a project is loaded from a dropped hex file"
+ },
+ "project-menu-action": {
+ "defaultMessage": "Actions for project ‘{name}’",
+ "description": "Aria label for the per-project actions menu button"
+ },
"project-name": {
"defaultMessage": "Intitulé du projet",
"description": "Text used to indicate the project name"
@@ -598,6 +770,10 @@
"defaultMessage": "Le nom du projet ne peut pas être vide",
"description": "Validation message for project name"
},
+ "project-skip-to-toolbar": {
+ "defaultMessage": "Skip to selection actions",
+ "description": "Accessible skip link from a selected project card to the toolbar"
+ },
"project-tab": {
"defaultMessage": "Projet",
"description": "Project tab button text"
@@ -606,6 +782,10 @@
"defaultMessage": "Visualiser, créer, ajouter et modifier les fichiers de votre projet",
"description": "Project tab description"
},
+ "projects-page-title": {
+ "defaultMessage": "Projects",
+ "description": "Title of the projects page"
+ },
"python-powered": {
"defaultMessage": "Fonctionne avec Python",
"description": "Python powered logo alt text"
@@ -634,6 +814,14 @@
"defaultMessage": "Référence",
"description": "Reference tab button text"
},
+ "rename-project-action": {
+ "defaultMessage": "Rename",
+ "description": "Rename project button/menu item"
+ },
+ "rename-project-heading": {
+ "defaultMessage": "Rename project",
+ "description": "Heading for the rename project dialog"
+ },
"replace-action-label": {
"defaultMessage": "Remplacer",
"description": "Action label for replacing project dialog"
@@ -678,6 +866,14 @@
"defaultMessage": "Rechercher",
"description": "Aria label for searching documentation"
},
+ "select-project-action": {
+ "defaultMessage": "Select project ‘{name}’",
+ "description": "Accessible label for the per-project selection checkbox"
+ },
+ "selection-actions-group": {
+ "defaultMessage": "Actions for selected projects",
+ "description": "Accessible label for the selection toolbar"
+ },
"send-action": {
"defaultMessage": "Envoyer vers micro:bit",
"description": "Send to micro:bit button text"
@@ -1050,6 +1246,30 @@
"defaultMessage": "Versions logicielles",
"description": "Heading for a table of software versions in the about dialog"
},
+ "sort-option-last-modified": {
+ "defaultMessage": "Last modified",
+ "description": "Sort projects by last modified date"
+ },
+ "sort-option-name": {
+ "defaultMessage": "Name",
+ "description": "Sort projects by name"
+ },
+ "sort-option-relevance": {
+ "defaultMessage": "Relevance",
+ "description": "Sort projects by search relevance"
+ },
+ "sort-order-ascending-label": {
+ "defaultMessage": "Sort ascending",
+ "description": "Accessible label to toggle to ascending sort order"
+ },
+ "sort-order-descending-label": {
+ "defaultMessage": "Sort descending",
+ "description": "Accessible label to toggle to descending sort order"
+ },
+ "sort-select-label": {
+ "defaultMessage": "Sort projects by",
+ "description": "Accessible label for the project sort dropdown"
+ },
"start-coding-action": {
"defaultMessage": "Commencer à programmer",
"description": "Start coding button text"
@@ -1058,6 +1278,14 @@
"defaultMessage": "Assistance",
"description": "Support menu option text"
},
+ "teacher-resources-row-carousel": {
+ "defaultMessage": "Teacher resources",
+ "description": "Accessible name for the teacher resources carousel"
+ },
+ "teacher-resources-row-title": {
+ "defaultMessage": "Teacher resources",
+ "description": "Title for the teacher resources row"
+ },
"terms-of-use": {
"defaultMessage": "Conditions d’utilisation",
"description": "Terms of use menu option text"
@@ -1098,6 +1326,10 @@
"defaultMessage": "Transférer le fichier hex enregistré vers le micro:bit",
"description": "Title for the transfer hex dialog"
},
+ "troubleshooting-resource-title": {
+ "defaultMessage": "Troubleshooting",
+ "description": "Title for the troubleshooting help card"
+ },
"try-again-action": {
"defaultMessage": "Réessayer",
"description": "Try again button text"
@@ -1130,6 +1362,10 @@
"defaultMessage": "Guide de l'utilisateur",
"description": "Menu item for link to user guide site"
},
+ "view-all-projects": {
+ "defaultMessage": "View all projects",
+ "description": "Link/card to view the full projects list"
+ },
"visit-dot-org": {
"defaultMessage": "visiter microbit.org (s’ouvre dans un nouvel onglet)",
"description": "alt text for logo link to .org"
diff --git a/lang/ui.ga-ie.json b/lang/ui.ga-ie.json
index 7a6dda50a..d7275f308 100644
--- a/lang/ui.ga-ie.json
+++ b/lang/ui.ga-ie.json
@@ -27,6 +27,18 @@
"defaultMessage": "Inrochtaineacht",
"description": "Menu item for link to accessibility site"
},
+ "accessibility-resource-title": {
+ "defaultMessage": "Accessibility",
+ "description": "Title for the accessibility help card"
+ },
+ "add-files-action": {
+ "defaultMessage": "Add file(s)",
+ "description": "Button to add files to the current project"
+ },
+ "add-files-hover": {
+ "defaultMessage": "Add files to this project",
+ "description": "Tooltip for the add files button"
+ },
"added-change": {
"defaultMessage": "Cuireadh comhad leis {changeName}",
"description": "Change made to file"
@@ -71,6 +83,18 @@
"defaultMessage": "Cealaigh",
"description": "Cancel button text"
},
+ "carousel-role": {
+ "defaultMessage": "carousel",
+ "description": "Accessible role description for a carousel"
+ },
+ "carousel-slide-label": {
+ "defaultMessage": "{slideNum} of {totalSlides}",
+ "description": "Accessible label for a carousel slide"
+ },
+ "carousel-slide-role": {
+ "defaultMessage": "slide",
+ "description": "Accessible role description for a carousel slide"
+ },
"change-files": {
"defaultMessage": "Athraigh comhaid?",
"description": "Header for dialog of confirmation of files changed"
@@ -227,10 +251,22 @@
"defaultMessage": "Cruthaigh comhad",
"description": "Button text for action that creates a new blank Python file in the current project"
},
+ "create-project-action": {
+ "defaultMessage": "Create",
+ "description": "Create project button"
+ },
+ "create-project-dialog-heading": {
+ "defaultMessage": "Name your project",
+ "description": "Heading for the create project dialog"
+ },
"create-python": {
"defaultMessage": "Cruthaigh comhad nua Python sa tionscadal seo",
"description": "Hover and dialog title when creating a new Python file"
},
+ "createai-taster-lessons-resource-title": {
+ "defaultMessage": "Taster lessons",
+ "description": "Title for a lesson card (placeholder)"
+ },
"created-file": {
"defaultMessage": "Cruthaithe {filename}",
"description": "Action feedback for creating a file"
@@ -243,6 +279,26 @@
"defaultMessage": "Scrios {name}",
"description": "Menu option to delete file"
},
+ "delete-project-action": {
+ "defaultMessage": "Delete",
+ "description": "Delete project menu item/button"
+ },
+ "delete-project-confirm-heading": {
+ "defaultMessage": "Delete project",
+ "description": "Heading for the delete project confirmation dialog"
+ },
+ "delete-project-confirm-text": {
+ "defaultMessage": "Are you sure you want to delete ‘{project}’? This cannot be undone.",
+ "description": "Body text for the delete project confirmation dialog"
+ },
+ "delete-projects-confirm-heading": {
+ "defaultMessage": "Delete projects",
+ "description": "Heading for the delete multiple projects confirmation dialog"
+ },
+ "delete-projects-confirm-text": {
+ "defaultMessage": "Are you sure you want to delete {numProjects} projects? This cannot be undone.",
+ "description": "Body for the delete multiple projects confirmation dialog"
+ },
"deleted-file": {
"defaultMessage": "Scriosta {filename}",
"description": "Confirmation message that file got deleted"
@@ -263,6 +319,14 @@
"defaultMessage": "Tarraing agus scaoil",
"description": "Draggable code hover text"
},
+ "duplicate-project-action": {
+ "defaultMessage": "Duplicate",
+ "description": "Duplicate project button/menu item"
+ },
+ "duplicate-project-heading": {
+ "defaultMessage": "Name your project",
+ "description": "Heading for the duplicate project dialog"
+ },
"edit-file-action": {
"defaultMessage": "Cuir {name} in eagar",
"description": "Menu option to edit file"
@@ -315,6 +379,14 @@
"defaultMessage": "Ní féidir spásanna a bheith san ainm",
"description": "Warning text for new Python file name with whitespace"
},
+ "files-tab": {
+ "defaultMessage": "Files",
+ "description": "Sidebar tab label for the project files"
+ },
+ "files-tab-description": {
+ "defaultMessage": "Manage your project files",
+ "description": "Subheading for the Files sidebar tab"
+ },
"firmware-update-link": {
"defaultMessage": "Ní mór duit do dochtearraí a nuashonrú sular féidir leat ceangal leis an micro:bit seo.",
"description": "Text in the firmware update dialog"
@@ -327,6 +399,10 @@
"defaultMessage": "Nuashonrú dochtearraí ag teastáil",
"description": "Title for the firmware update dialog"
},
+ "first-lessons-with-python-resource-title": {
+ "defaultMessage": "First lessons with Python and the micro:bit",
+ "description": "Title for a lesson card"
+ },
"flash-action": {
"defaultMessage": "Splanc",
"description": "Text for flash button"
@@ -359,6 +435,14 @@
"defaultMessage": "Cabhair",
"description": "Help menu label"
},
+ "help-resources-row-carousel": {
+ "defaultMessage": "Help and support",
+ "description": "Accessible name for the help and support carousel"
+ },
+ "help-resources-row-title": {
+ "defaultMessage": "Help and support",
+ "description": "Title for the help and support row"
+ },
"help-support": {
"defaultMessage": "Cabhair & tacaíocht",
"description": "Menu item for link to support site"
@@ -383,6 +467,22 @@
"defaultMessage": "Simplí",
"description": "Highlight code structure option"
},
+ "home-action": {
+ "defaultMessage": "Home",
+ "description": "Aria label for the home button that returns to the project list"
+ },
+ "homepage-banner-heading": {
+ "defaultMessage": "Code your BBC micro:bit with Python",
+ "description": "Home page banner heading"
+ },
+ "homepage-banner-subtitle": {
+ "defaultMessage": "Create, edit and flash MicroPython programs to your micro:bit.",
+ "description": "Home page banner subtitle"
+ },
+ "homepage-title": {
+ "defaultMessage": "micro:bit Python Editor",
+ "description": "Application name shown in the home page header"
+ },
"ideas-tab": {
"defaultMessage": "Smaointe",
"description": "Ideas tab button text. Tab shows programs to give students ideas."
@@ -391,6 +491,10 @@
"defaultMessage": "Bain triail as na tionscadail seo, athraigh iad agus spreag iad",
"description": "Ideas tab description text. Tab shows programs to give students ideas."
},
+ "import-file-action": {
+ "defaultMessage": "Import",
+ "description": "Button to import a project file (hex)"
+ },
"insert-code-action": {
"defaultMessage": "Ionsáigh cód"
},
@@ -398,6 +502,10 @@
"defaultMessage": "Teanga",
"description": "Language option text"
},
+ "learn-more-action": {
+ "defaultMessage": "Learn more",
+ "description": "Learn more button on the home page banner"
+ },
"less-action": {
"defaultMessage": "Níos lú",
"description": "Less button text (showing less content)"
@@ -474,6 +582,14 @@
"defaultMessage": "Rabhadh: Ní íoslódálfar ach main.py",
"description": "Title of dialog shown when multiple files are available for download but only the main file downloaded."
},
+ "my-projects-row-carousel": {
+ "defaultMessage": "Your projects",
+ "description": "Accessible name for the your projects carousel"
+ },
+ "my-projects-row-title": {
+ "defaultMessage": "Your projects",
+ "description": "Title for the your projects row"
+ },
"name-project": {
"defaultMessage": "Ainmnigh do thionscadal",
"description": "Name your project header"
@@ -490,10 +606,18 @@
"defaultMessage": "Cuirfimid an síneadh .py ar do shon.",
"description": "Hint shown in the new Python file dialog"
},
+ "new-project-action": {
+ "defaultMessage": "New project",
+ "description": "New project card action"
+ },
"next-action": {
"defaultMessage": "Ar Aghaidh",
"description": "Next button text"
},
+ "no-projects": {
+ "defaultMessage": "No projects found",
+ "description": "Shown when a project search returns nothing"
+ },
"not-found-checklist-one": {
"defaultMessage": "An bhfuil do micro:bit plugáilte isteach? Ar lean tú na céimeanna seo?",
"description": "Checklist text in the no micro:bit found dialog"
@@ -538,6 +662,10 @@
"defaultMessage": "Oscail comhad heicsidheachúlach nó Python nó cuir comhaid eile leis",
"description": "Hover text over load button"
},
+ "open-project-action": {
+ "defaultMessage": "Open",
+ "description": "Open project menu item"
+ },
"options": {
"defaultMessage": "Roghanna",
"description": "Label for an options menu"
@@ -586,10 +714,54 @@
"defaultMessage": "Gníomhartha tionscadail",
"description": "Aria label for the bar with project actions"
},
+ "project-file-count": {
+ "defaultMessage": "{count, plural, one {# file} other {# files}}",
+ "description": "Number of files in a project"
+ },
"project-header": {
"defaultMessage": "Ceanntásc an tionscadail",
"description": "Aria label for the project header area"
},
+ "project-idea-animated-animals-title": {
+ "defaultMessage": "Animated animals",
+ "description": "Title for a make it, code it project idea card"
+ },
+ "project-idea-beating-heart-title": {
+ "defaultMessage": "Beating heart",
+ "description": "Title for a make it, code it project idea card"
+ },
+ "project-idea-emotion-badge-title": {
+ "defaultMessage": "Emotion badge",
+ "description": "Title for a make it, code it project idea card"
+ },
+ "project-idea-flashing-emotions-title": {
+ "defaultMessage": "Flashing emotions",
+ "description": "Title for a make it, code it project idea card"
+ },
+ "project-idea-get-silly-title": {
+ "defaultMessage": "Get silly",
+ "description": "Title for a make it, code it project idea card"
+ },
+ "project-idea-heart-title": {
+ "defaultMessage": "Heart",
+ "description": "Title for a make it, code it project idea card"
+ },
+ "project-ideas-row-carousel": {
+ "defaultMessage": "Project ideas",
+ "description": "Accessible name for the project ideas carousel"
+ },
+ "project-ideas-row-title": {
+ "defaultMessage": "Project ideas",
+ "description": "Title for the project ideas row"
+ },
+ "project-loaded": {
+ "defaultMessage": "Project loaded",
+ "description": "Toast shown after a project is loaded from a dropped hex file"
+ },
+ "project-menu-action": {
+ "defaultMessage": "Actions for project ‘{name}’",
+ "description": "Aria label for the per-project actions menu button"
+ },
"project-name": {
"defaultMessage": "Ainm an tionscadail",
"description": "Text used to indicate the project name"
@@ -598,6 +770,10 @@
"defaultMessage": "Ní féidir ainm an tionscadail a fholmhú",
"description": "Validation message for project name"
},
+ "project-skip-to-toolbar": {
+ "defaultMessage": "Skip to selection actions",
+ "description": "Accessible skip link from a selected project card to the toolbar"
+ },
"project-tab": {
"defaultMessage": "Tionscadal",
"description": "Project tab button text"
@@ -606,6 +782,10 @@
"defaultMessage": "Amharc ar na comhaid i do thionscadal, iad a chruthú, a chur leis agus a chur in eagar",
"description": "Project tab description"
},
+ "projects-page-title": {
+ "defaultMessage": "Projects",
+ "description": "Title of the projects page"
+ },
"python-powered": {
"defaultMessage": "Python faoi thiomáint",
"description": "Python powered logo alt text"
@@ -634,6 +814,14 @@
"defaultMessage": "Tagairt",
"description": "Reference tab button text"
},
+ "rename-project-action": {
+ "defaultMessage": "Rename",
+ "description": "Rename project button/menu item"
+ },
+ "rename-project-heading": {
+ "defaultMessage": "Rename project",
+ "description": "Heading for the rename project dialog"
+ },
"replace-action-label": {
"defaultMessage": "Ionadaigh",
"description": "Action label for replacing project dialog"
@@ -678,6 +866,14 @@
"defaultMessage": "Cuardaigh",
"description": "Aria label for searching documentation"
},
+ "select-project-action": {
+ "defaultMessage": "Select project ‘{name}’",
+ "description": "Accessible label for the per-project selection checkbox"
+ },
+ "selection-actions-group": {
+ "defaultMessage": "Actions for selected projects",
+ "description": "Accessible label for the selection toolbar"
+ },
"send-action": {
"defaultMessage": "Seol chuig micro:bit",
"description": "Send to micro:bit button text"
@@ -1050,6 +1246,30 @@
"defaultMessage": "Leaganacha bogearraí",
"description": "Heading for a table of software versions in the about dialog"
},
+ "sort-option-last-modified": {
+ "defaultMessage": "Last modified",
+ "description": "Sort projects by last modified date"
+ },
+ "sort-option-name": {
+ "defaultMessage": "Name",
+ "description": "Sort projects by name"
+ },
+ "sort-option-relevance": {
+ "defaultMessage": "Relevance",
+ "description": "Sort projects by search relevance"
+ },
+ "sort-order-ascending-label": {
+ "defaultMessage": "Sort ascending",
+ "description": "Accessible label to toggle to ascending sort order"
+ },
+ "sort-order-descending-label": {
+ "defaultMessage": "Sort descending",
+ "description": "Accessible label to toggle to descending sort order"
+ },
+ "sort-select-label": {
+ "defaultMessage": "Sort projects by",
+ "description": "Accessible label for the project sort dropdown"
+ },
"start-coding-action": {
"defaultMessage": "Tosaigh códú",
"description": "Start coding button text"
@@ -1058,6 +1278,14 @@
"defaultMessage": "Tacaíocht",
"description": "Support menu option text"
},
+ "teacher-resources-row-carousel": {
+ "defaultMessage": "Teacher resources",
+ "description": "Accessible name for the teacher resources carousel"
+ },
+ "teacher-resources-row-title": {
+ "defaultMessage": "Teacher resources",
+ "description": "Title for the teacher resources row"
+ },
"terms-of-use": {
"defaultMessage": "Téarmaí úsáide",
"description": "Terms of use menu option text"
@@ -1098,6 +1326,10 @@
"defaultMessage": "Aistrigh comhad heicsidheachúlach sábháilte go micro:bit",
"description": "Title for the transfer hex dialog"
},
+ "troubleshooting-resource-title": {
+ "defaultMessage": "Troubleshooting",
+ "description": "Title for the troubleshooting help card"
+ },
"try-again-action": {
"defaultMessage": "Bain triail as arís",
"description": "Try again button text"
@@ -1130,6 +1362,10 @@
"defaultMessage": "Treoir d'úsáideoirí",
"description": "Menu item for link to user guide site"
},
+ "view-all-projects": {
+ "defaultMessage": "View all projects",
+ "description": "Link/card to view the full projects list"
+ },
"visit-dot-org": {
"defaultMessage": "tabhair cuairt ar microbit.org (osclaítear i gcluaisín nua)",
"description": "alt text for logo link to .org"
diff --git a/lang/ui.ja.json b/lang/ui.ja.json
index 17bfcd23c..890409d63 100644
--- a/lang/ui.ja.json
+++ b/lang/ui.ja.json
@@ -27,6 +27,18 @@
"defaultMessage": "アクセシビリティ",
"description": "Menu item for link to accessibility site"
},
+ "accessibility-resource-title": {
+ "defaultMessage": "Accessibility",
+ "description": "Title for the accessibility help card"
+ },
+ "add-files-action": {
+ "defaultMessage": "Add file(s)",
+ "description": "Button to add files to the current project"
+ },
+ "add-files-hover": {
+ "defaultMessage": "Add files to this project",
+ "description": "Tooltip for the add files button"
+ },
"added-change": {
"defaultMessage": "ファイル {changeName} を追加しました",
"description": "Change made to file"
@@ -71,6 +83,18 @@
"defaultMessage": "キャンセル",
"description": "Cancel button text"
},
+ "carousel-role": {
+ "defaultMessage": "carousel",
+ "description": "Accessible role description for a carousel"
+ },
+ "carousel-slide-label": {
+ "defaultMessage": "{slideNum} of {totalSlides}",
+ "description": "Accessible label for a carousel slide"
+ },
+ "carousel-slide-role": {
+ "defaultMessage": "slide",
+ "description": "Accessible role description for a carousel slide"
+ },
"change-files": {
"defaultMessage": "ファイルを変更しますか?",
"description": "Header for dialog of confirmation of files changed"
@@ -227,10 +251,22 @@
"defaultMessage": "ファイルを作成",
"description": "Button text for action that creates a new blank Python file in the current project"
},
+ "create-project-action": {
+ "defaultMessage": "Create",
+ "description": "Create project button"
+ },
+ "create-project-dialog-heading": {
+ "defaultMessage": "Name your project",
+ "description": "Heading for the create project dialog"
+ },
"create-python": {
"defaultMessage": "このプロジェクトに新しいPythonファイルを作成",
"description": "Hover and dialog title when creating a new Python file"
},
+ "createai-taster-lessons-resource-title": {
+ "defaultMessage": "Taster lessons",
+ "description": "Title for a lesson card (placeholder)"
+ },
"created-file": {
"defaultMessage": "{filename} を作成しました",
"description": "Action feedback for creating a file"
@@ -243,6 +279,26 @@
"defaultMessage": "{name} を削除",
"description": "Menu option to delete file"
},
+ "delete-project-action": {
+ "defaultMessage": "Delete",
+ "description": "Delete project menu item/button"
+ },
+ "delete-project-confirm-heading": {
+ "defaultMessage": "Delete project",
+ "description": "Heading for the delete project confirmation dialog"
+ },
+ "delete-project-confirm-text": {
+ "defaultMessage": "Are you sure you want to delete ‘{project}’? This cannot be undone.",
+ "description": "Body text for the delete project confirmation dialog"
+ },
+ "delete-projects-confirm-heading": {
+ "defaultMessage": "Delete projects",
+ "description": "Heading for the delete multiple projects confirmation dialog"
+ },
+ "delete-projects-confirm-text": {
+ "defaultMessage": "Are you sure you want to delete {numProjects} projects? This cannot be undone.",
+ "description": "Body for the delete multiple projects confirmation dialog"
+ },
"deleted-file": {
"defaultMessage": "{filename} を削除しました",
"description": "Confirmation message that file got deleted"
@@ -263,6 +319,14 @@
"defaultMessage": "ドラッグ&ドロップ",
"description": "Draggable code hover text"
},
+ "duplicate-project-action": {
+ "defaultMessage": "Duplicate",
+ "description": "Duplicate project button/menu item"
+ },
+ "duplicate-project-heading": {
+ "defaultMessage": "Name your project",
+ "description": "Heading for the duplicate project dialog"
+ },
"edit-file-action": {
"defaultMessage": "{name} を編集",
"description": "Menu option to edit file"
@@ -315,6 +379,14 @@
"defaultMessage": "名前にスペースを含めることはできません",
"description": "Warning text for new Python file name with whitespace"
},
+ "files-tab": {
+ "defaultMessage": "Files",
+ "description": "Sidebar tab label for the project files"
+ },
+ "files-tab-description": {
+ "defaultMessage": "Manage your project files",
+ "description": "Subheading for the Files sidebar tab"
+ },
"firmware-update-link": {
"defaultMessage": "このmicro:bitに接続するには、ファームウェアを更新する必要があります。",
"description": "Text in the firmware update dialog"
@@ -327,6 +399,10 @@
"defaultMessage": "ファームウェアの更新が必要です",
"description": "Title for the firmware update dialog"
},
+ "first-lessons-with-python-resource-title": {
+ "defaultMessage": "First lessons with Python and the micro:bit",
+ "description": "Title for a lesson card"
+ },
"flash-action": {
"defaultMessage": "書き込み",
"description": "Text for flash button"
@@ -359,6 +435,14 @@
"defaultMessage": "ヘルプ",
"description": "Help menu label"
},
+ "help-resources-row-carousel": {
+ "defaultMessage": "Help and support",
+ "description": "Accessible name for the help and support carousel"
+ },
+ "help-resources-row-title": {
+ "defaultMessage": "Help and support",
+ "description": "Title for the help and support row"
+ },
"help-support": {
"defaultMessage": "ヘルプとサポート",
"description": "Menu item for link to support site"
@@ -383,6 +467,22 @@
"defaultMessage": "簡易",
"description": "Highlight code structure option"
},
+ "home-action": {
+ "defaultMessage": "Home",
+ "description": "Aria label for the home button that returns to the project list"
+ },
+ "homepage-banner-heading": {
+ "defaultMessage": "Code your BBC micro:bit with Python",
+ "description": "Home page banner heading"
+ },
+ "homepage-banner-subtitle": {
+ "defaultMessage": "Create, edit and flash MicroPython programs to your micro:bit.",
+ "description": "Home page banner subtitle"
+ },
+ "homepage-title": {
+ "defaultMessage": "micro:bit Python Editor",
+ "description": "Application name shown in the home page header"
+ },
"ideas-tab": {
"defaultMessage": "アイデア",
"description": "Ideas tab button text. Tab shows programs to give students ideas."
@@ -391,6 +491,10 @@
"defaultMessage": "これらのプロジェクトを試し、修正し、インスピレーションを得ることができます。",
"description": "Ideas tab description text. Tab shows programs to give students ideas."
},
+ "import-file-action": {
+ "defaultMessage": "Import",
+ "description": "Button to import a project file (hex)"
+ },
"insert-code-action": {
"defaultMessage": "コードを挿入"
},
@@ -398,6 +502,10 @@
"defaultMessage": "言語",
"description": "Language option text"
},
+ "learn-more-action": {
+ "defaultMessage": "Learn more",
+ "description": "Learn more button on the home page banner"
+ },
"less-action": {
"defaultMessage": "少なく表示",
"description": "Less button text (showing less content)"
@@ -474,6 +582,14 @@
"defaultMessage": "注意: main.pyのみダウンロードされました",
"description": "Title of dialog shown when multiple files are available for download but only the main file downloaded."
},
+ "my-projects-row-carousel": {
+ "defaultMessage": "Your projects",
+ "description": "Accessible name for the your projects carousel"
+ },
+ "my-projects-row-title": {
+ "defaultMessage": "Your projects",
+ "description": "Title for the your projects row"
+ },
"name-project": {
"defaultMessage": "プロジェクトに名前を付ける",
"description": "Name your project header"
@@ -490,10 +606,18 @@
"defaultMessage": ".py拡張子を追加します。",
"description": "Hint shown in the new Python file dialog"
},
+ "new-project-action": {
+ "defaultMessage": "New project",
+ "description": "New project card action"
+ },
"next-action": {
"defaultMessage": "次",
"description": "Next button text"
},
+ "no-projects": {
+ "defaultMessage": "No projects found",
+ "description": "Shown when a project search returns nothing"
+ },
"not-found-checklist-one": {
"defaultMessage": "micro:bitは接続されていますか?以下の手順に従いましたか?",
"description": "Checklist text in the no micro:bit found dialog"
@@ -538,6 +662,10 @@
"defaultMessage": "hex ファイルまたは Python ファイルを開くか、他のファイルを追加する",
"description": "Hover text over load button"
},
+ "open-project-action": {
+ "defaultMessage": "Open",
+ "description": "Open project menu item"
+ },
"options": {
"defaultMessage": "オプション",
"description": "Label for an options menu"
@@ -586,10 +714,54 @@
"defaultMessage": "プロジェクトアクション",
"description": "Aria label for the bar with project actions"
},
+ "project-file-count": {
+ "defaultMessage": "{count, plural, one {# file} other {# files}}",
+ "description": "Number of files in a project"
+ },
"project-header": {
"defaultMessage": "プロジェクトヘッダー",
"description": "Aria label for the project header area"
},
+ "project-idea-animated-animals-title": {
+ "defaultMessage": "Animated animals",
+ "description": "Title for a make it, code it project idea card"
+ },
+ "project-idea-beating-heart-title": {
+ "defaultMessage": "Beating heart",
+ "description": "Title for a make it, code it project idea card"
+ },
+ "project-idea-emotion-badge-title": {
+ "defaultMessage": "Emotion badge",
+ "description": "Title for a make it, code it project idea card"
+ },
+ "project-idea-flashing-emotions-title": {
+ "defaultMessage": "Flashing emotions",
+ "description": "Title for a make it, code it project idea card"
+ },
+ "project-idea-get-silly-title": {
+ "defaultMessage": "Get silly",
+ "description": "Title for a make it, code it project idea card"
+ },
+ "project-idea-heart-title": {
+ "defaultMessage": "Heart",
+ "description": "Title for a make it, code it project idea card"
+ },
+ "project-ideas-row-carousel": {
+ "defaultMessage": "Project ideas",
+ "description": "Accessible name for the project ideas carousel"
+ },
+ "project-ideas-row-title": {
+ "defaultMessage": "Project ideas",
+ "description": "Title for the project ideas row"
+ },
+ "project-loaded": {
+ "defaultMessage": "Project loaded",
+ "description": "Toast shown after a project is loaded from a dropped hex file"
+ },
+ "project-menu-action": {
+ "defaultMessage": "Actions for project ‘{name}’",
+ "description": "Aria label for the per-project actions menu button"
+ },
"project-name": {
"defaultMessage": "プロジェクト名",
"description": "Text used to indicate the project name"
@@ -598,6 +770,10 @@
"defaultMessage": "プロジェクト名は空にできません",
"description": "Validation message for project name"
},
+ "project-skip-to-toolbar": {
+ "defaultMessage": "Skip to selection actions",
+ "description": "Accessible skip link from a selected project card to the toolbar"
+ },
"project-tab": {
"defaultMessage": "プロジェクト",
"description": "Project tab button text"
@@ -606,6 +782,10 @@
"defaultMessage": "プロジェクト内のファイルの表示、作成、追加、編集",
"description": "Project tab description"
},
+ "projects-page-title": {
+ "defaultMessage": "Projects",
+ "description": "Title of the projects page"
+ },
"python-powered": {
"defaultMessage": "Python搭載",
"description": "Python powered logo alt text"
@@ -634,6 +814,14 @@
"defaultMessage": "リファレンス",
"description": "Reference tab button text"
},
+ "rename-project-action": {
+ "defaultMessage": "Rename",
+ "description": "Rename project button/menu item"
+ },
+ "rename-project-heading": {
+ "defaultMessage": "Rename project",
+ "description": "Heading for the rename project dialog"
+ },
"replace-action-label": {
"defaultMessage": "置換",
"description": "Action label for replacing project dialog"
@@ -678,6 +866,14 @@
"defaultMessage": "検索",
"description": "Aria label for searching documentation"
},
+ "select-project-action": {
+ "defaultMessage": "Select project ‘{name}’",
+ "description": "Accessible label for the per-project selection checkbox"
+ },
+ "selection-actions-group": {
+ "defaultMessage": "Actions for selected projects",
+ "description": "Accessible label for the selection toolbar"
+ },
"send-action": {
"defaultMessage": "micro:bitに送る",
"description": "Send to micro:bit button text"
@@ -1050,6 +1246,30 @@
"defaultMessage": "ソフトウェアのバージョン",
"description": "Heading for a table of software versions in the about dialog"
},
+ "sort-option-last-modified": {
+ "defaultMessage": "Last modified",
+ "description": "Sort projects by last modified date"
+ },
+ "sort-option-name": {
+ "defaultMessage": "Name",
+ "description": "Sort projects by name"
+ },
+ "sort-option-relevance": {
+ "defaultMessage": "Relevance",
+ "description": "Sort projects by search relevance"
+ },
+ "sort-order-ascending-label": {
+ "defaultMessage": "Sort ascending",
+ "description": "Accessible label to toggle to ascending sort order"
+ },
+ "sort-order-descending-label": {
+ "defaultMessage": "Sort descending",
+ "description": "Accessible label to toggle to descending sort order"
+ },
+ "sort-select-label": {
+ "defaultMessage": "Sort projects by",
+ "description": "Accessible label for the project sort dropdown"
+ },
"start-coding-action": {
"defaultMessage": "プログラミングを開始",
"description": "Start coding button text"
@@ -1058,6 +1278,14 @@
"defaultMessage": "サポート",
"description": "Support menu option text"
},
+ "teacher-resources-row-carousel": {
+ "defaultMessage": "Teacher resources",
+ "description": "Accessible name for the teacher resources carousel"
+ },
+ "teacher-resources-row-title": {
+ "defaultMessage": "Teacher resources",
+ "description": "Title for the teacher resources row"
+ },
"terms-of-use": {
"defaultMessage": "利用規約",
"description": "Terms of use menu option text"
@@ -1098,6 +1326,10 @@
"defaultMessage": "保存された hex ファイルをmicro:bitに転送する",
"description": "Title for the transfer hex dialog"
},
+ "troubleshooting-resource-title": {
+ "defaultMessage": "Troubleshooting",
+ "description": "Title for the troubleshooting help card"
+ },
"try-again-action": {
"defaultMessage": "もう一度やり直す",
"description": "Try again button text"
@@ -1130,6 +1362,10 @@
"defaultMessage": "ユーザーガイド",
"description": "Menu item for link to user guide site"
},
+ "view-all-projects": {
+ "defaultMessage": "View all projects",
+ "description": "Link/card to view the full projects list"
+ },
"visit-dot-org": {
"defaultMessage": "microbit.orgにアクセスします(新しいタブで開きます)",
"description": "alt text for logo link to .org"
diff --git a/lang/ui.ko.json b/lang/ui.ko.json
index ac6d9ccc0..3b304fb0c 100644
--- a/lang/ui.ko.json
+++ b/lang/ui.ko.json
@@ -27,6 +27,18 @@
"defaultMessage": "접근성",
"description": "Menu item for link to accessibility site"
},
+ "accessibility-resource-title": {
+ "defaultMessage": "Accessibility",
+ "description": "Title for the accessibility help card"
+ },
+ "add-files-action": {
+ "defaultMessage": "Add file(s)",
+ "description": "Button to add files to the current project"
+ },
+ "add-files-hover": {
+ "defaultMessage": "Add files to this project",
+ "description": "Tooltip for the add files button"
+ },
"added-change": {
"defaultMessage": "{changeName} 파일 추가됨",
"description": "Change made to file"
@@ -71,6 +83,18 @@
"defaultMessage": "취소",
"description": "Cancel button text"
},
+ "carousel-role": {
+ "defaultMessage": "carousel",
+ "description": "Accessible role description for a carousel"
+ },
+ "carousel-slide-label": {
+ "defaultMessage": "{slideNum} of {totalSlides}",
+ "description": "Accessible label for a carousel slide"
+ },
+ "carousel-slide-role": {
+ "defaultMessage": "slide",
+ "description": "Accessible role description for a carousel slide"
+ },
"change-files": {
"defaultMessage": "파일을 변경하시겠습니까?",
"description": "Header for dialog of confirmation of files changed"
@@ -227,10 +251,22 @@
"defaultMessage": "파일 생성",
"description": "Button text for action that creates a new blank Python file in the current project"
},
+ "create-project-action": {
+ "defaultMessage": "Create",
+ "description": "Create project button"
+ },
+ "create-project-dialog-heading": {
+ "defaultMessage": "Name your project",
+ "description": "Heading for the create project dialog"
+ },
"create-python": {
"defaultMessage": "이 프로젝트 안에서 새로운 Python 파일 생성",
"description": "Hover and dialog title when creating a new Python file"
},
+ "createai-taster-lessons-resource-title": {
+ "defaultMessage": "Taster lessons",
+ "description": "Title for a lesson card (placeholder)"
+ },
"created-file": {
"defaultMessage": "{filename} 생성됨",
"description": "Action feedback for creating a file"
@@ -243,6 +279,26 @@
"defaultMessage": "{name} 삭제",
"description": "Menu option to delete file"
},
+ "delete-project-action": {
+ "defaultMessage": "Delete",
+ "description": "Delete project menu item/button"
+ },
+ "delete-project-confirm-heading": {
+ "defaultMessage": "Delete project",
+ "description": "Heading for the delete project confirmation dialog"
+ },
+ "delete-project-confirm-text": {
+ "defaultMessage": "Are you sure you want to delete ‘{project}’? This cannot be undone.",
+ "description": "Body text for the delete project confirmation dialog"
+ },
+ "delete-projects-confirm-heading": {
+ "defaultMessage": "Delete projects",
+ "description": "Heading for the delete multiple projects confirmation dialog"
+ },
+ "delete-projects-confirm-text": {
+ "defaultMessage": "Are you sure you want to delete {numProjects} projects? This cannot be undone.",
+ "description": "Body for the delete multiple projects confirmation dialog"
+ },
"deleted-file": {
"defaultMessage": "{filename} 삭제됨",
"description": "Confirmation message that file got deleted"
@@ -263,6 +319,14 @@
"defaultMessage": "드래그 & 드롭",
"description": "Draggable code hover text"
},
+ "duplicate-project-action": {
+ "defaultMessage": "Duplicate",
+ "description": "Duplicate project button/menu item"
+ },
+ "duplicate-project-heading": {
+ "defaultMessage": "Name your project",
+ "description": "Heading for the duplicate project dialog"
+ },
"edit-file-action": {
"defaultMessage": "{name} 편집",
"description": "Menu option to edit file"
@@ -315,6 +379,14 @@
"defaultMessage": "이름에 띄어쓰기를 포함할 수 없습니다",
"description": "Warning text for new Python file name with whitespace"
},
+ "files-tab": {
+ "defaultMessage": "Files",
+ "description": "Sidebar tab label for the project files"
+ },
+ "files-tab-description": {
+ "defaultMessage": "Manage your project files",
+ "description": "Subheading for the Files sidebar tab"
+ },
"firmware-update-link": {
"defaultMessage": "이 micro:bit에 연결하기 전에 펌웨어를 업데이트해야 합니다.",
"description": "Text in the firmware update dialog"
@@ -327,6 +399,10 @@
"defaultMessage": "펌웨어 업데이트 필요",
"description": "Title for the firmware update dialog"
},
+ "first-lessons-with-python-resource-title": {
+ "defaultMessage": "First lessons with Python and the micro:bit",
+ "description": "Title for a lesson card"
+ },
"flash-action": {
"defaultMessage": "프로그램 업로드",
"description": "Text for flash button"
@@ -359,6 +435,14 @@
"defaultMessage": "도움 및 지원",
"description": "Help menu label"
},
+ "help-resources-row-carousel": {
+ "defaultMessage": "Help and support",
+ "description": "Accessible name for the help and support carousel"
+ },
+ "help-resources-row-title": {
+ "defaultMessage": "Help and support",
+ "description": "Title for the help and support row"
+ },
"help-support": {
"defaultMessage": "도움말 및 지원",
"description": "Menu item for link to support site"
@@ -383,6 +467,22 @@
"defaultMessage": "단순",
"description": "Highlight code structure option"
},
+ "home-action": {
+ "defaultMessage": "Home",
+ "description": "Aria label for the home button that returns to the project list"
+ },
+ "homepage-banner-heading": {
+ "defaultMessage": "Code your BBC micro:bit with Python",
+ "description": "Home page banner heading"
+ },
+ "homepage-banner-subtitle": {
+ "defaultMessage": "Create, edit and flash MicroPython programs to your micro:bit.",
+ "description": "Home page banner subtitle"
+ },
+ "homepage-title": {
+ "defaultMessage": "micro:bit Python Editor",
+ "description": "Application name shown in the home page header"
+ },
"ideas-tab": {
"defaultMessage": "아이디어들",
"description": "Ideas tab button text. Tab shows programs to give students ideas."
@@ -391,6 +491,10 @@
"defaultMessage": "다양한 프로젝트를 체험해보고 수정하며 아이디어를 얻어보세요",
"description": "Ideas tab description text. Tab shows programs to give students ideas."
},
+ "import-file-action": {
+ "defaultMessage": "Import",
+ "description": "Button to import a project file (hex)"
+ },
"insert-code-action": {
"defaultMessage": "코드 삽입"
},
@@ -398,6 +502,10 @@
"defaultMessage": "언어 선택",
"description": "Language option text"
},
+ "learn-more-action": {
+ "defaultMessage": "Learn more",
+ "description": "Learn more button on the home page banner"
+ },
"less-action": {
"defaultMessage": "간단히 보기",
"description": "Less button text (showing less content)"
@@ -474,6 +582,14 @@
"defaultMessage": "경고: main.py만 다운로드됨",
"description": "Title of dialog shown when multiple files are available for download but only the main file downloaded."
},
+ "my-projects-row-carousel": {
+ "defaultMessage": "Your projects",
+ "description": "Accessible name for the your projects carousel"
+ },
+ "my-projects-row-title": {
+ "defaultMessage": "Your projects",
+ "description": "Title for the your projects row"
+ },
"name-project": {
"defaultMessage": "프로젝트 이름을 지정하세요",
"description": "Name your project header"
@@ -490,10 +606,18 @@
"defaultMessage": "프로그램이 .py 확장자를 추가합니다.",
"description": "Hint shown in the new Python file dialog"
},
+ "new-project-action": {
+ "defaultMessage": "New project",
+ "description": "New project card action"
+ },
"next-action": {
"defaultMessage": "다음",
"description": "Next button text"
},
+ "no-projects": {
+ "defaultMessage": "No projects found",
+ "description": "Shown when a project search returns nothing"
+ },
"not-found-checklist-one": {
"defaultMessage": " micro:bit이 연결되었나요? 다음 단계를 따르셨나요?",
"description": "Checklist text in the no micro:bit found dialog"
@@ -538,6 +662,10 @@
"defaultMessage": "Hex 또는 Python 파일을 열거나 다른 파일을 추가하세요",
"description": "Hover text over load button"
},
+ "open-project-action": {
+ "defaultMessage": "Open",
+ "description": "Open project menu item"
+ },
"options": {
"defaultMessage": "옵션",
"description": "Label for an options menu"
@@ -586,10 +714,54 @@
"defaultMessage": "프로젝트 동작",
"description": "Aria label for the bar with project actions"
},
+ "project-file-count": {
+ "defaultMessage": "{count, plural, one {# file} other {# files}}",
+ "description": "Number of files in a project"
+ },
"project-header": {
"defaultMessage": "프로젝트 머리글",
"description": "Aria label for the project header area"
},
+ "project-idea-animated-animals-title": {
+ "defaultMessage": "Animated animals",
+ "description": "Title for a make it, code it project idea card"
+ },
+ "project-idea-beating-heart-title": {
+ "defaultMessage": "Beating heart",
+ "description": "Title for a make it, code it project idea card"
+ },
+ "project-idea-emotion-badge-title": {
+ "defaultMessage": "Emotion badge",
+ "description": "Title for a make it, code it project idea card"
+ },
+ "project-idea-flashing-emotions-title": {
+ "defaultMessage": "Flashing emotions",
+ "description": "Title for a make it, code it project idea card"
+ },
+ "project-idea-get-silly-title": {
+ "defaultMessage": "Get silly",
+ "description": "Title for a make it, code it project idea card"
+ },
+ "project-idea-heart-title": {
+ "defaultMessage": "Heart",
+ "description": "Title for a make it, code it project idea card"
+ },
+ "project-ideas-row-carousel": {
+ "defaultMessage": "Project ideas",
+ "description": "Accessible name for the project ideas carousel"
+ },
+ "project-ideas-row-title": {
+ "defaultMessage": "Project ideas",
+ "description": "Title for the project ideas row"
+ },
+ "project-loaded": {
+ "defaultMessage": "Project loaded",
+ "description": "Toast shown after a project is loaded from a dropped hex file"
+ },
+ "project-menu-action": {
+ "defaultMessage": "Actions for project ‘{name}’",
+ "description": "Aria label for the per-project actions menu button"
+ },
"project-name": {
"defaultMessage": "프로젝트 이름",
"description": "Text used to indicate the project name"
@@ -598,6 +770,10 @@
"defaultMessage": "프로젝트 이름을 입력해야 합니다",
"description": "Validation message for project name"
},
+ "project-skip-to-toolbar": {
+ "defaultMessage": "Skip to selection actions",
+ "description": "Accessible skip link from a selected project card to the toolbar"
+ },
"project-tab": {
"defaultMessage": "프로젝트",
"description": "Project tab button text"
@@ -606,6 +782,10 @@
"defaultMessage": "프로젝트에서 파일을 확인하고, 생성하고, 추가하고 편집할 수 있습니다",
"description": "Project tab description"
},
+ "projects-page-title": {
+ "defaultMessage": "Projects",
+ "description": "Title of the projects page"
+ },
"python-powered": {
"defaultMessage": "Python powered",
"description": "Python powered logo alt text"
@@ -634,6 +814,14 @@
"defaultMessage": "참조",
"description": "Reference tab button text"
},
+ "rename-project-action": {
+ "defaultMessage": "Rename",
+ "description": "Rename project button/menu item"
+ },
+ "rename-project-heading": {
+ "defaultMessage": "Rename project",
+ "description": "Heading for the rename project dialog"
+ },
"replace-action-label": {
"defaultMessage": "교체",
"description": "Action label for replacing project dialog"
@@ -678,6 +866,14 @@
"defaultMessage": "찾기",
"description": "Aria label for searching documentation"
},
+ "select-project-action": {
+ "defaultMessage": "Select project ‘{name}’",
+ "description": "Accessible label for the per-project selection checkbox"
+ },
+ "selection-actions-group": {
+ "defaultMessage": "Actions for selected projects",
+ "description": "Accessible label for the selection toolbar"
+ },
"send-action": {
"defaultMessage": "micro:bit로 전송",
"description": "Send to micro:bit button text"
@@ -1050,6 +1246,30 @@
"defaultMessage": "소프트웨어 버전",
"description": "Heading for a table of software versions in the about dialog"
},
+ "sort-option-last-modified": {
+ "defaultMessage": "Last modified",
+ "description": "Sort projects by last modified date"
+ },
+ "sort-option-name": {
+ "defaultMessage": "Name",
+ "description": "Sort projects by name"
+ },
+ "sort-option-relevance": {
+ "defaultMessage": "Relevance",
+ "description": "Sort projects by search relevance"
+ },
+ "sort-order-ascending-label": {
+ "defaultMessage": "Sort ascending",
+ "description": "Accessible label to toggle to ascending sort order"
+ },
+ "sort-order-descending-label": {
+ "defaultMessage": "Sort descending",
+ "description": "Accessible label to toggle to descending sort order"
+ },
+ "sort-select-label": {
+ "defaultMessage": "Sort projects by",
+ "description": "Accessible label for the project sort dropdown"
+ },
"start-coding-action": {
"defaultMessage": "코딩 시작",
"description": "Start coding button text"
@@ -1058,6 +1278,14 @@
"defaultMessage": "지원",
"description": "Support menu option text"
},
+ "teacher-resources-row-carousel": {
+ "defaultMessage": "Teacher resources",
+ "description": "Accessible name for the teacher resources carousel"
+ },
+ "teacher-resources-row-title": {
+ "defaultMessage": "Teacher resources",
+ "description": "Title for the teacher resources row"
+ },
"terms-of-use": {
"defaultMessage": "이용 약관",
"description": "Terms of use menu option text"
@@ -1098,6 +1326,10 @@
"defaultMessage": "저장된 hex 파일을 micro:bit으로 전송",
"description": "Title for the transfer hex dialog"
},
+ "troubleshooting-resource-title": {
+ "defaultMessage": "Troubleshooting",
+ "description": "Title for the troubleshooting help card"
+ },
"try-again-action": {
"defaultMessage": "다시 시도",
"description": "Try again button text"
@@ -1130,6 +1362,10 @@
"defaultMessage": "사용자 가이드",
"description": "Menu item for link to user guide site"
},
+ "view-all-projects": {
+ "defaultMessage": "View all projects",
+ "description": "Link/card to view the full projects list"
+ },
"visit-dot-org": {
"defaultMessage": "microbit.org 방문(새 탭에서 열기)",
"description": "alt text for logo link to .org"
diff --git a/lang/ui.lol.json b/lang/ui.lol.json
index 0a92d9142..437d6e2e5 100644
--- a/lang/ui.lol.json
+++ b/lang/ui.lol.json
@@ -27,6 +27,18 @@
"defaultMessage": "crwdns364038:0crwdne364038:0",
"description": "Menu item for link to accessibility site"
},
+ "accessibility-resource-title": {
+ "defaultMessage": "Accessibility",
+ "description": "Title for the accessibility help card"
+ },
+ "add-files-action": {
+ "defaultMessage": "Add file(s)",
+ "description": "Button to add files to the current project"
+ },
+ "add-files-hover": {
+ "defaultMessage": "Add files to this project",
+ "description": "Tooltip for the add files button"
+ },
"added-change": {
"defaultMessage": "crwdns331368:0{changeName}crwdne331368:0",
"description": "Change made to file"
@@ -71,6 +83,18 @@
"defaultMessage": "crwdns331388:0crwdne331388:0",
"description": "Cancel button text"
},
+ "carousel-role": {
+ "defaultMessage": "carousel",
+ "description": "Accessible role description for a carousel"
+ },
+ "carousel-slide-label": {
+ "defaultMessage": "{slideNum} of {totalSlides}",
+ "description": "Accessible label for a carousel slide"
+ },
+ "carousel-slide-role": {
+ "defaultMessage": "slide",
+ "description": "Accessible role description for a carousel slide"
+ },
"change-files": {
"defaultMessage": "crwdns331390:0crwdne331390:0",
"description": "Header for dialog of confirmation of files changed"
@@ -227,10 +251,22 @@
"defaultMessage": "crwdns331462:0crwdne331462:0",
"description": "Button text for action that creates a new blank Python file in the current project"
},
+ "create-project-action": {
+ "defaultMessage": "Create",
+ "description": "Create project button"
+ },
+ "create-project-dialog-heading": {
+ "defaultMessage": "Name your project",
+ "description": "Heading for the create project dialog"
+ },
"create-python": {
"defaultMessage": "crwdns331464:0crwdne331464:0",
"description": "Hover and dialog title when creating a new Python file"
},
+ "createai-taster-lessons-resource-title": {
+ "defaultMessage": "Taster lessons",
+ "description": "Title for a lesson card (placeholder)"
+ },
"created-file": {
"defaultMessage": "crwdns331466:0{filename}crwdne331466:0",
"description": "Action feedback for creating a file"
@@ -243,6 +279,26 @@
"defaultMessage": "crwdns331470:0{name}crwdne331470:0",
"description": "Menu option to delete file"
},
+ "delete-project-action": {
+ "defaultMessage": "Delete",
+ "description": "Delete project menu item/button"
+ },
+ "delete-project-confirm-heading": {
+ "defaultMessage": "Delete project",
+ "description": "Heading for the delete project confirmation dialog"
+ },
+ "delete-project-confirm-text": {
+ "defaultMessage": "Are you sure you want to delete ‘{project}’? This cannot be undone.",
+ "description": "Body text for the delete project confirmation dialog"
+ },
+ "delete-projects-confirm-heading": {
+ "defaultMessage": "Delete projects",
+ "description": "Heading for the delete multiple projects confirmation dialog"
+ },
+ "delete-projects-confirm-text": {
+ "defaultMessage": "Are you sure you want to delete {numProjects} projects? This cannot be undone.",
+ "description": "Body for the delete multiple projects confirmation dialog"
+ },
"deleted-file": {
"defaultMessage": "crwdns331472:0{filename}crwdne331472:0",
"description": "Confirmation message that file got deleted"
@@ -263,6 +319,14 @@
"defaultMessage": "crwdns331480:0crwdne331480:0",
"description": "Draggable code hover text"
},
+ "duplicate-project-action": {
+ "defaultMessage": "Duplicate",
+ "description": "Duplicate project button/menu item"
+ },
+ "duplicate-project-heading": {
+ "defaultMessage": "Name your project",
+ "description": "Heading for the duplicate project dialog"
+ },
"edit-file-action": {
"defaultMessage": "crwdns331482:0{name}crwdne331482:0",
"description": "Menu option to edit file"
@@ -315,6 +379,14 @@
"defaultMessage": "crwdns331506:0crwdne331506:0",
"description": "Warning text for new Python file name with whitespace"
},
+ "files-tab": {
+ "defaultMessage": "Files",
+ "description": "Sidebar tab label for the project files"
+ },
+ "files-tab-description": {
+ "defaultMessage": "Manage your project files",
+ "description": "Subheading for the Files sidebar tab"
+ },
"firmware-update-link": {
"defaultMessage": "crwdns331508:0crwdne331508:0",
"description": "Text in the firmware update dialog"
@@ -327,6 +399,10 @@
"defaultMessage": "crwdns331512:0crwdne331512:0",
"description": "Title for the firmware update dialog"
},
+ "first-lessons-with-python-resource-title": {
+ "defaultMessage": "First lessons with Python and the micro:bit",
+ "description": "Title for a lesson card"
+ },
"flash-action": {
"defaultMessage": "crwdns331514:0crwdne331514:0",
"description": "Text for flash button"
@@ -359,6 +435,14 @@
"defaultMessage": "crwdns331528:0crwdne331528:0",
"description": "Help menu label"
},
+ "help-resources-row-carousel": {
+ "defaultMessage": "Help and support",
+ "description": "Accessible name for the help and support carousel"
+ },
+ "help-resources-row-title": {
+ "defaultMessage": "Help and support",
+ "description": "Title for the help and support row"
+ },
"help-support": {
"defaultMessage": "crwdns331530:0crwdne331530:0",
"description": "Menu item for link to support site"
@@ -383,6 +467,22 @@
"defaultMessage": "crwdns331540:0crwdne331540:0",
"description": "Highlight code structure option"
},
+ "home-action": {
+ "defaultMessage": "Home",
+ "description": "Aria label for the home button that returns to the project list"
+ },
+ "homepage-banner-heading": {
+ "defaultMessage": "Code your BBC micro:bit with Python",
+ "description": "Home page banner heading"
+ },
+ "homepage-banner-subtitle": {
+ "defaultMessage": "Create, edit and flash MicroPython programs to your micro:bit.",
+ "description": "Home page banner subtitle"
+ },
+ "homepage-title": {
+ "defaultMessage": "micro:bit Python Editor",
+ "description": "Application name shown in the home page header"
+ },
"ideas-tab": {
"defaultMessage": "crwdns331542:0crwdne331542:0",
"description": "Ideas tab button text. Tab shows programs to give students ideas."
@@ -391,6 +491,10 @@
"defaultMessage": "crwdns331544:0crwdne331544:0",
"description": "Ideas tab description text. Tab shows programs to give students ideas."
},
+ "import-file-action": {
+ "defaultMessage": "Import",
+ "description": "Button to import a project file (hex)"
+ },
"insert-code-action": {
"defaultMessage": "crwdns331546:0crwdne331546:0"
},
@@ -398,6 +502,10 @@
"defaultMessage": "crwdns331548:0crwdne331548:0",
"description": "Language option text"
},
+ "learn-more-action": {
+ "defaultMessage": "Learn more",
+ "description": "Learn more button on the home page banner"
+ },
"less-action": {
"defaultMessage": "crwdns331550:0crwdne331550:0",
"description": "Less button text (showing less content)"
@@ -474,6 +582,14 @@
"defaultMessage": "crwdns331586:0crwdne331586:0",
"description": "Title of dialog shown when multiple files are available for download but only the main file downloaded."
},
+ "my-projects-row-carousel": {
+ "defaultMessage": "Your projects",
+ "description": "Accessible name for the your projects carousel"
+ },
+ "my-projects-row-title": {
+ "defaultMessage": "Your projects",
+ "description": "Title for the your projects row"
+ },
"name-project": {
"defaultMessage": "crwdns331588:0crwdne331588:0",
"description": "Name your project header"
@@ -490,10 +606,18 @@
"defaultMessage": "crwdns331594:0crwdne331594:0",
"description": "Hint shown in the new Python file dialog"
},
+ "new-project-action": {
+ "defaultMessage": "New project",
+ "description": "New project card action"
+ },
"next-action": {
"defaultMessage": "crwdns331596:0crwdne331596:0",
"description": "Next button text"
},
+ "no-projects": {
+ "defaultMessage": "No projects found",
+ "description": "Shown when a project search returns nothing"
+ },
"not-found-checklist-one": {
"defaultMessage": "crwdns331598:0crwdne331598:0",
"description": "Checklist text in the no micro:bit found dialog"
@@ -538,6 +662,10 @@
"defaultMessage": "crwdns331616:0crwdne331616:0",
"description": "Hover text over load button"
},
+ "open-project-action": {
+ "defaultMessage": "Open",
+ "description": "Open project menu item"
+ },
"options": {
"defaultMessage": "crwdns331618:0crwdne331618:0",
"description": "Label for an options menu"
@@ -586,10 +714,54 @@
"defaultMessage": "crwdns331638:0crwdne331638:0",
"description": "Aria label for the bar with project actions"
},
+ "project-file-count": {
+ "defaultMessage": "{count, plural, one {# file} other {# files}}",
+ "description": "Number of files in a project"
+ },
"project-header": {
"defaultMessage": "crwdns331640:0crwdne331640:0",
"description": "Aria label for the project header area"
},
+ "project-idea-animated-animals-title": {
+ "defaultMessage": "Animated animals",
+ "description": "Title for a make it, code it project idea card"
+ },
+ "project-idea-beating-heart-title": {
+ "defaultMessage": "Beating heart",
+ "description": "Title for a make it, code it project idea card"
+ },
+ "project-idea-emotion-badge-title": {
+ "defaultMessage": "Emotion badge",
+ "description": "Title for a make it, code it project idea card"
+ },
+ "project-idea-flashing-emotions-title": {
+ "defaultMessage": "Flashing emotions",
+ "description": "Title for a make it, code it project idea card"
+ },
+ "project-idea-get-silly-title": {
+ "defaultMessage": "Get silly",
+ "description": "Title for a make it, code it project idea card"
+ },
+ "project-idea-heart-title": {
+ "defaultMessage": "Heart",
+ "description": "Title for a make it, code it project idea card"
+ },
+ "project-ideas-row-carousel": {
+ "defaultMessage": "Project ideas",
+ "description": "Accessible name for the project ideas carousel"
+ },
+ "project-ideas-row-title": {
+ "defaultMessage": "Project ideas",
+ "description": "Title for the project ideas row"
+ },
+ "project-loaded": {
+ "defaultMessage": "Project loaded",
+ "description": "Toast shown after a project is loaded from a dropped hex file"
+ },
+ "project-menu-action": {
+ "defaultMessage": "Actions for project ‘{name}’",
+ "description": "Aria label for the per-project actions menu button"
+ },
"project-name": {
"defaultMessage": "crwdns331642:0crwdne331642:0",
"description": "Text used to indicate the project name"
@@ -598,6 +770,10 @@
"defaultMessage": "crwdns331644:0crwdne331644:0",
"description": "Validation message for project name"
},
+ "project-skip-to-toolbar": {
+ "defaultMessage": "Skip to selection actions",
+ "description": "Accessible skip link from a selected project card to the toolbar"
+ },
"project-tab": {
"defaultMessage": "crwdns331646:0crwdne331646:0",
"description": "Project tab button text"
@@ -606,6 +782,10 @@
"defaultMessage": "crwdns331648:0crwdne331648:0",
"description": "Project tab description"
},
+ "projects-page-title": {
+ "defaultMessage": "Projects",
+ "description": "Title of the projects page"
+ },
"python-powered": {
"defaultMessage": "crwdns331650:0crwdne331650:0",
"description": "Python powered logo alt text"
@@ -634,6 +814,14 @@
"defaultMessage": "crwdns331662:0crwdne331662:0",
"description": "Reference tab button text"
},
+ "rename-project-action": {
+ "defaultMessage": "Rename",
+ "description": "Rename project button/menu item"
+ },
+ "rename-project-heading": {
+ "defaultMessage": "Rename project",
+ "description": "Heading for the rename project dialog"
+ },
"replace-action-label": {
"defaultMessage": "crwdns331664:0crwdne331664:0",
"description": "Action label for replacing project dialog"
@@ -678,6 +866,14 @@
"defaultMessage": "crwdns331684:0crwdne331684:0",
"description": "Aria label for searching documentation"
},
+ "select-project-action": {
+ "defaultMessage": "Select project ‘{name}’",
+ "description": "Accessible label for the per-project selection checkbox"
+ },
+ "selection-actions-group": {
+ "defaultMessage": "Actions for selected projects",
+ "description": "Accessible label for the selection toolbar"
+ },
"send-action": {
"defaultMessage": "crwdns331686:0crwdne331686:0",
"description": "Send to micro:bit button text"
@@ -1050,6 +1246,30 @@
"defaultMessage": "crwdns331742:0crwdne331742:0",
"description": "Heading for a table of software versions in the about dialog"
},
+ "sort-option-last-modified": {
+ "defaultMessage": "Last modified",
+ "description": "Sort projects by last modified date"
+ },
+ "sort-option-name": {
+ "defaultMessage": "Name",
+ "description": "Sort projects by name"
+ },
+ "sort-option-relevance": {
+ "defaultMessage": "Relevance",
+ "description": "Sort projects by search relevance"
+ },
+ "sort-order-ascending-label": {
+ "defaultMessage": "Sort ascending",
+ "description": "Accessible label to toggle to ascending sort order"
+ },
+ "sort-order-descending-label": {
+ "defaultMessage": "Sort descending",
+ "description": "Accessible label to toggle to descending sort order"
+ },
+ "sort-select-label": {
+ "defaultMessage": "Sort projects by",
+ "description": "Accessible label for the project sort dropdown"
+ },
"start-coding-action": {
"defaultMessage": "crwdns331744:0crwdne331744:0",
"description": "Start coding button text"
@@ -1058,6 +1278,14 @@
"defaultMessage": "crwdns331746:0crwdne331746:0",
"description": "Support menu option text"
},
+ "teacher-resources-row-carousel": {
+ "defaultMessage": "Teacher resources",
+ "description": "Accessible name for the teacher resources carousel"
+ },
+ "teacher-resources-row-title": {
+ "defaultMessage": "Teacher resources",
+ "description": "Title for the teacher resources row"
+ },
"terms-of-use": {
"defaultMessage": "crwdns331748:0crwdne331748:0",
"description": "Terms of use menu option text"
@@ -1098,6 +1326,10 @@
"defaultMessage": "crwdns331768:0crwdne331768:0",
"description": "Title for the transfer hex dialog"
},
+ "troubleshooting-resource-title": {
+ "defaultMessage": "Troubleshooting",
+ "description": "Title for the troubleshooting help card"
+ },
"try-again-action": {
"defaultMessage": "crwdns331770:0crwdne331770:0",
"description": "Try again button text"
@@ -1130,6 +1362,10 @@
"defaultMessage": "crwdns364040:0crwdne364040:0",
"description": "Menu item for link to user guide site"
},
+ "view-all-projects": {
+ "defaultMessage": "View all projects",
+ "description": "Link/card to view the full projects list"
+ },
"visit-dot-org": {
"defaultMessage": "crwdns331784:0crwdne331784:0",
"description": "alt text for logo link to .org"
diff --git a/lang/ui.nl.json b/lang/ui.nl.json
index 902e56e7c..f124b0e47 100644
--- a/lang/ui.nl.json
+++ b/lang/ui.nl.json
@@ -27,6 +27,18 @@
"defaultMessage": "Toegankelijkheid",
"description": "Menu item for link to accessibility site"
},
+ "accessibility-resource-title": {
+ "defaultMessage": "Accessibility",
+ "description": "Title for the accessibility help card"
+ },
+ "add-files-action": {
+ "defaultMessage": "Add file(s)",
+ "description": "Button to add files to the current project"
+ },
+ "add-files-hover": {
+ "defaultMessage": "Add files to this project",
+ "description": "Tooltip for the add files button"
+ },
"added-change": {
"defaultMessage": "Toegevoegd bestand {changeName}",
"description": "Change made to file"
@@ -71,6 +83,18 @@
"defaultMessage": "Annuleren",
"description": "Cancel button text"
},
+ "carousel-role": {
+ "defaultMessage": "carousel",
+ "description": "Accessible role description for a carousel"
+ },
+ "carousel-slide-label": {
+ "defaultMessage": "{slideNum} of {totalSlides}",
+ "description": "Accessible label for a carousel slide"
+ },
+ "carousel-slide-role": {
+ "defaultMessage": "slide",
+ "description": "Accessible role description for a carousel slide"
+ },
"change-files": {
"defaultMessage": "Bestanden wijzigen?",
"description": "Header for dialog of confirmation of files changed"
@@ -227,10 +251,22 @@
"defaultMessage": "Bestand aanmaken",
"description": "Button text for action that creates a new blank Python file in the current project"
},
+ "create-project-action": {
+ "defaultMessage": "Create",
+ "description": "Create project button"
+ },
+ "create-project-dialog-heading": {
+ "defaultMessage": "Name your project",
+ "description": "Heading for the create project dialog"
+ },
"create-python": {
"defaultMessage": "Maak een nieuw Python bestand aan in dit project",
"description": "Hover and dialog title when creating a new Python file"
},
+ "createai-taster-lessons-resource-title": {
+ "defaultMessage": "Taster lessons",
+ "description": "Title for a lesson card (placeholder)"
+ },
"created-file": {
"defaultMessage": "Aangemaakt {filename}",
"description": "Action feedback for creating a file"
@@ -243,6 +279,26 @@
"defaultMessage": "Wissen {name}",
"description": "Menu option to delete file"
},
+ "delete-project-action": {
+ "defaultMessage": "Delete",
+ "description": "Delete project menu item/button"
+ },
+ "delete-project-confirm-heading": {
+ "defaultMessage": "Delete project",
+ "description": "Heading for the delete project confirmation dialog"
+ },
+ "delete-project-confirm-text": {
+ "defaultMessage": "Are you sure you want to delete ‘{project}’? This cannot be undone.",
+ "description": "Body text for the delete project confirmation dialog"
+ },
+ "delete-projects-confirm-heading": {
+ "defaultMessage": "Delete projects",
+ "description": "Heading for the delete multiple projects confirmation dialog"
+ },
+ "delete-projects-confirm-text": {
+ "defaultMessage": "Are you sure you want to delete {numProjects} projects? This cannot be undone.",
+ "description": "Body for the delete multiple projects confirmation dialog"
+ },
"deleted-file": {
"defaultMessage": "Verwijderd {filename}",
"description": "Confirmation message that file got deleted"
@@ -263,6 +319,14 @@
"defaultMessage": "Slepen en neerzetten",
"description": "Draggable code hover text"
},
+ "duplicate-project-action": {
+ "defaultMessage": "Duplicate",
+ "description": "Duplicate project button/menu item"
+ },
+ "duplicate-project-heading": {
+ "defaultMessage": "Name your project",
+ "description": "Heading for the duplicate project dialog"
+ },
"edit-file-action": {
"defaultMessage": "{name} bewerken",
"description": "Menu option to edit file"
@@ -315,6 +379,14 @@
"defaultMessage": "De naam mag geen spaties bevatten",
"description": "Warning text for new Python file name with whitespace"
},
+ "files-tab": {
+ "defaultMessage": "Files",
+ "description": "Sidebar tab label for the project files"
+ },
+ "files-tab-description": {
+ "defaultMessage": "Manage your project files",
+ "description": "Subheading for the Files sidebar tab"
+ },
"firmware-update-link": {
"defaultMessage": "Je moet firmware updaten voordat je verbinding kan maken met deze micro:bit.",
"description": "Text in the firmware update dialog"
@@ -327,6 +399,10 @@
"defaultMessage": "Firmware update vereist",
"description": "Title for the firmware update dialog"
},
+ "first-lessons-with-python-resource-title": {
+ "defaultMessage": "First lessons with Python and the micro:bit",
+ "description": "Title for a lesson card"
+ },
"flash-action": {
"defaultMessage": "Flash",
"description": "Text for flash button"
@@ -359,6 +435,14 @@
"defaultMessage": "Help",
"description": "Help menu label"
},
+ "help-resources-row-carousel": {
+ "defaultMessage": "Help and support",
+ "description": "Accessible name for the help and support carousel"
+ },
+ "help-resources-row-title": {
+ "defaultMessage": "Help and support",
+ "description": "Title for the help and support row"
+ },
"help-support": {
"defaultMessage": "Hulp & Ondersteuning",
"description": "Menu item for link to support site"
@@ -383,6 +467,22 @@
"defaultMessage": "Eenvoudig",
"description": "Highlight code structure option"
},
+ "home-action": {
+ "defaultMessage": "Home",
+ "description": "Aria label for the home button that returns to the project list"
+ },
+ "homepage-banner-heading": {
+ "defaultMessage": "Code your BBC micro:bit with Python",
+ "description": "Home page banner heading"
+ },
+ "homepage-banner-subtitle": {
+ "defaultMessage": "Create, edit and flash MicroPython programs to your micro:bit.",
+ "description": "Home page banner subtitle"
+ },
+ "homepage-title": {
+ "defaultMessage": "micro:bit Python Editor",
+ "description": "Application name shown in the home page header"
+ },
"ideas-tab": {
"defaultMessage": "Ideeën",
"description": "Ideas tab button text. Tab shows programs to give students ideas."
@@ -391,6 +491,10 @@
"defaultMessage": "Probeer deze projecten uit, verander ze en laat je inspireren",
"description": "Ideas tab description text. Tab shows programs to give students ideas."
},
+ "import-file-action": {
+ "defaultMessage": "Import",
+ "description": "Button to import a project file (hex)"
+ },
"insert-code-action": {
"defaultMessage": "Code invoegen"
},
@@ -398,6 +502,10 @@
"defaultMessage": "Taal",
"description": "Language option text"
},
+ "learn-more-action": {
+ "defaultMessage": "Learn more",
+ "description": "Learn more button on the home page banner"
+ },
"less-action": {
"defaultMessage": "Minder",
"description": "Less button text (showing less content)"
@@ -474,6 +582,14 @@
"defaultMessage": "Waarschuwing: Alleen main.py gedownload",
"description": "Title of dialog shown when multiple files are available for download but only the main file downloaded."
},
+ "my-projects-row-carousel": {
+ "defaultMessage": "Your projects",
+ "description": "Accessible name for the your projects carousel"
+ },
+ "my-projects-row-title": {
+ "defaultMessage": "Your projects",
+ "description": "Title for the your projects row"
+ },
"name-project": {
"defaultMessage": "Geef een naam aan je project",
"description": "Name your project header"
@@ -490,10 +606,18 @@
"defaultMessage": "We zullen de .py extensie voor je toevoegen.",
"description": "Hint shown in the new Python file dialog"
},
+ "new-project-action": {
+ "defaultMessage": "New project",
+ "description": "New project card action"
+ },
"next-action": {
"defaultMessage": "Volgende",
"description": "Next button text"
},
+ "no-projects": {
+ "defaultMessage": "No projects found",
+ "description": "Shown when a project search returns nothing"
+ },
"not-found-checklist-one": {
"defaultMessage": "Is je micro:bit aangesloten? Heb je deze stappen gevolgd?",
"description": "Checklist text in the no micro:bit found dialog"
@@ -538,6 +662,10 @@
"defaultMessage": "Open een hex of Python bestand of voeg andere bestanden toe",
"description": "Hover text over load button"
},
+ "open-project-action": {
+ "defaultMessage": "Open",
+ "description": "Open project menu item"
+ },
"options": {
"defaultMessage": "Opties",
"description": "Label for an options menu"
@@ -586,10 +714,54 @@
"defaultMessage": "Project acties",
"description": "Aria label for the bar with project actions"
},
+ "project-file-count": {
+ "defaultMessage": "{count, plural, one {# file} other {# files}}",
+ "description": "Number of files in a project"
+ },
"project-header": {
"defaultMessage": "Project koptekst",
"description": "Aria label for the project header area"
},
+ "project-idea-animated-animals-title": {
+ "defaultMessage": "Animated animals",
+ "description": "Title for a make it, code it project idea card"
+ },
+ "project-idea-beating-heart-title": {
+ "defaultMessage": "Beating heart",
+ "description": "Title for a make it, code it project idea card"
+ },
+ "project-idea-emotion-badge-title": {
+ "defaultMessage": "Emotion badge",
+ "description": "Title for a make it, code it project idea card"
+ },
+ "project-idea-flashing-emotions-title": {
+ "defaultMessage": "Flashing emotions",
+ "description": "Title for a make it, code it project idea card"
+ },
+ "project-idea-get-silly-title": {
+ "defaultMessage": "Get silly",
+ "description": "Title for a make it, code it project idea card"
+ },
+ "project-idea-heart-title": {
+ "defaultMessage": "Heart",
+ "description": "Title for a make it, code it project idea card"
+ },
+ "project-ideas-row-carousel": {
+ "defaultMessage": "Project ideas",
+ "description": "Accessible name for the project ideas carousel"
+ },
+ "project-ideas-row-title": {
+ "defaultMessage": "Project ideas",
+ "description": "Title for the project ideas row"
+ },
+ "project-loaded": {
+ "defaultMessage": "Project loaded",
+ "description": "Toast shown after a project is loaded from a dropped hex file"
+ },
+ "project-menu-action": {
+ "defaultMessage": "Actions for project ‘{name}’",
+ "description": "Aria label for the per-project actions menu button"
+ },
"project-name": {
"defaultMessage": "Projectnaam",
"description": "Text used to indicate the project name"
@@ -598,6 +770,10 @@
"defaultMessage": "De projectnaam kan niet leeg zijn",
"description": "Validation message for project name"
},
+ "project-skip-to-toolbar": {
+ "defaultMessage": "Skip to selection actions",
+ "description": "Accessible skip link from a selected project card to the toolbar"
+ },
"project-tab": {
"defaultMessage": "Project",
"description": "Project tab button text"
@@ -606,6 +782,10 @@
"defaultMessage": "Bekijk, aanmaken, toevoegen en bewerken van de bestanden in je project",
"description": "Project tab description"
},
+ "projects-page-title": {
+ "defaultMessage": "Projects",
+ "description": "Title of the projects page"
+ },
"python-powered": {
"defaultMessage": "Python actief",
"description": "Python powered logo alt text"
@@ -634,6 +814,14 @@
"defaultMessage": "Referentie",
"description": "Reference tab button text"
},
+ "rename-project-action": {
+ "defaultMessage": "Rename",
+ "description": "Rename project button/menu item"
+ },
+ "rename-project-heading": {
+ "defaultMessage": "Rename project",
+ "description": "Heading for the rename project dialog"
+ },
"replace-action-label": {
"defaultMessage": "Vervangen",
"description": "Action label for replacing project dialog"
@@ -678,6 +866,14 @@
"defaultMessage": "Zoeken",
"description": "Aria label for searching documentation"
},
+ "select-project-action": {
+ "defaultMessage": "Select project ‘{name}’",
+ "description": "Accessible label for the per-project selection checkbox"
+ },
+ "selection-actions-group": {
+ "defaultMessage": "Actions for selected projects",
+ "description": "Accessible label for the selection toolbar"
+ },
"send-action": {
"defaultMessage": "Stuur naar micro:bit",
"description": "Send to micro:bit button text"
@@ -1050,6 +1246,30 @@
"defaultMessage": "Software versies",
"description": "Heading for a table of software versions in the about dialog"
},
+ "sort-option-last-modified": {
+ "defaultMessage": "Last modified",
+ "description": "Sort projects by last modified date"
+ },
+ "sort-option-name": {
+ "defaultMessage": "Name",
+ "description": "Sort projects by name"
+ },
+ "sort-option-relevance": {
+ "defaultMessage": "Relevance",
+ "description": "Sort projects by search relevance"
+ },
+ "sort-order-ascending-label": {
+ "defaultMessage": "Sort ascending",
+ "description": "Accessible label to toggle to ascending sort order"
+ },
+ "sort-order-descending-label": {
+ "defaultMessage": "Sort descending",
+ "description": "Accessible label to toggle to descending sort order"
+ },
+ "sort-select-label": {
+ "defaultMessage": "Sort projects by",
+ "description": "Accessible label for the project sort dropdown"
+ },
"start-coding-action": {
"defaultMessage": "Start codering",
"description": "Start coding button text"
@@ -1058,6 +1278,14 @@
"defaultMessage": "Ondersteuning",
"description": "Support menu option text"
},
+ "teacher-resources-row-carousel": {
+ "defaultMessage": "Teacher resources",
+ "description": "Accessible name for the teacher resources carousel"
+ },
+ "teacher-resources-row-title": {
+ "defaultMessage": "Teacher resources",
+ "description": "Title for the teacher resources row"
+ },
"terms-of-use": {
"defaultMessage": "Gebruiksvoorwaarden",
"description": "Terms of use menu option text"
@@ -1098,6 +1326,10 @@
"defaultMessage": "Zet het opgeslagen hex-bestand over naar micro:bit",
"description": "Title for the transfer hex dialog"
},
+ "troubleshooting-resource-title": {
+ "defaultMessage": "Troubleshooting",
+ "description": "Title for the troubleshooting help card"
+ },
"try-again-action": {
"defaultMessage": "Probeer het opnieuw",
"description": "Try again button text"
@@ -1130,6 +1362,10 @@
"defaultMessage": "Gebruikershandleiding",
"description": "Menu item for link to user guide site"
},
+ "view-all-projects": {
+ "defaultMessage": "View all projects",
+ "description": "Link/card to view the full projects list"
+ },
"visit-dot-org": {
"defaultMessage": "bezoek microbit.org (opent in een nieuw tabblad)",
"description": "alt text for logo link to .org"
diff --git a/lang/ui.pl.json b/lang/ui.pl.json
index 8e6e38cc2..6d91e7014 100644
--- a/lang/ui.pl.json
+++ b/lang/ui.pl.json
@@ -27,6 +27,18 @@
"defaultMessage": "Dostępność",
"description": "Menu item for link to accessibility site"
},
+ "accessibility-resource-title": {
+ "defaultMessage": "Accessibility",
+ "description": "Title for the accessibility help card"
+ },
+ "add-files-action": {
+ "defaultMessage": "Add file(s)",
+ "description": "Button to add files to the current project"
+ },
+ "add-files-hover": {
+ "defaultMessage": "Add files to this project",
+ "description": "Tooltip for the add files button"
+ },
"added-change": {
"defaultMessage": "Dodany plik {changeName}",
"description": "Change made to file"
@@ -71,6 +83,18 @@
"defaultMessage": "Anuluj",
"description": "Cancel button text"
},
+ "carousel-role": {
+ "defaultMessage": "carousel",
+ "description": "Accessible role description for a carousel"
+ },
+ "carousel-slide-label": {
+ "defaultMessage": "{slideNum} of {totalSlides}",
+ "description": "Accessible label for a carousel slide"
+ },
+ "carousel-slide-role": {
+ "defaultMessage": "slide",
+ "description": "Accessible role description for a carousel slide"
+ },
"change-files": {
"defaultMessage": "Zmienić pliki?",
"description": "Header for dialog of confirmation of files changed"
@@ -227,10 +251,22 @@
"defaultMessage": "Utwórz plik",
"description": "Button text for action that creates a new blank Python file in the current project"
},
+ "create-project-action": {
+ "defaultMessage": "Create",
+ "description": "Create project button"
+ },
+ "create-project-dialog-heading": {
+ "defaultMessage": "Name your project",
+ "description": "Heading for the create project dialog"
+ },
"create-python": {
"defaultMessage": "Utwórz nowy plik Pythona w tym projekcie",
"description": "Hover and dialog title when creating a new Python file"
},
+ "createai-taster-lessons-resource-title": {
+ "defaultMessage": "Taster lessons",
+ "description": "Title for a lesson card (placeholder)"
+ },
"created-file": {
"defaultMessage": "Utworzono {filename}",
"description": "Action feedback for creating a file"
@@ -243,6 +279,26 @@
"defaultMessage": "Usuń {name}",
"description": "Menu option to delete file"
},
+ "delete-project-action": {
+ "defaultMessage": "Delete",
+ "description": "Delete project menu item/button"
+ },
+ "delete-project-confirm-heading": {
+ "defaultMessage": "Delete project",
+ "description": "Heading for the delete project confirmation dialog"
+ },
+ "delete-project-confirm-text": {
+ "defaultMessage": "Are you sure you want to delete ‘{project}’? This cannot be undone.",
+ "description": "Body text for the delete project confirmation dialog"
+ },
+ "delete-projects-confirm-heading": {
+ "defaultMessage": "Delete projects",
+ "description": "Heading for the delete multiple projects confirmation dialog"
+ },
+ "delete-projects-confirm-text": {
+ "defaultMessage": "Are you sure you want to delete {numProjects} projects? This cannot be undone.",
+ "description": "Body for the delete multiple projects confirmation dialog"
+ },
"deleted-file": {
"defaultMessage": "Usunięto {filename}",
"description": "Confirmation message that file got deleted"
@@ -263,6 +319,14 @@
"defaultMessage": "Przeciągnij i upuść",
"description": "Draggable code hover text"
},
+ "duplicate-project-action": {
+ "defaultMessage": "Duplicate",
+ "description": "Duplicate project button/menu item"
+ },
+ "duplicate-project-heading": {
+ "defaultMessage": "Name your project",
+ "description": "Heading for the duplicate project dialog"
+ },
"edit-file-action": {
"defaultMessage": "Edytuj {name}",
"description": "Menu option to edit file"
@@ -315,6 +379,14 @@
"defaultMessage": "Nazwa nie może zawierać spacji",
"description": "Warning text for new Python file name with whitespace"
},
+ "files-tab": {
+ "defaultMessage": "Files",
+ "description": "Sidebar tab label for the project files"
+ },
+ "files-tab-description": {
+ "defaultMessage": "Manage your project files",
+ "description": "Subheading for the Files sidebar tab"
+ },
"firmware-update-link": {
"defaultMessage": "Zanim będziesz mógł połączyć się z tym micro:bitem, musisz zaktualizować oprogramowanie sprzętowe.",
"description": "Text in the firmware update dialog"
@@ -327,6 +399,10 @@
"defaultMessage": "Wymagana jest aktualizacja oprogramowania firmowego",
"description": "Title for the firmware update dialog"
},
+ "first-lessons-with-python-resource-title": {
+ "defaultMessage": "First lessons with Python and the micro:bit",
+ "description": "Title for a lesson card"
+ },
"flash-action": {
"defaultMessage": "Zainstaluj",
"description": "Text for flash button"
@@ -359,6 +435,14 @@
"defaultMessage": "Pomoc",
"description": "Help menu label"
},
+ "help-resources-row-carousel": {
+ "defaultMessage": "Help and support",
+ "description": "Accessible name for the help and support carousel"
+ },
+ "help-resources-row-title": {
+ "defaultMessage": "Help and support",
+ "description": "Title for the help and support row"
+ },
"help-support": {
"defaultMessage": "Pomoc i wsparcie",
"description": "Menu item for link to support site"
@@ -383,6 +467,22 @@
"defaultMessage": "Prosty",
"description": "Highlight code structure option"
},
+ "home-action": {
+ "defaultMessage": "Home",
+ "description": "Aria label for the home button that returns to the project list"
+ },
+ "homepage-banner-heading": {
+ "defaultMessage": "Code your BBC micro:bit with Python",
+ "description": "Home page banner heading"
+ },
+ "homepage-banner-subtitle": {
+ "defaultMessage": "Create, edit and flash MicroPython programs to your micro:bit.",
+ "description": "Home page banner subtitle"
+ },
+ "homepage-title": {
+ "defaultMessage": "micro:bit Python Editor",
+ "description": "Application name shown in the home page header"
+ },
"ideas-tab": {
"defaultMessage": "Pomysły",
"description": "Ideas tab button text. Tab shows programs to give students ideas."
@@ -391,6 +491,10 @@
"defaultMessage": "Wypróbuj te projekty, zmodyfikuj je i poczuj się zainspirowany",
"description": "Ideas tab description text. Tab shows programs to give students ideas."
},
+ "import-file-action": {
+ "defaultMessage": "Import",
+ "description": "Button to import a project file (hex)"
+ },
"insert-code-action": {
"defaultMessage": "Wstaw kod"
},
@@ -398,6 +502,10 @@
"defaultMessage": "Język",
"description": "Language option text"
},
+ "learn-more-action": {
+ "defaultMessage": "Learn more",
+ "description": "Learn more button on the home page banner"
+ },
"less-action": {
"defaultMessage": "Mniej",
"description": "Less button text (showing less content)"
@@ -474,6 +582,14 @@
"defaultMessage": "Ostrzeżenie: pobrano tylko main.py",
"description": "Title of dialog shown when multiple files are available for download but only the main file downloaded."
},
+ "my-projects-row-carousel": {
+ "defaultMessage": "Your projects",
+ "description": "Accessible name for the your projects carousel"
+ },
+ "my-projects-row-title": {
+ "defaultMessage": "Your projects",
+ "description": "Title for the your projects row"
+ },
"name-project": {
"defaultMessage": "Nazwij swój projektu",
"description": "Name your project header"
@@ -490,10 +606,18 @@
"defaultMessage": "Dodamy rozszerzenie .py dla Ciebie.",
"description": "Hint shown in the new Python file dialog"
},
+ "new-project-action": {
+ "defaultMessage": "New project",
+ "description": "New project card action"
+ },
"next-action": {
"defaultMessage": "Dalej",
"description": "Next button text"
},
+ "no-projects": {
+ "defaultMessage": "No projects found",
+ "description": "Shown when a project search returns nothing"
+ },
"not-found-checklist-one": {
"defaultMessage": "Czy Twój micro:bit jest podłączony? Czy wykonałeś te kroki?",
"description": "Checklist text in the no micro:bit found dialog"
@@ -538,6 +662,10 @@
"defaultMessage": "Otwórz plik hex lub Pythona lub dodaj inne pliki",
"description": "Hover text over load button"
},
+ "open-project-action": {
+ "defaultMessage": "Open",
+ "description": "Open project menu item"
+ },
"options": {
"defaultMessage": "Opcje",
"description": "Label for an options menu"
@@ -586,10 +714,54 @@
"defaultMessage": "Działania w projekcie",
"description": "Aria label for the bar with project actions"
},
+ "project-file-count": {
+ "defaultMessage": "{count, plural, one {# file} other {# files}}",
+ "description": "Number of files in a project"
+ },
"project-header": {
"defaultMessage": "Nagłówek projektu",
"description": "Aria label for the project header area"
},
+ "project-idea-animated-animals-title": {
+ "defaultMessage": "Animated animals",
+ "description": "Title for a make it, code it project idea card"
+ },
+ "project-idea-beating-heart-title": {
+ "defaultMessage": "Beating heart",
+ "description": "Title for a make it, code it project idea card"
+ },
+ "project-idea-emotion-badge-title": {
+ "defaultMessage": "Emotion badge",
+ "description": "Title for a make it, code it project idea card"
+ },
+ "project-idea-flashing-emotions-title": {
+ "defaultMessage": "Flashing emotions",
+ "description": "Title for a make it, code it project idea card"
+ },
+ "project-idea-get-silly-title": {
+ "defaultMessage": "Get silly",
+ "description": "Title for a make it, code it project idea card"
+ },
+ "project-idea-heart-title": {
+ "defaultMessage": "Heart",
+ "description": "Title for a make it, code it project idea card"
+ },
+ "project-ideas-row-carousel": {
+ "defaultMessage": "Project ideas",
+ "description": "Accessible name for the project ideas carousel"
+ },
+ "project-ideas-row-title": {
+ "defaultMessage": "Project ideas",
+ "description": "Title for the project ideas row"
+ },
+ "project-loaded": {
+ "defaultMessage": "Project loaded",
+ "description": "Toast shown after a project is loaded from a dropped hex file"
+ },
+ "project-menu-action": {
+ "defaultMessage": "Actions for project ‘{name}’",
+ "description": "Aria label for the per-project actions menu button"
+ },
"project-name": {
"defaultMessage": "Nazwa projektu",
"description": "Text used to indicate the project name"
@@ -598,6 +770,10 @@
"defaultMessage": "Nazwa projektu nie może być pusta",
"description": "Validation message for project name"
},
+ "project-skip-to-toolbar": {
+ "defaultMessage": "Skip to selection actions",
+ "description": "Accessible skip link from a selected project card to the toolbar"
+ },
"project-tab": {
"defaultMessage": "Projekt",
"description": "Project tab button text"
@@ -606,6 +782,10 @@
"defaultMessage": "Przejrzyj, utwórz, dodaj i edytuj pliki w projekcie",
"description": "Project tab description"
},
+ "projects-page-title": {
+ "defaultMessage": "Projects",
+ "description": "Title of the projects page"
+ },
"python-powered": {
"defaultMessage": "Obsługiwany przez Python",
"description": "Python powered logo alt text"
@@ -634,6 +814,14 @@
"defaultMessage": "Referencje",
"description": "Reference tab button text"
},
+ "rename-project-action": {
+ "defaultMessage": "Rename",
+ "description": "Rename project button/menu item"
+ },
+ "rename-project-heading": {
+ "defaultMessage": "Rename project",
+ "description": "Heading for the rename project dialog"
+ },
"replace-action-label": {
"defaultMessage": "Zastąp",
"description": "Action label for replacing project dialog"
@@ -678,6 +866,14 @@
"defaultMessage": "Szukaj",
"description": "Aria label for searching documentation"
},
+ "select-project-action": {
+ "defaultMessage": "Select project ‘{name}’",
+ "description": "Accessible label for the per-project selection checkbox"
+ },
+ "selection-actions-group": {
+ "defaultMessage": "Actions for selected projects",
+ "description": "Accessible label for the selection toolbar"
+ },
"send-action": {
"defaultMessage": "Wyślij do micro:bita",
"description": "Send to micro:bit button text"
@@ -1050,6 +1246,30 @@
"defaultMessage": "Wersje oprogramowania",
"description": "Heading for a table of software versions in the about dialog"
},
+ "sort-option-last-modified": {
+ "defaultMessage": "Last modified",
+ "description": "Sort projects by last modified date"
+ },
+ "sort-option-name": {
+ "defaultMessage": "Name",
+ "description": "Sort projects by name"
+ },
+ "sort-option-relevance": {
+ "defaultMessage": "Relevance",
+ "description": "Sort projects by search relevance"
+ },
+ "sort-order-ascending-label": {
+ "defaultMessage": "Sort ascending",
+ "description": "Accessible label to toggle to ascending sort order"
+ },
+ "sort-order-descending-label": {
+ "defaultMessage": "Sort descending",
+ "description": "Accessible label to toggle to descending sort order"
+ },
+ "sort-select-label": {
+ "defaultMessage": "Sort projects by",
+ "description": "Accessible label for the project sort dropdown"
+ },
"start-coding-action": {
"defaultMessage": "Zacznij kodować",
"description": "Start coding button text"
@@ -1058,6 +1278,14 @@
"defaultMessage": "Wsparcie",
"description": "Support menu option text"
},
+ "teacher-resources-row-carousel": {
+ "defaultMessage": "Teacher resources",
+ "description": "Accessible name for the teacher resources carousel"
+ },
+ "teacher-resources-row-title": {
+ "defaultMessage": "Teacher resources",
+ "description": "Title for the teacher resources row"
+ },
"terms-of-use": {
"defaultMessage": "Warunki korzystania",
"description": "Terms of use menu option text"
@@ -1098,6 +1326,10 @@
"defaultMessage": "Przenieś zapisany plik hex na micro:bita",
"description": "Title for the transfer hex dialog"
},
+ "troubleshooting-resource-title": {
+ "defaultMessage": "Troubleshooting",
+ "description": "Title for the troubleshooting help card"
+ },
"try-again-action": {
"defaultMessage": "Spróbuj ponownie",
"description": "Try again button text"
@@ -1130,6 +1362,10 @@
"defaultMessage": "Podręcznik użytkownika",
"description": "Menu item for link to user guide site"
},
+ "view-all-projects": {
+ "defaultMessage": "View all projects",
+ "description": "Link/card to view the full projects list"
+ },
"visit-dot-org": {
"defaultMessage": "odwiedź microbit.org (otwiera się w nowej karcie)",
"description": "alt text for logo link to .org"
diff --git a/lang/ui.zh-cn.json b/lang/ui.zh-cn.json
index 63bb548e9..a17e51718 100644
--- a/lang/ui.zh-cn.json
+++ b/lang/ui.zh-cn.json
@@ -27,6 +27,18 @@
"defaultMessage": "辅助功能",
"description": "Menu item for link to accessibility site"
},
+ "accessibility-resource-title": {
+ "defaultMessage": "Accessibility",
+ "description": "Title for the accessibility help card"
+ },
+ "add-files-action": {
+ "defaultMessage": "Add file(s)",
+ "description": "Button to add files to the current project"
+ },
+ "add-files-hover": {
+ "defaultMessage": "Add files to this project",
+ "description": "Tooltip for the add files button"
+ },
"added-change": {
"defaultMessage": "已添加文件 {changeName}",
"description": "Change made to file"
@@ -71,6 +83,18 @@
"defaultMessage": "取消",
"description": "Cancel button text"
},
+ "carousel-role": {
+ "defaultMessage": "carousel",
+ "description": "Accessible role description for a carousel"
+ },
+ "carousel-slide-label": {
+ "defaultMessage": "{slideNum} of {totalSlides}",
+ "description": "Accessible label for a carousel slide"
+ },
+ "carousel-slide-role": {
+ "defaultMessage": "slide",
+ "description": "Accessible role description for a carousel slide"
+ },
"change-files": {
"defaultMessage": "更改文件?",
"description": "Header for dialog of confirmation of files changed"
@@ -227,10 +251,22 @@
"defaultMessage": "创建文件",
"description": "Button text for action that creates a new blank Python file in the current project"
},
+ "create-project-action": {
+ "defaultMessage": "Create",
+ "description": "Create project button"
+ },
+ "create-project-dialog-heading": {
+ "defaultMessage": "Name your project",
+ "description": "Heading for the create project dialog"
+ },
"create-python": {
"defaultMessage": "在此项目中创建一份新的 Python 文件",
"description": "Hover and dialog title when creating a new Python file"
},
+ "createai-taster-lessons-resource-title": {
+ "defaultMessage": "Taster lessons",
+ "description": "Title for a lesson card (placeholder)"
+ },
"created-file": {
"defaultMessage": "创建 {filename}",
"description": "Action feedback for creating a file"
@@ -243,6 +279,26 @@
"defaultMessage": "删除 {name}",
"description": "Menu option to delete file"
},
+ "delete-project-action": {
+ "defaultMessage": "Delete",
+ "description": "Delete project menu item/button"
+ },
+ "delete-project-confirm-heading": {
+ "defaultMessage": "Delete project",
+ "description": "Heading for the delete project confirmation dialog"
+ },
+ "delete-project-confirm-text": {
+ "defaultMessage": "Are you sure you want to delete ‘{project}’? This cannot be undone.",
+ "description": "Body text for the delete project confirmation dialog"
+ },
+ "delete-projects-confirm-heading": {
+ "defaultMessage": "Delete projects",
+ "description": "Heading for the delete multiple projects confirmation dialog"
+ },
+ "delete-projects-confirm-text": {
+ "defaultMessage": "Are you sure you want to delete {numProjects} projects? This cannot be undone.",
+ "description": "Body for the delete multiple projects confirmation dialog"
+ },
"deleted-file": {
"defaultMessage": "已删除 {filename}",
"description": "Confirmation message that file got deleted"
@@ -263,6 +319,14 @@
"defaultMessage": "拖放",
"description": "Draggable code hover text"
},
+ "duplicate-project-action": {
+ "defaultMessage": "Duplicate",
+ "description": "Duplicate project button/menu item"
+ },
+ "duplicate-project-heading": {
+ "defaultMessage": "Name your project",
+ "description": "Heading for the duplicate project dialog"
+ },
"edit-file-action": {
"defaultMessage": "编辑 {name}",
"description": "Menu option to edit file"
@@ -315,6 +379,14 @@
"defaultMessage": "名称不能包含空格",
"description": "Warning text for new Python file name with whitespace"
},
+ "files-tab": {
+ "defaultMessage": "Files",
+ "description": "Sidebar tab label for the project files"
+ },
+ "files-tab-description": {
+ "defaultMessage": "Manage your project files",
+ "description": "Subheading for the Files sidebar tab"
+ },
"firmware-update-link": {
"defaultMessage": "在连接 micro:bit 之前,您必须 update your firmware。",
"description": "Text in the firmware update dialog"
@@ -327,6 +399,10 @@
"defaultMessage": "需要更新固件",
"description": "Title for the firmware update dialog"
},
+ "first-lessons-with-python-resource-title": {
+ "defaultMessage": "First lessons with Python and the micro:bit",
+ "description": "Title for a lesson card"
+ },
"flash-action": {
"defaultMessage": "下载",
"description": "Text for flash button"
@@ -359,6 +435,14 @@
"defaultMessage": "帮助",
"description": "Help menu label"
},
+ "help-resources-row-carousel": {
+ "defaultMessage": "Help and support",
+ "description": "Accessible name for the help and support carousel"
+ },
+ "help-resources-row-title": {
+ "defaultMessage": "Help and support",
+ "description": "Title for the help and support row"
+ },
"help-support": {
"defaultMessage": "帮助与支持",
"description": "Menu item for link to support site"
@@ -383,6 +467,22 @@
"defaultMessage": "简单",
"description": "Highlight code structure option"
},
+ "home-action": {
+ "defaultMessage": "Home",
+ "description": "Aria label for the home button that returns to the project list"
+ },
+ "homepage-banner-heading": {
+ "defaultMessage": "Code your BBC micro:bit with Python",
+ "description": "Home page banner heading"
+ },
+ "homepage-banner-subtitle": {
+ "defaultMessage": "Create, edit and flash MicroPython programs to your micro:bit.",
+ "description": "Home page banner subtitle"
+ },
+ "homepage-title": {
+ "defaultMessage": "micro:bit Python Editor",
+ "description": "Application name shown in the home page header"
+ },
"ideas-tab": {
"defaultMessage": "创意",
"description": "Ideas tab button text. Tab shows programs to give students ideas."
@@ -391,6 +491,10 @@
"defaultMessage": "尝试这些项目,修改它们并获得灵感",
"description": "Ideas tab description text. Tab shows programs to give students ideas."
},
+ "import-file-action": {
+ "defaultMessage": "Import",
+ "description": "Button to import a project file (hex)"
+ },
"insert-code-action": {
"defaultMessage": "插入代码"
},
@@ -398,6 +502,10 @@
"defaultMessage": "语言",
"description": "Language option text"
},
+ "learn-more-action": {
+ "defaultMessage": "Learn more",
+ "description": "Learn more button on the home page banner"
+ },
"less-action": {
"defaultMessage": "更少",
"description": "Less button text (showing less content)"
@@ -474,6 +582,14 @@
"defaultMessage": "警告:只下载了 main.py",
"description": "Title of dialog shown when multiple files are available for download but only the main file downloaded."
},
+ "my-projects-row-carousel": {
+ "defaultMessage": "Your projects",
+ "description": "Accessible name for the your projects carousel"
+ },
+ "my-projects-row-title": {
+ "defaultMessage": "Your projects",
+ "description": "Title for the your projects row"
+ },
"name-project": {
"defaultMessage": "为您的项目命名",
"description": "Name your project header"
@@ -490,10 +606,18 @@
"defaultMessage": "我们将为您添加 .py 扩展名。",
"description": "Hint shown in the new Python file dialog"
},
+ "new-project-action": {
+ "defaultMessage": "New project",
+ "description": "New project card action"
+ },
"next-action": {
"defaultMessage": "下一个",
"description": "Next button text"
},
+ "no-projects": {
+ "defaultMessage": "No projects found",
+ "description": "Shown when a project search returns nothing"
+ },
"not-found-checklist-one": {
"defaultMessage": "您的 micro:bit 是否已插入?您是否 follow these steps?",
"description": "Checklist text in the no micro:bit found dialog"
@@ -538,6 +662,10 @@
"defaultMessage": "打开一 份 hex 或 Python 文件,或添加其他文件",
"description": "Hover text over load button"
},
+ "open-project-action": {
+ "defaultMessage": "Open",
+ "description": "Open project menu item"
+ },
"options": {
"defaultMessage": "选项",
"description": "Label for an options menu"
@@ -586,10 +714,54 @@
"defaultMessage": "项目行动",
"description": "Aria label for the bar with project actions"
},
+ "project-file-count": {
+ "defaultMessage": "{count, plural, one {# file} other {# files}}",
+ "description": "Number of files in a project"
+ },
"project-header": {
"defaultMessage": "项目标题",
"description": "Aria label for the project header area"
},
+ "project-idea-animated-animals-title": {
+ "defaultMessage": "Animated animals",
+ "description": "Title for a make it, code it project idea card"
+ },
+ "project-idea-beating-heart-title": {
+ "defaultMessage": "Beating heart",
+ "description": "Title for a make it, code it project idea card"
+ },
+ "project-idea-emotion-badge-title": {
+ "defaultMessage": "Emotion badge",
+ "description": "Title for a make it, code it project idea card"
+ },
+ "project-idea-flashing-emotions-title": {
+ "defaultMessage": "Flashing emotions",
+ "description": "Title for a make it, code it project idea card"
+ },
+ "project-idea-get-silly-title": {
+ "defaultMessage": "Get silly",
+ "description": "Title for a make it, code it project idea card"
+ },
+ "project-idea-heart-title": {
+ "defaultMessage": "Heart",
+ "description": "Title for a make it, code it project idea card"
+ },
+ "project-ideas-row-carousel": {
+ "defaultMessage": "Project ideas",
+ "description": "Accessible name for the project ideas carousel"
+ },
+ "project-ideas-row-title": {
+ "defaultMessage": "Project ideas",
+ "description": "Title for the project ideas row"
+ },
+ "project-loaded": {
+ "defaultMessage": "Project loaded",
+ "description": "Toast shown after a project is loaded from a dropped hex file"
+ },
+ "project-menu-action": {
+ "defaultMessage": "Actions for project ‘{name}’",
+ "description": "Aria label for the per-project actions menu button"
+ },
"project-name": {
"defaultMessage": "项目名称",
"description": "Text used to indicate the project name"
@@ -598,6 +770,10 @@
"defaultMessage": "项目名称不能为空",
"description": "Validation message for project name"
},
+ "project-skip-to-toolbar": {
+ "defaultMessage": "Skip to selection actions",
+ "description": "Accessible skip link from a selected project card to the toolbar"
+ },
"project-tab": {
"defaultMessage": "项目",
"description": "Project tab button text"
@@ -606,6 +782,10 @@
"defaultMessage": "查看、创建、添加和编辑您项目中的文件",
"description": "Project tab description"
},
+ "projects-page-title": {
+ "defaultMessage": "Projects",
+ "description": "Title of the projects page"
+ },
"python-powered": {
"defaultMessage": "Python 驱动",
"description": "Python powered logo alt text"
@@ -634,6 +814,14 @@
"defaultMessage": "参考",
"description": "Reference tab button text"
},
+ "rename-project-action": {
+ "defaultMessage": "Rename",
+ "description": "Rename project button/menu item"
+ },
+ "rename-project-heading": {
+ "defaultMessage": "Rename project",
+ "description": "Heading for the rename project dialog"
+ },
"replace-action-label": {
"defaultMessage": "替换",
"description": "Action label for replacing project dialog"
@@ -678,6 +866,14 @@
"defaultMessage": "搜索",
"description": "Aria label for searching documentation"
},
+ "select-project-action": {
+ "defaultMessage": "Select project ‘{name}’",
+ "description": "Accessible label for the per-project selection checkbox"
+ },
+ "selection-actions-group": {
+ "defaultMessage": "Actions for selected projects",
+ "description": "Accessible label for the selection toolbar"
+ },
"send-action": {
"defaultMessage": "发送至 micro:bit",
"description": "Send to micro:bit button text"
@@ -1050,6 +1246,30 @@
"defaultMessage": "软件版本",
"description": "Heading for a table of software versions in the about dialog"
},
+ "sort-option-last-modified": {
+ "defaultMessage": "Last modified",
+ "description": "Sort projects by last modified date"
+ },
+ "sort-option-name": {
+ "defaultMessage": "Name",
+ "description": "Sort projects by name"
+ },
+ "sort-option-relevance": {
+ "defaultMessage": "Relevance",
+ "description": "Sort projects by search relevance"
+ },
+ "sort-order-ascending-label": {
+ "defaultMessage": "Sort ascending",
+ "description": "Accessible label to toggle to ascending sort order"
+ },
+ "sort-order-descending-label": {
+ "defaultMessage": "Sort descending",
+ "description": "Accessible label to toggle to descending sort order"
+ },
+ "sort-select-label": {
+ "defaultMessage": "Sort projects by",
+ "description": "Accessible label for the project sort dropdown"
+ },
"start-coding-action": {
"defaultMessage": "开始编程",
"description": "Start coding button text"
@@ -1058,6 +1278,14 @@
"defaultMessage": "帮助",
"description": "Support menu option text"
},
+ "teacher-resources-row-carousel": {
+ "defaultMessage": "Teacher resources",
+ "description": "Accessible name for the teacher resources carousel"
+ },
+ "teacher-resources-row-title": {
+ "defaultMessage": "Teacher resources",
+ "description": "Title for the teacher resources row"
+ },
"terms-of-use": {
"defaultMessage": "使用条款",
"description": "Terms of use menu option text"
@@ -1098,6 +1326,10 @@
"defaultMessage": "将保存的 hex 文件传输到 micro:bit",
"description": "Title for the transfer hex dialog"
},
+ "troubleshooting-resource-title": {
+ "defaultMessage": "Troubleshooting",
+ "description": "Title for the troubleshooting help card"
+ },
"try-again-action": {
"defaultMessage": "重试",
"description": "Try again button text"
@@ -1130,6 +1362,10 @@
"defaultMessage": "用户指南",
"description": "Menu item for link to user guide site"
},
+ "view-all-projects": {
+ "defaultMessage": "View all projects",
+ "description": "Link/card to view the full projects list"
+ },
"visit-dot-org": {
"defaultMessage": "访问 microbit.org (在新标签页中打开)",
"description": "alt text for logo link to .org"
diff --git a/lang/ui.zh-tw.json b/lang/ui.zh-tw.json
index 3603a5d8c..77a2c8f08 100644
--- a/lang/ui.zh-tw.json
+++ b/lang/ui.zh-tw.json
@@ -27,6 +27,18 @@
"defaultMessage": "無障礙設定",
"description": "Menu item for link to accessibility site"
},
+ "accessibility-resource-title": {
+ "defaultMessage": "Accessibility",
+ "description": "Title for the accessibility help card"
+ },
+ "add-files-action": {
+ "defaultMessage": "Add file(s)",
+ "description": "Button to add files to the current project"
+ },
+ "add-files-hover": {
+ "defaultMessage": "Add files to this project",
+ "description": "Tooltip for the add files button"
+ },
"added-change": {
"defaultMessage": "已新增檔案 {changeName}",
"description": "Change made to file"
@@ -71,6 +83,18 @@
"defaultMessage": "取消",
"description": "Cancel button text"
},
+ "carousel-role": {
+ "defaultMessage": "carousel",
+ "description": "Accessible role description for a carousel"
+ },
+ "carousel-slide-label": {
+ "defaultMessage": "{slideNum} of {totalSlides}",
+ "description": "Accessible label for a carousel slide"
+ },
+ "carousel-slide-role": {
+ "defaultMessage": "slide",
+ "description": "Accessible role description for a carousel slide"
+ },
"change-files": {
"defaultMessage": "是否要變更檔案?",
"description": "Header for dialog of confirmation of files changed"
@@ -227,10 +251,22 @@
"defaultMessage": "建立檔案",
"description": "Button text for action that creates a new blank Python file in the current project"
},
+ "create-project-action": {
+ "defaultMessage": "Create",
+ "description": "Create project button"
+ },
+ "create-project-dialog-heading": {
+ "defaultMessage": "Name your project",
+ "description": "Heading for the create project dialog"
+ },
"create-python": {
"defaultMessage": "在本專案中建立新的 Python 檔案",
"description": "Hover and dialog title when creating a new Python file"
},
+ "createai-taster-lessons-resource-title": {
+ "defaultMessage": "Taster lessons",
+ "description": "Title for a lesson card (placeholder)"
+ },
"created-file": {
"defaultMessage": "已建立 {filename}",
"description": "Action feedback for creating a file"
@@ -243,6 +279,26 @@
"defaultMessage": "刪除 {name}",
"description": "Menu option to delete file"
},
+ "delete-project-action": {
+ "defaultMessage": "Delete",
+ "description": "Delete project menu item/button"
+ },
+ "delete-project-confirm-heading": {
+ "defaultMessage": "Delete project",
+ "description": "Heading for the delete project confirmation dialog"
+ },
+ "delete-project-confirm-text": {
+ "defaultMessage": "Are you sure you want to delete ‘{project}’? This cannot be undone.",
+ "description": "Body text for the delete project confirmation dialog"
+ },
+ "delete-projects-confirm-heading": {
+ "defaultMessage": "Delete projects",
+ "description": "Heading for the delete multiple projects confirmation dialog"
+ },
+ "delete-projects-confirm-text": {
+ "defaultMessage": "Are you sure you want to delete {numProjects} projects? This cannot be undone.",
+ "description": "Body for the delete multiple projects confirmation dialog"
+ },
"deleted-file": {
"defaultMessage": "已刪除 {filename}",
"description": "Confirmation message that file got deleted"
@@ -263,6 +319,14 @@
"defaultMessage": "拖放",
"description": "Draggable code hover text"
},
+ "duplicate-project-action": {
+ "defaultMessage": "Duplicate",
+ "description": "Duplicate project button/menu item"
+ },
+ "duplicate-project-heading": {
+ "defaultMessage": "Name your project",
+ "description": "Heading for the duplicate project dialog"
+ },
"edit-file-action": {
"defaultMessage": "編輯 {name}",
"description": "Menu option to edit file"
@@ -315,6 +379,14 @@
"defaultMessage": "名稱不能包含空格",
"description": "Warning text for new Python file name with whitespace"
},
+ "files-tab": {
+ "defaultMessage": "Files",
+ "description": "Sidebar tab label for the project files"
+ },
+ "files-tab-description": {
+ "defaultMessage": "Manage your project files",
+ "description": "Subheading for the Files sidebar tab"
+ },
"firmware-update-link": {
"defaultMessage": "在連線至 micro:bit 前,您必須更新您的韌體。",
"description": "Text in the firmware update dialog"
@@ -327,6 +399,10 @@
"defaultMessage": "韌體需要更新",
"description": "Title for the firmware update dialog"
},
+ "first-lessons-with-python-resource-title": {
+ "defaultMessage": "First lessons with Python and the micro:bit",
+ "description": "Title for a lesson card"
+ },
"flash-action": {
"defaultMessage": "燒錄",
"description": "Text for flash button"
@@ -359,6 +435,14 @@
"defaultMessage": "幫助",
"description": "Help menu label"
},
+ "help-resources-row-carousel": {
+ "defaultMessage": "Help and support",
+ "description": "Accessible name for the help and support carousel"
+ },
+ "help-resources-row-title": {
+ "defaultMessage": "Help and support",
+ "description": "Title for the help and support row"
+ },
"help-support": {
"defaultMessage": "說明與支援",
"description": "Menu item for link to support site"
@@ -383,6 +467,22 @@
"defaultMessage": "簡單",
"description": "Highlight code structure option"
},
+ "home-action": {
+ "defaultMessage": "Home",
+ "description": "Aria label for the home button that returns to the project list"
+ },
+ "homepage-banner-heading": {
+ "defaultMessage": "Code your BBC micro:bit with Python",
+ "description": "Home page banner heading"
+ },
+ "homepage-banner-subtitle": {
+ "defaultMessage": "Create, edit and flash MicroPython programs to your micro:bit.",
+ "description": "Home page banner subtitle"
+ },
+ "homepage-title": {
+ "defaultMessage": "micro:bit Python Editor",
+ "description": "Application name shown in the home page header"
+ },
"ideas-tab": {
"defaultMessage": "靈感",
"description": "Ideas tab button text. Tab shows programs to give students ideas."
@@ -391,6 +491,10 @@
"defaultMessage": "嘗試這些專案,進行修改並獲得靈感",
"description": "Ideas tab description text. Tab shows programs to give students ideas."
},
+ "import-file-action": {
+ "defaultMessage": "Import",
+ "description": "Button to import a project file (hex)"
+ },
"insert-code-action": {
"defaultMessage": "插入程式碼"
},
@@ -398,6 +502,10 @@
"defaultMessage": "語言",
"description": "Language option text"
},
+ "learn-more-action": {
+ "defaultMessage": "Learn more",
+ "description": "Learn more button on the home page banner"
+ },
"less-action": {
"defaultMessage": "查看較少",
"description": "Less button text (showing less content)"
@@ -474,6 +582,14 @@
"defaultMessage": "警告:只下載了 main.py",
"description": "Title of dialog shown when multiple files are available for download but only the main file downloaded."
},
+ "my-projects-row-carousel": {
+ "defaultMessage": "Your projects",
+ "description": "Accessible name for the your projects carousel"
+ },
+ "my-projects-row-title": {
+ "defaultMessage": "Your projects",
+ "description": "Title for the your projects row"
+ },
"name-project": {
"defaultMessage": "為您的專案命名",
"description": "Name your project header"
@@ -490,10 +606,18 @@
"defaultMessage": "我們將為您新增 .py 副檔名。",
"description": "Hint shown in the new Python file dialog"
},
+ "new-project-action": {
+ "defaultMessage": "New project",
+ "description": "New project card action"
+ },
"next-action": {
"defaultMessage": "下一個",
"description": "Next button text"
},
+ "no-projects": {
+ "defaultMessage": "No projects found",
+ "description": "Shown when a project search returns nothing"
+ },
"not-found-checklist-one": {
"defaultMessage": "您的 micro:bit 是否已插入?您是否遵循這些步驟?",
"description": "Checklist text in the no micro:bit found dialog"
@@ -538,6 +662,10 @@
"defaultMessage": "開啟 Hex 或 Python 檔案,或是新增其他檔案",
"description": "Hover text over load button"
},
+ "open-project-action": {
+ "defaultMessage": "Open",
+ "description": "Open project menu item"
+ },
"options": {
"defaultMessage": "選項",
"description": "Label for an options menu"
@@ -586,10 +714,54 @@
"defaultMessage": "專案動作",
"description": "Aria label for the bar with project actions"
},
+ "project-file-count": {
+ "defaultMessage": "{count, plural, one {# file} other {# files}}",
+ "description": "Number of files in a project"
+ },
"project-header": {
"defaultMessage": "專案標頭",
"description": "Aria label for the project header area"
},
+ "project-idea-animated-animals-title": {
+ "defaultMessage": "Animated animals",
+ "description": "Title for a make it, code it project idea card"
+ },
+ "project-idea-beating-heart-title": {
+ "defaultMessage": "Beating heart",
+ "description": "Title for a make it, code it project idea card"
+ },
+ "project-idea-emotion-badge-title": {
+ "defaultMessage": "Emotion badge",
+ "description": "Title for a make it, code it project idea card"
+ },
+ "project-idea-flashing-emotions-title": {
+ "defaultMessage": "Flashing emotions",
+ "description": "Title for a make it, code it project idea card"
+ },
+ "project-idea-get-silly-title": {
+ "defaultMessage": "Get silly",
+ "description": "Title for a make it, code it project idea card"
+ },
+ "project-idea-heart-title": {
+ "defaultMessage": "Heart",
+ "description": "Title for a make it, code it project idea card"
+ },
+ "project-ideas-row-carousel": {
+ "defaultMessage": "Project ideas",
+ "description": "Accessible name for the project ideas carousel"
+ },
+ "project-ideas-row-title": {
+ "defaultMessage": "Project ideas",
+ "description": "Title for the project ideas row"
+ },
+ "project-loaded": {
+ "defaultMessage": "Project loaded",
+ "description": "Toast shown after a project is loaded from a dropped hex file"
+ },
+ "project-menu-action": {
+ "defaultMessage": "Actions for project ‘{name}’",
+ "description": "Aria label for the per-project actions menu button"
+ },
"project-name": {
"defaultMessage": "專案名稱",
"description": "Text used to indicate the project name"
@@ -598,6 +770,10 @@
"defaultMessage": "專案名稱不可為空白",
"description": "Validation message for project name"
},
+ "project-skip-to-toolbar": {
+ "defaultMessage": "Skip to selection actions",
+ "description": "Accessible skip link from a selected project card to the toolbar"
+ },
"project-tab": {
"defaultMessage": "專案",
"description": "Project tab button text"
@@ -606,6 +782,10 @@
"defaultMessage": "檢視、建立、新增和編輯專案中的檔案",
"description": "Project tab description"
},
+ "projects-page-title": {
+ "defaultMessage": "Projects",
+ "description": "Title of the projects page"
+ },
"python-powered": {
"defaultMessage": "已啟動 Python",
"description": "Python powered logo alt text"
@@ -634,6 +814,14 @@
"defaultMessage": "參考資料",
"description": "Reference tab button text"
},
+ "rename-project-action": {
+ "defaultMessage": "Rename",
+ "description": "Rename project button/menu item"
+ },
+ "rename-project-heading": {
+ "defaultMessage": "Rename project",
+ "description": "Heading for the rename project dialog"
+ },
"replace-action-label": {
"defaultMessage": "取代",
"description": "Action label for replacing project dialog"
@@ -678,6 +866,14 @@
"defaultMessage": "搜尋",
"description": "Aria label for searching documentation"
},
+ "select-project-action": {
+ "defaultMessage": "Select project ‘{name}’",
+ "description": "Accessible label for the per-project selection checkbox"
+ },
+ "selection-actions-group": {
+ "defaultMessage": "Actions for selected projects",
+ "description": "Accessible label for the selection toolbar"
+ },
"send-action": {
"defaultMessage": "傳送至 micro:bit",
"description": "Send to micro:bit button text"
@@ -1050,6 +1246,30 @@
"defaultMessage": "軟體版本",
"description": "Heading for a table of software versions in the about dialog"
},
+ "sort-option-last-modified": {
+ "defaultMessage": "Last modified",
+ "description": "Sort projects by last modified date"
+ },
+ "sort-option-name": {
+ "defaultMessage": "Name",
+ "description": "Sort projects by name"
+ },
+ "sort-option-relevance": {
+ "defaultMessage": "Relevance",
+ "description": "Sort projects by search relevance"
+ },
+ "sort-order-ascending-label": {
+ "defaultMessage": "Sort ascending",
+ "description": "Accessible label to toggle to ascending sort order"
+ },
+ "sort-order-descending-label": {
+ "defaultMessage": "Sort descending",
+ "description": "Accessible label to toggle to descending sort order"
+ },
+ "sort-select-label": {
+ "defaultMessage": "Sort projects by",
+ "description": "Accessible label for the project sort dropdown"
+ },
"start-coding-action": {
"defaultMessage": "開始編碼",
"description": "Start coding button text"
@@ -1058,6 +1278,14 @@
"defaultMessage": "支援",
"description": "Support menu option text"
},
+ "teacher-resources-row-carousel": {
+ "defaultMessage": "Teacher resources",
+ "description": "Accessible name for the teacher resources carousel"
+ },
+ "teacher-resources-row-title": {
+ "defaultMessage": "Teacher resources",
+ "description": "Title for the teacher resources row"
+ },
"terms-of-use": {
"defaultMessage": "網站使用條款",
"description": "Terms of use menu option text"
@@ -1098,6 +1326,10 @@
"defaultMessage": "將儲存的 HEX 檔案傳輸至 micro:bit",
"description": "Title for the transfer hex dialog"
},
+ "troubleshooting-resource-title": {
+ "defaultMessage": "Troubleshooting",
+ "description": "Title for the troubleshooting help card"
+ },
"try-again-action": {
"defaultMessage": "重試一次",
"description": "Try again button text"
@@ -1130,6 +1362,10 @@
"defaultMessage": "用戶指南 ",
"description": "Menu item for link to user guide site"
},
+ "view-all-projects": {
+ "defaultMessage": "View all projects",
+ "description": "Link/card to view the full projects list"
+ },
"visit-dot-org": {
"defaultMessage": "造訪 microbit.org (在新索引標籤中開啟)",
"description": "alt text for logo link to .org"
diff --git a/package-lock.json b/package-lock.json
index 7d8ef09ec..7a097dd8e 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -39,6 +39,7 @@
"dompurify": "^3.2.5",
"file-saver": "^2.0.5",
"framer-motion": "^10.2.4",
+ "idb": "^8.0.3",
"lodash.debounce": "^4.0.8",
"lodash.sortby": "^4.7.0",
"lunr": "^2.3.9",
@@ -51,6 +52,8 @@
"react-hotkeys-hook": "^4.5.0",
"react-icons": "^4.12.0",
"react-intl": "^6.6.8",
+ "react-router-dom": "^7.18.1",
+ "swiper": "^14.0.1",
"vite": "^7.3.1",
"vscode-jsonrpc": "^8.0.0",
"vscode-languageserver-protocol": "^3.16.0",
@@ -199,7 +202,6 @@
"integrity": "sha512-RgHBCvtjbOK2gXSNBNIkNoEc9qoVEtau3hj8gEqKQuL3HZAibKarWFEI3Lfm6EYKkLalOh8eSrj9b+ch9H/VBA==",
"dev": true,
"license": "MIT",
- "peer": true,
"dependencies": {
"@babel/code-frame": "^7.29.7",
"@babel/generator": "^7.29.7",
@@ -1765,7 +1767,8 @@
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/@capacitor/synapse/-/synapse-1.0.4.tgz",
"integrity": "sha512-/C1FUo8/OkKuAT4nCIu/34ny9siNHr9qtFezu4kxm6GY1wNFxrCFWjfYx5C1tUhVGz3fxBABegupkpjXvjCHrw==",
- "license": "ISC"
+ "license": "ISC",
+ "peer": true
},
"node_modules/@chakra-ui/anatomy": {
"version": "2.3.6",
@@ -1838,7 +1841,6 @@
"resolved": "https://registry.npmjs.org/@chakra-ui/react/-/react-2.10.10.tgz",
"integrity": "sha512-uahxAfb83/O9fcgBm3ew/nVeQiNgE0uQf8NdQQp3I6u/PCuR2OjSEneV4Ba86W8z50Ppwcxvf9XDk5btYceggQ==",
"license": "MIT",
- "peer": true,
"dependencies": {
"@chakra-ui/hooks": "2.4.6",
"@chakra-ui/styled-system": "2.12.5",
@@ -1864,7 +1866,6 @@
"resolved": "https://registry.npmjs.org/@chakra-ui/styled-system/-/styled-system-2.12.5.tgz",
"integrity": "sha512-sy39LJWnOvGcOHYBXQxT3bC5zj+R7GVUgxzkkoqx+auV5KVKOOE5aZD+POsciWEt86bqdEa+LpFm+E5pcdbkyg==",
"license": "MIT",
- "peer": true,
"dependencies": {
"@chakra-ui/utils": "2.2.6",
"csstype": "^3.1.2"
@@ -2067,7 +2068,6 @@
}
],
"license": "MIT",
- "peer": true,
"engines": {
"node": ">=20.19.0"
},
@@ -2108,7 +2108,6 @@
}
],
"license": "MIT",
- "peer": true,
"engines": {
"node": ">=20.19.0"
}
@@ -2177,7 +2176,6 @@
"resolved": "https://registry.npmjs.org/@emotion/react/-/react-11.14.0.tgz",
"integrity": "sha512-O000MLDBDdk/EohJPFUqvnp4qnHeYkVP5B0xEG0D/L7cOKP9kefu2DXn8dj74cQfsEzUqh+sr1RzFqiL1o+PpA==",
"license": "MIT",
- "peer": true,
"dependencies": {
"@babel/runtime": "^7.18.3",
"@emotion/babel-plugin": "^11.13.5",
@@ -2221,7 +2219,6 @@
"resolved": "https://registry.npmjs.org/@emotion/styled/-/styled-11.14.1.tgz",
"integrity": "sha512-qEEJt42DuToa3gurlH4Qqc1kVpNq8wO8cJtDzU46TjlzWjDlsVyevtYCRijVq3SrHsROS+gVQ8Fnea108GnKzw==",
"license": "MIT",
- "peer": true,
"dependencies": {
"@babel/runtime": "^7.18.3",
"@emotion/babel-plugin": "^11.13.5",
@@ -4549,7 +4546,6 @@
"version": "18.3.3",
"resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.3.tgz",
"integrity": "sha512-hti/R0pS0q1/xx+TsI73XIqk26eBsISZ2R0wUijXIngRK9R/e7Xw/cXVxQK7R5JjW+SV4zGcn5hXjudkN/pLIw==",
- "peer": true,
"dependencies": {
"@types/prop-types": "*",
"csstype": "^3.0.2"
@@ -4662,7 +4658,6 @@
"integrity": "sha512-klQbnPAAiGYFyI02+znpBRLyjL4/BrBd0nyWkdC0s/6xFLkXYQ8OoRrSkqacS1ddVxf/LDyODIKbQ5TgKAf/Fg==",
"dev": true,
"license": "MIT",
- "peer": true,
"dependencies": {
"@typescript-eslint/scope-manager": "8.56.1",
"@typescript-eslint/types": "8.56.1",
@@ -5089,7 +5084,6 @@
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz",
"integrity": "sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==",
"devOptional": true,
- "peer": true,
"bin": {
"acorn": "bin/acorn"
},
@@ -5714,7 +5708,6 @@
}
],
"license": "MIT",
- "peer": true,
"dependencies": {
"baseline-browser-mapping": "^2.9.0",
"caniuse-lite": "^1.0.30001759",
@@ -6166,6 +6159,19 @@
"integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==",
"dev": true
},
+ "node_modules/cookie": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/cookie/-/cookie-1.1.1.tgz",
+ "integrity": "sha512-ei8Aos7ja0weRpFzJnEA9UHJ/7XQmqglbRwnf2ATjcB9Wq874VKH9kfjjirM6UhU2/E5fFYadylyhFldcqSidQ==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=18"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/express"
+ }
+ },
"node_modules/copy-to-clipboard": {
"version": "3.3.3",
"resolved": "https://registry.npmjs.org/copy-to-clipboard/-/copy-to-clipboard-3.3.3.tgz",
@@ -7051,7 +7057,6 @@
"resolved": "https://registry.npmjs.org/eslint/-/eslint-8.57.0.tgz",
"integrity": "sha512-dZ6+mexnaTIbSBZWgou51U6OmzIhYM2VcNdtiTtI7qPNZm35Akpr0f6vtw3w1Kmn5PYo+tZVfh13WrhpS6oLqQ==",
"dev": true,
- "peer": true,
"dependencies": {
"@eslint-community/eslint-utils": "^4.2.0",
"@eslint-community/regexpp": "^4.6.1",
@@ -7677,7 +7682,6 @@
"version": "10.18.0",
"resolved": "https://registry.npmjs.org/framer-motion/-/framer-motion-10.18.0.tgz",
"integrity": "sha512-oGlDh1Q1XqYPksuTD/usb0I70hq95OUzmL9+6Zd+Hs4XV0oaISBa/UUMSjYiq6m8EUF32132mOJ8xVZS+I0S6w==",
- "peer": true,
"dependencies": {
"tslib": "^2.4.0"
},
@@ -8224,10 +8228,9 @@
}
},
"node_modules/idb": {
- "version": "7.1.1",
- "resolved": "https://registry.npmjs.org/idb/-/idb-7.1.1.tgz",
- "integrity": "sha512-gchesWBzyvGHRO9W8tzUWFDycow5gwjvFKfyV9FF32Y7F50yZMp7mP+T2mJIWFx49zicqyC4uefHM17o6xKIVQ==",
- "dev": true,
+ "version": "8.0.3",
+ "resolved": "https://registry.npmjs.org/idb/-/idb-8.0.3.tgz",
+ "integrity": "sha512-LtwtVyVYO5BqRvcsKuB2iUMnHwPVByPCXFXOpuU96IZPPoPN6xjOGxZQ74pgSVVLQWtUOYgyeL4GE98BY5D3wg==",
"license": "ISC"
},
"node_modules/ieee754": {
@@ -9557,7 +9560,6 @@
"integrity": "sha512-0+MoQNYyr2rBHqO1xilltfDjV9G7ymYGlAUazgcDLQaUf8JDHbuGwsxN6U9qWaElZ4w1B2r7yEGIL3GdeW3Rug==",
"dev": true,
"license": "MIT",
- "peer": true,
"dependencies": {
"@acemir/cssom": "^0.9.31",
"@asamuzakjp/dom-selector": "^6.8.1",
@@ -10807,7 +10809,6 @@
"version": "18.3.1",
"resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz",
"integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==",
- "peer": true,
"dependencies": {
"loose-envify": "^1.1.0"
},
@@ -10831,7 +10832,6 @@
"version": "18.3.1",
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz",
"integrity": "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==",
- "peer": true,
"dependencies": {
"loose-envify": "^1.1.0",
"scheduler": "^0.23.2"
@@ -10974,6 +10974,44 @@
}
}
},
+ "node_modules/react-router": {
+ "version": "7.18.1",
+ "resolved": "https://registry.npmjs.org/react-router/-/react-router-7.18.1.tgz",
+ "integrity": "sha512-GDLgg3i3uM0aeJO3Fm+TCS+sDQ7gu12T6x0qdTEzcwqEfleci7JwugVNIF3U//0FWKnJT7ptG+20B2jfDqnZAg==",
+ "license": "MIT",
+ "dependencies": {
+ "cookie": "^1.0.1",
+ "set-cookie-parser": "^2.6.0"
+ },
+ "engines": {
+ "node": ">=20.0.0"
+ },
+ "peerDependencies": {
+ "react": ">=18",
+ "react-dom": ">=18"
+ },
+ "peerDependenciesMeta": {
+ "react-dom": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/react-router-dom": {
+ "version": "7.18.1",
+ "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-7.18.1.tgz",
+ "integrity": "sha512-KaZh+X/6UtEp28x51AUYZDMg9NGoz2ja3dNHa+ta/tk40vCzKhQ/RypCWBMLbmDr6//E24Vv5uPsrqXFozdkAg==",
+ "license": "MIT",
+ "dependencies": {
+ "react-router": "7.18.1"
+ },
+ "engines": {
+ "node": ">=20.0.0"
+ },
+ "peerDependencies": {
+ "react": ">=18",
+ "react-dom": ">=18"
+ }
+ },
"node_modules/react-style-singleton": {
"version": "2.2.3",
"resolved": "https://registry.npmjs.org/react-style-singleton/-/react-style-singleton-2.2.3.tgz",
@@ -11287,7 +11325,6 @@
"resolved": "https://registry.npmjs.org/rollup/-/rollup-4.59.0.tgz",
"integrity": "sha512-2oMpl67a3zCH9H79LeMcbDhXW/UmWG/y2zuqnF2jQq5uq9TbM9TVyXvA4+t+ne2IIkBdrLpAaRQAvo7YI/Yyeg==",
"license": "MIT",
- "peer": true,
"dependencies": {
"@types/estree": "1.0.8"
},
@@ -11494,6 +11531,12 @@
"node": ">=20.0.0"
}
},
+ "node_modules/set-cookie-parser": {
+ "version": "2.7.2",
+ "resolved": "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-2.7.2.tgz",
+ "integrity": "sha512-oeM1lpU/UvhTxw+g3cIfxXHyJRc/uidd3yK1P242gzHds0udQBYzs3y8j4gCCW+ZJ7ad0yctld8RYO+bdurlvw==",
+ "license": "MIT"
+ },
"node_modules/set-function-length": {
"version": "1.2.2",
"resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz",
@@ -12032,6 +12075,25 @@
"integrity": "sha512-e4hG1hRwoOdRb37cIMSgzNsxyzKfayW6VOflrwvR+/bzrkyxY/31WkbgnQpgtrNp1SdpJvpUAGTa/ZoiPNDuRQ==",
"dev": true
},
+ "node_modules/swiper": {
+ "version": "14.0.1",
+ "resolved": "https://registry.npmjs.org/swiper/-/swiper-14.0.1.tgz",
+ "integrity": "sha512-dibQY282S5rn6S9Ba+GTIvofyY4Qujy526a0cPaJnjR2S18Z7HMGKZBr8k/3ukboeKW/ig5h0q//7CYip0MCQw==",
+ "funding": [
+ {
+ "type": "custom",
+ "url": "https://sponsors.nolimits4web.com"
+ },
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/nolimits4web"
+ }
+ ],
+ "license": "MIT",
+ "engines": {
+ "node": ">= 4.7.0"
+ }
+ },
"node_modules/symbol-tree": {
"version": "3.2.4",
"resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz",
@@ -12164,7 +12226,6 @@
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz",
"integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==",
"license": "MIT",
- "peer": true,
"engines": {
"node": ">=12"
},
@@ -12262,8 +12323,7 @@
"node_modules/tslib": {
"version": "2.6.2",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz",
- "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==",
- "peer": true
+ "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q=="
},
"node_modules/type-check": {
"version": "0.4.0",
@@ -12383,7 +12443,6 @@
"integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==",
"devOptional": true,
"license": "Apache-2.0",
- "peer": true,
"bin": {
"tsc": "bin/tsc",
"tsserver": "bin/tsserver"
@@ -12639,7 +12698,6 @@
"resolved": "https://registry.npmjs.org/vite/-/vite-7.3.6.tgz",
"integrity": "sha512-4XP60spRGjSZFf1qYH+dJIkK2znL3zQfl9KkOV9MkkRR/3Dls0dxaBsQPTloEc5BLXWPL9vsOxopxyKoMmDueg==",
"license": "MIT",
- "peer": true,
"dependencies": {
"esbuild": "^0.27.0 || ^0.28.0",
"fdir": "^6.5.0",
@@ -13170,7 +13228,6 @@
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz",
"integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==",
"license": "MIT",
- "peer": true,
"engines": {
"node": ">=12"
},
@@ -13560,6 +13617,13 @@
"workbox-core": "7.4.1"
}
},
+ "node_modules/workbox-background-sync/node_modules/idb": {
+ "version": "7.1.1",
+ "resolved": "https://registry.npmjs.org/idb/-/idb-7.1.1.tgz",
+ "integrity": "sha512-gchesWBzyvGHRO9W8tzUWFDycow5gwjvFKfyV9FF32Y7F50yZMp7mP+T2mJIWFx49zicqyC4uefHM17o6xKIVQ==",
+ "dev": true,
+ "license": "ISC"
+ },
"node_modules/workbox-broadcast-update": {
"version": "7.4.1",
"resolved": "https://registry.npmjs.org/workbox-broadcast-update/-/workbox-broadcast-update-7.4.1.tgz",
@@ -13643,7 +13707,6 @@
"integrity": "sha512-PlXPeEWMXMZ7sPYOHqmDyCJzcfNrUr3fGNKtezX14ykXOEIvyK81d+qydx89KY5O71FKMPaQ2vBfBFI5NHR63A==",
"dev": true,
"license": "MIT",
- "peer": true,
"dependencies": {
"fast-deep-equal": "^3.1.3",
"fast-uri": "^3.0.1",
@@ -13810,6 +13873,13 @@
"workbox-core": "7.4.1"
}
},
+ "node_modules/workbox-expiration/node_modules/idb": {
+ "version": "7.1.1",
+ "resolved": "https://registry.npmjs.org/idb/-/idb-7.1.1.tgz",
+ "integrity": "sha512-gchesWBzyvGHRO9W8tzUWFDycow5gwjvFKfyV9FF32Y7F50yZMp7mP+T2mJIWFx49zicqyC4uefHM17o6xKIVQ==",
+ "dev": true,
+ "license": "ISC"
+ },
"node_modules/workbox-google-analytics": {
"version": "7.4.1",
"resolved": "https://registry.npmjs.org/workbox-google-analytics/-/workbox-google-analytics-7.4.1.tgz",
@@ -14061,8 +14131,7 @@
"node_modules/xterm": {
"version": "4.14.1",
"resolved": "https://registry.npmjs.org/xterm/-/xterm-4.14.1.tgz",
- "integrity": "sha512-jgzNg5BuGPwq5/M4dGnmbghZvHx2jaj+9crSEt15bV34Za49VziBmCu7zIy88zUKKiGTxeo7aVzirFSJArIMFw==",
- "peer": true
+ "integrity": "sha512-jgzNg5BuGPwq5/M4dGnmbghZvHx2jaj+9crSEt15bV34Za49VziBmCu7zIy88zUKKiGTxeo7aVzirFSJArIMFw=="
},
"node_modules/xterm-addon-fit": {
"version": "0.5.0",
diff --git a/package.json b/package.json
index cced08365..683658339 100644
--- a/package.json
+++ b/package.json
@@ -35,6 +35,7 @@
"dompurify": "^3.2.5",
"file-saver": "^2.0.5",
"framer-motion": "^10.2.4",
+ "idb": "^8.0.3",
"lodash.debounce": "^4.0.8",
"lodash.sortby": "^4.7.0",
"lunr": "^2.3.9",
@@ -47,6 +48,8 @@
"react-hotkeys-hook": "^4.5.0",
"react-icons": "^4.12.0",
"react-intl": "^6.6.8",
+ "react-router-dom": "^7.18.1",
+ "swiper": "^14.0.1",
"vite": "^7.3.1",
"vscode-jsonrpc": "^8.0.0",
"vscode-languageserver-protocol": "^3.16.0",
diff --git a/src/App.tsx b/src/App.tsx
index 020de3f2a..7e8366cb3 100644
--- a/src/App.tsx
+++ b/src/App.tsx
@@ -24,12 +24,13 @@ import { LanguageServerClientProvider } from "./language-server/language-server-
import { LoggingProvider } from "./logging/logging-hooks";
import TranslationProvider from "./messages/TranslationProvider";
import ProjectDropTarget from "./project/ProjectDropTarget";
-import { RouterProvider } from "./router-hooks";
+import { ProjectsProvider } from "./project/projects-hooks";
+import { RouterProvider } from "react-router-dom";
+import { router } from "./router";
import SessionSettingsProvider from "./settings/session-settings";
import SettingsProvider from "./settings/settings";
import BeforeUnloadDirtyCheck from "./workbench/BeforeUnloadDirtyCheck";
import { SelectionProvider } from "./workbench/use-selection";
-import Workbench from "./workbench/Workbench";
const isMockDeviceMode = () =>
// We use a cookie set from the e2e tests. Avoids having separate test and live builds.
@@ -79,15 +80,15 @@ const App = () => {
-
+
-
+
-
+
diff --git a/src/common/BackArrow.tsx b/src/common/BackArrow.tsx
new file mode 100644
index 000000000..c10f001ad
--- /dev/null
+++ b/src/common/BackArrow.tsx
@@ -0,0 +1,17 @@
+/**
+ * (c) 2024, Micro:bit Educational Foundation and contributors
+ *
+ * SPDX-License-Identifier: MIT
+ */
+import { Icon, IconProps } from "@chakra-ui/react";
+
+const BackArrow = (props: IconProps) => (
+
+
+
+);
+
+export default BackArrow;
diff --git a/src/common/HomeButton.tsx b/src/common/HomeButton.tsx
new file mode 100644
index 000000000..169ea30ca
--- /dev/null
+++ b/src/common/HomeButton.tsx
@@ -0,0 +1,66 @@
+/**
+ * (c) 2026, Micro:bit Educational Foundation and contributors
+ *
+ * SPDX-License-Identifier: MIT
+ */
+import { Button, IconButton } from "@chakra-ui/react";
+import { useCallback } from "react";
+import { RiHome2Line } from "react-icons/ri";
+import { useIntl } from "react-intl";
+import { useNavigate } from "react-router-dom";
+import { createHomePageUrl } from "../urls";
+import BackArrow from "./BackArrow";
+
+// Matches the "Learn more" button in the home page banner.
+export const homeButtonStyle = {
+ backgroundColor: "white",
+ border: 0,
+ textColor: "brand.700",
+ _hover: { textDecoration: "none" },
+ _focusVisible: {
+ boxShadow:
+ "0 0 0 2px var(--chakra-colors-brand-600), 0 0 0 6px rgba(255, 255, 255, 0.8)",
+ outline: "none",
+ },
+} as const;
+
+interface HomeButtonProps {
+ /** Render as an icon-only button (e.g. when the sidebar is collapsed). */
+ iconOnly?: boolean;
+}
+
+/**
+ * A "← Home" button that navigates to the project list.
+ */
+const HomeButton = ({ iconOnly }: HomeButtonProps) => {
+ const intl = useIntl();
+ const navigate = useNavigate();
+ const label = intl.formatMessage({ id: "home-action" });
+ const handleClick = useCallback(() => {
+ navigate(createHomePageUrl());
+ }, [navigate]);
+
+ if (iconOnly) {
+ // Collapsed: a plain white home icon (no button fill) reads more clearly.
+ return (
+ }
+ onClick={handleClick}
+ aria-label={label}
+ variant="ghost"
+ color="white"
+ fontSize="3xl"
+ _hover={{ bg: "whiteAlpha.300" }}
+ _active={{ bg: "whiteAlpha.400" }}
+ _focusVisible={{ boxShadow: "outline" }}
+ />
+ );
+ }
+ return (
+ } onClick={handleClick} {...homeButtonStyle}>
+ {label}
+
+ );
+};
+
+export default HomeButton;
diff --git a/src/common/LoadingOverlay.tsx b/src/common/LoadingOverlay.tsx
new file mode 100644
index 000000000..c0353d73f
--- /dev/null
+++ b/src/common/LoadingOverlay.tsx
@@ -0,0 +1,48 @@
+/**
+ * (c) 2024, Micro:bit Educational Foundation and contributors
+ *
+ * SPDX-License-Identifier: MIT
+ */
+import { Modal, ModalContent, ModalOverlay, Spinner } from "@chakra-ui/react";
+import { useIntl } from "react-intl";
+
+interface LoadingOverlayProps {
+ loading: boolean;
+}
+
+const doNothing = () => {};
+
+const LoadingOverlay = ({ loading }: LoadingOverlayProps) => {
+ const intl = useIntl();
+ return (
+
+
+
+
+
+
+ );
+};
+
+export default LoadingOverlay;
diff --git a/src/common/zIndex.ts b/src/common/zIndex.ts
index 58b8cdbe8..854d109f8 100644
--- a/src/common/zIndex.ts
+++ b/src/common/zIndex.ts
@@ -5,7 +5,7 @@
*/
export const zIndexCode = 1;
export const zIndexBreadcrumbContainer = 2;
-export const zIndexProjectAreaMenu = 3;
+export const zIndexFilesAreaMenu = 3;
export const zIndexCodePopUp = 3;
export const zIndexSidebarHeader = 3;
export const splitViewDivider = 3;
diff --git a/src/deployment/default/images/accessibility.svg b/src/deployment/default/images/accessibility.svg
new file mode 100644
index 000000000..b55922589
--- /dev/null
+++ b/src/deployment/default/images/accessibility.svg
@@ -0,0 +1,3 @@
+
diff --git a/src/deployment/default/images/animated-animals.gif b/src/deployment/default/images/animated-animals.gif
new file mode 100644
index 000000000..1231c37ff
Binary files /dev/null and b/src/deployment/default/images/animated-animals.gif differ
diff --git a/src/deployment/default/images/banner-background.svg b/src/deployment/default/images/banner-background.svg
new file mode 100644
index 000000000..d23534394
--- /dev/null
+++ b/src/deployment/default/images/banner-background.svg
@@ -0,0 +1,3 @@
+
diff --git a/src/deployment/default/images/beating-heart.gif b/src/deployment/default/images/beating-heart.gif
new file mode 100644
index 000000000..1231c37ff
Binary files /dev/null and b/src/deployment/default/images/beating-heart.gif differ
diff --git a/src/deployment/default/images/emotion-badge.png b/src/deployment/default/images/emotion-badge.png
new file mode 100644
index 000000000..0de505b6a
Binary files /dev/null and b/src/deployment/default/images/emotion-badge.png differ
diff --git a/src/deployment/default/images/first-lessons-python.svg b/src/deployment/default/images/first-lessons-python.svg
new file mode 100644
index 000000000..b55922589
--- /dev/null
+++ b/src/deployment/default/images/first-lessons-python.svg
@@ -0,0 +1,3 @@
+
diff --git a/src/deployment/default/images/flashing-emotions.gif b/src/deployment/default/images/flashing-emotions.gif
new file mode 100644
index 000000000..1231c37ff
Binary files /dev/null and b/src/deployment/default/images/flashing-emotions.gif differ
diff --git a/src/deployment/default/images/get-silly.png b/src/deployment/default/images/get-silly.png
new file mode 100644
index 000000000..0de505b6a
Binary files /dev/null and b/src/deployment/default/images/get-silly.png differ
diff --git a/src/deployment/default/images/heart.png b/src/deployment/default/images/heart.png
new file mode 100644
index 000000000..0de505b6a
Binary files /dev/null and b/src/deployment/default/images/heart.png differ
diff --git a/src/deployment/default/images/troubleshooting.svg b/src/deployment/default/images/troubleshooting.svg
new file mode 100644
index 000000000..b55922589
--- /dev/null
+++ b/src/deployment/default/images/troubleshooting.svg
@@ -0,0 +1,3 @@
+
diff --git a/src/deployment/default/images/user-guide.svg b/src/deployment/default/images/user-guide.svg
new file mode 100644
index 000000000..b55922589
--- /dev/null
+++ b/src/deployment/default/images/user-guide.svg
@@ -0,0 +1,3 @@
+
diff --git a/src/fs/db.ts b/src/fs/db.ts
new file mode 100644
index 000000000..2113302ac
--- /dev/null
+++ b/src/fs/db.ts
@@ -0,0 +1,75 @@
+/**
+ * (c) 2026, Micro:bit Educational Foundation and contributors
+ *
+ * SPDX-License-Identifier: MIT
+ */
+import { DBSchema, IDBPDatabase, openDB } from "idb";
+
+/**
+ * A project as persisted in IndexedDB.
+ *
+ * This is the multi-project "library". The currently open project is loaded
+ * from here into the in-memory {@link FileSystem} working copy and saved back
+ * as the user edits.
+ */
+export interface ProjectRecord {
+ /** Stable project identifier. */
+ id: string;
+ /** User-visible project name. */
+ name: string;
+ /** File content keyed by filename, base64 encoded (as in PythonProject). */
+ files: Record;
+ /** Last modified time, milliseconds since the epoch. */
+ timestamp: number;
+}
+
+const DB_NAME = "python-editor";
+const DB_VERSION = 1;
+const PROJECTS_STORE = "projects";
+
+interface Schema extends DBSchema {
+ [PROJECTS_STORE]: {
+ key: string;
+ value: ProjectRecord;
+ };
+}
+
+/**
+ * Data access layer for the multi-project store.
+ */
+export class ProjectsDatabase {
+ private dbPromise: Promise> | undefined;
+
+ private db(): Promise> {
+ if (!this.dbPromise) {
+ this.dbPromise = openDB(DB_NAME, DB_VERSION, {
+ upgrade(db) {
+ db.createObjectStore(PROJECTS_STORE, { keyPath: "id" });
+ },
+ });
+ }
+ return this.dbPromise;
+ }
+
+ async getAll(): Promise {
+ const db = await this.db();
+ return db.getAll(PROJECTS_STORE);
+ }
+
+ async get(id: string): Promise {
+ const db = await this.db();
+ return db.get(PROJECTS_STORE, id);
+ }
+
+ async put(record: ProjectRecord): Promise {
+ const db = await this.db();
+ await db.put(PROJECTS_STORE, record);
+ }
+
+ async delete(id: string): Promise {
+ const db = await this.db();
+ await db.delete(PROJECTS_STORE, id);
+ }
+}
+
+export const projectsDb = new ProjectsDatabase();
diff --git a/src/fs/project-sync.ts b/src/fs/project-sync.ts
new file mode 100644
index 000000000..d19d0e0aa
--- /dev/null
+++ b/src/fs/project-sync.ts
@@ -0,0 +1,50 @@
+/**
+ * Cross-tab project synchronisation via BroadcastChannel.
+ *
+ * Keeps the project library and the open project in sync between tabs and
+ * windows in the same browser.
+ *
+ * (c) 2026, Micro:bit Educational Foundation and contributors
+ *
+ * SPDX-License-Identifier: MIT
+ */
+export enum ProjectSyncMessageType {
+ /** A project's contents or name changed (or a project was created). */
+ ReloadProject = "reload-project",
+ /** A project was deleted. */
+ DeleteProject = "delete-project",
+}
+
+export interface ProjectSyncMessage {
+ type: ProjectSyncMessageType;
+ projectIds: string[];
+}
+
+const channel =
+ typeof BroadcastChannel !== "undefined"
+ ? new BroadcastChannel("python-editor-projects")
+ : undefined;
+
+export const postProjectSync = (message: ProjectSyncMessage): void => {
+ channel?.postMessage(message);
+};
+
+/**
+ * Subscribe to project sync messages from other tabs.
+ *
+ * Note: BroadcastChannel does not deliver a message to the tab that sent it,
+ * so listeners only see changes made elsewhere.
+ *
+ * @returns An unsubscribe function.
+ */
+export const addProjectSyncListener = (
+ listener: (message: ProjectSyncMessage) => void
+): (() => void) => {
+ if (!channel) {
+ return () => {};
+ }
+ const handler = (event: MessageEvent) =>
+ listener(event.data);
+ channel.addEventListener("message", handler);
+ return () => channel.removeEventListener("message", handler);
+};
diff --git a/src/homepage/ActionCard.tsx b/src/homepage/ActionCard.tsx
new file mode 100644
index 000000000..3abbf980b
--- /dev/null
+++ b/src/homepage/ActionCard.tsx
@@ -0,0 +1,69 @@
+/**
+ * (c) 2023, Center for Computational Thinking and Design at Aarhus University and contributors
+ * Modifications (c) 2024-2026, Micro:bit Educational Foundation and contributors
+ *
+ * SPDX-License-Identifier: MIT
+ */
+import {
+ Button,
+ Card,
+ CardBody,
+ Icon,
+ LinkBox,
+ LinkOverlay,
+ VStack,
+} from "@chakra-ui/react";
+import { IconType } from "react-icons/lib";
+import { FormattedMessage } from "react-intl";
+import { shortScreenHeightBreakpoint } from "./responsive";
+
+interface ActionCardProps {
+ onClick: () => void;
+ icon: IconType;
+ textId: string;
+}
+
+/**
+ * A large, coloured call-to-action card used in the projects carousel
+ * (e.g. "New project", "View all projects").
+ */
+const ActionCard = ({ onClick, icon, textId }: ActionCardProps) => {
+ return (
+
+
+
+
+
+
+
+
+
+
+
+
+ );
+};
+
+export default ActionCard;
diff --git a/src/homepage/DefaultPageLayout.tsx b/src/homepage/DefaultPageLayout.tsx
new file mode 100644
index 000000000..2b17bd2a3
--- /dev/null
+++ b/src/homepage/DefaultPageLayout.tsx
@@ -0,0 +1,112 @@
+/**
+ * (c) 2024-2026, Micro:bit Educational Foundation and contributors
+ *
+ * SPDX-License-Identifier: MIT
+ */
+import { Box, Flex, Heading, HStack, VStack } from "@chakra-ui/react";
+import { ReactNode } from "react";
+import { Link as RouterLink } from "react-router-dom";
+import HomeButton from "../common/HomeButton";
+import { useDeployment } from "../deployment";
+import SettingsMenu from "../settings/SettingsMenu";
+import { createHomePageUrl } from "../urls";
+import HelpMenu from "../workbench/HelpMenu";
+
+interface DefaultPageLayoutProps {
+ children: ReactNode;
+ /** Show a "← Home" button on the left instead of the app branding. */
+ showBackToHome?: boolean;
+}
+
+const Branding = () => {
+ const brand = useDeployment();
+ return (
+
+ {brand.squareLogo && (
+ <>
+
+
+ {brand.squareLogo}
+
+
+ {brand.horizontalLogo}
+
+
+
+ >
+ )}
+ {/* Product name; deliberately not translated. */}
+
+ Python Editor
+
+
+ );
+};
+
+/**
+ * Simple full-height page layout with a top toolbar and a scrollable body.
+ *
+ * A pared-down version of the CreateAI layout suitable for this prototype.
+ */
+const DefaultPageLayout = ({
+ children,
+ showBackToHome = false,
+}: DefaultPageLayoutProps) => {
+ return (
+
+
+ {showBackToHome ? : }
+
+
+
+
+
+
+ {children}
+
+
+ );
+};
+
+export default DefaultPageLayout;
diff --git a/src/homepage/HelpCards.tsx b/src/homepage/HelpCards.tsx
new file mode 100644
index 000000000..8c0e29e37
--- /dev/null
+++ b/src/homepage/HelpCards.tsx
@@ -0,0 +1,55 @@
+/**
+ * (c) 2024, Micro:bit Educational Foundation and contributors
+ *
+ * SPDX-License-Identifier: MIT
+ */
+import { IntlShape } from "react-intl";
+import {
+ accessibilityUrl,
+ supportSiteFolderUrl,
+ userGuideUrl,
+} from "./external-links";
+import helpImage1 from "theme-package/images/user-guide.svg";
+import helpImage2 from "theme-package/images/troubleshooting.svg";
+import helpImage3 from "theme-package/images/accessibility.svg";
+import ResourceCard from "./ResourceCard";
+
+interface HelpConfig {
+ titleId: string;
+ url: string;
+ imgSrc: string;
+ imagePadding?: number;
+ aspectRatio?: number;
+}
+
+const helpConfig: HelpConfig[] = [
+ {
+ titleId: "user-guide",
+ url: userGuideUrl(),
+ imgSrc: helpImage1,
+ },
+ {
+ titleId: "troubleshooting-resource-title",
+ url: supportSiteFolderUrl(),
+ imgSrc: helpImage2,
+ },
+ {
+ titleId: "accessibility-resource-title",
+ url: accessibilityUrl(),
+ imgSrc: helpImage3,
+ },
+];
+
+export const createHelpCards = (intl: IntlShape) =>
+ helpConfig.map((help) => (
+
+ ));
diff --git a/src/homepage/HomePage.tsx b/src/homepage/HomePage.tsx
new file mode 100644
index 000000000..1d44ef8b8
--- /dev/null
+++ b/src/homepage/HomePage.tsx
@@ -0,0 +1,84 @@
+/**
+ * (c) 2023, Center for Computational Thinking and Design at Aarhus University and contributors
+ * Modifications (c) 2024-2026, Micro:bit Educational Foundation and contributors
+ *
+ * SPDX-License-Identifier: MIT
+ */
+import { Heading } from "@chakra-ui/react";
+import { FormattedMessage, useIntl } from "react-intl";
+import { useProjects } from "../project/projects-hooks";
+import { useSettings } from "../settings/settings";
+import CarouselRow from "./carousel/CarouselRow";
+import DefaultPageLayout from "./DefaultPageLayout";
+import { createHelpCards } from "./HelpCards";
+import HomepageBanner from "./HomepageBanner";
+import ImportProjectButton from "./ImportProjectButton";
+import { createLessonCards } from "./LessonCards";
+import NewProjectCard from "./NewProjectCard";
+import ProjectCard from "./ProjectCard";
+import { createProjectIdeaCards } from "./ProjectIdeaCards";
+import { useProjectCardActions } from "./use-project-card-actions";
+import ViewAllProjectsCard from "./ViewAllProjectsCard";
+import ViewAllProjectsLink from "./ViewAllProjectsLink";
+
+const numCardsDisplayed = 10;
+
+const HomePage = () => {
+ const intl = useIntl();
+ const [{ languageId }] = useSettings();
+ const { projects } = useProjects();
+ const { handleCreate, handleOpen, handleRenameDuplicate, handleDelete } =
+ useProjectCardActions("home");
+
+ const projectCards: JSX.Element[] = [
+ ,
+ ...projects.slice(0, numCardsDisplayed).map((project) => (
+
+ )),
+ ...(projects.length > numCardsDisplayed
+ ? []
+ : []),
+ ];
+
+ return (
+
+
+ ,
+ ,
+ ]}
+ titleElement={
+
+
+
+ }
+ />
+
+
+
+
+ );
+};
+
+export default HomePage;
diff --git a/src/homepage/HomepageBanner.tsx b/src/homepage/HomepageBanner.tsx
new file mode 100644
index 000000000..ff2745c8b
--- /dev/null
+++ b/src/homepage/HomepageBanner.tsx
@@ -0,0 +1,83 @@
+/**
+ * (c) 2024, Micro:bit Educational Foundation and contributors
+ *
+ * SPDX-License-Identifier: MIT
+ */
+import { Button, Heading, HStack, Link, Text, VStack } from "@chakra-ui/react";
+import { FormattedMessage } from "react-intl";
+import { useSettings } from "../settings/settings";
+import { learnMoreUrl } from "./external-links";
+import bannerBackground from "theme-package/images/banner-background.svg";
+
+// For landscape mobile screen sizes.
+const shortScreenHeightBreakpoint = "@media (max-height: 700px)";
+
+const HomepageBanner = () => {
+ const [settings] = useSettings();
+ return (
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ );
+};
+
+export default HomepageBanner;
diff --git a/src/homepage/ImportProjectButton.tsx b/src/homepage/ImportProjectButton.tsx
new file mode 100644
index 000000000..17131e61f
--- /dev/null
+++ b/src/homepage/ImportProjectButton.tsx
@@ -0,0 +1,65 @@
+/**
+ * (c) 2024-2026, Micro:bit Educational Foundation and contributors
+ *
+ * SPDX-License-Identifier: MIT
+ */
+import { Button, IconButton, Input } from "@chakra-ui/react";
+import { useCallback, useRef } from "react";
+import { RiUpload2Line } from "react-icons/ri";
+import { FormattedMessage, useIntl } from "react-intl";
+import { useImportProject } from "../project/use-import-project";
+
+/**
+ * Opens a file picker to import a hex as a new project. Shown as a labelled
+ * button on wider screens and an icon-only button on narrow ones.
+ */
+const ImportProjectButton = () => {
+ const intl = useIntl();
+ const importProject = useImportProject();
+ const inputRef = useRef(null);
+
+ const handleClick = useCallback(() => {
+ inputRef.current?.click();
+ }, []);
+
+ const handleChange = useCallback(
+ (e: React.ChangeEvent) => {
+ const files = e.target.files ? Array.from(e.target.files) : [];
+ // Allow re-selecting the same file.
+ e.target.value = "";
+ if (files.length > 0) {
+ void importProject(files, "file-upload");
+ }
+ },
+ [importProject]
+ );
+
+ return (
+ <>
+
+ }
+ onClick={handleClick}
+ aria-label={intl.formatMessage({ id: "import-file-action" })}
+ variant="ghost"
+ display={{ base: "inline-flex", sm: "none" }}
+ />
+ }
+ onClick={handleClick}
+ display={{ base: "none", sm: "inline-flex" }}
+ >
+
+
+ >
+ );
+};
+
+export default ImportProjectButton;
diff --git a/src/homepage/LessonCards.tsx b/src/homepage/LessonCards.tsx
new file mode 100644
index 000000000..403346932
--- /dev/null
+++ b/src/homepage/LessonCards.tsx
@@ -0,0 +1,38 @@
+/**
+ * (c) 2024, Micro:bit Educational Foundation and contributors
+ *
+ * SPDX-License-Identifier: MIT
+ *
+ * NOTE: placeholder content/URLs carried over from CreateAI for the prototype.
+ */
+import { IntlShape } from "react-intl";
+import { lessonUrl } from "./external-links";
+import lessonImage1 from "theme-package/images/first-lessons-python.svg";
+import ResourceCard from "./ResourceCard";
+
+interface LessonConfig {
+ titleId: string;
+ url: string;
+ imgSrc: string;
+}
+
+const lessons: LessonConfig[] = [
+ {
+ titleId: "first-lessons-with-python-resource-title",
+ url: "first-lessons-with-python-and-the-microbit",
+ imgSrc: lessonImage1,
+ },
+];
+
+export const createLessonCards = (intl: IntlShape) =>
+ lessons.map((lesson) => (
+
+ ));
diff --git a/src/homepage/NewProjectCard.tsx b/src/homepage/NewProjectCard.tsx
new file mode 100644
index 000000000..14c073f43
--- /dev/null
+++ b/src/homepage/NewProjectCard.tsx
@@ -0,0 +1,17 @@
+/**
+ * (c) 2024-2026, Micro:bit Educational Foundation and contributors
+ *
+ * SPDX-License-Identifier: MIT
+ */
+import { RiAddLine } from "react-icons/ri";
+import ActionCard from "./ActionCard";
+
+interface NewProjectCardProps {
+ onClick: () => void;
+}
+
+const NewProjectCard = ({ onClick }: NewProjectCardProps) => (
+
+);
+
+export default NewProjectCard;
diff --git a/src/homepage/ProjectCard.tsx b/src/homepage/ProjectCard.tsx
new file mode 100644
index 000000000..2e162805f
--- /dev/null
+++ b/src/homepage/ProjectCard.tsx
@@ -0,0 +1,123 @@
+/**
+ * (c) 2024, Micro:bit Educational Foundation and contributors
+ *
+ * SPDX-License-Identifier: MIT
+ */
+import {
+ Button,
+ Card,
+ CardBody,
+ Icon,
+ LinkBox,
+ LinkOverlay,
+ Stack,
+ Text,
+} from "@chakra-ui/react";
+import { useCallback } from "react";
+import { FormattedMessage, useIntl } from "react-intl";
+import PythonLogo from "../common/PythonLogo";
+import { ProjectRecord } from "../fs/db";
+import { timeAgo } from "./datetime";
+import ProjectCardActions from "./ProjectCardActions";
+import { ProjectNameDialogReason } from "./project-name";
+import { shortScreenHeightBreakpoint } from "./responsive";
+
+interface ProjectCardProps {
+ projectData: ProjectRecord;
+ isSelected?: boolean;
+ onSelected?: (id: string) => void;
+ onSkipToToolbar?: () => void;
+ onDeleteProject: (id: string) => void;
+ onOpenProject: (id: string) => void;
+ onRenameDuplicateProject: (
+ reason: ProjectNameDialogReason,
+ id: string
+ ) => void;
+}
+
+const ProjectCard = ({
+ projectData,
+ isSelected,
+ onSelected,
+ onSkipToToolbar,
+ onDeleteProject,
+ onOpenProject,
+ onRenameDuplicateProject,
+}: ProjectCardProps) => {
+ const intl = useIntl();
+ const { id, name, files, timestamp } = projectData;
+ const fileCount = Object.keys(files).length;
+ const hasCheckbox = !!onSelected;
+
+ const handleOpen = useCallback(
+ (e: React.MouseEvent) => {
+ e.preventDefault();
+ onOpenProject(id);
+ },
+ [id, onOpenProject]
+ );
+
+ return (
+
+
+
+
+
+
+
+ {name}
+
+
+
+
+
+ {timeAgo(intl, timestamp)}
+
+
+
+
+
+ );
+};
+
+export default ProjectCard;
diff --git a/src/homepage/ProjectCardActions.tsx b/src/homepage/ProjectCardActions.tsx
new file mode 100644
index 000000000..73bfae238
--- /dev/null
+++ b/src/homepage/ProjectCardActions.tsx
@@ -0,0 +1,152 @@
+/**
+ * (c) 2024-2026, Micro:bit Educational Foundation and contributors
+ *
+ * SPDX-License-Identifier: MIT
+ */
+import {
+ Button,
+ Checkbox,
+ HStack,
+ IconButton,
+ Menu,
+ MenuButton,
+ MenuItem,
+ MenuList,
+ Portal,
+ VisuallyHidden,
+} from "@chakra-ui/react";
+import { useCallback } from "react";
+import { MdMoreVert } from "react-icons/md";
+import {
+ RiDeleteBin2Line,
+ RiEdit2Line,
+ RiFileCopyLine,
+ RiFolderOpenLine,
+} from "react-icons/ri";
+import { FormattedMessage, useIntl } from "react-intl";
+import { ProjectNameDialogReason } from "./project-name";
+
+interface ProjectCardActionsProps {
+ id: string;
+ name: string;
+ isSelected?: boolean;
+ onSelected?: (id: string) => void;
+ onDeleteProject: (id: string) => void;
+ onOpenProject: (id: string) => void;
+ onRenameDuplicateProject: (
+ reason: ProjectNameDialogReason,
+ id: string
+ ) => void;
+ onSkipToToolbar?: () => void;
+}
+
+const ProjectCardActions = ({
+ id,
+ name,
+ isSelected,
+ onSelected,
+ onDeleteProject,
+ onRenameDuplicateProject,
+ onOpenProject,
+ onSkipToToolbar,
+}: ProjectCardActionsProps) => {
+ const intl = useIntl();
+ const handleRenameProject = useCallback(
+ () => onRenameDuplicateProject("rename", id),
+ [onRenameDuplicateProject, id]
+ );
+ const handleDuplicateProject = useCallback(
+ () => onRenameDuplicateProject("duplicate", id),
+ [onRenameDuplicateProject, id]
+ );
+
+ return (
+
+ {onSelected && (
+ onSelected(id)}
+ color="brand.600"
+ zIndex={1}
+ borderColor="gray.600"
+ _hover={{ backgroundColor: "blackAlpha.50" }}
+ borderBottomRightRadius="md"
+ h="60px"
+ >
+
+
+
+
+ )}
+ {onSkipToToolbar && (
+
+ )}
+
+
+ );
+};
+
+export default ProjectCardActions;
diff --git a/src/homepage/ProjectIdeaCards.tsx b/src/homepage/ProjectIdeaCards.tsx
new file mode 100644
index 000000000..a65cf3f39
--- /dev/null
+++ b/src/homepage/ProjectIdeaCards.tsx
@@ -0,0 +1,64 @@
+/**
+ * (c) 2024-2026, Micro:bit Educational Foundation and contributors
+ *
+ * SPDX-License-Identifier: MIT
+ */
+import { IntlShape } from "react-intl";
+import { projectUrl } from "./external-links";
+import animatedAnimals from "theme-package/images/animated-animals.gif";
+import beatingHeart from "theme-package/images/beating-heart.gif";
+import emotionBadge from "theme-package/images/emotion-badge.png";
+import flashingEmotions from "theme-package/images/flashing-emotions.gif";
+import getSilly from "theme-package/images/get-silly.png";
+import heart from "theme-package/images/heart.png";
+import ResourceCard from "./ResourceCard";
+
+interface ProjectIdeaConfig {
+ titleId: string;
+ // "make it, code it" project slug.
+ slug: string;
+ imgSrc: string;
+}
+
+const projectIdeas: ProjectIdeaConfig[] = [
+ {
+ titleId: "project-idea-heart-title",
+ slug: "heart",
+ imgSrc: heart,
+ },
+ {
+ titleId: "project-idea-beating-heart-title",
+ slug: "beating-heart",
+ imgSrc: beatingHeart,
+ },
+ {
+ titleId: "project-idea-animated-animals-title",
+ slug: "animated-animals",
+ imgSrc: animatedAnimals,
+ },
+ {
+ titleId: "project-idea-emotion-badge-title",
+ slug: "emotion-badge",
+ imgSrc: emotionBadge,
+ },
+ {
+ titleId: "project-idea-get-silly-title",
+ slug: "get-silly",
+ imgSrc: getSilly,
+ },
+ {
+ titleId: "project-idea-flashing-emotions-title",
+ slug: "flashing-emotions",
+ imgSrc: flashingEmotions,
+ },
+];
+
+export const createProjectIdeaCards = (intl: IntlShape, languageId: string) =>
+ projectIdeas.map((project) => (
+
+ ));
diff --git a/src/homepage/ProjectNameBody.tsx b/src/homepage/ProjectNameBody.tsx
new file mode 100644
index 000000000..fa764ebe8
--- /dev/null
+++ b/src/homepage/ProjectNameBody.tsx
@@ -0,0 +1,31 @@
+/**
+ * (c) 2026, Micro:bit Educational Foundation and contributors
+ *
+ * SPDX-License-Identifier: MIT
+ */
+import { FormControl, FormLabel, Input } from "@chakra-ui/react";
+import { FormattedMessage, useIntl } from "react-intl";
+import { InputDialogBody } from "../common/InputDialog";
+
+const ProjectNameBody = ({
+ value,
+ setValue,
+ validationResult,
+}: InputDialogBody) => {
+ const intl = useIntl();
+ return (
+
+
+
+
+ setValue(e.target.value)}
+ aria-label={intl.formatMessage({ id: "name-text" })}
+ />
+
+ );
+};
+
+export default ProjectNameBody;
diff --git a/src/homepage/ProjectsPage.tsx b/src/homepage/ProjectsPage.tsx
new file mode 100644
index 000000000..6908a27b8
--- /dev/null
+++ b/src/homepage/ProjectsPage.tsx
@@ -0,0 +1,268 @@
+/**
+ * (c) 2024-2026, Micro:bit Educational Foundation and contributors
+ *
+ * SPDX-License-Identifier: MIT
+ */
+import {
+ Box,
+ Container,
+ Flex,
+ Heading,
+ HStack,
+ SimpleGrid,
+ Slide,
+ Stack,
+ Text,
+ useBreakpointValue,
+ VStack,
+} from "@chakra-ui/react";
+import { useCallback, useEffect, useMemo, useRef, useState } from "react";
+import { FormattedMessage } from "react-intl";
+import { ProjectRecord } from "../fs/db";
+import { useProjects } from "../project/projects-hooks";
+import DefaultPageLayout from "./DefaultPageLayout";
+import ProjectCard from "./ProjectCard";
+import { ProjectNameDialogReason } from "./project-name";
+import ProjectsToolbar from "./ProjectsToolbar";
+import Search from "./Search";
+import SortInput from "./SortInput";
+import { useProjectCardActions } from "./use-project-card-actions";
+
+type OrderByField = "timestamp" | "name";
+
+const searchScore = (project: ProjectRecord, terms: string[]): number => {
+ const name = project.name.toLowerCase();
+ const fileNames = Object.keys(project.files).map((f) => f.toLowerCase());
+ // Every term must match the name or one of the file names.
+ const allMatch = terms.every(
+ (t) => name.includes(t) || fileNames.some((f) => f.includes(t))
+ );
+ if (!allMatch) {
+ return 0;
+ }
+ let score = 0;
+ for (const term of terms) {
+ if (name === term) {
+ score += 100;
+ } else if (name.startsWith(term)) {
+ score += 50;
+ } else if (name.includes(term)) {
+ score += 30;
+ }
+ if (fileNames.some((f) => f.includes(term))) {
+ score += 5;
+ }
+ }
+ return score;
+};
+
+const ProjectsPage = () => {
+ const { projects } = useProjects();
+ const { handleOpen, handleRenameDuplicate, handleDelete, handleDeleteMany } =
+ useProjectCardActions("projects");
+
+ const [selectedProjectIds, setSelectedProjectIds] = useState([]);
+ const [query, setQuery] = useState("");
+ const [orderByField, setOrderByField] = useState("timestamp");
+ const [orderByDirection, setOrderByDirection] = useState<"asc" | "desc">(
+ "desc"
+ );
+ const mobileIconOnly = useBreakpointValue({ base: true, md: false });
+
+ // Drop selections for projects that no longer exist.
+ useEffect(() => {
+ const ids = new Set(projects.map((p) => p.id));
+ setSelectedProjectIds((prev) => prev.filter((id) => ids.has(id)));
+ }, [projects]);
+
+ const handleQueryChange = useCallback(
+ (e: React.ChangeEvent) => {
+ if (e.target.value.trim()) {
+ setSelectedProjectIds([]);
+ }
+ setQuery(e.target.value);
+ },
+ []
+ );
+
+ const handleOrderByFieldChange = useCallback(
+ (e: React.ChangeEvent) => {
+ const value = e.target.value as OrderByField;
+ setOrderByField(value);
+ setOrderByDirection(value === "name" ? "asc" : "desc");
+ },
+ []
+ );
+ const toggleOrderByDirection = useCallback(() => {
+ setOrderByDirection((prev) => (prev === "asc" ? "desc" : "asc"));
+ }, []);
+
+ const updateSelectedProjects = useCallback((id: string) => {
+ setSelectedProjectIds((prev) =>
+ prev.includes(id) ? prev.filter((v) => v !== id) : [...prev, id]
+ );
+ }, []);
+ const clearSelection = useCallback(() => setSelectedProjectIds([]), []);
+
+ const processedProjects = useMemo(() => {
+ const trimmed = query.toLowerCase().trim();
+ if (trimmed) {
+ const terms = trimmed.split(/\s+/);
+ return projects
+ .map((p) => ({ project: p, score: searchScore(p, terms) }))
+ .filter((x) => x.score > 0)
+ .sort((a, b) => b.score - a.score)
+ .map((x) => x.project);
+ }
+ const sorted = [...projects].sort((a, b) => {
+ if (orderByField === "name") {
+ return a.name.toLowerCase().localeCompare(b.name.toLowerCase());
+ }
+ return a.timestamp - b.timestamp;
+ });
+ return orderByDirection === "desc" ? sorted.reverse() : sorted;
+ }, [projects, query, orderByField, orderByDirection]);
+
+ const hasSelection = selectedProjectIds.length > 0;
+ const lastSelectionRef = useRef(selectedProjectIds);
+ if (hasSelection) {
+ lastSelectionRef.current = selectedProjectIds;
+ }
+
+ const desktopToolbarRef = useRef(null);
+ const mobileToolbarRef = useRef(null);
+ const handleSkipToToolbar = useCallback(() => {
+ const toolbar = desktopToolbarRef.current?.offsetParent
+ ? desktopToolbarRef.current
+ : mobileToolbarRef.current;
+ toolbar?.querySelector("button")?.focus();
+ }, []);
+
+ const handleToolbarRenameDuplicate = useCallback(
+ (reason: ProjectNameDialogReason) => {
+ if (selectedProjectIds.length === 1) {
+ void handleRenameDuplicate(reason, selectedProjectIds[0]);
+ }
+ },
+ [handleRenameDuplicate, selectedProjectIds]
+ );
+ const handleToolbarDelete = useCallback(() => {
+ void handleDeleteMany(selectedProjectIds);
+ }, [handleDeleteMany, selectedProjectIds]);
+
+ return (
+ <>
+
+
+
+
+
+
+
+ setQuery("")}
+ maxW="30ch"
+ my="1px"
+ />
+ {hasSelection && (
+
+
+
+ )}
+
+
+
+ {processedProjects.map((project) => (
+
+
+
+ ))}
+
+ {query.trim() && processedProjects.length === 0 && (
+
+
+
+
+
+ )}
+
+
+
+
+
+
+
+
+ >
+ );
+};
+
+export default ProjectsPage;
diff --git a/src/homepage/ProjectsToolbar.tsx b/src/homepage/ProjectsToolbar.tsx
new file mode 100644
index 000000000..4b5ac9eec
--- /dev/null
+++ b/src/homepage/ProjectsToolbar.tsx
@@ -0,0 +1,117 @@
+/**
+ * (c) 2024-2026, Micro:bit Educational Foundation and contributors
+ *
+ * SPDX-License-Identifier: MIT
+ */
+import {
+ Button,
+ ButtonGroup,
+ ButtonGroupProps,
+ IconButton,
+} from "@chakra-ui/react";
+import {
+ RiCloseLine,
+ RiDeleteBin2Line,
+ RiEdit2Line,
+ RiFileCopyLine,
+} from "react-icons/ri";
+import { FormattedMessage, useIntl } from "react-intl";
+import { ProjectNameDialogReason } from "./project-name";
+
+interface ProjectsToolbarProps extends ButtonGroupProps {
+ selectedProjectIds: string[];
+ onRenameDuplicateProject: (reason: ProjectNameDialogReason) => void;
+ onDeleteProject: () => void;
+ onClearSelection: () => void;
+ iconOnly?: boolean;
+}
+
+const ProjectsToolbar = ({
+ selectedProjectIds,
+ onRenameDuplicateProject,
+ onDeleteProject,
+ onClearSelection,
+ iconOnly,
+ ...rest
+}: ProjectsToolbarProps) => {
+ const count = selectedProjectIds.length;
+ const isSingle = count === 1;
+ const intl = useIntl();
+ const iconFontSize = iconOnly ? "xl" : undefined;
+
+ return (
+ button": { borderRadius: 0 },
+ "& > button + button": {
+ borderLeftWidth: "1px",
+ borderColor: "gray.200",
+ },
+ }}
+ {...rest}
+ >
+ {isSingle &&
+ (iconOnly ? (
+ onRenameDuplicateProject("rename")}
+ icon={}
+ fontSize={iconFontSize}
+ aria-label={intl.formatMessage({ id: "rename-project-action" })}
+ />
+ ) : (
+
+ ))}
+ {isSingle &&
+ (iconOnly ? (
+ onRenameDuplicateProject("duplicate")}
+ icon={}
+ fontSize={iconFontSize}
+ aria-label={intl.formatMessage({ id: "duplicate-project-action" })}
+ />
+ ) : (
+
+ ))}
+ {iconOnly ? (
+ }
+ fontSize={iconFontSize}
+ aria-label={intl.formatMessage({ id: "delete-project-action" })}
+ />
+ ) : (
+ }>
+
+
+ )}
+ {iconOnly ? (
+ }
+ fontSize={iconFontSize}
+ aria-label={intl.formatMessage({ id: "clear" })}
+ />
+ ) : (
+ } onClick={onClearSelection}>
+
+
+ )}
+
+ );
+};
+
+export default ProjectsToolbar;
diff --git a/src/homepage/ResourceCard.tsx b/src/homepage/ResourceCard.tsx
new file mode 100644
index 000000000..573afda6c
--- /dev/null
+++ b/src/homepage/ResourceCard.tsx
@@ -0,0 +1,68 @@
+/**
+ * (c) 2024, Micro:bit Educational Foundation and contributors
+ *
+ * SPDX-License-Identifier: MIT
+ */
+import {
+ AspectRatio,
+ Box,
+ Heading,
+ HStack,
+ Image,
+ Link,
+ LinkBox,
+ LinkOverlay,
+ VStack,
+} from "@chakra-ui/react";
+import { ReactNode } from "react";
+
+interface ResourceCardProps {
+ aspectRatio?: number;
+ imagePadding?: number;
+ url: string;
+ imgSrc: string;
+ title: ReactNode;
+}
+
+const ResourceCard = ({
+ aspectRatio = 4 / 3,
+ imagePadding,
+ imgSrc,
+ url,
+ title,
+}: ResourceCardProps) => {
+ return (
+
+
+
+
+
+
+
+
+
+
+ {title}
+
+
+
+
+
+ );
+};
+
+export default ResourceCard;
diff --git a/src/homepage/Search.tsx b/src/homepage/Search.tsx
new file mode 100644
index 000000000..15ee39b2e
--- /dev/null
+++ b/src/homepage/Search.tsx
@@ -0,0 +1,72 @@
+/**
+ * (c) 2024-2026, Micro:bit Educational Foundation and contributors
+ *
+ * SPDX-License-Identifier: MIT
+ */
+import {
+ BoxProps,
+ IconButton,
+ Input,
+ InputGroup,
+ InputLeftElement,
+ InputRightElement,
+} from "@chakra-ui/react";
+import { useCallback, useRef } from "react";
+import { RiCloseLine, RiSearch2Line } from "react-icons/ri";
+import { useIntl } from "react-intl";
+
+interface SearchProps extends BoxProps {
+ query: string;
+ onChange: React.ChangeEventHandler;
+ onClear: () => void;
+}
+
+const Search = ({
+ query,
+ onChange: onQueryChange,
+ onClear,
+ ...rest
+}: SearchProps) => {
+ const intl = useIntl();
+ const ref = useRef(null);
+
+ const handleClear = useCallback(() => {
+ onClear();
+ ref.current?.focus();
+ }, [onClear]);
+
+ return (
+
+
+
+
+
+ {query && (
+
+ }
+ onClick={handleClear}
+ />
+
+ )}
+
+ );
+};
+
+export default Search;
diff --git a/src/homepage/SortInput.tsx b/src/homepage/SortInput.tsx
new file mode 100644
index 000000000..e42b53a52
--- /dev/null
+++ b/src/homepage/SortInput.tsx
@@ -0,0 +1,93 @@
+/**
+ * (c) 2024-2026, Micro:bit Educational Foundation and contributors
+ *
+ * SPDX-License-Identifier: MIT
+ */
+import {
+ ButtonGroup,
+ ButtonGroupProps,
+ IconButton,
+ Select,
+} from "@chakra-ui/react";
+import { RiArrowDownLine, RiArrowUpLine } from "react-icons/ri";
+import { useIntl } from "react-intl";
+
+interface SortInputProps extends ButtonGroupProps {
+ value: string;
+ onSelectChange: React.ChangeEventHandler;
+ order: "desc" | "asc";
+ toggleOrder: () => void;
+ hasSearchQuery: boolean;
+}
+
+const SortInput = ({
+ value,
+ onSelectChange,
+ order,
+ toggleOrder,
+ hasSearchQuery,
+ ...rest
+}: SortInputProps) => {
+ const intl = useIntl();
+ return (
+
+ }
+ borderBottomRightRadius={0}
+ borderTopRightRadius={0}
+ _focus={{ zIndex: 1 }}
+ isDisabled={hasSearchQuery}
+ >
+ {hasSearchQuery ? (
+
+ ) : (
+ <>
+
+
+ >
+ )}
+
+
+ ) : (
+
+ )
+ }
+ />
+
+ );
+};
+
+export default SortInput;
diff --git a/src/homepage/ViewAllProjectsCard.tsx b/src/homepage/ViewAllProjectsCard.tsx
new file mode 100644
index 000000000..945bd2755
--- /dev/null
+++ b/src/homepage/ViewAllProjectsCard.tsx
@@ -0,0 +1,26 @@
+/**
+ * (c) 2024-2026, Micro:bit Educational Foundation and contributors
+ *
+ * SPDX-License-Identifier: MIT
+ */
+import { useCallback } from "react";
+import { RiFolderOpenLine } from "react-icons/ri";
+import { useNavigate } from "react-router-dom";
+import { createProjectsPageUrl } from "../urls";
+import ActionCard from "./ActionCard";
+
+const ViewAllProjectsCard = () => {
+ const navigate = useNavigate();
+ const handleClick = useCallback(() => {
+ navigate(createProjectsPageUrl());
+ }, [navigate]);
+ return (
+
+ );
+};
+
+export default ViewAllProjectsCard;
diff --git a/src/homepage/ViewAllProjectsLink.tsx b/src/homepage/ViewAllProjectsLink.tsx
new file mode 100644
index 000000000..5aad4f246
--- /dev/null
+++ b/src/homepage/ViewAllProjectsLink.tsx
@@ -0,0 +1,28 @@
+/**
+ * (c) 2024-2026, Micro:bit Educational Foundation and contributors
+ *
+ * SPDX-License-Identifier: MIT
+ */
+import { Link } from "@chakra-ui/react";
+import { FormattedMessage } from "react-intl";
+import { Link as RouterLink } from "react-router-dom";
+import { createProjectsPageUrl } from "../urls";
+
+const ViewAllProjectsLink = () => {
+ return (
+
+
+
+ );
+};
+
+export default ViewAllProjectsLink;
diff --git a/src/homepage/carousel/CarouselButton.tsx b/src/homepage/carousel/CarouselButton.tsx
new file mode 100644
index 000000000..8cd71e4d5
--- /dev/null
+++ b/src/homepage/carousel/CarouselButton.tsx
@@ -0,0 +1,66 @@
+/**
+ * (c) 2024, Micro:bit Educational Foundation and contributors
+ *
+ * SPDX-License-Identifier: MIT
+ */
+import { Box, BoxProps } from "@chakra-ui/react";
+import React from "react";
+import ChevronLeftIcon from "../icons/ChevronLeftIcon";
+import ChevronRightIcon from "../icons/ChevronRightIcon";
+
+interface CarouselButtonProps extends BoxProps {
+ direction: "left" | "right";
+ onClick?: () => void;
+ stroke?: string;
+}
+
+const CarouselButton = React.forwardRef(function CarouselButton(
+ { direction, onClick, stroke, ...rest }: CarouselButtonProps,
+ ref: React.ForwardedRef
+) {
+ return (
+
+ {direction === "left" ? (
+
+ ) : (
+
+ )}
+
+ );
+});
+
+export default CarouselButton;
diff --git a/src/homepage/carousel/CarouselRow.tsx b/src/homepage/carousel/CarouselRow.tsx
new file mode 100644
index 000000000..717e64fb7
--- /dev/null
+++ b/src/homepage/carousel/CarouselRow.tsx
@@ -0,0 +1,53 @@
+/**
+ * (c) 2024, Micro:bit Educational Foundation and contributors
+ *
+ * SPDX-License-Identifier: MIT
+ */
+import { Box, Heading, HStack } from "@chakra-ui/react";
+import { ReactNode } from "react";
+import { FormattedMessage } from "react-intl";
+import { shortScreenHeightBreakpoint } from "../responsive";
+import NewPageCarousel from "./NewPageCarousel";
+
+interface CarouselRowProps {
+ carouselItems: JSX.Element[];
+ containerMessageId: string;
+ titleElement?: ReactNode;
+ titleId?: string;
+ actions?: JSX.Element[];
+}
+
+const CarouselRow = ({
+ carouselItems,
+ containerMessageId,
+ titleElement,
+ titleId,
+ actions,
+}: CarouselRowProps) => {
+ return (
+
+
+ {typeof titleId === "string" ? (
+
+
+
+ ) : (
+ titleElement
+ )}
+ {actions}
+
+
+
+ );
+};
+
+export default CarouselRow;
diff --git a/src/homepage/carousel/NewPageCarousel.tsx b/src/homepage/carousel/NewPageCarousel.tsx
new file mode 100644
index 000000000..8d7dc06dc
--- /dev/null
+++ b/src/homepage/carousel/NewPageCarousel.tsx
@@ -0,0 +1,121 @@
+/**
+ * (c) 2024, Micro:bit Educational Foundation and contributors
+ *
+ * SPDX-License-Identifier: MIT
+ */
+import { useCallback, useMemo } from "react";
+import { SwiperClass } from "swiper/react";
+import SwiperCarousel from "./SwiperCarousel";
+
+const fast = 1000;
+const cardWidth = 260;
+const mobileSpaceBetween = 15;
+
+interface NewPageCarouselProps {
+ carouselItems: JSX.Element[];
+ containerMessageId: string;
+}
+
+const NewPageCarousel = ({
+ carouselItems,
+ containerMessageId,
+}: NewPageCarouselProps) => {
+ const getSlidesPerGroup = useCallback((spacing: number) => {
+ // --carousel-px is 20px at md+ where this calculation is used.
+ return Math.max(
+ 1,
+ Math.floor((window.innerWidth - 40) / (cardWidth + spacing))
+ );
+ }, []);
+
+ const breakpoints = useMemo(() => {
+ if (typeof window === "undefined") {
+ return;
+ }
+
+ return {
+ // When window width is >= 0px.
+ 0: {
+ spaceBetween: mobileSpaceBetween,
+ slidesPerGroup: 1,
+ },
+ // When window width is >= 768px.
+ 768: {
+ spaceBetween: 20,
+ slidesPerGroup: getSlidesPerGroup(20),
+ },
+ // When window width is >= 992px.
+ 992: {
+ spaceBetween: 25,
+ slidesPerGroup: getSlidesPerGroup(25),
+ },
+ // When window width is >= 1200px.
+ 1200: {
+ spaceBetween: 30,
+ slidesPerGroup: getSlidesPerGroup(30),
+ },
+ // When window width is >= 1400px.
+ 1400: {
+ spaceBetween: 30,
+ slidesPerGroup: getSlidesPerGroup(30),
+ },
+ };
+ }, [getSlidesPerGroup]);
+
+ const getBreakpoint = useCallback(() => {
+ if (typeof window !== "undefined" && breakpoints) {
+ if (window.innerWidth < 768) {
+ return breakpoints[0];
+ } else if (window.innerWidth < 992) {
+ return breakpoints[768];
+ } else if (window.innerWidth < 1200) {
+ return breakpoints[992];
+ } else if (window.innerWidth < 1400) {
+ return breakpoints[1200];
+ } else {
+ return breakpoints[1400];
+ }
+ }
+ }, [breakpoints]);
+
+ const recalculateBreakpoints = useCallback(
+ (swiper: SwiperClass) => {
+ if (typeof window === "undefined") {
+ return;
+ }
+ const breakpoint = getBreakpoint();
+ if (breakpoint) {
+ let slidesPerGroup = breakpoint.slidesPerGroup;
+ if (breakpoint.spaceBetween !== mobileSpaceBetween) {
+ slidesPerGroup = getSlidesPerGroup(breakpoint.spaceBetween);
+ }
+ swiper.params.slidesPerGroup = slidesPerGroup;
+ }
+ },
+ [getBreakpoint, getSlidesPerGroup]
+ );
+
+ return (
+ div": { height: "100%", width: "260px" },
+ "& .swiper": {
+ padding: "var(--carousel-pt) var(--carousel-px) var(--carousel-pb)",
+ },
+ }}
+ />
+ );
+};
+export default NewPageCarousel;
diff --git a/src/homepage/carousel/SwiperCarousel.tsx b/src/homepage/carousel/SwiperCarousel.tsx
new file mode 100644
index 000000000..90fbd7515
--- /dev/null
+++ b/src/homepage/carousel/SwiperCarousel.tsx
@@ -0,0 +1,125 @@
+/**
+ * (c) 2024, Micro:bit Educational Foundation and contributors
+ *
+ * SPDX-License-Identifier: MIT
+ */
+import { Box, SystemStyleObject } from "@chakra-ui/react";
+import React, { useCallback, useState } from "react";
+import { useIntl } from "react-intl";
+import { Swiper as SwiperClass } from "swiper";
+import "swiper/css";
+import "swiper/css/a11y";
+import "swiper/css/autoplay";
+import "swiper/css/navigation";
+import "swiper/css/pagination";
+import { A11y, Autoplay, Navigation, Pagination } from "swiper/modules";
+import { Swiper, SwiperProps, SwiperSlide } from "swiper/react";
+import SwiperCarouselButtons from "./SwiperCarouselButtons";
+
+interface SwiperCarouselProps extends SwiperProps {
+ carouselItems: JSX.Element[];
+ containerMessageId: string;
+ padding?: string | number;
+ slideClassName?: string;
+ swiperWrapperClassName?: string;
+ sx?: SystemStyleObject;
+}
+
+const swiperModules = [A11y, Autoplay, Navigation, Pagination];
+
+const SwiperCarousel = ({
+ carouselItems,
+ containerMessageId,
+ padding,
+ navigation,
+ slideClassName,
+ swiperWrapperClassName,
+ sx: sxProp,
+ ...props
+}: SwiperCarouselProps) => {
+ const intl = useIntl();
+ const isRtl = false;
+ const [swiper, setSwiper] = useState();
+ const handleSlideFocus = useCallback(
+ (e: React.FocusEvent) => {
+ if (swiper) {
+ swiper.slides.forEach((slide, i) => {
+ if (slide.contains(e.target)) {
+ swiper.activeIndex = i;
+ swiper.updateSlidesClasses();
+ swiper.slideTo(i);
+ }
+ });
+ }
+ },
+ [swiper]
+ );
+
+ const handleSwiper = useCallback((swiper: SwiperClass) => {
+ setSwiper(swiper);
+ swiper.update();
+ }, []);
+
+ return (
+
+
+ {navigation && }
+ {carouselItems.map((item) => (
+
+ {item}
+
+ ))}
+
+
+ );
+};
+
+export default SwiperCarousel;
diff --git a/src/homepage/carousel/SwiperCarouselButtons.tsx b/src/homepage/carousel/SwiperCarouselButtons.tsx
new file mode 100644
index 000000000..68c81dcd6
--- /dev/null
+++ b/src/homepage/carousel/SwiperCarouselButtons.tsx
@@ -0,0 +1,80 @@
+/**
+ * (c) 2024, Micro:bit Educational Foundation and contributors
+ *
+ * SPDX-License-Identifier: MIT
+ */
+import { Box } from "@chakra-ui/react";
+import { useEffect, useRef } from "react";
+import { useSwiper } from "swiper/react";
+import CarouselButton from "./CarouselButton";
+
+const buttonStyles = {
+ position: "absolute" as const,
+ zIndex: 5,
+ top: "var(--carousel-pt)",
+ // Draw over the box shadow below the carousel cards
+ bottom: "calc(var(--carousel-pb) - 8px)",
+};
+
+const SwiperCarouselButtons = () => {
+ const isRtl = false;
+ const swiper = useSwiper();
+ const nextButtonRef = useRef(null);
+ const prevButtonRef = useRef(null);
+ useEffect(() => {
+ if (!swiper.destroyed && prevButtonRef.current && nextButtonRef.current) {
+ swiper.navigation.prevEl = prevButtonRef.current;
+ swiper.navigation.nextEl = nextButtonRef.current;
+ swiper.navigation.update();
+ (swiper.navigation.nextEl as HTMLElement).tabIndex = -1;
+ (swiper.navigation.prevEl as HTMLElement).tabIndex = -1;
+ }
+ }, [swiper.destroyed, swiper.navigation]);
+
+ // Override tab index on buttons. These are useless for keyboard users.
+ // Just tab through the slide items/cards instead.
+ useEffect(() => {
+ const listener = () => {
+ (swiper.navigation.nextEl as HTMLElement).tabIndex = -1;
+ (swiper.navigation.prevEl as HTMLElement).tabIndex = -1;
+ };
+ if (!swiper.destroyed) {
+ swiper.on("activeIndexChange", listener);
+ }
+ return () => {
+ if (!swiper.destroyed) {
+ swiper.off("activeIndexChange", listener);
+ }
+ };
+ }, [swiper]);
+
+ return (
+
+ swiper.slidePrev()}
+ />
+ swiper.slideNext()}
+ />
+
+ );
+};
+
+export default SwiperCarouselButtons;
diff --git a/src/homepage/datetime.ts b/src/homepage/datetime.ts
new file mode 100644
index 000000000..e2b6e4ccf
--- /dev/null
+++ b/src/homepage/datetime.ts
@@ -0,0 +1,33 @@
+/**
+ * (c) 2026, Micro:bit Educational Foundation and contributors
+ *
+ * SPDX-License-Identifier: MIT
+ */
+import { IntlShape } from "react-intl";
+
+const units: [Intl.RelativeTimeFormatUnit, number][] = [
+ ["year", 1000 * 60 * 60 * 24 * 365],
+ ["month", 1000 * 60 * 60 * 24 * 30],
+ ["week", 1000 * 60 * 60 * 24 * 7],
+ ["day", 1000 * 60 * 60 * 24],
+ ["hour", 1000 * 60 * 60],
+ ["minute", 1000 * 60],
+];
+
+/**
+ * Formats a timestamp as a localized relative time, e.g. "3 days ago".
+ */
+export const timeAgo = (intl: IntlShape, timestamp: number): string => {
+ const diff = timestamp - Date.now();
+ const abs = Math.abs(diff);
+ for (const [unit, ms] of units) {
+ if (abs >= ms) {
+ return intl.formatRelativeTime(Math.round(diff / ms), unit, {
+ numeric: "auto",
+ });
+ }
+ }
+ return intl.formatRelativeTime(Math.round(diff / 1000), "second", {
+ numeric: "auto",
+ });
+};
diff --git a/src/homepage/external-links.ts b/src/homepage/external-links.ts
new file mode 100644
index 000000000..37eca466c
--- /dev/null
+++ b/src/homepage/external-links.ts
@@ -0,0 +1,39 @@
+/**
+ * External (theme-scoped) URLs used by the home page.
+ *
+ * For this prototype these live here rather than in the deployment/theme
+ * package. Several are placeholders carried over from CreateAI and can be
+ * updated to Python-specific destinations later.
+ *
+ * (c) 2026, Micro:bit Educational Foundation and contributors
+ *
+ * SPDX-License-Identifier: MIT
+ */
+import { stage } from "../environment";
+
+const microbitOrgBaseUrl =
+ stage === "PRODUCTION"
+ ? "https://microbit.org/"
+ : "https://stage.microbit.org/";
+
+const langPath = (languageId: string) =>
+ languageId === "en" ? "" : `${languageId.toLowerCase()}/`;
+
+export const projectUrl = (slug: string, language: string) =>
+ `${microbitOrgBaseUrl}${langPath(
+ language
+ )}projects/make-it-code-it/${encodeURIComponent(slug)}/`;
+
+export const lessonUrl = (slug: string) =>
+ `${microbitOrgBaseUrl}teach/lessons/${encodeURIComponent(slug)}/`;
+
+export const userGuideUrl = () =>
+ `${microbitOrgBaseUrl}get-started/user-guide/python-editor/`;
+
+export const supportSiteFolderUrl = () =>
+ "https://support.microbit.org/support/solutions/folders/19000170475";
+
+export const accessibilityUrl = () => `${microbitOrgBaseUrl}accessibility/`;
+
+export const learnMoreUrl = (languageId: string) =>
+ `${microbitOrgBaseUrl}${langPath(languageId)}code/`;
diff --git a/src/homepage/icons/ChevronLeftIcon.tsx b/src/homepage/icons/ChevronLeftIcon.tsx
new file mode 100644
index 000000000..77c4b97a1
--- /dev/null
+++ b/src/homepage/icons/ChevronLeftIcon.tsx
@@ -0,0 +1,29 @@
+/**
+ * (c) 2024, Micro:bit Educational Foundation and contributors
+ *
+ * SPDX-License-Identifier: MIT
+ */
+type Props = {
+ className?: string;
+ fill?: string;
+ stroke?: string;
+ strokeWidth?: number;
+};
+
+const ChevronLeftIcon = ({
+ className = "",
+ fill = "none",
+ stroke = "#556C84",
+ strokeWidth = 1.5,
+}: Props) => (
+
+);
+
+export default ChevronLeftIcon;
diff --git a/src/homepage/icons/ChevronRightIcon.tsx b/src/homepage/icons/ChevronRightIcon.tsx
new file mode 100644
index 000000000..22b1dea12
--- /dev/null
+++ b/src/homepage/icons/ChevronRightIcon.tsx
@@ -0,0 +1,29 @@
+/**
+ * (c) 2024, Micro:bit Educational Foundation and contributors
+ *
+ * SPDX-License-Identifier: MIT
+ */
+type Props = {
+ className?: string;
+ fill?: string;
+ stroke?: string;
+ strokeWidth?: number;
+};
+
+const ChevronRightIcon = ({
+ className = "",
+ fill = "none",
+ stroke = "#556C84",
+ strokeWidth = 1.5,
+}: Props) => (
+
+);
+
+export default ChevronRightIcon;
diff --git a/src/homepage/project-name.ts b/src/homepage/project-name.ts
new file mode 100644
index 000000000..5c5e3d48d
--- /dev/null
+++ b/src/homepage/project-name.ts
@@ -0,0 +1,6 @@
+/**
+ * (c) 2026, Micro:bit Educational Foundation and contributors
+ *
+ * SPDX-License-Identifier: MIT
+ */
+export type ProjectNameDialogReason = "rename" | "duplicate";
diff --git a/src/homepage/responsive.ts b/src/homepage/responsive.ts
new file mode 100644
index 000000000..90912c9dd
--- /dev/null
+++ b/src/homepage/responsive.ts
@@ -0,0 +1,8 @@
+/**
+ * (c) 2026, Micro:bit Educational Foundation and contributors
+ *
+ * SPDX-License-Identifier: MIT
+ */
+
+// For landscape mobile screen sizes.
+export const shortScreenHeightBreakpoint = "@media (max-height: 700px)";
diff --git a/src/homepage/use-project-card-actions.ts b/src/homepage/use-project-card-actions.ts
new file mode 100644
index 000000000..243617cf6
--- /dev/null
+++ b/src/homepage/use-project-card-actions.ts
@@ -0,0 +1,174 @@
+/**
+ * (c) 2026, Micro:bit Educational Foundation and contributors
+ *
+ * SPDX-License-Identifier: MIT
+ */
+import { createElement, useCallback } from "react";
+import { FormattedMessage, useIntl } from "react-intl";
+import { useNavigate } from "react-router-dom";
+import { ConfirmDialog } from "../common/ConfirmDialog";
+import {
+ InputDialog,
+ InputDialogBody,
+ InputValidationResult,
+} from "../common/InputDialog";
+import { useDialogs } from "../common/use-dialogs";
+import { useLogging } from "../logging/logging-hooks";
+import { useProjects } from "../project/projects-hooks";
+import { createEditorUrl } from "../urls";
+import ProjectNameBody from "./ProjectNameBody";
+import { ProjectNameDialogReason } from "./project-name";
+
+export type ProjectActionSurface = "home" | "projects";
+
+const validateName = (value: string): InputValidationResult =>
+ value.trim().length > 0 ? { ok: true } : { ok: false };
+
+/**
+ * Shared project card action handlers (create / open / rename / duplicate /
+ * delete) used by the home page and projects page.
+ */
+export const useProjectCardActions = (surface: ProjectActionSurface) => {
+ const intl = useIntl();
+ const navigate = useNavigate();
+ const dialogs = useDialogs();
+ const logging = useLogging();
+ const {
+ projects,
+ createProject,
+ openProject,
+ renameProject,
+ duplicateProject,
+ deleteProject,
+ } = useProjects();
+
+ const chooseName = useCallback(
+ (initialValue: string, headerId: string, actionId: string) =>
+ dialogs.show((callback) =>
+ createElement(InputDialog, {
+ header: createElement(FormattedMessage, { id: headerId }),
+ Body: ProjectNameBody as React.FC>,
+ initialValue,
+ actionLabel: intl.formatMessage({ id: actionId }),
+ validate: validateName,
+ callback,
+ })
+ ),
+ [dialogs, intl]
+ );
+
+ const handleCreate = useCallback(async () => {
+ const name = await chooseName(
+ intl.formatMessage({ id: "untitled-project" }),
+ "create-project-dialog-heading",
+ "create-project-action"
+ );
+ if (name) {
+ logging.event({ type: "project-create", detail: { surface } });
+ await createProject(name.trim());
+ navigate(createEditorUrl());
+ }
+ }, [chooseName, createProject, intl, logging, navigate, surface]);
+
+ const handleOpen = useCallback(
+ async (id: string) => {
+ logging.event({ type: "project-open", detail: { surface } });
+ await openProject(id);
+ navigate(createEditorUrl());
+ },
+ [logging, navigate, openProject, surface]
+ );
+
+ const handleRenameDuplicate = useCallback(
+ async (reason: ProjectNameDialogReason, id: string) => {
+ const project = projects.find((p) => p.id === id);
+ if (!project) {
+ return;
+ }
+ const name = await chooseName(
+ project.name,
+ reason === "rename"
+ ? "rename-project-heading"
+ : "duplicate-project-heading",
+ reason === "rename"
+ ? "rename-project-action"
+ : "duplicate-project-action"
+ );
+ if (name) {
+ if (reason === "rename") {
+ logging.event({ type: "project-rename", detail: { surface } });
+ await renameProject(id, name.trim());
+ } else {
+ logging.event({ type: "project-duplicate", detail: { surface } });
+ await duplicateProject(id, name.trim());
+ }
+ }
+ },
+ [chooseName, duplicateProject, logging, projects, renameProject, surface]
+ );
+
+ const handleDelete = useCallback(
+ async (id: string) => {
+ const project = projects.find((p) => p.id === id);
+ if (!project) {
+ return;
+ }
+ const confirmed = await dialogs.show((callback) =>
+ createElement(ConfirmDialog, {
+ header: intl.formatMessage({ id: "delete-project-confirm-heading" }),
+ body: createElement(FormattedMessage, {
+ id: "delete-project-confirm-text",
+ values: { project: project.name },
+ }),
+ actionLabel: intl.formatMessage({ id: "delete-project-action" }),
+ callback,
+ })
+ );
+ if (confirmed) {
+ logging.event({ type: "project-delete", detail: { surface } });
+ await deleteProject(id);
+ }
+ },
+ [deleteProject, dialogs, intl, logging, projects, surface]
+ );
+
+ const handleDeleteMany = useCallback(
+ async (ids: string[]) => {
+ if (ids.length === 0) {
+ return;
+ }
+ if (ids.length === 1) {
+ return handleDelete(ids[0]);
+ }
+ const confirmed = await dialogs.show((callback) =>
+ createElement(ConfirmDialog, {
+ header: intl.formatMessage({ id: "delete-projects-confirm-heading" }),
+ body: createElement(FormattedMessage, {
+ id: "delete-projects-confirm-text",
+ values: { numProjects: ids.length },
+ }),
+ actionLabel: intl.formatMessage({ id: "delete-project-action" }),
+ callback,
+ })
+ );
+ if (confirmed) {
+ logging.event({
+ type: "project-delete",
+ detail: { surface, count: ids.length },
+ });
+ for (const id of ids) {
+ await deleteProject(id);
+ }
+ }
+ },
+ [deleteProject, dialogs, handleDelete, intl, logging, surface]
+ );
+
+ return {
+ handleCreate,
+ handleOpen,
+ handleRenameDuplicate,
+ handleDelete,
+ handleDeleteMany,
+ };
+};
diff --git a/src/messages/ui.ca.json b/src/messages/ui.ca.json
index 00f5f41ac..a1b8c871a 100644
--- a/src/messages/ui.ca.json
+++ b/src/messages/ui.ca.json
@@ -65,6 +65,24 @@
"value": "Accessibilitat"
}
],
+ "accessibility-resource-title": [
+ {
+ "type": 0,
+ "value": "Accessibility"
+ }
+ ],
+ "add-files-action": [
+ {
+ "type": 0,
+ "value": "Add file(s)"
+ }
+ ],
+ "add-files-hover": [
+ {
+ "type": 0,
+ "value": "Add files to this project"
+ }
+ ],
"added-change": [
{
"type": 0,
@@ -165,6 +183,32 @@
"value": "Cancel·lar"
}
],
+ "carousel-role": [
+ {
+ "type": 0,
+ "value": "carousel"
+ }
+ ],
+ "carousel-slide-label": [
+ {
+ "type": 1,
+ "value": "slideNum"
+ },
+ {
+ "type": 0,
+ "value": " of "
+ },
+ {
+ "type": 1,
+ "value": "totalSlides"
+ }
+ ],
+ "carousel-slide-role": [
+ {
+ "type": 0,
+ "value": "slide"
+ }
+ ],
"change-files": [
{
"type": 0,
@@ -459,12 +503,30 @@
"value": "Crea un fitxer"
}
],
+ "create-project-action": [
+ {
+ "type": 0,
+ "value": "Create"
+ }
+ ],
+ "create-project-dialog-heading": [
+ {
+ "type": 0,
+ "value": "Name your project"
+ }
+ ],
"create-python": [
{
"type": 0,
"value": "Crea un nou fitxer Python en aquest projecte"
}
],
+ "createai-taster-lessons-resource-title": [
+ {
+ "type": 0,
+ "value": "Taster lessons"
+ }
+ ],
"created-file": [
{
"type": 0,
@@ -491,6 +553,52 @@
"value": "name"
}
],
+ "delete-project-action": [
+ {
+ "type": 0,
+ "value": "Delete"
+ }
+ ],
+ "delete-project-confirm-heading": [
+ {
+ "type": 0,
+ "value": "Delete project"
+ }
+ ],
+ "delete-project-confirm-text": [
+ {
+ "type": 0,
+ "value": "Are you sure you want to delete ‘"
+ },
+ {
+ "type": 1,
+ "value": "project"
+ },
+ {
+ "type": 0,
+ "value": "’? This cannot be undone."
+ }
+ ],
+ "delete-projects-confirm-heading": [
+ {
+ "type": 0,
+ "value": "Delete projects"
+ }
+ ],
+ "delete-projects-confirm-text": [
+ {
+ "type": 0,
+ "value": "Are you sure you want to delete "
+ },
+ {
+ "type": 1,
+ "value": "numProjects"
+ },
+ {
+ "type": 0,
+ "value": " projects? This cannot be undone."
+ }
+ ],
"deleted-file": [
{
"type": 0,
@@ -525,6 +633,18 @@
"value": "Arrossegar i deixar anar"
}
],
+ "duplicate-project-action": [
+ {
+ "type": 0,
+ "value": "Duplicate"
+ }
+ ],
+ "duplicate-project-heading": [
+ {
+ "type": 0,
+ "value": "Name your project"
+ }
+ ],
"edit-file-action": [
{
"type": 0,
@@ -615,6 +735,18 @@
"value": "El nom no pot contenir espais"
}
],
+ "files-tab": [
+ {
+ "type": 0,
+ "value": "Files"
+ }
+ ],
+ "files-tab-description": [
+ {
+ "type": 0,
+ "value": "Manage your project files"
+ }
+ ],
"firmware-update-link": [
{
"type": 0,
@@ -633,6 +765,12 @@
"value": "Cal actualitzar el firmware"
}
],
+ "first-lessons-with-python-resource-title": [
+ {
+ "type": 0,
+ "value": "First lessons with Python and the micro:bit"
+ }
+ ],
"flash-action": [
{
"type": 0,
@@ -691,6 +829,18 @@
"value": "Ajuda"
}
],
+ "help-resources-row-carousel": [
+ {
+ "type": 0,
+ "value": "Help and support"
+ }
+ ],
+ "help-resources-row-title": [
+ {
+ "type": 0,
+ "value": "Help and support"
+ }
+ ],
"help-support": [
{
"type": 0,
@@ -727,6 +877,30 @@
"value": "Senzill"
}
],
+ "home-action": [
+ {
+ "type": 0,
+ "value": "Home"
+ }
+ ],
+ "homepage-banner-heading": [
+ {
+ "type": 0,
+ "value": "Code your BBC micro:bit with Python"
+ }
+ ],
+ "homepage-banner-subtitle": [
+ {
+ "type": 0,
+ "value": "Create, edit and flash MicroPython programs to your micro:bit."
+ }
+ ],
+ "homepage-title": [
+ {
+ "type": 0,
+ "value": "micro:bit Python Editor"
+ }
+ ],
"ideas-tab": [
{
"type": 0,
@@ -739,6 +913,12 @@
"value": "Prova aquests projectes, modifica'ls i inspira't"
}
],
+ "import-file-action": [
+ {
+ "type": 0,
+ "value": "Import"
+ }
+ ],
"insert-code-action": [
{
"type": 0,
@@ -751,6 +931,12 @@
"value": "Idioma"
}
],
+ "learn-more-action": [
+ {
+ "type": 0,
+ "value": "Learn more"
+ }
+ ],
"less-action": [
{
"type": 0,
@@ -1017,6 +1203,18 @@
"value": "Avís: només s'ha descarregat main.py"
}
],
+ "my-projects-row-carousel": [
+ {
+ "type": 0,
+ "value": "Your projects"
+ }
+ ],
+ "my-projects-row-title": [
+ {
+ "type": 0,
+ "value": "Your projects"
+ }
+ ],
"name-project": [
{
"type": 0,
@@ -1055,12 +1253,24 @@
"value": "."
}
],
+ "new-project-action": [
+ {
+ "type": 0,
+ "value": "New project"
+ }
+ ],
"next-action": [
{
"type": 0,
"value": "Següent"
}
],
+ "no-projects": [
+ {
+ "type": 0,
+ "value": "No projects found"
+ }
+ ],
"not-found-checklist-one": [
{
"type": 0,
@@ -1169,6 +1379,12 @@
"value": "Obre un fitxer hexadecimal o Python o afegeix altres fitxers"
}
],
+ "open-project-action": [
+ {
+ "type": 0,
+ "value": "Open"
+ }
+ ],
"options": [
{
"type": 0,
@@ -1313,12 +1529,112 @@
"value": "Accions del projecte"
}
],
+ "project-file-count": [
+ {
+ "offset": 0,
+ "options": {
+ "one": {
+ "value": [
+ {
+ "type": 7
+ },
+ {
+ "type": 0,
+ "value": " file"
+ }
+ ]
+ },
+ "other": {
+ "value": [
+ {
+ "type": 7
+ },
+ {
+ "type": 0,
+ "value": " files"
+ }
+ ]
+ }
+ },
+ "pluralType": "cardinal",
+ "type": 6,
+ "value": "count"
+ }
+ ],
"project-header": [
{
"type": 0,
"value": "Capçalera del projecte"
}
],
+ "project-idea-animated-animals-title": [
+ {
+ "type": 0,
+ "value": "Animated animals"
+ }
+ ],
+ "project-idea-beating-heart-title": [
+ {
+ "type": 0,
+ "value": "Beating heart"
+ }
+ ],
+ "project-idea-emotion-badge-title": [
+ {
+ "type": 0,
+ "value": "Emotion badge"
+ }
+ ],
+ "project-idea-flashing-emotions-title": [
+ {
+ "type": 0,
+ "value": "Flashing emotions"
+ }
+ ],
+ "project-idea-get-silly-title": [
+ {
+ "type": 0,
+ "value": "Get silly"
+ }
+ ],
+ "project-idea-heart-title": [
+ {
+ "type": 0,
+ "value": "Heart"
+ }
+ ],
+ "project-ideas-row-carousel": [
+ {
+ "type": 0,
+ "value": "Project ideas"
+ }
+ ],
+ "project-ideas-row-title": [
+ {
+ "type": 0,
+ "value": "Project ideas"
+ }
+ ],
+ "project-loaded": [
+ {
+ "type": 0,
+ "value": "Project loaded"
+ }
+ ],
+ "project-menu-action": [
+ {
+ "type": 0,
+ "value": "Actions for project ‘"
+ },
+ {
+ "type": 1,
+ "value": "name"
+ },
+ {
+ "type": 0,
+ "value": "’"
+ }
+ ],
"project-name": [
{
"type": 0,
@@ -1331,6 +1647,12 @@
"value": "El nom del projecte no pot estar buit"
}
],
+ "project-skip-to-toolbar": [
+ {
+ "type": 0,
+ "value": "Skip to selection actions"
+ }
+ ],
"project-tab": [
{
"type": 0,
@@ -1343,6 +1665,12 @@
"value": "Visualitza, crea, afegeix i edita els fitxers del teu projecte"
}
],
+ "projects-page-title": [
+ {
+ "type": 0,
+ "value": "Projects"
+ }
+ ],
"python-powered": [
{
"type": 0,
@@ -1385,6 +1713,18 @@
"value": "Referència"
}
],
+ "rename-project-action": [
+ {
+ "type": 0,
+ "value": "Rename"
+ }
+ ],
+ "rename-project-heading": [
+ {
+ "type": 0,
+ "value": "Rename project"
+ }
+ ],
"replace-action-label": [
{
"type": 0,
@@ -1489,6 +1829,26 @@
"value": "Cerca"
}
],
+ "select-project-action": [
+ {
+ "type": 0,
+ "value": "Select project ‘"
+ },
+ {
+ "type": 1,
+ "value": "name"
+ },
+ {
+ "type": 0,
+ "value": "’"
+ }
+ ],
+ "selection-actions-group": [
+ {
+ "type": 0,
+ "value": "Actions for selected projects"
+ }
+ ],
"send-action": [
{
"type": 0,
@@ -2205,6 +2565,42 @@
"value": "Versions de programari"
}
],
+ "sort-option-last-modified": [
+ {
+ "type": 0,
+ "value": "Last modified"
+ }
+ ],
+ "sort-option-name": [
+ {
+ "type": 0,
+ "value": "Name"
+ }
+ ],
+ "sort-option-relevance": [
+ {
+ "type": 0,
+ "value": "Relevance"
+ }
+ ],
+ "sort-order-ascending-label": [
+ {
+ "type": 0,
+ "value": "Sort ascending"
+ }
+ ],
+ "sort-order-descending-label": [
+ {
+ "type": 0,
+ "value": "Sort descending"
+ }
+ ],
+ "sort-select-label": [
+ {
+ "type": 0,
+ "value": "Sort projects by"
+ }
+ ],
"start-coding-action": [
{
"type": 0,
@@ -2217,6 +2613,18 @@
"value": "Suport"
}
],
+ "teacher-resources-row-carousel": [
+ {
+ "type": 0,
+ "value": "Teacher resources"
+ }
+ ],
+ "teacher-resources-row-title": [
+ {
+ "type": 0,
+ "value": "Teacher resources"
+ }
+ ],
"terms-of-use": [
{
"type": 0,
@@ -2337,6 +2745,12 @@
"value": "Transfereix el fitxer hexadecimal desat a la micro:bit"
}
],
+ "troubleshooting-resource-title": [
+ {
+ "type": 0,
+ "value": "Troubleshooting"
+ }
+ ],
"try-again-action": [
{
"type": 0,
@@ -2417,6 +2831,12 @@
"value": "Guia de l'usuari"
}
],
+ "view-all-projects": [
+ {
+ "type": 0,
+ "value": "View all projects"
+ }
+ ],
"visit-dot-org": [
{
"type": 0,
diff --git a/src/messages/ui.de.json b/src/messages/ui.de.json
index a9ebc990e..e5e77b6df 100644
--- a/src/messages/ui.de.json
+++ b/src/messages/ui.de.json
@@ -65,6 +65,24 @@
"value": "Barrierefreiheit"
}
],
+ "accessibility-resource-title": [
+ {
+ "type": 0,
+ "value": "Accessibility"
+ }
+ ],
+ "add-files-action": [
+ {
+ "type": 0,
+ "value": "Add file(s)"
+ }
+ ],
+ "add-files-hover": [
+ {
+ "type": 0,
+ "value": "Add files to this project"
+ }
+ ],
"added-change": [
{
"type": 0,
@@ -173,6 +191,32 @@
"value": "Abbrechen"
}
],
+ "carousel-role": [
+ {
+ "type": 0,
+ "value": "carousel"
+ }
+ ],
+ "carousel-slide-label": [
+ {
+ "type": 1,
+ "value": "slideNum"
+ },
+ {
+ "type": 0,
+ "value": " of "
+ },
+ {
+ "type": 1,
+ "value": "totalSlides"
+ }
+ ],
+ "carousel-slide-role": [
+ {
+ "type": 0,
+ "value": "slide"
+ }
+ ],
"change-files": [
{
"type": 0,
@@ -495,12 +539,30 @@
"value": "Datei erstellen"
}
],
+ "create-project-action": [
+ {
+ "type": 0,
+ "value": "Create"
+ }
+ ],
+ "create-project-dialog-heading": [
+ {
+ "type": 0,
+ "value": "Name your project"
+ }
+ ],
"create-python": [
{
"type": 0,
"value": "Neue Python-Datei in diesem Projekt erstellen"
}
],
+ "createai-taster-lessons-resource-title": [
+ {
+ "type": 0,
+ "value": "Taster lessons"
+ }
+ ],
"created-file": [
{
"type": 1,
@@ -527,6 +589,52 @@
"value": "name"
}
],
+ "delete-project-action": [
+ {
+ "type": 0,
+ "value": "Delete"
+ }
+ ],
+ "delete-project-confirm-heading": [
+ {
+ "type": 0,
+ "value": "Delete project"
+ }
+ ],
+ "delete-project-confirm-text": [
+ {
+ "type": 0,
+ "value": "Are you sure you want to delete ‘"
+ },
+ {
+ "type": 1,
+ "value": "project"
+ },
+ {
+ "type": 0,
+ "value": "’? This cannot be undone."
+ }
+ ],
+ "delete-projects-confirm-heading": [
+ {
+ "type": 0,
+ "value": "Delete projects"
+ }
+ ],
+ "delete-projects-confirm-text": [
+ {
+ "type": 0,
+ "value": "Are you sure you want to delete "
+ },
+ {
+ "type": 1,
+ "value": "numProjects"
+ },
+ {
+ "type": 0,
+ "value": " projects? This cannot be undone."
+ }
+ ],
"deleted-file": [
{
"type": 1,
@@ -561,6 +669,18 @@
"value": "Drag-And-Drop"
}
],
+ "duplicate-project-action": [
+ {
+ "type": 0,
+ "value": "Duplicate"
+ }
+ ],
+ "duplicate-project-heading": [
+ {
+ "type": 0,
+ "value": "Name your project"
+ }
+ ],
"edit-file-action": [
{
"type": 1,
@@ -651,6 +771,18 @@
"value": "Der Name darf keine Leerzeichen enthalten"
}
],
+ "files-tab": [
+ {
+ "type": 0,
+ "value": "Files"
+ }
+ ],
+ "files-tab-description": [
+ {
+ "type": 0,
+ "value": "Manage your project files"
+ }
+ ],
"firmware-update-link": [
{
"type": 0,
@@ -683,6 +815,12 @@
"value": "Firmware-Aktualisierung erforderlich"
}
],
+ "first-lessons-with-python-resource-title": [
+ {
+ "type": 0,
+ "value": "First lessons with Python and the micro:bit"
+ }
+ ],
"flash-action": [
{
"type": 0,
@@ -741,6 +879,18 @@
"value": "Hilfe"
}
],
+ "help-resources-row-carousel": [
+ {
+ "type": 0,
+ "value": "Help and support"
+ }
+ ],
+ "help-resources-row-title": [
+ {
+ "type": 0,
+ "value": "Help and support"
+ }
+ ],
"help-support": [
{
"type": 0,
@@ -777,6 +927,30 @@
"value": "Einfach"
}
],
+ "home-action": [
+ {
+ "type": 0,
+ "value": "Home"
+ }
+ ],
+ "homepage-banner-heading": [
+ {
+ "type": 0,
+ "value": "Code your BBC micro:bit with Python"
+ }
+ ],
+ "homepage-banner-subtitle": [
+ {
+ "type": 0,
+ "value": "Create, edit and flash MicroPython programs to your micro:bit."
+ }
+ ],
+ "homepage-title": [
+ {
+ "type": 0,
+ "value": "micro:bit Python Editor"
+ }
+ ],
"ideas-tab": [
{
"type": 0,
@@ -789,6 +963,12 @@
"value": "Probiere diese Projekte aus, ändere sie und lasse dich inspirieren"
}
],
+ "import-file-action": [
+ {
+ "type": 0,
+ "value": "Import"
+ }
+ ],
"insert-code-action": [
{
"type": 0,
@@ -801,6 +981,12 @@
"value": "Sprache"
}
],
+ "learn-more-action": [
+ {
+ "type": 0,
+ "value": "Learn more"
+ }
+ ],
"less-action": [
{
"type": 0,
@@ -1071,6 +1257,18 @@
"value": "Warnung: Nur main.py heruntergeladen"
}
],
+ "my-projects-row-carousel": [
+ {
+ "type": 0,
+ "value": "Your projects"
+ }
+ ],
+ "my-projects-row-title": [
+ {
+ "type": 0,
+ "value": "Your projects"
+ }
+ ],
"name-project": [
{
"type": 0,
@@ -1109,12 +1307,24 @@
"value": "-Erweiterung für dich hinzufügen."
}
],
+ "new-project-action": [
+ {
+ "type": 0,
+ "value": "New project"
+ }
+ ],
"next-action": [
{
"type": 0,
"value": "Weiter"
}
],
+ "no-projects": [
+ {
+ "type": 0,
+ "value": "No projects found"
+ }
+ ],
"not-found-checklist-one": [
{
"type": 0,
@@ -1247,6 +1457,12 @@
"value": "Eine HEX- oder Python-Datei öffnen oder andere Dateien hinzufügen."
}
],
+ "open-project-action": [
+ {
+ "type": 0,
+ "value": "Open"
+ }
+ ],
"options": [
{
"type": 0,
@@ -1387,12 +1603,112 @@
"value": "Projekt-Aktionen"
}
],
+ "project-file-count": [
+ {
+ "offset": 0,
+ "options": {
+ "one": {
+ "value": [
+ {
+ "type": 7
+ },
+ {
+ "type": 0,
+ "value": " file"
+ }
+ ]
+ },
+ "other": {
+ "value": [
+ {
+ "type": 7
+ },
+ {
+ "type": 0,
+ "value": " files"
+ }
+ ]
+ }
+ },
+ "pluralType": "cardinal",
+ "type": 6,
+ "value": "count"
+ }
+ ],
"project-header": [
{
"type": 0,
"value": "Projekt-Kopfzeile"
}
],
+ "project-idea-animated-animals-title": [
+ {
+ "type": 0,
+ "value": "Animated animals"
+ }
+ ],
+ "project-idea-beating-heart-title": [
+ {
+ "type": 0,
+ "value": "Beating heart"
+ }
+ ],
+ "project-idea-emotion-badge-title": [
+ {
+ "type": 0,
+ "value": "Emotion badge"
+ }
+ ],
+ "project-idea-flashing-emotions-title": [
+ {
+ "type": 0,
+ "value": "Flashing emotions"
+ }
+ ],
+ "project-idea-get-silly-title": [
+ {
+ "type": 0,
+ "value": "Get silly"
+ }
+ ],
+ "project-idea-heart-title": [
+ {
+ "type": 0,
+ "value": "Heart"
+ }
+ ],
+ "project-ideas-row-carousel": [
+ {
+ "type": 0,
+ "value": "Project ideas"
+ }
+ ],
+ "project-ideas-row-title": [
+ {
+ "type": 0,
+ "value": "Project ideas"
+ }
+ ],
+ "project-loaded": [
+ {
+ "type": 0,
+ "value": "Project loaded"
+ }
+ ],
+ "project-menu-action": [
+ {
+ "type": 0,
+ "value": "Actions for project ‘"
+ },
+ {
+ "type": 1,
+ "value": "name"
+ },
+ {
+ "type": 0,
+ "value": "’"
+ }
+ ],
"project-name": [
{
"type": 0,
@@ -1405,6 +1721,12 @@
"value": "Der Projektname darf nicht leer sein"
}
],
+ "project-skip-to-toolbar": [
+ {
+ "type": 0,
+ "value": "Skip to selection actions"
+ }
+ ],
"project-tab": [
{
"type": 0,
@@ -1417,6 +1739,12 @@
"value": "Anzeigen, Erstellen, Hinzufügen und Bearbeiten der Dateien in deinem Projekt"
}
],
+ "projects-page-title": [
+ {
+ "type": 0,
+ "value": "Projects"
+ }
+ ],
"python-powered": [
{
"type": 0,
@@ -1459,6 +1787,18 @@
"value": "Referenz"
}
],
+ "rename-project-action": [
+ {
+ "type": 0,
+ "value": "Rename"
+ }
+ ],
+ "rename-project-heading": [
+ {
+ "type": 0,
+ "value": "Rename project"
+ }
+ ],
"replace-action-label": [
{
"type": 0,
@@ -1563,6 +1903,26 @@
"value": "Suche"
}
],
+ "select-project-action": [
+ {
+ "type": 0,
+ "value": "Select project ‘"
+ },
+ {
+ "type": 1,
+ "value": "name"
+ },
+ {
+ "type": 0,
+ "value": "’"
+ }
+ ],
+ "selection-actions-group": [
+ {
+ "type": 0,
+ "value": "Actions for selected projects"
+ }
+ ],
"send-action": [
{
"type": 0,
@@ -2295,6 +2655,42 @@
"value": "Software-Versionen"
}
],
+ "sort-option-last-modified": [
+ {
+ "type": 0,
+ "value": "Last modified"
+ }
+ ],
+ "sort-option-name": [
+ {
+ "type": 0,
+ "value": "Name"
+ }
+ ],
+ "sort-option-relevance": [
+ {
+ "type": 0,
+ "value": "Relevance"
+ }
+ ],
+ "sort-order-ascending-label": [
+ {
+ "type": 0,
+ "value": "Sort ascending"
+ }
+ ],
+ "sort-order-descending-label": [
+ {
+ "type": 0,
+ "value": "Sort descending"
+ }
+ ],
+ "sort-select-label": [
+ {
+ "type": 0,
+ "value": "Sort projects by"
+ }
+ ],
"start-coding-action": [
{
"type": 0,
@@ -2307,6 +2703,18 @@
"value": "Support"
}
],
+ "teacher-resources-row-carousel": [
+ {
+ "type": 0,
+ "value": "Teacher resources"
+ }
+ ],
+ "teacher-resources-row-title": [
+ {
+ "type": 0,
+ "value": "Teacher resources"
+ }
+ ],
"terms-of-use": [
{
"type": 0,
@@ -2427,6 +2835,12 @@
"value": "Gespeicherte Hex-Datei an micro:bit übertragen"
}
],
+ "troubleshooting-resource-title": [
+ {
+ "type": 0,
+ "value": "Troubleshooting"
+ }
+ ],
"try-again-action": [
{
"type": 0,
@@ -2499,6 +2913,12 @@
"value": "Benutzerhandbuch"
}
],
+ "view-all-projects": [
+ {
+ "type": 0,
+ "value": "View all projects"
+ }
+ ],
"visit-dot-org": [
{
"type": 0,
diff --git a/src/messages/ui.en.json b/src/messages/ui.en.json
index 9698703d9..67e489f45 100644
--- a/src/messages/ui.en.json
+++ b/src/messages/ui.en.json
@@ -65,6 +65,24 @@
"value": "Accessibility"
}
],
+ "accessibility-resource-title": [
+ {
+ "type": 0,
+ "value": "Accessibility"
+ }
+ ],
+ "add-files-action": [
+ {
+ "type": 0,
+ "value": "Add file(s)"
+ }
+ ],
+ "add-files-hover": [
+ {
+ "type": 0,
+ "value": "Add files to this project"
+ }
+ ],
"added-change": [
{
"type": 0,
@@ -165,6 +183,32 @@
"value": "Cancel"
}
],
+ "carousel-role": [
+ {
+ "type": 0,
+ "value": "carousel"
+ }
+ ],
+ "carousel-slide-label": [
+ {
+ "type": 1,
+ "value": "slideNum"
+ },
+ {
+ "type": 0,
+ "value": " of "
+ },
+ {
+ "type": 1,
+ "value": "totalSlides"
+ }
+ ],
+ "carousel-slide-role": [
+ {
+ "type": 0,
+ "value": "slide"
+ }
+ ],
"change-files": [
{
"type": 0,
@@ -455,12 +499,30 @@
"value": "Create file"
}
],
+ "create-project-action": [
+ {
+ "type": 0,
+ "value": "Create"
+ }
+ ],
+ "create-project-dialog-heading": [
+ {
+ "type": 0,
+ "value": "Name your project"
+ }
+ ],
"create-python": [
{
"type": 0,
"value": "Create a new Python file in this project"
}
],
+ "createai-taster-lessons-resource-title": [
+ {
+ "type": 0,
+ "value": "Taster lessons"
+ }
+ ],
"created-file": [
{
"type": 0,
@@ -487,6 +549,52 @@
"value": "name"
}
],
+ "delete-project-action": [
+ {
+ "type": 0,
+ "value": "Delete"
+ }
+ ],
+ "delete-project-confirm-heading": [
+ {
+ "type": 0,
+ "value": "Delete project"
+ }
+ ],
+ "delete-project-confirm-text": [
+ {
+ "type": 0,
+ "value": "Are you sure you want to delete ‘"
+ },
+ {
+ "type": 1,
+ "value": "project"
+ },
+ {
+ "type": 0,
+ "value": "’? This cannot be undone."
+ }
+ ],
+ "delete-projects-confirm-heading": [
+ {
+ "type": 0,
+ "value": "Delete projects"
+ }
+ ],
+ "delete-projects-confirm-text": [
+ {
+ "type": 0,
+ "value": "Are you sure you want to delete "
+ },
+ {
+ "type": 1,
+ "value": "numProjects"
+ },
+ {
+ "type": 0,
+ "value": " projects? This cannot be undone."
+ }
+ ],
"deleted-file": [
{
"type": 0,
@@ -521,6 +629,18 @@
"value": "Drag and drop"
}
],
+ "duplicate-project-action": [
+ {
+ "type": 0,
+ "value": "Duplicate"
+ }
+ ],
+ "duplicate-project-heading": [
+ {
+ "type": 0,
+ "value": "Name your project"
+ }
+ ],
"edit-file-action": [
{
"type": 0,
@@ -611,6 +731,18 @@
"value": "The name cannot contain spaces"
}
],
+ "files-tab": [
+ {
+ "type": 0,
+ "value": "Files"
+ }
+ ],
+ "files-tab-description": [
+ {
+ "type": 0,
+ "value": "Manage your project files"
+ }
+ ],
"firmware-update-link": [
{
"type": 0,
@@ -643,6 +775,12 @@
"value": "Firmware update required"
}
],
+ "first-lessons-with-python-resource-title": [
+ {
+ "type": 0,
+ "value": "First lessons with Python and the micro:bit"
+ }
+ ],
"flash-action": [
{
"type": 0,
@@ -701,6 +839,18 @@
"value": "Help"
}
],
+ "help-resources-row-carousel": [
+ {
+ "type": 0,
+ "value": "Help and support"
+ }
+ ],
+ "help-resources-row-title": [
+ {
+ "type": 0,
+ "value": "Help and support"
+ }
+ ],
"help-support": [
{
"type": 0,
@@ -737,6 +887,30 @@
"value": "Simple"
}
],
+ "home-action": [
+ {
+ "type": 0,
+ "value": "Home"
+ }
+ ],
+ "homepage-banner-heading": [
+ {
+ "type": 0,
+ "value": "Code your BBC micro:bit with Python"
+ }
+ ],
+ "homepage-banner-subtitle": [
+ {
+ "type": 0,
+ "value": "Create, edit and flash MicroPython programs to your micro:bit."
+ }
+ ],
+ "homepage-title": [
+ {
+ "type": 0,
+ "value": "micro:bit Python Editor"
+ }
+ ],
"ideas-tab": [
{
"type": 0,
@@ -749,6 +923,12 @@
"value": "Try out these projects, modify them and get inspired"
}
],
+ "import-file-action": [
+ {
+ "type": 0,
+ "value": "Import"
+ }
+ ],
"insert-code-action": [
{
"type": 0,
@@ -761,6 +941,12 @@
"value": "Language"
}
],
+ "learn-more-action": [
+ {
+ "type": 0,
+ "value": "Learn more"
+ }
+ ],
"less-action": [
{
"type": 0,
@@ -1027,6 +1213,18 @@
"value": "Warning: Only main.py downloaded"
}
],
+ "my-projects-row-carousel": [
+ {
+ "type": 0,
+ "value": "Your projects"
+ }
+ ],
+ "my-projects-row-title": [
+ {
+ "type": 0,
+ "value": "Your projects"
+ }
+ ],
"name-project": [
{
"type": 0,
@@ -1065,12 +1263,24 @@
"value": " extension for you."
}
],
+ "new-project-action": [
+ {
+ "type": 0,
+ "value": "New project"
+ }
+ ],
"next-action": [
{
"type": 0,
"value": "Next"
}
],
+ "no-projects": [
+ {
+ "type": 0,
+ "value": "No projects found"
+ }
+ ],
"not-found-checklist-one": [
{
"type": 0,
@@ -1203,6 +1413,12 @@
"value": "Open a hex or Python file or add other files"
}
],
+ "open-project-action": [
+ {
+ "type": 0,
+ "value": "Open"
+ }
+ ],
"options": [
{
"type": 0,
@@ -1347,12 +1563,112 @@
"value": "Project actions"
}
],
+ "project-file-count": [
+ {
+ "offset": 0,
+ "options": {
+ "one": {
+ "value": [
+ {
+ "type": 7
+ },
+ {
+ "type": 0,
+ "value": " file"
+ }
+ ]
+ },
+ "other": {
+ "value": [
+ {
+ "type": 7
+ },
+ {
+ "type": 0,
+ "value": " files"
+ }
+ ]
+ }
+ },
+ "pluralType": "cardinal",
+ "type": 6,
+ "value": "count"
+ }
+ ],
"project-header": [
{
"type": 0,
"value": "Project header"
}
],
+ "project-idea-animated-animals-title": [
+ {
+ "type": 0,
+ "value": "Animated animals"
+ }
+ ],
+ "project-idea-beating-heart-title": [
+ {
+ "type": 0,
+ "value": "Beating heart"
+ }
+ ],
+ "project-idea-emotion-badge-title": [
+ {
+ "type": 0,
+ "value": "Emotion badge"
+ }
+ ],
+ "project-idea-flashing-emotions-title": [
+ {
+ "type": 0,
+ "value": "Flashing emotions"
+ }
+ ],
+ "project-idea-get-silly-title": [
+ {
+ "type": 0,
+ "value": "Get silly"
+ }
+ ],
+ "project-idea-heart-title": [
+ {
+ "type": 0,
+ "value": "Heart"
+ }
+ ],
+ "project-ideas-row-carousel": [
+ {
+ "type": 0,
+ "value": "Project ideas"
+ }
+ ],
+ "project-ideas-row-title": [
+ {
+ "type": 0,
+ "value": "Project ideas"
+ }
+ ],
+ "project-loaded": [
+ {
+ "type": 0,
+ "value": "Project loaded"
+ }
+ ],
+ "project-menu-action": [
+ {
+ "type": 0,
+ "value": "Actions for project ‘"
+ },
+ {
+ "type": 1,
+ "value": "name"
+ },
+ {
+ "type": 0,
+ "value": "’"
+ }
+ ],
"project-name": [
{
"type": 0,
@@ -1365,6 +1681,12 @@
"value": "The project name cannot be empty"
}
],
+ "project-skip-to-toolbar": [
+ {
+ "type": 0,
+ "value": "Skip to selection actions"
+ }
+ ],
"project-tab": [
{
"type": 0,
@@ -1377,6 +1699,12 @@
"value": "View, create, add and edit the files in your project"
}
],
+ "projects-page-title": [
+ {
+ "type": 0,
+ "value": "Projects"
+ }
+ ],
"python-powered": [
{
"type": 0,
@@ -1419,6 +1747,18 @@
"value": "Reference"
}
],
+ "rename-project-action": [
+ {
+ "type": 0,
+ "value": "Rename"
+ }
+ ],
+ "rename-project-heading": [
+ {
+ "type": 0,
+ "value": "Rename project"
+ }
+ ],
"replace-action-label": [
{
"type": 0,
@@ -1523,6 +1863,26 @@
"value": "Search"
}
],
+ "select-project-action": [
+ {
+ "type": 0,
+ "value": "Select project ‘"
+ },
+ {
+ "type": 1,
+ "value": "name"
+ },
+ {
+ "type": 0,
+ "value": "’"
+ }
+ ],
+ "selection-actions-group": [
+ {
+ "type": 0,
+ "value": "Actions for selected projects"
+ }
+ ],
"send-action": [
{
"type": 0,
@@ -2243,6 +2603,42 @@
"value": "Software versions"
}
],
+ "sort-option-last-modified": [
+ {
+ "type": 0,
+ "value": "Last modified"
+ }
+ ],
+ "sort-option-name": [
+ {
+ "type": 0,
+ "value": "Name"
+ }
+ ],
+ "sort-option-relevance": [
+ {
+ "type": 0,
+ "value": "Relevance"
+ }
+ ],
+ "sort-order-ascending-label": [
+ {
+ "type": 0,
+ "value": "Sort ascending"
+ }
+ ],
+ "sort-order-descending-label": [
+ {
+ "type": 0,
+ "value": "Sort descending"
+ }
+ ],
+ "sort-select-label": [
+ {
+ "type": 0,
+ "value": "Sort projects by"
+ }
+ ],
"start-coding-action": [
{
"type": 0,
@@ -2255,6 +2651,18 @@
"value": "Support"
}
],
+ "teacher-resources-row-carousel": [
+ {
+ "type": 0,
+ "value": "Teacher resources"
+ }
+ ],
+ "teacher-resources-row-title": [
+ {
+ "type": 0,
+ "value": "Teacher resources"
+ }
+ ],
"terms-of-use": [
{
"type": 0,
@@ -2379,6 +2787,12 @@
"value": "Transfer saved hex file to micro:bit"
}
],
+ "troubleshooting-resource-title": [
+ {
+ "type": 0,
+ "value": "Troubleshooting"
+ }
+ ],
"try-again-action": [
{
"type": 0,
@@ -2451,6 +2865,12 @@
"value": "User guide"
}
],
+ "view-all-projects": [
+ {
+ "type": 0,
+ "value": "View all projects"
+ }
+ ],
"visit-dot-org": [
{
"type": 0,
diff --git a/src/messages/ui.es-es.json b/src/messages/ui.es-es.json
index a4c22242e..e9d8dc300 100644
--- a/src/messages/ui.es-es.json
+++ b/src/messages/ui.es-es.json
@@ -65,6 +65,24 @@
"value": "Accesibilidad"
}
],
+ "accessibility-resource-title": [
+ {
+ "type": 0,
+ "value": "Accessibility"
+ }
+ ],
+ "add-files-action": [
+ {
+ "type": 0,
+ "value": "Add file(s)"
+ }
+ ],
+ "add-files-hover": [
+ {
+ "type": 0,
+ "value": "Add files to this project"
+ }
+ ],
"added-change": [
{
"type": 0,
@@ -169,6 +187,32 @@
"value": "Cancelar"
}
],
+ "carousel-role": [
+ {
+ "type": 0,
+ "value": "carousel"
+ }
+ ],
+ "carousel-slide-label": [
+ {
+ "type": 1,
+ "value": "slideNum"
+ },
+ {
+ "type": 0,
+ "value": " of "
+ },
+ {
+ "type": 1,
+ "value": "totalSlides"
+ }
+ ],
+ "carousel-slide-role": [
+ {
+ "type": 0,
+ "value": "slide"
+ }
+ ],
"change-files": [
{
"type": 0,
@@ -459,12 +503,30 @@
"value": "Crear archivo"
}
],
+ "create-project-action": [
+ {
+ "type": 0,
+ "value": "Create"
+ }
+ ],
+ "create-project-dialog-heading": [
+ {
+ "type": 0,
+ "value": "Name your project"
+ }
+ ],
"create-python": [
{
"type": 0,
"value": "Crear un nuevo archivo Python en este proyecto"
}
],
+ "createai-taster-lessons-resource-title": [
+ {
+ "type": 0,
+ "value": "Taster lessons"
+ }
+ ],
"created-file": [
{
"type": 1,
@@ -491,6 +553,52 @@
"value": "name"
}
],
+ "delete-project-action": [
+ {
+ "type": 0,
+ "value": "Delete"
+ }
+ ],
+ "delete-project-confirm-heading": [
+ {
+ "type": 0,
+ "value": "Delete project"
+ }
+ ],
+ "delete-project-confirm-text": [
+ {
+ "type": 0,
+ "value": "Are you sure you want to delete ‘"
+ },
+ {
+ "type": 1,
+ "value": "project"
+ },
+ {
+ "type": 0,
+ "value": "’? This cannot be undone."
+ }
+ ],
+ "delete-projects-confirm-heading": [
+ {
+ "type": 0,
+ "value": "Delete projects"
+ }
+ ],
+ "delete-projects-confirm-text": [
+ {
+ "type": 0,
+ "value": "Are you sure you want to delete "
+ },
+ {
+ "type": 1,
+ "value": "numProjects"
+ },
+ {
+ "type": 0,
+ "value": " projects? This cannot be undone."
+ }
+ ],
"deleted-file": [
{
"type": 1,
@@ -525,6 +633,18 @@
"value": "Arrastra y suelta"
}
],
+ "duplicate-project-action": [
+ {
+ "type": 0,
+ "value": "Duplicate"
+ }
+ ],
+ "duplicate-project-heading": [
+ {
+ "type": 0,
+ "value": "Name your project"
+ }
+ ],
"edit-file-action": [
{
"type": 0,
@@ -615,6 +735,18 @@
"value": "El nombre no puede incluir espacios"
}
],
+ "files-tab": [
+ {
+ "type": 0,
+ "value": "Files"
+ }
+ ],
+ "files-tab-description": [
+ {
+ "type": 0,
+ "value": "Manage your project files"
+ }
+ ],
"firmware-update-link": [
{
"type": 0,
@@ -647,6 +779,12 @@
"value": "Es necesario actualizar el firmware"
}
],
+ "first-lessons-with-python-resource-title": [
+ {
+ "type": 0,
+ "value": "First lessons with Python and the micro:bit"
+ }
+ ],
"flash-action": [
{
"type": 0,
@@ -705,6 +843,18 @@
"value": "Ayuda"
}
],
+ "help-resources-row-carousel": [
+ {
+ "type": 0,
+ "value": "Help and support"
+ }
+ ],
+ "help-resources-row-title": [
+ {
+ "type": 0,
+ "value": "Help and support"
+ }
+ ],
"help-support": [
{
"type": 0,
@@ -741,6 +891,30 @@
"value": "Simple"
}
],
+ "home-action": [
+ {
+ "type": 0,
+ "value": "Home"
+ }
+ ],
+ "homepage-banner-heading": [
+ {
+ "type": 0,
+ "value": "Code your BBC micro:bit with Python"
+ }
+ ],
+ "homepage-banner-subtitle": [
+ {
+ "type": 0,
+ "value": "Create, edit and flash MicroPython programs to your micro:bit."
+ }
+ ],
+ "homepage-title": [
+ {
+ "type": 0,
+ "value": "micro:bit Python Editor"
+ }
+ ],
"ideas-tab": [
{
"type": 0,
@@ -753,6 +927,12 @@
"value": "Prueba estos proyectos y modifícalos para inspirarte"
}
],
+ "import-file-action": [
+ {
+ "type": 0,
+ "value": "Import"
+ }
+ ],
"insert-code-action": [
{
"type": 0,
@@ -765,6 +945,12 @@
"value": "Idioma"
}
],
+ "learn-more-action": [
+ {
+ "type": 0,
+ "value": "Learn more"
+ }
+ ],
"less-action": [
{
"type": 0,
@@ -1027,6 +1213,18 @@
"value": "Aviso: solo se ha descargado main.py"
}
],
+ "my-projects-row-carousel": [
+ {
+ "type": 0,
+ "value": "Your projects"
+ }
+ ],
+ "my-projects-row-title": [
+ {
+ "type": 0,
+ "value": "Your projects"
+ }
+ ],
"name-project": [
{
"type": 0,
@@ -1065,12 +1263,24 @@
"value": "."
}
],
+ "new-project-action": [
+ {
+ "type": 0,
+ "value": "New project"
+ }
+ ],
"next-action": [
{
"type": 0,
"value": "Siguiente"
}
],
+ "no-projects": [
+ {
+ "type": 0,
+ "value": "No projects found"
+ }
+ ],
"not-found-checklist-one": [
{
"type": 0,
@@ -1203,6 +1413,12 @@
"value": "Abre un archivo HEX o Python o añade otros archivos"
}
],
+ "open-project-action": [
+ {
+ "type": 0,
+ "value": "Open"
+ }
+ ],
"options": [
{
"type": 0,
@@ -1347,12 +1563,112 @@
"value": "Acciones del proyecto"
}
],
+ "project-file-count": [
+ {
+ "offset": 0,
+ "options": {
+ "one": {
+ "value": [
+ {
+ "type": 7
+ },
+ {
+ "type": 0,
+ "value": " file"
+ }
+ ]
+ },
+ "other": {
+ "value": [
+ {
+ "type": 7
+ },
+ {
+ "type": 0,
+ "value": " files"
+ }
+ ]
+ }
+ },
+ "pluralType": "cardinal",
+ "type": 6,
+ "value": "count"
+ }
+ ],
"project-header": [
{
"type": 0,
"value": "Cabecera del proyecto"
}
],
+ "project-idea-animated-animals-title": [
+ {
+ "type": 0,
+ "value": "Animated animals"
+ }
+ ],
+ "project-idea-beating-heart-title": [
+ {
+ "type": 0,
+ "value": "Beating heart"
+ }
+ ],
+ "project-idea-emotion-badge-title": [
+ {
+ "type": 0,
+ "value": "Emotion badge"
+ }
+ ],
+ "project-idea-flashing-emotions-title": [
+ {
+ "type": 0,
+ "value": "Flashing emotions"
+ }
+ ],
+ "project-idea-get-silly-title": [
+ {
+ "type": 0,
+ "value": "Get silly"
+ }
+ ],
+ "project-idea-heart-title": [
+ {
+ "type": 0,
+ "value": "Heart"
+ }
+ ],
+ "project-ideas-row-carousel": [
+ {
+ "type": 0,
+ "value": "Project ideas"
+ }
+ ],
+ "project-ideas-row-title": [
+ {
+ "type": 0,
+ "value": "Project ideas"
+ }
+ ],
+ "project-loaded": [
+ {
+ "type": 0,
+ "value": "Project loaded"
+ }
+ ],
+ "project-menu-action": [
+ {
+ "type": 0,
+ "value": "Actions for project ‘"
+ },
+ {
+ "type": 1,
+ "value": "name"
+ },
+ {
+ "type": 0,
+ "value": "’"
+ }
+ ],
"project-name": [
{
"type": 0,
@@ -1365,6 +1681,12 @@
"value": "El nombre del proyecto no puede estar en blanco"
}
],
+ "project-skip-to-toolbar": [
+ {
+ "type": 0,
+ "value": "Skip to selection actions"
+ }
+ ],
"project-tab": [
{
"type": 0,
@@ -1377,6 +1699,12 @@
"value": "Ver, crear, añadir y editar los archivos del proyecto"
}
],
+ "projects-page-title": [
+ {
+ "type": 0,
+ "value": "Projects"
+ }
+ ],
"python-powered": [
{
"type": 0,
@@ -1419,6 +1747,18 @@
"value": "Referencia"
}
],
+ "rename-project-action": [
+ {
+ "type": 0,
+ "value": "Rename"
+ }
+ ],
+ "rename-project-heading": [
+ {
+ "type": 0,
+ "value": "Rename project"
+ }
+ ],
"replace-action-label": [
{
"type": 0,
@@ -1523,6 +1863,26 @@
"value": "Buscar"
}
],
+ "select-project-action": [
+ {
+ "type": 0,
+ "value": "Select project ‘"
+ },
+ {
+ "type": 1,
+ "value": "name"
+ },
+ {
+ "type": 0,
+ "value": "’"
+ }
+ ],
+ "selection-actions-group": [
+ {
+ "type": 0,
+ "value": "Actions for selected projects"
+ }
+ ],
"send-action": [
{
"type": 0,
@@ -2235,6 +2595,42 @@
"value": "Versiones de software"
}
],
+ "sort-option-last-modified": [
+ {
+ "type": 0,
+ "value": "Last modified"
+ }
+ ],
+ "sort-option-name": [
+ {
+ "type": 0,
+ "value": "Name"
+ }
+ ],
+ "sort-option-relevance": [
+ {
+ "type": 0,
+ "value": "Relevance"
+ }
+ ],
+ "sort-order-ascending-label": [
+ {
+ "type": 0,
+ "value": "Sort ascending"
+ }
+ ],
+ "sort-order-descending-label": [
+ {
+ "type": 0,
+ "value": "Sort descending"
+ }
+ ],
+ "sort-select-label": [
+ {
+ "type": 0,
+ "value": "Sort projects by"
+ }
+ ],
"start-coding-action": [
{
"type": 0,
@@ -2247,6 +2643,18 @@
"value": "Ayuda Técnica"
}
],
+ "teacher-resources-row-carousel": [
+ {
+ "type": 0,
+ "value": "Teacher resources"
+ }
+ ],
+ "teacher-resources-row-title": [
+ {
+ "type": 0,
+ "value": "Teacher resources"
+ }
+ ],
"terms-of-use": [
{
"type": 0,
@@ -2367,6 +2775,12 @@
"value": "Transferir archivo HEX guardado a micro:bit"
}
],
+ "troubleshooting-resource-title": [
+ {
+ "type": 0,
+ "value": "Troubleshooting"
+ }
+ ],
"try-again-action": [
{
"type": 0,
@@ -2443,6 +2857,12 @@
"value": "Guía de usuario"
}
],
+ "view-all-projects": [
+ {
+ "type": 0,
+ "value": "View all projects"
+ }
+ ],
"visit-dot-org": [
{
"type": 0,
diff --git a/src/messages/ui.fr.json b/src/messages/ui.fr.json
index 78d2d1004..60ffe05e8 100644
--- a/src/messages/ui.fr.json
+++ b/src/messages/ui.fr.json
@@ -65,6 +65,24 @@
"value": "Accessibilité"
}
],
+ "accessibility-resource-title": [
+ {
+ "type": 0,
+ "value": "Accessibility"
+ }
+ ],
+ "add-files-action": [
+ {
+ "type": 0,
+ "value": "Add file(s)"
+ }
+ ],
+ "add-files-hover": [
+ {
+ "type": 0,
+ "value": "Add files to this project"
+ }
+ ],
"added-change": [
{
"type": 0,
@@ -165,6 +183,32 @@
"value": "Annuler"
}
],
+ "carousel-role": [
+ {
+ "type": 0,
+ "value": "carousel"
+ }
+ ],
+ "carousel-slide-label": [
+ {
+ "type": 1,
+ "value": "slideNum"
+ },
+ {
+ "type": 0,
+ "value": " of "
+ },
+ {
+ "type": 1,
+ "value": "totalSlides"
+ }
+ ],
+ "carousel-slide-role": [
+ {
+ "type": 0,
+ "value": "slide"
+ }
+ ],
"change-files": [
{
"type": 0,
@@ -455,12 +499,30 @@
"value": "Créer un fichier"
}
],
+ "create-project-action": [
+ {
+ "type": 0,
+ "value": "Create"
+ }
+ ],
+ "create-project-dialog-heading": [
+ {
+ "type": 0,
+ "value": "Name your project"
+ }
+ ],
"create-python": [
{
"type": 0,
"value": "Créer un nouveau fichier Python dans ce projet"
}
],
+ "createai-taster-lessons-resource-title": [
+ {
+ "type": 0,
+ "value": "Taster lessons"
+ }
+ ],
"created-file": [
{
"type": 1,
@@ -487,6 +549,52 @@
"value": "name"
}
],
+ "delete-project-action": [
+ {
+ "type": 0,
+ "value": "Delete"
+ }
+ ],
+ "delete-project-confirm-heading": [
+ {
+ "type": 0,
+ "value": "Delete project"
+ }
+ ],
+ "delete-project-confirm-text": [
+ {
+ "type": 0,
+ "value": "Are you sure you want to delete ‘"
+ },
+ {
+ "type": 1,
+ "value": "project"
+ },
+ {
+ "type": 0,
+ "value": "’? This cannot be undone."
+ }
+ ],
+ "delete-projects-confirm-heading": [
+ {
+ "type": 0,
+ "value": "Delete projects"
+ }
+ ],
+ "delete-projects-confirm-text": [
+ {
+ "type": 0,
+ "value": "Are you sure you want to delete "
+ },
+ {
+ "type": 1,
+ "value": "numProjects"
+ },
+ {
+ "type": 0,
+ "value": " projects? This cannot be undone."
+ }
+ ],
"deleted-file": [
{
"type": 1,
@@ -521,6 +629,18 @@
"value": "Glisser-déposer"
}
],
+ "duplicate-project-action": [
+ {
+ "type": 0,
+ "value": "Duplicate"
+ }
+ ],
+ "duplicate-project-heading": [
+ {
+ "type": 0,
+ "value": "Name your project"
+ }
+ ],
"edit-file-action": [
{
"type": 0,
@@ -611,6 +731,18 @@
"value": "Le nom ne peut pas contenir d'espaces"
}
],
+ "files-tab": [
+ {
+ "type": 0,
+ "value": "Files"
+ }
+ ],
+ "files-tab-description": [
+ {
+ "type": 0,
+ "value": "Manage your project files"
+ }
+ ],
"firmware-update-link": [
{
"type": 0,
@@ -643,6 +775,12 @@
"value": "Mise à jour du micrologiciel requise"
}
],
+ "first-lessons-with-python-resource-title": [
+ {
+ "type": 0,
+ "value": "First lessons with Python and the micro:bit"
+ }
+ ],
"flash-action": [
{
"type": 0,
@@ -701,6 +839,18 @@
"value": "Aide"
}
],
+ "help-resources-row-carousel": [
+ {
+ "type": 0,
+ "value": "Help and support"
+ }
+ ],
+ "help-resources-row-title": [
+ {
+ "type": 0,
+ "value": "Help and support"
+ }
+ ],
"help-support": [
{
"type": 0,
@@ -737,6 +887,30 @@
"value": "Simple"
}
],
+ "home-action": [
+ {
+ "type": 0,
+ "value": "Home"
+ }
+ ],
+ "homepage-banner-heading": [
+ {
+ "type": 0,
+ "value": "Code your BBC micro:bit with Python"
+ }
+ ],
+ "homepage-banner-subtitle": [
+ {
+ "type": 0,
+ "value": "Create, edit and flash MicroPython programs to your micro:bit."
+ }
+ ],
+ "homepage-title": [
+ {
+ "type": 0,
+ "value": "micro:bit Python Editor"
+ }
+ ],
"ideas-tab": [
{
"type": 0,
@@ -749,6 +923,12 @@
"value": "Essayez ces projets, modifiez-les et inspirez-vous en"
}
],
+ "import-file-action": [
+ {
+ "type": 0,
+ "value": "Import"
+ }
+ ],
"insert-code-action": [
{
"type": 0,
@@ -761,6 +941,12 @@
"value": "Langue"
}
],
+ "learn-more-action": [
+ {
+ "type": 0,
+ "value": "Learn more"
+ }
+ ],
"less-action": [
{
"type": 0,
@@ -1027,6 +1213,18 @@
"value": "Avertissement : Seul main.py est téléchargé"
}
],
+ "my-projects-row-carousel": [
+ {
+ "type": 0,
+ "value": "Your projects"
+ }
+ ],
+ "my-projects-row-title": [
+ {
+ "type": 0,
+ "value": "Your projects"
+ }
+ ],
"name-project": [
{
"type": 0,
@@ -1065,12 +1263,24 @@
"value": " pour vous."
}
],
+ "new-project-action": [
+ {
+ "type": 0,
+ "value": "New project"
+ }
+ ],
"next-action": [
{
"type": 0,
"value": "Suivant"
}
],
+ "no-projects": [
+ {
+ "type": 0,
+ "value": "No projects found"
+ }
+ ],
"not-found-checklist-one": [
{
"type": 0,
@@ -1203,6 +1413,12 @@
"value": "Ouvrir un fichier hex ou Python, ou ajouter d'autres fichiers"
}
],
+ "open-project-action": [
+ {
+ "type": 0,
+ "value": "Open"
+ }
+ ],
"options": [
{
"type": 0,
@@ -1347,12 +1563,112 @@
"value": "Actions du projet"
}
],
+ "project-file-count": [
+ {
+ "offset": 0,
+ "options": {
+ "one": {
+ "value": [
+ {
+ "type": 7
+ },
+ {
+ "type": 0,
+ "value": " file"
+ }
+ ]
+ },
+ "other": {
+ "value": [
+ {
+ "type": 7
+ },
+ {
+ "type": 0,
+ "value": " files"
+ }
+ ]
+ }
+ },
+ "pluralType": "cardinal",
+ "type": 6,
+ "value": "count"
+ }
+ ],
"project-header": [
{
"type": 0,
"value": "En-tête de projet"
}
],
+ "project-idea-animated-animals-title": [
+ {
+ "type": 0,
+ "value": "Animated animals"
+ }
+ ],
+ "project-idea-beating-heart-title": [
+ {
+ "type": 0,
+ "value": "Beating heart"
+ }
+ ],
+ "project-idea-emotion-badge-title": [
+ {
+ "type": 0,
+ "value": "Emotion badge"
+ }
+ ],
+ "project-idea-flashing-emotions-title": [
+ {
+ "type": 0,
+ "value": "Flashing emotions"
+ }
+ ],
+ "project-idea-get-silly-title": [
+ {
+ "type": 0,
+ "value": "Get silly"
+ }
+ ],
+ "project-idea-heart-title": [
+ {
+ "type": 0,
+ "value": "Heart"
+ }
+ ],
+ "project-ideas-row-carousel": [
+ {
+ "type": 0,
+ "value": "Project ideas"
+ }
+ ],
+ "project-ideas-row-title": [
+ {
+ "type": 0,
+ "value": "Project ideas"
+ }
+ ],
+ "project-loaded": [
+ {
+ "type": 0,
+ "value": "Project loaded"
+ }
+ ],
+ "project-menu-action": [
+ {
+ "type": 0,
+ "value": "Actions for project ‘"
+ },
+ {
+ "type": 1,
+ "value": "name"
+ },
+ {
+ "type": 0,
+ "value": "’"
+ }
+ ],
"project-name": [
{
"type": 0,
@@ -1365,6 +1681,12 @@
"value": "Le nom du projet ne peut pas être vide"
}
],
+ "project-skip-to-toolbar": [
+ {
+ "type": 0,
+ "value": "Skip to selection actions"
+ }
+ ],
"project-tab": [
{
"type": 0,
@@ -1377,6 +1699,12 @@
"value": "Visualiser, créer, ajouter et modifier les fichiers de votre projet"
}
],
+ "projects-page-title": [
+ {
+ "type": 0,
+ "value": "Projects"
+ }
+ ],
"python-powered": [
{
"type": 0,
@@ -1419,6 +1747,18 @@
"value": "Référence"
}
],
+ "rename-project-action": [
+ {
+ "type": 0,
+ "value": "Rename"
+ }
+ ],
+ "rename-project-heading": [
+ {
+ "type": 0,
+ "value": "Rename project"
+ }
+ ],
"replace-action-label": [
{
"type": 0,
@@ -1523,6 +1863,26 @@
"value": "Rechercher"
}
],
+ "select-project-action": [
+ {
+ "type": 0,
+ "value": "Select project ‘"
+ },
+ {
+ "type": 1,
+ "value": "name"
+ },
+ {
+ "type": 0,
+ "value": "’"
+ }
+ ],
+ "selection-actions-group": [
+ {
+ "type": 0,
+ "value": "Actions for selected projects"
+ }
+ ],
"send-action": [
{
"type": 0,
@@ -2235,6 +2595,42 @@
"value": "Versions logicielles"
}
],
+ "sort-option-last-modified": [
+ {
+ "type": 0,
+ "value": "Last modified"
+ }
+ ],
+ "sort-option-name": [
+ {
+ "type": 0,
+ "value": "Name"
+ }
+ ],
+ "sort-option-relevance": [
+ {
+ "type": 0,
+ "value": "Relevance"
+ }
+ ],
+ "sort-order-ascending-label": [
+ {
+ "type": 0,
+ "value": "Sort ascending"
+ }
+ ],
+ "sort-order-descending-label": [
+ {
+ "type": 0,
+ "value": "Sort descending"
+ }
+ ],
+ "sort-select-label": [
+ {
+ "type": 0,
+ "value": "Sort projects by"
+ }
+ ],
"start-coding-action": [
{
"type": 0,
@@ -2247,6 +2643,18 @@
"value": "Assistance"
}
],
+ "teacher-resources-row-carousel": [
+ {
+ "type": 0,
+ "value": "Teacher resources"
+ }
+ ],
+ "teacher-resources-row-title": [
+ {
+ "type": 0,
+ "value": "Teacher resources"
+ }
+ ],
"terms-of-use": [
{
"type": 0,
@@ -2367,6 +2775,12 @@
"value": "Transférer le fichier hex enregistré vers le micro:bit"
}
],
+ "troubleshooting-resource-title": [
+ {
+ "type": 0,
+ "value": "Troubleshooting"
+ }
+ ],
"try-again-action": [
{
"type": 0,
@@ -2443,6 +2857,12 @@
"value": "Guide de l'utilisateur"
}
],
+ "view-all-projects": [
+ {
+ "type": 0,
+ "value": "View all projects"
+ }
+ ],
"visit-dot-org": [
{
"type": 0,
diff --git a/src/messages/ui.ga-ie.json b/src/messages/ui.ga-ie.json
index d62dd8b27..12df6791a 100644
--- a/src/messages/ui.ga-ie.json
+++ b/src/messages/ui.ga-ie.json
@@ -65,6 +65,24 @@
"value": "Inrochtaineacht"
}
],
+ "accessibility-resource-title": [
+ {
+ "type": 0,
+ "value": "Accessibility"
+ }
+ ],
+ "add-files-action": [
+ {
+ "type": 0,
+ "value": "Add file(s)"
+ }
+ ],
+ "add-files-hover": [
+ {
+ "type": 0,
+ "value": "Add files to this project"
+ }
+ ],
"added-change": [
{
"type": 0,
@@ -193,6 +211,32 @@
"value": "Cealaigh"
}
],
+ "carousel-role": [
+ {
+ "type": 0,
+ "value": "carousel"
+ }
+ ],
+ "carousel-slide-label": [
+ {
+ "type": 1,
+ "value": "slideNum"
+ },
+ {
+ "type": 0,
+ "value": " of "
+ },
+ {
+ "type": 1,
+ "value": "totalSlides"
+ }
+ ],
+ "carousel-slide-role": [
+ {
+ "type": 0,
+ "value": "slide"
+ }
+ ],
"change-files": [
{
"type": 0,
@@ -499,12 +543,30 @@
"value": "Cruthaigh comhad"
}
],
+ "create-project-action": [
+ {
+ "type": 0,
+ "value": "Create"
+ }
+ ],
+ "create-project-dialog-heading": [
+ {
+ "type": 0,
+ "value": "Name your project"
+ }
+ ],
"create-python": [
{
"type": 0,
"value": "Cruthaigh comhad nua Python sa tionscadal seo"
}
],
+ "createai-taster-lessons-resource-title": [
+ {
+ "type": 0,
+ "value": "Taster lessons"
+ }
+ ],
"created-file": [
{
"type": 0,
@@ -531,6 +593,52 @@
"value": "name"
}
],
+ "delete-project-action": [
+ {
+ "type": 0,
+ "value": "Delete"
+ }
+ ],
+ "delete-project-confirm-heading": [
+ {
+ "type": 0,
+ "value": "Delete project"
+ }
+ ],
+ "delete-project-confirm-text": [
+ {
+ "type": 0,
+ "value": "Are you sure you want to delete ‘"
+ },
+ {
+ "type": 1,
+ "value": "project"
+ },
+ {
+ "type": 0,
+ "value": "’? This cannot be undone."
+ }
+ ],
+ "delete-projects-confirm-heading": [
+ {
+ "type": 0,
+ "value": "Delete projects"
+ }
+ ],
+ "delete-projects-confirm-text": [
+ {
+ "type": 0,
+ "value": "Are you sure you want to delete "
+ },
+ {
+ "type": 1,
+ "value": "numProjects"
+ },
+ {
+ "type": 0,
+ "value": " projects? This cannot be undone."
+ }
+ ],
"deleted-file": [
{
"type": 0,
@@ -565,6 +673,18 @@
"value": "Tarraing agus scaoil"
}
],
+ "duplicate-project-action": [
+ {
+ "type": 0,
+ "value": "Duplicate"
+ }
+ ],
+ "duplicate-project-heading": [
+ {
+ "type": 0,
+ "value": "Name your project"
+ }
+ ],
"edit-file-action": [
{
"type": 0,
@@ -659,6 +779,18 @@
"value": "Ní féidir spásanna a bheith san ainm"
}
],
+ "files-tab": [
+ {
+ "type": 0,
+ "value": "Files"
+ }
+ ],
+ "files-tab-description": [
+ {
+ "type": 0,
+ "value": "Manage your project files"
+ }
+ ],
"firmware-update-link": [
{
"type": 0,
@@ -691,6 +823,12 @@
"value": "Nuashonrú dochtearraí ag teastáil"
}
],
+ "first-lessons-with-python-resource-title": [
+ {
+ "type": 0,
+ "value": "First lessons with Python and the micro:bit"
+ }
+ ],
"flash-action": [
{
"type": 0,
@@ -749,6 +887,18 @@
"value": "Cabhair"
}
],
+ "help-resources-row-carousel": [
+ {
+ "type": 0,
+ "value": "Help and support"
+ }
+ ],
+ "help-resources-row-title": [
+ {
+ "type": 0,
+ "value": "Help and support"
+ }
+ ],
"help-support": [
{
"type": 0,
@@ -785,6 +935,30 @@
"value": "Simplí"
}
],
+ "home-action": [
+ {
+ "type": 0,
+ "value": "Home"
+ }
+ ],
+ "homepage-banner-heading": [
+ {
+ "type": 0,
+ "value": "Code your BBC micro:bit with Python"
+ }
+ ],
+ "homepage-banner-subtitle": [
+ {
+ "type": 0,
+ "value": "Create, edit and flash MicroPython programs to your micro:bit."
+ }
+ ],
+ "homepage-title": [
+ {
+ "type": 0,
+ "value": "micro:bit Python Editor"
+ }
+ ],
"ideas-tab": [
{
"type": 0,
@@ -797,6 +971,12 @@
"value": "Bain triail as na tionscadail seo, athraigh iad agus spreag iad"
}
],
+ "import-file-action": [
+ {
+ "type": 0,
+ "value": "Import"
+ }
+ ],
"insert-code-action": [
{
"type": 0,
@@ -809,6 +989,12 @@
"value": "Teanga"
}
],
+ "learn-more-action": [
+ {
+ "type": 0,
+ "value": "Learn more"
+ }
+ ],
"less-action": [
{
"type": 0,
@@ -1103,6 +1289,18 @@
"value": "Rabhadh: Ní íoslódálfar ach main.py"
}
],
+ "my-projects-row-carousel": [
+ {
+ "type": 0,
+ "value": "Your projects"
+ }
+ ],
+ "my-projects-row-title": [
+ {
+ "type": 0,
+ "value": "Your projects"
+ }
+ ],
"name-project": [
{
"type": 0,
@@ -1141,12 +1339,24 @@
"value": " ar do shon."
}
],
+ "new-project-action": [
+ {
+ "type": 0,
+ "value": "New project"
+ }
+ ],
"next-action": [
{
"type": 0,
"value": "Ar Aghaidh"
}
],
+ "no-projects": [
+ {
+ "type": 0,
+ "value": "No projects found"
+ }
+ ],
"not-found-checklist-one": [
{
"type": 0,
@@ -1279,6 +1489,12 @@
"value": "Oscail comhad heicsidheachúlach nó Python nó cuir comhaid eile leis"
}
],
+ "open-project-action": [
+ {
+ "type": 0,
+ "value": "Open"
+ }
+ ],
"options": [
{
"type": 0,
@@ -1423,12 +1639,112 @@
"value": "Gníomhartha tionscadail"
}
],
+ "project-file-count": [
+ {
+ "offset": 0,
+ "options": {
+ "one": {
+ "value": [
+ {
+ "type": 7
+ },
+ {
+ "type": 0,
+ "value": " file"
+ }
+ ]
+ },
+ "other": {
+ "value": [
+ {
+ "type": 7
+ },
+ {
+ "type": 0,
+ "value": " files"
+ }
+ ]
+ }
+ },
+ "pluralType": "cardinal",
+ "type": 6,
+ "value": "count"
+ }
+ ],
"project-header": [
{
"type": 0,
"value": "Ceanntásc an tionscadail"
}
],
+ "project-idea-animated-animals-title": [
+ {
+ "type": 0,
+ "value": "Animated animals"
+ }
+ ],
+ "project-idea-beating-heart-title": [
+ {
+ "type": 0,
+ "value": "Beating heart"
+ }
+ ],
+ "project-idea-emotion-badge-title": [
+ {
+ "type": 0,
+ "value": "Emotion badge"
+ }
+ ],
+ "project-idea-flashing-emotions-title": [
+ {
+ "type": 0,
+ "value": "Flashing emotions"
+ }
+ ],
+ "project-idea-get-silly-title": [
+ {
+ "type": 0,
+ "value": "Get silly"
+ }
+ ],
+ "project-idea-heart-title": [
+ {
+ "type": 0,
+ "value": "Heart"
+ }
+ ],
+ "project-ideas-row-carousel": [
+ {
+ "type": 0,
+ "value": "Project ideas"
+ }
+ ],
+ "project-ideas-row-title": [
+ {
+ "type": 0,
+ "value": "Project ideas"
+ }
+ ],
+ "project-loaded": [
+ {
+ "type": 0,
+ "value": "Project loaded"
+ }
+ ],
+ "project-menu-action": [
+ {
+ "type": 0,
+ "value": "Actions for project ‘"
+ },
+ {
+ "type": 1,
+ "value": "name"
+ },
+ {
+ "type": 0,
+ "value": "’"
+ }
+ ],
"project-name": [
{
"type": 0,
@@ -1441,6 +1757,12 @@
"value": "Ní féidir ainm an tionscadail a fholmhú"
}
],
+ "project-skip-to-toolbar": [
+ {
+ "type": 0,
+ "value": "Skip to selection actions"
+ }
+ ],
"project-tab": [
{
"type": 0,
@@ -1453,6 +1775,12 @@
"value": "Amharc ar na comhaid i do thionscadal, iad a chruthú, a chur leis agus a chur in eagar"
}
],
+ "projects-page-title": [
+ {
+ "type": 0,
+ "value": "Projects"
+ }
+ ],
"python-powered": [
{
"type": 0,
@@ -1495,6 +1823,18 @@
"value": "Tagairt"
}
],
+ "rename-project-action": [
+ {
+ "type": 0,
+ "value": "Rename"
+ }
+ ],
+ "rename-project-heading": [
+ {
+ "type": 0,
+ "value": "Rename project"
+ }
+ ],
"replace-action-label": [
{
"type": 0,
@@ -1636,6 +1976,26 @@
"value": "Cuardaigh"
}
],
+ "select-project-action": [
+ {
+ "type": 0,
+ "value": "Select project ‘"
+ },
+ {
+ "type": 1,
+ "value": "name"
+ },
+ {
+ "type": 0,
+ "value": "’"
+ }
+ ],
+ "selection-actions-group": [
+ {
+ "type": 0,
+ "value": "Actions for selected projects"
+ }
+ ],
"send-action": [
{
"type": 0,
@@ -2385,6 +2745,42 @@
"value": "Leaganacha bogearraí"
}
],
+ "sort-option-last-modified": [
+ {
+ "type": 0,
+ "value": "Last modified"
+ }
+ ],
+ "sort-option-name": [
+ {
+ "type": 0,
+ "value": "Name"
+ }
+ ],
+ "sort-option-relevance": [
+ {
+ "type": 0,
+ "value": "Relevance"
+ }
+ ],
+ "sort-order-ascending-label": [
+ {
+ "type": 0,
+ "value": "Sort ascending"
+ }
+ ],
+ "sort-order-descending-label": [
+ {
+ "type": 0,
+ "value": "Sort descending"
+ }
+ ],
+ "sort-select-label": [
+ {
+ "type": 0,
+ "value": "Sort projects by"
+ }
+ ],
"start-coding-action": [
{
"type": 0,
@@ -2397,6 +2793,18 @@
"value": "Tacaíocht"
}
],
+ "teacher-resources-row-carousel": [
+ {
+ "type": 0,
+ "value": "Teacher resources"
+ }
+ ],
+ "teacher-resources-row-title": [
+ {
+ "type": 0,
+ "value": "Teacher resources"
+ }
+ ],
"terms-of-use": [
{
"type": 0,
@@ -2517,6 +2925,12 @@
"value": "Aistrigh comhad heicsidheachúlach sábháilte go micro:bit"
}
],
+ "troubleshooting-resource-title": [
+ {
+ "type": 0,
+ "value": "Troubleshooting"
+ }
+ ],
"try-again-action": [
{
"type": 0,
@@ -2589,6 +3003,12 @@
"value": "Treoir d'úsáideoirí"
}
],
+ "view-all-projects": [
+ {
+ "type": 0,
+ "value": "View all projects"
+ }
+ ],
"visit-dot-org": [
{
"type": 0,
diff --git a/src/messages/ui.ja.json b/src/messages/ui.ja.json
index f2ca82117..b7cb118f8 100644
--- a/src/messages/ui.ja.json
+++ b/src/messages/ui.ja.json
@@ -65,6 +65,24 @@
"value": "アクセシビリティ"
}
],
+ "accessibility-resource-title": [
+ {
+ "type": 0,
+ "value": "Accessibility"
+ }
+ ],
+ "add-files-action": [
+ {
+ "type": 0,
+ "value": "Add file(s)"
+ }
+ ],
+ "add-files-hover": [
+ {
+ "type": 0,
+ "value": "Add files to this project"
+ }
+ ],
"added-change": [
{
"type": 0,
@@ -165,6 +183,32 @@
"value": "キャンセル"
}
],
+ "carousel-role": [
+ {
+ "type": 0,
+ "value": "carousel"
+ }
+ ],
+ "carousel-slide-label": [
+ {
+ "type": 1,
+ "value": "slideNum"
+ },
+ {
+ "type": 0,
+ "value": " of "
+ },
+ {
+ "type": 1,
+ "value": "totalSlides"
+ }
+ ],
+ "carousel-slide-role": [
+ {
+ "type": 0,
+ "value": "slide"
+ }
+ ],
"change-files": [
{
"type": 0,
@@ -479,12 +523,30 @@
"value": "ファイルを作成"
}
],
+ "create-project-action": [
+ {
+ "type": 0,
+ "value": "Create"
+ }
+ ],
+ "create-project-dialog-heading": [
+ {
+ "type": 0,
+ "value": "Name your project"
+ }
+ ],
"create-python": [
{
"type": 0,
"value": "このプロジェクトに新しいPythonファイルを作成"
}
],
+ "createai-taster-lessons-resource-title": [
+ {
+ "type": 0,
+ "value": "Taster lessons"
+ }
+ ],
"created-file": [
{
"type": 1,
@@ -511,6 +573,52 @@
"value": " を削除"
}
],
+ "delete-project-action": [
+ {
+ "type": 0,
+ "value": "Delete"
+ }
+ ],
+ "delete-project-confirm-heading": [
+ {
+ "type": 0,
+ "value": "Delete project"
+ }
+ ],
+ "delete-project-confirm-text": [
+ {
+ "type": 0,
+ "value": "Are you sure you want to delete ‘"
+ },
+ {
+ "type": 1,
+ "value": "project"
+ },
+ {
+ "type": 0,
+ "value": "’? This cannot be undone."
+ }
+ ],
+ "delete-projects-confirm-heading": [
+ {
+ "type": 0,
+ "value": "Delete projects"
+ }
+ ],
+ "delete-projects-confirm-text": [
+ {
+ "type": 0,
+ "value": "Are you sure you want to delete "
+ },
+ {
+ "type": 1,
+ "value": "numProjects"
+ },
+ {
+ "type": 0,
+ "value": " projects? This cannot be undone."
+ }
+ ],
"deleted-file": [
{
"type": 1,
@@ -545,6 +653,18 @@
"value": "ドラッグ&ドロップ"
}
],
+ "duplicate-project-action": [
+ {
+ "type": 0,
+ "value": "Duplicate"
+ }
+ ],
+ "duplicate-project-heading": [
+ {
+ "type": 0,
+ "value": "Name your project"
+ }
+ ],
"edit-file-action": [
{
"type": 1,
@@ -635,6 +755,18 @@
"value": "名前にスペースを含めることはできません"
}
],
+ "files-tab": [
+ {
+ "type": 0,
+ "value": "Files"
+ }
+ ],
+ "files-tab-description": [
+ {
+ "type": 0,
+ "value": "Manage your project files"
+ }
+ ],
"firmware-update-link": [
{
"type": 0,
@@ -667,6 +799,12 @@
"value": "ファームウェアの更新が必要です"
}
],
+ "first-lessons-with-python-resource-title": [
+ {
+ "type": 0,
+ "value": "First lessons with Python and the micro:bit"
+ }
+ ],
"flash-action": [
{
"type": 0,
@@ -729,6 +867,18 @@
"value": "ヘルプ"
}
],
+ "help-resources-row-carousel": [
+ {
+ "type": 0,
+ "value": "Help and support"
+ }
+ ],
+ "help-resources-row-title": [
+ {
+ "type": 0,
+ "value": "Help and support"
+ }
+ ],
"help-support": [
{
"type": 0,
@@ -765,6 +915,30 @@
"value": "簡易"
}
],
+ "home-action": [
+ {
+ "type": 0,
+ "value": "Home"
+ }
+ ],
+ "homepage-banner-heading": [
+ {
+ "type": 0,
+ "value": "Code your BBC micro:bit with Python"
+ }
+ ],
+ "homepage-banner-subtitle": [
+ {
+ "type": 0,
+ "value": "Create, edit and flash MicroPython programs to your micro:bit."
+ }
+ ],
+ "homepage-title": [
+ {
+ "type": 0,
+ "value": "micro:bit Python Editor"
+ }
+ ],
"ideas-tab": [
{
"type": 0,
@@ -777,6 +951,12 @@
"value": "これらのプロジェクトを試し、修正し、インスピレーションを得ることができます。"
}
],
+ "import-file-action": [
+ {
+ "type": 0,
+ "value": "Import"
+ }
+ ],
"insert-code-action": [
{
"type": 0,
@@ -789,6 +969,12 @@
"value": "言語"
}
],
+ "learn-more-action": [
+ {
+ "type": 0,
+ "value": "Learn more"
+ }
+ ],
"less-action": [
{
"type": 0,
@@ -1043,6 +1229,18 @@
"value": "注意: main.pyのみダウンロードされました"
}
],
+ "my-projects-row-carousel": [
+ {
+ "type": 0,
+ "value": "Your projects"
+ }
+ ],
+ "my-projects-row-title": [
+ {
+ "type": 0,
+ "value": "Your projects"
+ }
+ ],
"name-project": [
{
"type": 0,
@@ -1077,12 +1275,24 @@
"value": "拡張子を追加します。"
}
],
+ "new-project-action": [
+ {
+ "type": 0,
+ "value": "New project"
+ }
+ ],
"next-action": [
{
"type": 0,
"value": "次"
}
],
+ "no-projects": [
+ {
+ "type": 0,
+ "value": "No projects found"
+ }
+ ],
"not-found-checklist-one": [
{
"children": [
@@ -1211,6 +1421,12 @@
"value": "hex ファイルまたは Python ファイルを開くか、他のファイルを追加する"
}
],
+ "open-project-action": [
+ {
+ "type": 0,
+ "value": "Open"
+ }
+ ],
"options": [
{
"type": 0,
@@ -1351,12 +1567,112 @@
"value": "プロジェクトアクション"
}
],
+ "project-file-count": [
+ {
+ "offset": 0,
+ "options": {
+ "one": {
+ "value": [
+ {
+ "type": 7
+ },
+ {
+ "type": 0,
+ "value": " file"
+ }
+ ]
+ },
+ "other": {
+ "value": [
+ {
+ "type": 7
+ },
+ {
+ "type": 0,
+ "value": " files"
+ }
+ ]
+ }
+ },
+ "pluralType": "cardinal",
+ "type": 6,
+ "value": "count"
+ }
+ ],
"project-header": [
{
"type": 0,
"value": "プロジェクトヘッダー"
}
],
+ "project-idea-animated-animals-title": [
+ {
+ "type": 0,
+ "value": "Animated animals"
+ }
+ ],
+ "project-idea-beating-heart-title": [
+ {
+ "type": 0,
+ "value": "Beating heart"
+ }
+ ],
+ "project-idea-emotion-badge-title": [
+ {
+ "type": 0,
+ "value": "Emotion badge"
+ }
+ ],
+ "project-idea-flashing-emotions-title": [
+ {
+ "type": 0,
+ "value": "Flashing emotions"
+ }
+ ],
+ "project-idea-get-silly-title": [
+ {
+ "type": 0,
+ "value": "Get silly"
+ }
+ ],
+ "project-idea-heart-title": [
+ {
+ "type": 0,
+ "value": "Heart"
+ }
+ ],
+ "project-ideas-row-carousel": [
+ {
+ "type": 0,
+ "value": "Project ideas"
+ }
+ ],
+ "project-ideas-row-title": [
+ {
+ "type": 0,
+ "value": "Project ideas"
+ }
+ ],
+ "project-loaded": [
+ {
+ "type": 0,
+ "value": "Project loaded"
+ }
+ ],
+ "project-menu-action": [
+ {
+ "type": 0,
+ "value": "Actions for project ‘"
+ },
+ {
+ "type": 1,
+ "value": "name"
+ },
+ {
+ "type": 0,
+ "value": "’"
+ }
+ ],
"project-name": [
{
"type": 0,
@@ -1369,6 +1685,12 @@
"value": "プロジェクト名は空にできません"
}
],
+ "project-skip-to-toolbar": [
+ {
+ "type": 0,
+ "value": "Skip to selection actions"
+ }
+ ],
"project-tab": [
{
"type": 0,
@@ -1381,6 +1703,12 @@
"value": "プロジェクト内のファイルの表示、作成、追加、編集"
}
],
+ "projects-page-title": [
+ {
+ "type": 0,
+ "value": "Projects"
+ }
+ ],
"python-powered": [
{
"type": 0,
@@ -1423,6 +1751,18 @@
"value": "リファレンス"
}
],
+ "rename-project-action": [
+ {
+ "type": 0,
+ "value": "Rename"
+ }
+ ],
+ "rename-project-heading": [
+ {
+ "type": 0,
+ "value": "Rename project"
+ }
+ ],
"replace-action-label": [
{
"type": 0,
@@ -1516,6 +1856,26 @@
"value": "検索"
}
],
+ "select-project-action": [
+ {
+ "type": 0,
+ "value": "Select project ‘"
+ },
+ {
+ "type": 1,
+ "value": "name"
+ },
+ {
+ "type": 0,
+ "value": "’"
+ }
+ ],
+ "selection-actions-group": [
+ {
+ "type": 0,
+ "value": "Actions for selected projects"
+ }
+ ],
"send-action": [
{
"type": 0,
@@ -2229,6 +2589,42 @@
"value": "ソフトウェアのバージョン"
}
],
+ "sort-option-last-modified": [
+ {
+ "type": 0,
+ "value": "Last modified"
+ }
+ ],
+ "sort-option-name": [
+ {
+ "type": 0,
+ "value": "Name"
+ }
+ ],
+ "sort-option-relevance": [
+ {
+ "type": 0,
+ "value": "Relevance"
+ }
+ ],
+ "sort-order-ascending-label": [
+ {
+ "type": 0,
+ "value": "Sort ascending"
+ }
+ ],
+ "sort-order-descending-label": [
+ {
+ "type": 0,
+ "value": "Sort descending"
+ }
+ ],
+ "sort-select-label": [
+ {
+ "type": 0,
+ "value": "Sort projects by"
+ }
+ ],
"start-coding-action": [
{
"type": 0,
@@ -2241,6 +2637,18 @@
"value": "サポート"
}
],
+ "teacher-resources-row-carousel": [
+ {
+ "type": 0,
+ "value": "Teacher resources"
+ }
+ ],
+ "teacher-resources-row-title": [
+ {
+ "type": 0,
+ "value": "Teacher resources"
+ }
+ ],
"terms-of-use": [
{
"type": 0,
@@ -2361,6 +2769,12 @@
"value": "保存された hex ファイルをmicro:bitに転送する"
}
],
+ "troubleshooting-resource-title": [
+ {
+ "type": 0,
+ "value": "Troubleshooting"
+ }
+ ],
"try-again-action": [
{
"type": 0,
@@ -2445,6 +2859,12 @@
"value": "ユーザーガイド"
}
],
+ "view-all-projects": [
+ {
+ "type": 0,
+ "value": "View all projects"
+ }
+ ],
"visit-dot-org": [
{
"type": 0,
diff --git a/src/messages/ui.ko.json b/src/messages/ui.ko.json
index 399b3e316..accb4e20a 100644
--- a/src/messages/ui.ko.json
+++ b/src/messages/ui.ko.json
@@ -65,6 +65,24 @@
"value": "접근성"
}
],
+ "accessibility-resource-title": [
+ {
+ "type": 0,
+ "value": "Accessibility"
+ }
+ ],
+ "add-files-action": [
+ {
+ "type": 0,
+ "value": "Add file(s)"
+ }
+ ],
+ "add-files-hover": [
+ {
+ "type": 0,
+ "value": "Add files to this project"
+ }
+ ],
"added-change": [
{
"type": 1,
@@ -169,6 +187,32 @@
"value": "취소"
}
],
+ "carousel-role": [
+ {
+ "type": 0,
+ "value": "carousel"
+ }
+ ],
+ "carousel-slide-label": [
+ {
+ "type": 1,
+ "value": "slideNum"
+ },
+ {
+ "type": 0,
+ "value": " of "
+ },
+ {
+ "type": 1,
+ "value": "totalSlides"
+ }
+ ],
+ "carousel-slide-role": [
+ {
+ "type": 0,
+ "value": "slide"
+ }
+ ],
"change-files": [
{
"type": 0,
@@ -463,12 +507,30 @@
"value": "파일 생성"
}
],
+ "create-project-action": [
+ {
+ "type": 0,
+ "value": "Create"
+ }
+ ],
+ "create-project-dialog-heading": [
+ {
+ "type": 0,
+ "value": "Name your project"
+ }
+ ],
"create-python": [
{
"type": 0,
"value": "이 프로젝트 안에서 새로운 Python 파일 생성"
}
],
+ "createai-taster-lessons-resource-title": [
+ {
+ "type": 0,
+ "value": "Taster lessons"
+ }
+ ],
"created-file": [
{
"type": 1,
@@ -495,6 +557,52 @@
"value": " 삭제"
}
],
+ "delete-project-action": [
+ {
+ "type": 0,
+ "value": "Delete"
+ }
+ ],
+ "delete-project-confirm-heading": [
+ {
+ "type": 0,
+ "value": "Delete project"
+ }
+ ],
+ "delete-project-confirm-text": [
+ {
+ "type": 0,
+ "value": "Are you sure you want to delete ‘"
+ },
+ {
+ "type": 1,
+ "value": "project"
+ },
+ {
+ "type": 0,
+ "value": "’? This cannot be undone."
+ }
+ ],
+ "delete-projects-confirm-heading": [
+ {
+ "type": 0,
+ "value": "Delete projects"
+ }
+ ],
+ "delete-projects-confirm-text": [
+ {
+ "type": 0,
+ "value": "Are you sure you want to delete "
+ },
+ {
+ "type": 1,
+ "value": "numProjects"
+ },
+ {
+ "type": 0,
+ "value": " projects? This cannot be undone."
+ }
+ ],
"deleted-file": [
{
"type": 1,
@@ -529,6 +637,18 @@
"value": "드래그 & 드롭"
}
],
+ "duplicate-project-action": [
+ {
+ "type": 0,
+ "value": "Duplicate"
+ }
+ ],
+ "duplicate-project-heading": [
+ {
+ "type": 0,
+ "value": "Name your project"
+ }
+ ],
"edit-file-action": [
{
"type": 1,
@@ -619,6 +739,18 @@
"value": "이름에 띄어쓰기를 포함할 수 없습니다"
}
],
+ "files-tab": [
+ {
+ "type": 0,
+ "value": "Files"
+ }
+ ],
+ "files-tab-description": [
+ {
+ "type": 0,
+ "value": "Manage your project files"
+ }
+ ],
"firmware-update-link": [
{
"type": 0,
@@ -651,6 +783,12 @@
"value": "펌웨어 업데이트 필요"
}
],
+ "first-lessons-with-python-resource-title": [
+ {
+ "type": 0,
+ "value": "First lessons with Python and the micro:bit"
+ }
+ ],
"flash-action": [
{
"type": 0,
@@ -713,6 +851,18 @@
"value": "도움 및 지원"
}
],
+ "help-resources-row-carousel": [
+ {
+ "type": 0,
+ "value": "Help and support"
+ }
+ ],
+ "help-resources-row-title": [
+ {
+ "type": 0,
+ "value": "Help and support"
+ }
+ ],
"help-support": [
{
"type": 0,
@@ -749,6 +899,30 @@
"value": "단순"
}
],
+ "home-action": [
+ {
+ "type": 0,
+ "value": "Home"
+ }
+ ],
+ "homepage-banner-heading": [
+ {
+ "type": 0,
+ "value": "Code your BBC micro:bit with Python"
+ }
+ ],
+ "homepage-banner-subtitle": [
+ {
+ "type": 0,
+ "value": "Create, edit and flash MicroPython programs to your micro:bit."
+ }
+ ],
+ "homepage-title": [
+ {
+ "type": 0,
+ "value": "micro:bit Python Editor"
+ }
+ ],
"ideas-tab": [
{
"type": 0,
@@ -761,6 +935,12 @@
"value": "다양한 프로젝트를 체험해보고 수정하며 아이디어를 얻어보세요"
}
],
+ "import-file-action": [
+ {
+ "type": 0,
+ "value": "Import"
+ }
+ ],
"insert-code-action": [
{
"type": 0,
@@ -773,6 +953,12 @@
"value": "언어 선택"
}
],
+ "learn-more-action": [
+ {
+ "type": 0,
+ "value": "Learn more"
+ }
+ ],
"less-action": [
{
"type": 0,
@@ -1039,6 +1225,18 @@
"value": "경고: main.py만 다운로드됨"
}
],
+ "my-projects-row-carousel": [
+ {
+ "type": 0,
+ "value": "Your projects"
+ }
+ ],
+ "my-projects-row-title": [
+ {
+ "type": 0,
+ "value": "Your projects"
+ }
+ ],
"name-project": [
{
"type": 0,
@@ -1077,12 +1275,24 @@
"value": " 확장자를 추가합니다."
}
],
+ "new-project-action": [
+ {
+ "type": 0,
+ "value": "New project"
+ }
+ ],
"next-action": [
{
"type": 0,
"value": "다음"
}
],
+ "no-projects": [
+ {
+ "type": 0,
+ "value": "No projects found"
+ }
+ ],
"not-found-checklist-one": [
{
"type": 0,
@@ -1215,6 +1425,12 @@
"value": "Hex 또는 Python 파일을 열거나 다른 파일을 추가하세요"
}
],
+ "open-project-action": [
+ {
+ "type": 0,
+ "value": "Open"
+ }
+ ],
"options": [
{
"type": 0,
@@ -1355,12 +1571,112 @@
"value": "프로젝트 동작"
}
],
+ "project-file-count": [
+ {
+ "offset": 0,
+ "options": {
+ "one": {
+ "value": [
+ {
+ "type": 7
+ },
+ {
+ "type": 0,
+ "value": " file"
+ }
+ ]
+ },
+ "other": {
+ "value": [
+ {
+ "type": 7
+ },
+ {
+ "type": 0,
+ "value": " files"
+ }
+ ]
+ }
+ },
+ "pluralType": "cardinal",
+ "type": 6,
+ "value": "count"
+ }
+ ],
"project-header": [
{
"type": 0,
"value": "프로젝트 머리글"
}
],
+ "project-idea-animated-animals-title": [
+ {
+ "type": 0,
+ "value": "Animated animals"
+ }
+ ],
+ "project-idea-beating-heart-title": [
+ {
+ "type": 0,
+ "value": "Beating heart"
+ }
+ ],
+ "project-idea-emotion-badge-title": [
+ {
+ "type": 0,
+ "value": "Emotion badge"
+ }
+ ],
+ "project-idea-flashing-emotions-title": [
+ {
+ "type": 0,
+ "value": "Flashing emotions"
+ }
+ ],
+ "project-idea-get-silly-title": [
+ {
+ "type": 0,
+ "value": "Get silly"
+ }
+ ],
+ "project-idea-heart-title": [
+ {
+ "type": 0,
+ "value": "Heart"
+ }
+ ],
+ "project-ideas-row-carousel": [
+ {
+ "type": 0,
+ "value": "Project ideas"
+ }
+ ],
+ "project-ideas-row-title": [
+ {
+ "type": 0,
+ "value": "Project ideas"
+ }
+ ],
+ "project-loaded": [
+ {
+ "type": 0,
+ "value": "Project loaded"
+ }
+ ],
+ "project-menu-action": [
+ {
+ "type": 0,
+ "value": "Actions for project ‘"
+ },
+ {
+ "type": 1,
+ "value": "name"
+ },
+ {
+ "type": 0,
+ "value": "’"
+ }
+ ],
"project-name": [
{
"type": 0,
@@ -1373,6 +1689,12 @@
"value": "프로젝트 이름을 입력해야 합니다"
}
],
+ "project-skip-to-toolbar": [
+ {
+ "type": 0,
+ "value": "Skip to selection actions"
+ }
+ ],
"project-tab": [
{
"type": 0,
@@ -1385,6 +1707,12 @@
"value": "프로젝트에서 파일을 확인하고, 생성하고, 추가하고 편집할 수 있습니다"
}
],
+ "projects-page-title": [
+ {
+ "type": 0,
+ "value": "Projects"
+ }
+ ],
"python-powered": [
{
"type": 0,
@@ -1427,6 +1755,18 @@
"value": "참조"
}
],
+ "rename-project-action": [
+ {
+ "type": 0,
+ "value": "Rename"
+ }
+ ],
+ "rename-project-heading": [
+ {
+ "type": 0,
+ "value": "Rename project"
+ }
+ ],
"replace-action-label": [
{
"type": 0,
@@ -1531,6 +1871,26 @@
"value": "찾기"
}
],
+ "select-project-action": [
+ {
+ "type": 0,
+ "value": "Select project ‘"
+ },
+ {
+ "type": 1,
+ "value": "name"
+ },
+ {
+ "type": 0,
+ "value": "’"
+ }
+ ],
+ "selection-actions-group": [
+ {
+ "type": 0,
+ "value": "Actions for selected projects"
+ }
+ ],
"send-action": [
{
"type": 0,
@@ -2247,6 +2607,42 @@
"value": "소프트웨어 버전"
}
],
+ "sort-option-last-modified": [
+ {
+ "type": 0,
+ "value": "Last modified"
+ }
+ ],
+ "sort-option-name": [
+ {
+ "type": 0,
+ "value": "Name"
+ }
+ ],
+ "sort-option-relevance": [
+ {
+ "type": 0,
+ "value": "Relevance"
+ }
+ ],
+ "sort-order-ascending-label": [
+ {
+ "type": 0,
+ "value": "Sort ascending"
+ }
+ ],
+ "sort-order-descending-label": [
+ {
+ "type": 0,
+ "value": "Sort descending"
+ }
+ ],
+ "sort-select-label": [
+ {
+ "type": 0,
+ "value": "Sort projects by"
+ }
+ ],
"start-coding-action": [
{
"type": 0,
@@ -2259,6 +2655,18 @@
"value": "지원"
}
],
+ "teacher-resources-row-carousel": [
+ {
+ "type": 0,
+ "value": "Teacher resources"
+ }
+ ],
+ "teacher-resources-row-title": [
+ {
+ "type": 0,
+ "value": "Teacher resources"
+ }
+ ],
"terms-of-use": [
{
"type": 0,
@@ -2367,6 +2775,12 @@
"value": "저장된 hex 파일을 micro:bit으로 전송"
}
],
+ "troubleshooting-resource-title": [
+ {
+ "type": 0,
+ "value": "Troubleshooting"
+ }
+ ],
"try-again-action": [
{
"type": 0,
@@ -2439,6 +2853,12 @@
"value": "사용자 가이드"
}
],
+ "view-all-projects": [
+ {
+ "type": 0,
+ "value": "View all projects"
+ }
+ ],
"visit-dot-org": [
{
"type": 0,
diff --git a/src/messages/ui.lol.json b/src/messages/ui.lol.json
index 2f64ccfc4..4517d6c6a 100644
--- a/src/messages/ui.lol.json
+++ b/src/messages/ui.lol.json
@@ -41,6 +41,24 @@
"value": "crwdns364038:0crwdne364038:0"
}
],
+ "accessibility-resource-title": [
+ {
+ "type": 0,
+ "value": "Accessibility"
+ }
+ ],
+ "add-files-action": [
+ {
+ "type": 0,
+ "value": "Add file(s)"
+ }
+ ],
+ "add-files-hover": [
+ {
+ "type": 0,
+ "value": "Add files to this project"
+ }
+ ],
"added-change": [
{
"type": 0,
@@ -123,6 +141,32 @@
"value": "crwdns331388:0crwdne331388:0"
}
],
+ "carousel-role": [
+ {
+ "type": 0,
+ "value": "carousel"
+ }
+ ],
+ "carousel-slide-label": [
+ {
+ "type": 1,
+ "value": "slideNum"
+ },
+ {
+ "type": 0,
+ "value": " of "
+ },
+ {
+ "type": 1,
+ "value": "totalSlides"
+ }
+ ],
+ "carousel-slide-role": [
+ {
+ "type": 0,
+ "value": "slide"
+ }
+ ],
"change-files": [
{
"type": 0,
@@ -445,12 +489,30 @@
"value": "crwdns331462:0crwdne331462:0"
}
],
+ "create-project-action": [
+ {
+ "type": 0,
+ "value": "Create"
+ }
+ ],
+ "create-project-dialog-heading": [
+ {
+ "type": 0,
+ "value": "Name your project"
+ }
+ ],
"create-python": [
{
"type": 0,
"value": "crwdns331464:0crwdne331464:0"
}
],
+ "createai-taster-lessons-resource-title": [
+ {
+ "type": 0,
+ "value": "Taster lessons"
+ }
+ ],
"created-file": [
{
"type": 0,
@@ -485,6 +547,52 @@
"value": "crwdne331470:0"
}
],
+ "delete-project-action": [
+ {
+ "type": 0,
+ "value": "Delete"
+ }
+ ],
+ "delete-project-confirm-heading": [
+ {
+ "type": 0,
+ "value": "Delete project"
+ }
+ ],
+ "delete-project-confirm-text": [
+ {
+ "type": 0,
+ "value": "Are you sure you want to delete ‘"
+ },
+ {
+ "type": 1,
+ "value": "project"
+ },
+ {
+ "type": 0,
+ "value": "’? This cannot be undone."
+ }
+ ],
+ "delete-projects-confirm-heading": [
+ {
+ "type": 0,
+ "value": "Delete projects"
+ }
+ ],
+ "delete-projects-confirm-text": [
+ {
+ "type": 0,
+ "value": "Are you sure you want to delete "
+ },
+ {
+ "type": 1,
+ "value": "numProjects"
+ },
+ {
+ "type": 0,
+ "value": " projects? This cannot be undone."
+ }
+ ],
"deleted-file": [
{
"type": 0,
@@ -523,6 +631,18 @@
"value": "crwdns331480:0crwdne331480:0"
}
],
+ "duplicate-project-action": [
+ {
+ "type": 0,
+ "value": "Duplicate"
+ }
+ ],
+ "duplicate-project-heading": [
+ {
+ "type": 0,
+ "value": "Name your project"
+ }
+ ],
"edit-file-action": [
{
"type": 0,
@@ -625,6 +745,18 @@
"value": "crwdns331506:0crwdne331506:0"
}
],
+ "files-tab": [
+ {
+ "type": 0,
+ "value": "Files"
+ }
+ ],
+ "files-tab-description": [
+ {
+ "type": 0,
+ "value": "Manage your project files"
+ }
+ ],
"firmware-update-link": [
{
"type": 0,
@@ -643,6 +775,12 @@
"value": "crwdns331512:0crwdne331512:0"
}
],
+ "first-lessons-with-python-resource-title": [
+ {
+ "type": 0,
+ "value": "First lessons with Python and the micro:bit"
+ }
+ ],
"flash-action": [
{
"type": 0,
@@ -691,6 +829,18 @@
"value": "crwdns331528:0crwdne331528:0"
}
],
+ "help-resources-row-carousel": [
+ {
+ "type": 0,
+ "value": "Help and support"
+ }
+ ],
+ "help-resources-row-title": [
+ {
+ "type": 0,
+ "value": "Help and support"
+ }
+ ],
"help-support": [
{
"type": 0,
@@ -727,6 +877,30 @@
"value": "crwdns331540:0crwdne331540:0"
}
],
+ "home-action": [
+ {
+ "type": 0,
+ "value": "Home"
+ }
+ ],
+ "homepage-banner-heading": [
+ {
+ "type": 0,
+ "value": "Code your BBC micro:bit with Python"
+ }
+ ],
+ "homepage-banner-subtitle": [
+ {
+ "type": 0,
+ "value": "Create, edit and flash MicroPython programs to your micro:bit."
+ }
+ ],
+ "homepage-title": [
+ {
+ "type": 0,
+ "value": "micro:bit Python Editor"
+ }
+ ],
"ideas-tab": [
{
"type": 0,
@@ -739,6 +913,12 @@
"value": "crwdns331544:0crwdne331544:0"
}
],
+ "import-file-action": [
+ {
+ "type": 0,
+ "value": "Import"
+ }
+ ],
"insert-code-action": [
{
"type": 0,
@@ -751,6 +931,12 @@
"value": "crwdns331548:0crwdne331548:0"
}
],
+ "learn-more-action": [
+ {
+ "type": 0,
+ "value": "Learn more"
+ }
+ ],
"less-action": [
{
"type": 0,
@@ -897,6 +1083,18 @@
"value": "crwdns331586:0crwdne331586:0"
}
],
+ "my-projects-row-carousel": [
+ {
+ "type": 0,
+ "value": "Your projects"
+ }
+ ],
+ "my-projects-row-title": [
+ {
+ "type": 0,
+ "value": "Your projects"
+ }
+ ],
"name-project": [
{
"type": 0,
@@ -921,12 +1119,24 @@
"value": "crwdns331594:0crwdne331594:0"
}
],
+ "new-project-action": [
+ {
+ "type": 0,
+ "value": "New project"
+ }
+ ],
"next-action": [
{
"type": 0,
"value": "crwdns331596:0crwdne331596:0"
}
],
+ "no-projects": [
+ {
+ "type": 0,
+ "value": "No projects found"
+ }
+ ],
"not-found-checklist-one": [
{
"type": 0,
@@ -993,6 +1203,12 @@
"value": "crwdns331616:0crwdne331616:0"
}
],
+ "open-project-action": [
+ {
+ "type": 0,
+ "value": "Open"
+ }
+ ],
"options": [
{
"type": 0,
@@ -1081,12 +1297,112 @@
"value": "crwdns331638:0crwdne331638:0"
}
],
+ "project-file-count": [
+ {
+ "offset": 0,
+ "options": {
+ "one": {
+ "value": [
+ {
+ "type": 7
+ },
+ {
+ "type": 0,
+ "value": " file"
+ }
+ ]
+ },
+ "other": {
+ "value": [
+ {
+ "type": 7
+ },
+ {
+ "type": 0,
+ "value": " files"
+ }
+ ]
+ }
+ },
+ "pluralType": "cardinal",
+ "type": 6,
+ "value": "count"
+ }
+ ],
"project-header": [
{
"type": 0,
"value": "crwdns331640:0crwdne331640:0"
}
],
+ "project-idea-animated-animals-title": [
+ {
+ "type": 0,
+ "value": "Animated animals"
+ }
+ ],
+ "project-idea-beating-heart-title": [
+ {
+ "type": 0,
+ "value": "Beating heart"
+ }
+ ],
+ "project-idea-emotion-badge-title": [
+ {
+ "type": 0,
+ "value": "Emotion badge"
+ }
+ ],
+ "project-idea-flashing-emotions-title": [
+ {
+ "type": 0,
+ "value": "Flashing emotions"
+ }
+ ],
+ "project-idea-get-silly-title": [
+ {
+ "type": 0,
+ "value": "Get silly"
+ }
+ ],
+ "project-idea-heart-title": [
+ {
+ "type": 0,
+ "value": "Heart"
+ }
+ ],
+ "project-ideas-row-carousel": [
+ {
+ "type": 0,
+ "value": "Project ideas"
+ }
+ ],
+ "project-ideas-row-title": [
+ {
+ "type": 0,
+ "value": "Project ideas"
+ }
+ ],
+ "project-loaded": [
+ {
+ "type": 0,
+ "value": "Project loaded"
+ }
+ ],
+ "project-menu-action": [
+ {
+ "type": 0,
+ "value": "Actions for project ‘"
+ },
+ {
+ "type": 1,
+ "value": "name"
+ },
+ {
+ "type": 0,
+ "value": "’"
+ }
+ ],
"project-name": [
{
"type": 0,
@@ -1099,6 +1415,12 @@
"value": "crwdns331644:0crwdne331644:0"
}
],
+ "project-skip-to-toolbar": [
+ {
+ "type": 0,
+ "value": "Skip to selection actions"
+ }
+ ],
"project-tab": [
{
"type": 0,
@@ -1111,6 +1433,12 @@
"value": "crwdns331648:0crwdne331648:0"
}
],
+ "projects-page-title": [
+ {
+ "type": 0,
+ "value": "Projects"
+ }
+ ],
"python-powered": [
{
"type": 0,
@@ -1153,6 +1481,18 @@
"value": "crwdns331662:0crwdne331662:0"
}
],
+ "rename-project-action": [
+ {
+ "type": 0,
+ "value": "Rename"
+ }
+ ],
+ "rename-project-heading": [
+ {
+ "type": 0,
+ "value": "Rename project"
+ }
+ ],
"replace-action-label": [
{
"type": 0,
@@ -1235,6 +1575,26 @@
"value": "crwdns331684:0crwdne331684:0"
}
],
+ "select-project-action": [
+ {
+ "type": 0,
+ "value": "Select project ‘"
+ },
+ {
+ "type": 1,
+ "value": "name"
+ },
+ {
+ "type": 0,
+ "value": "’"
+ }
+ ],
+ "selection-actions-group": [
+ {
+ "type": 0,
+ "value": "Actions for selected projects"
+ }
+ ],
"send-action": [
{
"type": 0,
@@ -1873,6 +2233,42 @@
"value": "crwdns331742:0crwdne331742:0"
}
],
+ "sort-option-last-modified": [
+ {
+ "type": 0,
+ "value": "Last modified"
+ }
+ ],
+ "sort-option-name": [
+ {
+ "type": 0,
+ "value": "Name"
+ }
+ ],
+ "sort-option-relevance": [
+ {
+ "type": 0,
+ "value": "Relevance"
+ }
+ ],
+ "sort-order-ascending-label": [
+ {
+ "type": 0,
+ "value": "Sort ascending"
+ }
+ ],
+ "sort-order-descending-label": [
+ {
+ "type": 0,
+ "value": "Sort descending"
+ }
+ ],
+ "sort-select-label": [
+ {
+ "type": 0,
+ "value": "Sort projects by"
+ }
+ ],
"start-coding-action": [
{
"type": 0,
@@ -1885,6 +2281,18 @@
"value": "crwdns331746:0crwdne331746:0"
}
],
+ "teacher-resources-row-carousel": [
+ {
+ "type": 0,
+ "value": "Teacher resources"
+ }
+ ],
+ "teacher-resources-row-title": [
+ {
+ "type": 0,
+ "value": "Teacher resources"
+ }
+ ],
"terms-of-use": [
{
"type": 0,
@@ -1953,6 +2361,12 @@
"value": "crwdns331768:0crwdne331768:0"
}
],
+ "troubleshooting-resource-title": [
+ {
+ "type": 0,
+ "value": "Troubleshooting"
+ }
+ ],
"try-again-action": [
{
"type": 0,
@@ -2009,6 +2423,12 @@
"value": "crwdns364040:0crwdne364040:0"
}
],
+ "view-all-projects": [
+ {
+ "type": 0,
+ "value": "View all projects"
+ }
+ ],
"visit-dot-org": [
{
"type": 0,
diff --git a/src/messages/ui.nl.json b/src/messages/ui.nl.json
index 6364ad896..5c13fff70 100644
--- a/src/messages/ui.nl.json
+++ b/src/messages/ui.nl.json
@@ -65,6 +65,24 @@
"value": "Toegankelijkheid"
}
],
+ "accessibility-resource-title": [
+ {
+ "type": 0,
+ "value": "Accessibility"
+ }
+ ],
+ "add-files-action": [
+ {
+ "type": 0,
+ "value": "Add file(s)"
+ }
+ ],
+ "add-files-hover": [
+ {
+ "type": 0,
+ "value": "Add files to this project"
+ }
+ ],
"added-change": [
{
"type": 0,
@@ -165,6 +183,32 @@
"value": "Annuleren"
}
],
+ "carousel-role": [
+ {
+ "type": 0,
+ "value": "carousel"
+ }
+ ],
+ "carousel-slide-label": [
+ {
+ "type": 1,
+ "value": "slideNum"
+ },
+ {
+ "type": 0,
+ "value": " of "
+ },
+ {
+ "type": 1,
+ "value": "totalSlides"
+ }
+ ],
+ "carousel-slide-role": [
+ {
+ "type": 0,
+ "value": "slide"
+ }
+ ],
"change-files": [
{
"type": 0,
@@ -467,12 +511,30 @@
"value": "Bestand aanmaken"
}
],
+ "create-project-action": [
+ {
+ "type": 0,
+ "value": "Create"
+ }
+ ],
+ "create-project-dialog-heading": [
+ {
+ "type": 0,
+ "value": "Name your project"
+ }
+ ],
"create-python": [
{
"type": 0,
"value": "Maak een nieuw Python bestand aan in dit project"
}
],
+ "createai-taster-lessons-resource-title": [
+ {
+ "type": 0,
+ "value": "Taster lessons"
+ }
+ ],
"created-file": [
{
"type": 0,
@@ -499,6 +561,52 @@
"value": "name"
}
],
+ "delete-project-action": [
+ {
+ "type": 0,
+ "value": "Delete"
+ }
+ ],
+ "delete-project-confirm-heading": [
+ {
+ "type": 0,
+ "value": "Delete project"
+ }
+ ],
+ "delete-project-confirm-text": [
+ {
+ "type": 0,
+ "value": "Are you sure you want to delete ‘"
+ },
+ {
+ "type": 1,
+ "value": "project"
+ },
+ {
+ "type": 0,
+ "value": "’? This cannot be undone."
+ }
+ ],
+ "delete-projects-confirm-heading": [
+ {
+ "type": 0,
+ "value": "Delete projects"
+ }
+ ],
+ "delete-projects-confirm-text": [
+ {
+ "type": 0,
+ "value": "Are you sure you want to delete "
+ },
+ {
+ "type": 1,
+ "value": "numProjects"
+ },
+ {
+ "type": 0,
+ "value": " projects? This cannot be undone."
+ }
+ ],
"deleted-file": [
{
"type": 0,
@@ -533,6 +641,18 @@
"value": "Slepen en neerzetten"
}
],
+ "duplicate-project-action": [
+ {
+ "type": 0,
+ "value": "Duplicate"
+ }
+ ],
+ "duplicate-project-heading": [
+ {
+ "type": 0,
+ "value": "Name your project"
+ }
+ ],
"edit-file-action": [
{
"type": 1,
@@ -623,6 +743,18 @@
"value": "De naam mag geen spaties bevatten"
}
],
+ "files-tab": [
+ {
+ "type": 0,
+ "value": "Files"
+ }
+ ],
+ "files-tab-description": [
+ {
+ "type": 0,
+ "value": "Manage your project files"
+ }
+ ],
"firmware-update-link": [
{
"type": 0,
@@ -655,6 +787,12 @@
"value": "Firmware update vereist"
}
],
+ "first-lessons-with-python-resource-title": [
+ {
+ "type": 0,
+ "value": "First lessons with Python and the micro:bit"
+ }
+ ],
"flash-action": [
{
"type": 0,
@@ -713,6 +851,18 @@
"value": "Help"
}
],
+ "help-resources-row-carousel": [
+ {
+ "type": 0,
+ "value": "Help and support"
+ }
+ ],
+ "help-resources-row-title": [
+ {
+ "type": 0,
+ "value": "Help and support"
+ }
+ ],
"help-support": [
{
"type": 0,
@@ -749,6 +899,30 @@
"value": "Eenvoudig"
}
],
+ "home-action": [
+ {
+ "type": 0,
+ "value": "Home"
+ }
+ ],
+ "homepage-banner-heading": [
+ {
+ "type": 0,
+ "value": "Code your BBC micro:bit with Python"
+ }
+ ],
+ "homepage-banner-subtitle": [
+ {
+ "type": 0,
+ "value": "Create, edit and flash MicroPython programs to your micro:bit."
+ }
+ ],
+ "homepage-title": [
+ {
+ "type": 0,
+ "value": "micro:bit Python Editor"
+ }
+ ],
"ideas-tab": [
{
"type": 0,
@@ -761,6 +935,12 @@
"value": "Probeer deze projecten uit, verander ze en laat je inspireren"
}
],
+ "import-file-action": [
+ {
+ "type": 0,
+ "value": "Import"
+ }
+ ],
"insert-code-action": [
{
"type": 0,
@@ -773,6 +953,12 @@
"value": "Taal"
}
],
+ "learn-more-action": [
+ {
+ "type": 0,
+ "value": "Learn more"
+ }
+ ],
"less-action": [
{
"type": 0,
@@ -1047,6 +1233,18 @@
"value": "Waarschuwing: Alleen main.py gedownload"
}
],
+ "my-projects-row-carousel": [
+ {
+ "type": 0,
+ "value": "Your projects"
+ }
+ ],
+ "my-projects-row-title": [
+ {
+ "type": 0,
+ "value": "Your projects"
+ }
+ ],
"name-project": [
{
"type": 0,
@@ -1085,12 +1283,24 @@
"value": " extensie voor je toevoegen."
}
],
+ "new-project-action": [
+ {
+ "type": 0,
+ "value": "New project"
+ }
+ ],
"next-action": [
{
"type": 0,
"value": "Volgende"
}
],
+ "no-projects": [
+ {
+ "type": 0,
+ "value": "No projects found"
+ }
+ ],
"not-found-checklist-one": [
{
"type": 0,
@@ -1223,6 +1433,12 @@
"value": "Open een hex of Python bestand of voeg andere bestanden toe"
}
],
+ "open-project-action": [
+ {
+ "type": 0,
+ "value": "Open"
+ }
+ ],
"options": [
{
"type": 0,
@@ -1367,12 +1583,112 @@
"value": "Project acties"
}
],
+ "project-file-count": [
+ {
+ "offset": 0,
+ "options": {
+ "one": {
+ "value": [
+ {
+ "type": 7
+ },
+ {
+ "type": 0,
+ "value": " file"
+ }
+ ]
+ },
+ "other": {
+ "value": [
+ {
+ "type": 7
+ },
+ {
+ "type": 0,
+ "value": " files"
+ }
+ ]
+ }
+ },
+ "pluralType": "cardinal",
+ "type": 6,
+ "value": "count"
+ }
+ ],
"project-header": [
{
"type": 0,
"value": "Project koptekst"
}
],
+ "project-idea-animated-animals-title": [
+ {
+ "type": 0,
+ "value": "Animated animals"
+ }
+ ],
+ "project-idea-beating-heart-title": [
+ {
+ "type": 0,
+ "value": "Beating heart"
+ }
+ ],
+ "project-idea-emotion-badge-title": [
+ {
+ "type": 0,
+ "value": "Emotion badge"
+ }
+ ],
+ "project-idea-flashing-emotions-title": [
+ {
+ "type": 0,
+ "value": "Flashing emotions"
+ }
+ ],
+ "project-idea-get-silly-title": [
+ {
+ "type": 0,
+ "value": "Get silly"
+ }
+ ],
+ "project-idea-heart-title": [
+ {
+ "type": 0,
+ "value": "Heart"
+ }
+ ],
+ "project-ideas-row-carousel": [
+ {
+ "type": 0,
+ "value": "Project ideas"
+ }
+ ],
+ "project-ideas-row-title": [
+ {
+ "type": 0,
+ "value": "Project ideas"
+ }
+ ],
+ "project-loaded": [
+ {
+ "type": 0,
+ "value": "Project loaded"
+ }
+ ],
+ "project-menu-action": [
+ {
+ "type": 0,
+ "value": "Actions for project ‘"
+ },
+ {
+ "type": 1,
+ "value": "name"
+ },
+ {
+ "type": 0,
+ "value": "’"
+ }
+ ],
"project-name": [
{
"type": 0,
@@ -1385,6 +1701,12 @@
"value": "De projectnaam kan niet leeg zijn"
}
],
+ "project-skip-to-toolbar": [
+ {
+ "type": 0,
+ "value": "Skip to selection actions"
+ }
+ ],
"project-tab": [
{
"type": 0,
@@ -1397,6 +1719,12 @@
"value": "Bekijk, aanmaken, toevoegen en bewerken van de bestanden in je project"
}
],
+ "projects-page-title": [
+ {
+ "type": 0,
+ "value": "Projects"
+ }
+ ],
"python-powered": [
{
"type": 0,
@@ -1439,6 +1767,18 @@
"value": "Referentie"
}
],
+ "rename-project-action": [
+ {
+ "type": 0,
+ "value": "Rename"
+ }
+ ],
+ "rename-project-heading": [
+ {
+ "type": 0,
+ "value": "Rename project"
+ }
+ ],
"replace-action-label": [
{
"type": 0,
@@ -1546,6 +1886,26 @@
"value": "Zoeken"
}
],
+ "select-project-action": [
+ {
+ "type": 0,
+ "value": "Select project ‘"
+ },
+ {
+ "type": 1,
+ "value": "name"
+ },
+ {
+ "type": 0,
+ "value": "’"
+ }
+ ],
+ "selection-actions-group": [
+ {
+ "type": 0,
+ "value": "Actions for selected projects"
+ }
+ ],
"send-action": [
{
"type": 0,
@@ -2274,6 +2634,42 @@
"value": "Software versies"
}
],
+ "sort-option-last-modified": [
+ {
+ "type": 0,
+ "value": "Last modified"
+ }
+ ],
+ "sort-option-name": [
+ {
+ "type": 0,
+ "value": "Name"
+ }
+ ],
+ "sort-option-relevance": [
+ {
+ "type": 0,
+ "value": "Relevance"
+ }
+ ],
+ "sort-order-ascending-label": [
+ {
+ "type": 0,
+ "value": "Sort ascending"
+ }
+ ],
+ "sort-order-descending-label": [
+ {
+ "type": 0,
+ "value": "Sort descending"
+ }
+ ],
+ "sort-select-label": [
+ {
+ "type": 0,
+ "value": "Sort projects by"
+ }
+ ],
"start-coding-action": [
{
"type": 0,
@@ -2286,6 +2682,18 @@
"value": "Ondersteuning"
}
],
+ "teacher-resources-row-carousel": [
+ {
+ "type": 0,
+ "value": "Teacher resources"
+ }
+ ],
+ "teacher-resources-row-title": [
+ {
+ "type": 0,
+ "value": "Teacher resources"
+ }
+ ],
"terms-of-use": [
{
"type": 0,
@@ -2410,6 +2818,12 @@
"value": "Zet het opgeslagen hex-bestand over naar micro:bit"
}
],
+ "troubleshooting-resource-title": [
+ {
+ "type": 0,
+ "value": "Troubleshooting"
+ }
+ ],
"try-again-action": [
{
"type": 0,
@@ -2486,6 +2900,12 @@
"value": "Gebruikershandleiding"
}
],
+ "view-all-projects": [
+ {
+ "type": 0,
+ "value": "View all projects"
+ }
+ ],
"visit-dot-org": [
{
"type": 0,
diff --git a/src/messages/ui.pl.json b/src/messages/ui.pl.json
index a72d7986d..59550456d 100644
--- a/src/messages/ui.pl.json
+++ b/src/messages/ui.pl.json
@@ -65,6 +65,24 @@
"value": "Dostępność"
}
],
+ "accessibility-resource-title": [
+ {
+ "type": 0,
+ "value": "Accessibility"
+ }
+ ],
+ "add-files-action": [
+ {
+ "type": 0,
+ "value": "Add file(s)"
+ }
+ ],
+ "add-files-hover": [
+ {
+ "type": 0,
+ "value": "Add files to this project"
+ }
+ ],
"added-change": [
{
"type": 0,
@@ -181,6 +199,32 @@
"value": "Anuluj"
}
],
+ "carousel-role": [
+ {
+ "type": 0,
+ "value": "carousel"
+ }
+ ],
+ "carousel-slide-label": [
+ {
+ "type": 1,
+ "value": "slideNum"
+ },
+ {
+ "type": 0,
+ "value": " of "
+ },
+ {
+ "type": 1,
+ "value": "totalSlides"
+ }
+ ],
+ "carousel-slide-role": [
+ {
+ "type": 0,
+ "value": "slide"
+ }
+ ],
"change-files": [
{
"type": 0,
@@ -471,12 +515,30 @@
"value": "Utwórz plik"
}
],
+ "create-project-action": [
+ {
+ "type": 0,
+ "value": "Create"
+ }
+ ],
+ "create-project-dialog-heading": [
+ {
+ "type": 0,
+ "value": "Name your project"
+ }
+ ],
"create-python": [
{
"type": 0,
"value": "Utwórz nowy plik Pythona w tym projekcie"
}
],
+ "createai-taster-lessons-resource-title": [
+ {
+ "type": 0,
+ "value": "Taster lessons"
+ }
+ ],
"created-file": [
{
"type": 0,
@@ -503,6 +565,52 @@
"value": "name"
}
],
+ "delete-project-action": [
+ {
+ "type": 0,
+ "value": "Delete"
+ }
+ ],
+ "delete-project-confirm-heading": [
+ {
+ "type": 0,
+ "value": "Delete project"
+ }
+ ],
+ "delete-project-confirm-text": [
+ {
+ "type": 0,
+ "value": "Are you sure you want to delete ‘"
+ },
+ {
+ "type": 1,
+ "value": "project"
+ },
+ {
+ "type": 0,
+ "value": "’? This cannot be undone."
+ }
+ ],
+ "delete-projects-confirm-heading": [
+ {
+ "type": 0,
+ "value": "Delete projects"
+ }
+ ],
+ "delete-projects-confirm-text": [
+ {
+ "type": 0,
+ "value": "Are you sure you want to delete "
+ },
+ {
+ "type": 1,
+ "value": "numProjects"
+ },
+ {
+ "type": 0,
+ "value": " projects? This cannot be undone."
+ }
+ ],
"deleted-file": [
{
"type": 0,
@@ -537,6 +645,18 @@
"value": "Przeciągnij i upuść"
}
],
+ "duplicate-project-action": [
+ {
+ "type": 0,
+ "value": "Duplicate"
+ }
+ ],
+ "duplicate-project-heading": [
+ {
+ "type": 0,
+ "value": "Name your project"
+ }
+ ],
"edit-file-action": [
{
"type": 0,
@@ -627,6 +747,18 @@
"value": "Nazwa nie może zawierać spacji"
}
],
+ "files-tab": [
+ {
+ "type": 0,
+ "value": "Files"
+ }
+ ],
+ "files-tab-description": [
+ {
+ "type": 0,
+ "value": "Manage your project files"
+ }
+ ],
"firmware-update-link": [
{
"type": 0,
@@ -659,6 +791,12 @@
"value": "Wymagana jest aktualizacja oprogramowania firmowego"
}
],
+ "first-lessons-with-python-resource-title": [
+ {
+ "type": 0,
+ "value": "First lessons with Python and the micro:bit"
+ }
+ ],
"flash-action": [
{
"type": 0,
@@ -717,6 +855,18 @@
"value": "Pomoc"
}
],
+ "help-resources-row-carousel": [
+ {
+ "type": 0,
+ "value": "Help and support"
+ }
+ ],
+ "help-resources-row-title": [
+ {
+ "type": 0,
+ "value": "Help and support"
+ }
+ ],
"help-support": [
{
"type": 0,
@@ -753,6 +903,30 @@
"value": "Prosty"
}
],
+ "home-action": [
+ {
+ "type": 0,
+ "value": "Home"
+ }
+ ],
+ "homepage-banner-heading": [
+ {
+ "type": 0,
+ "value": "Code your BBC micro:bit with Python"
+ }
+ ],
+ "homepage-banner-subtitle": [
+ {
+ "type": 0,
+ "value": "Create, edit and flash MicroPython programs to your micro:bit."
+ }
+ ],
+ "homepage-title": [
+ {
+ "type": 0,
+ "value": "micro:bit Python Editor"
+ }
+ ],
"ideas-tab": [
{
"type": 0,
@@ -765,6 +939,12 @@
"value": "Wypróbuj te projekty, zmodyfikuj je i poczuj się zainspirowany"
}
],
+ "import-file-action": [
+ {
+ "type": 0,
+ "value": "Import"
+ }
+ ],
"insert-code-action": [
{
"type": 0,
@@ -777,6 +957,12 @@
"value": "Język"
}
],
+ "learn-more-action": [
+ {
+ "type": 0,
+ "value": "Learn more"
+ }
+ ],
"less-action": [
{
"type": 0,
@@ -1083,6 +1269,18 @@
"value": "Ostrzeżenie: pobrano tylko main.py"
}
],
+ "my-projects-row-carousel": [
+ {
+ "type": 0,
+ "value": "Your projects"
+ }
+ ],
+ "my-projects-row-title": [
+ {
+ "type": 0,
+ "value": "Your projects"
+ }
+ ],
"name-project": [
{
"type": 0,
@@ -1121,12 +1319,24 @@
"value": " dla Ciebie."
}
],
+ "new-project-action": [
+ {
+ "type": 0,
+ "value": "New project"
+ }
+ ],
"next-action": [
{
"type": 0,
"value": "Dalej"
}
],
+ "no-projects": [
+ {
+ "type": 0,
+ "value": "No projects found"
+ }
+ ],
"not-found-checklist-one": [
{
"type": 0,
@@ -1259,6 +1469,12 @@
"value": "Otwórz plik hex lub Pythona lub dodaj inne pliki"
}
],
+ "open-project-action": [
+ {
+ "type": 0,
+ "value": "Open"
+ }
+ ],
"options": [
{
"type": 0,
@@ -1403,12 +1619,112 @@
"value": "Działania w projekcie"
}
],
+ "project-file-count": [
+ {
+ "offset": 0,
+ "options": {
+ "one": {
+ "value": [
+ {
+ "type": 7
+ },
+ {
+ "type": 0,
+ "value": " file"
+ }
+ ]
+ },
+ "other": {
+ "value": [
+ {
+ "type": 7
+ },
+ {
+ "type": 0,
+ "value": " files"
+ }
+ ]
+ }
+ },
+ "pluralType": "cardinal",
+ "type": 6,
+ "value": "count"
+ }
+ ],
"project-header": [
{
"type": 0,
"value": "Nagłówek projektu"
}
],
+ "project-idea-animated-animals-title": [
+ {
+ "type": 0,
+ "value": "Animated animals"
+ }
+ ],
+ "project-idea-beating-heart-title": [
+ {
+ "type": 0,
+ "value": "Beating heart"
+ }
+ ],
+ "project-idea-emotion-badge-title": [
+ {
+ "type": 0,
+ "value": "Emotion badge"
+ }
+ ],
+ "project-idea-flashing-emotions-title": [
+ {
+ "type": 0,
+ "value": "Flashing emotions"
+ }
+ ],
+ "project-idea-get-silly-title": [
+ {
+ "type": 0,
+ "value": "Get silly"
+ }
+ ],
+ "project-idea-heart-title": [
+ {
+ "type": 0,
+ "value": "Heart"
+ }
+ ],
+ "project-ideas-row-carousel": [
+ {
+ "type": 0,
+ "value": "Project ideas"
+ }
+ ],
+ "project-ideas-row-title": [
+ {
+ "type": 0,
+ "value": "Project ideas"
+ }
+ ],
+ "project-loaded": [
+ {
+ "type": 0,
+ "value": "Project loaded"
+ }
+ ],
+ "project-menu-action": [
+ {
+ "type": 0,
+ "value": "Actions for project ‘"
+ },
+ {
+ "type": 1,
+ "value": "name"
+ },
+ {
+ "type": 0,
+ "value": "’"
+ }
+ ],
"project-name": [
{
"type": 0,
@@ -1421,6 +1737,12 @@
"value": "Nazwa projektu nie może być pusta"
}
],
+ "project-skip-to-toolbar": [
+ {
+ "type": 0,
+ "value": "Skip to selection actions"
+ }
+ ],
"project-tab": [
{
"type": 0,
@@ -1433,6 +1755,12 @@
"value": "Przejrzyj, utwórz, dodaj i edytuj pliki w projekcie"
}
],
+ "projects-page-title": [
+ {
+ "type": 0,
+ "value": "Projects"
+ }
+ ],
"python-powered": [
{
"type": 0,
@@ -1475,6 +1803,18 @@
"value": "Referencje"
}
],
+ "rename-project-action": [
+ {
+ "type": 0,
+ "value": "Rename"
+ }
+ ],
+ "rename-project-heading": [
+ {
+ "type": 0,
+ "value": "Rename project"
+ }
+ ],
"replace-action-label": [
{
"type": 0,
@@ -1601,6 +1941,26 @@
"value": "Szukaj"
}
],
+ "select-project-action": [
+ {
+ "type": 0,
+ "value": "Select project ‘"
+ },
+ {
+ "type": 1,
+ "value": "name"
+ },
+ {
+ "type": 0,
+ "value": "’"
+ }
+ ],
+ "selection-actions-group": [
+ {
+ "type": 0,
+ "value": "Actions for selected projects"
+ }
+ ],
"send-action": [
{
"type": 0,
@@ -2335,6 +2695,42 @@
"value": "Wersje oprogramowania"
}
],
+ "sort-option-last-modified": [
+ {
+ "type": 0,
+ "value": "Last modified"
+ }
+ ],
+ "sort-option-name": [
+ {
+ "type": 0,
+ "value": "Name"
+ }
+ ],
+ "sort-option-relevance": [
+ {
+ "type": 0,
+ "value": "Relevance"
+ }
+ ],
+ "sort-order-ascending-label": [
+ {
+ "type": 0,
+ "value": "Sort ascending"
+ }
+ ],
+ "sort-order-descending-label": [
+ {
+ "type": 0,
+ "value": "Sort descending"
+ }
+ ],
+ "sort-select-label": [
+ {
+ "type": 0,
+ "value": "Sort projects by"
+ }
+ ],
"start-coding-action": [
{
"type": 0,
@@ -2347,6 +2743,18 @@
"value": "Wsparcie"
}
],
+ "teacher-resources-row-carousel": [
+ {
+ "type": 0,
+ "value": "Teacher resources"
+ }
+ ],
+ "teacher-resources-row-title": [
+ {
+ "type": 0,
+ "value": "Teacher resources"
+ }
+ ],
"terms-of-use": [
{
"type": 0,
@@ -2467,6 +2875,12 @@
"value": "Przenieś zapisany plik hex na micro:bita"
}
],
+ "troubleshooting-resource-title": [
+ {
+ "type": 0,
+ "value": "Troubleshooting"
+ }
+ ],
"try-again-action": [
{
"type": 0,
@@ -2539,6 +2953,12 @@
"value": "Podręcznik użytkownika"
}
],
+ "view-all-projects": [
+ {
+ "type": 0,
+ "value": "View all projects"
+ }
+ ],
"visit-dot-org": [
{
"type": 0,
diff --git a/src/messages/ui.zh-cn.json b/src/messages/ui.zh-cn.json
index d2b9fbd07..0ff968b81 100644
--- a/src/messages/ui.zh-cn.json
+++ b/src/messages/ui.zh-cn.json
@@ -65,6 +65,24 @@
"value": "辅助功能"
}
],
+ "accessibility-resource-title": [
+ {
+ "type": 0,
+ "value": "Accessibility"
+ }
+ ],
+ "add-files-action": [
+ {
+ "type": 0,
+ "value": "Add file(s)"
+ }
+ ],
+ "add-files-hover": [
+ {
+ "type": 0,
+ "value": "Add files to this project"
+ }
+ ],
"added-change": [
{
"type": 0,
@@ -157,6 +175,32 @@
"value": "取消"
}
],
+ "carousel-role": [
+ {
+ "type": 0,
+ "value": "carousel"
+ }
+ ],
+ "carousel-slide-label": [
+ {
+ "type": 1,
+ "value": "slideNum"
+ },
+ {
+ "type": 0,
+ "value": " of "
+ },
+ {
+ "type": 1,
+ "value": "totalSlides"
+ }
+ ],
+ "carousel-slide-role": [
+ {
+ "type": 0,
+ "value": "slide"
+ }
+ ],
"change-files": [
{
"type": 0,
@@ -455,12 +499,30 @@
"value": "创建文件"
}
],
+ "create-project-action": [
+ {
+ "type": 0,
+ "value": "Create"
+ }
+ ],
+ "create-project-dialog-heading": [
+ {
+ "type": 0,
+ "value": "Name your project"
+ }
+ ],
"create-python": [
{
"type": 0,
"value": "在此项目中创建一份新的 Python 文件"
}
],
+ "createai-taster-lessons-resource-title": [
+ {
+ "type": 0,
+ "value": "Taster lessons"
+ }
+ ],
"created-file": [
{
"type": 0,
@@ -487,6 +549,52 @@
"value": "name"
}
],
+ "delete-project-action": [
+ {
+ "type": 0,
+ "value": "Delete"
+ }
+ ],
+ "delete-project-confirm-heading": [
+ {
+ "type": 0,
+ "value": "Delete project"
+ }
+ ],
+ "delete-project-confirm-text": [
+ {
+ "type": 0,
+ "value": "Are you sure you want to delete ‘"
+ },
+ {
+ "type": 1,
+ "value": "project"
+ },
+ {
+ "type": 0,
+ "value": "’? This cannot be undone."
+ }
+ ],
+ "delete-projects-confirm-heading": [
+ {
+ "type": 0,
+ "value": "Delete projects"
+ }
+ ],
+ "delete-projects-confirm-text": [
+ {
+ "type": 0,
+ "value": "Are you sure you want to delete "
+ },
+ {
+ "type": 1,
+ "value": "numProjects"
+ },
+ {
+ "type": 0,
+ "value": " projects? This cannot be undone."
+ }
+ ],
"deleted-file": [
{
"type": 0,
@@ -521,6 +629,18 @@
"value": "拖放"
}
],
+ "duplicate-project-action": [
+ {
+ "type": 0,
+ "value": "Duplicate"
+ }
+ ],
+ "duplicate-project-heading": [
+ {
+ "type": 0,
+ "value": "Name your project"
+ }
+ ],
"edit-file-action": [
{
"type": 0,
@@ -611,6 +731,18 @@
"value": "名称不能包含空格"
}
],
+ "files-tab": [
+ {
+ "type": 0,
+ "value": "Files"
+ }
+ ],
+ "files-tab-description": [
+ {
+ "type": 0,
+ "value": "Manage your project files"
+ }
+ ],
"firmware-update-link": [
{
"type": 0,
@@ -643,6 +775,12 @@
"value": "需要更新固件"
}
],
+ "first-lessons-with-python-resource-title": [
+ {
+ "type": 0,
+ "value": "First lessons with Python and the micro:bit"
+ }
+ ],
"flash-action": [
{
"type": 0,
@@ -701,6 +839,18 @@
"value": "帮助"
}
],
+ "help-resources-row-carousel": [
+ {
+ "type": 0,
+ "value": "Help and support"
+ }
+ ],
+ "help-resources-row-title": [
+ {
+ "type": 0,
+ "value": "Help and support"
+ }
+ ],
"help-support": [
{
"type": 0,
@@ -737,6 +887,30 @@
"value": "简单"
}
],
+ "home-action": [
+ {
+ "type": 0,
+ "value": "Home"
+ }
+ ],
+ "homepage-banner-heading": [
+ {
+ "type": 0,
+ "value": "Code your BBC micro:bit with Python"
+ }
+ ],
+ "homepage-banner-subtitle": [
+ {
+ "type": 0,
+ "value": "Create, edit and flash MicroPython programs to your micro:bit."
+ }
+ ],
+ "homepage-title": [
+ {
+ "type": 0,
+ "value": "micro:bit Python Editor"
+ }
+ ],
"ideas-tab": [
{
"type": 0,
@@ -749,6 +923,12 @@
"value": "尝试这些项目,修改它们并获得灵感"
}
],
+ "import-file-action": [
+ {
+ "type": 0,
+ "value": "Import"
+ }
+ ],
"insert-code-action": [
{
"type": 0,
@@ -761,6 +941,12 @@
"value": "语言"
}
],
+ "learn-more-action": [
+ {
+ "type": 0,
+ "value": "Learn more"
+ }
+ ],
"less-action": [
{
"type": 0,
@@ -1031,6 +1217,18 @@
"value": "警告:只下载了 main.py"
}
],
+ "my-projects-row-carousel": [
+ {
+ "type": 0,
+ "value": "Your projects"
+ }
+ ],
+ "my-projects-row-title": [
+ {
+ "type": 0,
+ "value": "Your projects"
+ }
+ ],
"name-project": [
{
"type": 0,
@@ -1069,12 +1267,24 @@
"value": " 扩展名。"
}
],
+ "new-project-action": [
+ {
+ "type": 0,
+ "value": "New project"
+ }
+ ],
"next-action": [
{
"type": 0,
"value": "下一个"
}
],
+ "no-projects": [
+ {
+ "type": 0,
+ "value": "No projects found"
+ }
+ ],
"not-found-checklist-one": [
{
"type": 0,
@@ -1207,6 +1417,12 @@
"value": "打开一 份 hex 或 Python 文件,或添加其他文件"
}
],
+ "open-project-action": [
+ {
+ "type": 0,
+ "value": "Open"
+ }
+ ],
"options": [
{
"type": 0,
@@ -1351,12 +1567,112 @@
"value": "项目行动"
}
],
+ "project-file-count": [
+ {
+ "offset": 0,
+ "options": {
+ "one": {
+ "value": [
+ {
+ "type": 7
+ },
+ {
+ "type": 0,
+ "value": " file"
+ }
+ ]
+ },
+ "other": {
+ "value": [
+ {
+ "type": 7
+ },
+ {
+ "type": 0,
+ "value": " files"
+ }
+ ]
+ }
+ },
+ "pluralType": "cardinal",
+ "type": 6,
+ "value": "count"
+ }
+ ],
"project-header": [
{
"type": 0,
"value": "项目标题"
}
],
+ "project-idea-animated-animals-title": [
+ {
+ "type": 0,
+ "value": "Animated animals"
+ }
+ ],
+ "project-idea-beating-heart-title": [
+ {
+ "type": 0,
+ "value": "Beating heart"
+ }
+ ],
+ "project-idea-emotion-badge-title": [
+ {
+ "type": 0,
+ "value": "Emotion badge"
+ }
+ ],
+ "project-idea-flashing-emotions-title": [
+ {
+ "type": 0,
+ "value": "Flashing emotions"
+ }
+ ],
+ "project-idea-get-silly-title": [
+ {
+ "type": 0,
+ "value": "Get silly"
+ }
+ ],
+ "project-idea-heart-title": [
+ {
+ "type": 0,
+ "value": "Heart"
+ }
+ ],
+ "project-ideas-row-carousel": [
+ {
+ "type": 0,
+ "value": "Project ideas"
+ }
+ ],
+ "project-ideas-row-title": [
+ {
+ "type": 0,
+ "value": "Project ideas"
+ }
+ ],
+ "project-loaded": [
+ {
+ "type": 0,
+ "value": "Project loaded"
+ }
+ ],
+ "project-menu-action": [
+ {
+ "type": 0,
+ "value": "Actions for project ‘"
+ },
+ {
+ "type": 1,
+ "value": "name"
+ },
+ {
+ "type": 0,
+ "value": "’"
+ }
+ ],
"project-name": [
{
"type": 0,
@@ -1369,6 +1685,12 @@
"value": "项目名称不能为空"
}
],
+ "project-skip-to-toolbar": [
+ {
+ "type": 0,
+ "value": "Skip to selection actions"
+ }
+ ],
"project-tab": [
{
"type": 0,
@@ -1381,6 +1703,12 @@
"value": "查看、创建、添加和编辑您项目中的文件"
}
],
+ "projects-page-title": [
+ {
+ "type": 0,
+ "value": "Projects"
+ }
+ ],
"python-powered": [
{
"type": 0,
@@ -1423,6 +1751,18 @@
"value": "参考"
}
],
+ "rename-project-action": [
+ {
+ "type": 0,
+ "value": "Rename"
+ }
+ ],
+ "rename-project-heading": [
+ {
+ "type": 0,
+ "value": "Rename project"
+ }
+ ],
"replace-action-label": [
{
"type": 0,
@@ -1516,6 +1856,26 @@
"value": "搜索"
}
],
+ "select-project-action": [
+ {
+ "type": 0,
+ "value": "Select project ‘"
+ },
+ {
+ "type": 1,
+ "value": "name"
+ },
+ {
+ "type": 0,
+ "value": "’"
+ }
+ ],
+ "selection-actions-group": [
+ {
+ "type": 0,
+ "value": "Actions for selected projects"
+ }
+ ],
"send-action": [
{
"type": 0,
@@ -2244,6 +2604,42 @@
"value": "软件版本"
}
],
+ "sort-option-last-modified": [
+ {
+ "type": 0,
+ "value": "Last modified"
+ }
+ ],
+ "sort-option-name": [
+ {
+ "type": 0,
+ "value": "Name"
+ }
+ ],
+ "sort-option-relevance": [
+ {
+ "type": 0,
+ "value": "Relevance"
+ }
+ ],
+ "sort-order-ascending-label": [
+ {
+ "type": 0,
+ "value": "Sort ascending"
+ }
+ ],
+ "sort-order-descending-label": [
+ {
+ "type": 0,
+ "value": "Sort descending"
+ }
+ ],
+ "sort-select-label": [
+ {
+ "type": 0,
+ "value": "Sort projects by"
+ }
+ ],
"start-coding-action": [
{
"type": 0,
@@ -2256,6 +2652,18 @@
"value": "帮助"
}
],
+ "teacher-resources-row-carousel": [
+ {
+ "type": 0,
+ "value": "Teacher resources"
+ }
+ ],
+ "teacher-resources-row-title": [
+ {
+ "type": 0,
+ "value": "Teacher resources"
+ }
+ ],
"terms-of-use": [
{
"type": 0,
@@ -2380,6 +2788,12 @@
"value": "将保存的 hex 文件传输到 micro:bit"
}
],
+ "troubleshooting-resource-title": [
+ {
+ "type": 0,
+ "value": "Troubleshooting"
+ }
+ ],
"try-again-action": [
{
"type": 0,
@@ -2452,6 +2866,12 @@
"value": "用户指南"
}
],
+ "view-all-projects": [
+ {
+ "type": 0,
+ "value": "View all projects"
+ }
+ ],
"visit-dot-org": [
{
"type": 0,
diff --git a/src/messages/ui.zh-tw.json b/src/messages/ui.zh-tw.json
index 16a70e617..99dba7493 100644
--- a/src/messages/ui.zh-tw.json
+++ b/src/messages/ui.zh-tw.json
@@ -61,6 +61,24 @@
"value": "無障礙設定"
}
],
+ "accessibility-resource-title": [
+ {
+ "type": 0,
+ "value": "Accessibility"
+ }
+ ],
+ "add-files-action": [
+ {
+ "type": 0,
+ "value": "Add file(s)"
+ }
+ ],
+ "add-files-hover": [
+ {
+ "type": 0,
+ "value": "Add files to this project"
+ }
+ ],
"added-change": [
{
"type": 0,
@@ -153,6 +171,32 @@
"value": "取消"
}
],
+ "carousel-role": [
+ {
+ "type": 0,
+ "value": "carousel"
+ }
+ ],
+ "carousel-slide-label": [
+ {
+ "type": 1,
+ "value": "slideNum"
+ },
+ {
+ "type": 0,
+ "value": " of "
+ },
+ {
+ "type": 1,
+ "value": "totalSlides"
+ }
+ ],
+ "carousel-slide-role": [
+ {
+ "type": 0,
+ "value": "slide"
+ }
+ ],
"change-files": [
{
"type": 0,
@@ -451,12 +495,30 @@
"value": "建立檔案"
}
],
+ "create-project-action": [
+ {
+ "type": 0,
+ "value": "Create"
+ }
+ ],
+ "create-project-dialog-heading": [
+ {
+ "type": 0,
+ "value": "Name your project"
+ }
+ ],
"create-python": [
{
"type": 0,
"value": "在本專案中建立新的 Python 檔案"
}
],
+ "createai-taster-lessons-resource-title": [
+ {
+ "type": 0,
+ "value": "Taster lessons"
+ }
+ ],
"created-file": [
{
"type": 0,
@@ -483,6 +545,52 @@
"value": "name"
}
],
+ "delete-project-action": [
+ {
+ "type": 0,
+ "value": "Delete"
+ }
+ ],
+ "delete-project-confirm-heading": [
+ {
+ "type": 0,
+ "value": "Delete project"
+ }
+ ],
+ "delete-project-confirm-text": [
+ {
+ "type": 0,
+ "value": "Are you sure you want to delete ‘"
+ },
+ {
+ "type": 1,
+ "value": "project"
+ },
+ {
+ "type": 0,
+ "value": "’? This cannot be undone."
+ }
+ ],
+ "delete-projects-confirm-heading": [
+ {
+ "type": 0,
+ "value": "Delete projects"
+ }
+ ],
+ "delete-projects-confirm-text": [
+ {
+ "type": 0,
+ "value": "Are you sure you want to delete "
+ },
+ {
+ "type": 1,
+ "value": "numProjects"
+ },
+ {
+ "type": 0,
+ "value": " projects? This cannot be undone."
+ }
+ ],
"deleted-file": [
{
"type": 0,
@@ -517,6 +625,18 @@
"value": "拖放"
}
],
+ "duplicate-project-action": [
+ {
+ "type": 0,
+ "value": "Duplicate"
+ }
+ ],
+ "duplicate-project-heading": [
+ {
+ "type": 0,
+ "value": "Name your project"
+ }
+ ],
"edit-file-action": [
{
"type": 0,
@@ -607,6 +727,18 @@
"value": "名稱不能包含空格"
}
],
+ "files-tab": [
+ {
+ "type": 0,
+ "value": "Files"
+ }
+ ],
+ "files-tab-description": [
+ {
+ "type": 0,
+ "value": "Manage your project files"
+ }
+ ],
"firmware-update-link": [
{
"type": 0,
@@ -639,6 +771,12 @@
"value": "韌體需要更新"
}
],
+ "first-lessons-with-python-resource-title": [
+ {
+ "type": 0,
+ "value": "First lessons with Python and the micro:bit"
+ }
+ ],
"flash-action": [
{
"type": 0,
@@ -697,6 +835,18 @@
"value": "幫助"
}
],
+ "help-resources-row-carousel": [
+ {
+ "type": 0,
+ "value": "Help and support"
+ }
+ ],
+ "help-resources-row-title": [
+ {
+ "type": 0,
+ "value": "Help and support"
+ }
+ ],
"help-support": [
{
"type": 0,
@@ -733,6 +883,30 @@
"value": "簡單"
}
],
+ "home-action": [
+ {
+ "type": 0,
+ "value": "Home"
+ }
+ ],
+ "homepage-banner-heading": [
+ {
+ "type": 0,
+ "value": "Code your BBC micro:bit with Python"
+ }
+ ],
+ "homepage-banner-subtitle": [
+ {
+ "type": 0,
+ "value": "Create, edit and flash MicroPython programs to your micro:bit."
+ }
+ ],
+ "homepage-title": [
+ {
+ "type": 0,
+ "value": "micro:bit Python Editor"
+ }
+ ],
"ideas-tab": [
{
"type": 0,
@@ -745,6 +919,12 @@
"value": "嘗試這些專案,進行修改並獲得靈感"
}
],
+ "import-file-action": [
+ {
+ "type": 0,
+ "value": "Import"
+ }
+ ],
"insert-code-action": [
{
"type": 0,
@@ -757,6 +937,12 @@
"value": "語言"
}
],
+ "learn-more-action": [
+ {
+ "type": 0,
+ "value": "Learn more"
+ }
+ ],
"less-action": [
{
"type": 0,
@@ -1027,6 +1213,18 @@
"value": "警告:只下載了 main.py"
}
],
+ "my-projects-row-carousel": [
+ {
+ "type": 0,
+ "value": "Your projects"
+ }
+ ],
+ "my-projects-row-title": [
+ {
+ "type": 0,
+ "value": "Your projects"
+ }
+ ],
"name-project": [
{
"type": 0,
@@ -1065,12 +1263,24 @@
"value": " 副檔名。"
}
],
+ "new-project-action": [
+ {
+ "type": 0,
+ "value": "New project"
+ }
+ ],
"next-action": [
{
"type": 0,
"value": "下一個"
}
],
+ "no-projects": [
+ {
+ "type": 0,
+ "value": "No projects found"
+ }
+ ],
"not-found-checklist-one": [
{
"type": 0,
@@ -1203,6 +1413,12 @@
"value": "開啟 Hex 或 Python 檔案,或是新增其他檔案"
}
],
+ "open-project-action": [
+ {
+ "type": 0,
+ "value": "Open"
+ }
+ ],
"options": [
{
"type": 0,
@@ -1347,12 +1563,112 @@
"value": "專案動作"
}
],
+ "project-file-count": [
+ {
+ "offset": 0,
+ "options": {
+ "one": {
+ "value": [
+ {
+ "type": 7
+ },
+ {
+ "type": 0,
+ "value": " file"
+ }
+ ]
+ },
+ "other": {
+ "value": [
+ {
+ "type": 7
+ },
+ {
+ "type": 0,
+ "value": " files"
+ }
+ ]
+ }
+ },
+ "pluralType": "cardinal",
+ "type": 6,
+ "value": "count"
+ }
+ ],
"project-header": [
{
"type": 0,
"value": "專案標頭"
}
],
+ "project-idea-animated-animals-title": [
+ {
+ "type": 0,
+ "value": "Animated animals"
+ }
+ ],
+ "project-idea-beating-heart-title": [
+ {
+ "type": 0,
+ "value": "Beating heart"
+ }
+ ],
+ "project-idea-emotion-badge-title": [
+ {
+ "type": 0,
+ "value": "Emotion badge"
+ }
+ ],
+ "project-idea-flashing-emotions-title": [
+ {
+ "type": 0,
+ "value": "Flashing emotions"
+ }
+ ],
+ "project-idea-get-silly-title": [
+ {
+ "type": 0,
+ "value": "Get silly"
+ }
+ ],
+ "project-idea-heart-title": [
+ {
+ "type": 0,
+ "value": "Heart"
+ }
+ ],
+ "project-ideas-row-carousel": [
+ {
+ "type": 0,
+ "value": "Project ideas"
+ }
+ ],
+ "project-ideas-row-title": [
+ {
+ "type": 0,
+ "value": "Project ideas"
+ }
+ ],
+ "project-loaded": [
+ {
+ "type": 0,
+ "value": "Project loaded"
+ }
+ ],
+ "project-menu-action": [
+ {
+ "type": 0,
+ "value": "Actions for project ‘"
+ },
+ {
+ "type": 1,
+ "value": "name"
+ },
+ {
+ "type": 0,
+ "value": "’"
+ }
+ ],
"project-name": [
{
"type": 0,
@@ -1365,6 +1681,12 @@
"value": "專案名稱不可為空白"
}
],
+ "project-skip-to-toolbar": [
+ {
+ "type": 0,
+ "value": "Skip to selection actions"
+ }
+ ],
"project-tab": [
{
"type": 0,
@@ -1377,6 +1699,12 @@
"value": "檢視、建立、新增和編輯專案中的檔案"
}
],
+ "projects-page-title": [
+ {
+ "type": 0,
+ "value": "Projects"
+ }
+ ],
"python-powered": [
{
"type": 0,
@@ -1419,6 +1747,18 @@
"value": "參考資料"
}
],
+ "rename-project-action": [
+ {
+ "type": 0,
+ "value": "Rename"
+ }
+ ],
+ "rename-project-heading": [
+ {
+ "type": 0,
+ "value": "Rename project"
+ }
+ ],
"replace-action-label": [
{
"type": 0,
@@ -1523,6 +1863,26 @@
"value": "搜尋"
}
],
+ "select-project-action": [
+ {
+ "type": 0,
+ "value": "Select project ‘"
+ },
+ {
+ "type": 1,
+ "value": "name"
+ },
+ {
+ "type": 0,
+ "value": "’"
+ }
+ ],
+ "selection-actions-group": [
+ {
+ "type": 0,
+ "value": "Actions for selected projects"
+ }
+ ],
"send-action": [
{
"type": 0,
@@ -2243,6 +2603,42 @@
"value": "軟體版本"
}
],
+ "sort-option-last-modified": [
+ {
+ "type": 0,
+ "value": "Last modified"
+ }
+ ],
+ "sort-option-name": [
+ {
+ "type": 0,
+ "value": "Name"
+ }
+ ],
+ "sort-option-relevance": [
+ {
+ "type": 0,
+ "value": "Relevance"
+ }
+ ],
+ "sort-order-ascending-label": [
+ {
+ "type": 0,
+ "value": "Sort ascending"
+ }
+ ],
+ "sort-order-descending-label": [
+ {
+ "type": 0,
+ "value": "Sort descending"
+ }
+ ],
+ "sort-select-label": [
+ {
+ "type": 0,
+ "value": "Sort projects by"
+ }
+ ],
"start-coding-action": [
{
"type": 0,
@@ -2255,6 +2651,18 @@
"value": "支援"
}
],
+ "teacher-resources-row-carousel": [
+ {
+ "type": 0,
+ "value": "Teacher resources"
+ }
+ ],
+ "teacher-resources-row-title": [
+ {
+ "type": 0,
+ "value": "Teacher resources"
+ }
+ ],
"terms-of-use": [
{
"type": 0,
@@ -2379,6 +2787,12 @@
"value": "將儲存的 HEX 檔案傳輸至 micro:bit"
}
],
+ "troubleshooting-resource-title": [
+ {
+ "type": 0,
+ "value": "Troubleshooting"
+ }
+ ],
"try-again-action": [
{
"type": 0,
@@ -2451,6 +2865,12 @@
"value": "用戶指南 "
}
],
+ "view-all-projects": [
+ {
+ "type": 0,
+ "value": "View all projects"
+ }
+ ],
"visit-dot-org": [
{
"type": 0,
diff --git a/src/project/OpenButton.tsx b/src/project/AddFilesButton.tsx
similarity index 62%
rename from src/project/OpenButton.tsx
rename to src/project/AddFilesButton.tsx
index 16a4e54dd..f68e31328 100644
--- a/src/project/OpenButton.tsx
+++ b/src/project/AddFilesButton.tsx
@@ -3,35 +3,35 @@
*
* SPDX-License-Identifier: MIT
*/
-import { RiFolderOpenLine } from "react-icons/ri";
+import { RiFileAddLine } from "react-icons/ri";
import { useIntl } from "react-intl";
import { CollapsibleButtonComposableProps } from "../common/CollapsibleButton";
import FileInputButton from "../common/FileInputButton";
import { useProjectActions } from "./project-hooks";
-interface OpenButtonProps extends CollapsibleButtonComposableProps {}
+interface AddFilesButtonProps extends CollapsibleButtonComposableProps {}
/**
- * Open HEX button, with an associated input field.
+ * Add file(s) button, with an associated input field.
*/
-const OpenButton = ({ children, ...props }: OpenButtonProps) => {
+const AddFilesButton = ({ children, ...props }: AddFilesButtonProps) => {
const actions = useProjectActions();
const intl = useIntl();
return (
}
+ icon={}
tooltip={intl.formatMessage({
- id: "open-hover",
+ id: "add-files-hover",
})}
/>
);
};
-export default OpenButton;
+export default AddFilesButton;
diff --git a/src/project/FileRow.tsx b/src/project/FileRow.tsx
index 6c1c2a413..f6dfc3639 100644
--- a/src/project/FileRow.tsx
+++ b/src/project/FileRow.tsx
@@ -17,7 +17,7 @@ import {
import { MdMoreVert } from "react-icons/md";
import { RiDeleteBin2Line, RiDownload2Line, RiEdit2Line } from "react-icons/ri";
import { FormattedMessage, useIntl } from "react-intl";
-import { zIndexProjectAreaMenu } from "../common/zIndex";
+import { zIndexFilesAreaMenu } from "../common/zIndex";
import { FileVersion, MAIN_FILE } from "../fs/fs";
import { useProjectActions } from "./project-hooks";
import { isEditableFile } from "./project-utils";
@@ -62,7 +62,7 @@ const FileRow = ({ projectName, value, onEdit, ...props }: FileRowProps) => {
color="grey.800"
/>
-
+
}
isDisabled={!isEditableFile(name)}
diff --git a/src/project/FilesArea.tsx b/src/project/FilesArea.tsx
new file mode 100644
index 000000000..559da7128
--- /dev/null
+++ b/src/project/FilesArea.tsx
@@ -0,0 +1,81 @@
+/**
+ * (c) 2021, Micro:bit Educational Foundation and contributors
+ *
+ * SPDX-License-Identifier: MIT
+ */
+import { Flex, List, ListItem } from "@chakra-ui/react";
+import { useIntl } from "react-intl";
+import AreaHeading from "../common/AreaHeading";
+import HeadedScrollablePanel from "../common/HeadedScrollablePanel";
+import FileRow from "./FileRow";
+import { useProject } from "./project-hooks";
+import { isEditableFile } from "./project-utils";
+import FilesAreaNav from "./FilesAreaNav";
+
+interface FilesAreaProps {
+ selectedFile: string | undefined;
+ onSelectedFileChanged: (name: string) => void;
+}
+
+/**
+ * The main files area, offering access to individual files.
+ */
+const FilesArea = ({ selectedFile, onSelectedFileChanged }: FilesAreaProps) => {
+ const { files, name: projectName } = useProject();
+ const intl = useIntl();
+ return (
+
+
+ }
+ >
+
+ {files.map((f) => {
+ const selected = selectedFile === f.name;
+ const select = () => {
+ if (isEditableFile(f.name)) {
+ onSelectedFileChanged(f.name);
+ }
+ };
+ return (
+
+ {
+ // Clicks on buttons in the row shouldn't select the row.
+ if (e.target === e.currentTarget) {
+ select();
+ }
+ }}
+ height={12}
+ value={f}
+ projectName={projectName}
+ onEdit={select}
+ />
+
+ );
+ })}
+
+
+
+
+ );
+};
+
+export default FilesArea;
diff --git a/src/project/FilesAreaNav.tsx b/src/project/FilesAreaNav.tsx
new file mode 100644
index 000000000..9acfb45c7
--- /dev/null
+++ b/src/project/FilesAreaNav.tsx
@@ -0,0 +1,21 @@
+/**
+ * (c) 2021, Micro:bit Educational Foundation and contributors
+ *
+ * SPDX-License-Identifier: MIT
+ */
+import { BoxProps, Flex, VStack } from "@chakra-ui/react";
+import AddFilesButton from "./AddFilesButton";
+import NewButton from "./NewButton";
+
+const FilesAreaNav = (props: BoxProps) => {
+ return (
+
+
+
+
+
+
+ );
+};
+
+export default FilesAreaNav;
diff --git a/src/project/ProjectActionBar.tsx b/src/project/ProjectActionBar.tsx
index b8ea31873..5432f3173 100644
--- a/src/project/ProjectActionBar.tsx
+++ b/src/project/ProjectActionBar.tsx
@@ -6,7 +6,6 @@
import { BoxProps, HStack, useMediaQuery } from "@chakra-ui/react";
import SendButton from "./SendButton";
import SaveMenuButton from "./SaveMenuButton";
-import OpenButton from "./OpenButton";
import { widthXl } from "../common/media-queries";
import React, { ForwardedRef } from "react";
@@ -31,8 +30,6 @@ const ProjectActionBar = React.forwardRef(
- {/* Min-width to avoid collapsing when out of space. Needs some work on responsiveness of the action bar. */}
-
);
diff --git a/src/project/ProjectArea.tsx b/src/project/ProjectArea.tsx
deleted file mode 100644
index 14049a80c..000000000
--- a/src/project/ProjectArea.tsx
+++ /dev/null
@@ -1,90 +0,0 @@
-/**
- * (c) 2021, Micro:bit Educational Foundation and contributors
- *
- * SPDX-License-Identifier: MIT
- */
-import { Box, List, ListItem, Text, VStack } from "@chakra-ui/react";
-import { FormattedMessage } from "react-intl";
-import FileRow from "./FileRow";
-import { useProject } from "./project-hooks";
-import { isEditableFile } from "./project-utils";
-import ProjectAreaNav from "./ProjectAreaNav";
-import ProjectNameEditable from "./ProjectNameEditable";
-
-interface ProjectAreaProps {
- selectedFile: string | undefined;
- onSelectedFileChanged: (name: string) => void;
-}
-
-/**
- * The main files area, offering access to individual files.
- */
-const ProjectArea = ({
- selectedFile,
- onSelectedFileChanged,
-}: ProjectAreaProps) => {
- const { files, name: projectName } = useProject();
- return (
-
-
-
-
-
-
-
-
-
- {files.map((f) => {
- const selected = selectedFile === f.name;
- const select = () => {
- if (isEditableFile(f.name)) {
- onSelectedFileChanged(f.name);
- }
- };
- return (
-
- {
- // Clicks on buttons in the row shouldn't select the row.
- if (e.target === e.currentTarget) {
- select();
- }
- }}
- height={12}
- value={f}
- projectName={projectName}
- onEdit={select}
- />
-
- );
- })}
-
-
-
- );
-};
-
-export default ProjectArea;
diff --git a/src/project/ProjectAreaNav.tsx b/src/project/ProjectAreaNav.tsx
deleted file mode 100644
index b7eaac00d..000000000
--- a/src/project/ProjectAreaNav.tsx
+++ /dev/null
@@ -1,25 +0,0 @@
-/**
- * (c) 2021, Micro:bit Educational Foundation and contributors
- *
- * SPDX-License-Identifier: MIT
- */
-import { Box, BoxProps, Flex, VStack } from "@chakra-ui/react";
-import NewButton from "./NewButton";
-import OpenButton from "./OpenButton";
-import ResetButton from "./ResetButton";
-
-const ProjectAreaNav = (props: BoxProps) => {
- return (
-
-
-
-
-
-
-
-
-
- );
-};
-
-export default ProjectAreaNav;
diff --git a/src/project/ProjectDropTarget.tsx b/src/project/ProjectDropTarget.tsx
index df16d868b..7ec227658 100644
--- a/src/project/ProjectDropTarget.tsx
+++ b/src/project/ProjectDropTarget.tsx
@@ -6,19 +6,19 @@
import { BoxProps } from "@chakra-ui/react";
import { useCallback } from "react";
import FileDropTarget from "../common/FileDropTarget";
-import { useProjectActions } from "./project-hooks";
+import { useImportProject } from "./use-import-project";
interface ProjectDropTargetProps extends BoxProps {
children: React.ReactElement;
}
const ProjectDropTarget = ({ children, ...props }: ProjectDropTargetProps) => {
- const actions = useProjectActions();
+ const importProject = useImportProject();
const handleDrop = useCallback(
(files: File[]) => {
- actions.load(files, "drop-load");
+ void importProject(files, "drop-load");
},
- [actions]
+ [importProject]
);
return (
+ window.sessionStorage.getItem(CURRENT_PROJECT_KEY) ?? undefined;
+
+const setStoredCurrentProjectId = (id: string | undefined) => {
+ if (id) {
+ window.sessionStorage.setItem(CURRENT_PROJECT_KEY, id);
+ } else {
+ window.sessionStorage.removeItem(CURRENT_PROJECT_KEY);
+ }
+};
+
+/**
+ * A stable serialization of a project's syncable content, used to detect
+ * whether the file system state actually differs from what is stored. This
+ * lets autosave skip no-op writes and, crucially, stops a cross-tab reload
+ * from bouncing back out as a fresh change.
+ */
+const serializeProject = (
+ name: string | undefined,
+ files: Record
+): string => {
+ const keys = Object.keys(files).sort();
+ return JSON.stringify({
+ name: name ?? null,
+ files: keys.map((k) => [k, files[k]]),
+ });
+};
+
+export interface ProjectsContextValue {
+ /** All projects in the library, most recently modified first. */
+ projects: ProjectRecord[];
+ /** True until the initial load from IndexedDB has completed. */
+ loading: boolean;
+ /** The id of the project currently persisted as "open" (session scoped). */
+ currentProjectId: string | undefined;
+ /** The id of the project currently loaded into the editor, if any. */
+ loadedProjectId: string | undefined;
+ /** Reload the project list from storage. */
+ refresh: () => Promise;
+ /** Create a new project, load it into the editor and return its id. */
+ createProject: (name: string) => Promise;
+ /**
+ * Create a new project whose contents come from a single file-system
+ * mutation (e.g. loading a hex), and load it into the editor.
+ *
+ * Unlike {@link createProject} this performs exactly one file-system change,
+ * so the editor transitions straight from the previous project to the
+ * imported one with no intermediate "default project" flash. The previously
+ * open project is left untouched. Rejects (rolling back the new project) if
+ * `populateFs` throws.
+ *
+ * @param name Fallback project name if the content doesn't specify one.
+ * @param populateFs Replaces the file system with the imported content.
+ */
+ importProject: (
+ name: string,
+ populateFs: () => Promise
+ ) => Promise;
+ /**
+ * Load a project into the editor working copy.
+ * Returns false if the project no longer exists.
+ */
+ openProject: (id: string) => Promise;
+ renameProject: (id: string, name: string) => Promise;
+ duplicateProject: (id: string, name: string) => Promise;
+ deleteProject: (id: string) => Promise;
+}
+
+const ProjectsContext = createContext(
+ undefined
+);
+
+const byTimestampDesc = (a: ProjectRecord, b: ProjectRecord) =>
+ b.timestamp - a.timestamp;
+
+export const ProjectsProvider = ({ children }: { children: ReactNode }) => {
+ const fs = useFileSystem();
+ const intl = useIntl();
+ const [projects, setProjects] = useState([]);
+ const [loading, setLoading] = useState(true);
+ const [currentProjectId, setCurrentProjectId] = useState(
+ getStoredCurrentProjectId
+ );
+ // The project currently loaded into the in-memory file system. Autosave is
+ // only active for this project so that a page load (which initialises the
+ // file system with a default program) can't overwrite a stored project.
+ const [loadedProjectId, setLoadedProjectId] = useState(
+ undefined
+ );
+ // Serialization of the last content we loaded or saved for the loaded
+ // project, used to suppress redundant/echoed autosaves.
+ const lastSyncedRef = useRef<{ id: string; serialized: string } | null>(null);
+ // Shows a full-screen spinner while importing a project (e.g. from a hex).
+ const [importing, setImporting] = useState(false);
+
+ const untitled = intl.formatMessage({ id: "untitled-project" });
+
+ const refresh = useCallback(async () => {
+ const all = await projectsDb.getAll();
+ all.sort(byTimestampDesc);
+ setProjects(all);
+ }, []);
+
+ const setCurrent = useCallback((id: string | undefined) => {
+ setStoredCurrentProjectId(id);
+ setCurrentProjectId(id);
+ }, []);
+
+ const loadIntoFs = useCallback(
+ async (record: ProjectRecord) => {
+ await fs.replaceWithMultipleFiles({
+ files: record.files,
+ projectName: record.name,
+ });
+ lastSyncedRef.current = {
+ id: record.id,
+ serialized: serializeProject(record.name, record.files),
+ };
+ setLoadedProjectId(record.id);
+ },
+ [fs]
+ );
+
+ // Seed / migrate on first load. If the library is empty we migrate any
+ // existing single-project work (held by the file system's session storage)
+ // into IndexedDB as the first project.
+ useEffect(() => {
+ let cancelled = false;
+ (async () => {
+ const all = await projectsDb.getAll();
+ if (all.length === 0) {
+ await fs.initialize();
+ const existing = await fs.getPythonProject();
+ if (Object.keys(existing.files).length > 0) {
+ const record: ProjectRecord = {
+ id: generateId(),
+ name: existing.projectName ?? untitled,
+ files: existing.files,
+ timestamp: Date.now(),
+ };
+ await projectsDb.put(record);
+ }
+ }
+ if (!cancelled) {
+ await refresh();
+ setLoading(false);
+ }
+ })();
+ return () => {
+ cancelled = true;
+ };
+ // Intentionally only run once on mount.
+ // eslint-disable-next-line react-hooks/exhaustive-deps
+ }, []);
+
+ const createProject = useCallback(
+ async (name: string) => {
+ const record: ProjectRecord = {
+ id: generateId(),
+ name,
+ files: { ...defaultInitialProject.files },
+ timestamp: Date.now(),
+ };
+ await projectsDb.put(record);
+ setCurrent(record.id);
+ await loadIntoFs(record);
+ await refresh();
+ postProjectSync({
+ type: ProjectSyncMessageType.ReloadProject,
+ projectIds: [record.id],
+ });
+ return record.id;
+ },
+ [loadIntoFs, refresh, setCurrent]
+ );
+
+ const importProject = useCallback(
+ async (name: string, populateFs: () => Promise) => {
+ const id = generateId();
+ // Point the current/loaded project at the new id *before* mutating the
+ // file system, so autosave targets the new project and can never write
+ // the imported content back over the previously open one.
+ setCurrent(id);
+ setLoadedProjectId(id);
+ lastSyncedRef.current = null;
+ // The overlay hides the file-system transition (previous project ->
+ // imported project) and the navigation that follows.
+ setImporting(true);
+ try {
+ try {
+ await populateFs();
+ } catch (e) {
+ // Roll back: nothing was persisted under this id yet.
+ await projectsDb.delete(id);
+ setLoadedProjectId(undefined);
+ setCurrent(undefined);
+ throw e;
+ }
+ const pythonProject = await fs.getPythonProject();
+ const record: ProjectRecord = {
+ id,
+ name: pythonProject.projectName ?? name,
+ files: pythonProject.files,
+ timestamp: Date.now(),
+ };
+ await projectsDb.put(record);
+ lastSyncedRef.current = {
+ id,
+ serialized: serializeProject(record.name, record.files),
+ };
+ await refresh();
+ postProjectSync({
+ type: ProjectSyncMessageType.ReloadProject,
+ projectIds: [id],
+ });
+ return id;
+ } finally {
+ setImporting(false);
+ }
+ },
+ [fs, refresh, setCurrent]
+ );
+
+ const openProject = useCallback(
+ async (id: string) => {
+ if (loadedProjectId === id) {
+ setCurrent(id);
+ return true;
+ }
+ const record = await projectsDb.get(id);
+ if (!record) {
+ return false;
+ }
+ setCurrent(id);
+ await loadIntoFs(record);
+ // Bump recency. Deliberately not broadcast: it must not cause other tabs
+ // editing the same project to reload and lose in-flight edits.
+ await projectsDb.put({ ...record, timestamp: Date.now() });
+ await refresh();
+ return true;
+ },
+ [loadIntoFs, loadedProjectId, refresh, setCurrent]
+ );
+
+ const renameProject = useCallback(
+ async (id: string, name: string) => {
+ const record = await projectsDb.get(id);
+ if (!record) {
+ return;
+ }
+ await projectsDb.put({ ...record, name, timestamp: Date.now() });
+ if (id === loadedProjectId) {
+ await fs.setProjectName(name);
+ lastSyncedRef.current = {
+ id,
+ serialized: serializeProject(name, record.files),
+ };
+ }
+ await refresh();
+ postProjectSync({
+ type: ProjectSyncMessageType.ReloadProject,
+ projectIds: [id],
+ });
+ },
+ [fs, loadedProjectId, refresh]
+ );
+
+ const duplicateProject = useCallback(
+ async (id: string, name: string) => {
+ const record = await projectsDb.get(id);
+ if (!record) {
+ return id;
+ }
+ const newRecord: ProjectRecord = {
+ id: generateId(),
+ name,
+ files: { ...record.files },
+ timestamp: Date.now(),
+ };
+ await projectsDb.put(newRecord);
+ await refresh();
+ postProjectSync({
+ type: ProjectSyncMessageType.ReloadProject,
+ projectIds: [newRecord.id],
+ });
+ return newRecord.id;
+ },
+ [refresh]
+ );
+
+ const deleteProject = useCallback(
+ async (id: string) => {
+ await projectsDb.delete(id);
+ if (id === currentProjectId) {
+ setCurrent(undefined);
+ }
+ if (id === loadedProjectId) {
+ setLoadedProjectId(undefined);
+ lastSyncedRef.current = null;
+ }
+ await refresh();
+ postProjectSync({
+ type: ProjectSyncMessageType.DeleteProject,
+ projectIds: [id],
+ });
+ },
+ [currentProjectId, loadedProjectId, refresh, setCurrent]
+ );
+
+ // Autosave the currently loaded project back to IndexedDB as it is edited,
+ // and broadcast the change to other tabs.
+ useEffect(() => {
+ if (!loadedProjectId) {
+ return;
+ }
+ const save = debounce(async () => {
+ const pythonProject = await fs.getPythonProject();
+ const serialized = serializeProject(
+ pythonProject.projectName,
+ pythonProject.files
+ );
+ if (
+ lastSyncedRef.current?.id === loadedProjectId &&
+ lastSyncedRef.current.serialized === serialized
+ ) {
+ // No real change (e.g. this edit came from loading a cross-tab update).
+ return;
+ }
+ const existing = await projectsDb.get(loadedProjectId);
+ await projectsDb.put({
+ id: loadedProjectId,
+ name: pythonProject.projectName ?? existing?.name ?? untitled,
+ files: pythonProject.files,
+ timestamp: Date.now(),
+ });
+ lastSyncedRef.current = { id: loadedProjectId, serialized };
+ postProjectSync({
+ type: ProjectSyncMessageType.ReloadProject,
+ projectIds: [loadedProjectId],
+ });
+ }, 1_000);
+ fs.addEventListener("project_updated", save);
+ fs.addEventListener("file_text_updated", save);
+ return () => {
+ fs.removeEventListener("project_updated", save);
+ fs.removeEventListener("file_text_updated", save);
+ save.cancel();
+ };
+ }, [fs, loadedProjectId, untitled]);
+
+ // React to changes broadcast from other tabs.
+ useEffect(() => {
+ return addProjectSyncListener((message) => {
+ void (async () => {
+ // Keep the project library list current everywhere.
+ await refresh();
+ if (!loadedProjectId || !message.projectIds.includes(loadedProjectId)) {
+ return;
+ }
+ if (message.type === ProjectSyncMessageType.ReloadProject) {
+ const record = await projectsDb.get(loadedProjectId);
+ if (record) {
+ // Reloads editor content; dedup ref prevents this echoing back out.
+ await loadIntoFs(record);
+ }
+ } else if (message.type === ProjectSyncMessageType.DeleteProject) {
+ // The open project was deleted elsewhere. Clearing loadedProjectId
+ // makes ProjectGate redirect back to the home page.
+ setLoadedProjectId(undefined);
+ setCurrent(undefined);
+ lastSyncedRef.current = null;
+ }
+ })();
+ });
+ }, [loadIntoFs, loadedProjectId, refresh, setCurrent]);
+
+ const value = useMemo(
+ () => ({
+ projects,
+ loading,
+ currentProjectId,
+ loadedProjectId,
+ refresh,
+ createProject,
+ importProject,
+ openProject,
+ renameProject,
+ duplicateProject,
+ deleteProject,
+ }),
+ [
+ projects,
+ loading,
+ currentProjectId,
+ loadedProjectId,
+ refresh,
+ createProject,
+ importProject,
+ openProject,
+ renameProject,
+ duplicateProject,
+ deleteProject,
+ ]
+ );
+
+ return (
+
+
+ {children}
+
+ );
+};
+
+export const useProjects = (): ProjectsContextValue => {
+ const value = useContext(ProjectsContext);
+ if (!value) {
+ throw new Error("Missing ProjectsProvider");
+ }
+ return value;
+};
+
+export { getStoredCurrentProjectId };
diff --git a/src/project/use-import-project.ts b/src/project/use-import-project.ts
new file mode 100644
index 000000000..2124e30e2
--- /dev/null
+++ b/src/project/use-import-project.ts
@@ -0,0 +1,82 @@
+/**
+ * (c) 2026, Micro:bit Educational Foundation and contributors
+ *
+ * SPDX-License-Identifier: MIT
+ */
+import { isMakeCodeForV1Hex } from "@microbit/microbit-universal-hex";
+import { useCallback } from "react";
+import { useIntl } from "react-intl";
+import useActionFeedback from "../common/use-action-feedback";
+import { useFileSystem } from "../fs/fs-hooks";
+import { getLowercaseFileExtension, readFileAsText } from "../fs/fs-util";
+import { router } from "../router";
+import { createEditorUrl } from "../urls";
+import { LoadType } from "./project-actions";
+import { useProjectActions } from "./project-hooks";
+import { useProjects } from "./projects-hooks";
+
+const isMakeCodeHex = (hex: string): boolean => {
+ try {
+ return isMakeCodeForV1Hex(hex);
+ } catch {
+ return false;
+ }
+};
+
+/**
+ * Returns a handler that imports dropped/selected files.
+ *
+ * A single hex file becomes a brand new project (leaving the currently open
+ * project untouched) and we navigate to the editor. Other files fall back to
+ * the existing load-into-current-project behaviour.
+ */
+export const useImportProject = () => {
+ const intl = useIntl();
+ const fs = useFileSystem();
+ const actions = useProjectActions();
+ const actionFeedback = useActionFeedback();
+ const { importProject } = useProjects();
+
+ return useCallback(
+ async (files: File[], loadType: LoadType = "file-upload") => {
+ if (files.length === 0) {
+ return;
+ }
+ const isSingleHex =
+ files.length === 1 &&
+ getLowercaseFileExtension(files[0].name) === "hex";
+ if (!isSingleHex) {
+ // Non-hex files keep the existing behaviour (load into the open project).
+ void actions.load(files, loadType);
+ return;
+ }
+
+ // A hex creates a new project from its contents. Importing in a single
+ // file-system step (behind the loading overlay) avoids showing the
+ // previous project, then a default project, then the imported one.
+ const file = files[0];
+ const projectName = file.name.replace(/\.hex$/i, "");
+ const hex = await readFileAsText(file);
+ try {
+ await importProject(projectName, () =>
+ fs.replaceWithHexContents(projectName, hex)
+ );
+ void router.navigate(createEditorUrl());
+ actionFeedback.success({
+ title: intl.formatMessage({ id: "project-loaded" }),
+ });
+ } catch (e: any) {
+ actionFeedback.expectedError({
+ title: intl.formatMessage(
+ { id: "load-error-title" },
+ { fileCount: 1 }
+ ),
+ description: isMakeCodeHex(hex)
+ ? intl.formatMessage({ id: "load-error-makecode-info" })
+ : e.message,
+ });
+ }
+ },
+ [actionFeedback, actions, fs, importProject, intl]
+ );
+};
diff --git a/src/router-hooks.tsx b/src/router-hooks.tsx
index 0ccf1bac9..9bb8d5f1c 100644
--- a/src/router-hooks.tsx
+++ b/src/router-hooks.tsx
@@ -1,28 +1,29 @@
/**
- * A simple custom router. We don't have pages as such, but the different UI areas
- * use query parameters to keep some state, for example to allow navigating back from
- * drilling down into the documentation in the side panel or making tab selections.
+ * Editor routing.
*
- * Which UI state is encoded into the URL might be subject to change in future
- * based on user feedback and discussion.
+ * The different UI areas (documentation tabs, drill-down anchors) encode some
+ * of their state in the URL. This used to be a bespoke router; it is now a thin
+ * compatibility layer over react-router so the rest of the app can keep using
+ * the same [state, setState] API.
*
- * (c) 2021-2022, Micro:bit Educational Foundation and contributors
+ * The editor lives under `/project` with tabs at `/project/` and
+ * documentation anchors at `/project//`.
+ *
+ * (c) 2021-2026, Micro:bit Educational Foundation and contributors
*
* SPDX-License-Identifier: MIT
*/
-import {
- createContext,
- ReactNode,
- useCallback,
- useContext,
- useEffect,
- useMemo,
- useState,
-} from "react";
+import { useCallback, useMemo } from "react";
+import { useLocation, useNavigate, useParams } from "react-router-dom";
import { baseUrl } from "./base";
import { useLogging } from "./logging/logging-hooks";
-export type TabName = "api" | "ideas" | "reference" | "project";
+export type TabName = "api" | "ideas" | "reference" | "files";
+
+const tabNames: TabName[] = ["api", "ideas", "reference", "files"];
+
+const isTabName = (value: string | undefined): value is TabName =>
+ !!value && (tabNames as string[]).includes(value);
/**
* An anchor-like navigation used for scroll positions.
@@ -33,8 +34,6 @@ export type TabName = "api" | "ideas" | "reference" | "project";
export interface Anchor {
id: string;
}
-const anchorForParam = (param: string | null): Anchor | undefined =>
- param ? { id: param } : undefined;
export interface RouterState {
tab?: TabName;
@@ -53,85 +52,71 @@ type RouterContextValue = [
(state: RouterState, source?: NavigationSource) => void
];
-const RouterContext = createContext(undefined);
+export const editorBasePath = "/project";
-const parse = (pathname: string): RouterState => {
- pathname = pathname.slice(baseUrl.length);
- if (pathname) {
- const parts = pathname.split("/");
- const tab = parts[0];
- if (
- tab === "api" ||
- tab === "reference" ||
- tab === "ideas" ||
- tab === "project"
- ) {
- return { tab, slug: anchorForParam(parts[1]) };
- }
- }
- return {};
+const buildEditorPath = (state: RouterState): string => {
+ const parts = [state.tab, state.slug?.id].filter(
+ (x): x is string => !!x
+ );
+ return [editorBasePath, ...parts].join("/");
};
+/**
+ * Build a full href (including the app base URL) for a router state.
+ * Used for link targets; navigation itself goes through the router.
+ */
+export const toUrl = (state: RouterState): string =>
+ baseUrl + buildEditorPath(state).replace(/^\//, "");
+
/**
* The full router state.
- * Consider using useRouterParam instead if you only care about one parameter.
+ * Consider using useRouterTabSlug instead if you only care about one parameter.
*
* Updating the state updates the URL.
*
* @return a [state, setState] pair.
*/
export const useRouterState = (): RouterContextValue => {
- const value = useContext(RouterContext);
- if (!value) {
- throw new Error("Missing provider!");
- }
- return value;
-};
+ const params = useParams();
+ const location = useLocation();
+ const navigate = useNavigate();
+ const logging = useLogging();
-export const toUrl = (state: RouterState): string => {
- const parts = [state.tab, state.slug?.id];
- const pathname = baseUrl + parts.filter((x): x is string => !!x).join("/");
- return window.location.toString().split("/", 1)[0] + pathname;
-};
+ const tab = isTabName(params.tab) ? params.tab : undefined;
+ const slugId = params.slug;
+ const focus = (location.state as { focus?: boolean } | null)?.focus ?? false;
+ // Tie identity to location.key so that navigating to the same anchor again
+ // (e.g. clicking the same search result twice) produces a fresh state object
+ // and re-triggers scroll/focus effects, matching the previous behaviour.
+ const state = useMemo(
+ () => ({
+ tab,
+ slug: slugId ? { id: slugId } : undefined,
+ focus,
+ }),
+ // eslint-disable-next-line react-hooks/exhaustive-deps
+ [tab, slugId, focus, location.key]
+ );
-export const RouterProvider = ({ children }: { children: ReactNode }) => {
- const logging = useLogging();
- const [state, setState] = useState(parse(window.location.pathname));
- useEffect(() => {
- // This detects browser navigation but not our programatic changes,
- // so we need to update state there ourselves.
- const listener = (_: PopStateEvent) => {
- const newState = parse(window.location.pathname);
- setState(newState);
- };
- window.addEventListener("popstate", listener);
- return () => {
- window.removeEventListener("popstate", listener);
- };
- }, [setState]);
- const navigate = useCallback(
+ const setState = useCallback(
(newState: RouterState, source?: NavigationSource) => {
if (source) {
- const parts = [newState.tab, newState.slug?.id];
- const message = parts.filter((x): x is string => !!x).join("-");
+ const parts = [newState.tab, newState.slug?.id].filter(
+ (x): x is string => !!x
+ );
logging.event({
type: source,
- message,
+ message: parts.join("-"),
});
}
- const url = toUrl(newState);
- window.history.pushState(newState, "", url);
-
- setState(newState);
+ navigate(buildEditorPath(newState), {
+ state: { focus: newState.focus },
+ });
},
- [logging, setState]
- );
- const value: RouterContextValue = useMemo(() => {
- return [state, navigate];
- }, [state, navigate]);
- return (
- {children}
+ [logging, navigate]
);
+
+ return [state, setState];
};
/**
diff --git a/src/router.tsx b/src/router.tsx
new file mode 100644
index 000000000..ec8772af4
--- /dev/null
+++ b/src/router.tsx
@@ -0,0 +1,22 @@
+/**
+ * (c) 2026, Micro:bit Educational Foundation and contributors
+ *
+ * SPDX-License-Identifier: MIT
+ */
+import { createBrowserRouter } from "react-router-dom";
+import HomePage from "./homepage/HomePage";
+import ProjectsPage from "./homepage/ProjectsPage";
+import { routerBasename } from "./urls";
+import ProjectGate from "./workbench/ProjectGate";
+
+export const router = createBrowserRouter(
+ [
+ { path: "/", element: },
+ { path: "/projects", element: },
+ { path: "/project", element: },
+ { path: "/project/:tab", element: },
+ { path: "/project/:tab/:slug", element: },
+ { path: "*", element: },
+ ],
+ { basename: routerBasename }
+);
diff --git a/src/settings/SettingsMenu.tsx b/src/settings/SettingsMenu.tsx
index 7f6ed1ed3..e5a2f608e 100644
--- a/src/settings/SettingsMenu.tsx
+++ b/src/settings/SettingsMenu.tsx
@@ -26,12 +26,13 @@ import { SettingsDialog } from "./SettingsDialog";
interface SettingsMenuProps extends ThemingProps<"Menu"> {
size?: ThemeTypings["components"]["Button"]["sizes"];
+ fontSize?: string;
}
/**
* The settings button triggers a menu with main and other settings.
*/
-const SettingsMenu = ({ size, ...props }: SettingsMenuProps) => {
+const SettingsMenu = ({ size, fontSize = "xl", ...props }: SettingsMenuProps) => {
const languageDisclosure = useDisclosure();
const intl = useIntl();
const dialogs = useDialogs();
@@ -59,7 +60,7 @@ const SettingsMenu = ({ size, ...props }: SettingsMenuProps) => {
data-testid="settings"
aria-label={intl.formatMessage({ id: "settings" })}
size={size}
- fontSize="xl"
+ fontSize={fontSize}
variant="sidebar"
icon={}
color="white"
diff --git a/src/urls.ts b/src/urls.ts
new file mode 100644
index 000000000..15bb91969
--- /dev/null
+++ b/src/urls.ts
@@ -0,0 +1,16 @@
+/**
+ * Internal app routes (relative to the router basename).
+ *
+ * (c) 2026, Micro:bit Educational Foundation and contributors
+ *
+ * SPDX-License-Identifier: MIT
+ */
+import { baseUrl } from "./base";
+
+/** react-router basename derived from the Vite base URL. */
+export const routerBasename =
+ baseUrl === "/" ? undefined : baseUrl.replace(/\/$/, "");
+
+export const createHomePageUrl = () => "/";
+export const createEditorUrl = () => "/project";
+export const createProjectsPageUrl = () => "/projects";
diff --git a/src/workbench/HelpMenu.tsx b/src/workbench/HelpMenu.tsx
index 45940aec2..adcd9ed04 100644
--- a/src/workbench/HelpMenu.tsx
+++ b/src/workbench/HelpMenu.tsx
@@ -32,12 +32,13 @@ import FeedbackForm from "./FeedbackForm";
interface HelpMenuProps extends ThemingProps<"Menu"> {
size?: ThemeTypings["components"]["Button"]["sizes"];
+ fontSize?: string;
}
/**
* A help button that triggers a drop-down menu with actions.
*/
-const HelpMenu = ({ size, ...props }: HelpMenuProps) => {
+const HelpMenu = ({ size, fontSize = "xl", ...props }: HelpMenuProps) => {
const aboutDialogDisclosure = useDisclosure();
const intl = useIntl();
const dialogs = useDialogs();
@@ -69,7 +70,7 @@ const HelpMenu = ({ size, ...props }: HelpMenuProps) => {
as={IconButton}
aria-label={intl.formatMessage({ id: "help" })}
size={size}
- fontSize="xl"
+ fontSize={fontSize}
variant="sidebar"
icon={}
color="white"
diff --git a/src/workbench/ProjectGate.tsx b/src/workbench/ProjectGate.tsx
new file mode 100644
index 000000000..93ad76812
--- /dev/null
+++ b/src/workbench/ProjectGate.tsx
@@ -0,0 +1,66 @@
+/**
+ * (c) 2026, Micro:bit Educational Foundation and contributors
+ *
+ * SPDX-License-Identifier: MIT
+ */
+import { Flex, Spinner } from "@chakra-ui/react";
+import { useEffect, useRef, useState } from "react";
+import { Navigate } from "react-router-dom";
+import {
+ getStoredCurrentProjectId,
+ useProjects,
+} from "../project/projects-hooks";
+import Workbench from "./Workbench";
+
+type Status = "loading" | "ready" | "missing";
+
+/**
+ * Ensures a project is loaded into the editor before rendering the workbench.
+ *
+ * The "current" project id is held in session storage. If it's missing or no
+ * longer exists we redirect back to the home page.
+ */
+const ProjectGate = () => {
+ const { openProject, loadedProjectId } = useProjects();
+ const openProjectRef = useRef(openProject);
+ openProjectRef.current = openProject;
+ const [status, setStatus] = useState("loading");
+
+ useEffect(() => {
+ let cancelled = false;
+ const id = getStoredCurrentProjectId();
+ if (!id) {
+ setStatus("missing");
+ return;
+ }
+ openProjectRef.current(id).then((ok) => {
+ if (!cancelled) {
+ setStatus(ok ? "ready" : "missing");
+ }
+ });
+ return () => {
+ cancelled = true;
+ };
+ }, []);
+
+ useEffect(() => {
+ // The open project was deleted (possibly from another tab): go home.
+ if (status === "ready" && loadedProjectId === undefined) {
+ setStatus("missing");
+ }
+ }, [status, loadedProjectId]);
+
+ if (status === "missing") {
+ return ;
+ }
+ if (status !== "ready") {
+ return (
+
+
+
+ );
+ }
+ return ;
+};
+
+export default ProjectGate;
diff --git a/src/workbench/SideBar.tsx b/src/workbench/SideBar.tsx
index 93f2b678f..24230c7e8 100644
--- a/src/workbench/SideBar.tsx
+++ b/src/workbench/SideBar.tsx
@@ -25,7 +25,7 @@ import ApiArea from "../documentation/ApiArea";
import IdeasArea from "../documentation/IdeasArea";
import ReferenceArea from "../documentation/ReferenceArea";
import { flags } from "../flags";
-import ProjectArea from "../project/ProjectArea";
+import FilesArea from "../project/FilesArea";
import { TabName, useRouterState } from "../router-hooks";
import SettingsMenu from "../settings/SettingsMenu";
import HelpMenu from "./HelpMenu";
@@ -97,11 +97,11 @@ const SideBar = ({
mb: "auto",
},
{
- id: "project" as const,
- title: intl.formatMessage({ id: "project-tab" }),
+ id: "files" as const,
+ title: intl.formatMessage({ id: "files-tab" }),
icon: VscFiles,
contents: (
-
diff --git a/src/workbench/SideBarHeader.tsx b/src/workbench/SideBarHeader.tsx
index 64335d74a..1a4cf182e 100644
--- a/src/workbench/SideBarHeader.tsx
+++ b/src/workbench/SideBarHeader.tsx
@@ -9,9 +9,7 @@ import {
Container,
Fade,
Flex,
- HStack,
IconButton,
- Link,
Modal,
ModalBody,
ModalContent,
@@ -22,15 +20,14 @@ import { useCallback, useEffect, useRef, useState } from "react";
import { RiCloseLine, RiSearch2Line } from "react-icons/ri";
import { useIntl } from "react-intl";
import CollapsibleButton from "../common/CollapsibleButton";
+import HomeButton from "../common/HomeButton";
import HideSplitViewButton from "../common/SplitView/HideSplitViewButton";
import { useResizeObserverContentRect } from "../common/use-resize-observer";
import { zIndexSidebarHeader } from "../common/zIndex";
-import { useDeployment } from "../deployment";
import { topBarHeight } from "../deployment/misc";
import { supportedSearchLanguages } from "../documentation/search/search.worker";
import { useSearch } from "../documentation/search/search-hooks";
import SearchDialog from "../documentation/search/SearchDialog";
-import { microbitOrgUrl } from "../external-links";
import { useLogging } from "../logging/logging-hooks";
import { RouterState, useRouterState } from "../router-hooks";
import { useSettings } from "../settings/settings";
@@ -51,7 +48,6 @@ const SideBarHeader = ({
}: SideBarHeaderProps) => {
const intl = useIntl();
const logging = useLogging();
- const brand = useDeployment();
const searchModal = useDisclosure();
const { results, query, setQuery } = useSearch();
const [, setRouterState] = useRouterState();
@@ -182,34 +178,19 @@ const SideBarHeader = ({
}
alignItems="center"
justifyContent="space-between"
- pr={4}
+ pr={sidebarShown ? 4 : 0}
transition="height .2s"
position="relative"
>
-
-
-
- {brand.squareLogo}
-
- {!query && sidebarShown && (
-
- {brand.horizontalLogo}
-
- )}
-
-
+
+
{searchAvailable && !query && sidebarShown && (
{
const intl = useIntl();
+ useProjectScopedSelection();
const [maybeInvalidSelection, setSelection] = useSelection();
const { files } = useProject();
const selection = defaultSelection(maybeInvalidSelection, files);
diff --git a/src/workbench/use-selection.tsx b/src/workbench/use-selection.tsx
index 7834787ba..671e84461 100644
--- a/src/workbench/use-selection.tsx
+++ b/src/workbench/use-selection.tsx
@@ -8,10 +8,13 @@ import React, {
ReactNode,
SetStateAction,
useContext,
+ useLayoutEffect,
+ useRef,
useState,
} from "react";
import { MAIN_FILE } from "../fs/fs";
+import { useProjects } from "../project/projects-hooks";
const Selection = React.createContext<
[WorkbenchSelection, Dispatch>] | undefined
>(undefined);
@@ -56,3 +59,30 @@ export const SelectionProvider = ({ children }: { children: ReactNode }) => {
});
return {children};
};
+
+/**
+ * Resets the (global) workbench selection to main.py whenever a different
+ * project becomes active, so switching/loading/creating a project always
+ * opens main.py rather than leaking the previously open file.
+ *
+ * Note: this deliberately does not remember the open file per project. See
+ * team notes if we want to revisit per-project file memory.
+ *
+ * Call once from the workbench.
+ */
+export const useProjectScopedSelection = () => {
+ const { loadedProjectId } = useProjects();
+ const [, setSelection] = useSelection();
+ const activeProjectRef = useRef(undefined);
+
+ // useLayoutEffect (not useEffect) so the reset happens before the browser
+ // paints: reopening a project must not briefly show the previously active
+ // file before switching back to main.py.
+ useLayoutEffect(() => {
+ if (activeProjectRef.current === loadedProjectId) {
+ return;
+ }
+ activeProjectRef.current = loadedProjectId;
+ setSelection({ file: MAIN_FILE, location: { line: undefined } });
+ }, [loadedProjectId, setSelection]);
+};