- Table of Contents + {terms.table_of_contents}

    {chapters.map(chapter => @@ -44,7 +39,7 @@ export const TableOfContents = () => { } : {}} // May have HTML generated from markdown dangerouslySetInnerHTML={{__html: page.title}}/> - {isCurrent && " (current)"} + {isCurrent && ` ${terms.current_page}`} ; } )} diff --git a/frontend/src/book/store.js b/frontend/src/book/store.js index bc2a9324..65a87a47 100644 --- a/frontend/src/book/store.js +++ b/frontend/src/book/store.js @@ -7,6 +7,7 @@ import "firebase/auth"; import "firebase/analytics"; import pagesUrl from "./pages.json.load_by_url" import axios from "axios"; +import * as terms from "../terms.json" const firebaseApp = firebase.initializeApp({ apiKey: "AIzaSyAZmDPaMC92X9YFbS-Mt0p-dKHIg4w48Ow", @@ -37,7 +38,7 @@ const initialState = { previousRoute: "main", pages: { loading_placeholder: { - title: "Loading...", + title: terms.loading_wait, slug: "loading_placeholder", index: 0, steps: [ diff --git a/frontend/src/components/HeaderLoginInfo.jsx b/frontend/src/components/HeaderLoginInfo.jsx index 4c4f7e9d..1db6c938 100644 --- a/frontend/src/components/HeaderLoginInfo.jsx +++ b/frontend/src/components/HeaderLoginInfo.jsx @@ -4,6 +4,7 @@ import StyledFirebaseAuth from "react-firebaseui/StyledFirebaseAuth"; import firebase from "firebase"; import {updateDatabase, updateUserData} from "../book/store"; import Popup from "reactjs-popup"; +import * as terms from "../terms.json" const HeaderLoginInfo = ({ email }) => { return email ? @@ -11,7 +12,7 @@ const HeaderLoginInfo = ({ email }) => { - Login / Sign up + {terms.login_or_sign_up} } modal diff --git a/frontend/src/english_terms.json b/frontend/src/english_terms.json new file mode 100644 index 00000000..ee293545 --- /dev/null +++ b/frontend/src/english_terms.json @@ -0,0 +1,60 @@ +{ + "stop": "Stop", + "run": "Run", + "ask_for_help": "Ask for Help", + "question_wizard": "Question Wizard", + "previous": "Previous", + "next": "Next", + "table_of_contents": "Table of Contents", + "skip_step": "Skip step", + "reverse_step": "Reverse step", + "sign_out": "Sign out", + "settings": "Settings", + "feedback": "Feedback", + "developer_mode": "Developer mode", + "developer_mode_description": "Enables the \"Reverse step\" and \"Skip step\" buttons.", + "loading_wait": "Loading...", + "login_or_sign_up": "Login / Sign up", + "error_traceback":"Error traceback:", + "did_you_mean": "Did you mean...", + "similar_frames_skipped": "Similar frames skipped:", + "report_error": "Report error", + "report_error_instructions": "Oops, something went wrong! Please describe what you were just doing and what steps someone can take to reproduce the problem, then click Submit. Or click Cancel to not send a report.", + "click_for_error_details": "Click for error details", + "give_feedback": "Give feedback", + "feedback_email_placeholder": "Email (optional, publicly visible)", + "title": "Title", + "description": "Description", + "submit": "Submit", + "cancel": "Cancel", + "contact_directly": "Alternatively, you can contact us directly:", + "send_email_to": "Email", + "open_github_issue": "Open an issue on GitHub", + "chat_on_slack": "Chat on Slack", + "copying_solution_not_allowed": "Copying from the hints/solution area is not allowed!", + "get_hint": "Get a hint", + "get_another_hint": "Get another hint", + "show_solution": "Show solution", + "show_unscrambled_solution": "Show unscrambled solution", + "show_shuffled_solution": "Show shuffled solution", + "parsons_solution_instructions": "Above is an example solution with the lines out of order. You can drag them around to reorder them. Finding a correct order is up to you, and we won't will tell you if you get it right. Experimenting and running partial solutions in the editor may help you figure it out. You still need to type a correct solution into the editor and run it to continue.", + "are_you_sure": "Are you sure?", + "yes": "Yes", + "no": "No", + "hidden_solution_instructions": "Above is an example solution, but it's hidden. Click the Reveal button repeatedly to reveal the solution bit by bit. Try to stop when you think you've revealed enough and can fill in the remaining gaps yourself. Then type a solution in the editor and run it. Your solution doesn't have to be the same as the one above.", + "reveal": "Reveal", + "output_prediction_question": "What do you think the result will be?", + "output_prediction_wrong_once": "Oops, that's not right. You can try one more time!", + "output_prediction_wrong_twice": "Sorry, wrong answer. Try again next time!", + "output_prediction_correct": "Correct!", + "output_prediction_error_choice": "Error", + "ok": "OK", + "current_page": "(current)", + "question_wizard_intro": "If you need help, there are many sites like [Stack Overflow](https://stackoverflow.com/) and [reddit](https://www.reddit.com/r/learnpython/) where you can ask questions. This is a tool to help you write a good quality question that is likely to get answers.\n\nEnter and run your code on the right. If you don't have any code because you don't know where to get started, I'm afraid this tool can't help you. You can still ask for help, but it might be good to first read [What types of questions should I avoid asking?](https://stackoverflow.com/help/dont-ask)\n\nIf your question is about servers (e.g. Django or Flask), web requests, databases, or a package that can't be imported here, then this tool won't work. However, just because your current code *involves* those things, that doesn't mean that's what your question is *about*. If you're having a general Python/programming/logic problem, then extract that problem from the other stuff. Python with Django is still Python. If you can't do that, then read [How to create a Minimal, Reproducible Example](https://stackoverflow.com/help/minimal-reproducible-example) before asking your question.", + "question_wizard_expected_output": "Good, now enter the output you expect/want from your program below. What would it show if it worked correctly? If it's not supposed to output anything, then add some `print()` calls to your code so that it would output something useful.\n\nWhen you're done, click 'Run' again to generate your question.", + "give_feedback_instructions": "Tell us what you like or don't like! If you're reporting a bug, give a detailed description of the problem:\n\n- What were you doing before and when the problem occurred?\n- What steps can someone take to reproduce it?\n- What do you observe happening, and what do you expect to happen instead?", + "toc_instructions": "Below are links to different pages in the course. You can start anywhere and go in any order, and your progress on each page will be recorded.\n\nIf you're completely new to programming, or you have doubts, just start at the beginning and click Next as you finish each page.", + "hints_progress": "Shown ${numHints} of ${totalHints} hints", + "repeated_frames_description": "${name} at line ${lineno} (${count} times)", + "copy_warning": "**STOP!**\n\nTry to avoid copy pasting code. You will learn, absorb, and remember better if you type in the code yourself.\n\nWhen copying is appropriate, there will be a button to click to make it easy. If there's no button, try typing.\n\nHaving said that, we're not going to force you. Copy if you really want to." +} diff --git a/frontend/src/shell/TerminalMessage.jsx b/frontend/src/shell/TerminalMessage.jsx index 0d346368..b1d38e41 100644 --- a/frontend/src/shell/TerminalMessage.jsx +++ b/frontend/src/shell/TerminalMessage.jsx @@ -5,6 +5,8 @@ import sourceStyles from './defs/styles/TerminalMessage' import {FontAwesomeIcon} from "@fortawesome/react-fontawesome"; import {faInfoCircle} from "@fortawesome/free-solid-svg-icons"; import Popup from "reactjs-popup"; +import * as terms from "../terms.json" +import _ from "lodash"; const ansi_up = new AnsiUp(); @@ -46,7 +48,7 @@ const Tracebacks = ({data, codeSource}) => { return
    {!simple &&
    - Error traceback: + {terms.error_traceback}
    } { @@ -88,7 +90,7 @@ const Tracebacks = ({data, codeSource}) => { { traceback.didyoumean.length > 0 &&
    - Did you mean... + {terms.did_you_mean}
      { traceback.didyoumean.map((suggestion, suggestionIndex) => @@ -139,15 +141,16 @@ const Frame = ({frame}) =>
    +const repeatedFramesDescription = _.template(terms.repeated_frames_description); const RepeatedFrames = ({data}) =>
    -
    Similar frames skipped:
    +
    {terms.similar_frames_skipped}
      { data.map((item, itemIndex) =>
    • - {`${item.name} at line ${item.lineno} (${item.count} times)`} + {repeatedFramesDescription(item)}
    • ) }
    diff --git a/translations/english.po b/translations/english.po index 8ce39b5f..eeb30da0 100644 --- a/translations/english.po +++ b/translations/english.po @@ -17311,6 +17311,211 @@ msgstr "x3" msgid "code_bits.your_name" msgstr "your_name" +msgid "frontend.are_you_sure" +msgstr "Are you sure?" + +msgid "frontend.ask_for_help" +msgstr "Ask for Help" + +msgid "frontend.cancel" +msgstr "Cancel" + +msgid "frontend.chat_on_slack" +msgstr "Chat on Slack" + +msgid "frontend.click_for_error_details" +msgstr "Click for error details" + +msgid "frontend.contact_directly" +msgstr "Alternatively, you can contact us directly:" + +msgid "frontend.copy_warning" +msgstr "" +"**STOP!**\n" +"\n" +"Try to avoid copy pasting code. You will learn, absorb, and remember better if you type in the code yourself.\n" +"\n" +"When copying is appropriate, there will be a button to click to make it easy. If there's no button, try typing.\n" +"\n" +"Having said that, we're not going to force you. Copy if you really want to." + +msgid "frontend.copying_solution_not_allowed" +msgstr "Copying from the hints/solution area is not allowed!" + +msgid "frontend.current_page" +msgstr "(current)" + +msgid "frontend.description" +msgstr "Description" + +msgid "frontend.developer_mode" +msgstr "Developer mode" + +msgid "frontend.developer_mode_description" +msgstr "Enables the \"Reverse step\" and \"Skip step\" buttons." + +msgid "frontend.did_you_mean" +msgstr "Did you mean..." + +msgid "frontend.error_traceback" +msgstr "Error traceback:" + +msgid "frontend.feedback" +msgstr "Feedback" + +msgid "frontend.feedback_email_placeholder" +msgstr "Email (optional, publicly visible)" + +msgid "frontend.get_another_hint" +msgstr "Get another hint" + +msgid "frontend.get_hint" +msgstr "Get a hint" + +msgid "frontend.give_feedback" +msgstr "Give feedback" + +msgid "frontend.give_feedback_instructions" +msgstr "" +"Tell us what you like or don't like! If you're reporting a bug, give a detailed description of the problem:\n" +"\n" +"- What were you doing before and when the problem occurred?\n" +"- What steps can someone take to reproduce it?\n" +"- What do you observe happening, and what do you expect to happen instead?" + +msgid "frontend.hidden_solution_instructions" +msgstr "" +"Above is an example solution, but it's hidden. Click the Reveal button repeatedly to reveal the solution bit by bit. " +"Try to stop when you think you've revealed enough and can fill in the remaining gaps yourself. Then type a solution in" +" the editor and run it. Your solution doesn't have to be the same as the one above." + +msgid "frontend.hints_progress" +msgstr "Shown ${numHints} of ${totalHints} hints" + +msgid "frontend.loading_wait" +msgstr "Loading..." + +msgid "frontend.login_or_sign_up" +msgstr "Login / Sign up" + +msgid "frontend.next" +msgstr "Next" + +msgid "frontend.no" +msgstr "No" + +msgid "frontend.ok" +msgstr "OK" + +msgid "frontend.open_github_issue" +msgstr "Open an issue on GitHub" + +msgid "frontend.output_prediction_correct" +msgstr "Correct!" + +msgid "frontend.output_prediction_error_choice" +msgstr "Error" + +msgid "frontend.output_prediction_question" +msgstr "What do you think the result will be?" + +msgid "frontend.output_prediction_wrong_once" +msgstr "Oops, that's not right. You can try one more time!" + +msgid "frontend.output_prediction_wrong_twice" +msgstr "Sorry, wrong answer. Try again next time!" + +msgid "frontend.parsons_solution_instructions" +msgstr "" +"Above is an example solution with the lines out of order. You can drag them around to reorder them. Finding a correct " +"order is up to you, and we won't will tell you if you get it right. Experimenting and running partial solutions in the" +" editor may help you figure it out. You still need to type a correct solution into the editor and run it to continue." + +msgid "frontend.previous" +msgstr "Previous" + +msgid "frontend.question_wizard" +msgstr "Question Wizard" + +msgid "frontend.question_wizard_expected_output" +msgstr "" +"Good, now enter the output you expect/want from your program below. What would it show if it worked correctly? If it's not supposed to output anything, then add some `print()` calls to your code so that it would output something useful.\n" +"\n" +"When you're done, click 'Run' again to generate your question." + +msgid "frontend.question_wizard_intro" +msgstr "" +"If you need help, there are many sites like [Stack Overflow](https://stackoverflow.com/) and [reddit](https://www.reddit.com/r/learnpython/) where you can ask questions. This is a tool to help you write a good quality question that is likely to get answers.\n" +"\n" +"Enter and run your code on the right. If you don't have any code because you don't know where to get started, I'm afraid this tool can't help you. You can still ask for help, but it might be good to first read [What types of questions should I avoid asking?](https://stackoverflow.com/help/dont-ask)\n" +"\n" +"If your question is about servers (e.g. Django or Flask), web requests, databases, or a package that can't be imported here, then this tool won't work. However, just because your current code *involves* those things, that doesn't mean that's what your question is *about*. If you're having a general Python/programming/logic problem, then extract that problem from the other stuff. Python with Django is still Python. If you can't do that, then read [How to create a Minimal, Reproducible Example](https://stackoverflow.com/help/minimal-reproducible-example) before asking your question." + +msgid "frontend.repeated_frames_description" +msgstr "${name} at line ${lineno} (${count} times)" + +msgid "frontend.report_error" +msgstr "Report error" + +msgid "frontend.report_error_instructions" +msgstr "" +"Oops, something went wrong! Please describe what you were just doing and what steps someone can take to reproduce the " +"problem, then click Submit. Or click Cancel to not send a report." + +msgid "frontend.reveal" +msgstr "Reveal" + +msgid "frontend.reverse_step" +msgstr "Reverse step" + +msgid "frontend.run" +msgstr "Run" + +msgid "frontend.send_email_to" +msgstr "Email" + +msgid "frontend.settings" +msgstr "Settings" + +msgid "frontend.show_shuffled_solution" +msgstr "Show shuffled solution" + +msgid "frontend.show_solution" +msgstr "Show solution" + +msgid "frontend.show_unscrambled_solution" +msgstr "Show unscrambled solution" + +msgid "frontend.sign_out" +msgstr "Sign out" + +msgid "frontend.similar_frames_skipped" +msgstr "Similar frames skipped:" + +msgid "frontend.skip_step" +msgstr "Skip step" + +msgid "frontend.stop" +msgstr "Stop" + +msgid "frontend.submit" +msgstr "Submit" + +msgid "frontend.table_of_contents" +msgstr "Table of Contents" + +msgid "frontend.title" +msgstr "Title" + +msgid "frontend.toc_instructions" +msgstr "" +"Below are links to different pages in the course. You can start anywhere and go in any order, and your progress on each page will be recorded.\n" +"\n" +"If you're completely new to programming, or you have doubts, just start at the beginning and click Next as you finish each page." + +msgid "frontend.yes" +msgstr "Yes" + msgid "linting_messages.pyflakes.ImportShadowedByLoopVar.message_format" msgstr "" "**Import `{0}` shadowed by loop variable**\n" diff --git a/translations/generate_po_file.py b/translations/generate_po_file.py index 31856bda..e6428949 100644 --- a/translations/generate_po_file.py +++ b/translations/generate_po_file.py @@ -5,7 +5,7 @@ from pathlib import Path from textwrap import indent, dedent -from littleutils import group_by_key +from littleutils import group_by_key, file_to_json from polib import POEntry, POFile from core import linting @@ -13,6 +13,9 @@ from core.text import pages, get_predictions, get_special_messages, load_chapters from core.utils import markdown_codes +this_dir = Path(__file__).parent +frontend_src = this_dir / "../frontend/src" + code_blocks = defaultdict(dict) code_bits = defaultdict(set) page_link = "" @@ -98,6 +101,9 @@ def main(): for chapter in chapters: entry(t.chapter_title(chapter["slug"]), chapter["title"]) + for key, value in file_to_json(frontend_src / "english_terms.json").items(): + entry(f"frontend.{key}", value) + entry( "output_predictions.Error", "Error", @@ -108,8 +114,8 @@ def main(): entry(t.misc_term(key), value) po.sort(key=lambda e: e.msgid) - po.save(str(Path(__file__).parent / "english.po")) - po.save_as_mofile(str(Path(__file__).parent / "locales/en/LC_MESSAGES/futurecoder.mo")) + po.save(str(this_dir / "english.po")) + po.save_as_mofile(str(this_dir / "locales/en/LC_MESSAGES/futurecoder.mo")) t.codes_path.write_text(json.dumps(code_blocks)) diff --git a/translations/locales/en/LC_MESSAGES/futurecoder.mo b/translations/locales/en/LC_MESSAGES/futurecoder.mo index 0a4631539377c95acd18c9a585c049035c0dfb4d..ff477556bd3e667d903106a72c36fbfb8aad9097 100644 GIT binary patch delta 28413 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
    HULCNrGlyn;`eg{g0Poh^4mL+`A{0pVW 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 eI>kFBOCXt?k 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 x#QYiUrtR1Gz1Wr%?LN*rd*6s` Date: Sun, 30 Jan 2022 22:23:49 +0200 Subject: [PATCH 188/730] terms.json --- frontend/src/terms.json | 1 + 1 file changed, 1 insertion(+) create mode 100644 frontend/src/terms.json diff --git a/frontend/src/terms.json b/frontend/src/terms.json new file mode 100644 index 00000000..54831ade --- /dev/null +++ b/frontend/src/terms.json @@ -0,0 +1 @@ +{"stop": "Stop", "run": "Run", "ask_for_help": "Ask for Help", "question_wizard": "Question Wizard", "previous": "Previous", "next": "Next", "table_of_contents": "Table of Contents", "skip_step": "Skip step", "reverse_step": "Reverse step", "sign_out": "Sign out", "settings": "Settings", "feedback": "Feedback", "developer_mode": "Developer mode", "developer_mode_description": "Enables the \"Reverse step\" and \"Skip step\" buttons.", "loading_wait": "Loading...", "login_or_sign_up": "Login / Sign up", "error_traceback": "Error traceback:", "did_you_mean": "Did you mean...", "similar_frames_skipped": "Similar frames skipped:", "report_error": "Report error", "report_error_instructions": "Oops, something went wrong! Please describe what you were just doing and what steps someone can take to reproduce the problem, then click Submit. Or click Cancel to not send a report.", "click_for_error_details": "Click for error details", "give_feedback": "Give feedback", "feedback_email_placeholder": "Email (optional, publicly visible)", "title": "Title", "description": "Description", "submit": "Submit", "cancel": "Cancel", "contact_directly": "Alternatively, you can contact us directly:", "send_email_to": "Email", "open_github_issue": "Open an issue on GitHub", "chat_on_slack": "Chat on Slack", "copying_solution_not_allowed": "Copying from the hints/solution area is not allowed!", "get_hint": "Get a hint", "get_another_hint": "Get another hint", "show_solution": "Show solution", "show_unscrambled_solution": "Show unscrambled solution", "show_shuffled_solution": "Show shuffled solution", "parsons_solution_instructions": "Above is an example solution with the lines out of order. You can drag them around to reorder them. Finding a correct order is up to you, and we won't will tell you if you get it right. Experimenting and running partial solutions in the editor may help you figure it out. You still need to type a correct solution into the editor and run it to continue.", "are_you_sure": "Are you sure?", "yes": "Yes", "no": "No", "hidden_solution_instructions": "Above is an example solution, but it's hidden. Click the Reveal button repeatedly to reveal the solution bit by bit. Try to stop when you think you've revealed enough and can fill in the remaining gaps yourself. Then type a solution in the editor and run it. Your solution doesn't have to be the same as the one above.", "reveal": "Reveal", "output_prediction_question": "What do you think the result will be?", "output_prediction_wrong_once": "Oops, that's not right. You can try one more time!", "output_prediction_wrong_twice": "Sorry, wrong answer. Try again next time!", "output_prediction_correct": "Correct!", "output_prediction_error_choice": "Error", "ok": "OK", "current_page": "(current)", "question_wizard_intro": "

    If you need help, there are many sites like Stack Overflow and reddit where you can ask questions. This is a tool to help you write a good quality question that is likely to get answers.

    \n

    Enter and run your code on the right. If you don't have any code because you don't know where to get started, I'm afraid this tool can't help you. You can still ask for help, but it might be good to first read What types of questions should I avoid asking?

    \n

    If your question is about servers (e.g. Django or Flask), web requests, databases, or a package that can't be imported here, then this tool won't work. However, just because your current code involves those things, that doesn't mean that's what your question is about. If you're having a general Python/programming/logic problem, then extract that problem from the other stuff. Python with Django is still Python. If you can't do that, then read How to create a Minimal, Reproducible Example before asking your question.

    ", "question_wizard_expected_output": "

    Good, now enter the output you expect/want from your program below. What would it show if it worked correctly? If it's not supposed to output anything, then add some print() calls to your code so that it would output something useful.

    \n

    When you're done, click 'Run' again to generate your question.

    ", "give_feedback_instructions": "

    Tell us what you like or don't like! If you're reporting a bug, give a detailed description of the problem:

    \n
      \n
    • What were you doing before and when the problem occurred?
    • \n
    • What steps can someone take to reproduce it?
    • \n
    • What do you observe happening, and what do you expect to happen instead?
    • \n
    ", "toc_instructions": "

    Below are links to different pages in the course. You can start anywhere and go in any order, and your progress on each page will be recorded.

    \n

    If you're completely new to programming, or you have doubts, just start at the beginning and click Next as you finish each page.

    ", "hints_progress": "Shown ${numHints} of ${totalHints} hints", "repeated_frames_description": "${name} at line ${lineno} (${count} times)", "copy_warning": "

    STOP!

    \n

    Try to avoid copy pasting code. You will learn, absorb, and remember better if you type in the code yourself.

    \n

    When copying is appropriate, there will be a button to click to make it easy. If there's no button, try typing.

    \n

    Having said that, we're not going to force you. Copy if you really want to.

    "} \ No newline at end of file From 1a939c82d404dfa279eda2bbfd13064d6a929adf Mon Sep 17 00:00:00 2001 From: Alex Hall Date: Sun, 30 Jan 2022 22:48:33 +0200 Subject: [PATCH 189/730] Make question wizard links open in new tab --- core/generate_static_files.py | 12 +++++-- core/question_wizard.py | 4 +-- core/utils.py | 4 +++ frontend/src/terms.json | 61 ++++++++++++++++++++++++++++++++++- 4 files changed, 75 insertions(+), 6 deletions(-) diff --git a/core/generate_static_files.py b/core/generate_static_files.py index 3d6294f0..a0903bdf 100644 --- a/core/generate_static_files.py +++ b/core/generate_static_files.py @@ -32,7 +32,7 @@ from core.checker import check_entry from core.runner.utils import site_packages from core.text import get_pages, step_test_entries, load_chapters -from core.utils import unwrapped_markdown +from core.utils import unwrapped_markdown, new_tab_links str("import sentry_sdk after core.utils for stubs") import sentry_sdk # noqa imported lazily @@ -87,11 +87,17 @@ def tarfile_filter(tar_info): def frontend_terms(): for key, value in file_to_json(frontend_src / "english_terms.json").items(): translation = t.get(f"frontend.{key}", value) + if "\n" in translation: value = markdown(translation) else: value = unwrapped_markdown(translation) - yield key, value + + result = new_tab_links(value) + if value != result: + assert key.startswith("question_wizard_") + + yield key, result def main(): @@ -100,7 +106,7 @@ def main(): json_to_file(list(load_chapters()), frontend_src / "chapters.json") json_to_file(get_pages(), frontend_src / "book/pages.json.load_by_url") - json_to_file(dict(frontend_terms()), frontend_src / "terms.json") + json_to_file(dict(frontend_terms()), frontend_src / "terms.json", indent=4) birdseye_dest = frontend / "public/birdseye" shutil.rmtree(birdseye_dest, ignore_errors=True) diff --git a/core/question_wizard.py b/core/question_wizard.py index 9e713c10..15a21969 100644 --- a/core/question_wizard.py +++ b/core/question_wizard.py @@ -6,7 +6,7 @@ from littleutils import only from core.linting import lint -from core.utils import highlighted_markdown +from core.utils import highlighted_markdown, new_tab_links def input_messages(input_nodes): @@ -82,5 +82,5 @@ def question_wizard_check(entry, output, runner): else: messages.append(t.Terms.q_wiz_debugger) - messages = [highlighted_markdown(message) for message in messages] + messages = [new_tab_links(highlighted_markdown(message)) for message in messages] return messages diff --git a/core/utils.py b/core/utils.py index f9e2c731..314371ec 100644 --- a/core/utils.py +++ b/core/utils.py @@ -164,6 +164,10 @@ def markdown_codes(text): return highlighted_markdown_and_codes(text)[1] +def new_tab_links(s): + return s.replace("If you need help, there are many sites like Stack Overflow and reddit where you can ask questions. This is a tool to help you write a good quality question that is likely to get answers.

    \n

    Enter and run your code on the right. If you don't have any code because you don't know where to get started, I'm afraid this tool can't help you. You can still ask for help, but it might be good to first read What types of questions should I avoid asking?

    \n

    If your question is about servers (e.g. Django or Flask), web requests, databases, or a package that can't be imported here, then this tool won't work. However, just because your current code involves those things, that doesn't mean that's what your question is about. If you're having a general Python/programming/logic problem, then extract that problem from the other stuff. Python with Django is still Python. If you can't do that, then read How to create a Minimal, Reproducible Example before asking your question.

    ", "question_wizard_expected_output": "

    Good, now enter the output you expect/want from your program below. What would it show if it worked correctly? If it's not supposed to output anything, then add some print() calls to your code so that it would output something useful.

    \n

    When you're done, click 'Run' again to generate your question.

    ", "give_feedback_instructions": "

    Tell us what you like or don't like! If you're reporting a bug, give a detailed description of the problem:

    \n
      \n
    • What were you doing before and when the problem occurred?
    • \n
    • What steps can someone take to reproduce it?
    • \n
    • What do you observe happening, and what do you expect to happen instead?
    • \n
    ", "toc_instructions": "

    Below are links to different pages in the course. You can start anywhere and go in any order, and your progress on each page will be recorded.

    \n

    If you're completely new to programming, or you have doubts, just start at the beginning and click Next as you finish each page.

    ", "hints_progress": "Shown ${numHints} of ${totalHints} hints", "repeated_frames_description": "${name} at line ${lineno} (${count} times)", "copy_warning": "

    STOP!

    \n

    Try to avoid copy pasting code. You will learn, absorb, and remember better if you type in the code yourself.

    \n

    When copying is appropriate, there will be a button to click to make it easy. If there's no button, try typing.

    \n

    Having said that, we're not going to force you. Copy if you really want to.

    "} \ No newline at end of file +{ + "stop": "Stop", + "run": "Run", + "ask_for_help": "Ask for Help", + "question_wizard": "Question Wizard", + "previous": "Previous", + "next": "Next", + "table_of_contents": "Table of Contents", + "skip_step": "Skip step", + "reverse_step": "Reverse step", + "sign_out": "Sign out", + "settings": "Settings", + "feedback": "Feedback", + "developer_mode": "Developer mode", + "developer_mode_description": "Enables the \"Reverse step\" and \"Skip step\" buttons.", + "loading_wait": "Loading...", + "login_or_sign_up": "Login / Sign up", + "error_traceback": "Error traceback:", + "did_you_mean": "Did you mean...", + "similar_frames_skipped": "Similar frames skipped:", + "report_error": "Report error", + "report_error_instructions": "Oops, something went wrong! Please describe what you were just doing and what steps someone can take to reproduce the problem, then click Submit. Or click Cancel to not send a report.", + "click_for_error_details": "Click for error details", + "give_feedback": "Give feedback", + "feedback_email_placeholder": "Email (optional, publicly visible)", + "title": "Title", + "description": "Description", + "submit": "Submit", + "cancel": "Cancel", + "contact_directly": "Alternatively, you can contact us directly:", + "send_email_to": "Email", + "open_github_issue": "Open an issue on GitHub", + "chat_on_slack": "Chat on Slack", + "copying_solution_not_allowed": "Copying from the hints/solution area is not allowed!", + "get_hint": "Get a hint", + "get_another_hint": "Get another hint", + "show_solution": "Show solution", + "show_unscrambled_solution": "Show unscrambled solution", + "show_shuffled_solution": "Show shuffled solution", + "parsons_solution_instructions": "Above is an example solution with the lines out of order. You can drag them around to reorder them. Finding a correct order is up to you, and we won't will tell you if you get it right. Experimenting and running partial solutions in the editor may help you figure it out. You still need to type a correct solution into the editor and run it to continue.", + "are_you_sure": "Are you sure?", + "yes": "Yes", + "no": "No", + "hidden_solution_instructions": "Above is an example solution, but it's hidden. Click the Reveal button repeatedly to reveal the solution bit by bit. Try to stop when you think you've revealed enough and can fill in the remaining gaps yourself. Then type a solution in the editor and run it. Your solution doesn't have to be the same as the one above.", + "reveal": "Reveal", + "output_prediction_question": "What do you think the result will be?", + "output_prediction_wrong_once": "Oops, that's not right. You can try one more time!", + "output_prediction_wrong_twice": "Sorry, wrong answer. Try again next time!", + "output_prediction_correct": "Correct!", + "output_prediction_error_choice": "Error", + "ok": "OK", + "current_page": "(current)", + "question_wizard_intro": "

    If you need help, there are many sites like Stack Overflow and reddit where you can ask questions. This is a tool to help you write a good quality question that is likely to get answers.

    \n

    Enter and run your code on the right. If you don't have any code because you don't know where to get started, I'm afraid this tool can't help you. You can still ask for help, but it might be good to first read What types of questions should I avoid asking?

    \n

    If your question is about servers (e.g. Django or Flask), web requests, databases, or a package that can't be imported here, then this tool won't work. However, just because your current code involves those things, that doesn't mean that's what your question is about. If you're having a general Python/programming/logic problem, then extract that problem from the other stuff. Python with Django is still Python. If you can't do that, then read How to create a Minimal, Reproducible Example before asking your question.

    ", + "question_wizard_expected_output": "

    Good, now enter the output you expect/want from your program below. What would it show if it worked correctly? If it's not supposed to output anything, then add some print() calls to your code so that it would output something useful.

    \n

    When you're done, click 'Run' again to generate your question.

    ", + "give_feedback_instructions": "

    Tell us what you like or don't like! If you're reporting a bug, give a detailed description of the problem:

    \n
      \n
    • What were you doing before and when the problem occurred?
    • \n
    • What steps can someone take to reproduce it?
    • \n
    • What do you observe happening, and what do you expect to happen instead?
    • \n
    ", + "toc_instructions": "

    Below are links to different pages in the course. You can start anywhere and go in any order, and your progress on each page will be recorded.

    \n

    If you're completely new to programming, or you have doubts, just start at the beginning and click Next as you finish each page.

    ", + "hints_progress": "Shown ${numHints} of ${totalHints} hints", + "repeated_frames_description": "${name} at line ${lineno} (${count} times)", + "copy_warning": "

    STOP!

    \n

    Try to avoid copy pasting code. You will learn, absorb, and remember better if you type in the code yourself.

    \n

    When copying is appropriate, there will be a button to click to make it easy. If there's no button, try typing.

    \n

    Having said that, we're not going to force you. Copy if you really want to.

    " +} \ No newline at end of file From 68df3efb2e1707d895b233735f9e6902a1be8322 Mon Sep 17 00:00:00 2001 From: Alex Hall Date: Sun, 6 Feb 2022 10:57:26 +0200 Subject: [PATCH 190/730] update spanish translations --- tests/golden_files/es/test_transcript.json | 293 ++++++++++++++++-- .../locales/es/LC_MESSAGES/futurecoder.mo | Bin 271145 -> 291451 bytes 2 files changed, 260 insertions(+), 33 deletions(-) diff --git a/tests/golden_files/es/test_transcript.json b/tests/golden_files/es/test_transcript.json index 7f995228..2ab098ca 100644 --- a/tests/golden_files/es/test_transcript.json +++ b/tests/golden_files/es/test_transcript.json @@ -1203,7 +1203,7 @@ "step": "for_inside_if" }, { - "page": "Entendiendo Programas con Snoop", + "page": "Entendiendo Programas con snoop", "program": [ "frase = 'Hola Mundo'", "", @@ -1240,7 +1240,7 @@ "step": "print_tail" }, { - "page": "Entendiendo Programas con Snoop", + "page": "Entendiendo Programas con snoop", "program": [ "frase = 'Hola Mundo'", "", @@ -1456,7 +1456,7 @@ "", "print(nueva_frase)" ], - "page": "Entendiendo Programas con Snoop", + "page": "Entendiendo Programas con snoop", "program": [ "frase = 'Hello there'", "incluir = True", @@ -1794,13 +1794,13 @@ "page": "El operador de igualdad", "program": [ "nombre = 'kesha'", - "juego_nuevo = ''", + "nuevo_nombre = ''", "for c in nombre:", " if c == 's':", " c = '$'", - " juego_nuevo += c", + " nuevo_nombre += c", "", - "print(juego_nuevo)" + "print(nuevo_nombre)" ], "response": { "message": "", @@ -1816,7 +1816,7 @@ }, { "get_solution": [ - "juego_nuevo = ''", + "nuevo_nombre = ''", "for c in nombre:", " if c == 'e':", " c = '3'", @@ -1824,14 +1824,14 @@ " c = '$'", " if c == 'a':", " c = '@'", - " juego_nuevo += c", + " nuevo_nombre += c", "", - "print(juego_nuevo)" + "print(nuevo_nombre)" ], "page": "El operador de igualdad", "program": [ "nombre = 'kesha'", - "juego_nuevo = ''", + "nuevo_nombre = ''", "for c in nombre:", " if c == 'e':", " c = '3'", @@ -1839,9 +1839,9 @@ " c = '$'", " if c == 'a':", " c = '@'", - " juego_nuevo += c", + " nuevo_nombre += c", "", - "print(juego_nuevo)" + "print(nuevo_nombre)" ], "response": { "message": "", @@ -2424,15 +2424,31 @@ { "page": "Recuperando elementos en una posici\u00f3n, range() y len().", "program": [ - "for i in range(10):", - " print(i)" + "palabras = ['Esto', 'es', 'una', 'lista']", + "indices = [0, 1, 2, 3]", + "", + "for indice in indices:", + " print(indice)", + " print(palabras[indice])" ], "response": { "message": "", "passed": true, + "prediction": { + "answer": "0\nEsto\n1\nes\n2\nuna\n3\nlista", + "choices": [ + "Esto\nes\nuna\nlista", + "0\n1\n2\n3", + "0\nEsto\n1\nes\n2\nuna\n3\nlista", + "Esto\n0\nes\n1\nuna\n2\nlista\n3", + "0\n1\n2\n3\nEsto\nes\nuna\nlista", + "Esto\nes\nuna\nlista\n0\n1\n2\n3", + "Error" + ] + }, "result": [ { - "text": "0\n1\n2\n3\n4\n5\n6\n7\n8\n9\n", + "text": "0\nEsto\n1\nes\n2\nuna\n3\nlista\n", "type": "stdout" } ] @@ -2448,32 +2464,243 @@ " print(posicion)", " print(palabras[posicion])" ], + "response": { + "message": "", + "passed": true, + "result": [ + { + "text": "0\nEsto\n1\nes\n2\nuna\n3\nlista\n", + "type": "stdout" + } + ] + }, + "step": "range_len" + }, + { + "page": "Recuperando elementos en una posici\u00f3n, range() y len().", + "program": [ + "indices = range(4)", + "", + "print(indices[0])", + "print(indices[1])", + "print(indices[2])", + "print(indices[3])" + ], "response": { "message": "", "passed": true, "prediction": { - "answer": "0\nEsto\n1\nes\n2\nuna\n3\nlista", + "answer": "0\n1\n2\n3", "choices": [ - "Esto\nes\nuna\nlista", "0\n1\n2\n3", - "0\nEsto\n1\nes\n2\nuna\n3\nlista", - "\nEsto\n0\nes\n1\nuna\n2\nlista\n3", - "0\n1\n2\n3\nEsto\nes\nuna\nlista", - "Esto\nes\nuna\nlista\n0\n1\n2\n3", + "1\n2\n3\n4", + "[0]\n[1]\n[2]\n[3]", + "[1]\n[2]\n[3]\n[4]", + "Esta\nes\nuna\nlista", "Error" ] }, "result": [ { - "text": "0\nEsto\n1\nes\n2\nuna\n3\nlista\n", + "text": "0\n1\n2\n3\n", "type": "stdout" } ] }, - "step": "range_len" + "step": "printing_the_range" + }, + { + "page": "Recuperando elementos en una posici\u00f3n, range() y len().", + "program": [ + "indices[4]" + ], + "response": { + "message": "", + "passed": true, + "prediction": { + "answer": "Error", + "choices": [ + "0", + "1", + "2", + "3", + "4", + "Error" + ] + }, + "result": [ + { + "data": [ + { + "didyoumean": [], + "exception": { + "message": "range object index out of range", + "type": "IndexError" + }, + "frames": [ + { + "lines": [ + { + "content": "indices[4]", + "is_current": true, + "lineno": 1, + "type": "line" + } + ], + "name": "", + "type": "frame", + "variables": [ + { + "name": "indices\n", + "value": "range(0, 4)\n" + } + ] + } + ], + "friendly": "

    An IndexError occurs when you try to get an item from a list,\na tuple, or a similar object (sequence), and use an index which\ndoes not exist; typically, this happens because the index you give\nis greater than the length of the sequence.

    \n

    You have tried to get the item with index 4 of indices,\nrange object of length 4.\nThe valid index values of indices are integers ranging from\n-4 to 3.

    ", + "tail": "" + } + ], + "text": [ + "Traceback (most recent call last):", + " File \"my_program.py\", line 1, in ", + "--> 1 | indices[4]", + " ^^^^^^^^^^", + "indices = range(0, 4)", + "", + "IndexError: range object index out of range" + ], + "type": "traceback" + } + ] + }, + "step": "indices_out_of_bounds" }, { "page": "Recuperando elementos en una posici\u00f3n, range() y len().", + "program": [ + "range(4)" + ], + "response": { + "message": "", + "passed": true, + "result": [ + { + "text": "range(0, 4)\n", + "type": "stdout" + } + ] + }, + "step": "range_almost_the_same_as_list" + }, + { + "page": "Recuperando elementos en una posici\u00f3n, range() y len().", + "program": [ + "list(range(4))" + ], + "response": { + "message": "", + "passed": true, + "prediction": { + "answer": "[0, 1, 2, 3]", + "choices": [ + "range(4)", + "range(0, 4)", + "list(range(4))", + "list(range(0, 4))", + "range(0, 1, 2, 3)", + "(0, 1, 2, 3)", + "[0, 1, 2, 3]", + "Error" + ] + }, + "result": [ + { + "text": "[0, 1, 2, 3]\n", + "type": "stdout" + } + ] + }, + "step": "range_versus_list" + }, + { + "page": "Recuperando elementos en una posici\u00f3n, range() y len().", + "program": [ + "palabras = ['Esta', 'es', 'una', 'lista']", + "print(len(palabras))" + ], + "response": { + "message": "", + "passed": true, + "prediction": { + "answer": "4", + "choices": [ + "0", + "1", + "2", + "3", + "4", + "5", + "Error" + ] + }, + "result": [ + { + "text": "4\n", + "type": "stdout" + } + ] + }, + "step": "using_len_first_time" + }, + { + "get_solution": [ + "print(palabras[len(palabras) - 1])" + ], + "page": "Recuperando elementos en una posici\u00f3n, range() y len().", + "program": [ + "palabras = ['Python']", + "print(palabras[len(palabras) - 1])" + ], + "response": { + "message": "", + "passed": true, + "result": [ + { + "text": "Python\n", + "type": "stdout" + } + ] + }, + "step": "print_last_element" + }, + { + "get_solution": [ + "for indice in range(len(palabras)):", + " print(indice)", + " print(palabras[indice])" + ], + "page": "Recuperando elementos en una posici\u00f3n, range() y len().", + "program": [ + "palabras = ['Python']", + "for indice in range(len(palabras)):", + " print(indice)", + " print(palabras[indice])" + ], + "response": { + "message": "", + "passed": true, + "result": [ + { + "text": "0\nPython\n", + "type": "stdout" + } + ] + }, + "step": "print_indices_and_words" + }, + { + "page": "Ejercicios con range() y len()", "program": [ "cosas = ['on', 'the', 'way', 'to', 'the', 'store']", "a_encontrar = 'the'", @@ -2494,7 +2721,7 @@ "step": "index_exercise" }, { - "page": "Recuperando elementos en una posici\u00f3n, range() y len().", + "page": "Ejercicios con range() y len()", "program": [ "cosas = ['on', 'the', 'way', 'to', 'the', 'store']", "a_encontrar = 'the'", @@ -2523,7 +2750,7 @@ " print(i)", " break" ], - "page": "Recuperando elementos en una posici\u00f3n, range() y len().", + "page": "Ejercicios con range() y len()", "program": [ "cosas = ['on', 'the', 'way', 'to', 'the', 'store']", "a_encontrar = 'the'", @@ -2551,7 +2778,7 @@ " car2 = cadena2[i]", " print(car1 + ' ' + car2)" ], - "page": "Recuperando elementos en una posici\u00f3n, range() y len().", + "page": "Ejercicios con range() y len()", "program": [ "cadena1 = 'Hello'", "cadena2 = 'World'", @@ -2595,7 +2822,7 @@ "", " print(car1 + ' ' + car2)" ], - "page": "Recuperando elementos en una posici\u00f3n, range() y len().", + "page": "Ejercicios con range() y len()", "program": [ "cadena1 = 'Goodbye'", "cadena2 = 'World'", @@ -4032,7 +4259,7 @@ ], "page": "f-strings", "program": [ - "personas = ['xXHpwj', 'KviHqnTYy', 'UwalMAWd', 'pCldL', 'ILiVG', 'WupPwbGR', 'WsnkbMl', 'lAMDfz']", + "personas = ['eODoUwNzS', 'ofHBEzZxs', 'zwTrQA', 'LDaOKmpHU', 'HCMLTt', 'NbRmEjaoyD']", "print(f\"Hay {len(personas)} personas esperando, el nombre de la primera es {personas[0]}.\")" ], "response": { @@ -4040,7 +4267,7 @@ "passed": true, "result": [ { - "text": "Hay 8 personas esperando, el nombre de la primera es xXHpwj.\n", + "text": "Hay 6 personas esperando, el nombre de la primera es eODoUwNzS.\n", "type": "stdout" } ] @@ -6579,7 +6806,7 @@ ], "page": "Tipos de Dato", "program": [ - "numero = '7'", + "numero = '1'", "for i in range(int(numero)):", " print('Comenzando...' + str(i + 1))", "print('\u00a1V\u00e9!')" @@ -6589,7 +6816,7 @@ "passed": true, "result": [ { - "text": "Comenzando...1\nComenzando...2\nComenzando...3\nComenzando...4\nComenzando...5\nComenzando...6\nComenzando...7\n\u00a1V\u00e9!\n", + "text": "Comenzando...1\n\u00a1V\u00e9!\n", "type": "stdout" } ] @@ -6691,11 +6918,11 @@ "type": "input_prompt" }, { - "text": "\n", + "text": "\n", "type": "stdout" }, { - "text": "\u00a1Nope!\n", + "text": "\u00a1Incre\u00edble! \u00bfEres ps\u00edquico?\n", "type": "stdout" } ] diff --git a/translations/locales/es/LC_MESSAGES/futurecoder.mo b/translations/locales/es/LC_MESSAGES/futurecoder.mo index 15af11ab4b770f0af7384c9d9aea95ada599763b..549b7bc058dfcc3a4ecb80664064087036473a9c 100644 GIT binary patch delta 34703 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 Tsr#xWf1Y$Qb=?`sch~)Y8Hv-! delta 22304 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�g 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 Date: Sun, 6 Feb 2022 11:47:49 +0200 Subject: [PATCH 191/730] update spanish translations, fix debugger names in english text --- core/chapters/c08_nested_loops.py | 6 +++--- core/translation.py | 7 +++---- translations/english.po | 10 +++++----- .../locales/en/LC_MESSAGES/futurecoder.mo | Bin 266227 -> 266239 bytes .../locales/es/LC_MESSAGES/futurecoder.mo | Bin 291451 -> 291555 bytes 5 files changed, 11 insertions(+), 12 deletions(-) diff --git a/core/chapters/c08_nested_loops.py b/core/chapters/c08_nested_loops.py index 4f27069f..0ed323d2 100644 --- a/core/chapters/c08_nested_loops.py +++ b/core/chapters/c08_nested_loops.py @@ -1217,7 +1217,7 @@ class double_subscripting(Step): Take a good look at this syntax. If it looks new and fancy, it's not. It's just the usual syntax for subscripting, applied twice. -Try it in birdseye to see how Python breaks it down into smaller pieces. +Try it in `birdseye` to see how Python breaks it down into smaller pieces. """ expected_code_source = "birdseye" @@ -1261,7 +1261,7 @@ def check(self): Indexing works similarly on lists and strings. Do you get an `index out of range` error? Is it for a string, or a list? Why? Make sure you are not confusing the order of the list index and the string index. -Use birdseye if you're having trouble. +Use `birdseye` if you're having trouble. """ tests = [ (["abc", "de", "fghi", "jklmn", "o"], 'n'), @@ -1311,7 +1311,7 @@ def solution(self, strings: List[List[str]]): First you need to access a sublist. Then a string in that sublist. Then a letter in that string. -Use birdseye if you're having trouble. +Use `birdseye` if you're having trouble. """ tests = [ diff --git a/core/translation.py b/core/translation.py index 9cb3d33f..f8259a02 100644 --- a/core/translation.py +++ b/core/translation.py @@ -50,9 +50,8 @@ def get(msgid, default): result = translation.gettext(msgid) if result == msgid: - # TODO remove misc_terms assert ( - msgid.startswith(("code_bits.", "misc_terms.")) + msgid.startswith(("code_bits.")) or "output_prediction_choices" in msgid or ".disallowed." in msgid ) @@ -253,7 +252,7 @@ class Terms: expected_mode_birdseye = ( "With your code in the editor, click the `birdseye` button." ) - expected_mode_snoop = "With your code in the editor, click the Snoop button." + expected_mode_snoop = "With your code in the editor, click the `snoop` button." expected_mode_pythontutor = ( "With your code in the editor, click the Python Tutor button." ) @@ -304,7 +303,7 @@ class Terms: - Make sure the output is showing the problem you have and not something else. - Reduce your code to a **minimal** example. Remove any code that isn't directly related to the problem. -- Run your code through the Snoop, Birdseye, and Python Tutor debuggers to understand what it's doing. +- Run your code through the `snoop`, `birdseye`, and Python Tutor debuggers to understand what it's doing. - Search for your problem online. - Read [How do I ask a good question?](https://stackoverflow.com/help/how-to-ask) diff --git a/translations/english.po b/translations/english.po index 52eabb72..2ede1062 100644 --- a/translations/english.po +++ b/translations/english.po @@ -17610,7 +17610,7 @@ msgid "misc_terms.expected_mode_shell" msgstr "Type your code directly in the shell after `>>>` and press Enter." msgid "misc_terms.expected_mode_snoop" -msgstr "With your code in the editor, click the Snoop button." +msgstr "With your code in the editor, click the `snoop` button." msgid "misc_terms.incorrect_mode" msgstr "The code is correct, but you didn't run it as instructed." @@ -17642,7 +17642,7 @@ msgstr "" "\n" "- Make sure the output is showing the problem you have and not something else.\n" "- Reduce your code to a **minimal** example. Remove any code that isn't directly related to the problem.\n" -"- Run your code through the Snoop, Birdseye, and Python Tutor debuggers to understand what it's doing.\n" +"- Run your code through the `snoop`, `birdseye`, and Python Tutor debuggers to understand what it's doing.\n" "- Search for your problem online.\n" "- Read [How do I ask a good question?](https://stackoverflow.com/help/how-to-ask)\n" "\n" @@ -22122,7 +22122,7 @@ msgstr "" "\n" "Take a good look at this syntax. If it looks new and fancy, it's not.\n" "It's just the usual syntax for subscripting, applied twice.\n" -"Try it in birdseye to see how Python breaks it down into smaller pieces." +"Try it in `birdseye` to see how Python breaks it down into smaller pieces." #. https://futurecoder.io/course/#IntroducingNestedLists #. @@ -22170,7 +22170,7 @@ msgstr "Make sure you are not confusing the order of the list index and the stri #. #. https://poeditor.com/projects/view_terms?id=490053&search=pages.IntroducingNestedLists.steps.double_subscripting_exercise msgid "pages.IntroducingNestedLists.steps.double_subscripting_exercise.hints.7.text" -msgstr "Use birdseye if you're having trouble." +msgstr "Use `birdseye` if you're having trouble." #. https://futurecoder.io/course/#IntroducingNestedLists msgid "pages.IntroducingNestedLists.steps.double_subscripting_exercise.text" @@ -22336,7 +22336,7 @@ msgstr "Then a letter in that string." #. #. https://poeditor.com/projects/view_terms?id=490053&search=pages.IntroducingNestedLists.steps.triple_subscripting msgid "pages.IntroducingNestedLists.steps.triple_subscripting.hints.5.text" -msgstr "Use birdseye if you're having trouble." +msgstr "Use `birdseye` if you're having trouble." #. https://futurecoder.io/course/#IntroducingNestedLists msgid "pages.IntroducingNestedLists.steps.triple_subscripting.text" diff --git a/translations/locales/en/LC_MESSAGES/futurecoder.mo b/translations/locales/en/LC_MESSAGES/futurecoder.mo index a73b56b335e7f69349cbed41f1a1e7b60273643d..508d8784ad395d3bafa4c417f31d7911c94d7635 100644 GIT binary patch delta 8567 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 delta 9303 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 NlAW}OWOr@A{{i6{D6s$l From 9c2ab32ae1073604177f64f8fd608437ba4c15f9 Mon Sep 17 00:00:00 2001 From: Alex Hall Date: Sun, 6 Feb 2022 11:51:41 +0200 Subject: [PATCH 192/730] update spanish translations --- .../locales/es/LC_MESSAGES/futurecoder.mo | Bin 291555 -> 291468 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/translations/locales/es/LC_MESSAGES/futurecoder.mo b/translations/locales/es/LC_MESSAGES/futurecoder.mo index 945d5229d5cdaaad9b757ca415f8f68615b8c184..adcca7095920433792f345df1963ada3a9703878 100644 GIT binary patch delta 9092 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%0A*6>hJ&W=mX+$ASafg?07;7 zXw!ATvc$7d`fhvB`*@Hzte|f*;scZlPb%b_WmK?jVeRwBp}uLy7^+vqx4(caDel|6 z(WQiMD$4x-iUWDTpU9TTyg_M!>Lq={f9B16%tl-z%(p+AHN}OLe}EY&e^lBxThJ}z z+flwPXqvLV`IPHApmf>Ia=x9uUU}dC&=HP-Wt@1zK{PI`z~IBPD1)+bMRgK3ApQX* zU%bU}SdjlRypKyz){GMS9lNyb+~>6O3Q6Undh%@ zJGsA7eXaP-Xx~Io-n*e*{|(BZyn-FEaG;Sk$ww%IZXhP xP`3WQ{m;h7ID-nU#|T=o>Ojq$Bd3h%{Qa2DPQ4a0a;$aubHC5A);s*`{{c@k3B&*Z delta 9180 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 Date: Sun, 6 Feb 2022 12:05:54 +0200 Subject: [PATCH 193/730] ignore terms.json --- frontend/.gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/frontend/.gitignore b/frontend/.gitignore index 014c9540..1a72c6fd 100644 --- a/frontend/.gitignore +++ b/frontend/.gitignore @@ -24,6 +24,7 @@ yarn-error.log* *.load_by_url chapters.json +terms.json python_core.tar public/birdseye/ From 755cb2eddd7bd32aab4c571b5a771c88dccdfd30 Mon Sep 17 00:00:00 2001 From: Alex Hall Date: Sun, 6 Feb 2022 12:45:33 +0200 Subject: [PATCH 194/730] Package translation files better --- core/generate_static_files.py | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/core/generate_static_files.py b/core/generate_static_files.py index a6b22a67..3f3a9ec8 100644 --- a/core/generate_static_files.py +++ b/core/generate_static_files.py @@ -75,7 +75,7 @@ def tarfile_filter(tar_info): x in name for x in [ "__pycache__", - "friendly/locales", + "friendly_traceback/locales", "birdseye/static", "pygments/lexers", ] @@ -125,7 +125,15 @@ def main(): with tarfile.open(frontend_src / "python_core.tar.load_by_url", "w") as tar: tar.add(this_dir, arcname=this_dir.stem, recursive=True, filter=tarfile_filter) - tar.add(this_dir.parent / "translations", arcname="translations", recursive=True, filter=tarfile_filter) + if t.current_language not in (None, "en"): + for arcname in [ + f"translations/locales/{t.current_language}", + f"translations/codes.json", + ]: + tar.add(this_dir.parent / arcname, arcname=arcname, recursive=True, filter=tarfile_filter) + arcname = f"friendly_traceback/locales/{t.current_language}/LC_MESSAGES/friendly_tb_{t.current_language}.mo" + tar.add(Path(site_packages) / arcname, arcname=arcname) + for root in roots: tar.add( Path(site_packages) / root, From d82e21c6bf7ac5c6fc325b61a0aa8299c4d71df4 Mon Sep 17 00:00:00 2001 From: Alex Hall Date: Sun, 6 Feb 2022 13:03:48 +0200 Subject: [PATCH 195/730] REACT_APP_LANGUAGE env var --- frontend/src/Worker.js | 2 +- frontend/src/load.py | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/frontend/src/Worker.js b/frontend/src/Worker.js index 59c3c183..9fa8e231 100644 --- a/frontend/src/Worker.js +++ b/frontend/src/Worker.js @@ -40,7 +40,7 @@ async function loadPyodideAndPackages() { console.time("load_package_buffer(buffer)") const load_package_buffer = pyodide.globals.get("load_package_buffer") - const result = load_package_buffer(buffer); + const result = load_package_buffer(buffer, process.env.REACT_APP_LANGUAGE); ({check_entry, install_imports} = toObject(result)); console.timeEnd("load_package_buffer(buffer)") } diff --git a/frontend/src/load.py b/frontend/src/load.py index de6756b5..f163088d 100644 --- a/frontend/src/load.py +++ b/frontend/src/load.py @@ -7,7 +7,7 @@ tarfile.TarFile.chown = lambda *_, **__: None -def load_package_buffer(buffer): +def load_package_buffer(buffer, lang): fd = io.BytesIO(buffer.to_py()) with tarfile.TarFile(fileobj=fd) as zf: zf.extractall(package_path) @@ -17,7 +17,8 @@ def load_package_buffer(buffer): from core.text import load_chapters from core import translation as t - t.set_language("es") + if lang: + t.set_language(lang) list(load_chapters()) From 2716bc64d84c4055eca8ca0a78e0a96242bebc1f Mon Sep 17 00:00:00 2001 From: Alex Hall Date: Sun, 6 Feb 2022 13:06:22 +0200 Subject: [PATCH 196/730] avoid `t.set_language("en")` in load.py --- frontend/src/load.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/src/load.py b/frontend/src/load.py index f163088d..11b29ebc 100644 --- a/frontend/src/load.py +++ b/frontend/src/load.py @@ -17,7 +17,7 @@ def load_package_buffer(buffer, lang): from core.text import load_chapters from core import translation as t - if lang: + if lang and lang != "en": t.set_language(lang) list(load_chapters()) From 1e3fbc30105ae82b6badd4522dbc83d196ef2aae Mon Sep 17 00:00:00 2001 From: Alex Hall Date: Sun, 6 Feb 2022 13:17:46 +0200 Subject: [PATCH 197/730] REACT_APP_LANGUAGE=$FUTURECODER_LANGUAGE --- build.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.sh b/build.sh index e023b44b..812cd7d2 100755 --- a/build.sh +++ b/build.sh @@ -11,7 +11,7 @@ poetry run python -m translations.generate_po_file poetry run python -m core.generate_static_files cd frontend -CI=false npm run build +REACT_APP_LANGUAGE=$FUTURECODER_LANGUAGE CI=false npm run build cd .. cp -r frontend/build/* dist/course/ From 3e1a2ac12ba4e4aba529d4f5c2146a693fbf5011 Mon Sep 17 00:00:00 2001 From: Alex Hall Date: Sun, 6 Feb 2022 13:23:45 +0200 Subject: [PATCH 198/730] revert workflow.yml, preview is managed with local commands --- .github/workflows/workflow.yml | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/.github/workflows/workflow.yml b/.github/workflows/workflow.yml index 3111df75..4ab855b6 100644 --- a/.github/workflows/workflow.yml +++ b/.github/workflows/workflow.yml @@ -21,17 +21,17 @@ jobs: REACT_APP_FEEDBACK_GITHUB_TOKEN: ${{ secrets.REACT_APP_FEEDBACK_GITHUB_TOKEN }} REACT_APP_SENTRY_DSN: https://37b1f01452b54bf4a0fe88656070998f@o871617.ingest.sentry.io/5824691 REACT_APP_USE_FIREBASE_EMULATORS: '1' - FUTURECODER_LANGUAGE: es + FUTURECODER_LANGUAGE: en run: ./full_build.sh -# - name: Test -# env: -# FUTURECODER_LANGUAGE: en -# run: ./ci_test.sh -# - name: Upload test artifacts -# uses: actions/upload-artifact@v2 -# if: steps.build.outcome == 'success' -# with: -# path: '**/test_frontend_assets/' + - name: Test + env: + FUTURECODER_LANGUAGE: en + run: ./ci_test.sh + - name: Upload test artifacts + uses: actions/upload-artifact@v2 + if: steps.build.outcome == 'success' + with: + path: '**/test_frontend_assets/' - name: Deploy uses: FirebaseExtended/action-hosting-deploy@v0 if: steps.build.outcome == 'success' From 3d206e8b85dd0f1c9085fcf7e863fd5abdc1cc91 Mon Sep 17 00:00:00 2001 From: Alex Hall Date: Sun, 6 Feb 2022 14:01:52 +0200 Subject: [PATCH 199/730] Update friendly_traceback --- generate.sh | 2 +- poetry.lock | 14 +++++++------- pyproject.toml | 2 +- tests/golden_files/en/test_transcript.json | 2 +- tests/golden_files/es/test_transcript.json | 22 +++++++++++----------- 5 files changed, 21 insertions(+), 21 deletions(-) diff --git a/generate.sh b/generate.sh index 3b706a70..79f2afc4 100755 --- a/generate.sh +++ b/generate.sh @@ -6,7 +6,7 @@ poetry run python -m translations.generate_po_file export FIX_CORE_IMPORTS=1 export FIX_TESTS=1 -for lang in en +for lang in es en do export FUTURECODER_LANGUAGE=$lang poetry run python -m core.generate_static_files diff --git a/poetry.lock b/poetry.lock index f51f52c1..3c3be366 100644 --- a/poetry.lock +++ b/poetry.lock @@ -123,7 +123,7 @@ pyflakes = ">=2.2.0,<2.3.0" [[package]] name = "friendly-traceback" -version = "0.4.111" +version = "0.5.30" description = "Friendlier tracebacks in any language." category = "main" optional = false @@ -215,7 +215,7 @@ python-versions = "*" [[package]] name = "pure-eval" -version = "0.2.1" +version = "0.2.2" description = "Safely evaluate AST nodes without side effects" category = "main" optional = false @@ -401,7 +401,7 @@ socks = ["PySocks (>=1.5.6,!=1.5.7,<2.0)"] [metadata] lock-version = "1.1" python-versions = "~3.9" -content-hash = "2a20bfd696af4b333e8fa11d49917fc2096b34efc887597806d71a5610082a1c" +content-hash = "4c55af646e134959e750c2fbd468f4c6546cdb6ea73a9af2e719bc3a24a41881" [metadata.files] astcheck = [ @@ -446,8 +446,8 @@ flake8 = [ {file = "flake8-3.8.3.tar.gz", hash = "sha256:f04b9fcbac03b0a3e58c0ab3a0ecc462e023a9faf046d57794184028123aa208"}, ] friendly-traceback = [ - {file = "friendly-traceback-0.4.111.tar.gz", hash = "sha256:8102a4a73a1c1621a49550b73ca82a8597dfc4c52a8f395693f6270e6bb36221"}, - {file = "friendly_traceback-0.4.111-py3-none-any.whl", hash = "sha256:90016d0bf4839fcbdcf2b9531c544dc7f0254755eb424ff9fb196293ac8ce365"}, + {file = "friendly-traceback-0.5.30.tar.gz", hash = "sha256:edfdab56802d0dab95cd1a66dfe7b95119d991bc63c8649477e4b55bfd79cf3d"}, + {file = "friendly_traceback-0.5.30-py3-none-any.whl", hash = "sha256:31caf436407eda23104852a35e81e7f3f953123a18b87e5a5e6d18679131f631"}, ] iniconfig = [ {file = "iniconfig-1.1.1-py2.py3-none-any.whl", hash = "sha256:011e24c64b7f47f6ebd835bb12a743f2fbe9a26d4cecaa7f53bc4f35ee9da8b3"}, @@ -481,8 +481,8 @@ polib = [ {file = "polib-1.1.1.tar.gz", hash = "sha256:e02c355ae5e054912e3b0d16febc56510eff7e49d60bf22aecb463bd2f2a2dfa"}, ] pure-eval = [ - {file = "pure_eval-0.2.1-py3-none-any.whl", hash = "sha256:94eeb505a88721bec7bb21a4ac49758b8b1a01530da1a70d4ffc1d9937689d71"}, - {file = "pure_eval-0.2.1.tar.gz", hash = "sha256:0f04483b16c9429532d2c0ddc96e2b3bb6b2dc37a2bfb0e986248dbfd0b78873"}, + {file = "pure_eval-0.2.2-py3-none-any.whl", hash = "sha256:01eaab343580944bc56080ebe0a674b39ec44a945e6d09ba7db3cb8cec289350"}, + {file = "pure_eval-0.2.2.tar.gz", hash = "sha256:2b45320af6dfaa1750f543d714b6d1c520a1688dec6fd24d339063ce0aaa9ac3"}, ] py = [ {file = "py-1.9.0-py2.py3-none-any.whl", hash = "sha256:366389d1db726cd2fcfc79732e75410e5fe4d31db13692115529d34069a043c2"}, diff --git a/pyproject.toml b/pyproject.toml index 121100b7..fe66d20c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -20,7 +20,7 @@ astcheck = "^0.2.5" pyflakes = "^2.2.0" BetterErrorMessages = "^0.4" sentry-sdk = "^1.1.0" -friendly-traceback = "^0.4.94" +friendly-traceback = "@latest" [tool.poetry.dev-dependencies] flake8 = {version = "^3.8.3", optional = true} diff --git a/tests/golden_files/en/test_transcript.json b/tests/golden_files/en/test_transcript.json index f0ce4ef2..87a65505 100644 --- a/tests/golden_files/en/test_transcript.json +++ b/tests/golden_files/en/test_transcript.json @@ -4023,7 +4023,7 @@ "passed": true, "result": [ { - "text": " print('Alice's Diner')\n ^\nSyntaxError: invalid syntax\nat line 1\n\nA `SyntaxError` occurs when Python cannot understand your code.\n\nThere appears to be a Python identifier (variable name)\nimmediately following a string.\nI suspect that you were trying to use a quote inside a string\nthat was enclosed in quotes of the same kind.\n\n\n", + "text": " print('Alice's Diner')\n ^\nSyntaxError: invalid syntax\nat line 1\n\nA `SyntaxError` occurs when Python cannot understand your code.\n\nI suspect that you were trying to use a quote character inside a string\nthat was enclosed in quotes of the same kind.\nPerhaps you should have escaped the inner quote character:\n\n print('Alice\\'s Diner')\n ^^\n\n\n", "type": "syntax_error" } ] diff --git a/tests/golden_files/es/test_transcript.json b/tests/golden_files/es/test_transcript.json index 2ab098ca..d5d9e5af 100644 --- a/tests/golden_files/es/test_transcript.json +++ b/tests/golden_files/es/test_transcript.json @@ -4004,7 +4004,7 @@ "passed": true, "result": [ { - "text": " print('Alice's Diner')\n ^\nSyntaxError: invalid syntax\nen la l\u00ednea 1\n\nA `SyntaxError` occurs when Python cannot understand your code.\n\nThere appears to be a Python identifier (variable name)\nimmediately following a string.\nI suspect that you were trying to use a quote inside a string\nthat was enclosed in quotes of the same kind.\n\n\n", + "text": " print('Alice's Diner')\n ^\nSyntaxError: invalid syntax\nen la l\u00ednea 1\n\nA `SyntaxError` occurs when Python cannot understand your code.\n\nI suspect that you were trying to use a quote character inside a string\nthat was enclosed in quotes of the same kind.\nPerhaps you should have escaped the inner quote character:\n\n print('Alice\\'s Diner')\n ^^\n\n\n", "type": "syntax_error" } ] @@ -4133,7 +4133,7 @@ "program": [ "nombre = \"Alicia\"", "edad = 20", - "print(\"Hola\" + nombre + \". T\u00fa eres \" + edad + \" a\u00f1os.\")" + "print(\"Hola \" + nombre + \". T\u00fa eres \" + edad + \" a\u00f1os.\")" ], "response": { "message": "", @@ -4161,7 +4161,7 @@ { "lines": [ { - "content": "print("Hola" + nombre + ". T\u00fa eres " + edad + " a\u00f1os.")", + "content": "print("Hola " + nombre + ". T\u00fa eres " + edad + " a\u00f1os.")", "is_current": true, "lineno": 3, "type": "line" @@ -4171,12 +4171,12 @@ "type": "frame", "variables": [ { - "name": ""Hola" + nombre\n", - "value": "'HolaAlicia'\n" + "name": ""Hola " + nombre\n", + "value": "'Hola Alicia'\n" }, { - "name": ""Hola" + nombre + ". T\u00fa eres "\n", - "value": "'HolaAlicia. T\u00fa eres '\n" + "name": ""Hola " + nombre + ". T\u00fa eres "\n", + "value": "'Hola Alicia. T\u00fa eres '\n" }, { "name": "edad\n", @@ -4197,10 +4197,10 @@ "Traceback (most recent call last):", " File \"my_program.py\", line 3, in ", " 2 | edad = 20", - "--> 3 | print(\"Hola\" + nombre + \". T\u00fa eres \" + edad + \" a\u00f1os.\")", - " ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^", - "\"Hola\" + nombre = 'HolaAlicia'", - "\"Hola\" + nombre + \". T\u00fa eres \" = 'HolaAlicia. T\u00fa eres '", + "--> 3 | print(\"Hola \" + nombre + \". T\u00fa eres \" + edad + \" a\u00f1os.\")", + " ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^", + "\"Hola \" + nombre = 'Hola Alicia'", + "\"Hola \" + nombre + \". T\u00fa eres \" = 'Hola Alicia. T\u00fa eres '", "edad = 20", "nombre = 'Alicia'", "", From 5ac89b24bc844b05f6eb1039eb9a26ed6534ae39 Mon Sep 17 00:00:00 2001 From: Alex Hall Date: Sun, 6 Feb 2022 14:06:10 +0200 Subject: [PATCH 200/730] Set friendly_traceback language --- core/runner/friendly_traceback.py | 3 ++ tests/golden_files/es/test_transcript.json | 40 +++++++++++----------- 2 files changed, 23 insertions(+), 20 deletions(-) diff --git a/core/runner/friendly_traceback.py b/core/runner/friendly_traceback.py index 5a36e08f..66738b91 100644 --- a/core/runner/friendly_traceback.py +++ b/core/runner/friendly_traceback.py @@ -7,6 +7,9 @@ sys.__dict__.pop("last_" + attr, None) from friendly_traceback.core import FriendlyTraceback +import friendly_traceback + +friendly_traceback.set_lang(t.current_language or "en") def friendly_syntax_error(e, filename): diff --git a/tests/golden_files/es/test_transcript.json b/tests/golden_files/es/test_transcript.json index d5d9e5af..51571997 100644 --- a/tests/golden_files/es/test_transcript.json +++ b/tests/golden_files/es/test_transcript.json @@ -43,7 +43,7 @@ "passed": false, "result": [ { - "text": " 3 x 4\n ^\nSyntaxError: invalid syntax\nen la l\u00ednea 1\n\nA `SyntaxError` occurs when Python cannot understand your code.\n\nCurrently, I cannot guess the likely cause of this error.\nTry to examine closely the line indicated as well as the line\nimmediately above to see if you can identify some misspelled\nword, or missing symbols, like (, ), [, ], :, etc.\n\nUnless your code uses type annotations, which are beyond our scope,\nif you think that this is something which should be handled\nby friendly, please report this case to\nhttps://github.com/aroberge/friendly/issues\n\n\n\n", + "text": " 3 x 4\n ^\nSyntaxError: invalid syntax\nen la l\u00ednea 1\n\nUn `SyntaxError` ocurre cuando Python no puede entender tu c\u00f3digo.\n\nActualmente, no puedo detectar la causa probable de este error.\nIntente examinar detenidamente la l\u00ednea indicada, as\u00ed como la l\u00ednea\ninmediatamente superior para ver si puede identificar alguna palabra mal escrita\no s\u00edmbolos que falten, como (, ), [, ], :, etc.\n\nA menos que su c\u00f3digo utilice anotaciones de tipo, que est\u00e1n fuera de nuestro alcance,\nsi cree que esto es algo que deber\u00eda ser manejado\npor friendly, por favor reporte este caso a\nhttps://github.com/aroberge/friendly/issues\n\n\n\n", "type": "syntax_error" } ] @@ -248,7 +248,7 @@ "variables": [] } ], - "friendly": "

    A NameError exception indicates that a variable or\nfunction name is not known to Python.\nMost often, this is because there is a spelling mistake.\nHowever, sometimes it is because the name is used\nbefore being defined or given a value.

    \n

    In your program, no object with the name sol exists.\nI have no additional information for you.

    ", + "friendly": "

    Una excepci\u00f3n NameError indica que una variable o\nnombre de funci\u00f3n no es conocido por Python.\nLa mayor\u00eda de las veces, esto se debe a un error ortogr\u00e1fico.\nSin embargo, a veces es porque el nombre se utiliza\nantes de ser definido o de recibir un valor.

    \n

    En su programa, no existe ning\u00fan objeto con el nombre sol.\nNo tengo informaci\u00f3n adicional para usted.

    ", "tail": "" } ], @@ -563,7 +563,7 @@ "passed": true, "result": [ { - "text": " print(caracter)\n ^\nIndentationError: expected an indented block\nen la l\u00ednea 2\n\nAn `IndentationError` occurs when a given line of code is\nnot indented (aligned vertically with other lines) as expected.\n\nLine `2` identified above was expected to begin a new indented block.\n\n\n", + "text": " print(caracter)\n ^\nIndentationError: expected an indented block\nen la l\u00ednea 2\n\nUn `IndentationError` ocurre cuando una l\u00ednea de c\u00f3digo dada no est\u00e1\ncon la indentaci\u00f3n (alineada verticalmente con otras l\u00edneas) que se espera.\n\nSe esperaba que la l\u00ednea `2` identificada anteriormente comenzara un nuevo bloque indentado.\n\n\n", "type": "syntax_error" } ] @@ -624,7 +624,7 @@ "passed": true, "result": [ { - "text": " print('---')\n ^\nIndentationError: unindent does not match any outer indentation level\nen la l\u00ednea 3\n\nAn `IndentationError` occurs when a given line of code is\nnot indented (aligned vertically with other lines) as expected.\n\nLine `3` identified above is less indented than expected.\n\n\n", + "text": " print('---')\n ^\nIndentationError: unindent does not match any outer indentation level\nen la l\u00ednea 3\n\nUn `IndentationError` ocurre cuando una l\u00ednea de c\u00f3digo dada no est\u00e1\ncon la indentaci\u00f3n (alineada verticalmente con otras l\u00edneas) que se espera.\n\nLa l\u00ednea `3` identificada arriba tiene menos indentaci\u00f3n de la esperada.\n\n\n", "type": "syntax_error" } ] @@ -1624,7 +1624,7 @@ ] } ], - "friendly": "

    A NameError exception indicates that a variable or\nfunction name is not known to Python.\nMost often, this is because there is a spelling mistake.\nHowever, sometimes it is because the name is used\nbefore being defined or given a value.

    \n

    In your program, no object with the name car exists.\nThe Python builtin chr has a similar name.

    ", + "friendly": "

    Una excepci\u00f3n NameError indica que una variable o\nnombre de funci\u00f3n no es conocido por Python.\nLa mayor\u00eda de las veces, esto se debe a un error ortogr\u00e1fico.\nSin embargo, a veces es porque el nombre se utiliza\nantes de ser definido o de recibir un valor.

    \n

    En su programa, no existe ning\u00fan objeto con el nombre car.\nEl builtin de Python chr tiene un nombre similar.

    ", "tail": "" } ], @@ -1783,7 +1783,7 @@ "passed": true, "result": [ { - "text": " print(1 + 2 = 3)\n ^\nSyntaxError: expression cannot contain assignment, perhaps you meant \"==\"?\nen la l\u00ednea 1\n\nA `SyntaxError` occurs when Python cannot understand your code.\n\nYou likely called a function with a named argument:\n\n a_function(invalid=something) \n\nwhere `invalid` is not a valid variable name in Python\neither because it starts with a number, or is a string,\nor contains a period, etc.\n\n\n", + "text": " print(1 + 2 = 3)\n ^\nSyntaxError: expression cannot contain assignment, perhaps you meant \"==\"?\nen la l\u00ednea 1\n\nUn `SyntaxError` ocurre cuando Python no puede entender tu c\u00f3digo.\n\nEs probable que hayas llamado a una funci\u00f3n con un argumento con nombre:\n\n unaa_funci\u00f3n(inv\u00e1lido=algo) \n\ndonde `inv\u00e1lido` no es un nombre de variable v\u00e1lido en Python\nya sea porque comienza con un n\u00famero, o es una cadena\no contiene un punto, etc.\n\n\n", "type": "syntax_error" } ] @@ -2402,7 +2402,7 @@ ] } ], - "friendly": "

    An IndexError occurs when you try to get an item from a list,\na tuple, or a similar object (sequence), and use an index which\ndoes not exist; typically, this happens because the index you give\nis greater than the length of the sequence.

    \n

    You have tried to get the item with index 4 of palabras,\na list of length 4.\nThe valid index values of palabras are integers ranging from\n-4 to 3.

    ", + "friendly": "

    Un IndexError se produce cuando se intenta obtener un elemento de una lista\nuna tupla, o un objeto similar (secuencia), y utiliza un \u00edndice que\nno existe; normalmente, esto ocurre porque el \u00edndice que se da\nes mayor que la longitud de la secuencia.

    \n

    Ha intentado obtener el elemento con \u00edndice 4 de palabras,\nuna list de longitud 4.\nLos valores de \u00edndice v\u00e1lidos de palabras son n\u00fameros enteros que van desde\n-4 a 3.

    ", "tail": "" } ], @@ -2557,7 +2557,7 @@ ] } ], - "friendly": "

    An IndexError occurs when you try to get an item from a list,\na tuple, or a similar object (sequence), and use an index which\ndoes not exist; typically, this happens because the index you give\nis greater than the length of the sequence.

    \n

    You have tried to get the item with index 4 of indices,\nrange object of length 4.\nThe valid index values of indices are integers ranging from\n-4 to 3.

    ", + "friendly": "

    Un IndexError se produce cuando se intenta obtener un elemento de una lista\nuna tupla, o un objeto similar (secuencia), y utiliza un \u00edndice que\nno existe; normalmente, esto ocurre porque el \u00edndice que se da\nes mayor que la longitud de la secuencia.

    \n

    Ha intentado obtener el elemento con \u00edndice 4 de indices,\nrange object de longitud 4.\nLos valores de \u00edndice v\u00e1lidos de indices son n\u00fameros enteros que van desde\n-4 a 3.

    ", "tail": "" } ], @@ -2939,7 +2939,7 @@ ] } ], - "friendly": "

    A TypeError is usually caused by trying\nto combine two incompatible types of objects,\nby calling a function with the wrong type of object,\nor by trying to do an operation not allowed on a given type of object.

    \n

    The parenthesis () following f are interpreted\nby Python as a function call for f.\nHowever, f is not a function but an object of type str.

    ", + "friendly": "

    Un TypeError suele producirse al intentar\ncombinar dos tipos de objetos incompatibles,\npor llamar a una funci\u00f3n con el tipo de objeto equivocado,\no por intentar realizar una operaci\u00f3n no permitida en un tipo de objeto determinado.

    \n

    Los par\u00e9ntesis () que siguen a f son interpretados\npor Python como una llamada a una funci\u00f3n para f.\nSin embargo, f no es una funci\u00f3n sino un objeto de tipo str.

    ", "tail": "" } ], @@ -3023,7 +3023,7 @@ ] } ], - "friendly": "

    A TypeError is usually caused by trying\nto combine two incompatible types of objects,\nby calling a function with the wrong type of object,\nor by trying to do an operation not allowed on a given type of object.

    \n

    No information is known about this exception.\nPlease report this example to\nhttps://github.com/friendly-traceback/friendly-traceback/issues/new\nIf you are using a REPL, use www('bug') to do so.

    \n

    If you are using the Friendly console, use www() to\ndo an Internet search for this particular case.

    ", + "friendly": "

    Un TypeError suele producirse al intentar\ncombinar dos tipos de objetos incompatibles,\npor llamar a una funci\u00f3n con el tipo de objeto equivocado,\no por intentar realizar una operaci\u00f3n no permitida en un tipo de objeto determinado.

    \n

    No se conoce ninguna informaci\u00f3n sobre esta excepci\u00f3n.\nPor favor, informe de este ejemplo a\nhttps://github.com/friendly-traceback/friendly-traceback/issues/new\nSi est\u00e1 utilizando un REPL, utilice www('bug') para hacerlo.

    \n

    Si est\u00e1 utilizando la consola Friendly, utilice www() para\nhacer una b\u00fasqueda en Internet para este caso en particular.

    ", "tail": "" } ], @@ -3100,7 +3100,7 @@ ] } ], - "friendly": "

    An AttributeError occurs when the code contains something like\n object.x\nand x is not a method or attribute (variable) belonging to object.

    \n

    The object palabra has no attribute named append.\nThe following are some of its known attributes:\ncapitalize, casefold, center, count, encode, endswith, expandtabs, find, format, ....

    ", + "friendly": "

    Un AttributeError ocurre cuando el c\u00f3digo contiene algo como\n objeto.x\ny x no es un m\u00e9todo o atributo (variable) perteneciente al objeto.

    \n

    Un objeto de tipo palabra no tiene ning\u00fan atributo llamado append.\nA continuaci\u00f3n se detallan algunos de sus atributos conocidos:\ncapitalize, casefold, center, count, encode, endswith, expandtabs, find, format, ....

    ", "tail": "" } ], @@ -3633,7 +3633,7 @@ "variables": [] } ], - "friendly": "

    An AttributeError occurs when the code contains something like\n object.x\nand x is not a method or attribute (variable) belonging to object.

    \n

    The object 'Python' has no attribute named append.\nThe following are some of its known attributes:\ncapitalize, casefold, center, count, encode, endswith, expandtabs, find, format, ....

    ", + "friendly": "

    Un AttributeError ocurre cuando el c\u00f3digo contiene algo como\n objeto.x\ny x no es un m\u00e9todo o atributo (variable) perteneciente al objeto.

    \n

    Un objeto de tipo 'Python' no tiene ning\u00fan atributo llamado append.\nA continuaci\u00f3n se detallan algunos de sus atributos conocidos:\ncapitalize, casefold, center, count, encode, endswith, expandtabs, find, format, ....

    ", "tail": "" } ], @@ -3881,7 +3881,7 @@ ] } ], - "friendly": "

    An IndexError occurs when you try to get an item from a list,\na tuple, or a similar object (sequence), and use an index which\ndoes not exist; typically, this happens because the index you give\nis greater than the length of the sequence.

    \n

    You have tried to get the item with index 4 of numeros,\na list of length 4.\nThe valid index values of numeros are integers ranging from\n-4 to 3.

    ", + "friendly": "

    Un IndexError se produce cuando se intenta obtener un elemento de una lista\nuna tupla, o un objeto similar (secuencia), y utiliza un \u00edndice que\nno existe; normalmente, esto ocurre porque el \u00edndice que se da\nes mayor que la longitud de la secuencia.

    \n

    Ha intentado obtener el elemento con \u00edndice 4 de numeros,\nuna list de longitud 4.\nLos valores de \u00edndice v\u00e1lidos de numeros son n\u00fameros enteros que van desde\n-4 a 3.

    ", "tail": "" } ], @@ -4004,7 +4004,7 @@ "passed": true, "result": [ { - "text": " print('Alice's Diner')\n ^\nSyntaxError: invalid syntax\nen la l\u00ednea 1\n\nA `SyntaxError` occurs when Python cannot understand your code.\n\nI suspect that you were trying to use a quote character inside a string\nthat was enclosed in quotes of the same kind.\nPerhaps you should have escaped the inner quote character:\n\n print('Alice\\'s Diner')\n ^^\n\n\n", + "text": " print('Alice's Diner')\n ^\nSyntaxError: invalid syntax\nen la l\u00ednea 1\n\nUn `SyntaxError` ocurre cuando Python no puede entender tu c\u00f3digo.\n\nI suspect that you were trying to use a quote character inside a string\nthat was enclosed in quotes of the same kind.\nPerhaps you should have escaped the inner quote character:\n\n print('Alice\\'s Diner')\n ^^\n\n\n", "type": "syntax_error" } ] @@ -4189,7 +4189,7 @@ ] } ], - "friendly": "

    A TypeError is usually caused by trying\nto combine two incompatible types of objects,\nby calling a function with the wrong type of object,\nor by trying to do an operation not allowed on a given type of object.

    \n

    You tried to concatenate (add) two different types of objects:\na string (str) and an integer (int).

    ", + "friendly": "

    Un TypeError suele producirse al intentar\ncombinar dos tipos de objetos incompatibles,\npor llamar a una funci\u00f3n con el tipo de objeto equivocado,\no por intentar realizar una operaci\u00f3n no permitida en un tipo de objeto determinado.

    \n

    Has intentado concatenar (sumar) dos tipos de objetos diferentes:\nun string (str) y un n\u00famero entero (int).

    ", "tail": "" } ], @@ -4337,7 +4337,7 @@ "variables": [] } ], - "friendly": "

    A TypeError is usually caused by trying\nto combine two incompatible types of objects,\nby calling a function with the wrong type of object,\nor by trying to do an operation not allowed on a given type of object.

    \n

    You tried to add two incompatible types of objects:\nan integer (int) and a string (str).

    ", + "friendly": "

    Un TypeError suele producirse al intentar\ncombinar dos tipos de objetos incompatibles,\npor llamar a una funci\u00f3n con el tipo de objeto equivocado,\no por intentar realizar una operaci\u00f3n no permitida en un tipo de objeto determinado.

    \n

    Has intentado a\u00f1adir dos tipos de objetos incompatibles:\nun n\u00famero entero (int) y un string (str).

    ", "tail": "" } ], @@ -4454,7 +4454,7 @@ "passed": false, "result": [ { - "text": " 3 x 4\n ^\nSyntaxError: invalid syntax\nen la l\u00ednea 2\n\nA `SyntaxError` occurs when Python cannot understand your code.\n\nCurrently, I cannot guess the likely cause of this error.\nTry to examine closely the line indicated as well as the line\nimmediately above to see if you can identify some misspelled\nword, or missing symbols, like (, ), [, ], :, etc.\n\nUnless your code uses type annotations, which are beyond our scope,\nif you think that this is something which should be handled\nby friendly, please report this case to\nhttps://github.com/aroberge/friendly/issues\n\n\n\n", + "text": " 3 x 4\n ^\nSyntaxError: invalid syntax\nen la l\u00ednea 2\n\nUn `SyntaxError` ocurre cuando Python no puede entender tu c\u00f3digo.\n\nActualmente, no puedo detectar la causa probable de este error.\nIntente examinar detenidamente la l\u00ednea indicada, as\u00ed como la l\u00ednea\ninmediatamente superior para ver si puede identificar alguna palabra mal escrita\no s\u00edmbolos que falten, como (, ), [, ], :, etc.\n\nA menos que su c\u00f3digo utilice anotaciones de tipo, que est\u00e1n fuera de nuestro alcance,\nsi cree que esto es algo que deber\u00eda ser manejado\npor friendly, por favor reporte este caso a\nhttps://github.com/aroberge/friendly/issues\n\n\n\n", "type": "syntax_error" } ] @@ -6067,7 +6067,7 @@ "passed": true, "result": [ { - "text": " es_amigo = nombre == \"Alicia\" or\n ^\nSyntaxError: invalid syntax\nen la l\u00ednea 1\n\nA `SyntaxError` occurs when Python cannot understand your code.\n\nThe Python keyword `or` can only be used for boolean expressions.\nPerhaps you meant to write\n\n`es_amigo = nombre == \"Alicia\" ,`\n\n\n", + "text": " es_amigo = nombre == \"Alicia\" or\n ^\nSyntaxError: invalid syntax\nen la l\u00ednea 1\n\nUn `SyntaxError` ocurre cuando Python no puede entender tu c\u00f3digo.\n\nLa palabra clave de Python `or` s\u00f3lo puede utilizarse para expresiones booleanas.\nQuiz\u00e1s haya querido escribir\n\n`es_amigo = nombre == \"Alicia\" ,`\n\n\n", "type": "syntax_error" } ] @@ -6453,7 +6453,7 @@ "passed": true, "result": [ { - "text": " \"XOX\n ^\nSyntaxError: EOL while scanning string literal\nen la l\u00ednea 7\n\nA `SyntaxError` occurs when Python cannot understand your code.\n\nYou started writing a string with a single or double quote\nbut never ended the string with another quote on that line.\n\n\n", + "text": " \"XOX\n ^\nSyntaxError: EOL while scanning string literal\nen la l\u00ednea 7\n\nUn `SyntaxError` ocurre cuando Python no puede entender tu c\u00f3digo.\n\nHa empezado a escribir una cadena con una comilla simple o doble\npero nunca termin\u00f3 la cadena con otra comilla en esa l\u00ednea.\n\n\n", "type": "syntax_error" } ] @@ -6780,7 +6780,7 @@ "variables": [] } ], - "friendly": "

    A TypeError is usually caused by trying\nto combine two incompatible types of objects,\nby calling a function with the wrong type of object,\nor by trying to do an operation not allowed on a given type of object.

    \n

    You tried to add two incompatible types of objects:\nan integer (int) and a string (str).\nPerhaps you forgot to convert the string '34' into an integer (int).

    ", + "friendly": "

    Un TypeError suele producirse al intentar\ncombinar dos tipos de objetos incompatibles,\npor llamar a una funci\u00f3n con el tipo de objeto equivocado,\no por intentar realizar una operaci\u00f3n no permitida en un tipo de objeto determinado.

    \n

    Has intentado a\u00f1adir dos tipos de objetos incompatibles:\nun n\u00famero entero (int) y un string (str).\nTal vez haya olvidado convertir la cadena '34' en un n\u00famero entero (int).

    ", "tail": "" } ], From dd4ce0ce65a910950cab2316a1c516b135546aba Mon Sep 17 00:00:00 2001 From: Alex Hall Date: Sun, 6 Feb 2022 14:10:53 +0200 Subject: [PATCH 201/730] update spanish translations --- .../locales/es/LC_MESSAGES/futurecoder.mo | Bin 291468 -> 291490 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/translations/locales/es/LC_MESSAGES/futurecoder.mo b/translations/locales/es/LC_MESSAGES/futurecoder.mo index adcca7095920433792f345df1963ada3a9703878..d95811e03f7e7834fb68c7921c49a1ea24e2a29d 100644 GIT binary patch delta 9184 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 From 1c3ce8e55c1f521145b4b7d9e71c4be0f7e19102 Mon Sep 17 00:00:00 2001 From: Alex Hall Date: Sun, 6 Feb 2022 15:17:00 +0200 Subject: [PATCH 202/730] Configure new firebase project --- frontend/src/book/store.js | 27 +++++++++++++++++++++------ 1 file changed, 21 insertions(+), 6 deletions(-) diff --git a/frontend/src/book/store.js b/frontend/src/book/store.js index 65a87a47..3108e631 100644 --- a/frontend/src/book/store.js +++ b/frontend/src/book/store.js @@ -9,25 +9,40 @@ import pagesUrl from "./pages.json.load_by_url" import axios from "axios"; import * as terms from "../terms.json" -const firebaseApp = firebase.initializeApp({ +const firebaseConfig = { + es: { + apiKey: "AIzaSyDNpI4qJjFfRWuFqOnonuqmJGYr0Hp3Iuk", + authDomain: "futurecoder-es-latam.firebaseapp.com", + databaseURL: "https://futurecoder-es-latam-default-rtdb.firebaseio.com/", + projectId: "futurecoder-es-latam", + storageBucket: "futurecoder-es-latam.appspot.com", + messagingSenderId: "1084443780130", + appId: "1:1084443780130:web:cb507edf79f9ba131b967b", + measurementId: "G-W0ZYL2E5W5" + }, +}[process.env.REACT_APP_LANGUAGE] || { apiKey: "AIzaSyAZmDPaMC92X9YFbS-Mt0p-dKHIg4w48Ow", authDomain: "futurecoder-io.firebaseapp.com", + databaseURL: "https://futurecoder-io-default-rtdb.firebaseio.com/", projectId: "futurecoder-io", storageBucket: "futurecoder-io.appspot.com", messagingSenderId: "361930705093", appId: "1:361930705093:web:dda41fee927c949daf88ac", measurementId: "G-ZKCE9KY52F", -}); +}; + +const firebaseApp = firebase.initializeApp(firebaseConfig); + +let {databaseURL} = firebaseConfig; -let databaseUrl = `https://futurecoder-io-default-rtdb.firebaseio.com`; if (process.env.REACT_APP_USE_FIREBASE_EMULATORS && window.location.hostname === "localhost") { // firebase.database().useEmulator("localhost", 9009); - databaseUrl = "http://localhost:9009/"; + databaseURL = "http://localhost:9009/"; firebase.auth().useEmulator("http://localhost:9099/"); } let firebaseAnalytics; -export const isProduction = window.location.hostname === "futurecoder.io"; +export const isProduction = window.location.hostname.endsWith("futurecoder.io"); if (isProduction) { firebaseAnalytics = firebase.analytics(firebaseApp); } @@ -228,7 +243,7 @@ export const databaseRequest = async (method, data={}, endpoint="users") => { } const auth = await currentUser.getIdToken(); const response = await axios.request({ - url: `${databaseUrl}/${endpoint}/${currentUser.uid}.json`, + url: `${databaseURL}/${endpoint}/${currentUser.uid}.json`, params: {auth}, method, data, From 4fd56a77748970d7698efb1082b7baf520c3b5d4 Mon Sep 17 00:00:00 2001 From: Alex Hall Date: Sun, 6 Feb 2022 17:22:41 +0200 Subject: [PATCH 203/730] Note manually translated programs --- translations/get_manual_programs.py | 23 +++ .../locales/es/LC_MESSAGES/futurecoder.mo | Bin 291490 -> 291490 bytes translations/manual_programs.json | 191 ++++++++++++++++++ 3 files changed, 214 insertions(+) create mode 100644 translations/get_manual_programs.py create mode 100644 translations/manual_programs.json diff --git a/translations/get_manual_programs.py b/translations/get_manual_programs.py new file mode 100644 index 00000000..d26c7131 --- /dev/null +++ b/translations/get_manual_programs.py @@ -0,0 +1,23 @@ +from collections import defaultdict + +import polib +from pathlib import Path + +from littleutils import json_to_file + + +def main(): + this_dir = Path(__file__).parent + locales = this_dir / "locales" + result = defaultdict(dict) + + for lang_dir in locales.iterdir(): + mofile = polib.mofile(str(lang_dir / "LC_MESSAGES/futurecoder.mo")) + for entry in mofile: + if entry.msgid.endswith(".program"): + result[entry.msgid][lang_dir.name] = entry.msgstr.splitlines() + + json_to_file(result, this_dir / "manual_programs.json", indent=4, sort_keys=True) + + +main() diff --git a/translations/locales/es/LC_MESSAGES/futurecoder.mo b/translations/locales/es/LC_MESSAGES/futurecoder.mo index d95811e03f7e7834fb68c7921c49a1ea24e2a29d..9ed9f52e70eb757a6a9f7189583731fbbf6a192d 100644 GIT binary patch delta 38 tcmZ4VRB+K#!G Date: Sun, 6 Feb 2022 17:24:22 +0200 Subject: [PATCH 204/730] Update spanish translations --- tests/golden_files/es/test_transcript.json | 12 ++++++------ .../locales/es/LC_MESSAGES/futurecoder.mo | Bin 291490 -> 291484 bytes translations/manual_programs.json | 10 +++++----- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/tests/golden_files/es/test_transcript.json b/tests/golden_files/es/test_transcript.json index 51571997..d4b7edb0 100644 --- a/tests/golden_files/es/test_transcript.json +++ b/tests/golden_files/es/test_transcript.json @@ -2127,7 +2127,7 @@ { "page": "Introducci\u00f3n a las Listas", "program": [ - "palabras = ['Esta', 'es', 'una', 'lista']", + "palabras = ['Esto', 'es', 'una', 'lista']", "", "for palabra in palabras:", " print(palabra)" @@ -2137,7 +2137,7 @@ "passed": true, "result": [ { - "text": "Esta\nes\nuna\nlista\n", + "text": "Esto\nes\nuna\nlista\n", "type": "stdout" } ] @@ -2460,9 +2460,9 @@ "program": [ "palabras = ['Esto', 'es', 'una', 'lista']", "", - "for posicion in range(len(palabras)):", - " print(posicion)", - " print(palabras[posicion])" + "for indice in range(len(palabras)):", + " print(indice)", + " print(palabras[indice])" ], "response": { "message": "", @@ -2626,7 +2626,7 @@ { "page": "Recuperando elementos en una posici\u00f3n, range() y len().", "program": [ - "palabras = ['Esta', 'es', 'una', 'lista']", + "palabras = ['Esto', 'es', 'una', 'lista']", "print(len(palabras))" ], "response": { diff --git a/translations/locales/es/LC_MESSAGES/futurecoder.mo b/translations/locales/es/LC_MESSAGES/futurecoder.mo index 9ed9f52e70eb757a6a9f7189583731fbbf6a192d..9d5d4cc3fb80c4ea949aa8d3d29016fbac0de99b 100644 GIT binary patch delta 6645 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 delta 6644 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 b=0V9BkKQ%8kKVOkr@Hdmxk1U^JE8vtw-S72 diff --git a/translations/manual_programs.json b/translations/manual_programs.json index 71fce899..3eba241d 100644 --- a/translations/manual_programs.json +++ b/translations/manual_programs.json @@ -55,9 +55,9 @@ "es": [ "palabras = ['Esto', 'es', 'una', 'lista']", "", - "for posicion in range(len(palabras)):", - " print(posicion)", - " print(palabras[posicion])" + "for indice in range(len(palabras)):", + " print(indice)", + " print(palabras[indice])" ] }, "pages.GettingElementsAtPosition.steps.using_len_first_time.program": { @@ -66,7 +66,7 @@ "print(len(words))" ], "es": [ - "palabras = ['Esta', 'es', 'una', 'lista']", + "palabras = ['Esto', 'es', 'una', 'lista']", "print(len(palabras))" ] }, @@ -100,7 +100,7 @@ " print(word)" ], "es": [ - "palabras = ['Esta', 'es', 'una', 'lista']", + "palabras = ['Esto', 'es', 'una', 'lista']", "", "for palabra in palabras:", " print(palabra)" From 09c27d687df7dde8ef51a6335e4a05864f4fc787 Mon Sep 17 00:00:00 2001 From: Alex Hall Date: Mon, 7 Feb 2022 13:37:04 +0200 Subject: [PATCH 205/730] Update spanish translations --- tests/golden_files/es/test_transcript.json | 8 ++++---- .../locales/es/LC_MESSAGES/futurecoder.mo | Bin 291484 -> 291467 bytes 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/golden_files/es/test_transcript.json b/tests/golden_files/es/test_transcript.json index d4b7edb0..fb0766c8 100644 --- a/tests/golden_files/es/test_transcript.json +++ b/tests/golden_files/es/test_transcript.json @@ -3997,14 +3997,14 @@ { "page": "Comillas simples y dobles en las cadenas", "program": [ - "print('Alice's Diner')" + "print('Ese es el perro'e Juan')" ], "response": { "message": "", "passed": true, "result": [ { - "text": " print('Alice's Diner')\n ^\nSyntaxError: invalid syntax\nen la l\u00ednea 1\n\nUn `SyntaxError` ocurre cuando Python no puede entender tu c\u00f3digo.\n\nI suspect that you were trying to use a quote character inside a string\nthat was enclosed in quotes of the same kind.\nPerhaps you should have escaped the inner quote character:\n\n print('Alice\\'s Diner')\n ^^\n\n\n", + "text": " print('Ese es el perro'e Juan')\n ^\nSyntaxError: invalid syntax\nen la l\u00ednea 1\n\nUn `SyntaxError` ocurre cuando Python no puede entender tu c\u00f3digo.\n\nI suspect that you were trying to use a quote character inside a string\nthat was enclosed in quotes of the same kind.\nPerhaps you should have escaped the inner quote character:\n\n print('Ese es el perro\\'e Juan')\n ^^\n\n\n", "type": "syntax_error" } ] @@ -4014,14 +4014,14 @@ { "page": "Comillas simples y dobles en las cadenas", "program": [ - "print(\"Alice's Diner\")" + "print(\"Ese es el perro'e Juan\")" ], "response": { "message": "", "passed": true, "result": [ { - "text": "Alice's Diner\n", + "text": "Ese es el perro'e Juan\n", "type": "stdout" } ] diff --git a/translations/locales/es/LC_MESSAGES/futurecoder.mo b/translations/locales/es/LC_MESSAGES/futurecoder.mo index 9d5d4cc3fb80c4ea949aa8d3d29016fbac0de99b..a69af208bcf8cb9f4bbd8c1bdad980d01f12fade 100644 GIT binary patch delta 11811 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 YcU*LAN`uVKX#4-u_LM`}oO6Bu56u(GH~;_u delta 11784 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 Date: Thu, 10 Feb 2022 12:24:42 +0200 Subject: [PATCH 206/730] Update spanish translations --- README.md | 11 ++++++----- frontend/src/RunCode.js | 2 +- generate.sh | 2 +- 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 953eb4ec..ee4a0c7c 100644 --- a/README.md +++ b/README.md @@ -134,16 +134,17 @@ Several debuggers are provided, including [snoop](https://github.com/alexmojaki/ ## Running locally -1. Install Python 3.9 and [poetry](https://python-poetry.org/docs/#installation). -2. Run `poetry install` to install Python dependencies. -3. Run `poetry run python -m core.generate_static_files`. -4. In the `frontend` folder: +1. Fork this repo, `git clone` it, and enter the top-level `futurecoder` folder. +2. Install Python 3.9 and [poetry](https://python-poetry.org/docs/#installation). +3. Run `poetry install` to install Python dependencies. +4. Run `./generate.sh` to generate various static files from Python used by the frontend, and run tests. Repeat this step whenever you change Python files. +5. In the `frontend` folder: 1. Ensure you have version 14.15.4 (lts/fermium) of `node` and version 7.5.2 of `npm`. 2. Run `npm ci` to download dependencies. 3. Run `npm start` to start the frontend development server. -5. Go to http://localhost:3000/course/ +6. Go to http://localhost:3000/course/ To learn more about the system, see the [contributing guide](how_to_contribute.md). diff --git a/frontend/src/RunCode.js b/frontend/src/RunCode.js index ee6c9322..7984d77a 100644 --- a/frontend/src/RunCode.js +++ b/frontend/src/RunCode.js @@ -227,7 +227,7 @@ export const runCode = async ({code, source}) => { databaseRequest("POST", { entry, result: { - messages: data.messages.map(m => _.truncate(m, {length: 1000})), + messages: data.messages?.map(m => _.truncate(m, {length: 1000})), output: _.truncate(data.output, {length: 1000}), }, state: { diff --git a/generate.sh b/generate.sh index 79f2afc4..99f471d0 100755 --- a/generate.sh +++ b/generate.sh @@ -6,7 +6,7 @@ poetry run python -m translations.generate_po_file export FIX_CORE_IMPORTS=1 export FIX_TESTS=1 -for lang in es en +for lang in ${FUTURECODER_LANGUAGES:-en} do export FUTURECODER_LANGUAGE=$lang poetry run python -m core.generate_static_files From e1e2a2ab16140f725fba9719d0fbf7d15c7c6d90 Mon Sep 17 00:00:00 2001 From: Alex Hall Date: Thu, 10 Feb 2022 12:25:52 +0200 Subject: [PATCH 207/730] clarify README --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index ee4a0c7c..8dd9dd7d 100644 --- a/README.md +++ b/README.md @@ -137,7 +137,7 @@ Several debuggers are provided, including [snoop](https://github.com/alexmojaki/ 1. Fork this repo, `git clone` it, and enter the top-level `futurecoder` folder. 2. Install Python 3.9 and [poetry](https://python-poetry.org/docs/#installation). 3. Run `poetry install` to install Python dependencies. -4. Run `./generate.sh` to generate various static files from Python used by the frontend, and run tests. Repeat this step whenever you change Python files. +4. Run `./generate.sh`. This will generate various static files from Python used by the frontend and run some tests. Repeat this step whenever you change Python files. 5. In the `frontend` folder: 1. Ensure you have version 14.15.4 (lts/fermium) of `node` and version 7.5.2 of `npm`. From 51eea8e663de48181504ac87f72ea86d9a8bfead Mon Sep 17 00:00:00 2001 From: Alex Hall Date: Thu, 10 Feb 2022 12:35:15 +0200 Subject: [PATCH 208/730] Service worker instructions --- README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 8dd9dd7d..953c9b4e 100644 --- a/README.md +++ b/README.md @@ -143,7 +143,9 @@ Several debuggers are provided, including [snoop](https://github.com/alexmojaki/ 2. Run `npm ci` to download dependencies. - 3. Run `npm start` to start the frontend development server. + 3. For some browsers, especially Safari, you will need to run `npm run build` and then copy `service-worker.js` from the `build` folder to the `public` folder. + + 4. Run `npm start` to start the frontend development server. 6. Go to http://localhost:3000/course/ To learn more about the system, see the [contributing guide](how_to_contribute.md). From c8e6da14409b0063b89aafe5a4347bf3f20a4226 Mon Sep 17 00:00:00 2001 From: Alex Hall Date: Sat, 12 Feb 2022 13:12:26 +0200 Subject: [PATCH 209/730] sync-message 0.0.7 --- frontend/package-lock.json | 6 +++--- frontend/package.json | 2 +- frontend/src/RunCode.js | 25 ++++++++----------------- frontend/src/Worker.js | 4 ++-- 4 files changed, 14 insertions(+), 23 deletions(-) diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 934793d0..f74c70ed 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -15837,9 +15837,9 @@ "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==" }, "sync-message": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/sync-message/-/sync-message-0.0.3.tgz", - "integrity": "sha512-D3OuvsLbLoTXAwGute+BjR5xNExqe4Wqkwk2sGOZGBCIT73MuZCSROJpqzhao73tByherNEypnYaRK/lKeSp1w==" + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/sync-message/-/sync-message-0.0.7.tgz", + "integrity": "sha512-twxYOlWDxGvMX5WahdOfsbzf3KNzxrAm3bQ+Bn1A9MDJDHlM2LxaI7+Azi2WX3NrqoPGpKXBs1H0T9ARiaTzQQ==" }, "table": { "version": "6.7.0", diff --git a/frontend/package.json b/frontend/package.json index c4b82692..7f4735a7 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -36,7 +36,7 @@ "redux-logger": "^3.0.6", "redux-thunk": "^2.3.0", "sass": "^1.32.8", - "sync-message": "0.0.3" + "sync-message": "0.0.7" }, "scripts": { "start": "craco start", diff --git a/frontend/src/RunCode.js b/frontend/src/RunCode.js index 7984d77a..641c312d 100644 --- a/frontend/src/RunCode.js +++ b/frontend/src/RunCode.js @@ -18,7 +18,7 @@ import localforage from "localforage"; import {animateScroll} from "react-scroll"; import React from "react"; import * as Sentry from "@sentry/react"; -import {makeAtomicsChannel, makeServiceWorkerChannel} from "sync-message"; +import {makeChannel, writeMessage} from "sync-message"; let worker, workerWrapper; @@ -29,19 +29,10 @@ function initWorker() { initWorker(); -const channelPromise = (async () => { - if (typeof SharedArrayBuffer !== "undefined") { - return makeAtomicsChannel(); - } else { - await navigator.serviceWorker.register("./service-worker.js"); - const result = await makeServiceWorkerChannel({timeout: 1000}); - if (!result) { - // TODO what if this doesn't work? - window.location.reload(); - } - return result; - } -})(); +const channel = makeChannel({serviceWorker: {scope: "/course/"}}); +if (channel?.type === "serviceWorker") { + navigator.serviceWorker.register("/course/service-worker.js", {scope: "/course/"}); +} let interruptBuffer = null; if (typeof SharedArrayBuffer != "undefined") { @@ -73,7 +64,7 @@ export const runCode = async ({code, source}) => { if (awaitingInput) { const messageId = awaitingInput; awaitingInput = false; - (await channelPromise).writeInput({text: code}, messageId); + await writeMessage(channel, {text: code}, messageId); bookSetState("processing", true); return; } @@ -116,7 +107,7 @@ export const runCode = async ({code, source}) => { if (awaitingInput) { const messageId = awaitingInput; awaitingInput = false; - (await channelPromise).writeInput({interrupted: true}, messageId); + await writeMessage(channel, {interrupted: true}, messageId); } else { doInterrupt(); } @@ -162,7 +153,7 @@ export const runCode = async ({code, source}) => { interruptPromise, workerWrapper.runCode( entry, - (await channelPromise).channel, + channel, interruptBuffer, Comlink.proxy(outputCallback), Comlink.proxy(inputCallback), diff --git a/frontend/src/Worker.js b/frontend/src/Worker.js index 9fa8e231..690a2b33 100644 --- a/frontend/src/Worker.js +++ b/frontend/src/Worker.js @@ -5,7 +5,7 @@ import * as Comlink from 'comlink'; import pythonCoreUrl from "./python_core.tar.load_by_url" import loadPythonString from "!!raw-loader!./load.py" -import {readChannel, syncSleep, uuidv4} from "sync-message"; +import {readMessage, syncSleep, uuidv4} from "sync-message"; async function getPackageBuffer() { const response = await fetch(pythonCoreUrl); @@ -69,7 +69,7 @@ async function runCode(entry, channel, interruptBuffer, outputCallback, inputCal const fullInputCallback = (data) => { const messageId = uuidv4(); inputCallback(messageId, toObject(data)); - const result = readChannel(channel, messageId).text; + const result = readMessage(channel, messageId).text; if (result == null) { return null; } From 67fd898a86b30d21ff2b79f49a5366cde334b2ca Mon Sep 17 00:00:00 2001 From: Alex Hall Date: Sat, 12 Feb 2022 14:49:07 +0200 Subject: [PATCH 210/730] Handle sync-message problems --- core/checker.py | 3 --- core/runner/runner.py | 25 +++++++++++++++++++++++++ frontend/package-lock.json | 6 +++--- frontend/package.json | 2 +- frontend/src/RunCode.js | 8 ++++++-- frontend/src/Worker.js | 26 +++++++++++++++++++------- 6 files changed, 54 insertions(+), 16 deletions(-) diff --git a/core/checker.py b/core/checker.py index 44b3bdb6..11711213 100644 --- a/core/checker.py +++ b/core/checker.py @@ -43,9 +43,6 @@ def reset(self): self.console.locals.update(assert_equal=assert_equal) - def non_str_input(self): - raise KeyboardInterrupt - runner = FullRunner() diff --git a/core/runner/runner.py b/core/runner/runner.py index 037453d5..ee11869c 100644 --- a/core/runner/runner.py +++ b/core/runner/runner.py @@ -41,3 +41,28 @@ def serialize_syntax_error(self, exc, source_code): return { "text": friendly_syntax_error(exc, self.filename), } + + def non_str_input(self): + # TODO do this in python_runner, then return early + line = self.line + self.line = "" + + if line == 1: + raise KeyboardInterrupt + elif line == 2: + raise RuntimeError( + "The service worker for reading input isn't working. " + "Try closing all futurecoder tabs, then reopening." + ) + elif line == 3: + raise RuntimeError( + "This browser doesn't support reading input. " + "Try upgrading to the most recent version or switching to a different browser, e.g. Chrome/Firefox. " + "The browser must support SharedArrayBuffer or Service Workers." + ) + else: + # TODO raise specific exception to trigger proper feedback + raise RuntimeError( + "Oops, something went wrong while reading input! " + "Please report this error!" + ) diff --git a/frontend/package-lock.json b/frontend/package-lock.json index f74c70ed..806d62b6 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -15837,9 +15837,9 @@ "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==" }, "sync-message": { - "version": "0.0.7", - "resolved": "https://registry.npmjs.org/sync-message/-/sync-message-0.0.7.tgz", - "integrity": "sha512-twxYOlWDxGvMX5WahdOfsbzf3KNzxrAm3bQ+Bn1A9MDJDHlM2LxaI7+Azi2WX3NrqoPGpKXBs1H0T9ARiaTzQQ==" + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/sync-message/-/sync-message-0.0.8.tgz", + "integrity": "sha512-2DiQIfLgf6OnBU2cNEqV38UZyMD9nUkXyaWXUPFIykdbfpXl3V5x9VmJH4s7M66IK5G1C7wY6KB9W/44E+vVvQ==" }, "table": { "version": "6.7.0", diff --git a/frontend/package.json b/frontend/package.json index 7f4735a7..3e6029ea 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -36,7 +36,7 @@ "redux-logger": "^3.0.6", "redux-thunk": "^2.3.0", "sass": "^1.32.8", - "sync-message": "0.0.7" + "sync-message": "0.0.8" }, "scripts": { "start": "craco start", diff --git a/frontend/src/RunCode.js b/frontend/src/RunCode.js index 641c312d..8d4cc1e5 100644 --- a/frontend/src/RunCode.js +++ b/frontend/src/RunCode.js @@ -31,7 +31,7 @@ initWorker(); const channel = makeChannel({serviceWorker: {scope: "/course/"}}); if (channel?.type === "serviceWorker") { - navigator.serviceWorker.register("/course/service-worker.js", {scope: "/course/"}); + navigator.serviceWorker.register("./service-worker.js"); } let interruptBuffer = null; @@ -64,7 +64,11 @@ export const runCode = async ({code, source}) => { if (awaitingInput) { const messageId = awaitingInput; awaitingInput = false; - await writeMessage(channel, {text: code}, messageId); + try { + await writeMessage(channel, {text: code}, messageId); + } catch { + return; + } bookSetState("processing", true); return; } diff --git a/frontend/src/Worker.js b/frontend/src/Worker.js index 690a2b33..d65a63e9 100644 --- a/frontend/src/Worker.js +++ b/frontend/src/Worker.js @@ -5,7 +5,7 @@ import * as Comlink from 'comlink'; import pythonCoreUrl from "./python_core.tar.load_by_url" import loadPythonString from "!!raw-loader!./load.py" -import {readMessage, syncSleep, uuidv4} from "sync-message"; +import {readMessage, ServiceWorkerError, syncSleep, uuidv4} from "sync-message"; async function getPackageBuffer() { const response = await fetch(pythonCoreUrl); @@ -67,13 +67,25 @@ async function runCode(entry, channel, interruptBuffer, outputCallback, inputCal await pyodideReadyPromise; const fullInputCallback = (data) => { - const messageId = uuidv4(); - inputCallback(messageId, toObject(data)); - const result = readMessage(channel, messageId).text; - if (result == null) { - return null; + try { + if (!channel) { + return 3; // browser not supported + } + const messageId = uuidv4(); + inputCallback(messageId, toObject(data)); + const result = readMessage(channel, messageId).text; + if (result == null) { + return 1; // interrupt + } + return result + "\n"; + } catch (e) { + if (e instanceof ServiceWorkerError) { + return 2; // suggesting closing all tabs and reopening + } else { + console.error(e); + return 4; // general error + } } - return result + "\n"; } if (interruptBuffer) { From 9bd5bcd8508883b533d56d5ce77dc59927554ace Mon Sep 17 00:00:00 2001 From: Alex Hall Date: Sat, 12 Feb 2022 15:11:16 +0200 Subject: [PATCH 211/730] interruptible sleep --- frontend/src/RunCode.js | 20 ++++++++++++++------ frontend/src/Worker.js | 12 +++++++++++- 2 files changed, 25 insertions(+), 7 deletions(-) diff --git a/frontend/src/RunCode.js b/frontend/src/RunCode.js index 8d4cc1e5..40a7d557 100644 --- a/frontend/src/RunCode.js +++ b/frontend/src/RunCode.js @@ -42,14 +42,19 @@ if (typeof SharedArrayBuffer != "undefined") { export const terminalRef = React.createRef(); let awaitingInput = false; +let sleeping = false; let pendingOutput = []; localforage.config({name: "birdseye", storeName: "birdseye"}); -function inputCallback(messageId) { - awaitingInput = messageId; - bookSetState("processing", false); - terminalRef.current.focusTerminal(); +function inputCallback(messageId, data) { + if (data.sleeping) { + sleeping = messageId; + } else { + awaitingInput = messageId; + bookSetState("processing", false); + terminalRef.current.focusTerminal(); + } } export let interrupt = () => { @@ -83,6 +88,7 @@ export const runCode = async ({code, source}) => { } awaitingInput = false; + sleeping = false; pendingOutput = []; bookSetState("processing", true); @@ -108,9 +114,10 @@ export const runCode = async ({code, source}) => { let interruptResolver; const interruptPromise = new Promise(r => interruptResolver = r); interrupt = async () => { - if (awaitingInput) { - const messageId = awaitingInput; + if (awaitingInput || sleeping) { + const messageId = awaitingInput || sleeping; awaitingInput = false; + sleeping = false; await writeMessage(channel, {interrupted: true}, messageId); } else { doInterrupt(); @@ -165,6 +172,7 @@ export const runCode = async ({code, source}) => { ]); awaitingInput = false; + sleeping = false; const {error} = data; diff --git a/frontend/src/Worker.js b/frontend/src/Worker.js index d65a63e9..99479271 100644 --- a/frontend/src/Worker.js +++ b/frontend/src/Worker.js @@ -104,7 +104,17 @@ async function runCode(entry, channel, interruptBuffer, outputCallback, inputCal }; function sleepCallback(data) { - syncSleep(toObject(data).seconds * 1000, channel); + const timeout = toObject(data).seconds * 1000; + if (!(timeout > 0 && channel)) { + return; + } + const messageId = uuidv4(); + try { + inputCallback(messageId, {sleeping: true}); + readMessage(channel, messageId, {timeout}); + } catch (e) { + console.error(e); + } } const result = check_entry(entry, fullInputCallback, fullOutputCallback, sleepCallback); From a96f8e16ee96a077b9f03c8f081f65eab64f290b Mon Sep 17 00:00:00 2001 From: Alex Hall Date: Sun, 13 Feb 2022 14:29:00 +0200 Subject: [PATCH 212/730] new poetry installer --- full_build.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/full_build.sh b/full_build.sh index bf450c2e..9cda639f 100755 --- a/full_build.sh +++ b/full_build.sh @@ -2,7 +2,7 @@ set -eux -poetry --version || curl -sSL https://raw.githubusercontent.com/sdispater/poetry/master/get-poetry.py | python +poetry --version || curl -sSL https://install.python-poetry.org | python3 - source $HOME/.poetry/env poetry install From f853f51425a7db803b55f5d7c1d119eb8d4b497e Mon Sep 17 00:00:00 2001 From: Alex Hall Date: Sun, 13 Feb 2022 14:30:06 +0200 Subject: [PATCH 213/730] new poetry installer --- full_build.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/full_build.sh b/full_build.sh index 9cda639f..b4fa4cde 100755 --- a/full_build.sh +++ b/full_build.sh @@ -3,7 +3,7 @@ set -eux poetry --version || curl -sSL https://install.python-poetry.org | python3 - -source $HOME/.poetry/env +#source $HOME/.poetry/env poetry install cd frontend From 8cafdb9b13d0b766fa45d8c9694fa054e4b5654d Mon Sep 17 00:00:00 2001 From: Alex Hall Date: Sun, 13 Feb 2022 14:31:49 +0200 Subject: [PATCH 214/730] new poetry installer --- build.sh | 2 -- ci_test.sh | 1 - full_build.sh | 1 - 3 files changed, 4 deletions(-) diff --git a/build.sh b/build.sh index 812cd7d2..c741d0d2 100755 --- a/build.sh +++ b/build.sh @@ -5,8 +5,6 @@ set -eux rm -rf dist || true mkdir -p dist/course/ -source $HOME/.poetry/env - poetry run python -m translations.generate_po_file poetry run python -m core.generate_static_files diff --git a/ci_test.sh b/ci_test.sh index 27f97ee4..9ab31aac 100755 --- a/ci_test.sh +++ b/ci_test.sh @@ -5,5 +5,4 @@ set -eux export DISPLAY=:99 chromedriver --url-base=/wd/hub & npm install -g firebase-tools -source $HOME/.poetry/env firebase emulators:exec "poetry run pytest tests" diff --git a/full_build.sh b/full_build.sh index b4fa4cde..df58c7b3 100755 --- a/full_build.sh +++ b/full_build.sh @@ -3,7 +3,6 @@ set -eux poetry --version || curl -sSL https://install.python-poetry.org | python3 - -#source $HOME/.poetry/env poetry install cd frontend From e2888d6709cbdc34cb5e43616b436e891c551935 Mon Sep 17 00:00:00 2001 From: Alex Hall Date: Sun, 13 Feb 2022 14:38:25 +0200 Subject: [PATCH 215/730] ignore _distutils_hack --- core/generate_static_files.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/core/generate_static_files.py b/core/generate_static_files.py index 3f3a9ec8..2e7ce29f 100644 --- a/core/generate_static_files.py +++ b/core/generate_static_files.py @@ -62,6 +62,10 @@ def get_roots(): relative = strip_required_prefix(f, site_packages) root = relative.split(os.path.sep)[0] + + if root == "_distutils_hack": + continue + roots.add(root) mod_names.append(module.__name__) From ad3b91d3e4d0614af53160a80d4c4f8a9444da8e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 13 Feb 2022 20:01:12 +0000 Subject: [PATCH 216/730] Bump follow-redirects from 1.14.7 to 1.14.8 in /frontend Bumps [follow-redirects](https://github.com/follow-redirects/follow-redirects) from 1.14.7 to 1.14.8. - [Release notes](https://github.com/follow-redirects/follow-redirects/releases) - [Commits](https://github.com/follow-redirects/follow-redirects/compare/v1.14.7...v1.14.8) --- updated-dependencies: - dependency-name: follow-redirects dependency-type: indirect ... Signed-off-by: dependabot[bot] --- frontend/package-lock.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 806d62b6..2fc80ef2 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -7896,9 +7896,9 @@ } }, "follow-redirects": { - "version": "1.14.7", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.7.tgz", - "integrity": "sha512-+hbxoLbFMbRKDwohX8GkTataGqO6Jb7jGwpAlwgy2bIz25XtRm7KEzJM76R1WiNT5SwZkX4Y75SwBolkpmE7iQ==" + "version": "1.14.8", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.8.tgz", + "integrity": "sha512-1x0S9UVJHsQprFcEC/qnNzBLcIxsjAV905f/UkQxbclCsoTWlacCNOpQa/anodLl2uaEKFhfWOvM2Qg77+15zA==" }, "for-in": { "version": "1.0.2", From 070b3a9ce17180775382eccf379c198d4291690b Mon Sep 17 00:00:00 2001 From: Alex Hall Date: Mon, 14 Feb 2022 22:50:07 +0200 Subject: [PATCH 217/730] Upgrade stack_data --- poetry.lock | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/poetry.lock b/poetry.lock index 3c3be366..9f7dc353 100644 --- a/poetry.lock +++ b/poetry.lock @@ -363,7 +363,7 @@ tests = ["pytest", "littleutils", "prettyprinter", "pprintpp", "pandas (>=0.24.2 [[package]] name = "stack-data" -version = "0.1.4" +version = "0.2.0" description = "Extract data from python stack frames and tracebacks for informative displays" category = "main" optional = false @@ -375,7 +375,7 @@ executing = "*" pure-eval = "*" [package.extras] -tests = ["pytest", "typeguard", "pygments", "littleutils"] +tests = ["pytest", "typeguard", "pygments", "littleutils", "cython"] [[package]] name = "toml" @@ -529,8 +529,8 @@ snoop = [ {file = "snoop-0.4.1.tar.gz", hash = "sha256:425bcc620fa77d70cd9e3f82d1c2191966956949374c0eb23dae4ed110dad9cd"}, ] stack-data = [ - {file = "stack_data-0.1.4-py3-none-any.whl", hash = "sha256:02cc0683cbc445ae4ca8c4e3a0e58cb1df59f252efb0aa016b34804a707cf9bc"}, - {file = "stack_data-0.1.4.tar.gz", hash = "sha256:7769ed2482ce0030e00175dd1bf4ef1e873603b6ab61cd3da443b410e64e9477"}, + {file = "stack_data-0.2.0-py3-none-any.whl", hash = "sha256:999762f9c3132308789affa03e9271bbbe947bf78311851f4d485d8402ed858e"}, + {file = "stack_data-0.2.0.tar.gz", hash = "sha256:45692d41bd633a9503a5195552df22b583caf16f0b27c4e58c98d88c8b648e12"}, ] toml = [ {file = "toml-0.10.1-py2.py3-none-any.whl", hash = "sha256:bda89d5935c2eac546d648028b9901107a595863cb36bae0c73ac804a9b4ce88"}, From c12b4510bc2da5707b0444e354799dbe87ce5e94 Mon Sep 17 00:00:00 2001 From: Alex Hall Date: Wed, 16 Feb 2022 12:33:03 +0200 Subject: [PATCH 218/730] Upgrade friendly-traceback --- poetry.lock | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/poetry.lock b/poetry.lock index 9f7dc353..7b075600 100644 --- a/poetry.lock +++ b/poetry.lock @@ -123,7 +123,7 @@ pyflakes = ">=2.2.0,<2.3.0" [[package]] name = "friendly-traceback" -version = "0.5.30" +version = "0.5.35" description = "Friendlier tracebacks in any language." category = "main" optional = false @@ -133,7 +133,7 @@ python-versions = ">=3.6" asttokens = ">=2.0.4" executing = ">=0.7.0" pure-eval = ">=0.2.1" -stack-data = ">=0.1.3" +stack-data = ">=0.2.0" [[package]] name = "iniconfig" @@ -446,8 +446,8 @@ flake8 = [ {file = "flake8-3.8.3.tar.gz", hash = "sha256:f04b9fcbac03b0a3e58c0ab3a0ecc462e023a9faf046d57794184028123aa208"}, ] friendly-traceback = [ - {file = "friendly-traceback-0.5.30.tar.gz", hash = "sha256:edfdab56802d0dab95cd1a66dfe7b95119d991bc63c8649477e4b55bfd79cf3d"}, - {file = "friendly_traceback-0.5.30-py3-none-any.whl", hash = "sha256:31caf436407eda23104852a35e81e7f3f953123a18b87e5a5e6d18679131f631"}, + {file = "friendly-traceback-0.5.35.tar.gz", hash = "sha256:3e93c27f7bbd97520930a079b54263e1b213371a49890a15d78fc4cbc2d17cf9"}, + {file = "friendly_traceback-0.5.35-py3-none-any.whl", hash = "sha256:2698d5e6e29d267e9bd2dd1a2899b570a8f41f5357d9014cd919777dc0e1c561"}, ] iniconfig = [ {file = "iniconfig-1.1.1-py2.py3-none-any.whl", hash = "sha256:011e24c64b7f47f6ebd835bb12a743f2fbe9a26d4cecaa7f53bc4f35ee9da8b3"}, From cd338d4bec12a434e432ba524b28640febb5495b Mon Sep 17 00:00:00 2001 From: Alex Hall Date: Wed, 16 Feb 2022 12:40:49 +0200 Subject: [PATCH 219/730] Upgrade pyodide --- frontend/src/Worker.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/frontend/src/Worker.js b/frontend/src/Worker.js index 99479271..96e176c9 100644 --- a/frontend/src/Worker.js +++ b/frontend/src/Worker.js @@ -5,7 +5,7 @@ import * as Comlink from 'comlink'; import pythonCoreUrl from "./python_core.tar.load_by_url" import loadPythonString from "!!raw-loader!./load.py" -import {readMessage, ServiceWorkerError, syncSleep, uuidv4} from "sync-message"; +import {readMessage, ServiceWorkerError, uuidv4} from "sync-message"; async function getPackageBuffer() { const response = await fetch(pythonCoreUrl); @@ -19,7 +19,7 @@ let pyodide; async function loadPyodideOnly() { console.time("importScripts pyodide") - const indexURL = 'https://cdn.jsdelivr.net/pyodide/v0.18.0/full/'; + const indexURL = 'https://cdn.jsdelivr.net/pyodide/v0.19.0/full/'; importScripts(indexURL + 'pyodide.js'); console.timeEnd("importScripts pyodide") @@ -89,7 +89,7 @@ async function runCode(entry, channel, interruptBuffer, outputCallback, inputCal } if (interruptBuffer) { - pyodide._module.setInterruptBuffer(interruptBuffer); + pyodide.setInterruptBuffer(interruptBuffer); } try { From 4669d97d3a0deeeaa24476fabd396d101c14c56c Mon Sep 17 00:00:00 2001 From: Alex Hall Date: Wed, 16 Feb 2022 12:52:27 +0200 Subject: [PATCH 220/730] Stop trying to load manifest.json --- frontend/public/index.html | 5 ----- 1 file changed, 5 deletions(-) diff --git a/frontend/public/index.html b/frontend/public/index.html index f92e1650..0d92d5d0 100644 --- a/frontend/public/index.html +++ b/frontend/public/index.html @@ -15,11 +15,6 @@ - -
    @@ -150,6 +150,96 @@

    Designed with care for beginners

    +
    + +
    @@ -159,7 +249,7 @@

    Take a peek inside!

    -
    +
    diff --git a/homepage/static/css/home.scss b/homepage/static/css/home.scss index 1702e419..99506c80 100644 --- a/homepage/static/css/home.scss +++ b/homepage/static/css/home.scss @@ -8,3 +8,41 @@ border-radius: .25rem; } } + +.badges { + display: flex; + flex-wrap: wrap; + justify-content: center; + + .badge { + border-radius: 10px; + border: 1px solid grey; + width: 288px; + padding: 5px; + margin-right: 1em; + margin-bottom: 1em; + + .center-text { + font-size: larger; + margin-bottom: 0.6em; + color: white; + } + + .flex { + display: flex; + justify-content: space-around; + } + + a { + text-decoration: none; + } + + strong { + color: white; + } + + .testimonial { + font-style: italic; + } + } +} From 6f343161c3f47087eeb4e553e9593f5b38e6228f Mon Sep 17 00:00:00 2001 From: Alex Hall Date: Sat, 19 Feb 2022 13:31:24 +0200 Subject: [PATCH 231/730] Reduce initial aos delays by a second --- homepage/index.html | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/homepage/index.html b/homepage/index.html index d0fa623c..f21075f0 100644 --- a/homepage/index.html +++ b/homepage/index.html @@ -30,7 +30,7 @@
    - @@ -372,11 +372,11 @@

    Messages d'erreur améliorés

    -

    Puzzle Parsons

    +

    Puzzle de Parsons

    - Si un étudiant est bloqué malgré les différents indices proposés, + Si un étudiant est bloqué malgré les différentes aides proposés, la solution lui est fournie dans le désordre... À lui de la réorganiser. Il peut ainsi progresser facilement sans pour autant arrêter de réfléchir ! @@ -396,11 +396,11 @@

    Puzzle Parsons

    data-aos-delay="200">
    -

    Solution Breadcrumbs

    +

    Solutions pas à pas

    En dernier ressort, les étudiants peuvent afficher une solution partiellement masquée. - Des portions de codes sont dévoilées graduellement, à eux de compélter le reste. + Des portions de codes sont dévoilées graduellement, à eux de compléter le reste

    @@ -463,18 +463,18 @@

    Vous souhaitez être informé des mises à jou

    À propos

    futurecoder est une plateforme libre et open-source permettant - à de grands débutants de découvrir Python par eux-mêmes/ + à de grands débutants de découvrir Python par eux-mêmes

    Les objectifs à long terme de futurecoder sont ambitieux :
    • Révolutionner l'apprentissage de la programmation. - Nous sommes persuadés que les plateformes d'apprentissage en ligne pourraient être bien meilleures.
    • + Nous sommes persuadés que les plateformes d'apprentissage en ligne pourraient être bien meilleures
    • Proposer les meilleurs cours possibles en permettant à chacun de participer
    • Permettre à chacun d'apprendre la programmation, quel que soit son niveau ou ses aptitudes
    Comment faire ?
    } diff --git a/frontend/src/english_terms.json b/frontend/src/english_terms.json index 6d7f9e8a..5bdc932d 100644 --- a/frontend/src/english_terms.json +++ b/frontend/src/english_terms.json @@ -1,6 +1,6 @@ { - "switch_language_label": "\uD83C\uDDE6\uD83C\uDDF7 Español", - "switch_language_url": "https://es-latam.futurecoder.io/course/", + "switch_language_label": "Français", + "switch_language_url": "https://fr.futurecoder.io/course/", "stop": "Stop", "run": "Run", "ask_for_help": "Ask for Help", diff --git a/frontend/src/img/language.png b/frontend/src/img/language.png new file mode 100644 index 0000000000000000000000000000000000000000..7f17162fb94ca7bdbdf05be6b8e6d16cf05c3a56 GIT binary patch literal 10705 zcmeHsXH-+$)^-2^=^!2HO?nba=)FttT?ipSfY5spq*oCTln#P`fYN(Mn$mlbjv_^x zRB67^bMC$8jPLz($N1iVCu1bpd#z_abIxbYwZ>j+$7pLR6X4R|0ssI4RTTwY)W6KH z?_Dg^Zz;lU82}(*^w&4`)P?#my1KjABAnoio_?-yMz}A+769;Fcx{Hr*yW19sW3RX zhyM~G8ox3tzV+oi32?tSnP$JNwe+(X72fuieTeej&)bH{pR4^0{j$ZUU5Z~1e~4^Q zdv!;-#^5`Bh__#_+npx1vk#di;Kh~{&S%ZyB%6Ydj@fF zO1rktMGuWKL3cpcWgl1rT`$ViKR@x+>RYF=G*OF?Ti)KjjCoelfQYRKqc?1ldUHOz zJ#AW?BR>?EymWedCdPTS%=PM$P8#}nVsuwoAE9#cD(H5vEt1c%k85H(&q0{7E{!=C z#J53my(L3DOh?~Aq37$T*ov-gVO8h(k~=hmTp;x)uSX8bW9kyr7mYgP;$uK35%auxjD?x*JfHlC$f@$91%CRS2Jq zyvv&+;j@tCduuXJ9LC!p492I>3F4ZL4V~RRjoNdtk{vX)rHs*bqSv!2b7luw+lM`& zICyXIyut&$t(F%0m&NPYNkk<;S(1iP9LL=jBz!bu%U|VF?h?4Nbdjk7Y0?yUVre zvj5jMBB@I#dcL(A%P3U5PPE!}kUUvt+T`J=McjAdTYCUdc>A$c$4BOUdz+lW6@siBM~|!(GI@ ztwB|9$6>QJt{M34{tXUB(obg?^qS2Nt3wmEw9Q#qx@bKL#1WtvyREe>cL zye2vNo_##0--0CAE;7VZdq%%tZ-1keCgZ2TNEg@=G|BbUk<6{?&!}>ysuHnhLcGV- zX!_B!!!&te$blova(a?o)IKd71iQO+5wakWg}sB`m=|fEZ$p=tyL^ns`GcwQF$;Fv zsgv(r1#c-I?nGy88Cwh)IWq-z?t3{OtX>yQFB@Ano!Hm7eePrAV5n&@t?JVgH*yS7 z9JyqMQ{aGndP2=Y$=X<}1ig$*gfgJ+^pdMhm4uPq2Vz-(-Q-LrPwr9^^MQHgt))0` zH|fQCrS6aB6g^h=(xi^^-W8aa9n#AreF1;5e<1iQgju~*k8VaUz2G&=-IhCckH02i zY4)&~t@%)k7L|A6bA!CmKGaL`Xrv98h6-DI0nFDpsLJgyI={a<@IU!>^-Q;6frprK zUSWO>L2o&ML(r9UA-iUkA}HQ6w3EvG#HCpwHKJR8OB9o*~uyKee#*+1?w1tFEqsj*W+37HmwXG3nOsWt6ILD3@go= z##l`8?RTNz4`h525Rfth_LRf5v8>Y^+RppUQ_#$0Oi2{HXSRJx78n2Oi%W><)pHA|m66K} z7#W+zSKm7#1d2X-+~2rL9sh)n1(=efT^5QlrbDgp1lv-9#JjHzC#H=yP%Z8$m41?5 z@<{&OwNwkU3uGkoq*75giB2d<4%>Wi0&UFQS-rWg>$SGgyz}U`SD#4ywsoDiTihE4 z2ESEqnftokyENY~RJ>=nB6`#1s3m7-|442r>7}9^p&#aY-5K<4z-beG_X2^f+#SrB zA{(b@CThO%lq#PJ^#+@_yVO54FW4n&n4iEJVIP86V{7>pTldmmwFoGNuX5}0wAY+> zX7<$C@eP`*^@}-^ zheh@a@AoZVy+fLBccvQL;~0-oUT9abEI&}AE&s-M<=R)Za@iQ7(NZ!yLr|LZ#xQOhrbegubp*Hc;JG;hwn^)`6!AJ5m3u;k$p&A)l zff%GwlV?!Ld~yBbMy*%;0gIg^=OG~;`)N?_$i>z;*9kJ!kjhj z&~;A?m7lp#?+>vq+4E10jS@sCGl`!Z*FTT&w&BcHYJ{%g7UN|)sq71+H7X|8zplS` zI+R8q%y4En^}fX1vd9E670pg*cXd$h)I&tUL!POh?Z(Z$agd?R=oYAT&0vhcI3JPmIW_0;5Z^g>s zyx`qW78A6`IYt%*>(XPicaIInVbUirrV}yD{vJbR5GkxW8|fkw$O^kBo79!~L>>pM{(=DX#SlYaZ~FM0{1L)kiQTua%A3SxMaO zg&C1gS{H0*rbW*5*imbRRA{a^Lsm2zf^*bK!n(pdF#RyLrqCpIBvG)EKW%<_TE@Ge zYf7K3rlOT?S{d)Nwt4pD_!lmvGoO)yDPeNLKRGe*~6&Mw6 zNDl+Ia@Iwq(GzIFr&KAP$0;YWch5B$RtLO!sF=)h#Az*GCYJ58W;z{Y`m6<2#M!b~ z)txu=uK+p-&- zJKWl&W)FU|-qb`oB9?xs;GcLnc=R$iDbq%FDL#S<9O|ny?BP}zj(gls)upziE6J42 zjE8Y_7;lJIT{15~R805w2TV$lDt%IAk^Np=fx64Nw&zwgCU)~BawO2=Ni=4D& zN4_nNYNP8f+63CKS%r16G+nWqHMK^h2d2H6gzhM~OYYn5xl(N(wTr|%v6L5~-LO}| z`qQkBGOgnu>m*Fi6H|BdO7Ax0Rtf8Ay(f3^e%?3Mm*CT|w(u%_u~F#$>dn`Npj*q1 zNhQv=St0D1DVflCvKjIo^th8UlelY_!Pe1Kzm&pduh+{f;1TAm<8gs>e~yzki0=ym zYYyM5y?$nNj4_Z>5sD_FZsr~#uuKK#W!)eiqH`j^~S8iJcSZ7MipT3Yd*gaKcEjYC6$7$EeiwDR12BCfN zwONe--U5|A_($`d@0zbZ3+~JPSkxlyun=qu_TD$ba2p%cSn>-mpPf@(QL5&~S`qAJ z3h7t5K{#I)kKQNCJ$q2t`n@7DZ}6Ugu+$8sCP1y*jL*yN`!|dpiA&LhBo=(^Vu9SW zhQ;W|hb(-vuk9uq?6)oT38&l~hn$zd`}Wi+*`Bq@I0XfDIZr>s2788_Z1K<9y=ou8 zjN$dx^`iGv{Z zGr)o5m)CFSa|$k;tRC7UaFr7qQ{|oNh|Gl zC4GB7qU`*s*~G@Tg_4@N$CEMH;`D8aasnNBxM>T)3y0jL8el@uWqXbErCy>r5@YSD z>?L7%wO=ZLJO(QP_C%Ja!~zk6>A)tnDwT0R)un#tQ8UN6p}6ul-ACL5%AW$AJC8_` z=gS)`@5kOE<&$Q(h&yr5Gm#8SpZLhI`wnOKFBf7OS37dk7^eeoo90iD#R?O4$*ar} zi((x|F4<-dYp0#_-$lZ(K+Yb?R5py8*ah)gMix z`i*NMJSKdPU%NmuR_Xl0uyQlzywg8V^|TEtNM}-n_aDWRj97?rDs^y$-zF~)_o&hk zrY*6=kHoC)#kWv=PKYCr5V*M_6faBZE7)onZp`&}JGtr`$$0XnDv@GhMuu6I;{X_Z zL@2(0VJ>m3arS6oX+7Foq0~XK-0lEYD^&V;Ko|BZ4gT;oAD7}#2L|#rpvEjpGw~esJ5?sX0TLhxd5Lwsyh3*SH!4^?8Ngu`~ zCPhd1k5t)JV-h!#>KlMdIX8t-wfdLw@4`~;TMq-4 z!4eqJ6Ah~dKqln<=qBf1w5n~USIephwc{;Bl3mlayGVyAil9J6r64C zD+})hvIlBjik`eqxxFQ3Yr=r z{YnhqZ#rAH0&}JIFcs)c_FOb$^Js5tZvwl?pJY~eqGxl;Hk%&&j8 z_7>q_DKWaE&QNF&sIwAd4RtY?3z83N<6;fx^F_L%&QbsX329$fD9jP=$!HC?LpVz^ zAGCBZGa_sxnT>=rKpL*{aC?M`zdKydUsE6E?+6pMVV0J{mGBiq5g_57P)1**le34I zuO#ztUNO}5uVx@K<8O$kqa?GjhBl+Ti#wcAkWY{g#H;9w@aAWh!ex|jx3Lw|RZ#kq z0(B?JZ13smDh34l`1tVo2=KYM+X2C%qM|?$KaiiF7lq*U@N@Qr`tmw^u>7LhbGx&py`ARrP6{HukB zr=mBCm}gdc$pgJ3`t0(FL=II@`ff^ZU<&`d2ℜF(R8;CGe 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 literal 0 HcmV?d00001 diff --git a/homepage/index.html b/homepage/index.html index ed4eb42e..11c1c56c 100644 --- a/homepage/index.html +++ b/homepage/index.html @@ -31,14 +31,16 @@
    -
    @@ -127,11 +129,6 @@

    Designed with care for beginners

    Just code
    -