chore: move docs to its own project (#53882)

This commit is contained in:
Mrugesh Mohapatra
2024-02-26 20:32:28 +05:30
committed by GitHub
parent 074af6effb
commit 8094047966
383 changed files with 21 additions and 71846 deletions
-265
View File
@@ -1,265 +0,0 @@
name: i18n - Download Docs
on:
workflow_dispatch:
schedule:
# runs Monday and Wednesday at 12:15 PM UTC
- cron: '15 12 * * 1,3'
env:
GITHUB_TOKEN: ${{ secrets.CROWDIN_CAMPERBOT_PAT }}
CROWDIN_PROJECT_ID: ${{ secrets.CROWDIN_PROJECT_ID_DOCS }}
CROWDIN_PERSONAL_TOKEN: ${{ secrets.CROWDIN_CAMPERBOT_SERVICE_TOKEN }}
CROWDIN_API_URL: 'https://freecodecamp.crowdin.com/api/v2/'
jobs:
i18n-download-docs-translations:
name: Docs
runs-on: ubuntu-22.04
steps:
- name: Checkout Source Files
uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3
with:
token: ${{ secrets.CROWDIN_CAMPERBOT_PAT }}
- name: Generate Crowdin Config
uses: freecodecamp/crowdin-action@main
env:
PLUGIN: 'generate-config'
PROJECT_NAME: 'docs'
##### Download Chinese #####
- name: Crowdin Download Chinese Translations
uses: crowdin/github-action@master
# options: https://github.com/crowdin/github-action/blob/master/action.yml
with:
# uploads
upload_sources: false
upload_translations: false
auto_approve_imported: false
import_eq_suggestions: false
# downloads
download_translations: true
download_language: zh-CN
skip_untranslated_files: false
export_only_approved: true
push_translations: false
# pull-request
create_pull_request: false
# global options
config: './crowdin-config.yml'
base_url: ${{ secrets.CROWDIN_BASE_URL_FCC }}
# Uncomment below to debug
# dryrun_action: true
# Convert Simplified Chinese to Traditional #
- name: Convert Chinese
uses: freecodecamp/crowdin-action@main
env:
PLUGIN: 'convert-chinese'
FILE_PATHS: '["/docs/i18n/chinese/"]'
##### Download Portuguese#####
- name: Crowdin Download Portuguese Translations
uses: crowdin/github-action@master
# options: https://github.com/crowdin/github-action/blob/master/action.yml
with:
# uploads
upload_sources: false
upload_translations: false
auto_approve_imported: false
import_eq_suggestions: false
# downloads
download_translations: true
download_language: pt-BR
skip_untranslated_files: false
export_only_approved: true
push_translations: false
# pull-request
create_pull_request: false
# global options
config: './crowdin-config.yml'
base_url: ${{ secrets.CROWDIN_BASE_URL_FCC }}
# Uncomment below to debug
# dryrun_action: true
##### Download Espanol #####
- name: Crowdin Espanol Download Translations
uses: crowdin/github-action@master
# options: https://github.com/crowdin/github-action/blob/master/action.yml
with:
# uploads
upload_sources: false
upload_translations: false
auto_approve_imported: false
import_eq_suggestions: false
# downloads
download_translations: true
download_language: es-EM
skip_untranslated_files: false
export_only_approved: true
push_translations: false
# pull-request
create_pull_request: false
# global options
config: './crowdin-config.yml'
base_url: ${{ secrets.CROWDIN_BASE_URL_FCC }}
# Uncomment below to debug
# dryrun_action: true
##### Download Italian #####
- name: Crowdin Download Italian Translations
uses: crowdin/github-action@master
# options: https://github.com/crowdin/github-action/blob/master/action.yml
with:
# uploads
upload_sources: false
upload_translations: false
auto_approve_imported: false
import_eq_suggestions: false
# downloads
download_translations: true
download_language: it
skip_untranslated_files: false
export_only_approved: true
push_translations: false
# pull-request
create_pull_request: false
# global options
config: './crowdin-config.yml'
base_url: ${{ secrets.CROWDIN_BASE_URL_FCC }}
# Uncomment below to debug
# dryrun_action: true
##### Download Japanese #####
- name: Crowdin Download Japanese Translations
uses: crowdin/github-action@master
# options: https://github.com/crowdin/github-action/blob/master/action.yml
with:
# uploads
upload_sources: false
upload_translations: false
auto_approve_imported: false
import_eq_suggestions: false
# downloads
download_translations: true
download_language: ja
skip_untranslated_files: false
export_only_approved: true
push_translations: false
# pull-request
create_pull_request: false
# global options
config: './crowdin-config.yml'
base_url: ${{ secrets.CROWDIN_BASE_URL_FCC }}
# Uncomment below to debug
# dryrun_action: true
##### Download Ukrainian #####
- name: Crowdin Download Ukrainian Translations
uses: crowdin/github-action@master
# options: https://github.com/crowdin/github-action/blob/master/action.yml
with:
# uploads
upload_sources: false
upload_translations: false
auto_approve_imported: false
import_eq_suggestions: false
# downloads
download_translations: true
download_language: uk
skip_untranslated_files: false
export_only_approved: true
push_translations: false
# pull-request
create_pull_request: false
# global options
config: './crowdin-config.yml'
base_url: ${{ secrets.CROWDIN_BASE_URL_FCC }}
# Uncomment below to debug
# dryrun_action: true
##### Download German #####
- name: Crowdin Download German Translations
uses: crowdin/github-action@master
# options: https://github.com/crowdin/github-action/blob/master/action.yml
with:
# uploads
upload_sources: false
upload_translations: false
auto_approve_imported: false
import_eq_suggestions: false
# downloads
download_translations: true
download_language: de
skip_untranslated_files: false
export_only_approved: true
push_translations: false
# pull-request
create_pull_request: false
# global options
config: './crowdin-config.yml'
base_url: ${{ secrets.CROWDIN_BASE_URL_FCC }}
# Uncomment below to debug
# dryrun_action: true
# Create Commit
- name: Commit Changes
uses: freecodecamp/crowdin-action@main
env:
PLUGIN: 'commit-changes'
GH_USERNAME: 'camperbot'
GH_EMAIL: ${{ secrets.ACTIONS_CAMPERBOT_EMAIL }}
GH_BRANCH: 'i18n-sync-docs'
GH_MESSAGE: 'chore(i18n,docs): processed translations'
# Generate PR #
# All languages should go ABOVE this. #
- name: Create PR
uses: freecodecamp/crowdin-action@main
env:
PLUGIN: 'pull-request'
GH_TOKEN: ${{ secrets.CROWDIN_CAMPERBOT_PAT }}
BRANCH: 'i18n-sync-docs'
REPOSITORY: 'freecodecamp/freecodecamp'
BASE: 'main'
TITLE: 'chore(i18n,docs): processed translations'
BODY: 'This PR was opened auto-magically by Crowdin.'
LABELS: 'crowdin-sync'
TEAM_REVIEWERS: 'i18n'
-50
View File
@@ -1,50 +0,0 @@
name: i18n - Upload Docs
on:
workflow_dispatch:
schedule:
# runs every weekday at 11:00 AM UTC
- cron: '0 11 * * 1-5'
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
CROWDIN_PERSONAL_TOKEN: ${{ secrets.CROWDIN_CAMPERBOT_SERVICE_TOKEN }}
CROWDIN_API_URL: 'https://freecodecamp.crowdin.com/api/v2/'
CROWDIN_PROJECT_ID: ${{ secrets.CROWDIN_PROJECT_ID_DOCS }}
jobs:
i18n-upload-docs-files:
name: Docs
runs-on: ubuntu-22.04
steps:
- name: Checkout Source Files
uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3
- name: Generate Crowdin Config
uses: freecodecamp/crowdin-action@main
env:
PLUGIN: 'generate-config'
PROJECT_NAME: 'docs'
- name: Crowdin Upload
uses: crowdin/github-action@master
# options: https://github.com/crowdin/github-action/blob/master/action.yml
with:
# uploads
upload_sources: true
upload_translations: false
auto_approve_imported: false
import_eq_suggestions: false
# downloads
download_translations: false
# pull-request
create_pull_request: false
# global options
config: './crowdin-config.yml'
base_url: ${{ secrets.CROWDIN_BASE_URL_FCC }}
# Uncomment below to debug
# dryrun_action: true
View File
-109
View File
@@ -1,109 +0,0 @@
# Frequently Asked Questions
Answers to common questions.
## I am new to GitHub and Open Source. Where should I start?
Read our ["How to Contribute to Open Source Guide"](https://github.com/freeCodeCamp/how-to-contribute-to-open-source). It's a comprehensive reference for first-timer-friendly projects. And it includes a lot of open-source contribution tips.
## What do I need to know to contribute to the codebase?
freeCodeCamp runs on a modern JavaScript stack. If you're interested in contributing to our codebase, you will need some familiarity with JavaScript and some of the technologies we use like Node.js, MongoDB, OAuth 2.0, React, Gatsby, and Webpack.
## Can I translate freeCodeCamp's resources?
Yes - You can contribute to any of the 30+ languages we have enabled on our translation platform.
We have user-contributed translations live in some languages. We intend to localize freeCodeCamp into several major world languages. You can read all about this in our [announcement here](https://www.freecodecamp.org/news/help-translate-freecodecamp-language/).
If you are interested in contributing to translations please make sure you [read this guide](how-to-translate-files.md) first.
## Can I contribute articles to freeCodeCamp News or videos to freeCodeCamp's YouTube channel?
Yes - you can contribute to our publication blog and YouTube channel.
If you're interested in writing articles for freeCodeCamp News, please visit this [publication guide](https://www.freecodecamp.org/news/how-to-write-for-freecodecamp/). In addition, please read our [style guide](https://www.freecodecamp.org/news/developer-news-style-guide/) as this will help you write stronger and more effective articles.
To help us make educational videos for our YouTube channel, you can follow the [YouTube channel guide here](https://www.freecodecamp.org/news/how-to-contribute-to-the-freecodecamp-community-youtube-channel-b86bce4c865/).
## How can I report a new bug?
If you think you've found a bug, first read the ["How to Report a Bug"](https://www.freecodecamp.org/news/how-to-report-a-bug-to-freecodecamp/) article and follow its instructions.
If you're confident it's a new bug, go ahead and create a new GitHub issue. Be sure to include as much information as possible so that we can reproduce the bug. We have a pre-defined issue template to help you through this.
Please note that these GitHub issues are for codebase-related issues and discussions – not for getting help with learning to code. Whenever in doubt, you should [seek assistance on the forum](https://forum.freecodecamp.org) before creating a GitHub issue.
## How can I report a security issue?
Please don't create GitHub issues for security issues. Instead, please [follow our security policy](https://contribute.freecodecamp.org/#/security).
## I am a student. Can I work on a feature for academic credits?
Yes. Please note we are unable to commit to any timelines or paperwork that may be a requirement by your college or university. We receive many pull-requests and code contributions from volunteer developers, and we respect their time and efforts. Out of respect for all of our other contributors, we will not give any PR special priority just because it happens to be school-related.
We request you to plan ahead and work on code contributions with this in mind.
## What do these different labels that are tagged on issues mean?
The code maintainers [triage](https://en.wikipedia.org/wiki/Software_bug#Bug_management) issues and pull requests based on their priority, severity, and other factors. You can [find a complete glossary of their meanings here](https://github.com/freecodecamp/freecodecamp/labels).
## Where do I start if I want to work on an issue?
You should go through [**`help wanted`**](https://github.com/freeCodeCamp/freeCodeCamp/issues?q=is%3Aopen+is%3Aissue+label%3A%22help+wanted%22) or [**`first timers only`**](https://github.com/freeCodeCamp/freeCodeCamp/issues?q=is%3Aopen+is%3Aissue+label%3A%22first+timers+only%22) issues for a quick overview of what is available for you to work on.
> [!TIP] **`help wanted`** issues are up for grabs, and you do not need to seek permission before working on them. However, issues with the **`first timers only`** label are special issues that are designed for people who have not contributed to the freeCodeCamp codebase before.
## I found a typo. Should I report an issue before I can make a pull request?
For typos and other wording changes, you can directly open pull requests without creating an issue first. Please be sure to mention details in the pull request description to help us understand and review your contribution – even if it's just a minor change.
Please do create an issue if you want to discuss bigger aspects of the codebase or curriculum.
## How can I get an issue assigned to me?
We typically do not assign issues to anyone other than long-time contributors. Instead, we follow the below policy to be fair to everyone:
1. We are most likely to merge the first pull request that addresses the issue.
2. In the case of multiple contributors opening a pull request for the same issue at around the same time, we will give priority to the pull request that best addresses the issue. Some of the things we consider:
- Did you include tests?
- Did you catch all use cases?
- Did you ensure all tests pass, and confirm everything works locally?
3. Finally, we give priority to pull requests which follow our recommended guidelines.
- Did you follow the pull request checklist?
- Did you give your pull request a meaningful title?
## I am interested in being a moderator at freeCodeCamp. Where should I start?
Our community moderators are our heroes. Their voluntary contributions make freeCodeCamp a safe and welcoming community.
First and foremost, we would need you to be an active participant in the community, and live by our [code of conduct](https://www.freecodecamp.org/news/code-of-conduct/) (not just enforce it).
Here are some recommended paths for some of our platforms:
- To be a **Discord/Chat** moderator, have an active presence in our chat and have positive engagements with others, while also learning and practicing how to deal with potential conflicts that may arise.
- To be a **Forum** moderator, similar to a chat moderator, have an active presence and engage with other forum posters, supporting others in their learning journey, and even giving feedback when asked. Take a look at [The Subforum Leader Handbook](https://forum.freecodecamp.org/t/the-subforum-leader-handbook/326326) for more information.
- To be a **GitHub** moderator, help process GitHub issues that are brought up to see if they are valid and (ideally) try to propose solutions for these issues to be picked up by others (or yourself).
Altogether, be respectful to others. We are humans from all around the world. With that in mind, please also consider using encouraging or supportive language and be mindful of cross-cultural communication.
If you practice the above **consistently for a while** and our fellow moderator members recommend you, a staff member will reach out and onboard you to the moderators' team. Open source work is voluntary work and our time is limited. We acknowledge that this is probably true in your case as well. So we emphasize being **consistent** rather than engaging in the community 24/7.
Take a look at our [Moderator Handbook](moderator-handbook.md) for a more exhaustive list of other responsibilities and expectations we have of our moderators.
## I am stuck on something that is not included in this documentation.
**Feel free to ask for help in:**
- The `Contributors` category of [our community forum](https://forum.freecodecamp.org/c/contributors).
- The `#Contributors` channel on [our chat server](https://discord.gg/PRyKn3Vbay).
We are excited to help you contribute to any of the topics that you would like to work on. If you ask us questions on the related issue threads, we will be glad to clarify. Be sure to search for your question before posting a new one.
Thanks in advance for being polite and patient. Remember – this community is run mainly by volunteers.
## Additional Assistance
If you have queries about the stack, architecture of the codebase, translations, or anything else, feel free to reach out to our staff team [on the forum](https://forum.freecodecamp.org/g/team).
**You can email our developer staff at: `dev[at]freecodecamp.org`**
-3
View File
@@ -1,3 +0,0 @@
## Our contributing docs are available here: <https://contribute.freecodecamp.org>.
Looking to edit these docs? Read [this document](how-to-work-on-the-docs-theme.md) first.
-12
View File
@@ -1,12 +0,0 @@
# Contribute to freeCodeCamp.org
## This community is possible thanks to thousands of kind volunteers like you.
## Here are some quick and fun ways you can help the community.
- <span class='cover-icon'><i class="fas fa-question-circle"></i></span> [Help by answering coding questions](https://forum.freecodecamp.org) on our community forum.
- <span class='cover-icon'><i class="fas fa-comments"></i></span> [Give feedback on coding projects](https://forum.freecodecamp.org/c/project-feedback?max_posts=1) built by campers.
- <span class='cover-icon'><i class="fas fa-language"></i></span> [Help us translate](/index?id=translations) freeCodeCamp.org's resources.
- <span class='cover-icon'><i class="fab fa-github"></i></span> [Contribute to our open-source codebase](/index?id=learning-platform) on GitHub.
[Read our contributing guidelines](/index.md)
-1
View File
@@ -1 +0,0 @@
- [Translations](_translations.md)
-48
View File
@@ -1,48 +0,0 @@
- **Getting Started**
- [Introduction](index.md 'Contribute to the freeCodeCamp.org Community')
- [Frequently Asked Questions](FAQ.md)
- [Reporting a Vulnerability](security.md)
- **Translation Contribution**
- [Work on translating resources](how-to-translate-files.md)
- [Work on proofreading translations](how-to-proofread-files.md)
- **Code Contribution**
- [Set up freeCodeCamp](how-to-setup-freecodecamp-locally.md)
- [Follow best-practices](codebase-best-practices.md)
- [Work on Codebase](how-to-contribute-to-the-codebase.md)
- [Work on Coding Challenges](how-to-work-on-coding-challenges.md)
- [Use the Curriculum Helpers](curriculum-help.md)
- [Work on Component Library](how-to-work-on-the-component-library.md)
- [Work on Practice Projects](how-to-work-on-practice-projects.md)
- [Work on Mobile app](how-to-setup-freecodecamp-mobile-app-locally.md)
- [Work on tutorials with CodeRoad](how-to-work-on-tutorials-that-use-coderoad.md)
- [Work on Localized Web App](how-to-work-on-localized-client-webapp.md)
- [Work on Playwright Tests](how-to-add-playwright-tests.md)
- [Work on Video Challenges](how-to-help-with-video-challenges.md)
- [Work on Documentation](how-to-work-on-the-docs-theme.md)
- [Open a pull request](how-to-open-a-pull-request.md)
- **Additional Guides**
- [Understand the curriculum file structure](curriculum-file-structure.md)
- [Debug outgoing emails locally](how-to-catch-outgoing-emails-locally.md)
- [Work on Cypress Tests](how-to-add-cypress-tests.md)
- [Set up freeCodeCamp on Windows (WSL)](how-to-setup-wsl.md)
- [Use Docker on Windows Home](how-to-use-docker-on-windows-home.md)
- [User Token Workflow](user-token-workflow.md)
- [Troubleshooting Development Issues](troubleshooting-development-issues.md)
- [Authors Analytics Manual](authors-analytics-manual.md)
---
- **Flight Manuals** (for Staff & Mods)
- [Moderator Handbook](moderator-handbook.md)
- [Reply Templates](reply-templates.md)
- [Language Lead Handbook](language-lead-handbook.md)
- [DevOps Handbook](devops.md)
- [Courses VSCode Extension](courses-vscode-extension.md)
- [Enable New Language](how-to-enable-new-languages.md)
---
- **Our Community**
- [**GitHub**](https://github.com/freecodecamp/freecodecamp)
- [**Discourse Forum**](https://freecodecamp.org/forum/c/contributors)
- [**Chat Server**](https://discord.gg/PRyKn3Vbay)
-508
View File
@@ -1,508 +0,0 @@
:root {
--theme-color: #0a0a23;
--yellow-gold: #ffbf00;
--gray-00: #ffffff;
--gray-05: #f5f6f7;
--gray-10: #dfdfe2;
--gray-15: #d0d0d5;
--gray-45: #858591;
--gray-75: #3b3b4f;
--gray-80: #2a2a40;
--gray-85: #1b1b32;
--gray-90: #0a0a23;
--purple-light: #dbb8ff;
--purple-dark: #5a01a7;
--yellow-light: #ffc300;
--yellow-dark: #4d3800;
--blue-light: rgb(153, 201, 255);
--blue-light-translucent: rgba(153, 201, 255, 0.3);
--blue-dark: rgb(0, 46, 173);
--blue-dark-translucent: rgba(0, 46, 173, 0.3);
--green-light: #acd157;
--blue-mid: #198eee;
--purple-mid: #9400d3;
--green-dark: #00471b;
--red-light: #ffadad;
--red-dark: #850000;
--love-light: #f8577c;
--love-dark: #f82153;
--editor-background-light: #fffffe;
--editor-background-dark: #2a2b40;
--focus-outline-color: var(--blue-mid);
--font-family-sans-serif: 'Lato', sans-serif;
--font-family-monospace: 'Hack-ZeroSlash', monospace;
--size: 1.5rem;
--line-height: 2rem;
}
.light {
--primary-color: var(--gray-90);
--secondary-color: var(--gray-85);
--tertiary-color: var(--gray-80);
--quaternary-color: var(--gray-75);
--quaternary-background: var(--gray-15);
--tertiary-background: var(--gray-10);
--secondary-background: var(--gray-05);
--primary-background: var(--gray-00);
--highlight-color: var(--blue-dark);
--highlight-background: var(--blue-light);
--selection-color: var(--blue-dark-translucent);
--success-color: var(--green-dark);
--success-background: var(--green-light);
--danger-color: var(--red-dark);
--danger-background: var(--red-light);
--love-color: var(--love-dark);
--editor-background: var(--editor-background-light);
}
.dark {
--primary-color: var(--gray-00);
--secondary-color: var(--gray-05);
--tertiary-color: var(--gray-10);
--quaternary-color: var(--gray-15);
--quaternary-background: var(--gray-75);
--tertiary-background: var(--gray-80);
--secondary-background: var(--gray-85);
--primary-background: var(--gray-90);
--highlight-color: var(--blue-light);
--highlight-background: var(--blue-dark);
--selection-color: var(--blue-light-translucent);
--success-color: var(--green-light);
--success-background: var(--green-dark);
--danger-color: var(--red-light);
--danger-background: var(--red-dark);
--love-color: var(--love-light);
--editor-background: var(--editor-background-dark);
}
body {
font-size: 100%;
line-height: 2.3em;
background: var(--secondary-background);
color: var(--secondary-color);
}
* {
text-decoration: none !important;
}
body .content {
max-width: 80%;
margin-left: auto;
margin-right: auto;
}
/****** Nav ****/
.universal-nav {
margin: 0;
width: 100vw;
height: 38px;
background-color: var(--theme-color);
position: fixed;
top: 0;
display: flex;
justify-content: center;
z-index: 100;
}
.universal-nav a.translations-link {
color: var(--gray-00);
position: fixed;
right: 50px;
line-height: 24px;
font-size: 16px;
margin: 6px 0;
padding: 0;
}
.universal-nav img {
margin: 7px 0;
height: 24px;
}
.app-nav {
visibility: hidden;
}
@media screen and (max-width: 768px) {
.universal-nav a.translations-link {
visibility: hidden;
}
body .content {
max-width: 100%;
}
}
.theme-toggle {
background-color: var(--tertiary-background);
position: fixed;
left: 10px;
line-height: 24px;
font-size: 16px;
margin: 2px 0;
padding: 4px;
}
/****** Cover Page ******/
section.cover {
padding-bottom: 112px;
height: auto;
min-height: 100vh;
background: var(--secondary-background) !important;
color: var(--secondary-color);
}
section.cover .cover-main {
display: flex;
justify-content: center;
align-items: center;
flex-direction: column;
margin: 0;
padding: 32px 8px 0;
}
section.cover h1 {
font-weight: bold;
font-size: 2.3rem;
margin: 2em 0;
}
section.cover span {
background-color: var(--secondary-background);
color: var(--secondary-color);
}
section.cover a {
text-decoration: none;
border-bottom: 0.01rem solid var(--secondary-color);
color: var(--secondary-color);
background-color: var(--secondary-background);
transition: all 0.3s ease;
}
section.cover a:hover {
background-color: var(--tertiary-background);
color: var(--tertiary-color);
border: none;
}
section.cover a.anchor {
border: none;
}
.cover-icon {
margin-right: 0.75em;
}
section.cover ul {
font-size: var(--size);
line-height: var(--line-height);
display: grid;
text-align: left;
grid-column-gap: 16px;
grid-row-gap: 20px;
list-style: none;
max-width: unset;
margin: 1.5em 0;
}
section.cover .cover-main > p:last-child a:last-child {
font-size: var(--size);
line-height: var(--line-height);
background-color: var(--quaternary-background);
color: var(--secondary-color);
border-radius: 0;
border: 3px solid var(--secondary-color);
}
section.cover .cover-main > p:last-child a:last-child:hover {
font-size: var(--size);
line-height: var(--line-height);
background-color: var(--secondary-color);
color: var(--secondary-background);
opacity: 1;
}
section.cover.show ~ .sidebar,
section.cover.show ~ .sidebar-toggle {
display: none;
}
@media (max-width: 850px) {
section.cover ul {
grid-template-columns: 100%;
padding: 0;
}
section.cover ul li {
text-align: center;
}
}
@media (max-width: 450px) {
section.cover ul li {
white-space: normal;
}
.cover-main .buttons a {
width: 100%;
margin: 0.2rem 0;
}
}
@media (max-width: 400px) {
section.cover .cover-main > p:last-child a:last-child {
padding-left: 0;
padding-right: 0;
margin-right: 0;
margin-left: 0;
}
}
/****** Sidebar ******/
.sidebar {
background-color: var(--primary-background);
color: var(--quaternary-color);
padding: 0;
}
.sidebar ul li a,
.search a {
color: var(--quaternary-color);
}
.sidebar ul li > a:hover,
.search a:hover {
color: var(--primary-color);
}
.sidebar .search .clear-button {
cursor: pointer;
}
.sidebar ul li.active > a {
color: var(--primary-color);
}
/****** Sidebar Toggle ******/
.sidebar-toggle,
.sidebar,
.content {
margin-top: 38px;
}
.sidebar-toggle {
cursor: pointer;
}
body .sidebar-toggle {
background: none;
top: var(--size);
left: calc(300px + 1.5rem);
cursor: pointer;
width: var(--size);
height: var(--size);
padding: 0;
transition: left 0.25s ease-out;
}
body .sidebar-toggle span {
background-color: var(--secondary-color);
height: 0.2rem;
width: var(--size);
position: absolute;
left: 0;
margin: 0;
transform-origin: 0;
border-radius: 1px;
}
body.close .sidebar-toggle {
transition: left 0.25s ease-out;
background-color: var(--secondary-background);
width: var(--size);
height: var(--size);
left: var(--size);
}
body.close .sidebar-toggle span {
transform-origin: center;
}
body .sidebar-toggle span:nth-child(1) {
top: 0;
}
body .sidebar-toggle span:nth-child(2) {
top: 0.5rem;
}
body .sidebar-toggle span:nth-child(3) {
top: 1rem;
}
.sidebar-toggle:hover {
opacity: 0.8;
}
.sidebar-toggle .sidebar-toggle-button:hover {
opacity: 1;
}
@media screen and (max-width: 768px) {
body .sidebar-toggle {
left: 1rem;
}
body.close .sidebar-toggle {
left: calc(300px + 1.5rem);
}
}
body.close .app-nav,
body.close .github-corner {
display: block !important;
text-align: center;
}
/****** Markdown General ******/
/* Undo vue.css defaults */
.anchor span {
all: unset;
}
.markdown-section h1,
.markdown-section h2 {
margin: 1em 0;
color: var(--secondary-color);
}
.markdown-section p {
font-size: 18px;
line-height: 28px;
}
.markdown-section code {
background-color: var(--quaternary-background);
color: var(--quaternary-color);
padding: 0.05em 0.15em 0.15em;
margin: 0.05em;
font-size: 16px;
line-height: 24px;
}
.markdown-section a {
text-decoration: none;
color: var(--secondary-color);
border-bottom: 0.1rem solid var(--secondary-color);
}
.markdown-section a:hover {
background-color: var(--tertiary-background);
border: none;
}
.markdown-section a.anchor {
border: none;
}
.markdown-section strong {
color: var(--primary-color);
}
.markdown-section pre {
background-color: var(--primary-background);
}
.markdown-section pre > code {
background-color: var(--primary-background);
color: var(--secondary-color);
}
.markdown-section a > code,
.markdown-section a > strong > code {
background-color: var(--primary-color);
color: var(--tertiary-background);
padding: 0.05em 0.15em 0;
margin: 0.05em;
}
.markdown-section a > code:hover,
.markdown-section a > code:active,
.markdown-section a > strong > code:hover,
.markdown-section a > strong > code:active {
background-color: #525252;
color: #f8f8f8;
padding: 0.05em 0.15em 0;
margin: 0.05em;
}
.markdown-section em,
.markdown-section blockquote {
color: var(--tertiary-color);
}
.markdown-section tr:nth-child(2n) {
background-color: var(--tertiary-background);
}
@media screen and (max-width: 768px) {
.markdown-section {
max-width: 90%;
padding: 40px 15px;
}
}
/****** CODE HIGHLIGHTING ******/
.token.punctuation {
color: var(--yellow-gold);
}
.token.attr-value {
color: var(--blue-mid);
}
.token.string {
color: var(--love-dark);
}
/****** COPY TO CLIPBOARD ******/
.docsify-copy-code-button {
font-size: 0.7em !important;
}
/****** Others ******/
.search input {
background-color: var(--secondary-background);
color: var(--secondary-color);
}
.search .search-keyword {
color: var(--secondary-color);
}
.i18n-lang-list ul {
height: 10em;
font-size: larger;
list-style: none;
display: -webkit-flex;
display: flex;
-webkit-align-items: center;
align-items: center;
-webkit-justify-content: center;
justify-content: center;
-webkit-flex-flow: column wrap;
flex-flow: column wrap;
-webkit-align-content: stretch;
align-content: stretch;
}
.i18n-lang-list li {
text-align: left;
width: 10em;
}
-31
View File
@@ -1,31 +0,0 @@
<div style='text-align: center'>
## Read these guides in other languages
</div>
<br />
<div class='i18n-lang-list'>
- [Chinese](/i18n/chinese/index.md)
- [Chinese Traditional](/i18n/chinese-traditional/index.md)
- [English](/index.md)
- [Español](/i18n/espanol/index.md)
- [German](/i18n/german/index.md)
- [Italian](/i18n/italian/index.md)
- [Japanese](/i18n/japanese/index.md)
- [Portuguese](/i18n/portuguese/index.md)
- [Ukrainian](/i18n/ukrainian/index.md)
</div>
<br />
<br />
<br />
<div style='text-align: center'>
Interested in updating the translations? Visit: <https://translate.freecodecamp.org>
</div>
-27
View File
@@ -1,27 +0,0 @@
# Authors Analytics Manual
If you are an author with access to the publication's Google Analytics Property (News), you can use this guide to view your article engagement and search for articles by publication language.
## Search by Language
To search for engagement reports in a specific language:
![Image - Show steps to search by language on googla analytics](https://contribute.freecodecamp.org/images/google-analytics/search-by-language.png)
1. From the top dropdown menu, select `News`.
1. From the sidebar, click on `Reports`.
1. From the secondary sidebar, select `Engagement`.
1. Click on `Pages and Screens`.
1. In the search bar, type the subpath for the desired language.
1. From the dropdown under the search bar, choose `Page path and screen class`.
## Filter Reports by Author
After arriving at the `Pages and Screens` reports mentioned above, use the following steps to filter the results by specific authors.
![Image - Show steps to search by language on googla analytics](https://contribute.freecodecamp.org/images/google-analytics/filter-by-author.png)
1. Click on the `Add filter` button.
1. From the side navigation include `Author`.
1. From the `Dimensions values` dropdown, choose an author's name.
1. Click on the `Apply` button to apply changes.
-189
View File
@@ -1,189 +0,0 @@
# Codebase Best Practices
## Styling a component
We recommend styling components using our [design style guide](https://design-style-guide.freecodecamp.org/).
The colors are defined in [`variable.css`](/client/src/components/layouts/variables.css), and the fonts are in [`fonts.css`](/client/src/components/layouts/fonts.css).
We are strongly opinionated about adding new variables/tokens to the colors. After careful research, the colors have been chosen to respect the freeCodeCamp brand identity, developer experience, and accessibility.
The `!important` keyword may be used to override values in some cases (e.g. accessibility concerns). You should add a comment describing the issue, so it doesn't get removed in future refactoring.
### RTL support
We are striving to support right-to-left (RTL) layout in the codebase for languages that are read in this direction. For this, you need to be mindful of how to style components. Here are some quick rules of thumb to follow:
- Don't use `float` properties
- Use Flexbox and Grid layouts instead, as they have RTL support already built-in, and those will be easier to maintain and review.
- Don't define the direction while using `margin` and `padding`: it may seem harmless to use `padding-right` and `margin-left`, but these directions aren't mirrored when the layout changes to RTL, and adding counter values for them in the RTL file makes maintaining the codebase harder.
- Use logical properties for them: You can add the same spacing by using `padding-inline-end` and `margin-inline-start`, and you won't need to worry about RTL layout, as they follow where the line starts and ends, and you won't need to add any extra values in the RTL files, so people won't need to remember to change the same values in two files.
- Don't use `!important` in `font-family`: RTL layout uses different fonts compared to the LTR layout, when you add `!important` in the `font-family` property it affects the RTL layout too.
## General JavaScript
In most cases, our [linter](how-to-setup-freecodecamp-locally.md#follow-these-steps-to-get-your-development-environment-ready) will warn of any formatting which goes against this codebase's preferred practice.
It is encouraged to use functional components over class-based components.
## Specific TypeScript
### Migrating a JavaScript File to TypeScript
#### Retaining Git File History
Sometimes changing the file from `<filename>.js` to `<filename>.ts` (or `.tsx`) causes the original file to be deleted, and a new one created, and other times the filename just changes - in terms of Git. Ideally, we want the file history to be preserved.
The best bet at achieving this is to:
1. Rename the file
2. Commit with the flag `--no-verify` to prevent Husky from complaining about the lint errors
3. Refactor to TypeScript for migration, in a separate commit
> [!NOTE]
> Editors like VSCode are still likely to show you the file has been deleted and a new one created. If you use the CLI to `git add .`, then VSCode will show the file as renamed in stage
### Naming Conventions
#### Interfaces and Types
For the most part, it is encouraged to use interface declarations over type declarations.
React Component Props - suffix with `Props`
```typescript
interface MyComponentProps {}
// type MyComponentProps = {};
const MyComponent = (props: MyComponentProps) => {};
```
React Stateful Components - suffix with `State`
```typescript
interface MyComponentState {}
// type MyComponentState = {};
class MyComponent extends Component<MyComponentProps, MyComponentState> {}
```
Default - object name in PascalCase
```typescript
interface MyObject {}
// type MyObject = {};
const myObject: MyObject = {};
```
<!-- #### Redux Actions -->
<!-- TODO: Once refactored to TS, showcase naming convention for Reducers/Actions and how to type dispatch funcs -->
## Redux
### Action Definitions
```typescript
enum AppActionTypes = {
actionFunction = 'actionFunction'
}
export const actionFunction = (
arg: Arg
): ReducerPayload<AppActionTypes.actionFunction> => ({
type: AppActionTypes.actionFunction,
payload: arg
});
```
### How to Reduce
```typescript
// Base reducer action without payload
type ReducerBase<T> = { type: T };
// Logic for handling optional payloads
type ReducerPayload<T extends AppActionTypes> =
T extends AppActionTypes.actionFunction
? ReducerBase<T> & {
payload: AppState['property'];
}
: ReducerBase<T>;
// Switch reducer exported to Redux combineReducers
export const reducer = (
state: AppState = initialState,
action: ReducerPayload<AppActionTypes>
): AppState => {
switch (action.type) {
case AppActionTypes.actionFunction:
return { ...state, property: action.payload };
default:
return state;
}
};
```
### How to Dispatch
Within a component, import the actions and selectors needed.
```tsx
// Add type definition
interface MyComponentProps {
actionFunction: typeof actionFunction;
}
// Connect to Redux store
const mapDispatchToProps = {
actionFunction
};
// Example React Component connected to store
const MyComponent = ({ actionFunction }: MyComponentProps): JSX.Element => {
const handleClick = () => {
// Dispatch function
actionFunction();
};
return <button onClick={handleClick}>freeCodeCamp is awesome!</button>;
};
export default connect(null, mapDispatchToProps)(MyComponent);
```
<!-- ### Redux Types File -->
<!-- The types associated with the Redux store state are located in `client/src/redux/types.ts`... -->
## API
### Testing
The `api/` tests are split into two parts:
1. Unit tests
2. Integration tests
#### Unit Tests
Unit tests isolate a single function or component. The tests do not need mocking, but will require fixtures.
The unit tests are located in a new file adjacent to the file exporting that is being tested:
```text
api/
├── src/
│ ├── utils.ts
│ ├── utils.test.ts
```
#### Integration Tests
Integration tests test the API as a whole. The tests will require mocking and should not require fixtures beyond the database seeding data and a method for authentication.
Typically, each integration test file will be directly related to a route. The integration tests are located in the `api/tests/` directory:
```text
api/
├── tests/
│ ├── settings.ts
```
## Further Literature
- [TypeScript Docs](https://www.typescriptlang.org/docs/)
- [TypeScript with React CheatSheet](https://github.com/typescript-cheatsheets/react#readme)
-42
View File
@@ -1,42 +0,0 @@
# Courses VSCode Extension
This details the maintenance guidelines for the [freeCodeCamp/courses-vscode-extension](https://github.com/freeCodeCamp/courses-vscode-extension) repository which contains the source code for the [freeCodeCamp - Courses](https://marketplace.visualstudio.com/items?itemName=freeCodeCamp.freecodecamp-courses) extension.
## Publishing the Extension
A GitHub Action automagically publishes the extension to the Visual Studio Marketplace, on the release of a new GitHub Release.
1. Package a new version of the extension:
```bash
npm run pack -- <tag_type>
```
Where `<tag_type>` is one of: `major`, `minor`, `patch`.
2. Push the new version to `main`:
```bash
git commit -am "<tag_type>(<version>): <description>"
git push
```
Optionally, you can push directly to `upstream/main`, but opening a new PR is recommended for a sanity check.
3. Create a new GitHub Release using the GitHub UI:
- Correctly increment the version number, when creating a new tag.
- Upload the `.vsix` file with the release.
- Publish the release, and confirm the action succeeded.
> [!NOTE]
> Creating a release requires write access to the `freeCodeCamp/courses-vscode-extension` repository.
## Manually Publishing the Extension
A manual upload to the Visual Studio Marketplace can be achieved, by following these steps:
1. Visit https://marketplace.visualstudio.com/ and sign in
2. Navigate to the [freeCodeCamp Publisher page](https://marketplace.visualstudio.com/manage/publishers/freecodecamp)
3. Select the relevant extension, and select `Update`
4. Upload the file from your local files
-107
View File
@@ -1,107 +0,0 @@
# Curriculum File Structure
Our core instructional content is located within the conveniently named `curriculum` directory. This page will break down how these files are organized.
## Terminology
There are a few terms we use when discussing our curriculum content.
- `certification` : When referring to a certification in this instance, it is talking about the actual certificate that users claim. Which is separate from the name of the superBlock.
- `superBlock` : A superblock is the top level collection of challenges. Each superblock corresponds to a certification in the curriculum (e.g. Responsive Web Design).
- `block` : A block is a section within a superblock. A block corresponds to a group of challenges in a given certification (e.g. Basic HTML and HTML5)
- `challenge` : A challenge is a single lesson within the curriculum (e.g. Say Hello to HTML Elements)
## File Tree
Using those terms, here is how the file structure would be defined:
<!-- prettier-ignore -->
```md
curriculum/
├─ _meta/
│ ├─ {block}/
│ │ ├─ meta.json
├─ {language}/
│ ├─ {superBlock}/
│ │ ├─ {block}/
│ │ │ ├─ {challenge}.md
```
## The `_meta` Directory
The `_meta` directory is a special directory which contains `.json` files. These files correspond to each block in the curriculum, and are used to determine which superBlock a block belongs to, and the order of the challenges within that block.
## Renaming Files
There may be times when you need to rename a certificate, superblock, block, or challenge. This section will outline the steps needed to avoid build errors when doing so.
> [!ATTENTION]
> Renaming files within the curriculum structure will often change the path (or URL) of the content on the main webpage. Doing so should be done with care, as redirects have to be set up for each change that is made.
### Renaming a Certification
When renaming a certification, you will likely want to rename the associated superblock along with it. Do the following to rename only the certificate:
1. Rename the `curriculum/challenges/_meta/{superBlock}-certificate` folder to the new name.
1. In the `meta.json` file of that folder, rename the values in `name`, `dashedName`, and `challengeOrder` to the new cert name.
1. In `curriculum/challenges/english/12-certificate`, rename the `{superBlock}-certificate` folder, and the YAML file within it, to the new name.
1. In the YAML file, change the `title` to the new name.
1. Rename the file and folder from step 3 for the rest of the curriculum languages.
1. Update `client/src/redux/index.ts` to use the correct `title`.
1. Optionally, update the `certSlug` for the superblock in the same file. **Note** that renaming a `certSlug` will change the URL for certifications and should only be done with careful consideration.
1. Update the `title` in `client/src/resources/cert-and-project-map.ts` to the new value. **Note** that changing the `title` here **will break** the superBlock page for the associated certification. It relies on the superBlock title to match the certification title. You will likely want to rename the superBlock at the same time.
1. If you renamed the `certSlug` in step 7, change it here for the cert and all the nested `projects` values.
1. In `shared/config/certification-settings.js`, update the value of `certTypeTitleMap` to the new name.
1. If you renamed the `certSlug` in step 7, update the key of `certSlugTypeMap` in the same file.
1. Update the certificate name in the `legacyCerts` array of the `client/src/client-only-routes/show-project-links.tsx` if needed.
1. Update the main `README.md` file to the new name.
### Renaming a Superblock
> [!NOTE]
> When you rename a superBlock, the new folder name is used as the path and should be considered the "correct" name. All other values should be updated to reflect that change.
Also, you will likely want to rename the certificate and the `{superBlock}-projects` block when you rename a superBlock since they all share a name. To rename only a superBlock you need to:
1. Rename the superBlock folder in the `curriculum/challenges/english` directory.
1. Rename the superBlock folder in _all_ other `curriculum/challenges/{language}` directories.
1. For each block within that superBlock, update the `superBlock` value in the `meta.json` file to its dashedName. You don't need to rename any folders here. Do that when renaming a block.
1. Rename the superblock folder in `client/src/pages/learn`.
1. Update the `index.md` file in the above folder, changing the `title` and `superBlock` values to the new name.
1. For each block folder within the above, update the `index.md` to use the correct `superBlock` value.
1. In the `client/src/resources/cert-and-project-map.ts` file, update the path for the cert at the top of the file, and the `title` value for that superBlock. **Note** that changing the `title` here **will break** the ability to view the actual certification for this superBlock. It relies on the superBlock title to match the certification title. You will likely want to rename the certification at the same time.
1. Update the `superBlockCertTypeMap` key in `shared/config/certification-settings.js` to the new superBlock name.
1. Update the path value in `client/src/assets/icons/index.tsx`.
1. For each language in `client/i18n/locales`, update the `intro.json` file to use the new superBlock `dashedName`. In the English file, also update the `title`.
1. Check the `shared/config/i18n/all-langs.js` file to see if the superBlock is enabled in i18n builds. Update all the values where it is used.
1. Update the main `README.md` file to the new name.
### Renaming a Block
When renaming a curriculum block, you need to:
1. Change the name of the block folder in the `curriculum/challenges/english/{superBlock}` directory.
1. Change the name of the same block folder in _all_ of the other language directories to match. These must all be the same as the English structure or the build will error out.
1. Change the name of the block folder in the `_meta` directory.
1. Update the `name` and `dashedName` property for that block's `meta.json` file.
1. Update the block folder in `client/src/pages/learn/{superBlock}`.
1. In the `index.md` file of the above folder, update the `block` value in the frontmatter.
1. In the `client/i18n/locales/{language}/intro.json` files, update the block name to the new name for all the languages. In the English `intro.json` file, update the `title` as well.
1. Update the main `README.md` file to the new name.
### Renaming a Challenge
When renaming a single challenge file, you need to:
1. Change the name of the challenge file in the `curriculum/challenges/english` directory.
1. Change the name of the `title` and `dashedName` within that file.
1. Change the name of the file, and the `dashedName` in those files for _all_ of the other language directories to match.
1. Update the name of the challenge in the relevant `meta.json` file. The challenge names here are not used in the build, but provide a user-friendly way to identify the challenge order.
1. If the challenge is a certificate project, update the YAML file in `curriculum/english/12-certificates/<superBlock>` to the new name.
1. If the challenge is a certificate project, update the `title` and `link` in `client/src/resources/cert-and-project-map.ts`
1. If the challenge is a certificate project, update the main `README.md` file to the new name.
## The `dashedName` Property
The `dashedName` property is used to generate the URL path for the superblock, block, or challenge. These should generally match what the `/utils/slugs.js` helper would output for the file name.
-161
View File
@@ -1,161 +0,0 @@
# Using the Curriculum Helpers
The test runner has access to a few helpers that can assist with testing campers' code.
## CSS Helper
To instantiate the helper within a test block, use this:
```js
const helper = new __helpers.CSSHelp(document);
```
In that example, the `document` variable refers to the document object of the test runner's iframe.
### Methods
There are a few methods available for parsing and testing CSS.
#### `.getStyle()`
The `.getStyle()` method takes a CSS selector and returns a CSS style declaration object.
For example, if the camper has written the following CSS:
```css
body {
background: linear-gradient(45deg, rgb(118, 201, 255), rgb(247, 255, 222));
margin: 0;
padding: 0;
width: 100%;
height: 100vh;
overflow: hidden;
}
```
You would get an object that looks like this:
```js
{
0: "background-image",
1: "background-position-x",
2: "background-position-y",
3: "background-size",
4: "background-repeat-x",
5: "background-repeat-y",
6: "background-attachment",
7: "background-origin",
8: "background-clip",
9: "background-color",
10: "margin-top",
11: "margin-right",
12: "margin-bottom",
13: "margin-left",
14: "padding-top",
15: "padding-right",
16: "padding-bottom",
17: "padding-left",
18: "width",
19: "height",
20: "overflow-x",
21: "overflow-y",
"accentColor": "",
"additiveSymbols": "",
"alignContent": "",
"alignItems": "",
...
}
```
This method allows you to test that specific properties have been set:
```js
assert.strictEqual(helper.getStyle('body')?.width, '100%');
```
The helper attaches a `.getPropVal()` method to the style declaration object that allows you to get the value of a specific property:
```js
assert.strictEqual(helper.getStyle('body').getPropVal('width'), '100%');
```
#### `.getCSSRules()`
The `.getCSSRules()` takes an at-rule type from the union `media | fontface | import | keyframes`, and returns an array of CSS rules matching that at-rule.
For example, if the camper has written the following code:
```css
@media (max-width: 100px) {
body {
background-color: green;
}
}
```
Then the returned value of `helper.getCSSRules('media')` would be this array:
```js
[
{
conditionText: "(max-width: 100px)",
cssRules: [
selectorText: 'body',
style: CSSStyleDeclaration,
styleMap: StylePropertyMap,
cssRules: CSSRuleList,
type: 1,
...
],
cssText: "@media (max-width: 100px) {\n body { background-color: green; }\n}",
...
}
]
```
You can then test that the camper has written the correct media query:
```js
const hasCorrectHeight = helper.getCSSRules('media').some(x => x.style.height === '3px');;
assert.isTrue(hasCorrectHeight);
```
#### `.getRuleListsWithinMedia()`
The `.getRuleListsWithinMedia()` method takes a media text (e.g. `("max-width: 200")`) and returns the CSS rules within that media query.
The return result is the equivalent of that media rule's `cssRules` property from the return value of `.getCSSRules("media")`.
### Less Frequent Methods
These methods are not as commonly used, but are available if needed.
#### `.getStyleDeclarations()`
The `.getStyleDeclarations()` method takes a CSS selector and returns an array of CSS style declaration objects (from the `.getStyle()` method).
#### `.isPropertyUsed()`
The `.isPropertyUsed()` method takes a CSS **property** and checks if it has been set/used anywhere in the camper's CSS.
#### `.getStyleRule()`
The `.getStyleRule()` method takes a CSS selector and returns the CSS Style Declaration, much like `.getStyle()`. However, the declaration returned from this method includes an additional `.isDeclaredAfter()` method which takes a selector and returns whether this rule is declared after the selector passed in.
#### `.getStyleSheet()`
The `.getStyleSheet()` method returns the camper's CSS, parsed into a CSS Style Sheet object.
## Strip Content
There are a few methods on the `__helpers` object to remove content from the camper's code.
These do NOT need to be instantiated they are static methods.
### Removing Comments
Using `__helpers.removeCssComments()`, `__helpers.removeHTMLComments()`, or `__helpers.removeJSComments()` allows you to pass the camper's code (through the `code` variable) to remove comments matching the language's comment syntax.
### Removing Whitespace
Using `__helpers.removeWhitespace()` allows you to pass the camper's code (through the `code` variable) to remove all whitespace.
-1017
View File
File diff suppressed because it is too large Load Diff
-120
View File
@@ -1,120 +0,0 @@
# How to add Cypress tests
When making changes to JavaScript, CSS, or HTML which could change the functionality or layout of a page, it's important to add corresponding [Cypress](https://docs.cypress.io) integration tests.
To learn how to write Cypress tests, or 'specs', please see Cypress' official [documentation](https://docs.cypress.io/guides/getting-started/writing-your-first-test.html).
## Where to Add a Test
- Cypress tests are in the `./cypress` directory.
- Cypress tests for a curriculum module are in the corresponding curriculum directory, i.e. `cypress/integration/learn/responsive-web-design/basic-css/index.js`.
## How to Run Tests
> [!NOTE]
> If using Gitpod, please see [Cypress-Gitpod Setup](how-to-add-cypress-tests.md#cypress-gitpod-setup)
### 1. Ensure that MongoDB and Client Applications are Running
- [Start MongoDB and seed the database](how-to-setup-freecodecamp-locally.md#step-3-start-mongodb-and-seed-the-database)
- [Start the freeCodeCamp client application and API server](how-to-setup-freecodecamp-locally.md#step-4-start-the-freecodecamp-client-application-and-api-server)
### 2. Run the Cypress Tests
To run tests against production builds, replace `dev` with `prd` below.
- To run all tests in the `./cypress` directory:
```bash
pnpm run cypress:dev:run
```
- To run a single test:
```bash
pnpm run cypress run --spec=cypress/<path_to_test_file>
```
For example:
```bash
pnpm run cypress run --spec=cypress/e2e/default/landing.ts
```
- To create a development build, start the development server, and run all existing cypress end-to-end tests:
```bash
pnpm run e2e:dev:run
```
## Cypress-Gitpod Setup
### 1. Ensure Development Environment is Running
If starting the Gitpod environment did not automatically develop the environment:
- Follow the [MongoDB installation guide](https://www.mongodb.com/basics/get-started).
- Create a config file.
```bash
pnpm run create:shared
```
- Seed the database
```bash
pnpm run seed
```
- Develop the server and client
```bash
pnpm run develop
```
### 2. Install Cypress Build Tools
```bash
pnpm run cypress:install-build-tools
```
- When prompted in the terminal, select your keyboard layout by language/area
Now, [Cypress can be run](how-to-add-cypress-tests.md#_2-run-the-cypress-tests)
## Troubleshooting
### Unable to Connect to Port 8000
If Cypress fails to run with the following error:
```
CypressError: `cy.visit()` failed trying to load:
http://localhost:3000/signin
We attempted to make an http request to this URL but the request failed without a response.
We received this error at the network level:
> Error: connect ECONNREFUSED 127.0.0.1:8000
Common situations why this would fail:
- you don't have internet access
- you forgot to run / boot your web server
- your web server isn't accessible
- you have weird network configuration settings on your computer
This error occurred while creating the session. Because the session setup failed, we failed the test.
```
You can resolve the issue by:
- Going to the root `package.json` file and adding `--host 0.0.0.0` to the `develop:client` command:
```json
"scripts": {
"develop:client": "cd ./client && pnpm run develop --host 0.0.0.0"
}
```
- Then, re-running `pnpm run develop`
-345
View File
@@ -1,345 +0,0 @@
# How to add Playwright tests
## Installation
To install Playwright run:
```bash
pnpm run playwright:install-build-tools
```
Alternatively you can follow official documentation referenced below:
To install and configure Playwright on your machine check out this [documentation](https://playwright.dev/docs/intro#installing-playwright).
To learn how to write Playwright tests, or 'specs', please see Playwright's official [documentation](https://playwright.dev/docs/writing-tests).
## Where to Add a Test
- Playwright tests are in the `./e2e` directory.
- Playwright test files are always with a `.spec.ts` extension.
## Best Practices for writing E2E tests
This section will explain in detail about best practices for writing and documenting E2E tests based on Playwright documentation and our community code-style.
### - Imports
Always start with necessary imports at the beginning of the file.
For example:
```ts
import { test, expect, type Page } from '@playwright/test';
```
### - Identifying a DOM element
Playwright comes with [multiple built-in locators](https://playwright.dev/docs/locators#quick-guide), but we recommend prioritizing the following locators:
- `getByRole` for querying semantic elements, whose role is important and allows assistive technology to perceive the page correctly.
- `getByText` for querying non-semantic elements such as `div`, `span`, or `p`.
For example:
```ts
await expect(page.getByRole('heading', { name: 'Sign up' })).toBeVisible();
await expect(page.getByText('Hello World')).toBeVisible();
```
In cases where the elements cannot be queried using the above-mentioned locators, you can use the `data-playwright-test-label` attribute as the last resort. This attribute is used to identify elements in the DOM for testing with playwright only. It is not used for styling or any other purpose.
For example:
```html
<div data-playwright-test-label="landing-page-figure">
<img src="..." alt="..." />
</div>
```
In the test file, you can use the `getByTestId` method to identify the element.
For example:
```ts
await expect(page.getByTestId('landing-page-figure')).toBeVisible();
```
### - Constants
Define any constant elements, data sets, or configurations used throughout your tests for easy reference.
For example:
```ts
const landingPageElements = { ... };
const superBlocks = [ ... ];
```
### - Shared Context
If tests depend on a shared context (like a loaded web page), use beforeAll and afterAll hooks to set up and tear down that context.
For example:
```ts
let page: Page;
beforeAll(async ({ browser }) => {
page = await browser.newPage();
});
afterAll(async () => {
await page.close();
});
```
### - Descriptive test names
Each test block should have a clear and concise name describing exactly what it's testing.
For example:
```ts
test('The component landing-top renders correctly', async ({ page }) => {
// ...
});
```
### - Human readable assertions
Each assertion should be as human readable as possible. This makes it easier to understand what the test is doing and what it's expecting.
For example:
```ts
await expect(landingHeading1).toHaveText('Learn to code — for free.');
```
### - Keep it DRY
Make sure that the tests are not repeating the same code over and over again. If you find yourself repeating the same code, consider refactoring it as a loop or a function.
For example:
```ts
for (const logo of await logos.all()) {
await expect(logo).toBeVisible();
}
```
### - Tests for mobile screens
Use the `isMobile` argument to run tests that include logic that varies for mobile screens.
For example:
```ts
test('The campers landing page figure is visible on desktop and hidden on mobile view', async ({
isMobile
}) => {
const landingPageImage = page.getByTestId('landing-page-figure');
if (isMobile) {
await expect(landingPageImage).toBeHidden();
} else {
await expect(landingPageImage).toBeVisible();
}
});
```
### - Group related tests
Group related tests together using describe blocks. This makes it easier to understand what the tests are doing and what they're testing.
For example:
```ts
describe('The campers landing page', () => {
test('The campers landing page figure is visible on desktop and hidden on mobile view', async ({
isMobile
}) => {
// ...
});
test('The campers landing page figure has the correct image', async () => {
// ...
});
});
```
## How to Run Tests
### 1. Ensure that MongoDB and Client Applications are Running
- [Start MongoDB and seed the database](how-to-setup-freecodecamp-locally.md#step-3-start-mongodb-and-seed-the-database). In order for Playwright tests to work, be sure that you use the `pnpm run seed:certified-user` command.
- [Start the freeCodeCamp client application and API server](how-to-setup-freecodecamp-locally.md#step-4-start-the-freecodecamp-client-application-and-api-server)
### 2. Run the Playwright Tests
To run tests with Playwright check the following below
- Make sure you navigate to the e2e repo first
```bash
cd e2e
```
- To run tests in UI helper mode:
```bash
npx playwright test --ui
```
- To run a single test:
```bash
npx playwright test <filename>
```
For example:
```bash
npx playwright test landing-page.spec.ts
```
- Run a set of test files in respective folders:
```bash
npx playwright test <pathToFolder1> <pathToFolder2>
```
For example:
```bash
npx playwright test tests/todo-page/ tests/landing-page/
```
- Run the test with the title:
```bash
npx playwright test -g <title>
```
For example:
```bash
npx playwright test -g "add a todo item"
```
### 3. Debugging Tests
Since Playwright runs in Node.js, you can debug it with your debugger of choice e.g. using console.log or inside your IDE
- Debugging all tests:
```bash
npx playwright test --debug
```
- Debugging one test file:
```bash
npx playwright test example.spec.ts --debug
```
### 4. Generate Test Reports
The HTML Reporter shows you a full report of your tests allowing you to filter the report by browsers, passed tests, failed tests, skipped tests and flaky tests.
```bash
npx playwright show-report
```
### 5. Troubleshooting
Playwright is generally a solid bullet-proof tool. The contributor has already configured the tests to run on all OS machines, including major distributions of Windows, MacOS and Linux.
- (MacOs and Linux) If running Playwright results in an error due to kernel dependencies, run the following command:
```bash
pnpm run playwright:install-build-tools-linux
```
- A common error seen in playwright is as follows:
```bash
Error: page.goto: Could not connect: Connection refused
=========================== logs ===========================
navigating to "https://127.0.0.1:8000/", waiting until "load"
============================================================
```
You can fix the above error with the following steps:
1. **Check the URL:** Ensure that the URL you're trying to navigate to is correct and properly formatted. Make sure there are no typos in the URL.
2. **Server Status:** Check whether the server at the URL is running and accessible. You might encounter this error if the server is not running or is not accessible.
3. **Port Availability:** Verify that the port mentioned in the URL (8000 in this case) is the correct port and is available for use. Make sure no other process is already using that port.
4. **Firewall or Security Software:** Sometimes, firewall or security software can block connections to specific ports. Check your firewall settings to ensure that the port is allowed.
5. **Network Connectivity:** Ensure that your system has a working network connection and can access external resources.
- Another common error seen in playwright is as follows:
```bash
Protocol error (Network.getResponseBody): Request content was evicted from inspector cache
```
1. The network request was made using a method that does not include a response body, such as HEAD or CONNECT.
2. The network request was made over a secure (HTTPS) connection, and the response body is not available for security reasons.
3. The network request was made by a third-party resource (such as an advertisement or a tracking pixel) that is not controlled by the script.
4. The network request was made by a script that has been paused or stopped before the response was received.
**For more insights on issues visit the official documentation.**
## Playwright-Gitpod Setup
### 1. Ensure Development Environment is Running
If starting the Gitpod environment did not automatically develop the environment:
- Follow the [MongoDB installation guide](https://www.mongodb.com/basics/get-started).
- Create the .env
```bash
cp sample.env .env
```
- Create a config file.
```bash
pnpm run create:shared
```
- Seed the database
```bash
pnpm run seed:certified-user
```
- Develop the server and client
```bash
pnpm run develop
```
### 2. Install Playwright Build Tools
To install necessary dependencies for running Playwright run the following command:
```bash
pnpm run playwright:install-build-tools
```
### 3. Run the Playwright Tests on Gitpod
To run all Playwright tests, run the following command:
```bash
cd e2e
npx playwright test
```
@@ -1,111 +0,0 @@
> **Note:** This is an **optional** step and is required only when working with email workflows
- [Introduction](#introduction)
- [Installing MailHog](#installing-mailhog)
- [Using MailHog](#using-mailhog)
- [Useful Links](#useful-links)
## Introduction
Some email workflows, like updating a user's email, require the back-end API server to send outgoing emails. MailHog is an alternative to using an email service provider to send actual email messages. It is a developer tool for email testing that will catch the email messages sent by your freeCodeCamp instance.
## Installing MailHog
MailHog can be installed on macOS, Windows, and Linux or used via Docker.
<details><summary>Installing MailHog with Docker</summary>
If you have Docker installed then you can use
```bash
docker run -d --name mailhog --network host --rm mailhog/mailhog
```
to start MailHog in the background and
```bash
docker stop mailhog
```
to stop it.
When the installation completes, you can start [using MailHog](#using-mailhog).
</details>
<details><summary>Installing MailHog on macOS</summary>
Install MailHog on macOS with [Homebrew](https://brew.sh/):
```bash
brew install mailhog
brew services start mailhog
```
The above commands will start a MailHog service in the background.
When the installation completes, you can start [using MailHog](#using-mailhog).
</details>
<details><summary>Installing MailHog on Windows</summary>
Download the latest version of MailHog from [MailHog's official repository](https://github.com/mailhog/MailHog/releases). Locate and click on the link for your Windows version (32 or 64 bit) and a `.exe` file will be downloaded to your computer.
When the download completes, click to open the file. A Windows firewall notification may appear, requesting access permission for MailHog. A standard Windows command line prompt will open where MailHog will be running once firewall access is granted.
Close MailHog by closing the command prompt window. To start MailHog again, click on the MailHog executable (`.exe`) file that was downloaded initially - it is not necessary to download a new MailHog installation file.
Start [using MailHog](#using-mailhog).
</details>
<details><summary>Installing MailHog on Linux</summary>
First, install [Go](https://golang.org).
Run the following commands to install GO on Debian-based systems like Ubuntu and Linux Mint.
```bash
sudo apt-get install golang
```
Run the following commands to install GO on RPM-based systems like CentOS, Fedora, Red Hat Linux, etc.
```bash
sudo dnf install golang
```
Alternatively, run the following commands to install GO.
```bash
sudo yum install golang
```
Now set the path for Go with the following commands.
```bash
echo "export GOPATH=$HOME/go" >> ~/.profile
echo 'export PATH=$PATH:/usr/local/go/bin:$GOPATH/bin' >> ~/.profile
source ~/.profile
```
Finally, enter the commands below to install and run MailHog.
```bash
go get github.com/mailhog/MailHog
sudo cp /home/$(whoami)/go/bin/MailHog /usr/local/bin/mailhog
mailhog
```
Start [using MailHog](#using-mailhog).
</details>
## Using MailHog
Open a new browser tab or window and navigate to [http://localhost:8025](http://localhost:8025) to open your MailHog inbox when the MailHog installation has been completed and MailHog is running.
## Useful Links
- Check out the [MailHog](https://github.com/mailhog/MailHog) repository for further information related to MailHog. Additional information is also available regarding custom MailHog configurations.
-217
View File
@@ -1,217 +0,0 @@
Follow these guidelines to contribute to the codebase. This is highly recommended if you want to contribute regularly.
Ignoring these steps may soil your copy which makes the contributing, maintaining, and reviewing processes difficult.
## Contributing to the Codebase
You can now make changes to files and commit your changes to your fork, which you can prepare by reading [how to set up freeCodeCamp locally](how-to-setup-freecodecamp-locally.md).
Follow these steps:
1. Validate that you are on the `main` branch:
```bash
git status
```
You should get an output like this:
```bash
On branch main
Your branch is up-to-date with 'origin/main'.
nothing to commit, working directory clean
```
If you got a different message, then you aren't on main or your working directory isn't clean, resolve any outstanding files/commits and checkout `main`:
```bash
git checkout main
```
2. Sync the latest changes from the freeCodeCamp upstream `main` branch to your `main` fork branch:
> [!WARNING]
> If you have any outstanding pull requests that you made from the `main` branch of your fork, you will lose them at the end of this step.
>
> You should ensure your pull request is merged by a moderator before performing this step. To avoid this scenario, you should **always** work on a branch other than the `main`.
This step **will sync the latest changes** from the main repository of freeCodeCamp.
Update your copy of the freeCodeCamp upstream repository:
```bash
git fetch upstream
```
Hard reset your main branch with the freeCodeCamp main:
```bash
git reset --hard upstream/main
```
Push your main branch to your origin to have a clean history on your fork on GitHub:
```bash
git push origin main --force
```
You can validate that your current main matches the upstream/main by performing a diff:
```bash
git diff upstream/main
```
The resulting output should be empty. This process is important, because you will be rebasing your branch on top of the latest `upstream/main` as often as possible to avoid conflicts later.
3. Create a fresh new branch:
Working on a separate branch for each issue helps you keep your work copy clean. You should never work on the `main`. This will soil your copy of freeCodeCamp and you may have to start over with a fresh clone or fork.
Check that you are on `main` as explained previously, and branch off from there:
```bash
git checkout -b fix/update-guide-for-xyz
```
Your branch name should start with a `fix/`, `feat/`, `docs/`, etc. Avoid using issue numbers in branches. Keep them short, meaningful and unique.
Some examples of good branch names are:
```md
fix/update-challenges-for-react
fix/update-guide-for-html-css
fix/platform-bug-sign-in-issues
feat/add-guide-article-for-javascript
translate/add-spanish-basic-html
```
4. Edit pages and work on code in your favorite text editor.
5. Once you are happy with the changes you should optionally run freeCodeCamp to preview the changes.
6. Make sure you fix any errors and check the formatting of your changes.
7. Check and confirm the files you are updating:
```bash
git status
```
This should show a list of `unstaged` files that you have edited.
```bash
On branch feat/documentation
Your branch is up to date with 'upstream/feat/documentation'.
Changes were not staged for commit:
(use "git add/rm <file>..." to update what will be committed)
(use "git checkout -- <file>..." to discard changes in the working directory)
modified: CONTRIBUTING.md
modified: docs/README.md
modified: docs/how-to-setup-freecodecamp-locally.md
modified: docs/how-to-work-on-guide-articles.md
...
```
8. Stage the changes and make a commit:
In this step, you should only mark files that you have edited or added yourself. You can perform a reset and resolve files that you did not intend to change if needed.
```bash
git add path/to/my/changed/file.ext
```
Or you can add all the `unstaged` files to the staging area:
```bash
git add .
```
Only the files that were moved to the staging area will be added when you make a commit.
```bash
git status
```
Output:
```bash
On branch feat/documentation
Your branch is up to date with 'upstream/feat/documentation'.
Changes to be committed:
(use "git reset HEAD <file>..." to unstage)
modified: CONTRIBUTING.md
modified: docs/README.md
modified: docs/how-to-setup-freecodecamp-locally.md
modified: docs/how-to-work-on-guide-articles.md
```
Now, you can commit your changes with a short message like so:
```bash
git commit -m "fix: my short commit message"
```
Some examples:
```md
fix: add test for JavaScript - for loop step
feat: add link for article for alexa skills
```
Make a conventional commit message. This is a good practice as a developer, and you will be following standard practices.
Some examples of conventional commit messages are:
```md
fix: improve HTML step
fix: fix build scripts for Travis-CI
feat: add link to JavaScript hoisting article
docs: update contributing guidelines
```
Keep these short, not more than 50 characters. You can always add additional information in the description of the commit message.
This does not take any more time than an unconventional message like 'update file' or 'add index.md'
You can learn more about why you should use conventional commits [here](https://www.conventionalcommits.org/en/v1.0.0-beta.2/#why-use-conventional-commits).
9. If you realize that you need to edit a file or update the commit message after making a commit you can do so after editing the files with:
```bash
git commit --amend
```
This will open up a default text editor like `nano` or `vi` where you can edit the commit message title and add/edit the description.
10. Next, you can push your changes to your fork:
```bash
git push origin branch/name-here
```
## Proposing a Pull Request (PR)
After you've committed your changes, check here for [how to open a Pull Request](how-to-open-a-pull-request.md).
## Quick commands reference
A quick reference to the commands that you will need when working.
| command | description |
| ----------------------------------------------------------------- | ----------------------------------------------------------------------------------- |
| `pnpm test` | Run all JS tests in the system, including client, server, lint and challenge tests. |
| `pnpm run test-client` | Run the client test suite. |
| `pnpm run test-client -u` | Run the client test suite, updating the Jest snapshots that are out of sync. |
| `pnpm run test:curriculum` | Run the curriculum test suite. |
| `FCC_BLOCK='Basic HTML and HTML5' pnpm run test:curriculum` | Test a specific Block. |
| `FCC_SUPERBLOCK='responsive-web-design' pnpm run test:curriculum` | Test a specific SuperBlock. |
| `pnpm run test-curriculum-full-output` | Run the curriculum test suite, without bailing after the first error |
| `pnpm run test-server` | Run the server test suite. |
| `pnpm run e2e` | Run the Cypress end to end tests. |
| `pnpm run clean` | Uninstalls all dependencies and cleans up caches. |
| `pnpm run storybook` | Starts Storybook for component library development. |
-469
View File
@@ -1,469 +0,0 @@
# Deploying New Languages on `/learn`
To enable a new language on `/learn` (curriculum), you need to complete the following steps:
- Complete translating and approving the first 3 certifications on Crowdin. (New Responsive Web Design, JavaScript Algorithms and Data Structures, and Front End Development Libraries)
- Complete translating and approving all strings in Learn UI project on Crowdin.
- Update Crowdin settings to add a custom language code for the new language.
- Open the 1st PR to configure GitHub Actions. You need to update 2 files:
- `crowdin-download.client-ui.yml`
- `crowdin-download.curriculum.yml`
- Open the 2nd PR to add other configurations. You need to update/add the following files:
- Update `i18n.ts`
- Update `superblocks.ts`
- Update `algolia-locale-setup.ts`
- Add `links.json`
- Add `meta-tags.json`
- Add `motivation.json`
- Ask infrastructure team to spin up the VM for the new language.
- Once the VM is ready, open the 3rd PR to show the new language in the navigation menu.
We will explain each step in the following sections.
## Updating Crowdin Settings
Before you can release a new language, you will need to allow the languages to download from Crowdin. To configure that, you need to add a custom language code for your language.
In the `Curriculum` and `Learn UI` projects on Crowdin, you will need to select `Settings` > `Languages` from the sidebar. Then scroll down to `Language Mapping`, where you will see an option to add custom language codes. Add a new entry for the language you are releasing, selecting `language` as the `Placeholder` value, and entering a URL-friendly lower-case spelling of your language's name for the `Custom code`. If you aren't sure what to use, or you don't have an admin role and can't see the settings, reach out in our contributor chat and we will assist you.
## Updating Workflows for GitHub Actions
Then you need to configure the syncing between Crowdin and GitHub.
You will need to add a step to the [`crowdin-download.client-ui.yml`](https://github.com/freeCodeCamp/freeCodeCamp/blob/main/.github/workflows/crowdin-download.client-ui.yml) and [`crowdin-download.curriculum.yml`](https://github.com/freeCodeCamp/freeCodeCamp/blob/main/.github/workflows/crowdin-download.curriculum.yml). The step for these will be the same. For example, if you want to enable Dothraki downloads:
```yml
##### Download Dothraki #####
- name: Crowdin Download Dothraki Translations
uses: crowdin/github-action@master
# options: https://github.com/crowdin/github-action/blob/master/action.yml
with:
# uploads
upload_sources: false
upload_translations: false
auto_approve_imported: false
import_eq_suggestions: false
# downloads
download_translations: true
download_language: mis
skip_untranslated_files: false
export_only_approved: true
push_translations: false
# pull-request
create_pull_request: false
# global options
config: './crowdin-config.yml'
base_url: ${{ secrets.CROWDIN_BASE_URL_FCC }}
# Uncomment below to debug
# dryrun_action: true
```
Note that the `download_language` key needs to be set to the language code displayed on Crowdin.
## Enabling a Language
> [!NOTE]
> The above section with updating the workflows should be completed before proceeding - these need to be done in separate steps or the builds will fail.
There are a few steps to take in order to allow the codebase to build in your desired language.
First, visit the [`shared/config/i18n.ts`](https://github.com/freeCodeCamp/freeCodeCamp/blob/main/shared/config/i18n.ts) file to add the language to the list of available languages and configure the values. There are several objects here.
- `Languages`: Add the new language to `Languages` enum, similar to the others. The string value here will be used in the `.env` file to set a build language later.
- `availableLangs`: Add the new property from the `Languages` enum to both the `client` and `curriculum` arrays.
- `i18nextCodes`: These are the ISO language codes for each language. You will need to add the appropriate ISO code for the language you are enabling. These do need to be unique for each language.
- `LangNames`: These are the display names for the language selector in the navigation menu.
- `LangCodes`: These are the language codes used for formatting dates and numbers. These should be Unicode CLDR codes instead of ISO codes.
- `hiddenLangs`: These languages will not be displayed in the navigation menu. This is used for languages that are not yet ready for release. Include your language in this array in the first PR and ask staff team to prepare the VM instance for your language. When the VM is ready, make another PR to remove it from the array.
- `rtlLangs`: These are languages that read from right to left.
As an example, if you wanted to enable Dothraki as a language, your `i18n.ts` objects should look like this:
```js
export enum Languages {
English = 'english',
Espanol = 'espanol',
Chinese = 'chinese',
ChineseTraditional = 'chinese-traditional',
Dothraki = 'dothraki'
}
export const availableLangs = {
client: [
Languages.English,
Languages.Espanol,
Languages.Chinese,
Languages.ChineseTraditional,
Languages.Dothraki
],
curriculum: [
Languages.English,
Languages.Espanol,
Languages.Chinese,
Languages.ChineseTraditional,
Languages.Dothraki
]
};
export const i18nextCodes = {
[Languages.English]: 'en',
[Languages.Espanol]: 'es',
[Languages.Chinese]: 'zh',
[Languages.ChineseTraditional]: 'zh-Hant',
[Languages.Dothraki]: 'mis'
};
export enum LangNames = {
[Languages.English]: 'English',
[Languages.Espanol]: 'Español',
[Languages.Chinese]: '中文(简体字)',
[Languages.ChineseTraditional]: '中文(繁體字)',
[Languages.Dothraki]: 'Dothraki'
};
export enum LangCodes = {
[Languages.English]: 'en-US',
[Languages.Espanol]: 'es-419',
[Languages.Chinese]: 'zh',
[Languages.ChineseTraditional]: 'zh-Hant',
[Languages.Dothraki]: 'mis'
};
export const hiddenLangs = ['dothraki'];
export const rtlLangs = [''];
```
> [!NOTE]
> When a language has been set up in the deployment pipeline AND has a public `/learn` instance live, it can be removed from the `hiddenLangs` array and be made available to the public.
### Set Translated SuperBlocks
In the [shared/config/superblocks.ts](https://github.com/freeCodeCamp/freeCodeCamp/blob/main/shared/config/superblocks.ts) file, add the new language to the `notAuditedSuperBlocks` object. This lists all the superblocks which are not fully translated. Add an array of superblocks that have not been fully translated to it. For example:
```js
export const notAuditedSuperBlocks: NotAuditedSuperBlocks = {
...
[Languages.Dothraki]: [
SuperBlocks.DataVis,
SuperBlocks.RelationalDb,
SuperBlocks.BackEndDevApis,
SuperBlocks.QualityAssurance,
SuperBlocks.SciCompPy,
SuperBlocks.DataAnalysisPy,
SuperBlocks.InfoSec,
SuperBlocks.MachineLearningPy,
SuperBlocks.CollegeAlgebraPy,
SuperBlocks.FoundationalCSharp,
SuperBlocks.CodingInterviewPrep,
SuperBlocks.ProjectEuler,
SuperBlocks.JsAlgoDataStructNew,
SuperBlocks.TheOdinProject
]
}
```
Be sure to only add the superblocks that are **not** fully translated and approved. The translated superblocks will be calculated from this object. When a new superblock is finished being fully translated, remove it from the array for that language.
See the `SuperBlocks` enum at the beginning of the same file for the full list of superblocks.
### Configure Search
Next, open the [`client/src/utils/algolia-locale-setup.ts`](https://github.com/freeCodeCamp/freeCodeCamp/blob/main/client/src/utils/algolia-locale-setup.ts) file. This data is used for the search bar that loads `/news` articles. While it is unlikely that you are going to test this functionality, missing the data for your language can lead to errors when attempting to build the codebase locally.
Add an object for your language to the `algoliaIndices` object. You should use the same values as the `english` object for local testing, replacing the `english` key with your language's `availableLangs` value.
> [!NOTE]
> If we have already deployed an instance of news in your target language, you can update the values to reflect the live instance. Otherwise, use the English values.
If you were to add Dothraki:
```js
const algoliaIndices = {
english: {
name: 'news',
searchPage: 'https://www.freecodecamp.org/news/search/'
},
espanol: {
name: 'news-es',
searchPage: 'https://www.freecodecamp.org/espanol/news/search/'
},
chinese: {
name: 'news-zh',
searchPage: 'https://chinese.freecodecamp.org/news/search/'
},
'chinese-traditional': {
name: 'news-zh',
searchPage: 'https://chinese.freecodecamp.org/news/search'
},
dothraki: {
name: 'news',
searchPage: 'https://www.freecodecamp.org/news/search/'
}
// If we already have /news in the target language up and running, you can update the values like this:
// dothraki: {
// name: 'news-mis',
// searchPage: 'https://www.freecodecamp.org/dothraki/news/search/'
// }
};
```
### Client UI
You will need to take an additional step to handle the client UI translations.
The Crowdin workflows will automatically pull down _some_ of the UI translations, but there are a couple of files that need to be moved manually.
You will want to copy the following files from [`/client/i18n/locales/english`](https://github.com/freeCodeCamp/freeCodeCamp/tree/main/client/i18n/locales/english) to `/client/i18n/locales/<your-language>`, and apply translations as needed:
- `links.json`
- `meta-tags.json`
- `motivation.json`
You don't have to have everything in these 3 files translated at first. It's possible to translate only the relevant parts and make adjustments later.
#### `links.json`
You can replace any URLs that you have corresponding pages ready in your language.
For example, if you have a publication in your language, you can replace the URL for `"news"`. If you want to translate articles listed in the footer links, see [How to Translate Articles in the Footer Links](language-lead-handbook.md#how-to-translate-articles-in-the-footer-links).
#### `meta-tags.json`
This file contains metadata for the web page of `/learn` in your language. You can translate the values for `"title"`, `"description"`, and `"social-description"`. The value for `"youre-unsubscribed"` is used when someone unsubscribes from Quincy's weekly email.
Also, you can translate or add relevant keywords in your language to the `"keywords"` array.
#### `motivation.json`
This file contains the compliments that will be displayed to campers when they complete a challenge, and motivational quotes that are displayed on the top page of `/learn`.
You can translate them, or even replace them with relevant compliments/quotes of your choice in your language.
### Enabling Localized Videos
This section is applicable only if you have localized videos in the challenges. Otherwise, you can skip this section.
For the video challenges, you need to change a few things. First, add the new locale to the GraphQL query in the [`client/src/templates/Challenges/video/Show.tsx`](https://github.com/freeCodeCamp/freeCodeCamp/blob/main/client/src/templates/Challenges/video/show.tsx) file. For example, adding Dothraki to the query:
```tsx
query VideoChallenge($slug: String!) {
challengeNode(fields: { slug: { eq: $slug } }) {
videoId
videoLocaleIds {
espanol
italian
portuguese
dothraki
}
...
```
Then add an id for the new language to any video challenge in an audited block. For example, if `auditedCerts` in `i18n.ts` includes `scientific-computing-with-python` for `dothraki`, then you must add a `dothraki` entry in `videoLocaleIds`. The frontmatter should then look like this:
```yml
videoLocaleIds:
espanol: 3muQV-Im3Z0
italian: hiRTRAqNlpE
portuguese: AelGAcoMXbI
dothraki: new-id-here
dashedName: introduction-why-program
---
```
Update the `VideoLocaleIds` interface in `client/src/redux/prop-types` to include the new language.
```ts
export interface VideoLocaleIds {
espanol?: string;
italian?: string;
portuguese?: string;
dothraki?: string;
}
```
And finally, update the challenge schema in `curriculum/schema/challengeSchema.js`.
```js
videoLocaleIds: Joi.when('challengeType', {
is: challengeTypes.video,
then: Joi.object().keys({
espanol: Joi.string(),
italian: Joi.string(),
portuguese: Joi.string(),
dothraki: Joi.string()
})
}),
```
## Testing Translations Locally
If you would like to test translations locally, before adding them to our main repository - skip the Crowdin workflow changes. Follow the steps for enabling a language, then download the translations from Crowdin and load them into your local code.
Because the language has not been approved for production, our scripts are not automatically downloading the translations yet. Only staff have access to directly download the translations - you are welcome to reach out to us in our [contributors chat room](https://discord.gg/PRyKn3Vbay), or you can translate the English markdown files locally for testing purposes.
Once you have the files, you will need to place them in the correct directory. For the curriculum challenges, you should place the certification folders (i.e. `01-responsive-web-design`) within the `curriculum/challenges/{lang}` directory. For our Dothraki translations, this would be `curriculum/challenges/dothraki`. The client translation `.json` files will go in the `client/i18n/locales/{lang}` directory.
Update your `.env` file to use your new language for `CLIENT_LOCALE` and `CURRICULUM_LOCALE`.
Once these are in place, you should be able to run `pnpm run develop` to view your translated version of freeCodeCamp.
> [!TIP]
> If you build the client in one language and then want to build it in a different language, you will need to use the command `pnpm run clean-and-develop` after changing the `.env` file, as Gatsby will cache the first language.
> [!ATTENTION]
> While you may perform translations locally for the purpose of testing, we remind everyone that translations should _not_ be submitted through GitHub and should only be done through Crowdin. Be sure to reset your local codebase after you are done testing.
## Show the language in the navigation menu
When your prior PR is merged and the VM for your language is ready, make another PR to show your language in the navigation menu.
In [`shared/config/i18n.ts`](https://github.com/freeCodeCamp/freeCodeCamp/blob/main/shared/config/i18n.ts) file, you have included your language in `hiddenLangs` array in the prior PR. Remove it from the array now.
```js
export const hiddenLangs = []; // Remove your language from the array
```
When this PR is merged and deployed, the curriculum in your language will be live.
# Deploying New Languages on `/news`
To deploy News for a new language, you'll need to create two PRs. One PR will be to the [CDN repo](https://github.com/freeCodeCamp/cdn), and the other will be to the [News repo](https://github.com/freeCodeCamp/news).
## Prep the CDN Repo for the New Language
News sources trending links and article titles from our CDN during the build and adds them to the footer. News also fetches Day.js files from the CDN during the build to localize dates and times for each language.
### Add a YAML File for Trending Articles
Clone the [CDN repo](https://github.com/freeCodeCamp/cdn) and create a new branch.
In the [`build/universal/trending`](https://github.com/freeCodeCamp/cdn/tree/main/build/universal/trending) directory, create a new file and name it `language.yaml`. For example, if you are launching Dothraki News, name the file `dothraki.yaml`.
Then copy the contents of the [`english.yaml`](https://github.com/freeCodeCamp/cdn/blob/main/build/universal/trending/english.yaml) trending file and paste it into the new YAML file you just created.
The contents will look something like this:
```yaml
article0title: 'Learn JavaScript'
article0link: 'https://www.freecodecamp.org/news/learn-javascript-free-js-courses-for-beginners/'
article1title: 'Linux ln Example'
article1link: 'https://www.freecodecamp.org/news/linux-ln-how-to-create-a-symbolic-link-in-linux-example-bash-command'
article2title: 'JS document.ready()'
article2link: 'https://www.freecodecamp.org/news/javascript-document-ready-jquery-example/'
article3title: ...
article3link: ...
...
```
### Add a Day.js Locale File for the New Language
By default, Day.js only includes English as a locale. To enable it to work with other languages, you need to add a new Day.js locale file to the CDN.
In the [`build/news-assets/dayjs/<version>/locale`](https://github.com/freeCodeCamp/cdn/tree/main/build/news-assets/dayjs/1.10.4/locale) directory, create a new file and name it `isocode.min.js`. For example, if you are launching Dothraki News, name the file `mis.min.js`.
> [!NOTE]
> The version number will change as the dependencies are updated.
Then, visit [this page on cdnjs](https://cdnjs.com/libraries/dayjs/1.10.4) with all available Day.js files for the version we're using, find the `https://cdnjs.cloudflare.com/ajax/libs/dayjs/<version>/locale/isocode.min.js` link for the new language, and open it in a new tab.
> [!NOTE]
> You only need to add the .../dayjs/\<version\>/_locale_/isocode.min.js locale file. You do not need to add any other Day.js files.
Copy the Day.js locale code from the new tab into the new file you created. For example, here is an un-minified version of the English locale code for Day.js:
```js
!(function (e, n) {
'object' == typeof exports && 'undefined' != typeof module
? (module.exports = n())
: 'function' == typeof define && define.amd
? define(n)
: (e.dayjs_locale_en = n());
})(this, function () {
'use strict';
return {
name: 'en',
weekdays: 'Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday'.split(
'_'
),
months:
'January_February_March_April_May_June_July_August_September_October_November_December'.split(
'_'
)
};
});
```
Then open a PR to the CDN repo to add both the YAML and Day.js files for review.
## Prep the News Repo for the New Language
The [News repo](https://github.com/freeCodeCamp/news) pulls data from a Ghost instance, the files you added to the CDN, builds News, and deploys it.
> [!WARN]
> Pull requests to the News repo _must_ come from the same repo. You should not work off of a fork for this step.
### Modify the Main Config File
Clone the News repo and create a new branch.
Open the `config/index.js` file to add the new language and configure the necessary values. There are a few objects and arrays to modify:
- `locales`: This array contains the active and upcoming News languages. These are the values that are used in the `.env` file to choose the Ghost instance and UI to use for each build. Add the text name of the new language in lowercase to this array.
- `localeCodes`: This object is a map of ISO codes for each language, and is used to configure i18next before building the UI. To add a new language, use the lowercase language name as the _key_ and the ISO 639-1 language code as the _value_.
- `algoliaIndices`: This object is a map of Algolia indices for each language. To add a new language, use the lowercase language name as the _key_, and `news-` followed by the lowercase ISO 639-1 language code as the _value_.
> [!NOTE]
> If you are unsure about the string to use while setting `algoliaIndices`, send a message to Kris (@scissorsneedfoodtoo), or someone else with access to Algolia, and ask them to check.
For example, if you are launching Dothraki News, here are what the objects / arrays above should look like:
```js
const locales = ['arabic', 'bengali', 'chinese', 'english', 'dothraki'];
const localeCodes = {
arabic: 'ar',
bengali: 'bn',
chinese: 'zh',
english: 'en',
dothraki: 'mis'
};
const algoliaIndices = {
arabic: 'news-ar',
bengali: 'news-bn',
chinese: 'news-zh',
english: 'news',
dothraki: 'news-mis'
};
```
### Add the i18next JSON Files for the New Language
Next, go to the `shared/config/i18n/locales` directory, create a new folder, and give it the name of the new language you're adding. For example, if you're launching Dothraki News, create a new folder named `dothraki`.
Then copy the JSON files from the `english` directory to your new folder.
In your new folder, open the `redirects.json` file and replace its contents with an empty array:
```json
[]
```
Then commit and push your branch directly to the News repo.
> [!NOTE]
> You need to be on one of the teams with access to the News repo to push branches directly to News. Currently, only the dev, i18n, and staff teams are allowed to do this.
Finally, open a PR for review.
Once both your PRs to the CDN and News repo have been approved, they can be merged.
> [!NOTE]
> Deployment will be handled subsequently by the staff. Here is a sample PR: [freeCodeCamp/news#485](https://github.com/freeCodeCamp/news/pull/485) of how they do it and more details are available in the [staff-wiki](https://staff-wiki.freecodecamp.org/docs/flight-manuals/news-instances#jamstack---news--assets).
-206
View File
@@ -1,206 +0,0 @@
# How to Help with Video Challenges
Video challenges are a new type of challenge in the freeCodeCamp curriculum.
A video challenge is a small section of a full-length video course on a particular topic. A video challenge page embeds a YouTube video. Each challenge page has a single multiple-choice question related to the video. A user must answer the question correctly before moving on to the next video challenge in the course.
The video challenge pages are created by members of the freeCodeCamp team. YouTube videos are also uploaded by members of the freeCodeCamp team. Many of the video challenges do not yet have questions associated with them.
You can help by creating multiple-choice questions related to video sections and adding the questions to the markdown files for the video challenges.
## Challenge Template
Below is a template of what the challenge markdown files look like.
````md
---
id: Unique identifier (alphanumerical, MongoDB_id)
title: Challenge Title
challengeType: 11
videoId: 'YouTube videoId for video challenge'
forumTopicId: 12345
---
# --description--
Challenge description text, in markdown
```html
<div>example code</div>
```
# --question--
These fields are currently used for the multiple-choice Python challenges.
## --text--
The question text goes here.
## --answers--
Answer 1
---
Answer 2
---
More answers
## --video-solution--
The number for the correct answer goes here.
````
## Creating Questions for Video Challenges
### Access the Video Challenge Markdown Files
You can find the markdown files for video challenges at the following locations in the curriculum:
- [Data Analysis with Python Course](https://github.com/freeCodeCamp/freeCodeCamp/tree/main/curriculum/challenges/english/08-data-analysis-with-python/data-analysis-with-python-course)
- [TensorFlow 2.0 Course](https://github.com/freeCodeCamp/freeCodeCamp/tree/main/curriculum/challenges/english/11-machine-learning-with-python/tensorflow)
- [Numpy Course](https://github.com/freeCodeCamp/freeCodeCamp/tree/main/curriculum/challenges/english/08-data-analysis-with-python/numpy)
- [How Neural Networks Work Course](https://github.com/freeCodeCamp/freeCodeCamp/tree/main/curriculum/challenges/english/11-machine-learning-with-python/how-neural-networks-work)
Pick a challenge markdown file from the options above.
### Skim through the video associated with the challenge and create a multiple-choice question
First, find the `videoId`.
For example, in the following code from the header of a video challenge markdown file, the `videoId` is "nVAaxZ34khk". On GitHub, the information should be laid out in a table format.
```
---
id: 5e9a093a74c4063ca6f7c14d
title: Data Analysis Example A
challengeType: 11
videoId: nVAaxZ34khk
---
```
Next, access the YouTube video with that `videoId`. The URL for the video will be:
https://www.youtube.com/watch?v=[videoId] (replace `videoId` in the URL with the video's ID - without square brackets)
In the example above, the URL is https://www.youtube.com/watch?v=nVAaxZ34khk
Skim the YouTube video with that `videoId` and think of a multiple-choice question based on the content of the video.
### Add the Question to the Markdown File
You can add the question locally or using the GitHub interface. To add the question locally, you need to [set up freeCodeCamp locally](how-to-setup-freecodecamp-locally.md). You can also find the file on GitHub and click the edit button to add the question right in your browser.
If a question has not yet been added to a particular video challenge, it will have the following default question:
```md
# --question--
## --text--
Question text
## --answers--
Answer 1
---
Answer 2
---
More answers
## --video-solution--
1
```
Add/Update the question text under the part that shows:
```
# --question--
## --text--
```
Add/Update answers (`Answer 1`, `Answer 2`, and so on) under `## --answers--`. Make sure to update the number under `## --video-solution--` with the correct answer number. You can add more possible answers using the same format. The questions and answers can be surrounded with quotation marks.
### Question examples
````md
# --question--
## --text--
What does this JavaScript code log to the console?
```js
console.log('hello world');
```
## --answers--
hello _world_
---
**hello** world
---
hello world
---
## --video-solution--
3
````
````md
# --question--
## --text--
What will print out after running this code:
```py
width = 15
height = 12.0
print(height/3)
```
## --answers--
39
---
4
---
4.0
---
5.0
---
5
## --video-solution--
3
````
For more examples, you can look at the markdown files for the following video course. All the challenges already have questions: [Python for Everybody Course](https://github.com/freeCodeCamp/freeCodeCamp/tree/main/curriculum/challenges/english/07-scientific-computing-with-python/python-for-everybody)
## Open a Pull Request
After creating one or more questions, you can commit the changes to a new branch and [open a pull request](how-to-open-a-pull-request.md).
-210
View File
@@ -1,210 +0,0 @@
# How to open a Pull Request (PR)
A pull request (PR), enables you to send changes from your fork on GitHub to freeCodeCamp.org's main repository. Once you are done making changes to the code, you can follow these guidelines to open a PR.
We expect our contributors to be aware of the process specific to this project. Following the guidelines carefully earns you the respect of fellow maintainers and saves everyone time.
Some examples of this are:
1. Do not edit files directly through GitHub – while you can, it's not a good idea.
2. Make sure the PR title follows [our convention](#prepare-a-good-pr-title).
3. Make sure you follow the PR checklist and not just tick things off; otherwise, we won't take you seriously.
4. Use the correct way to link issues in the description of the PR by updating the `XXXXXX`. Do not just add issue numbers everywhere and anywhere you feel like.
5. Do not "@mention" or request someone for reviews too many times.
We understand you are excited about contributing. As much as a maintainer will love to get back to you, they are busy people looking after hundreds of requests just like yours. Be patient, someone will get to you sooner or later.
6. Do not work directly off your `main` branch - create a new branch for the changes you are working on.
> [!NOTE]
> Your PR should be targeting changes to the English curriculum only. Read [this guide](index.md#translations) instead for contributing to translations.
## Prepare a Good PR Title
We use [conventional title and messages](https://www.conventionalcommits.org/) for commits and pull requests. The convention has the following format:
> `<type>([optional scope(s)]): <description>`
>
> For example:
>
> `fix(learn): tests for the do...while loop challenge`
Whenever you open a Pull Request (PR), you can use the below to determine the type, scope (optional), and description.
**Type:**
| Type | When to select |
|:------|:--------------------------------------------------------------------------------|
| fix | Changed or updated/improved functionality, tests, the wording of a lesson, etc. |
| feat | Only if you are adding new functionality, tests, etc. |
| chore | Changes that are not related to code, tests, or verbiage of a lesson. |
| docs | Changes to `/docs` directory or the contributing guidelines, etc. |
**Scope:**
You can select a scope from [this list of labels](https://github.com/freeCodeCamp/freeCodeCamp/labels?q=scope).
**Description:**
Keep it short (less than 30 characters) and simple; you can add more information in the PR description box and comments.
Some examples of good PR titles would be:
- `fix(a11y): improved search bar contrast`
- `feat: add more tests to HTML and CSS challenges`
- `fix(api,client): prevent CORS errors on form submission`
- `docs(i18n): fix links to be relative instead of absolute`
## Proposing a Pull Request
1. Once the edits have been committed, you will be prompted to create a pull request on your fork's GitHub Page.
<details>
<summary>See screenshot</summary>
![Image - Compare & pull request prompt on GitHub](https://contribute.freecodecamp.org/images/github/compare-pull-request-prompt.png)
</details>
2. By default, all pull requests should be against the freeCodeCamp main repo, `main` branch.
Make sure that your Base Fork is set to freeCodeCamp/freeCodeCamp when raising a Pull Request.
<details>
<summary>See screenshot</summary>
![Image - Comparing forks when making a pull request](https://contribute.freecodecamp.org/images/github/comparing-forks-for-pull-request.png)
</details>
3. Submit the pull request from your branch to freeCodeCamp's `main` branch.
4. Include a more detailed summary of the changes you made and how your changes are helpful in the body of your PR.
- You will be presented with a pull request template. This is a checklist that you should have followed before opening the pull request.
- Fill in the details as you see fit. Ensure that you give the reviewers enough context to review the changes. If the PR makes changes to the UI, be sure to include screenshots of the changes as well. All of this information will be reviewed and the reviewers will decide whether or not your pull request is accepted.
- If the PR is meant to address an existing GitHub Issue then, at the end of
your PR's description body, use the keyword _Closes_ with the issue number to [automatically close that issue if the PR is accepted and merged](https://help.github.com/en/articles/closing-issues-using-keywords).
> Example: `Closes #123` will close issue 123
5. Indicate if you have tested on a local copy of the site or not.
- This is very important when making changes that are not just edits to text content like documentation or a challenge description. Examples of changes that need local testing include JavaScript, CSS, or HTML, which could change the functionality or layout of a page.
- If your PR affects the behavior of a page, it should be accompanied by corresponding [Playwright integration tests](how-to-add-playwright-tests.md).
## Feedback on Pull Requests
> :tada: Congratulations on making a PR and thanks a lot for taking the time to contribute.
Our moderators will now take a look and leave you feedback. Please be patient with the fellow moderators and respect their time. All pull requests are reviewed in due course.
And as always, feel free to ask questions on the ['Contributors' category on our forum](https://forum.freecodecamp.org/c/contributors) or [the contributors chat room](https://discord.gg/PRyKn3Vbay).
> [!TIP]
> If you are to be contributing more pull requests, we recommend you read the [making changes and syncing](how-to-setup-freecodecamp-locally.md#making-changes-locally) guidelines to avoid having to delete your fork.
## Conflicts on a Pull Request
Conflicts can arise because many contributors work on the repository, and changes can break your PR which is pending a review and merge.
Since we squash all commits, you may not need to do a rebase. However, if a rebase is requested, check our [For Usual Bug Fixes and Features](#for-usual-bug-fixes-and-features) or [For Upcoming Curriculum and Features](#for-upcoming-curriculum-and-features) guides to learn how to do this process for your corresponding PR.
### For Usual Bug Fixes and Features
When you are working on regular bugs and features on our development branch `main`, you are able to do a simple rebase:
1. Rebase your local copy:
```bash
git checkout <pr-branch>
git pull --rebase upstream main
```
2. Resolve any conflicts and add / edit commits
```bash
# Either
git add .
git commit -m "chore: resolve conflicts"
# Or
git add .
git commit --amend --no-edit
```
3. Push back your changes to the PR
```bash
git push --force origin <pr-branch>
```
### For Upcoming Curriculum and Features
When you are working on features for our upcoming curriculum `next-*` branches, you have to do a `cherry-pick`:
1. Make sure your upstream comes in sync with your local:
```bash
git checkout main
git fetch --all --prune
git checkout next-python-projects
git reset --hard upstream/next-python-projects
```
2. Take a backup
a. Either delete your local branch after taking a backup (if you still have it locally):
```bash
git checkout <pr-branch-name>
# example:
# git checkout feat/add-numpy-video-question
git checkout -b <backup-branch-name>
# example:
# git checkout -b backup-feat/add-numpy-video-question
git branch -D <pr-branch-name>
```
b. Or just a backup of your PR branch (if you do not have it locally):
```bash
git checkout -b <backup-branch-name> origin/<pr-branch-name>
# example:
# git checkout -b backup-feat/add-numpy-video-question origin/feat/add-numpy-video-question
```
3. Start off with a clean slate:
```bash
git checkout -b <pr-branch-name> next-python-projects
git cherry-pick <commit-hash>
```
4. Resolve any conflicts, cleanup, and install dependencies and run tests
```bash
pnpm run clean
pnpm install
FCC_SUPERBLOCK='<superblock-name>' pnpm run test:curriculum
# example:
# FCC_SUPERBLOCK='python-for-everybody' pnpm run test:curriculum
```
5. If everything looks good, push back to the PR
```bash
git push --force origin <pr-branch-name>
```
-57
View File
@@ -1,57 +0,0 @@
# How to Proofread Translations
Our proofreading team is responsible for ensuring that translations accurately reflect the source text. We trust our proofreaders to ensure that we have very high quality translations.
All our translations are done by hand, by real humans. Proofreading ensures that there is a consistent tone across all our translated resources like the curriculum.
To begin proofreading, visit [our translation platform](https://translate.freecodecamp.org) and login. Select "Go to console" in the top navigation bar to switch from the public view to the workspace view.
## Select a File
You should see the list of projects you have been granted access to. Select the project that you would like to proofread, then select the language.
![Image - Proofreading File Tree](https://contribute.freecodecamp.org/images/crowdin/proof-file-tree.png)
You should now see the list of available files. Choose your file by selecting the `Proofread` button on the right of that file, then choosing `Proofreading` from the drop-down menu that appears.
> [!NOTE]
> If you are in this workspace view, but want to work on [translating a file](how-to-translate-files.md) instead of proofreading, you may select `Crowdsourcing` from the dropdown menu instead.
## Proofread Translations
![Image - Proofreading View](https://contribute.freecodecamp.org/images/crowdin/proofread.png)
<!--Add proofread/crowdsource button to the image-->
Here you will see the list of strings in the selected file, with their related translations. The translation that is displayed here is the translation that has received the highest score (between upvotes and downvotes) from the translation community.
While you can view _all_ proposed translations for a given string, the community scores (determined by the upvotes and downvotes) should be taken into consideration when choosing which translation to approve. The community can review proposed translations and recommend which one is most accurate and clear.
1. This is the original string (in English).
2. This is the matching translated string. The most popular translation proposal, based on upvotes and downvotes, will be displayed here.
3. Clicking this checkmark button will approve that translation.
4. Crowdin will display the status of each string. `Done` means a translation has been approved and will be downloaded on our next Crowdin pull. `Todo` means the string has not been proofread. `Hidden` means the string is locked and _should not be translated_. `Comment` means the string has a related comment.
5. Translations can be selected with the checkboxes and approved here in one bulk action.
6. You can view the community proposed translations, their popularity scores, and Crowdin suggested translations here.
7. This button shows/hides the right-hand side display pane, where you can view translations, comments, translation memory, and glossary terms.
8. Crowdin displays error messages here from the quality assurance checks. In other words, if something does not seem correct in the translation, Crowdin will notify you. These translations should be approved with care.
No additional actions are required once a file has been proofread.
> [!NOTE]
> Approving a string in the proofreading view will mark it as complete and it will be downloaded in our next pull from Crowdin to GitHub.
## Becoming a Proofreader
If you have any questions, or are interested in becoming a proofreader, feel free to reach out to us in our [contributors chat room](https://discord.gg/PRyKn3Vbay). We will typically grant you proofreading access if you have been contributing to freeCodeCamp for a while.
Our staff team and community moderators teams are always looking for kind volunteers like you who help us make high quality translations available to the world.
> [!NOTE]
> Crowdin will allow you to approve your translations. In general, it is best to allow another proofreader to review your proposed translations as extra safety to ensure there are no errors.
## Creating a Channel on Chat for a World Language
For the most part, we encourage you to use the [contributors chat](https://discord.gg/PRyKn3Vbay) room for all correspondence. However if the team of volunteer translators grows for a certain language, we can consider creating an additional break-out channel for the language.
If you are already a proofreader and are interested in having a dedicated channel on our chat servers for a specific language, [fill out this form](https://forms.gle/XU5CyutrYCgDYaVZA).
-302
View File
@@ -1,302 +0,0 @@
Follow these guidelines for setting up a development environment for freeCodeCamp. This is highly recommended if you want to contribute regularly.
## Choose between Gitpod or your Own Machine (local setup)
> [!ATTENTION]
> - freeCodeCamp does not build and run natively on Windows, you will [need to use WSL2](how-to-setup-wsl.md) for a Linux-like setup on Windows.
> - You can't use Windows Command Prompt, Git Bash or PowerShell to build and run the codebase.
> - Note that if using Windows, the hardware requirements need to be more than [what we mention](how-to-setup-freecodecamp-locally?id=how-to-prepare-your-local-machine) to accommodate for WSL-based setup.
If you are looking to make a one-off contribution, you should use Gitpod to make changes. The Gitpod setup launches a ready-to-code environment in a few minutes in your web browser. To contribute long-term, we recommend you set up freeCodeCamp on your local machine.
Here are some pros and cons which should help you decide which option is best for you:
| Gitpod | Your own machine (local setup) |
| ----------------------------------------------------------------- | --------------------------------------------------------------------- |
| No minimum hardware requirements | Specific and minimum requirements |
| No need to install any software | Additional software required |
| Always up to date copy of repository | Need to maintain a local copy of the repository |
| Slower and can take a few minutes to launch | Faster and can be launched in seconds |
| Need an internet connection to work | Minimal internet connection required (once setup) |
| Some tasks like compilation and tests can take longer to complete | Faster completion of tasks (depending on your machine's capabilities) |
### How to Prepare a Gitpod Workspace
We have automated the process of installing all the dependencies & tools you will need. With Gitpod you get a free ready-to-code environment in a few minutes, and is useful if you do not have access to a computer or want to make one-time changes.
There are various ways to launch a Gitpod workspace:
1. **(Fastest)** Prepend `gitpod.io/#` in front of any URL from GitHub.
For example, if you visit your fork at `https://github.com/YOUR_USER_NAME/freeCodeCamp.git`, add `gitpod.io/#` in the front of the URL in the address bar and hit enter.
That is you can navigate to `gitpod.io/#https://github.com/YOUR_USER_NAME/freeCodeCamp.git` and you should see a workspace created for you. This works for any repository or pull-request on GitHub.
2. Alternatively install one of the below extensions for your browser.
- [Chrome Webstore](https://chrome.google.com/webstore/detail/gitpod-always-ready-to-co/dodmmooeoklaejobgleioelladacbeki) - works with Chromium-based browsers like Google Chrome, Brave, Edge, etc.
- [Firefox Add-on](https://addons.mozilla.org/en-US/firefox/addon/gitpod) - Firefox
Once installed you will see a 'Gitpod' button on every repository, pull-request, etc. as a handy shortcut to launch a workspace from there. See the extension page for details, screenshots, etc.
That's it, you can now skip to the 'syncing up from parent' section after you have launched a Gitpod workspace. Most parts of this guide applies to Gitpod workspaces, but be mindful of [how the URLs & Ports work within a Gitpod](https://www.gitpod.io/docs/configure/workspaces/ports) workspace.
**Note: Troubleshooting port issues on Gitpod**
Sometimes the service on port `8000` doesn't go live. This is common when you are restarting an inactive workspace.
If the service is not coming up on port `8000`, you can troubleshoot using these steps:
- **Start the server**: Run `pnpm run develop:server` in one terminal window from the root project directory (`/workspace/freeCodeCamp`) to start the server.
- **Start the client**: In another terminal window, run `pnpm run develop -- -H '0.0.0.0'` from the client directory (`/workspace/freeCodeCamp/client`) to start the client.
This should make port `8000` available.
### How to Prepare your Local Machine
Here is a minimum system requirement for running freeCodeCamp locally:
- 8 GB RAM
- Relatively fast CPU (4+ cores)
- Windows 10 or 11 (with WSL), macOS, or Linux
Start by installing the prerequisite software for your operating system.
We primarily support development on Linux and Unix-based systems like Ubuntu and macOS. You can develop on Windows 10 or 11 with WSL2 only. You can follow [this guide](how-to-setup-wsl.md) to set up WSL2. You can't use Command Prompt, Git Bash or PowerShell to run freeCodeCamp natively within windows.
#### Prerequisites:
| Prerequisite | Version | Notes |
| --------------------------------------------------------------------------------------------- | ------- | ------------------------------------------------------------------------------------------- |
| [Node.js](http://nodejs.org) | `20.x` | We use the "Active LTS" version, See [LTS Schedule](https://nodejs.org/en/about/releases/). |
| [pnpm](https://pnpm.io/installation) | `8.x` | - |
| [MongoDB Community Server](https://docs.mongodb.com/manual/administration/install-community/) | `5.0.x` | - |
> [!ATTENTION]
> If you have a different version, please install the recommended version. We can only support installation issues for recommended versions. See [troubleshooting section](troubleshooting-development-issues.md) for details.
If Node.js is already installed on your machine, run the following commands to validate the versions:
```bash
node -v
pnpm -v
```
> [!TIP]
> We highly recommend updating to the latest stable releases of the software listed above, also known as Long Term Support (LTS) releases.
Once you have the prerequisites installed, you need to prepare your development environment. This is common for many development workflows, and you will only need to do this once.
##### Follow these steps to get your development environment ready:
1. Install [Git](https://git-scm.com/) or your favorite Git client, if you haven't already. Update to the latest version; the version that came bundled with your OS may be outdated.
2. (Optional but recommended) [Set up an SSH Key](https://help.github.com/articles/generating-an-ssh-key/) for GitHub.
3. Install a code editor of your choice. If you aren't sure which one to use, we recommend [Visual Studio Code](https://code.visualstudio.com/) — it's free and open source.
4. Set up linting for your code editor.
You should have [ESLint running in your editor](http://eslint.org/docs/user-guide/integrations.html), and it will highlight anything that doesn't conform to [freeCodeCamp's JavaScript Style Guide](http://forum.freecodecamp.org/t/free-code-camp-javascript-style-guide/19121).
> [!TIP]
> Please do not ignore any linting errors. They are meant to **help** you and to ensure a clean and simple codebase.
## Fork the Repository on GitHub
[Forking](https://help.github.com/articles/about-forks/) is a step where you get your own copy of freeCodeCamp's main repository (a.k.a _repo_) on GitHub.
This is essential, as it allows you to work on your own copy of freeCodeCamp on GitHub, or to download (clone) your repository to work on locally. Later, you will be able to request changes to be pulled into the main repository from your fork via a pull request (PR).
> [!TIP]
> The main repository at `https://github.com/freeCodeCamp/freeCodeCamp` is often referred to as the `upstream` repository.
>
> Your fork at `https://github.com/YOUR_USER_NAME/freeCodeCamp` is often referred to as the `origin` repository. `YOUR_USER_NAME` would be replaced with your GitHub username.
**Follow these steps to fork the `https://github.com/freeCodeCamp/freeCodeCamp` repository:**
1. Go to the freeCodeCamp repository on GitHub: <https://github.com/freeCodeCamp/freeCodeCamp>
2. Click the "Fork" Button in the upper right-hand corner of the interface ([More Details Here](https://help.github.com/articles/fork-a-repo/))
3. After the repository has been forked, you will be taken to your copy of the freeCodeCamp repository at `https://github.com/YOUR_USER_NAME/freeCodeCamp` (`YOUR_USER_NAME` would be replaced with your GitHub user name.)
<details>
<summary>
How to fork freeCodeCamp on GitHub (screenshot)
</summary>
<br>
<img src="https://raw.githubusercontent.com/freeCodeCamp/freeCodeCamp/main/docs/images/github/how-to-fork-freeCodeCamp.gif" alt="How to fork freeCodeCamp on GitHub">
</details>
## Clone your Fork from GitHub
[Cloning](https://help.github.com/articles/cloning-a-repository/) is where you **download** a copy of a repository from a `remote` location that is either owned by you or by someone else. In your case, this remote location is your `fork` of freeCodeCamp's repository that should be available at `https://github.com/YOUR_USER_NAME/freeCodeCamp`. (`YOUR_USER_NAME` would be replaced with your GitHub user name.)
> [!WARNING]
> If you are working on a WSL2 Linux Distro, you might get performance and stability issues by running this project in a folder which is shared between Windows and WSL2 (e.g. `/mnt/c/Users/`).
> Therefore we recommend to clone this repo into a folder which is mainly used by your WSL2 Linux Distro and not directly shared with Windows (e.g. `~/PROJECTS/`).
>
> See [this GitHub Issue](https://github.com/freeCodeCamp/freeCodeCamp/issues/40632) for further information about this problem.
Run these commands on your local machine:
1. Open a Terminal / Command Prompt / Shell in your projects directory
_i.e.: `/yourprojectsdirectory/`_
2. Clone your fork of freeCodeCamp, replacing `YOUR_USER_NAME` with your GitHub Username
```bash
git clone --depth=1 https://github.com/YOUR_USER_NAME/freeCodeCamp.git
```
This will download the entire freeCodeCamp repository to your projects directory.
Note: `--depth=1` creates a shallow clone of your fork, with only the most recent history/commit.
## Set up Syncing from Parent
Now that you have downloaded a copy of your fork, you will need to set up an `upstream` remote to the parent repository.
[As mentioned earlier](#fork-the-repository-on-github), the main repository is referred to as the `upstream` repository. Your fork is referred to as the `origin` repository.
You need a reference from your local clone to the `upstream` repository in addition to the `origin` repository. This is so that you can sync changes from the main repository without the requirement of forking and cloning repeatedly.
1. Change the directory to the new freeCodeCamp directory:
```bash
cd freeCodeCamp
```
2. Add a remote reference to the main freeCodeCamp repository:
```bash
git remote add upstream https://github.com/freeCodeCamp/freeCodeCamp.git
```
3. Ensure the configuration looks correct:
```bash
git remote -v
```
The output should look something like below (replacing `YOUR_USER_NAME` with your GitHub username):
```bash
origin https://github.com/YOUR_USER_NAME/freeCodeCamp.git (fetch)
origin https://github.com/YOUR_USER_NAME/freeCodeCamp.git (push)
upstream https://github.com/freeCodeCamp/freeCodeCamp.git (fetch)
upstream https://github.com/freeCodeCamp/freeCodeCamp.git (push)
```
## Running freeCodeCamp Locally
Now that you have a local copy of freeCodeCamp, you can follow these instructions to run it locally. This will allow you to:
- Preview edits to pages as they would appear on the learning platform.
- Work on UI related issues and enhancements.
- Debug and fix issues with the application servers and client apps.
If you do run into issues, first perform a web search for your issue and see if it has already been answered. If you cannot find a solution, please search our [GitHub issues](https://github.com/freeCodeCamp/freeCodeCamp/issues) page for a solution and report the issue if it has not yet been reported.
And as always, feel free to ask questions on the ['Contributors' category on our forum](https://forum.freecodecamp.org/c/contributors) or [our chat server](https://discord.gg/PRyKn3Vbay).
### Configuring Dependencies
#### Step 1: Set up the Environment Variable File
The default API keys and environment variables are stored in the file `sample.env`. This file needs to be copied to a new file named `.env` that is accessed dynamically during the installation step.
```bash
# Create a copy of the "sample.env" and name it ".env".
# Populate it with the necessary API keys and secrets
```
```bash
cp sample.env .env
```
The keys in the `.env` file are _not_ required to be changed to run the app locally. You can leave the default values copied over from `sample.env` as-is.
> [!TIP]
> Keep in mind if you want to use services like Auth0 or Algolia, you'll have to acquire your own API keys for those services and edit the entries accordingly in the `.env` file.
#### Step 2: Install Dependencies
This step will install the dependencies required for the application to run:
```bash
pnpm install && pnpm run create:shared
```
#### Step 3: Start MongoDB and Seed the Database
Before you can run the application locally, you will need to start the MongoDB service.
> [!NOTE]
> Unless you have MongoDB running in a setup different than the default, the URL stored as the `MONGOHQ_URL` value in the `.env` file should work fine. If you are using a custom configuration, modify this value as needed.
>
> If you followed along with the [Windows 10 via WSL2 Setup Guide](how-to-setup-wsl.md), then you should be able to skip this step if the MongoDB server from that guide is already running. You can confirm this by checking that you can reach `http://localhost:27017` on your local machine.
Start the MongoDB server in a separate terminal:
```bash
mongod
```
> [!TIP]
> You can avoid having to start MongoDB every time by installing it as a background service. You can [learn more about it in their documentation for your OS](https://docs.mongodb.com/manual/administration/install-community/)
Next, let's seed the database. In this step, we run the below command that fills the MongoDB server with some initial data sets that are required by services. These include a few schemas, among other things.
```bash
pnpm run seed
```
By default, you will be signed in as a new user without any completed certifications. Run the following command if you need to develop with completed certifications or write Playwright tests:
```bash
pnpm run seed:certified-user
```
> [!WARNING]
> Running `pnpm run seed:certified-user` will log you out. You will have to clear your browser cookies and sign in again.
#### Step 4: Start the freeCodeCamp Client Application and API Server
You can now start up the API server and the client applications.
```bash
pnpm run develop
```
This single command will fire up all the services, including the API server and the client applications available for you to work on.
Once ready, open a web browser and visit <http://localhost:8000>. If the app loads, sign in. Congratulations – you're all set! You now have a copy of freeCodeCamp's entire learning platform running on your local machine.
The API server serves endpoints at `http://localhost:3000`. The Gatsby app serves the client application at `http://localhost:8000`.
While you are logged in, if you visit <http://localhost:3000/explorer> you should see the available APIs.
> [!WARNING]
> Clearing your cookies or running `pnpm run seed:certified-user` will log you out, and you will have to sign in again.
If you have issues while installing it, check out the [troubleshooting section](troubleshooting-development-issues.md).
## Quick Commands Reference
A quick reference to the commands that you will need when working locally.
| command | description |
| ----------------- | ----------------------------------------------------------------------------- |
| `pnpm install` | Installs / re-installs all dependencies and bootstraps the different services. |
| `pnpm run seed` | Creates authorized test users and inserts them into MongoDB. Also runs `seed:exams` and `seed:surveys` below. |
| `pnpm run seed:certified-user` | Creates authorized test users with certifications fully completed, and inserts them into MongoDB. |
| `pnpm run seed:exams` | Creates exams and inserts them into MongoDB. |
| `pnpm run seed:surveys` | Creates surveys for defaults users and inserts them into MongoDB. |
| `pnpm run develop` | Starts the freeCodeCamp API Server and Client Applications. |
| `pnpm run clean` | Uninstalls all dependencies and cleans up caches. |
@@ -1,506 +0,0 @@
Follow this guide for setting up the freeCodeCamp mobile app locally on your system. This is highly recommended if you want to contribute regularly.
Some of the contribution workflows – like fixing bugs in the codebase – need you to run the freeCodeCamp app locally.
## How to Prepare your Local Machine
Start by installing the prerequisite software for your operating system.
### Prerequisites
| Prerequisite | Version | Notes |
| --------------------------------- | ------- | ---------------------------------------- |
| [Flutter](https://flutter.dev/) | `3.x` | - |
| Dart (comes bundled with Flutter) | `3.x` | We use the version bundled with Flutter. |
> [!ATTENTION]
> If you have a different version, please install the recommended version. We can only support installation issues for recommended versions.
If Flutter is already installed on your machine, run the following commands to validate the versions:
```bash
flutter --version
dart --version
```
> [!TIP]
> We highly recommend updating to the latest stable releases of the software listed above.
Once you have the prerequisites installed, you need to prepare your development environment. This is common for many development workflows, and you will only need to do this once.
#### Follow these steps to get your development environment ready:
1. Install [Git](https://git-scm.com/) or your favorite Git client, if you haven't already. Update to the latest version; the version that came bundled with your OS may be outdated.
2. Set up [Android Studio](https://developer.android.com/studio) and [Android Emulators](https://developer.android.com/studio/run/managing-avds) with the latest released Android version. We recommend using the Pixel 3a XL and Nexus One(for emulating smaller screens).
3. (Optional for MacOS) Set up Xcode and iOS Simulator with the latest released iOS version.
4. (Optional but recommended) [Set up an SSH Key](https://help.github.com/articles/generating-an-ssh-key/) for GitHub.
5. Install a code editor of your choice.
We highly recommend using [Visual Studio Code](https://code.visualstudio.com/) or Android Studio. We also recommend installing the official [extensions](https://docs.flutter.dev/get-started/editor?tab=vscode).
## Fork the Repository on GitHub
[Forking](https://help.github.com/articles/about-forks/) is a step where you get your own copy of the repository (a.k.a _repo_) on GitHub.
This is essential, as it allows you to work on your own copy of the freeCodeCamp mobile app on GitHub, or to download (clone) your repository to work on locally. Later, you will be able to request changes to be pulled into the main repository from your fork via a pull request (PR).
> [!TIP]
> The main repository at `https://github.com/freeCodeCamp/mobile` is often referred to as the `upstream` repository.
>
> Your fork at `https://github.com/YOUR_USER_NAME/mobile` is often referred to as the `origin` repository. `YOUR_USER_NAME` would be replaced with your GitHub username.
**Follow these steps to fork the `https://github.com/freeCodeCamp/mobile` repository:**
1. Go to the freeCodeCamp mobile repository on GitHub: <https://github.com/freeCodeCamp/mobile>
2. Click the "Fork" Button in the upper right-hand corner of the interface ([More Details Here](https://help.github.com/articles/fork-a-repo/))
3. After the repository has been forked, you will be taken to your copy of the repository at `https://github.com/YOUR_USER_NAME/mobile` (`YOUR_USER_NAME` would be replaced with your GitHub user name.)
## Clone your Fork from GitHub
[Cloning](https://help.github.com/articles/cloning-a-repository/) is where you **download** a copy of a repository from a `remote` location that is either owned by you or by someone else. In your case, this remote location is your `fork` of freeCodeCamp's repository which should be available at `https://github.com/YOUR_USER_NAME/mobile`. (`YOUR_USER_NAME` would be replaced with your GitHub user name.)
Run these commands on your local machine:
1. Open a Terminal / Command Prompt / Shell in your projects directory
_i.e.: `/yourprojectsdirectory/`_
2. Clone your fork of freeCodeCamp, replacing `YOUR_USER_NAME` with your GitHub Username
```bash
git clone --depth=1 https://github.com/YOUR_USER_NAME/mobile.git
```
This will download the entire freeCodeCamp mobile repository to your projects directory.
Note: `--depth=1` creates a shallow clone of your fork, with only the most recent history/commit.
## Set up Syncing from Parent
Now that you have downloaded a copy of your fork, you will need to set up an `upstream` remote to the parent repository.
[As mentioned earlier](#fork-the-repository-on-github), the main repository is referred to as the `upstream` repository. Your fork is referred to as the `origin` repository.
You need a reference from your local clone to the `upstream` repository in addition to the `origin` repository. This is so that you can sync changes from the main repository without the requirement of forking and cloning repeatedly.
1. Change directory to the new `mobile` directory:
```bash
cd mobile
```
2. Add a remote reference to the main freeCodeCamp mobile repository:
```bash
git remote add upstream https://github.com/freeCodeCamp/mobile.git
```
3. Ensure the configuration looks correct:
```bash
git remote -v
```
The output should look something like below (replacing `YOUR_USER_NAME` with your GitHub username):
```bash
origin https://github.com/YOUR_USER_NAME/mobile.git (fetch)
origin https://github.com/YOUR_USER_NAME/mobile.git (push)
upstream https://github.com/freeCodeCamp/mobile.git (fetch)
upstream https://github.com/freeCodeCamp/mobile.git (push)
```
## Running freeCodeCamp Mobile App Locally
Now that you have a local copy of the mobile app, you can follow these instructions to run it locally.
If you do run into issues, first perform a web search for your issue and see if it has already been answered. If you cannot find a solution, please search our [GitHub issues](https://github.com/freeCodeCamp/mobile/issues) page for a solution and report the issue if it has not yet been reported.
And as always, feel free to ask questions on the ['Contributors' category on our forum](https://forum.freecodecamp.org/c/contributors) or [our chat server](https://discord.gg/PRyKn3Vbay).
> [!NOTE]
> The `mobile` directory contains two folders ie. `mobile-api` and `mobile-app`. `mobile-api` contains the API code used for serving the podcasts. `mobile-app` contains the Flutter app which is where you should be when you follow the below steps.
### Configuring Dependencies
#### Step 1: Set Up the Environment Variable File
The default API keys and environment variables are stored in the file `sample.env`. This file needs to be copied to a new file named `.env` which is accessed dynamically during the installation step. Remember to change the directory to `mobile-app` before running the following commands.
```bash
# Create a copy of the "sample.env" and name it ".env".
# Populate it with the necessary API keys and secrets:
```
#### **macOS/Linux**
```bash
cp sample.env .env
```
#### **Windows**
```bash
copy sample.env .env
```
The keys in the `.env` file are _not_ required to be changed to run the app locally. You can leave the default values copied over from `sample.env` as-is.
#### Step 2: Install dependencies
This step will install the dependencies required for the application to run:
```bash
flutter pub get
```
#### Step 3: Start the freeCodeCamp mobile app
Start the emulator of your choice(Android or iOS) and wait for the bootup process to complete.
You can now start the app by running the following command:
```bash
flutter run
```
> [!TIP]
> If you're using VSCode or Android Studio then you can easily start the app without having to execute any terminal commands. More information [here](https://docs.flutter.dev/get-started/test-drive).
## Making Changes Locally
You can now make changes to files and commit your changes to the local clone of your fork.
Follow these steps:
1. Validate that you are on the `main` branch:
```bash
git status
```
You should get an output like this:
```bash
On branch main
Your branch is up-to-date with 'origin/main'.
nothing to commit, working directory clean
```
If you are not on main or your working directory is not clean, resolve any outstanding files/commits and checkout `main`:
```bash
git checkout main
```
2. Sync the latest changes from the upstream `main` branch to your local main branch:
> [!WARNING]
> If you have any outstanding pull request that you made from the `main` branch of your fork, you will lose them at the end of this step.
>
> You should ensure your pull request is merged by a moderator before performing this step. To avoid this scenario, you should **always** work on a branch other than the `main`.
This step **will sync the latest changes** from the main repository of freeCodeCamp mobile. It is important that you rebase your branch on top of the latest `upstream/main` as often as possible to avoid conflicts later.
Update your local copy of the freeCodeCamp mobile upstream repository:
```bash
git fetch upstream
```
Hard reset your main branch with the freeCodeCamp mobile main:
```bash
git reset --hard upstream/main
```
Push your main branch to your origin to have a clean history on your fork on GitHub:
```bash
git push origin main --force
```
You can validate that your current main matches the upstream/main by performing a diff:
```bash
git diff upstream/main
```
The resulting output should be empty.
3. Create a fresh new branch:
Working on a separate branch for each issue helps you keep your local work copy clean. You should never work on the `main`. This will soil your copy of freeCodeCamp mobile and you may have to start over with a fresh clone or fork.
Check that you are on `main` as explained previously, and branch off from there:
```bash
git checkout -b fix/update-guide-for-xyz
```
Your branch name should start with a `fix/`, `feat/`, `docs/`, etc. Avoid using issue numbers in branches. Keep them short, meaningful, and unique.
Some examples of good branch names are:
```md
fix/update-challenges-for-react
fix/update-guide-for-html-css
fix/platform-bug-sign-in-issues
feat/add-guide-article-for-javascript
translate/add-spanish-basic-html
```
4. Edit pages and work on code in your favorite text editor.
5. Once you are happy with the changes you should optionally run the mobile app locally to preview the changes.
6. Make sure you fix any errors and check the formatting of your changes.
7. Check and confirm the files you are updating:
```bash
git status
```
This should show a list of `unstaged` files that you have edited.
```bash
On branch feat/documentation
Your branch is up to date with 'upstream/feat/documentation'.
Changes were not staged for commit:
(use "git add/rm <file>..." to update what will be committed)
(use "git checkout -- <file>..." to discard changes in the working directory)
modified: README.md
modified: mobile-app/lib/main.dart
...
```
8. Stage the changes and make a commit:
In this step, you should only mark files that you have edited or added yourself. You can perform a reset and resolve files that you did not intend to change if needed.
```bash
git add path/to/my/changed/file.ext
```
Or you can add all the `unstaged` files to the staging area:
```bash
git add .
```
Only the files that were moved to the staging area will be added when you make a commit.
```bash
git status
```
Output:
```bash
On branch feat/documentation
Your branch is up to date with 'upstream/feat/documentation'.
Changes to be committed:
(use "git reset HEAD <file>..." to unstage)
modified: README.md
modified: mobile-app/lib/main.dart
```
Now, you can commit your changes with a short message like so:
```bash
git commit -m "fix: my short commit message"
```
Some examples:
```md
fix: update guide article for Java - for loop
feat: add guide article for alexa skills
```
Optional:
We highly recommend making a conventional commit message. This is a good practice that you will see on some of the popular Open Source repositories. As a developer, this encourages you to follow standard practices.
Some examples of conventional commit messages are:
```md
fix: update HTML guide article
fix: update build scripts for Travis-CI
feat: add article for JavaScript hoisting
docs: update contributing guidelines
```
Keep these short, not more than 50 characters. You can always add additional information in the description of the commit message.
This does not take any additional time than an unconventional message like 'update file' or 'add index.md'
You can learn more about why you should use conventional commits [here](https://www.conventionalcommits.org/en/v1.0.0-beta.2/#why-use-conventional-commits).
9. If you realize that you need to edit a file or update the commit message after making a commit you can do so after editing the files with:
```bash
git commit --amend
```
This will open up a default text editor like `nano` or `vi` where you can edit the commit message title and add/edit the description.
10. Next, you can push your changes to your fork:
```bash
git push origin branch/name-here
```
## Running mobile curriculum tests
> [!NOTE]
> You only need to follow this section if you're modifying the challenge test runner in the mobile app. Otherwise, you can go to the next section on [how to open a pull request](#proposing-a-pull-request-pr).
1. Clone a copy of the [freeCodeCamp repo](https://github.com/freeCodeCamp/freeCodeCamp) locally outside of your local copy of the freeCodeCamp mobile repo. Your folder structure should look like this:
```bash
├── freeCodeCamp
├── mobile
```
2. Change the directory to the freeCodeCamp repo:
```bash
cd freeCodeCamp
```
3. Make a copy of the `.env` file:
#### **macOS/Linux**
```bash
cp sample.env .env
```
#### **Windows**
```bash
copy sample.env .env
```
4. Install the dependencies for the freeCodeCamp repo:
```bash
pnpm install && pnpm run create:shared
```
5. Generate the challenge data JSON file:
```bash
pnpm run build:curriculum
```
6. Copy the generated JSON file to the mobile app:
#### **macOS/Linux**
```bash
cp ./shared/config/curriculum.json ../mobile/mobile-app/curriculum.json
```
#### **Windows**
```bash
copy .\shared\config\curriculum.json ..\mobile\mobile-app\curriculum.json
```
7. Change directory to the mobile app:
```bash
cd ../mobile/mobile-app
```
8. Install the dependencies for the mobile app:
```bash
flutter pub get
```
9. Update the test file to use the challenge data JSON file:
```bash
sed -i '' 's/..\/..\/shared\/config\/curriculum.json/.\/curriculum.json/g' test/widget_test.dart
```
10. Generate the challenge files:
```bash
flutter test test/widget_test.dart
```
11. Start a local server to serve the challenge files with the help of `serve` package:
```bash
npx serve
```
12. In a different terminal go back to the freeCodeCamp repo:
```bash
cd ../../freeCodeCamp
```
13. Run the cypress tests:
```bash
pnpm cypress run --config retries=1,screenshotOnRunFailure=false,video=false,baseUrl=http://localhost:3000/generated-tests/,specPattern=cypress/e2e/mobile-learn/test-challenges.js -s cypress/e2e/mobile-learn/test-challenges.js -b chrome
```
## Proposing a Pull Request (PR)
After you've committed your changes, check here for [how to open a Pull Request](how-to-open-a-pull-request.md).
<!-- ## Quick commands reference - NEED TO DISCUSS ABOUT THIS
A quick reference to the commands that you will need when working locally.
| command | description |
| -------------------------------------------------------------- | ----------------------------------------------------------------------------------- |
| `npm ci` | Installs / re-install all dependencies and bootstraps the different services. |
| `npm run seed` | Parses all the challenge markdown files and inserts them into MongoDB. | -->
## Troubleshooting
### Issues with installing the recommended prerequisites
We regularly develop on the latest or most popular operating systems like macOS 10.15 or later, Ubuntu 18.04 or later, and Windows 10 (with WSL2).
It is recommended to research your specific issue on resources such as Google, Stack Overflow, and Stack Exchange. There is a good chance that someone has faced the same issue and there is already an answer to your specific query.
If you are on a different OS and/or are still running into issues, see [getting help](#getting-help).
### Issues with the UI, build errors, etc.
If you face issues with the UI, or build errors a cleanup can be useful:
```bash
flutter clean
```
### Issues Installing Dependencies
If you get errors while installing the dependencies, please make sure that you are not in a restricted network or that your firewall settings do not prevent you from accessing resources.
Be patient as the first-time setup can take a while depending on your network bandwidth.
## Getting Help
If you are stuck and need help, feel free to ask questions on the ['Contributors' category on our forum](https://forum.freecodecamp.org/c/contributors) or [the contributors chat room](https://discord.gg/PRyKn3Vbay).
There might be an error in the console of your browser or in Bash / Terminal / Command Line that will help identify the problem. Provide this error message in your problem description so others can more easily identify the issue and help you find a resolution.
-220
View File
@@ -1,220 +0,0 @@
# Set up freeCodeCamp on Windows Subsystem for Linux (WSL)
> [!NOTE]
> Before you follow these instructions make sure your system meets the requirements.
>
> **WSL 2**: Windows 10 64-bit (Version 2004, Build 19041 or higher) - available for all distributions including Windows 10 Home.
>
> **Docker Desktop for Windows**: See respective requirements for [Windows 10 Pro](https://docs.docker.com/docker-for-windows/install/#system-requirements) and [Windows 10 Home](https://docs.docker.com/docker-for-windows/install-windows-home/#system-requirements)
This guide covers some common steps with the setup of WSL2. Once some of the common issues with WSL2 are addressed, you should be able to follow [this local setup guide](how-to-setup-freecodecamp-locally.md) to work with freeCodeCamp on Windows running a WSL distro like Ubuntu.
## Enable WSL
Follow the instructions on the [official documentation](https://docs.microsoft.com/en-us/windows/wsl/install-win10) to install WSL2.
## Install Ubuntu
1. We recommended using Ubuntu-18.04 or above with WSL2.
> [!NOTE]
>
> While you may use other non-Debian-based distributions, they all come with their own 'gotchas' that are beyond the scope of this guide.
As of November 2023, Ubuntu and Debian are the only Linux distributions [officially supported by Playwright](https://playwright.dev/docs/intro#system-requirements), the end-to-end testing library used by freeCodeCamp.
2. Update the dependencies for the OS
```bash
sudo apt update
sudo apt upgrade -y
# cleanup
sudo apt autoremove -y
```
## Set up Git
Git comes pre-installed with Ubuntu 18.04, verify your Git version with `git --version`.
```output
~
❯ git --version
git version 2.25.1
```
(Optional but recommended) You can now proceed to [setting up your ssh keys](https://help.github.com/articles/generating-an-ssh-key) with GitHub.
## Installing a Code Editor
We highly recommend installing [Visual Studio Code](https://code.visualstudio.com) on Windows 10. It has great support for WSL and automatically installs all the necessary extensions on your WSL distribution.
Essentially, you will edit and store your code on Ubuntu-18.04 with VS Code installed on Windows.
If you use [IntelliJ Idea](https://www.jetbrains.com/idea/), you may need to update your Node interpreter and npm package manager to what is installed on your WSL distro.
You can check these settings by going to Settings > Languages & Frameworks > Node.js and npm.
## Installing Docker Desktop
**Docker Desktop for Windows** allows you to install and run databases like MongoDB and other services like NGINX and more. This is useful to avoid common pitfalls with installing MongoDB or other services directly on Windows or WSL2.
Follow the instructions on the [official documentation](https://docs.docker.com/docker-for-windows/install) and install Docker Desktop for your Windows distribution.
There are some minimum hardware requirements for the best experience.
## Configure Docker Desktop for WSL
Once Docker Desktop is installed, [follow these instructions](https://docs.docker.com/docker-for-windows/wsl) and configure it to use the Ubuntu-18.04 installation as a backend.
This makes it so that the containers run on the WSL side instead of running on Windows. You will be able to access the services over `http://localhost` on both Windows and Ubuntu.
## Install MongoDB from Docker Hub
Once you have configured Docker Desktop to work with WSL2, follow these steps to start a MongoDB service:
1. Launch a new Ubuntu terminal
2. Pull MongoDB from Docker Hub. Please refer to the [Prerequisites](how-to-setup-freecodecamp-locally.md#Prerequisites) table for the current version of MongoDB used by freeCodeCamp. For example, if the version number is `5.0.x`, replace `<x.y>` with `5.0` in the following two code snippets.
```bash
docker pull mongo:<x.y>
```
3. Start the MongoDB service at port `27017`, and configure it to run automatically on system restarts
```bash
docker run -it \
-v mongodata:/data/db \
-p 27017:27017 \
--name mongodb \
--restart unless-stopped \
-d mongo:<x.y>
```
4. You can now access the service from both Windows or Ubuntu at `mongodb://localhost:27017`.
## Installing Node.js and pnpm
We recommend you install the LTS release for Node.js with a node version manager - [nvm](https://github.com/nvm-sh/nvm#installing-and-updating).
Once installed use this command to install and use the latest Node.js LTS version:
```bash
nvm install --lts
```
For instructions on installing and using a different version of Node.js, please refer to the [nvm docs](https://github.com/nvm-sh/nvm#usage).
Node.js comes bundled with `npm`, which you can use to install `pnpm`:
```bash
npm install -g pnpm
```
## Set up freeCodeCamp Locally
Now that you have installed the pre-requisites, follow [our local setup guide](how-to-setup-freecodecamp-locally.md) to clone, install and set up freeCodeCamp locally on your machine.
> [!WARNING]
>
> Please note, at this time the setup for Cypress tests (and related GUI needs) is a work in progress. You should still be able to work on most of the codebase.
## Optimize Windows and WSL
> [!NOTE]
>
> The following tips were collected from across the web and have not gone through vigorous testing. Your mileage may vary.
### Adjust processor scheduling for background services
This may reduce incidents of Docker containers crashing due to lack of resources.
Open the System Properties control panel by pressing <kbd>Win + R</kbd> and entering `sysdm.cpl`
<details>
<summary>
Enter <code>sysdm.cpl</code> in the Run dialog (screenshot)
</summary>
<br>
<img src="https://raw.githubusercontent.com/freeCodeCamp/freeCodeCamp/main/docs/images/wsl/run-sysdm.png" alt="Enter `sysdm.cpl` in the Run dialog">
</details>
<br>
Go to Advanced -> Performance -> Settings…
<details>
<summary>
Performance Settings button under Advanced tab in System Properties (screenshot)
</summary>
<br>
<img src="https://raw.githubusercontent.com/freeCodeCamp/freeCodeCamp/main/docs/images/wsl/advanced-performance-settings.png" alt="Performance Settings button under Advanced tab in System Properties">
</details>
<br>
Under Advanced -> Processor scheduling, choose "Background services". Do not close the window. Continue to the next tip.
<details>
<summary>
Background services radio button under Advanced tab in Performance Options (screenshot)
</summary>
<br>
<img src="https://raw.githubusercontent.com/freeCodeCamp/freeCodeCamp/main/docs/images/wsl/background-services.png" alt="Background services radio button under Advanced tab in Performance Options">
</details>
### Increase the size of Windows paging file for the system drive
Under Advanced -> Virtual memory, click "Change…"
<details>
<summary>
Change virtual memory button under Advanced tab in Performance Options (screenshot)
</summary>
<br>
<img src="https://raw.githubusercontent.com/freeCodeCamp/freeCodeCamp/main/docs/images/wsl/advanced-virtual-memory.png" alt="Change virtual memory button under Advanced tab in Performance Options">
</details>
<br>
Choose "Custom size". Set the initial size to 1.5x and the maximum size to 3x of your physical memory. Then click "Set".
<details>
<summary>
Set custom size button in Virtual Memory window (screenshot)
</summary>
<br>
<img src="https://raw.githubusercontent.com/freeCodeCamp/freeCodeCamp/main/docs/images/wsl/set-custom-size.png" alt="Set custom size button in Virtual Memory window">
</details>
### Increase the size of memory allocated to WSL
Create a [`.wslconfig` file](https://learn.microsoft.com/en-us/windows/wsl/wsl-config#configuration-setting-for-wslconfig) in your [`%UserProfile%` directory](https://learn.microsoft.com/en-us/windows/wsl/wsl-config#wslconfig) (typically `C:\Users\<UserName>\.wslconfig`). Please read the [WSL documentation](https://learn.microsoft.com/en-us/windows/wsl/wsl-config#configuration-setting-for-wslconfig) carefully and replace `x` with values that suit your own needs:
```ini
# Settings apply across all Linux distros running on WSL 2
[wsl2]
# How much memory to assign to the WSL 2 VM. The default value might not be enough
memory=xGB
# How much swap space to add to the WSL 2 VM, default is 25% of available RAM
swap=xGB
```
### Increase Node.js max old space size
This fixes the ["JavaScript heap out of memory" error](https://stackoverflow.com/a/54456814) with ESLint. Add the following to your `~/.bashrc` or `~/.zshrc`:
```sh
export NODE_OPTIONS="--max-old-space-size=4096"
```
### Avoid `pnpm run test`
Instead, use the script [appropriate to your PR](https://forum.freecodecamp.org/t/wsl-performance-issues-while-working-on-the-codebase/644215/2#:~:text=usually%2C%20you%20just%20want%20to%20test%20something%20specific%20to%20either%20the%20curriculum%20or%20the%20client%20or%20the%20api%20-%20almost%20never%20all%203.); either `pnpm run test:api`, `pnpm run test:curriculum`, or `pnpm run test-client`.
## Useful Links
- [A WSL2 Dev Setup with Ubuntu 20.04, Node.js, MongoDB, VS Code, and Docker](https://hn.mrugesh.dev/wsl2-dev-setup-with-ubuntu-nodejs-mongodb-and-docker) - an article by Mrugesh Mohapatra (Staff Developer at freeCodeCamp.org)
- Frequently asked questions on:
- [Windows Subsystem for Linux](https://docs.microsoft.com/en-us/windows/wsl/faq)
- [Docker Desktop for Windows](https://docs.docker.com/docker-for-windows/faqs)
-346
View File
@@ -1,346 +0,0 @@
# How to Translate freeCodeCamp's resources
## Prepare yourself for Contributions
> The freeCodeCamp Localization Roadmap – There Are No Speed Limits
> [!TIP]
> You can start by reading [this announcement](https://www.freecodecamp.org/news/help-translate-freecodecamp-language/). We recommend joining [our community forum](https://forum.freecodecamp.org/c/contributors/3) and [Discord chat server](https://discord.gg/PRyKn3Vbay).
You can translate as much as you want, when you want. It's only a matter of how much time and energy you are willing to invest as a volunteer translator.
We just ask that you understand the following:
1. **Translations are a team effort.**
Translating freeCodeCamp's resources is one of the most fun and rewarding experiences as a contributor, and it works best if you involve your friends and colleagues who speak the same world language as you.
You can start by reading [this announcement](https://www.freecodecamp.org/news/help-translate-freecodecamp-language/). We recommend joining [our community forum](https://forum.freecodecamp.org/c/contributors/3) and [Discord chat server](https://discord.gg/PRyKn3Vbay) with your friends and showing your interest before starting off with translations. Crowdin and other tools make it easy to contribute translations, but it's still a lot of work.
We want you to enjoy contributing and not burn out or lose interest.
A small group of 4-5 individuals is a good size to start your niche for your world language. You can then recruit even more friends to join the team.
2. **It costs quite a lot to spin servers for each language.**
On the surface it might not seem how complicated the technical stack is, but it costs quite a lot to keep the engines running. This includes provisioning additional servers and dedicating staff to look after them.
freeCodeCamp.org is committed to providing these for free as always, however we need to prioritize resources for those who need them the most. The last thing we want is to shutdown servers for a language if the translation activity dies off & things become outdated.
For translating the curriculum, once a language reaches at least a few certifications we can begin deploying the language live on [`/learn`](https://www.freecodecamp.org/learn), while you continue to translate the remaining certifications.
For example, we would want to deploy at least the entire front-end certifications suite when we ship a new world language for the first time.
3. **But what about the languages not listed on the translation platform?**
We have looked at our user base and added 30+ most widely spoken languages to the list of enabled languages on the translations platform. Some languages like Chinese and Spanish are already deployed live on **"/learn"** at this moment.
Unfortunately, the list does not include hundreds of languages out there. We get dozens of requests from contributors like you every day who want to help translate the site into a language they speak.
We are definitely looking forward to adding more languages to the list, but as you may already guess, it would only be feasible if we get enough momentum around a world language.
If you would like us to include a new world language, we recommend getting your friends excited about this.
Once you have a small group of people (at least 4-5) interested and committed, we can hop on a call. We will explain all the details and walk you through some of the tools and processes.
## Overview of Crowdin
It's our dream to provide you with the resources to learn, no matter the world language you speak. To help us with this massive effort, we have integrated our open-source codebase & curriculum with [Crowdin](https://crowdin.com/) - A tool to help us localize our code-base.
> [!NOTE]
> We use a different tool and workflow for translating [news articles](https://www.freecodecamp.org/news). If you are interested in translating articles, read [this announcement](https://www.freecodecamp.org/news/help-translate-freecodecamp-language/) and reach out to your Language Lead.
The translation workflow is split into two main activities:
- **Translating** curriculum files, documentation and UI elements like buttons, labels, etc.:
As a translator you can sign up on [our translation platform](https://translate.freecodecamp.org) and contribute translations in any of the 30+ languages enabled in there.
- **Proofreading** the translations for all of the above.
Proofreaders verify that the community contributed translations are uniform in tone and free of common issues like typos, etc. In short, they ensure that the quality of translations is high. Note that we do not use machine translations for a reason.
> [!WARNING]
> We are no longer using GitHub to translate files directly, if you are a returning contributor head to our [translation platform](https://translate.freecodecamp.org/) instead.
## Getting Started
First, make sure you come say "Hi" in our [Discord](https://discord.gg/PRyKn3Vbay). We post regular updates about translating resources and answer a lot of your queries in there.
Next, head to our [translation platform](https://translate.freecodecamp.org/) and login (if you have not contributed to translations before, you will need to create an account).
Finally, go through the detailed walk-thru below to understand the translation tools and workflows at your disposal.
Happy translating.
## Select a Project and File
Once you visit the translation platform, you should see multiple "projects" available for translation:
1. [Contributing documentation](https://translate.freecodecamp.org/contributing-docs) project, which contains the files for this documentation site.
2. [Coding Curriculum](https://translate.freecodecamp.org/curriculum) project, which contains our challenge files for our curriculum.
3. [Learn User Interface](https://translate.freecodecamp.org/learn-ui) project which contains strings for UI elements like buttons, labels, etc. for our learning platform.
Select any project you want to contribute to, and you will see a list of available languages for translation.
![Image - List of available languages](https://contribute.freecodecamp.org/images/crowdin/languages.png)
Select the language you want to work on, and you will see the complete file tree.
![Image - List of available files](https://contribute.freecodecamp.org/images/crowdin/file-tree.png)
Each file and folder will show a progress bar. The **blue** portion of the progress bar indicates what percentage of the file has been translated, while the **green** portion of the progress bar indicates what percentage of the file has been approved by the proofreading team.
Select a file to work on and Crowdin will open the editor view.
> [!NOTE]
> When the editor view opens, you will need to click the settings icon (shown as a gear) and switch the 'HTML tags displaying' setting to 'SHOW'. This will ensure you can see tags such as `<code></code>` instead of `<0></0>`.
## Translate Curriculum
![Image - Editor View](https://contribute.freecodecamp.org/images/crowdin/editor.png)
Crowdin separates a document into translatable "strings", usually sentences. Each string is translated individually. Referring to the image above:
1. A string highlighted in green already has a proposed translation.
2. A string highlighted in red does _not_ have a proposed translation.
3. A string with greyed out text is not translatable. This is the case for code blocks and other content that must not be translated. You will be unable to select these strings in the editor.
4. If a contributor has proposed a translation to a string, Crowdin will display those proposals here. You will not be able to save an identical translation - instead, if a translation is accurate, you should click the `+` icon to "upvote" it. An inaccurate translation can be "downvoted" with the `-` icon.
5. Crowdin will recommend translations based on Translation Memory (TM) or Machine Translation (MT). Translation Memory refers to similar or identical strings that we have translated/approved in other files. Machine Translation refers to translations recommended by their integrated library.
6. This is the editor pane, where you may write your proposed translation for the selected string.
7. The currently selected string in the editor will be highlighted in yellow.
8. Here you will see tags indicating the state of the string. `Done` means the string has at least one proposed translation. `Todo` means the string does not have any proposed translations.
9. Here you can see the comments window. If you have questions or concerns about a particular string, you can leave a comment on the string here for other translators to see.
10. These two "pane" buttons will hide the left (document) and right (comments) views.
> [!NOTE]
> If you see a hidden string that includes translations, please notify us in the [Discord](https://discord.gg/PRyKn3Vbay) so we can remove the translation from memory.
When you have completed a translation for a string, select the `Save` button to store your translation on Crowdin. Other contributors will then be able to vote on your translation and proofreaders will be able to approve it.
You are welcome to translate as many strings as you like - there are no additional steps required when you complete a full file or propose a new translation. Clicking the `Save` button is all that is needed to store a translation.
> [!NOTE]
> If you see something in the English source file that is inaccurate or incorrect, please do not fix it through the translation flow. Instead, leave a comment on the string to notify us that there is a discrepancy, or create a GitHub issue.
## Translate the Learn Interface
Our `/learn` interface relies on JSON files loaded into an i18n plugin to generate translated text. This translation effort is split across both Crowdin and GitHub.
### On GitHub
The `links.json`, `meta-tags.json`, `motivation.json`, and `trending.json` files contain information that needs to be updated to reflect your language. However, we cannot load these into Crowdin, as the content isn't something that would be a one-to-one translation.
These files will most likely be maintained by your language lead but you are welcome to [read about how to translate them](language-lead-handbook.md).
### On Crowdin
> [!ATTENTION]
> Do not edit the following files through a GitHub PR.
The `intro.json` and `translations.json` files are both translated on Crowdin, in the Learn User Interface project. Translating these can be a bit tricky, as each individual JSON value appears as its own string and sometimes the context is missing.
However, the `Context` information provided in Crowdin can help understand where the string fits in to the larger structure.
![Image with an arrow pointing to Crowdin's context information](https://contribute.freecodecamp.org/images/crowdin/context.png)
If you have any questions about where a string fits in to the prose, reach out to us in our [contributor chat](https://discord.gg/PRyKn3Vbay).
## Translate Documentation
Translating our contributing documentation is a similar flow to translating our curriculum files.
> [!NOTE]
> Our contributing documentation is powered by `docsify`, and we have special parsing for message boxes like this one. If you see strings that start with `[!NOTE]`, `[!WARNING]`, or `[!TIP]`, these words should NOT be translated.
### How to Translate Documentation with Internal Links
When you work on translating contributing documentation, watch out for internal links targeting a different section of the documentation.
Make sure to replace the id of the target section (the part after `#`) with the id on the translated document. For example, it will look like this in Japanese:
Before translation
```
// in HTML
<a href="target-file-name.md#target-section-heading-id">Link text</a>
<a href="#target-section-heading-id">Link text</a>
// in Markdown
[Link text](target-file-name.md#target-section-heading-id)
[Link text](#target-section-heading-id)
```
After translation
```
// in HTML
<a href="target-file-name.md#翻訳後の-id">翻訳後のリンクテキスト</a>
<a href="#翻訳後の-id">翻訳後のリンクテキスト</a>
// in Markdown
[翻訳後のリンクテキスト](target-file-name.md#翻訳後の-id)
[翻訳後のリンクテキスト](#翻訳後の-id)
```
The actual files in docs are written in Markdown, but they will appear as HTML tags on Crowdin.
You can find out how `docsify` converts a string in your language into an id by looking into the translated pages. If the translation is not deployed yet, you can preview it by [running the docs site locally](how-to-work-on-the-docs-theme.md#serving-the-documentation-site-locally).
You can learn more about [internal links in our docs here](how-to-work-on-the-docs-theme.md#how-to-create-an-internal-link).
## Translate the LearnToCode RPG
The LearnToCode RPG runs on Ren'Py, which uses special syntax for translated strings: (See [Ren'Py Text documentation](https://www.renpy.org/doc/html/text.html))
- The sentences to be translated are always between `""`. These are dialogues or UI strings. The keywords that come before or after the dialogue are game engine control keywords and will be explained in details in subsequent rules. Please note that this first rule governs all subsequent rules listed.
- In case of `new "..."` Do not translate the `new` keyword.
- Prefixes like `player`, `annika`, `layla`, `marco` (or variants like `player happy`, `player @ happy`) should not be translated. These are control keywords to correctly display the character sprite in the game.
- Postfixes like `nointeract` should not be translated.
- Do not translate things between `[]` and `{}`. These are variable interpolations and text tags. These must remain halfwidth parentheses `[]` and `{}` instead of their fullwidth counterparts `【】` and `「」`
- Do not translate the `nointeract` keyword at the end of the sentence.
- If we try to use fullwidth parentheses `()`, a QA warning will show. To avoid the QA warning, use halfwidth parentheses `()`
### Examples
---
#### Before translation
```renpy
# "[player_name]? What a coincidence! Our VIP team member {a=[vip_profile_url]}[player_name]{/a} will be honored to hear that."
"[player_name]? What a coincidence! Our VIP team member {a=[vip_profile_url]}[player_name]{/a} will be honored to hear that." <--- this is the line that needs to be translated. see translation below
```
#### After translation
```renpy
# "[player_name]? What a coincidence! Our VIP team member {a=[vip_profile_url]}[player_name]{/a} will be honored to hear that."
"[player_name]?好巧,我们的VIP队友{a=[vip_profile_url]}[player_name]{/a}会很高兴的。"
```
Note: The `[]` and `{}` tags should be left intact.
---
#### Before translation
```renpy
old "{icon=icon-fast-forward} Skip"
new "{icon=icon-fast-forward} Skip" <-- translate this line, see below
```
#### After translation
```renpy
old "{icon=icon-fast-forward} Skip"
new "{icon=icon-fast-forward} 跳过"
```
Note: Again, the `new` prefix and the `{icon=icon-fast-forward}` tag should be left intact.
---
#### Before translation
```renpy
# layla @ neutral "Hehe, [player_name], you are a fun one. I'm sure you will enjoy your work as a developer."
layla @ neutral "Hehe, [player_name], you are a fun one. I'm sure you will enjoy your work as a developer."
```
#### After translation
```renpy
# layla @ neutral "Hehe, [player_name], you are a fun one. I'm sure you will enjoy your work as a developer."
layla @ neutral "哈哈,[player_name],你真有趣。我相信你一定会喜欢你的开发者工作的。"
```
Note: `layla @ neutral` and `[player_name]` are left unchanged.
---
#### Before translation
```renpy
# player "Maybe this is all a dream?" nointeract
player "Maybe this is all a dream?" nointeract
```
#### After translation
```renpy
# player "Maybe this is all a dream?" nointeract
player "也许这都是一场梦?" nointeract
```
---
### A Note on How Crowdin Segments a Sentence
Pay attention to how Crowdin segments a line of dialogue wrapped between opening and closing quotes `""`. When we are translating the dialogue, we need to make sure to retain the opening and closing quotes, even if the quotes appear in different segments.
This is the line to be translated:
```renpy
player @ surprised "{b}Full-stack{/b}... What is that? I better take notes so I can learn more about it."
```
Crowdin segments it into three parts like below:
<img width="836" alt="Screen Shot 2022-01-23 at 10 36 43" src="https://user-images.githubusercontent.com/35674052/150693962-d3b091e5-2432-44d0-9d24-195ea7d7aeda.png">
```renpy
# original
player @ surprised "{b}Full-stack{/b}
# translated, keeping the opening quotes `"`
player @ surprised "{b}全栈{/b}
```
<img width="750" alt="Screen Shot 2022-01-23 at 10 36 49" src="https://user-images.githubusercontent.com/35674052/150693965-15411504-791a-4db3-8b14-bc9177be6375.png">
```renpy
# original
What is that?
# translated, no quotes on either side
这是什么?
```
<img width="857" alt="Screen Shot 2022-01-23 at 10 36 54" src="https://user-images.githubusercontent.com/35674052/150693969-062e3268-580f-4ad2-97db-cab6240b6095.png">
```renpy
# original
I better take notes so I can learn more about it."
# translated, keeping the closing quotes `"`
我最好做笔记,这样我可以学习更多东西。"
```
## Rate Translations
Crowdin allows you to rate the existing proposed translations. If you attempt to save a translation, you may see a message indicating that you cannot save a duplicate translation - this means another contributor has proposed that identical translation. If you agree with that translation, click the `+` button to "upvote" the translation.
If you see a translation that is inaccurate or does not provide the same clarity as the original string, click the `-` button to "downvote" the translation.
Crowdin uses these votes to give a score to each proposed translation for a string, which helps the proofreading team determine which translation is the best fit for each string.
## Quality Assurance Checks
We have enabled some quality assurance steps that will verify a translation is as accurate as possible - this helps our proofreaders review proposed translations.
When you attempt to save a translation, you may see a warning message appear with a notification regarding your proposed translation.
![Image - QA Warning Message](https://contribute.freecodecamp.org/images/crowdin/qa-message.png)
This message appears when Crowdin's QA system has identified a potential error in the proposed translation. In this example, we have modified the text of a `<code>` tag and Crowdin has caught that.
> [!WARNING]
> You have the option to save a translation in spite of errors. If you do, by clicking "Save Anyway", you should also tag a proofreader or project manager and explain why the QA message needs to be ignored in this case.
## Translation Best Practices
Follow these guidelines to ensure our translations are as accurate as possible:
- Do not translate the content within `<code>` tags. These tags indicate text that is found in code and should be left in English.
- Do not add additional content. If you feel a challenge requires changes in the text content or additional information, you should propose the changes through a GitHub issue or a pull request that modifies the English file.
- Do not change the order of content.
If you have any questions, feel free to reach out to us in our [Discord](https://discord.gg/PRyKn3Vbay) and we will be happy to assist you.
-15
View File
@@ -1,15 +0,0 @@
# How to use Docker on Windows Home
There are a few pitfalls to be avoided when setting up Docker on Windows Home. First of all, you have to use [Docker Toolbox](https://docs.docker.com/toolbox/toolbox_install_windows/) as Administrator. Unfortunately Windows Home does not support Docker for Windows Desktop, so Toolbox must be used instead. It has to be run as Administrator as the installation uses symlinks, which cannot be created otherwise.
Once you've installed the toolbox, run Docker Quickstart Terminal as Administrator. This will create a `default` virtual machine if it does not already exist. Once that has happened, close the terminal and open VirtualBox (again as Administrator). You should be able to see the `default` machine. The site is quite resource-intensive, so stop the virtual machine and raise the settings as much as you can - memory in particular. It has been confirmed to work with 4GB of RAM.
Once you're happy that Docker is working, clone the freeCodeCamp repository to a directory inside `C:\Users`. These directories are shared giving Docker access to the local directories, which it needs during installation.
If you see messages like
```shell
bash: change_volumes_owner.sh: No such file or directory
```
when you `pnpm run docker:init` this is likely the culprit.
-730
View File
@@ -1,730 +0,0 @@
# How to work on coding challenges
Our goal is to develop a fun and clear interactive learning experience.
Designing interactive coding challenges is difficult. It would be much easier to write a lengthy explanation or to create a video tutorial. But for our core curriculum, we're sticking with what works best for most people - a fully interactive, video game-like experience.
We want campers to achieve a flow state. We want them to build momentum and blast through our curriculum with as few snags as possible. We want them to go into the projects with confidence and gain wide exposure to programming concepts.
Note that for Version 7.0 of the freeCodeCamp curriculum, we are moving toward [an entirely project-focused model with a lot more repetition](https://www.freecodecamp.org/news/python-curriculum-is-live/).
Creating these challenges requires immense creativity and attention to detail. There's plenty of help available. You'll have support from a whole team of contributors to whom you can bounce ideas off and demo your challenges.
And as always, feel free to ask questions on the ['Contributors' category on our forum](https://forum.freecodecamp.org/c/contributors) or [the contributors chat room](https://discord.gg/PRyKn3Vbay).
With your help, we can design an interactive coding curriculum that will help millions of people learn to code for years to come.
The content for each challenge is stored in its markdown file. This markdown file is later converted to HTML using our tools to create interactive web pages.
You can find all of freeCodeCamp.org's curricular content in the [`/curriculum/challenges`](https://github.com/freeCodeCamp/freeCodeCamp/tree/main/curriculum/challenges) directory.
## Set up the tooling for the curriculum
Before you work on the curriculum, you would need to set up some tooling to help you test your changes. You can use any option from the below:
- You can [set up freeCodeCamp locally](how-to-setup-freecodecamp-locally.md). This is **highly recommended** for regular/repeat contributions. This setup allows you to work and test your changes.
- Use Gitpod, a free online dev environment. Clicking the button below will start a ready-to-code dev environment for freeCodeCamp in your browser. It only takes a few minutes.
[![Open in Gitpod](https://gitpod.io/button/open-in-gitpod.svg)](https://gitpod.io/#https://github.com/freeCodeCamp/freeCodeCamp)
### How to work on practice projects
The practice projects have some additional tooling to help create new projects and steps. To read more, see [these docs](how-to-work-on-practice-projects.md)
## Challenge Template
````md
---
id: Unique identifier (alphanumerical, MongoDB_id)
title: 'Challenge Title'
challengeType: Integer, defined in `client/utils/challenge-types.js`
videoUrl: 'url of video explanation'
forumTopicId: 12345
---
# --description--
Challenge description text, in markdown
```html
<div>example code</div>
```
# --instructions--
Challenge instruction text, in markdown
# --hints--
Tests to run against user code, in pairs of markdown text and code block test code.
```js
Code for test one
```
If you want dynamic output based on the user's code, --fcc-expected-- and --fcc-actual-- will be replaced with the expected and actual values of the test's assertion. Take care if you have multiple assertions since the first failing assertion will determine the values of --fcc-expected-- and --fcc-actual--.
```js
assert.equal(
'this will replace --fcc-actual--',
'this will replace --fcc-expected--'
);
```
# --notes--
Extra information for a challenge, in markdown
# --seed--
## --before-user-code--
```lang
Code evaluated before the user’s code.
```
## --after-user-code--
```lang
Code evaluated after the user’s code, and just before the tests
```
## --seed-contents--
Boilerplate code to render to the editor. This section should only contain code inside backticks, like the following:
```html
<body>
<p class="main-text">Hello world!</p>
</body>
```
```css
body {
margin: 0;
background-color: #3a3240;
}
.main-text {
color: #aea8d3;
}
```
```js
console.log('freeCodeCamp is awesome!');
```
# --solutions--
Solutions are used for the CI tests to ensure that changes to the hints will still pass as intended
```js
// first solution - the language(s) should match the seed.
```
---
```js
// second solution - so if the seed is written in HTML...
```
---
```js
// third solution etc. - Your solutions should be in HTML.
```
# --assignments--
This will show a checkbox that campers have to check before completing a challenge
---
This will show another checkbox that campers have to check before completing a challenge
# --question--
These fields are currently used for the multiple-choice Python challenges.
## --text--
The question text goes here.
## --answers--
Answer 1
### --feedback--
This will be shown as feedback when campers guess this answer
---
Answer 2
---
More answers
## --video-solution--
The number for the correct answer goes here.
# --fillInTheBlank--
These are for the English curriculum challenges.
## --sentence--
Sentence to be shown with with blanks that campers have to fill in. Example:
`Hello, You _ the new graphic designer, _?`
The two underscores will show up as blanks. The sentence must be surrounded in backticks.
## --blanks--
The solution for the first blank in the sentence above. Example:
`are`
### --feedback--
Feedback shown when campers input the wrong solution for this blank.
---
Solution for the second blank. Example:
`right`
If no feedback is here, a generic "wrong answer" message will be shown.
# --scene--
```json
// # --scene-- can only consist of a single json object
{
// Setup the scene. Properties not marked optional are required.
"setup": {
// Background file to start the scene. A list of scene asset filenames can be found here: https://github.com/freeCodeCamp/cdn/pull/233/files
"background": "company2-center.png",
// Array of all characters that will appear in the scene
"characters": [
{
// Name of character. See list of available characters in scene-assets.tsx
"character": "Maria",
// Where to start the character. Maria will start off screen to the left
"position": { "x": -25, "y": 0, "z": 1 }
},
{
"character": "Tom",
// Tom will start 70% from the left of the screen and 1.5 times regular size
"position": { "x": 70, "y": 0, "z": 1.5 },
// Optional, defaults to 1. Tom will start invisible
"opacity": 0
}
],
"audio": {
// Audio filename
"filename": "1.1-1.mp3",
// Seconds after the scene starts before the audio starts playing
"startTime": 1.3,
// Optional. Timestamp of the audio file where it starts playing from.
"startTimestamp": 0,
// Optional. Timestamp of the audio file where is stops playing. If these two aren't used, the whole audio file will play.
"finishTimestamp": 8.4
},
// Optional, defaults to false. Use this for the long dialogues. It stops the accessibility icon from showing which gives campers the option to show or hide the dialogue text
"alwaysShowDialogue": true
},
// Array of commands that make up the scene
"commands": [
{
// Character that will have an action for this command
"character": "Maria",
// Optional, defaults to previous value. Maria will move to 25% from the left of the screen. The movement takes 0.5 seconds
"position": { "x": 25, "y": 0, "z": 1 },
// When the command will start. Zero seconds after the camper presses play
"startTime": 0
},
{
"character": "Tom",
// Optional, defaults to previous value. Tom will fade into view. The transition take 0.5 seconds. Movement and Opacity transitions take 0.5 seconds
"opacity": 1,
// Tom will fade into view 0.5 seconds into the scene (immediately after Maria finishes moving on screen)
"startTime": 0.5
},
{
"character": "Maria",
// When the command starts: Maria will start saying this line 1.3 seconds into the scene. Note that this is the same time as the audio.startTime above. It doesn't have to match that (maybe there's a pause at the beginning of the audio or something)
"startTime": 1.3,
// The character will stop moving their mouth at the finishTime
"finishTime": 4.95,
"dialogue": {
// Text that will appear if the dialogue is visible
"text": "Hello! You're the new graphic designer, right? I'm Maria, the team lead.",
// Where the dialogue text will be aligned. Can be 'left', 'center', or 'right'
"align": "left"
}
},
{
// background will change to this at 5.4 seconds into the scene
"background": "company2-breakroom.png",
"character": "Tom",
"startTime": 5.4,
"finishTime": 9.4,
"dialogue": {
"text": "Hi, that's right! I'm Tom McKenzie. It's a pleasure to meet you.",
// Tom's text will be aligned to the right since he is on the right side of the screen
"align": "right"
}
},
{
"character": "Tom",
// Tom will fade to 0 opacity
"opacity": 0,
// I like to move characters off screen or fade them 0.5 second after the last talking command
"startTime": 9.9
},
{
"character": "Maria",
// Maria will slide back off the screen to the left
"position": { "x": -25, "y": 0, "z": 1 },
// The animation will stop playing 0.5 seconds after the 'finishTime' of the last command - or 0.5 seconds after 'startTime' if 'finishTime' isn't there.
"startTime": 10.4
}
]
}
```
````
> [!NOTE]
>
> 1. In the above sections, examples of `lang` are:
>
> - `html` - HTML/CSS
> - `js` - JavaScript
> - `jsx` - JSX
## Numbering Challenges
Every challenge needs an `id`. If you don't specify one, then MongoDB will create a new random one when it saves the data; however, we don't want it to do that, since we want the challenge ids to be consistent across different environments (staging, production, lots of different developers, etc.).
To generate a new one in a shell (assuming MongoDB is running separately):
1. Run `mongo` command.
2. Run `ObjectId()` command.
For example:
```bash
$ mongo
MongoDB shell version v3.6.1
connecting to: mongodb://127.0.0.1:27017
MongoDB server version: 3.4.10
...
$ ObjectId()
ObjectId("5a474d78df58bafeb3535d34")
```
The result is a new id, for example, `5a474d78df58bafeb3535d34` above.
Once you have your id, put it into the markdown file as the `id` field at the top, e.g.
```yml
---
id: 5a474d78df58bafeb3535d34
title: Challenge Title
```
## Naming challenges
Naming things is hard. We've made it easier by imposing some constraints.
All challenge titles should be explicit and should follow this pattern:
[verb][object clause]
Here are some example challenge names:
- Use Clockwise Notation to Specify the Padding of an Element
- Condense arrays with .reduce
- Use Bracket Notation to Find the First Character in a String
## Challenge descriptions/instructions
Sentences should be clear and concise with minimal jargon. If used, jargon should be immediately defined in plain English.
Keep paragraphs short (around 1-4 sentences). People are more likely to read several short paragraphs than a wall of text.
Use american english, e.g., use `labeled` instead of `labelled`.
Challenge text should use the second person ("you") to help to give it a conversational tone. This way the text and instructions seem to speak directly to the camper working through the challenge. Try to avoid using the first person ("I", "we", "let's", and "us").
Don't use outbound links. These interrupt the flow. Campers should never have to google anything during these challenges. If there are resources you think campers would benefit from, add them to the challenge's Guide-related article.
You can add diagrams if necessary.
Don't use emojis or emoticons in challenges. freeCodeCamp has a global community, and the cultural meaning of an emoji or emoticon may be different around the world. Also, emojis can render differently on different systems.
Proper nouns should use correct capitalization when possible. Below is a list of words as they should appear in the challenges.
- JavaScript (capital letters in "J" and "S" and no abbreviations)
- Node.js
- Although sometimes inaccurate, non-hyphenated forms of 'back end' and 'front end' should be used, as they are more widely used.
### The 2-minute rule
Each challenge should be solvable within 120 seconds by a native English speaker who has completed the challenges leading up to it. This includes the amount of time it takes to read the directions/instructions understand the seeded code, write their code and get all the tests to pass.
If it takes longer than two minutes to complete the challenge, you have two options:
- Simplify the challenge, or
- Split the challenge into two challenges.
The 2-minute rule forces you, the challenge designer, to make your directions concise, your seed code clear, and your tests straightforward.
We track how long it takes for campers to solve challenges and use this information to identify challenges that need to be simplified or split.
### Modularity
Each challenge should teach exactly one concept, and that concept should be apparent from the challenge's name.
We can reinforce previously covered concepts through repetition and variations - for example, introducing h1 elements in one challenge, then h3 elements a few challenges later.
Our goal is to have thousands of 2-minute challenges. These can flow together and reiterate previously-covered concepts.
### Formatting challenge text
Here are specific formatting guidelines for challenge text and examples:
- Language keywords go in `\`` backticks. For example, HTML tag names or CSS property names.
- References to code parts (i.e. function, method, or variable names) should be wrapped in `\`` backticks. See example below:
```md
Use `parseInt` to convert the variable `realNumber` into an integer.
```
- References to file names and path directories (e.g. `package.json`, `src/components`) should be wrapped in `\`` backticks.
- Multi-line code blocks **must be preceded by an empty line**. The next line must start with three backticks followed immediately by one of the [supported languages](https://prismjs.com/#supported-languages). To complete the code block, you must start a new line that only has three backticks and **another empty line**. See example below:
- Whitespace matters in Markdown, so we recommend that you make it visible in your editor.
**Note:** If you are going to use an example code in YAML, use `yaml` instead of `yml` for the language to the right of the backticks.
The following is an example of code:
````md
```{language}
[YOUR CODE HERE]
```
````
- Additional information in the form of a note should be surrounded by blank lines, and formatted: `**Note:** Rest of note text...`
- If multiple notes are needed, then list all of the notes in separate sentences using the format: `**Notes:** First note text. Second note text.`
- Use single quotes where applicable
**Note:** The equivalent _Markdown_ should be used in place of _HTML_ tags.
## Writing tests
Challenges should have the minimum number of tests necessary to verify that a camper understands a concept.
Our goal is to communicate the single point that the challenge is trying to teach, and test that they have understood that point.
Challenge tests can make use of the Node.js and Chai.js assertion libraries. Also, if needed, user-generated code can be accessed in the `code` variable. In addition, the `__helpers` object exposes several functions that simplify the process of writing tests. The available functions are defined in the [curriculum-helpers](https://github.com/freeCodeCamp/curriculum-helpers/blob/main/lib/index.ts) repo.
## Formatting Seed Code
Here are specific formatting guidelines for the challenge seed code:
- Use two spaces to indent
- JavaScript statements end with a semicolon
- Use double quotes where applicable
### Seed Code Comments
We have a [comment dictionary](https://github.com/freeCodeCamp/freeCodeCamp/blob/main/curriculum/dictionaries/english/comments.json) that contains the only comments that can be used within the seed code. The exact case and spacing of the dictionary comment must be used. The comment dictionary should not be expanded without prior discussion with the dev-team.
Comments used should have a space between the comment characters and the comment themselves. In general, comments should be used sparingly. Always consider rewriting a challenge's description or instructions if it could avoid using a seed code comment.
Example of a valid single-line JavaScript comment:
```js
// Only change code below this line
```
Example of a valid CSS comment:
```css
/* Only change code above this line */
```
If a challenge only has a single place where code changes are needed, please use the comments in the following example to instruct the user where changes should be made.
```js
var a = 3;
var b = 17;
var c = 12;
// Only change code below this line
a = a + 12;
b = 9 + b;
c = c + 7;
```
If a challenge has multiple places where the user is expected to change code (i.e. the React challenges)
```jsx
class MyComponent extends React.Component {
constructor(props) {
super(props);
this.state = {
text: 'Hello'
};
// Change code below this line
// Change code above this line
}
handleClick() {
this.setState({
text: 'You clicked!'
});
}
render() {
return (
<div>
{/* Change code below this line */}
<button>Click Me</button>
{/* Change code above this line */}
<h1>{this.state.text}</h1>
</div>
);
}
}
```
### Translation of Seed Code Comments
There are separate comment dictionaries for each language. The [English version of the comment dictionary](https://github.com/freeCodeCamp/freeCodeCamp/blob/main/curriculum/dictionaries/english/comments.json) is the basis for the translations found in the corresponding non-English versions of the files. The non-English version of the Chinese comment dictionary would be located at `/curriculum/dictionaries/chinese/comments.json`. Each dictionary consists of an array of objects with a unique `id` property and a `text` property. Only the `text` should be modified to encompass the translation of the corresponding English comment.
Some comments may contain a word/phrase that should not be translated. For example, variable names or proper library names like "React" should not be translated. See the comment below as an example. The word `myGlobal` should not be translated.
```text
Declare the myGlobal variable below this line
```
> [!NOTE]
>
> We are working on an integration to make it possible to work on i18n for the comment dictionary.
## Hints and Solutions
Each challenge has a `Get a Hint` button, so a user can access any hints/solutions which have been created for the challenge. Curriculum hints/solutions topics are located on [our forum](https://forum.freecodecamp.org/c/guide) under the `Guide` category.
If you find a problem with an existing challenge's hints/solutions topic, you can make suggestions in the [contributors category](https://forum.freecodecamp.org/c/contributors) on the forum. Moderators and users with trust level 3 will review the comments and decide whether or not to include the changes in the corresponding hint/solutions topic.
### Adding new Challenge hints/solutions Topics
Take the following steps when adding a new challenge hints/solutions-related topic.
1. Start by following the same steps for creating a new topic but review the next for creating the title.
2. The title of the topic should start with `freeCodeCamp Challenge Guide: ` concatenated with the actual title of the curriculum challenge. For example, if the challenge is named "`Chunky Monkey`", the topic title would be "`freeCodeCamp Challenge Guide: Chunky Monkey`".
3. `camperbot` should be the owner of these topics/posts, so you will need to request an admin to change the ownership of the main post to `camperbot`.
4. Once the new topic is created, a forum topic id is created. It is located at the end of the forum topic URL. This id must be added to the frontmatter of the curriculum challenge file via the normal pull request process for the `Get a Hint` button to link to the topic.
### Guidelines for Content of Hints and Solutions Topics
When proposing a solution for a curriculum challenge-related Guide topic, the full code must be added. This includes all the original seed code plus any changes needed to pass all the challenge tests. The following template should be used when creating new hints/solutions topics:
````md
# Challenge Name Goes Here
---
## Problem Explanation
This summarizes what needs to be done without just restating the challenge description and/or instructions. This is an optional section
#### Relevant Links
- [Link Text](link_url_goes_here)
- [Link Text](link_url_goes_here)
---
## Hints
### Hint 1
Hint goes here
### Hint 2
Hint goes here
---
## Solutions
<details><summary>Solution 1 (Click to Show/Hide)</summary>
```js
function myFunc() {
console.log('Hello World!');
}
```
#### Code Explanation
- Code explanation goes here
- Code explanation goes here
#### Relevant Links
- [Link Text](link_url_goes_here)
- [Link Text](link_url_goes_here)
</details>
````
## Testing Challenges
Before you [create a pull request](how-to-open-a-pull-request.md) for your changes, you need to validate that the changes you have made do not inadvertently cause problems with the challenge.
1. To test all challenges run the below command from the root directory
```
pnpm run test:curriculum
```
2. To test single challenge, you can use it challenge id with following command
```
FCC_CHALLENGE_ID=646cf6cbca98e258da65c979 pnpm run test:curriculum
```
3. You can also test a block or a superblock of challenges with these commands
```
FCC_BLOCK='Basic HTML and HTML5' pnpm run test:curriculum
```
```
FCC_SUPERBLOCK='responsive-web-design' pnpm run test:curriculum
```
You are also able to test challenges by title by performing the following steps:
1. Switch to the `curriculum` directory:
```
cd curriculum
```
2. Run the following for each challenge file for which you have changed (replacing `challenge-title-goes-here` with the full title of the challenge):
```
pnpm run test -- -g challenge-title-goes-here
```
> [!TIP]
> You can set the environment variable `LOCALE` in the `.env` to the language of the challenge(s) you need to test.
>
> The currently accepted values are `english` and `chinese`, with `english` being set by default.
## Proposing a Pull Request (PR)
After you've committed your changes, check here for [how to open a Pull Request](how-to-open-a-pull-request.md).
## Useful Links
Creating and Editing Challenges:
1. [Challenge types](https://github.com/freeCodeCamp/freeCodeCamp/blob/main/client/utils/challenge-types.js#L1-L13) - what the numeric challenge type values mean (enum).
2. [Contributing to FreeCodeCamp - Writing ES6 Challenge Tests](https://www.youtube.com/watch?v=iOdD84OSfAE#t=2h49m55s) - a video following [Ethan Arrowood](https://twitter.com/ArrowoodTech) as he contributes to the old version of the curriculum.
## Helper Scripts
> [!NOTE]
> If you are working with the step-based challenges, refer to the [Work on Practice Projects](how-to-work-on-practice-projects.md) section.
There are a few helper scripts that can be used to manage the challenges in a block. Note that these commands should all be run in the block directory. For example:
```bash
cd curriculum/challenges/english/02-javascript-algorithms-and-data-structures/basic-algorithm-scripting
```
### Add New Challenge
To add a new challenge at the end of a block, call the script:
```bash
pnpm run create-next-challenge
```
This will prompt you for the challenge information and create the challenge file, updating the `meta.json` file with the new challenge information.
### Delete a Challenge
To delete a challenge, call the script:
```bash
pnpm run delete-challenge
```
This will prompt you to select which challenge should be deleted, then delete the file and update the `meta.json` file to remove the challenge from the order.
### Insert a Challenge
To insert a challenge before an existing challenge, call the script:
```bash
pnpm run insert-challenge
```
This will prompt you for the challenge information, then for the challenge to insert before. For example, if your choices are:
```bash
a
b
c
```
If you choose `b`, your new order will be:
```bash
a
new challenge
b
c
```
### Update Challenge Order
If you need to manually re-order the challenges, call the script:
```bash
pnpm run update-challenge-order
```
This will take you through an interactive process to select the order of the challenges.
## Troubleshooting
### Infinite Loop Detected
If you see the following error in the console while previewing a challenge:
```text
Potential infinite loop detected on line <number>...
```
This means that the loop-protect plugin has found a long-running loop or recursive function. If your challenge needs to do that (e.g. it contains an event loop that is supposed to run indefinitely), then you can prevent the plugin from being used in the preview. To do so, add `disableLoopProtectPreview: true` to the block's `meta.json` file.
If your tests are computationally intensive, then you may see this error when they run. If this happens then you can add `disableLoopProtectTests: true` to the block's `meta.json` file.
It's not typically necessary to have both set to true, so only set them as needed.
@@ -1,283 +0,0 @@
# How to Work on Localized Client Webapp
The React-based client web app that powers our learning platform is built using Gatsby. It is translated into various world languages using [react-i18next](https://react.i18next.com/) and [i18next](https://www.i18next.com/).
You can learn more about setting up the client application locally for development by following [our local setup guide here](how-to-setup-freecodecamp-locally.md). By default, the application is available only in English.
Once you have set up the project locally you should be able to follow this documentation to run the client in the language of your choice from the list of available languages.
This could be helpful when you are working on a feature that specifically targets something that involves localization, and requires you to validate for instance a button's label in a different language.
> [!TIP]
> You do not need to follow this document to translate freeCodeCamp's curriculum or contributing documentation. Read [this guide here](how-to-translate-files.md) instead.
Let's understand how the i18n frameworks and tooling work.
## File Structure
Most of the files for translating the platform are located in the [`client/i18n`](https://github.com/freeCodeCamp/freeCodeCamp/tree/main/client/i18n) folder. Each language has a directory that contains JSON files with the translations.
```bash
config
└── i18n.ts
...
client/i18n
├── configForTests.js
├── config.js
├── locales
│   ├── chinese
│   │   ├── intro.json
│   │   ├── links.json
│   │   ├── meta-tags.json
│   │   ├── motivation.json
│   │   └── translations.json
... ...
│   ├── dothraki
│   │   ├── intro.json
│   │   ├── links.json
│   │   ├── meta-tags.json
│   │   ├── motivation.json
│   │   └── translations.json
... ...
│   ├── english
│   │   ├── intro.json
│   │   ├── links.json
│   │   ├── meta-tags.json
│   │   ├── motivation.json
│   │   └── translations.json
│   └── espanol
│   ├── intro.json
│   ├── links.json
│   ├── meta-tags.json
│   ├── motivation.json
│   └── translations.json
├── locales.test.js
├── schema-validation.js
└── validate-keys.ts
```
Some of these files are translated on our translation platform (Crowdin) and some are translated or created via PRs on GitHub.
**Files translated on our translation platform:**
- The `translations.json` file contains the majority of the text that appears on the user interface elements. The keys are used in the codebase to get the correct text for whatever language is set. This file needs to have the same keys in all languages.
- The `intro.json` file contains the key-value pairs for the introduction text on the certification pages.
If you want to add/update translations for the keys please [read this guide here](how-to-translate-files.md).
**Files NOT translated on our translations platform:**
- The `motivation.json` files are not required to have the same quotes, compliments, or array length. Just the same JSON structure.
- The `meta-tags.json` file contains the information for our website's meta tag information.
Changes to these files are typically done by the staff team. If you see something out of the ordinary we recommend you reach us in the [contributors chat room](https://discord.gg/PRyKn3Vbay).
## Testing the Client App in a World Language
You can test the client app in any language available in the [list of `availableLangs` here](https://github.com/freeCodeCamp/freeCodeCamp/blob/main/shared/config/i18n.ts).
```js
export const availableLangs = {
client: [
Languages.English,
Languages.Espanol,
Languages.Chinese,
Languages.ChineseTraditional,
Languages.Italian,
Languages.Portuguese,
Languages.Ukrainian,
Languages.Japanese,
Languages.German,
Languages.Arabic
],
...
};
```
If you are testing a new language, create a folder with the language name as the title next to the other languages and copy the JSON files from another language into your new folder.
Add the new language to the `Languages` enum and the `client` array at the top of the [`shared/config/i18n.ts`](https://github.com/freeCodeCamp/freeCodeCamp/blob/main/shared/config/i18n.ts) file.
Next, follow the instructions in the comments in the same file to add/update the rest of the variables as needed.
Finally, set the `CLIENT_LOCALE` variable in your `.env` file to the string of the locale you want to build from the `Languages` enum in the above file.
## How to Structure Components
If you are working on a feature or a bug for the client web app, say for example adding new UI items on the settings page, you should follow the guidelines below. They will help you prepare the components for localization into all the supported world languages.
### Functional Component
```js
import { useTranslation } from 'react-i18next';
// in the render method:
const { t } = useTranslation();
// call the "t" function with a key from the JSON file:
<p>{t('key')}</p>; // more details below
```
### Class Component
```js
import { withTranslation } from 'react-i18next';
// withTranslation adds the "t" function to props:
const { t } = this.props;
// call the "t" function with a key from the JSON file:
<h1>{t('key')}</h1> // more details below
// export without redux:
export default withTranslation()(Component);
// or with redux:
export default connect(...)(withTranslation()(Component));
```
## Translate Using the "t" Function
### Basic Translation
```js
// in the component:
<p>{t('p1')}</p>
// in the JSON file:
{
"p1": "My paragraph"
}
// output:
<p>My paragraph</p>
```
### With Dynamic Data
```js
// in the component:
const username = 'moT';
<p>{t('welcome', { username: username })}</p>
// in the JSON file:
{
"welcome": "Welcome {{username}}"
}
// output:
<p>Welcome moT</p>
```
The above example passes an object to the `t` function with a `username` variable. The variable will be used in the JSON value where `{{username}}` is.
## Translate with the `Trans` Component
The general rule is to use the "t" function when you can. But there's a `Trans` component for when that isn't enough, usually when you have elements embedded in the text. You can use the `Trans` component with any type of react component.
### Basic Elements Nested
```js
// in the component:
import { Trans } from 'react-i18next'
<p>
<Trans>fcc.greeting</Trans>
</p>
// in the JSON file:
{
"fcc": {
"greeting": "Welcome to <strong>freeCodeCamp</strong>"
}
}
// output:
<p>Welcome to <strong>freeCodeCamp</strong></p>
```
You can place the key inside the component tags like in the above example if the text contains "simple" tags with no attributes. `br`, `strong`, `i`, and `p` are the default, but that list can be expanded in the i18n config.
### Complex Elements Nested
Other times, you will want to have certain text inside another element, an anchor tag is a good example:
```js
// in the component:
<p>
<Trans i18nKey='check-forum'>
<a href='https://forum.freecodecamp.org/'>placeholder</a>
</Trans>
</p>
// in the JSON file:
{
"check-forum": "Check out <0>our forum</0>."
}
// output:
<p>Check out <a href='https://forum.freecodecamp.org/'>our forum</a></p>
```
In the above example, the key is set in the attributes of the `Trans` component. The `<0>` and `</0>` in the JSON represent the first child of the component, in this case, the anchor element. If there were more children, they would just count up from there using the same syntax. You can find the children of a component in the react dev tools by inspecting it. `placeholder` is simply there because the linter complains about empty `<a>` elements.
### With a Variable
```js
// in the component:
const email = 'team@freecodecamp.org';
<p>
<Trans email={email} i18nKey='fcc.email'>
<a href={`mailto:${email}`}>
{{ email }}
</a>
</Trans>
</p>
// in the JSON file:
{
"fcc": {
"email": "Send us an email at: <0>{{email}}</0>"
}
}
// output:
<p>Send us an email at: <a href='mailto:team@freecodecamp.org'>team@freecodecamp.org</a><p>
```
In the above example, the key and a variable are set in the attributes of the `Trans` component. `{{ email }}` needs to be somewhere in the `Trans` component as well, it doesn't matter where.
## Changing Text
To change text on the client side of things, go to the relevant `.json` file, find the key that is being used in the React component, and change the value to the new text you want. You should search the codebase for that key to make sure it isn't being used elsewhere. Or, if it is, that the changes make sense in all places.
Run `pnpm run clean-and-develop` to apply the change.
## Adding Text
If the text you want to add to the client exists in the relevant `.json` file, use the existing key. Otherwise, create a new key.
The English file is the "source of truth" for all of the `.json` files sharing the same name. If you need to add a new key, add it there. Then, add the key to **all** of the `translations.json` files.
> [!NOTE]
> Use English text for all languages if the file is translated through Crowdin. The tests will fail if you don't.
It would be nice to keep the keys in the same order across all the files as well. Also, try to put all punctuation, spacing, quotes, etc. in the JSON files and not in the components or server files.
> [!NOTE]
> The underscore (`_`) is a reserved character for keys in the client-side files. See [the documentation](https://www.i18next.com/translation-function/plurals) for how they are used.
Run `pnpm run clean-and-develop` to apply the change.
## Proposing a Pull Request (PR)
After you've committed your changes, check here for [how to open a Pull Request](how-to-open-a-pull-request.md).
## Helpful Documentation
- [react-i18next docs](https://react.i18next.com/latest/usetranslation-hook)
- [i18next docs](https://www.i18next.com/translation-function/essentials)
-152
View File
@@ -1,152 +0,0 @@
# How to Work on Practice Projects
Our practice projects use a step-based approach to teach concepts to campers. A project will consist of multiple files, which we refer to as **"steps"**. These files are named by the challenge ID, to avoid issues with the translation flow. Unfortunately, this makes it difficult to find the file associated with a specific step.
We've built a challenge editor tool that helps remedy this. This tool allows you to navigate the available projects, and the steps for each project (in order). There's also an embedded code editor you can use to work on the files directly.
## Using the Challenge Editor
These instructions will tell you how to use our challenge editor tool to work on the practice projects.
### Starting the Editor
To start the editor, make sure you are in the root freeCodeCamp directory. Then, run `pnpm run challenge-editor` to start both the client and the API that powers the editor.
The client will run on port `3300`, so you can access it at `http://localhost:3300`. The API runs on port `3200`, to avoid conflicts with the learn client and server. This will allow you to run the freeCodeCamp application at the same time as the editor, so you can test your changes locally.
### Navigating the Editor
The default view will list the available `superblocks` - these are the certifications. Click on the certification link you want to work on.
This will take you to the list of blocks. These are the practice projects. Click on the project link you want to work on.
This will take you to a list of steps for the project. If you are working on an existing step, you can click on the step link to open the editor. If you are adding or removing steps, click the `Use the step tools` link to switch to the step tools for that challenge.
### Editing Steps
When you click on a step, you'll be taken to the editor. This is a basic text editor that offers syntax highlighting.
After you have made your changes, click the `Save Changes` button to save your changes. You will get a browser alert letting you know that your changes are ready to commit. Note that you'll need to use `git` manually to stage and commit your files - this tool will not do that for you.
### Step Tools
When you click the `Use the step tools` link, you'll be taken to the step tools page. This allows you to add or remove steps from the project.
#### Create Next Step
Clicking this button will add a new step at the end of the project. This step will use the previous step's code as the seed.
#### Create Empty Steps
Enter the number of steps you want to add in the input. Then, clicking the button will create many empty steps at the end of the project.
#### Insert Step
Enter the step number that you want to add. Then, click the `Insert Step` button to add the step. The following steps will be re-ordered.
#### Delete Step
Enter the step number you want to delete. Then click the `Delete Step` button to remove that step. This will automatically update the step numbers for the remaining steps.
#### Update Step Titles
You should not have to use this tool unless you've manually deleted or added steps. This tool will reorder the step numbers.
## Using the Scripts Manually
If you want to work on the steps manually, in your local IDE, you can run the step management scripts directly.
The `tools/challenge-helper-scripts` folder contains tools to help facilitate the creation and maintenance of the freeCodeCamp project-based curriculum.
### Create a New Project
Change directory to `tools/challenge-helper-scripts` and run `pnpm run create-project`. This opens up a command line UI that guides you through the process. Once that has finished, there should be a new challenge in the English curriculum that you can use for the first step of the project. For example, if you created a project called `test-project` in the Responsive Web Design certification, it would be in `curriculum/challenges/english/01-responsive-web-design/test-project`.
If you want to create new steps, the following tools simplify that process.
### create-next-step
A one-off script that will automatically add the next step based on the last step in the project. The challenge seed code will use the previous step's challenge seed code.
#### How to Run the Script
1. Change to the directory of the project.
2. Run the following command:
```bash
pnpm run create-next-step
```
### create-empty-steps
A one-off script that automatically adds a specified number of steps. The challenge seed code for all steps created will be empty.
**Note:** This script also runs [update-step-titles](#update-step-titles).
#### How to Run the Script
1. Change to the directory of the project.
2. Run the following command:
```bash
pnpm run create-empty-steps X # where X is the number of steps to create.
```
### insert-step
A one-off script that automatically adds a new step at a specified position, incrementing all subsequent steps (both their titles and in their meta.json). The challenge seed code will use the previous step's challenge seed code with the editable region markers (ERMs) removed.
**Note:** This script also runs [update-step-titles](#update-step-titles).
#### How to Run the Script
1. Change to the directory of the project.
2. Run the following command:
```bash
pnpm run insert-step X # where X is the position to insert the new step.
```
### delete-step
A one-off script that deletes an existing step, decrementing all subsequent steps (both their titles and in their meta.json)
**Note:** This script also runs [update-step-titles](#update-step-titles).
#### How to Run the Script
1. Change to the directory of the project.
2. Run the following command:
```bash
pnpm run delete-step X # where X is the step number to be deleted.
```
### update-step-titles
A one-off script that automatically updates the frontmatter in a project's markdown files so that they are consistent with the project's meta.json. It ensures that each step's title (and dashedName) matches the meta's `challengeOrder`.
#### How to Run the Script
1. Change to the directory of the project.
2. Run the following command:
```bash
pnpm run update-step-titles
```
### repair-meta
One-off script to parse the step names from the project and update the meta.json order to reflect those steps. Useful if you've accidentally lost the changes to the meta.json file when adding/removing steps.
#### How to Run the Script
1. Change to the directory of the project.
2. Run the following command:
```bash
pnpm run repair-meta
```
## Proposing a Pull Request (PR)
After you've committed your changes, check here for [how to open a Pull Request](how-to-open-a-pull-request.md).
@@ -1,112 +0,0 @@
# How to Work on the Component Library
Welcome to freeCodeCamp's `ui-components` library. The components are built mostly from scratch with basic HTML elements and [Tailwind CSS](https://tailwindcss.com/).
> [!NOTE]
>
> freeCodeCamp has been using Bootstrap components in the UI. However, we are moving away from it and building our own component library, which helps standardize our UX/UI patterns and improve accessibility. The project is tracked in [this GitHub issue](https://github.com/freeCodeCamp/freeCodeCamp/issues/44668).
The following steps are recommended when working on a new component:
- Research and planning
- Implement the component
- Display the use cases on Storybook
- Write unit tests
## Researching and Planning
Before building a component, you need to research and document on how the existing version behaves and looks, to ensure that the new one has matching styles and supports all the current usages. In order to meet the web accessibility requirements, you should also pay attention to the accessibility aspect of the component, see which HTML elements and ARIA attributes are used under the hood.
Once you have gathered enough information about the component, you can start thinking about the props interface. Ideally, the interface should be as similar to the current version as possible, to ease the adoption later on. Since we are using Bootstrap components, the simplest approach is to mimic [their implementation](https://github.com/react-bootstrap/react-bootstrap/tree/master/src).
We prefer smaller pull requests rather than a large one, because they speed up the review time and reduce cognitive overload for the reviewers. For that reason, you should think about how you would break down the implementation and come up with a delivery plan.
We recommend opening a separate GitHub issue for each component and include all the notes in the issue description. It can be used as a place to host all of your working notes, as well as a way to communicate the approach with the reviewers. We will use the issue thread for further discussion if needed. [The issue for Button component](https://github.com/freeCodeCamp/freeCodeCamp/issues/45357) can be used as a reference.
## Implementing the Component
A new component can be created using the following command from the root directory:
```bash
cd tools/ui-components
pnpm run gen-component MyComponent
```
The command will generate a new folder inside the `ui-components` directory, with the following files:
| File name | Purpose |
| -------------------------- | ---------------------------------------------------------- |
| `index.ts` | It is used for exporting the component and its types. |
| `my-component.stories.tsx` | It is used for demoing the component on Storybook. |
| `my-component.test.tsx` | It is a test file. |
| `my-component.tsx` | It is where we implement the component. |
| `types.ts` | It is where we locate the component's interface and types. |
Each component is different, but in general, a component should:
- Support forwarding ref
- Be styled for both light and dark themes
- Be styled internally based on their props (the consumers should not need to restyle the component with the `className` prop)
- Utilize the built-in styling system from Tailwind instead of having custom styles
### Using Colors
There are two color "layers" in the component library:
- The base layer, where the color names describe what the colors are, e.g. `gray00`, `blue50`
- The semantic layer, where the color names describe what the colors are for, e.g. `foreground-primary`, `background-danger`
Generally, when using colors in a component, you should choose semantic variables over the base ones. There are exceptions, however, specifically when you are styling the component's states such as hover, active, disabled, etc. In these cases, we recommend using the base variables directly instead of creating new semantic variables, since each component can have different styles for its states.
> [!NOTE]
> Color definition can be found in the [`colors.css` file](https://github.com/freeCodeCamp/freeCodeCamp/blob/main/tools/ui-components/src/colors.css). A color is only available for use if it is added to the [`tailwind.config.js` file](https://github.com/freeCodeCamp/freeCodeCamp/blob/main/tools/ui-components/tailwind.config.js) under the `colors` property.
### Useful Links
- [Tailwind CSS Configuration](https://tailwindcss.com/docs/configuration)
- [React Bootstrap v0.33 Docs](https://react-bootstrap-v3.netlify.app)
- [Bootstrap 3.3.7 stylesheet](https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.7/css/bootstrap.css)
- [React Bootstrap current implementation](https://github.com/react-bootstrap/react-bootstrap/tree/master/src)
- [React Bootstrap current tests](https://github.com/react-bootstrap/react-bootstrap/tree/master/test)
## Displaying the Use Cases on Storybook
Use cases of the component should be added to the Storybook file (`.stories.tsx`).
To start Storybook, run the following command from the root directory:
```bash
pnpm run storybook
```
The Storybook page is available on [http://localhost:6006](http://localhost:6006).
## Writing Unit Tests
We use [React Testing Library](https://testing-library.com/docs/react-testing-library/intro/) to write unit tests. The tests should assert that the components behave as expected and are accessible.
To run tests against the component library, run the following command from the root directory:
```bash
pnpm run test-ui-components
```
## Proposing a Pull Request (PR)
After you've committed your changes, check here for [how to open a Pull Request](how-to-open-a-pull-request.md).
## Adding Packages to the UI-Component Library
We restrict adding new packages to the UI Components to help with the project's maintainability. In the rare chance that you think a dependency is needed, please check with the maintainers first and then use the following command to add a package:
```bash
cd tools/ui-components
pnpm add package_name
```
## Useful Links
- [Testing for Accessibility](https://testing-library.com/docs/dom-testing-library/api-accessibility)
- [Order of priority of React Testing Library's queries](https://testing-library.com/docs/queries/about/#priority)
- [Common mistakes with React Testing Library](https://kentcdodds.com/blog/common-mistakes-with-react-testing-library)
-59
View File
@@ -1,59 +0,0 @@
# How to Work on Documentation
## Work on the Content of the Docs
To work on the contributing guidelines, you can edit or add files in the `docs` directory [available here](https://github.com/freeCodeCamp/freeCodeCamp/tree/main/docs). When your changes are merged, they will be made available automatically at the documentation site.
When adding a new file to the `docs` directory, you should evaluate if the file should also be added to the sidebar navigation. We typically create a link in the [`_sidebar.md`](_sidebar.md) file for new and independent guides. Alternatively, You may follow the instructions below on creating an internal link for supporting guides.
### How to Create an Internal Link
If you want to create a link targeting a different section of the contributing guidelines, follow this format:
```md
[Link text](target-file-name.md#target-section-heading-id)
// If the target section is within the same page, you can omit the file name
[Link text](#target-section-heading-id)
```
Make sure you include the file extension (`.md`). Don't specify the full URL or append `/` before the file name.
This is necessary to make these links work for the translated version of the document. Otherwise, they will redirect to the English version of the page regardless of the language.
#### Translating docs with internal links
When you work on translating docs on Crowdin, make sure to replace the `#target-section-heading-id` with the id on the translated document. [Learn more about translating docs here](how-to-translate-files.md#translate-documentation).
## Work on the Docs Theme
> [!NOTE]
> A quick reminder that you do not need to set up anything for working on the content for the documentation site.
>
> To work on the contributing guidelines, see [work on the docs content](#work-on-the-docs-content) section.
### Structure of the Docs Website
The site is generated using [`docsify`](https://docsify.js.org) and served using GitHub pages.
Typically you would not need to change any configuration or build the site locally. In case you are interested, here is how it works:
- The homepage's source for this site is available in [`docs/index.html`](index.html).
- We serve this file as a SPA using `docsify` and GitHub Pages.
- The `docsify` script generates the content of `markdown` files in the `docs` directory on demand.
- The homepage is generated from the [`_coverpage.md`](_coverpage.md).
- The sidebar navigation is generated from [`_sidebar.md`](_sidebar.md).
### Serving the Documentation Site Locally
Install freeCodeCamp locally ([see the local setup guide](how-to-setup-freecodecamp-locally)), we bundled the CLI with the development tools so you can run the command below as needed from the root of the repo:
```bash
pnpm run docs:serve
```
> The documentation site should be available at <http://localhost:3400>
## Proposing a Pull Request (PR)
After you've committed your changes, check here for [how to open a Pull Request](how-to-open-a-pull-request.md).
@@ -1,138 +0,0 @@
This page describes how to contribute to the freeCodeCamp tutorials and projects that are completed using the CodeRoad VS Code extension.
## How the Tutorials Work
Each of the freeCodeCamp tutorials that use CodeRoad has its own repo under the freeCodeCamp GitHub organization. They all start with `learn-`. For example, `https://github.com/freeCodeCamp/learn-bash-by-building-a-boilerplate/`.
Each tutorial repo has a `main` branch and a "version" branch, e.g. `v1.0.0`.
The two main files on the `main` branch are `TUTORIAL.md` and `coderoad.yaml`. `TUTORIAL.md` contains all the instructions, hints, titles, and so on, for the tutorial. `coderoad.yaml` contains instructions for CodeRoad, such as what commands to run and when, what files to watch for changes, and what version branch to use for the steps.
The "version" branch contains the commits that will be loaded on each step of a tutorial. The commit messages on this branch have to be specific. The first commit needs `INIT` for its message and contains all the files to load before the first lesson.
Subsequent commit messages have to match the step number in `TUTORIAL.md` from the `main` branch. For example, the commit with the message `10.1` will be loaded when a user goes to step `10.1`.
In order to make changes to commits on a version branch, you would need to rebase and edit the commits you want to change. This will rewrite the Git history, so we cannot accept PRs to these types of branches. Once a version branch is on the freeCodeCamp repo, it should never change.
> [!WARNING]
>
> Never make or push changes to a version branch that is on one of the freeCodeCamp repos. Always create a new one
## How to Contribute
### Prerequisites
Install the [CodeRoad CLI tools](https://www.npmjs.com/package/@coderoad/cli) with `npm install -g @coderoad/cli`.
There have been some issues with the latest version. If `coderoad --version` doesn't work after installing, downgrade to `0.7.0` with `npm install -g @coderoad/cli@0.7.0`.
### Working on `main`
This set of instructions is for PRs that only make minor changes on `main` to **existing lessons**. That mainly consists of typo, grammar, hint, and instructional changes or fixes in the `TUTORIAL.md` file.
For everything else, including adding or deleting lessons, follow the [working on a version branch instructions](#working-on-version-branch). You will not need to create a new version branch for this - you can create a PR following the instructions below.
> [!NOTE]
>
> These changes will use the existing version branch. If they are substantial, feel free to add them to `CHANGELOG.md`. Most of the time, a good commit message should work
You never need to modify the `tutorial.json` file directly. That will be created with the CLI tools.
If you are only making minor changes like fixing a typo or grammatical error, you don't have to test your changes.
Follow these instructions to make a PR, keeping in mind that instructions usually use the lessons around them for context:
- Create a copy of the latest version branch with `git branch vX.X.X upstream/vX.X.X` - you do not need to check this branch out, it just needs to exist.
- Create and checkout a new branch off of `main`
- Make **and commit** your changes. Reminder: You don't need to change anything in the `tutorial.json` file. You likely only need to make changes to `TUTORIAL.md`
- Run `coderoad build` to recreate the `tutorial.json` file
- Commit the changes with `update json` as the message
- Make a PR
### Testing Changes on `main`
If you want to test your changes to `main` after using the above instructions, follow these instructions:
- Follow the instructions on the [rdb-alpha repo](https://github.com/freeCodeCamp/rdb-alpha) to run a container
- Start the tutorial using the `tutorial.json` file on the new branch
### Reviewing PRs to `main`
If reviewing a PR that only changes `main` with instructional or grammar issues as described above, the changes in `TUTORIAL.md` should match the changes in `tutorial.json`.
The `tutorial.json` file should not have changes to commit hashes, or step/level ids. Startup or level commands or file watchers likely should not be changed either. There are exceptions if there's an issue with a step, but they should be treated with more caution.
Also, keep in mind that instructions usually use the lessons around them for context, so make sure they make sense.
### Working on Version Branch
> [!WARNING]
>
> Reminder: Never make or push changes to a version branch that is on one of the freeCodeCamp repos. Always create a new one
There's no easy way to see exactly what changed between version branches since the Git history will be rewritten. Accepting new version branches to use will need to be done with careful consideration and testing.
These instructions are for changing anything on a "version" branch, such as tests, test text, reset files, adding and deleting steps, among other things.
Follow these instructions to create a new version:
- Checkout the **latest** version branch with `git checkout -b vX.X.X upstream/vX.X.X`
- Create a new branch off of that, incrementing the version, with `git checkout -b vX.X.Y`
- Make your changes to the version branch. See more info in the [CodeRoad Documentation](https://coderoad.github.io/docs/edit-tutorial) for how to work with tutorials
- Push the new branch to your fork with `git push -u origin vX.X.Y`
- Checkout the `main` branch
- Create a new branch off `main`. e.g. `feat/version-X.X.Y`
- Change the `uri` in `coderoad.yaml` to your fork of the repo. This is so you and reviewers can test it before pushing it to the freeCodeCamp repo. Change the version to the new branch in the two spots of that file. Add your changes for the new version to `CHANGELOG.md`. Make any other changes you need.
- Commit your changes with the message `feat: release version X.X.Y - <optional description>`
- Run `coderoad build` to create a new `tutorial.json` file
- Add and commit the file
- Push the changes to your fork
- Test your changes following the [testing instructions below](#testing-changes-to-a-version-branch). Make any additional changes and commit them as you just did, or, if you are satisfied, follow the rest of the instructions
- Make a PR to `main` using your new `feat/version-X.X.Y` branch. Give it a title of `version X.X.Y ready for review`. This will not be merged, it is just to let reviewers know that there is a new version ready
- Leave it here for reviewers
### Testing Changes to a Version Branch
- Follow the instructions on the [rdb-alpha repo](https://github.com/freeCodeCamp/rdb-alpha) to run a container
- Start the tutorial using the `tutorial.json` file on whatever fork the changes are on. Make sure to use the file on the `feat: version-X.X.Y` branch and not the `main` branch
### Pushing a New Version
Before pushing a new version, view the new `feat/version-vX.X.Y` (will be merged to `main`) branch on the user's fork. Make sure there are additions to the `CHANGELOG.md` file that include the new changes, and the version in the two spots of `coderoad.yaml` matches the new version branch.
If you have write access to the freeCodeCamp repo, have verified the `CHANGELOG` and `coderoad.yaml` files, have tested the changes using the instructions above, and want to push a new version of a tutorial:
> [!WARNING]
>
> Reminder: Never make or push changes to a version branch that is on one of the freeCodeCamp repos. Always create a new one
- If you don't have a remote to where the new changes exist, create a remote to the user's fork with `git remote add <users_fork>`
- Delete any **local** branches that share a name with the new branches. Likely named either `vX.X.Y` or `feat/version-X.X.Y`
- Checkout the new version branch with `git checkout -b vX.X.Y <remote>/vX.X.Y`
- Push the new version branch to the freeCodeCamp repo with `git push -u upstream/vX.X.Y`. You need to push the new branch before you update `main` with the new `tutorial.json` file
- Checkout the users branch that will be merged into `main` with `git checkout -b feat/version-X.X.Y <remote>/feat/version-X.X.Y`
- Change the `uri` in `coderoad.yaml` back to the freeCodeCamp repo
- Add and commit the changes
- Run `coderoad build` to create the new `tutorial.json` file
- Add and commit the file
- Push the changes to your fork with `git push -u origin/feat/version-X.X.Y`
- Make a PR to `main` on the freeCodeCamp repo
- If you are satisfied, merge it or leave it and ask for a review from someone
- After the PR is merged, open the tutorial by following the instructions on the [rdb-alpha repo](https://github.com/freeCodeCamp/rdb-alpha) to make sure it's loading properly, and that you can get through a few steps
- Finally, if any PRs for this version exist, close them
### How to Revert to a Previous Version
- Create a new branch off of the latest `main` with `git checkout -b revert/to-version-X.X.X`
- Revert all commits on this branch up to and including the commit of the version after the one you want to revert to. For example, you may have commits that look like this:
```
fix: typo
release: version 1.0.1
fix: typo
release: version 1.0.0
```
If you want to revert to v1.0.0, revert all the commits from `release: version 1.0.1` and after
- Create a PR. Give it a title of `revert: to version X.X.X`
-109
View File
@@ -1,109 +0,0 @@
# Frequently Asked Questions
Answers to common questions.
## I am new to GitHub and Open Source. Where should I start?
Read our ["How to Contribute to Open Source Guide"](https://github.com/freeCodeCamp/how-to-contribute-to-open-source). It's a comprehensive reference for first-timer-friendly projects. And it includes a lot of open-source contribution tips.
## What do I need to know to contribute to the codebase?
freeCodeCamp runs on a modern JavaScript stack. If you're interested in contributing to our codebase, you will need some familiarity with JavaScript and some of the technologies we use like Node.js, MongoDB, OAuth 2.0, React, Gatsby, and Webpack.
## Can I translate freeCodeCamp's resources?
Yes - You can contribute to any of the 30+ languages we have enabled on our translation platform.
We have user-contributed translations live in some languages. We intend to localize freeCodeCamp into several major world languages. You can read all about this in our [announcement here](https://www.freecodecamp.org/news/help-translate-freecodecamp-language/).
If you are interested in contributing to translations please make sure you [read this guide](how-to-translate-files.md) first.
## Can I contribute articles to freeCodeCamp News or videos to freeCodeCamp's YouTube channel?
Yes - you can contribute to our publication blog and YouTube channel.
If you're interested in writing articles for freeCodeCamp News, please visit this [publication guide](https://www.freecodecamp.org/news/how-to-write-for-freecodecamp/). In addition, please read our [style guide](https://www.freecodecamp.org/news/developer-news-style-guide/) as this will help you write stronger and more effective articles.
To help us make educational videos for our YouTube channel, you can follow the [YouTube channel guide here](https://www.freecodecamp.org/news/how-to-contribute-to-the-freecodecamp-community-youtube-channel-b86bce4c865/).
## How can I report a new bug?
If you think you've found a bug, first read the ["How to Report a Bug"](https://www.freecodecamp.org/news/how-to-report-a-bug-to-freecodecamp/) article and follow its instructions.
If you're confident it's a new bug, go ahead and create a new GitHub issue. Be sure to include as much information as possible so that we can reproduce the bug. We have a pre-defined issue template to help you through this.
Please note that these GitHub issues are for codebase-related issues and discussions – not for getting help with learning to code. Whenever in doubt, you should [seek assistance on the forum](https://forum.freecodecamp.org) before creating a GitHub issue.
## How can I report a security issue?
Please don't create GitHub issues for security issues. Instead, please [follow our security policy](https://contribute.freecodecamp.org/#/security).
## I am a student. Can I work on a feature for academic credits?
Yes. Please note we are unable to commit to any timelines or paperwork that may be a requirement by your college or university. We receive many pull-requests and code contributions from volunteer developers, and we respect their time and efforts. Out of respect for all of our other contributors, we will not give any PR special priority just because it happens to be school-related.
We request you to plan ahead and work on code contributions with this in mind.
## What do these different labels that are tagged on issues mean?
The code maintainers [triage](https://en.wikipedia.org/wiki/Software_bug#Bug_management) issues and pull requests based on their priority, severity, and other factors. You can [find a complete glossary of their meanings here](https://github.com/freecodecamp/freecodecamp/labels).
## Where do I start if I want to work on an issue?
You should go through [**`help wanted`**](https://github.com/freeCodeCamp/freeCodeCamp/issues?q=is%3Aopen+is%3Aissue+label%3A%22help+wanted%22) or [**`first timers only`**](https://github.com/freeCodeCamp/freeCodeCamp/issues?q=is%3Aopen+is%3Aissue+label%3A%22first+timers+only%22) issues for a quick overview of what is available for you to work on.
> [!TIP] **`help wanted`** issues are up for grabs, and you do not need to seek permission before working on them. 然而,具有 **`first timers only`** 標籤的 issue 是特別爲以前沒有爲 freeCodeCodeCamp 代碼庫貢獻的人設計的任務。
## I found a typo. Should I report an issue before I can make a pull request?
For typos and other wording changes, you can directly open pull requests without creating an issue first. Please be sure to mention details in the pull request description to help us understand and review your contribution – even if it's just a minor change.
Please do create an issue if you want to discuss bigger aspects of the codebase or curriculum.
## How can I get an issue assigned to me?
We typically do not assign issues to anyone other than long-time contributors. Instead, we follow the below policy to be fair to everyone:
1. We are most likely to merge the first pull request that addresses the issue.
2. In the case of multiple contributors opening a pull request for the same issue at around the same time, we will give priority to the pull request that best addresses the issue. Some of the things we consider:
- Did you include tests?
- 你是否考慮了所有用例?
- 你是否確保通過所有測試,並確認所有東西在本地正常運行?
3. Finally, we give priority to pull requests which follow our recommended guidelines.
- Did you follow the pull request checklist?
- Did you give your pull request a meaningful title?
## I am interested in being a moderator at freeCodeCamp. Where should I start?
Our community moderators are our heroes. Their voluntary contributions make freeCodeCamp a safe and welcoming community.
First and foremost, we would need you to be an active participant in the community, and live by our [code of conduct](https://www.freecodecamp.org/news/code-of-conduct/) (not just enforce it).
Here are some recommended paths for some of our platforms:
- To be a **Discord/Chat** moderator, have an active presence in our chat and have positive engagements with others, while also learning and practicing how to deal with potential conflicts that may arise.
- To be a **Forum** moderator, similar to a chat moderator, have an active presence and engage with other forum posters, supporting others in their learning journey, and even giving feedback when asked. Take a look at [The Subforum Leader Handbook](https://forum.freecodecamp.org/t/the-subforum-leader-handbook/326326) for more information.
- To be a **GitHub** moderator, help process GitHub issues that are brought up to see if they are valid and (ideally) try to propose solutions for these issues to be picked up by others (or yourself).
Altogether, be respectful to others. We are humans from all around the world. With that in mind, please also consider using encouraging or supportive language and be mindful of cross-cultural communication.
If you practice the above **consistently for a while** and our fellow moderator members recommend you, a staff member will reach out and onboard you to the moderators' team. Open source work is voluntary work and our time is limited. We acknowledge that this is probably true in your case as well. So we emphasize being **consistent** rather than engaging in the community 24/7.
Take a look at our [Moderator Handbook](moderator-handbook.md) for a more exhaustive list of other responsibilities and expectations we have of our moderators.
## I am stuck on something that is not included in this documentation.
**Feel free to ask for help in:**
- The `Contributors` category of [our community forum](https://forum.freecodecamp.org/c/contributors).
- The `#Contributors` channel on [our chat server](https://discord.gg/PRyKn3Vbay).
We are excited to help you contribute to any of the topics that you would like to work on. If you ask us questions on the related issue threads, we will be glad to clarify. Be sure to search for your question before posting a new one.
Thanks in advance for being polite and patient. Remember – this community is run mainly by volunteers.
## Additional Assistance
If you have queries about the stack, architecture of the codebase, translations, or anything else, feel free to reach out to our staff team [on the forum](https://forum.freecodecamp.org/g/team).
**You can email our developer staff at: `dev[at]freecodecamp.org`**
-48
View File
@@ -1,48 +0,0 @@
- **準備開始**
- [介紹](index.md "爲 freeCodeCamp.org 社區貢獻")
- [常見問題](FAQ.md)
- [Reporting a Vulnerability](security.md)
- **Translation Contribution**
- [Work on translating resources](how-to-translate-files.md)
- [Work on proofreading translations](how-to-proofread-files.md)
- **Code Contribution**
- [Set up freeCodeCamp](how-to-setup-freecodecamp-locally.md)
- [Follow best-practices](codebase-best-practices.md)
- [Work on Codebase](how-to-contribute-to-the-codebase.md)
- [Work on Coding Challenges](how-to-work-on-coding-challenges.md)
- [Use the Curriculum Helpers](curriculum-help.md)
- [Work on Component Library](how-to-work-on-the-component-library.md)
- [Work on Practice Projects](how-to-work-on-practice-projects.md)
- [Work on Mobile app](how-to-setup-freecodecamp-mobile-app-locally.md)
- [Work on tutorials with CodeRoad](how-to-work-on-tutorials-that-use-coderoad.md)
- [Work on Localized Web App](how-to-work-on-localized-client-webapp.md)
- [Work on Playwright Tests](how-to-add-playwright-tests.md)
- [Work on Video Challenges](how-to-help-with-video-challenges.md)
- [Work on Documentation](how-to-work-on-the-docs-theme.md)
- [Open a pull request](how-to-open-a-pull-request.md)
- **Additional Guides**
- [Understand the curriculum file structure](curriculum-file-structure.md)
- [Debug outgoing emails locally](how-to-catch-outgoing-emails-locally.md)
- [Work on Cypress Tests](how-to-add-cypress-tests.md)
- [Set up freeCodeCamp on Windows (WSL)](how-to-setup-wsl.md)
- [Use Docker on Windows Home](how-to-use-docker-on-windows-home.md)
- [User Token Workflow](user-token-workflow.md)
- [Troubleshooting Development Issues](troubleshooting-development-issues.md)
- [Authors Analytics Manual](authors-analytics-manual.md)
---
- **飛行手冊**(針對員工 & 維護人員)
- [維護人員手冊](moderator-handbook.md)
- [Reply Templates](reply-templates.md)
- [Language Lead Handbook](language-lead-handbook.md)
- [DevOps Handbook](devops.md)
- [Courses VSCode Extension](courses-vscode-extension.md)
- [Enable New Language](how-to-enable-new-languages.md)
---
- **我們的社區**
- [**GitHub**](https://github.com/freecodecamp/freecodecamp)
- [**Discourse 論壇**](https://freecodecamp.org/forum/c/contributors)
- [**聊天室**](https://discord.gg/PRyKn3Vbay)
@@ -1,27 +0,0 @@
# Authors Analytics Manual
If you are an author with access to the publication's Google Analytics Property (News), you can use this guide to view your article engagement and search for articles by publication language.
## Search by Language
To search for engagement reports in a specific language:
![Image - Show steps to search by language on googla analytics](https://contribute.freecodecamp.org/images/google-analytics/search-by-language.png)
1. From the top dropdown menu, select `News`.
1. From the sidebar, click on `Reports`.
1. From the secondary sidebar, select `Engagement`.
1. Click on `Pages and Screens`.
1. In the search bar, type the subpath for the desired language.
1. From the dropdown under the search bar, choose `Page path and screen class`.
## Filter Reports by Author
After arriving at the `Pages and Screens` reports mentioned above, use the following steps to filter the results by specific authors.
![Image - Show steps to search by language on googla analytics](https://contribute.freecodecamp.org/images/google-analytics/filter-by-author.png)
1. Click on the `Add filter` button.
1. From the side navigation include `Author`.
1. From the `Dimensions values` dropdown, choose an author's name.
1. Click on the `Apply` button to apply changes.
@@ -1,188 +0,0 @@
# Codebase Best Practices
## Styling a component
We recommend styling components using our [design style guide](https://design-style-guide.freecodecamp.org/).
The colors are defined in [`variable.css`](/client/src/components/layouts/variables.css), and the fonts are in [`fonts.css`](/client/src/components/layouts/fonts.css).
We are strongly opinionated about adding new variables/tokens to the colors. After careful research, the colors have been chosen to respect the freeCodeCamp brand identity, developer experience, and accessibility.
The `!important` keyword may be used to override values in some cases (e.g. accessibility concerns). You should add a comment describing the issue, so it doesn't get removed in future refactoring.
### RTL support
We are striving to support right-to-left (RTL) layout in the codebase for languages that are read in this direction. For this, you need to be mindful of how to style components. Here are some quick rules of thumb to follow:
- Don't use `float` properties
- Use Flexbox and Grid layouts instead, as they have RTL support already built-in, and those will be easier to maintain and review.
- Don't define the direction while using `margin` and `padding`: it may seem harmless to use `padding-right` and `margin-left`, but these directions aren't mirrored when the layout changes to RTL, and adding counter values for them in the RTL file makes maintaining the codebase harder.
- Use logical properties for them: You can add the same spacing by using `padding-inline-end` and `margin-inline-start`, and you won't need to worry about RTL layout, as they follow where the line starts and ends, and you won't need to add any extra values in the RTL files, so people won't need to remember to change the same values in two files.
- Don't use `!important` in `font-family`: RTL layout uses different fonts compared to the LTR layout, when you add `!important` in the `font-family` property it affects the RTL layout too.
## General JavaScript
In most cases, our [linter](how-to-setup-freecodecamp-locally.md#follow-these-steps-to-get-your-development-environment-ready) will warn of any formatting which goes against this codebase's preferred practice.
It is encouraged to use functional components over class-based components.
## Specific TypeScript
### Migrating a JavaScript File to TypeScript
#### Retaining Git File History
Sometimes changing the file from `<filename>.js` to `<filename>.ts` (or `.tsx`) causes the original file to be deleted, and a new one created, and other times the filename just changes - in terms of Git. Ideally, we want the file history to be preserved.
The best bet at achieving this is to:
1. Rename the file
2. Commit with the flag `--no-verify` to prevent Husky from complaining about the lint errors
3. Refactor to TypeScript for migration, in a separate commit
> [!NOTE] Editors like VSCode are still likely to show you the file has been deleted and a new one created. If you use the CLI to `git add .`, then VSCode will show the file as renamed in stage
### Naming Conventions
#### Interfaces and Types
For the most part, it is encouraged to use interface declarations over type declarations.
React Component Props - suffix with `Props`
```typescript
interface MyComponentProps {}
// type MyComponentProps = {};
const MyComponent = (props: MyComponentProps) => {};
```
React Stateful Components - suffix with `State`
```typescript
interface MyComponentState {}
// type MyComponentState = {};
class MyComponent extends Component<MyComponentProps, MyComponentState> {}
```
Default - object name in PascalCase
```typescript
interface MyObject {}
// type MyObject = {};
const myObject: MyObject = {};
```
<!-- #### Redux Actions -->
<!-- TODO: Once refactored to TS, showcase naming convention for Reducers/Actions and how to type dispatch funcs -->
## Redux
### Action Definitions
```typescript
enum AppActionTypes = {
actionFunction = 'actionFunction'
}
export const actionFunction = (
arg: Arg
): ReducerPayload<AppActionTypes.actionFunction> => ({
type: AppActionTypes.actionFunction,
payload: arg
});
```
### How to Reduce
```typescript
// Base reducer action without payload
type ReducerBase<T> = { type: T };
// Logic for handling optional payloads
type ReducerPayload<T extends AppActionTypes> =
T extends AppActionTypes.actionFunction
? ReducerBase<T> & {
payload: AppState['property'];
}
: ReducerBase<T>;
// Switch reducer exported to Redux combineReducers
export const reducer = (
state: AppState = initialState,
action: ReducerPayload<AppActionTypes>
): AppState => {
switch (action.type) {
case AppActionTypes.actionFunction:
return { ...state, property: action.payload };
default:
return state;
}
};
```
### How to Dispatch
Within a component, import the actions and selectors needed.
```tsx
// Add type definition
interface MyComponentProps {
actionFunction: typeof actionFunction;
}
// Connect to Redux store
const mapDispatchToProps = {
actionFunction
};
// Example React Component connected to store
const MyComponent = ({ actionFunction }: MyComponentProps): JSX.Element => {
const handleClick = () => {
// Dispatch function
actionFunction();
};
return <button onClick={handleClick}>freeCodeCamp is awesome!</button>;
};
export default connect(null, mapDispatchToProps)(MyComponent);
```
<!-- ### Redux Types File -->
<!-- The types associated with the Redux store state are located in `client/src/redux/types.ts`... -->
## API
### Testing
The `api/` tests are split into two parts:
1. Unit tests
2. Integration tests
#### Unit Tests
Unit tests isolate a single function or component. The tests do not need mocking, but will require fixtures.
The unit tests are located in a new file adjacent to the file exporting that is being tested:
```text
api/
├── src/
│ ├── utils.ts
│ ├── utils.test.ts
```
#### Integration Tests
Integration tests test the API as a whole. The tests will require mocking and should not require fixtures beyond the database seeding data and a method for authentication.
Typically, each integration test file will be directly related to a route. The integration tests are located in the `api/tests/` directory:
```text
api/
├── tests/
│ ├── settings.ts
```
## Further Literature
- [TypeScript Docs](https://www.typescriptlang.org/docs/)
- [TypeScript with React CheatSheet](https://github.com/typescript-cheatsheets/react#readme)
@@ -1,41 +0,0 @@
# Courses VSCode Extension
This details the maintenance guidelines for the [freeCodeCamp/courses-vscode-extension](https://github.com/freeCodeCamp/courses-vscode-extension) repository which contains the source code for the [freeCodeCamp - Courses](https://marketplace.visualstudio.com/items?itemName=freeCodeCamp.freecodecamp-courses) extension.
## Publishing the Extension
A GitHub Action automagically publishes the extension to the Visual Studio Marketplace, on the release of a new GitHub Release.
1. Package a new version of the extension:
```bash
npm run pack -- <tag_type>
```
Where `<tag_type>` is one of: `major`, `minor`, `patch`.
2. Push the new version to `main`:
```bash
git commit -am "<tag_type>(<version>): <description>"
git push
```
Optionally, you can push directly to `upstream/main`, but opening a new PR is recommended for a sanity check.
3. Create a new GitHub Release using the GitHub UI:
- Correctly increment the version number, when creating a new tag.
- Upload the `.vsix` file with the release.
- Publish the release, and confirm the action succeeded.
> [!NOTE] Creating a release requires write access to the `freeCodeCamp/courses-vscode-extension` repository.
## Manually Publishing the Extension
A manual upload to the Visual Studio Marketplace can be achieved, by following these steps:
1. Visit https://marketplace.visualstudio.com/ and sign in
2. Navigate to the [freeCodeCamp Publisher page](https://marketplace.visualstudio.com/manage/publishers/freecodecamp)
3. Select the relevant extension, and select `Update`
4. Upload the file from your local files
@@ -1,105 +0,0 @@
# Curriculum File Structure
Our core instructional content is located within the conveniently named `curriculum` directory. This page will break down how these files are organized.
## Terminology
There are a few terms we use when discussing our curriculum content.
- `certification` : When referring to a certification in this instance, it is talking about the actual certificate that users claim. Which is separate from the name of the superBlock.
- `superBlock` : A superblock is the top level collection of challenges. Each superblock corresponds to a certification in the curriculum (e.g. Responsive Web Design).
- `block` : A block is a section within a superblock. A block corresponds to a group of challenges in a given certification (e.g. Basic HTML and HTML5)
- `challenge` : A challenge is a single lesson within the curriculum (e.g. Say Hello to HTML Elements)
## File Tree
Using those terms, here is how the file structure would be defined:
<!-- prettier-ignore -->
```md
curriculum/
├─ _meta/
│ ├─ {block}/
│ │ ├─ meta.json
├─ {language}/
│ ├─ {superBlock}/
│ │ ├─ {block}/
│ │ │ ├─ {challenge}.md
```
## The `_meta` Directory
The `_meta` directory is a special directory which contains `.json` files. These files correspond to each block in the curriculum, and are used to determine which superBlock a block belongs to, and the order of the challenges within that block.
## Renaming Files
There may be times when you need to rename a certificate, superblock, block, or challenge. This section will outline the steps needed to avoid build errors when doing so.
> [!ATTENTION] Renaming files within the curriculum structure will often change the path (or URL) of the content on the main webpage. Doing so should be done with care, as redirects have to be set up for each change that is made.
### Renaming a Certification
When renaming a certification, you will likely want to rename the associated superblock along with it. Do the following to rename only the certificate:
1. Rename the `curriculum/challenges/_meta/{superBlock}-certificate` folder to the new name.
1. In the `meta.json` file of that folder, rename the values in `name`, `dashedName`, and `challengeOrder` to the new cert name.
1. In `curriculum/challenges/english/12-certificate`, rename the `{superBlock}-certificate` folder, and the YAML file within it, to the new name.
1. In the YAML file, change the `title` to the new name.
1. Rename the file and folder from step 3 for the rest of the curriculum languages.
1. Update `client/src/redux/index.ts` to use the correct `title`.
1. Optionally, update the `certSlug` for the superblock in the same file. **Note** that renaming a `certSlug` will change the URL for certifications and should only be done with careful consideration.
1. Update the `title` in `client/src/resources/cert-and-project-map.ts` to the new value. **Note** that changing the `title` here **will break** the superBlock page for the associated certification. It relies on the superBlock title to match the certification title. You will likely want to rename the superBlock at the same time.
1. If you renamed the `certSlug` in step 7, change it here for the cert and all the nested `projects` values.
1. In `shared/config/certification-settings.js`, update the value of `certTypeTitleMap` to the new name.
1. If you renamed the `certSlug` in step 7, update the key of `certSlugTypeMap` in the same file.
1. Update the certificate name in the `legacyCerts` array of the `client/src/client-only-routes/show-project-links.tsx` if needed.
1. Update the main `README.md` file to the new name.
### Renaming a Superblock
> [!NOTE] When you rename a superBlock, the new folder name is used as the path and should be considered the "correct" name. All other values should be updated to reflect that change.
Also, you will likely want to rename the certificate and the `{superBlock}-projects` block when you rename a superBlock since they all share a name. To rename only a superBlock you need to:
1. Rename the superBlock folder in the `curriculum/challenges/english` directory.
1. Rename the superBlock folder in _all_ other `curriculum/challenges/{language}` directories.
1. For each block within that superBlock, update the `superBlock` value in the `meta.json` file to its dashedName. You don't need to rename any folders here. Do that when renaming a block.
1. Rename the superblock folder in `client/src/pages/learn`.
1. Update the `index.md` file in the above folder, changing the `title` and `superBlock` values to the new name.
1. For each block folder within the above, update the `index.md` to use the correct `superBlock` value.
1. In the `client/src/resources/cert-and-project-map.ts` file, update the path for the cert at the top of the file, and the `title` value for that superBlock. **Note** that changing the `title` here **will break** the ability to view the actual certification for this superBlock. It relies on the superBlock title to match the certification title. You will likely want to rename the certification at the same time.
1. Update the `superBlockCertTypeMap` key in `shared/config/certification-settings.js` to the new superBlock name.
1. Update the path value in `client/src/assets/icons/index.tsx`.
1. For each language in `client/i18n/locales`, update the `intro.json` file to use the new superBlock `dashedName`. In the English file, also update the `title`.
1. Check the `shared/config/i18n/all-langs.js` file to see if the superBlock is enabled in i18n builds. Update all the values where it is used.
1. Update the main `README.md` file to the new name.
### Renaming a Block
When renaming a curriculum block, you need to:
1. Change the name of the block folder in the `curriculum/challenges/english/{superBlock}` directory.
1. Change the name of the same block folder in _all_ of the other language directories to match. These must all be the same as the English structure or the build will error out.
1. Change the name of the block folder in the `_meta` directory.
1. Update the `name` and `dashedName` property for that block's `meta.json` file.
1. Update the block folder in `client/src/pages/learn/{superBlock}`.
1. In the `index.md` file of the above folder, update the `block` value in the frontmatter.
1. In the `client/i18n/locales/{language}/intro.json` files, update the block name to the new name for all the languages. In the English `intro.json` file, update the `title` as well.
1. Update the main `README.md` file to the new name.
### Renaming a Challenge
When renaming a single challenge file, you need to:
1. Change the name of the challenge file in the `curriculum/challenges/english` directory.
1. Change the name of the `title` and `dashedName` within that file.
1. Change the name of the file, and the `dashedName` in those files for _all_ of the other language directories to match.
1. Update the name of the challenge in the relevant `meta.json` file. The challenge names here are not used in the build, but provide a user-friendly way to identify the challenge order.
1. If the challenge is a certificate project, update the YAML file in `curriculum/english/12-certificates/<superBlock>` to the new name.
1. If the challenge is a certificate project, update the `title` and `link` in `client/src/resources/cert-and-project-map.ts`
1. If the challenge is a certificate project, update the main `README.md` file to the new name.
## The `dashedName` Property
The `dashedName` property is used to generate the URL path for the superblock, block, or challenge. These should generally match what the `/utils/slugs.js` helper would output for the file name.
@@ -1,161 +0,0 @@
# Using the Curriculum Helpers
The test runner has access to a few helpers that can assist with testing campers' code.
## CSS Helper
To instantiate the helper within a test block, use this:
```js
const helper = new __helpers.CSSHelp(document);
```
In that example, the `document` variable refers to the document object of the test runner's iframe.
### Methods
There are a few methods available for parsing and testing CSS.
#### `.getStyle()`
The `.getStyle()` method takes a CSS selector and returns a CSS style declaration object.
For example, if the camper has written the following CSS:
```css
body {
background: linear-gradient(45deg, rgb(118, 201, 255), rgb(247, 255, 222));
margin: 0;
padding: 0;
width: 100%;
height: 100vh;
overflow: hidden;
}
```
You would get an object that looks like this:
```js
{
0: "background-image",
1: "background-position-x",
2: "background-position-y",
3: "background-size",
4: "background-repeat-x",
5: "background-repeat-y",
6: "background-attachment",
7: "background-origin",
8: "background-clip",
9: "background-color",
10: "margin-top",
11: "margin-right",
12: "margin-bottom",
13: "margin-left",
14: "padding-top",
15: "padding-right",
16: "padding-bottom",
17: "padding-left",
18: "width",
19: "height",
20: "overflow-x",
21: "overflow-y",
"accentColor": "",
"additiveSymbols": "",
"alignContent": "",
"alignItems": "",
...
}
```
This method allows you to test that specific properties have been set:
```js
assert.strictEqual(helper.getStyle('body')?.width, '100%');
```
The helper attaches a `.getPropVal()` method to the style declaration object that allows you to get the value of a specific property:
```js
assert.strictEqual(helper.getStyle('body').getPropVal('width'), '100%');
```
#### `.getCSSRules()`
The `.getCSSRules()` takes an at-rule type from the union `media | fontface | import | keyframes`, and returns an array of CSS rules matching that at-rule.
For example, if the camper has written the following code:
```css
@media (max-width: 100px) {
body {
background-color: green;
}
}
```
Then the returned value of `helper.getCSSRules('media')` would be this array:
```js
[
{
conditionText: "(max-width: 100px)",
cssRules: [
selectorText: 'body',
style: CSSStyleDeclaration,
styleMap: StylePropertyMap,
cssRules: CSSRuleList,
type: 1,
...
],
cssText: "@media (max-width: 100px) {\n body { background-color: green; }\n}",
...
}
]
```
You can then test that the camper has written the correct media query:
```js
const hasCorrectHeight = helper.getCSSRules('media').some(x => x.style.height === '3px');;
assert.isTrue(hasCorrectHeight);
```
#### `.getRuleListsWithinMedia()`
The `.getRuleListsWithinMedia()` method takes a media text (e.g. `("max-width: 200")`) and returns the CSS rules within that media query.
The return result is the equivalent of that media rule's `cssRules` property from the return value of `.getCSSRules("media")`.
### Less Frequent Methods
These methods are not as commonly used, but are available if needed.
#### `.getStyleDeclarations()`
The `.getStyleDeclarations()` method takes a CSS selector and returns an array of CSS style declaration objects (from the `.getStyle()` method).
#### `.isPropertyUsed()`
The `.isPropertyUsed()` method takes a CSS **property** and checks if it has been set/used anywhere in the camper's CSS.
#### `.getStyleRule()`
The `.getStyleRule()` method takes a CSS selector and returns the CSS Style Declaration, much like `.getStyle()`. However, the declaration returned from this method includes an additional `.isDeclaredAfter()` method which takes a selector and returns whether this rule is declared after the selector passed in.
#### `.getStyleSheet()`
The `.getStyleSheet()` method returns the camper's CSS, parsed into a CSS Style Sheet object.
## Strip Content
There are a few methods on the `__helpers` object to remove content from the camper's code.
These do NOT need to be instantiated they are static methods.
### Removing Comments
Using `__helpers.removeCssComments()`, `__helpers.removeHTMLComments()`, or `__helpers.removeJSComments()` allows you to pass the camper's code (through the `code` variable) to remove comments matching the language's comment syntax.
### Removing Whitespace
Using `__helpers.removeWhitespace()` allows you to pass the camper's code (through the `code` variable) to remove all whitespace.
-979
View File
@@ -1,979 +0,0 @@
# DevOps Handbook
This guide will help you understand our infrastructure stack and how we maintain our platforms. While this guide does not have exhaustive details for all operations, it could be used as a reference for your understanding of the systems.
Let us know if you have feedback or queries and we will be happy to clarify.
## Flight Manual - Code Deployments
This repository is continuously built, tested, and deployed to **separate sets of infrastructure (Servers, Databases, CDNs, etc.)**.
This involves three steps to be followed in sequence:
1. New changes (both fixes and features) are merged into our primary development branch (`main`) via pull requests.
2. These changes are run through a series of automated tests.
3. Once the tests pass we release the changes (or update them if needed) to deployments on our infrastructure.
### Building the codebase - Mapping Git Branches to Deployments
Typically, [`main`](https://github.com/freeCodeCamp/freeCodeCamp/tree/main) (the default development branch) is merged into the [`prod-staging`](https://github.com/freeCodeCamp/freeCodeCamp/tree/prod-staging) branch once a day and is released into an isolated infrastructure.
This is an intermediate release for our developers and volunteer contributors. It is also known as our "staging" or "beta" release.
It is identical to our live production environment at `freeCodeCamp.org`, other than it using a separate set of databases, servers, web-proxies, etc. This isolation lets us test ongoing development and features in a "production" like scenario, without affecting regular users of freeCodeCamp.org's main platforms.
Once the developer team [`@freeCodeCamp/dev-team`](https://github.com/orgs/freeCodeCamp/teams/dev-team/members) is happy with the changes on the staging platform, these changes are moved every few days to the [`prod-current`](https://github.com/freeCodeCamp/freeCodeCamp/tree/prod-current) branch.
This is the final release that moves changes to our production platforms on freeCodeCamp.org.
### Testing changes - Integration and User Acceptance Testing
We employ various levels of integration and acceptance testing to check on the quality of the code. All our tests are done through software like [GitHub Actions CI](https://github.com/freeCodeCamp/freeCodeCamp/actions) and [Azure Pipelines](https://dev.azure.com/freeCodeCamp-org/freeCodeCamp).
We have unit tests for testing our challenge solutions, Server APIs, and Client User interfaces. These help us test the integration between different components.
> [!NOTE] We are also in the process of writing end user tests which will help in replicating real-world scenarios like updating an email or making a call to the API or third-party services.
Together these tests help in preventing issues from repeating themselves and ensure we do not introduce a bug while working on another bug or a feature.
### Deploying Changes - Pushing changes to servers
We have configured continuous delivery software to push changes to our development and production servers.
Once the changes are pushed to the protected release branches, a build pipeline is automatically triggered for the branch. The build pipelines are responsible for building artifacts and keeping them in a cold storage for later use.
The build pipeline goes on to trigger a corresponding release pipeline if it completes a successful run. The release pipelines are responsible for collecting the build artifacts, moving them to the servers, and going live.
The statuses of builds and releases are [available here](#build-test-and-deployment-status).
## Trigger a Build, Test, and Deploy
Currently, only members of the developer team can push to the production branches. The changes to the `production-*` branches can land only via fast-forward merge to the [`upstream`](https://github.com/freeCodeCamp/freeCodeCamp).
> [!NOTE] In the upcoming days, we would improve this flow to be done via pull requests, for better access management and transparency.
### Pushing changes to Staging Applications
1. Configure your remotes correctly.
```sh
git remote -v
```
**Results:**
```
origin git@github.com:raisedadead/freeCodeCamp.git (fetch)
origin git@github.com:raisedadead/freeCodeCamp.git (push)
upstream git@github.com:freeCodeCamp/freeCodeCamp.git (fetch)
upstream git@github.com:freeCodeCamp/freeCodeCamp.git (push)
```
2. Make sure your `main` branch is pristine and in sync with the upstream.
```sh
git checkout main
git fetch --all --prune
git reset --hard upstream/main
```
3. Check that the GitHub CI is passing on the `main` branch for upstream.
The [continuous integration](https://github.com/freeCodeCamp/freeCodeCamp/actions) tests should be green and PASSING for the `main` branch. Click the green check mark next to the commit hash when viewing the `main` branch code.
<details> <summary> Checking status on GitHub Actions (screenshot) </summary>
<br>
![Check build status on GitHub Actions](https://raw.githubusercontent.com/freeCodeCamp/freeCodeCamp/main/docs/images/devops/github-actions.png)
</details>
If this is failing you should stop and investigate the errors.
4. Confirm that you are able to build the repository locally.
```
pnpm run clean-and-develop
```
5. Move changes from `main` to `prod-staging` via a fast-forward merge
```
git checkout prod-staging
git merge main
git push upstream
```
> [!NOTE] You will not be able to force push and if you have re-written the history in any way, these commands will error out.
>
> If they do, you may have done something incorrectly and you should just start over.
The above steps will automatically trigger a run on the build pipeline for the `prod-staging` branch. Once the build is complete, the artifacts are saved as `.zip` files in a cold storage to be retrieved and used later.
The release pipeline is triggered automatically when a fresh artifact is available from the connected build pipeline. For staging platforms, this process does not involve manual approval, and the artifacts are pushed to the Client CDN and API servers.
### Pushing changes to Production Applications
The process is mostly the same as the staging platforms, with a few extra checks in place. This is just to make sure, we do not break anything on freeCodeCamp.org which can see hundreds of users using it at any moment.
| Do NOT execute these commands unless you have verified that everything is working on the staging platform. You should not bypass or skip any testing on staging before proceeding further. |
|:------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| |
1. Make sure your `prod-staging` branch is pristine and in sync with the upstream.
```sh
git checkout prod-staging
git fetch --all --prune
git reset --hard upstream/prod-staging
```
2. Move changes from `prod-staging` to `prod-current` via a fast-forward merge
```
git checkout prod-current
git merge prod-staging
git push upstream
```
> [!NOTE] You will not be able to force push and if you have re-written the history in any way, these commands will error out.
>
> If they do, you may have done something incorrectly and you should just start over.
The above steps will automatically trigger a run on the build pipeline for the `prod-current` branch. Once a build artifact is ready, it will trigger a run on the release pipeline.
**Additional Steps for Staff Action**
Once a release run is triggered, members of the developer staff team will receive an automated manual intervention email. They can either _approve_ or _reject_ the release run.
If the changes are working nicely and have been tested on the staging platform, then it can be approved. The approval must be given within 4 hours of the release being triggered before getting rejected automatically. A staff can re-trigger the release run manually for rejected runs, or wait for the next cycle of release.
For staff use:
| Check your email for a direct link or [go to the release dashboard](https://dev.azure.com/freeCodeCamp-org/freeCodeCamp/_release) after the build run is complete. |
|:------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| |
Once one of the staff members approves a release, the pipeline will push the changes live to freeCodeCamp.org's production CDN and API servers.
## Build, Test and Deployment Status
Here is the current test, build and deployment status of the codebase.
| Branch | Unit Tests | Integration Tests | Builds & Deployments |
|:-------------------------------------------------------------------------------- |:-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |:--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |:--------------------------------------------------------------------------------------------------------------------------------- |
| [`main`](https://github.com/freeCodeCamp/freeCodeCamp/tree/main) | [![Node.js CI](https://github.com/freeCodeCamp/freeCodeCamp/workflows/Node.js%20CI/badge.svg?branch=main)](https://github.com/freeCodeCamp/freeCodeCamp/actions?query=workflow%3A%22Node.js+CI%22) | [![Cypress E2E 測試](https://img.shields.io/endpoint?url=https://dashboard.cypress.io/badge/simple/ke77ns/main&style=flat&logo=cypress)](https://dashboard.cypress.io/projects/ke77ns/analytics/runs-over-time) | - |
| [`prod-staging`](https://github.com/freeCodeCamp/freeCodeCamp/tree/prod-staging) | [![Node.js CI](https://github.com/freeCodeCamp/freeCodeCamp/workflows/Node.js%20CI/badge.svg?branch=prod-staging)](https://github.com/freeCodeCamp/freeCodeCamp/actions?query=workflow%3A%22Node.js+CI%22+branch%3Aprod-staging) | [![Cypress E2E 測試](https://img.shields.io/endpoint?url=https://dashboard.cypress.io/badge/simple/ke77ns/prod-staging&style=flat&logo=cypress)](https://dashboard.cypress.io/projects/ke77ns/analytics/runs-over-time) | [Azure Pipelines](https://dev.azure.com/freeCodeCamp-org/freeCodeCamp/_dashboards/dashboard/d59f36b9-434a-482d-8dbd-d006b71713d4) |
| [`prod-current`](https://github.com/freeCodeCamp/freeCodeCamp/tree/prod-current) | [![Node.js CI](https://github.com/freeCodeCamp/freeCodeCamp/workflows/Node.js%20CI/badge.svg?branch=prod-current)](https://github.com/freeCodeCamp/freeCodeCamp/actions?query=workflow%3A%22Node.js+CI%22+branch%3Aprod-current) | [![Cypress E2E 測試](https://img.shields.io/endpoint?url=https://dashboard.cypress.io/badge/simple/ke77ns/prod-current&style=flat&logo=cypress)](https://dashboard.cypress.io/projects/ke77ns/analytics/runs-over-time) | [Azure Pipelines](https://dev.azure.com/freeCodeCamp-org/freeCodeCamp/_dashboards/dashboard/d59f36b9-434a-482d-8dbd-d006b71713d4) |
| `prod-next` (experimental, upcoming) | - | - | - |
## Early Access and Beta Testing
We welcome you to test these releases in a **"public beta testing"** mode and get early access to upcoming features to the platforms. Sometimes these features/changes are referred to as **next, beta, staging,** etc. interchangeably.
Your contributions via feedback and issue reports will help us in making the production platforms at `freeCodeCamp.org` more **resilient**, **consistent**, and **stable** for everyone.
We thank you for reporting bugs that you encounter and help in making freeCodeCamp.org better. You rock!
### Identifying the Upcoming Version of the Platforms
Currently, a public beta testing version is available at:
| Application | Language | URL |
|:----------- |:-------- |:---------------------------------------- |
| Learn | English | <https://www.freecodecamp.dev> |
| | Espanol | <https://www.freecodecamp.dev/espanol> |
| | Chinese | <https://www.freecodecamp.dev/chinese> |
| News | English | <https://www.freecodecamp.dev/news> |
| Forum | English | <https://forum.freecodecamp.dev> |
| | Chinese | <https://freecodecamp.dev/chinese/forum> |
| API | - | `https://api.freecodecamp.dev` |
> [!NOTE] The domain name is different than **`freeCodeCamp.org`**. This is intentional to prevent search engine indexing and avoid confusion for regular users of the platform.
>
> The above list is not exhaustive of all the applications that we provision. Also, not all language variants are deployed in staging to conserve resources.
### Identifying the Current Version of the Platforms
**The current version of the platform is always available at [`freeCodeCamp.org`](https://www.freecodecamp.org).**
The dev-team merges changes from the `prod-staging` branch to `prod-current` when they release changes. The top commit should be what you see live on the site.
You can identify the exact version deployed by visiting the build and deployment logs available in the status section. Alternatively, you can also ping us in the [contributors chat room](https://discord.gg/PRyKn3Vbay) for a confirmation.
### Known Limitations
There are some known limitations and tradeoffs when using the beta version of the platform.
- **All data / personal progress on these beta platforms will NOT be saved or carried over to production**
**Users on the beta version will have a separate account from the production.** The beta version uses a physically separate database from production. This gives us the ability to prevent any accidental loss of data or modifications. The dev-team may purge the database on this beta version as needed.
- **The beta platforms do not provide any assurances regarding uptime and reliability**
Deployment is expected to be frequent and in rapid iterations, sometimes multiple times a day. As a result, there will be unexpected downtime at times or broken functionality on the beta version.
- **To ensure the effectiveness of the fix, it is advised not to direct regular users to this site for verification purposes.**
The beta site is and always has been to augment local development and testing, nothing else. It's not a promise of what’s coming, but a glimpse of what is being worked upon.
- **Sign in page may look different than production**
We use a test tenant for freeCodeCamp.dev on Auth0, and hence do not have the ability to set a custom domain. This makes it so that all the redirect callbacks and the login page appear at a default domain like: `https://freecodecamp-dev.auth0.com/`. This does not affect the functionality and is as close to production as we can get.
## Reporting issues and leaving feedback
Please open fresh issues for discussions and reporting bugs.
You may send an email to `dev[at]freecodecamp.org` if you have any queries. As always all security vulnerabilities should be reported to `security[at]freecodecamp.org` instead of the public tracker and forum.
## Flight Manual - Server Maintenance
> [!WARNING]
>
> 1. The guide applies to the **freeCodeCamp Staff members only**.
> 2. These instructions should not be considered exhaustive, please use caution.
As a member of the staff, you may have been given access to our cloud service providers like Azure, Digital Ocean, etc.
Here are some handy commands that you can use to work on the Virtual Machines (VM), for instance performing maintenance updates or doing general housekeeping.
## Get a list of the VMs
> [!NOTE] While you may already have SSH access to the VMs, that alone will not let you list VMs unless you have been granted access to the cloud portals as well.
### Azure
Install Azure CLI `az`: https://docs.microsoft.com/en-us/cli/azure/install-azure-cli
> **(One-time) Install on macOS with [`homebrew`](https://brew.sh):**
```
brew install azure-cli
```
> **(One-time) Login:**
```
az login
```
> **Get the list of VM names and IP addresses:**
```
az vm list-ip-addresses --output table
```
### Digital Ocean
Install Digital Ocean CLI `doctl`: https://github.com/digitalocean/doctl#installing-doctl
> **(One-time) Install on macOS with [`homebrew`](https://brew.sh):**
```
brew install doctl
```
> **(One-time) Login:**
Authentication and context switching: https://github.com/digitalocean/doctl#authenticating-with-digitalocean
```
doctl auth init
```
> **Get the list of VM names and IP addresses:**
```
doctl compute droplet list --format "ID,Name,PublicIPv4"
```
## Spin New Resources
We are working on creating our IaC setup, and while that is in works you can use the Azure portal or the Azure CLI to spin new virtual machines and other resources.
> [!TIP] No matter your choice of spinning resources, we have a few [handy cloud-init config files](https://github.com/freeCodeCamp/infra/tree/main/cloud-init) to help you do some of the basic provisioning like installing docker or adding SSH keys, etc.
## Keep VMs Updated
You should keep the VMs up to date by performing updates and upgrades. This will ensure that the virtual machine is patched with the latest security fixes.
> [!WARNING] Before you run these commands:
>
> - Make sure that the VM has been provisioned completely and that there are no post-install steps running.
> - If you are updating packages on a VM that is already serving an application, make sure the app has been stopped / saved. Package updates will cause network bandwidth, memory and/or CPU usage spikes leading to outages on running applications.
Update package information
```bash
sudo apt update
```
Upgrade installed packages
```bash
sudo apt upgrade -y
```
Cleanup unused packages
```bash
sudo apt autoremove -y
```
## Work on Web Servers (Proxy)
We are running load balanced (Azure Load Balancer) instances for our web servers. These servers are running NGINX which reverse proxy all of the traffic to freeCodeCamp.org from various applications running on their own infrastructures.
The NGINX config is available on [this repository](https://github.com/freeCodeCamp/nginx-config).
### First Install
Provisioning VMs with the Code
1. Install NGINX and configure from repository.
```bash
sudo su
cd /var/www/html
git clone https://github.com/freeCodeCamp/error-pages
cd /etc/
rm -rf nginx
git clone https://github.com/freeCodeCamp/nginx-config nginx
cd /etc/nginx
```
2. Install Cloudflare origin certificates and upstream application config.
Get the Cloudflare origin certificates from the secure storage and install at required locations.
**OR**
Move over existing certificates:
```bash
# Local
scp -r username@source-server-public-ip:/etc/nginx/ssl ./
scp -pr ./ssl username@target-server-public-ip:/tmp/
# Remote
rm -rf ./ssl
mv /tmp/ssl ./
```
Update Upstream Configurations:
```bash
vi configs/upstreams.conf
```
Add/update the source/origin application IP addresses.
3. Set up networking and firewalls.
Configure Azure firewalls and `ufw` as needed for ingress origin addresses.
4. Add the VM to the load balancer backend pool.
Configure and add rules to load balancer if needed. You may also need to add the VMs to load balancer backend pool if needed.
### Logging and Monitoring
1. Check status for NGINX service using the below command:
```bash
sudo systemctl status nginx
```
2. Logging and monitoring for the servers are available at:
NGINX Amplify: [https://amplify.nginx.com]('https://amplify.nginx.com'), our current basic monitoring dashboard. We are working on more granular metrics for better observability
### Updating Instances (Maintenance)
Config changes to our NGINX instances are maintained on GitHub, these should be deployed on each instance like so:
1. SSH into the instance and enter sudo
```bash
sudo su
```
2. Get the latest config code.
```bash
cd /etc/nginx
git fetch --all --prune
git reset --hard origin/main
```
3. Test and reload the config [with Signals](https://docs.nginx.com/nginx/admin-guide/basic-functionality/runtime-control/#controlling-nginx).
```bash
nginx -t
nginx -s reload
```
## Work on API Instances
1. Install build tools for node binaries (`node-gyp`) etc.
```bash
sudo apt install build-essential
```
### First Install
Provisioning VMs with the Code
1. Install Node LTS.
2. Install pnpm globally.
```bash
npm install -g pnpm
```
3. Install pm2 globally.
```bash
npm install -g pm2
```
4. Clone freeCodeCamp, set up env, and keys.
```bash
git clone https://github.com/freeCodeCamp/freeCodeCamp.git
cd freeCodeCamp
git checkout prod-current # or any other branch to be deployed
```
5. Create the `.env` from the secure credentials storage.
6. Install dependencies
```bash
pnpm install
```
7. Setup pm2 `logrotate` and startup on boot
```bash
pm2 install pm2-logrotate
pm2 startup
```
8. Build the server
```bash
pnpm prebuild && pnpm build:curriculum && pnpm build:server
```
9. Start Instances
```bash
pnpm start:server
```
### Logging and Monitoring
```bash
pm2 logs
```
```bash
pm2 monit
```
### Updating Instances (Maintenance)
Code changes need to be deployed to the API instances from time to time. It can be a rolling update or a manual update. The latter is essential when changing dependencies or adding environment variables.
> [!ATTENTION] The automated pipelines are not handling dependencies updates at the minute. We need to do a manual update before any deployment pipeline runs.
#### 1. Manual Updates - Used for updating dependencies, env variables.
1. Stop all instances
```bash
pm2 stop all
```
2. Install dependencies
```bash
pnpm install
```
3. Build the server
```bash
pnpm prebuild && pnpm build:curriculum && pnpm build:server
```
4. Start Instances
```bash
pnpm start:server && pm2 logs
```
#### 2. Rolling updates - Used for logical changes to code.
```bash
pnpm reload:server && pm2 logs
```
> [!NOTE] We are handling rolling updates to code and logic via pipelines. You should not need to run these commands. These are here for documentation.
#### 3. Updating Node
1. Install new Node version
2. Update pm2 to use the new version
```bash
pm2 update
```
## Work on Client Instances
1. Install build tools for node binaries (`node-gyp`) etc.
```bash
sudo apt install build-essential
```
### First Install
Provisioning VMs with the Code
1. Install Node LTS.
2. Update `npm` and install PM2 and setup `logrotate` and startup on boot
```bash
npm i -g npm@8
npm i -g pm2@4
npm install -g serve@13
pm2 install pm2-logrotate
pm2 startup
```
3. Clone client config, setup env and keys.
```bash
git clone https://github.com/freeCodeCamp/client-config.git client
cd client
```
Start placeholder instances for the web client, these will be updated with artifacts from the Azure pipeline.
> Todo: This setup needs to move to S3 or Azure Blob storage
>
> ```bash
> echo "serve -c ../serve.json -p 50505 www" > client-start-primary.sh
> chmod +x client-start-primary.sh
> pm2 delete client-primary
> pm2 start ./client-start-primary.sh --name client-primary
> echo "serve -c ../serve.json -p 52525 www" > client-start-secondary.sh
> chmod +x client-start-secondary.sh
> pm2 delete client-secondary
> pm2 start ./client-start-secondary.sh --name client-secondary
> ```
### Logging and Monitoring
```bash
pm2 logs
```
```bash
pm2 monit
```
### Updating Instances (Maintenance)
Code changes need to be deployed to the API instances from time to time. It can be a rolling update or a manual update. The later is essential when changing dependencies or adding environment variables.
> [!ATTENTION] The automated pipelines are not handling dependencies updates at the minute. We need to do a manual update before any deployment pipeline runs.
#### 1. Manual Updates - Used for updating dependencies, env variables.
1. Stop all instances
```bash
pm2 stop all
```
2. Install or update dependencies
3. Start Instances
```bash
pm2 start all --update-env && pm2 logs
```
#### 2. Rolling updates - Used for logical changes to code.
```bash
pm2 reload all --update-env && pm2 logs
```
> [!NOTE] We are handling rolling updates to code, logic, via pipelines. You should not need to run these commands. These are here for documentation.
## Work on Chat Servers
Our chat servers are available with a HA configuration [recommended in Rocket.Chat docs](https://docs.rocket.chat/installation/docker-containers/high-availability-install). The `docker-compose` file for this is [available here](https://github.com/freeCodeCamp/chat-config).
We provision redundant NGINX instances which are themselves load balanced (Azure Load Balancer) in front of the Rocket.Chat cluster. The NGINX configuration file are [available here](https://github.com/freeCodeCamp/chat-nginx-config).
### First Install
Provisioning VMs with the Code
**NGINX Cluster:**
1. Install NGINX and configure from repository.
```bash
sudo su
cd /var/www/html
git clone https://github.com/freeCodeCamp/error-pages
cd /etc/
rm -rf nginx
git clone https://github.com/freeCodeCamp/chat-nginx-config nginx
cd /etc/nginx
```
2. Install Cloudflare origin certificates and upstream application config.
Get the Cloudflare origin certificates from the secure storage and install at required locations.
**OR**
Move over existing certificates:
```bash
# Local
scp -r username@source-server-public-ip:/etc/nginx/ssl ./
scp -pr ./ssl username@target-server-public-ip:/tmp/
# Remote
rm -rf ./ssl
mv /tmp/ssl ./
```
Update Upstream Configurations:
```bash
vi configs/upstreams.conf
```
Add/update the source/origin application IP addresses.
3. Set up networking and firewalls.
Configure Azure firewalls and `ufw` as needed for ingress origin addresses.
4. Add the VM to the load balancer backend pool.
Configure and add rules to load balancer if needed. You may also need to add the VMs to load balancer backend pool if needed.
**Docker Cluster:**
1. Install Docker and configure from the repository
```bash
git clone https://github.com/freeCodeCamp/chat-config.git chat
cd chat
```
2. Configure the required environment variables and instance IP addresses.
3. Run rocket-chat server
```bash
docker-compose config
docker-compose up -d
```
### Logging and Monitoring
1. Check status for NGINX service using the below command:
```bash
sudo systemctl status nginx
```
2. Check status for running docker instances with:
```bash
docker ps
```
### Updating Instances (Maintenance)
**NGINX Cluster:**
Config changes to our NGINX instances are maintained on GitHub, these should be deployed on each instance like so:
1. SSH into the instance and enter sudo
```bash
sudo su
```
2. Get the latest config code.
```bash
cd /etc/nginx
git fetch --all --prune
git reset --hard origin/main
```
3. Test and reload the config [with Signals](https://docs.nginx.com/nginx/admin-guide/basic-functionality/runtime-control/#controlling-nginx).
```bash
nginx -t
nginx -s reload
```
**Docker Cluster:**
1. SSH into the instance and navigate to the chat config path
```bash
cd ~/chat
```
2. Get the latest config code.
```bash
git fetch --all --prune
git reset --hard origin/main
```
3. Pull down the latest docker image for Rocket.Chat
```bash
docker-compose pull
```
4. Update the running instances
```bash
docker-compose up -d
```
5. Validate the instances are up
```bash
docker ps
```
6. Cleanup extraneous resources
```bash
docker system prune --volumes
```
Output:
```bash
WARNING! This will remove:
- all stopped containers
- all networks not used by at least one container
- all volumes not used by at least one container
- all dangling images
- all dangling build cache
Are you sure you want to continue? [y/N] y
```
Select yes (y) to remove everything that is not in use. This will remove all stopped containers, all networks and volumes not used by at least one container, and all dangling images and build caches.
## Work on Contributor Tools
### Deploy Updates
ssh into the VM (hosted on Digital Ocean).
```bash
cd tools
git pull origin master
pnpm install
pnpm run build
pm2 restart contribute-app
```
## Updating Node.js Versions on VMs
List currently installed node & npm versions
```bash
nvm -v
node -v
npm -v
nvm ls
```
Install the latest Node.js LTS, and reinstall any global packages
```bash
nvm install --lts --reinstall-packages-from=default
```
Verify installed packages
```bash
npm ls -g --depth=0
```
Alias the `default` Node.js version to the current LTS (pinned to the latest major version)
```bash
nvm alias default 16
```
(Optional) Uninstall old versions
```bash
nvm uninstall <version>
```
> [!ATTENTION] For client applications, the shell script can't be resurrected between Node.js versions with `pm2 resurrect`. Deploy processes from scratch instead. This should become nicer when we move to a docker-based setup.
>
> If using PM2 for processes you would also need to bring up the applications and save the process list for automatic recovery on restarts.
Get the uninstall instructions/commands with the `unstartup` command and use the output to remove the systemctl services
```bash
pm2 unstartup
```
Get the install instructions/commands with the `startup` command and use the output to add the systemctl services
```bash
pm2 startup
```
Quick commands for PM2 to list, resurrect saved processes, etc.
```bash
pm2 ls
```
```bash
pm2 resurrect
```
```bash
pm2 save
```
```bash
pm2 logs
```
## Installing and Updating Azure Pipeline Agents
See: https://docs.microsoft.com/en-us/azure/devops/pipelines/agents/v2-linux?view=azure-devops and follow the instructions to stop, remove, and reinstall agents. Broadly you can follow the steps listed here.
You would need a PAT, that you can grab from here: https://dev.azure.com/freeCodeCamp-org/_usersSettings/tokens
### Installing Agents on Deployment targets
Navigate to [Azure Devops](https://dev.azure.com/freeCodeCamp-org) and register the agent from scratch in the requisite [deployment groups](https://dev.azure.com/freeCodeCamp-org/freeCodeCamp/_machinegroup).
> [!NOTE] 你應該在主目錄運行腳本,並確保沒有其他 `azagent` 目錄存在。
### Updating Agents
Currently updating agents requires them to be removed and reconfigured. This is required for them to correctly pick up `PATH` values and other system environment variables. 例如,我們需要在部署目標虛擬機上更新 Node.js 時這樣做。
1. Navigate and check status of the service
```bash
cd ~/azagent
sudo ./svc.sh status
```
2. Stop the service
```bash
sudo ./svc.sh stop
```
3. Uninstall the service
```bash
sudo ./svc.sh uninstall
```
4. Remove the agent from the pipeline pool
```bash
./config.sh remove
```
5. Remove the config files
```bash
cd ~
rm -rf ~/azagent
```
Once You have completed the steps above, you can repeat the same steps as installing the agent.
## Flight Manual - Email Blast
We use [a CLI tool](https://github.com/freecodecamp/sendgrid-email-blast) to send out the weekly newsletter. To spin this up and begin the process:
1. Sign in to DigitalOcean, and spin up new droplets under the `Sendgrid` project. Use the Ubuntu Sendgrid snapshot with the most recent date. This comes pre-loaded with the CLI tool and the script to fetch emails from the database. With the current volume, three droplets are sufficient to send the emails in a timely manner.
2. Set up the script to fetch the email list.
```bash
cd /home/freecodecamp/scripts/emails
cp sample.env .env
```
You will need to replace the placeholder values in the `.env` file with your credentials.
3. Run the script.
```bash
node get-emails.js emails.csv
```
This will save the email list in an `emails.csv` file.
4. Break the emails down into multiple files, depending on the number of droplets you need. This is easiest to do by using `scp` to pull the email list locally and using your preferred text editor to split them into multiple files. Each file will need the `email,unsubscribeId` header.
5. Switch to the CLI directory with `cd /home/sendgrid-email-blast` and configure the tool [per the documentation](https://github.com/freeCodeCamp/sendgrid-email-blast/blob/main/README.md).
6. Run the tool to send the emails, following the [usage documentation](https://github.com/freeCodeCamp/sendgrid-email-blast/blob/main/docs/cli-steps.md).
7. When the email blast is complete, verify that no emails have failed before destroying the droplets.
## Flight Manual - Adding news instances for new languages
### Theme Changes
We use a custom [theme](https://github.com/freeCodeCamp/news-theme) for our news publication. Adding the following changes to the theme enables the addition of new languages.
1. Include an `else if` statement for the new [ISO language code](https://www.loc.gov/standards/iso639-2/php/code_list.php) in [`setup-locale.js`](https://github.com/freeCodeCamp/news-theme/blob/main/assets/config/setup-locale.js)
2. Create an initial config folder by duplicating the [`assets/config/en`](https://github.com/freeCodeCamp/news-theme/tree/main/assets/config/en) folder and changing its name to the new language code. (`en` —> `es` for Spanish)
3. Inside the new language folder, change the variable names in `main.js` and `footer.js` to the relevant language short code (`enMain` —> `esMain` for Spanish)
4. Duplicate the [`locales/en.json`](https://github.com/freeCodeCamp/news-theme/blob/main/locales/en.json) and rename it to the new language code.
5. In [`partials/i18n.hbs`](https://github.com/freeCodeCamp/news-theme/blob/main/partials/i18n.hbs), add scripts for the newly created config files.
6. Add the related language `day.js` script from [cdnjs](https://cdnjs.com/libraries/dayjs/1.10.4) to the [freeCodeCamp CDN](https://github.com/freeCodeCamp/cdn/tree/main/build/news-assets/dayjs/1.10.4/locale)
### Ghost Dashboard Changes
Update the publication assets by going to the Ghost dashboard > settings > general and uploading the publications's [icon](https://github.com/freeCodeCamp/design-style-guide/blob/master/assets/fcc-puck-500-favicon.png), [logo](https://github.com/freeCodeCamp/design-style-guide/blob/master/downloads/fcc_primary_large.png), and [cover](https://github.com/freeCodeCamp/design-style-guide/blob/master/assets/fcc_ghost_publication_cover.png).
@@ -1,119 +0,0 @@
# How to add Cypress tests
When making changes to JavaScript, CSS, or HTML which could change the functionality or layout of a page, it's important to add corresponding [Cypress](https://docs.cypress.io) integration tests.
To learn how to write Cypress tests, or 'specs', please see Cypress' official [documentation](https://docs.cypress.io/guides/getting-started/writing-your-first-test.html).
## Where to Add a Test
- Cypress tests are in the `./cypress` directory.
- Cypress tests for a curriculum module are in the corresponding curriculum directory, i.e. `cypress/integration/learn/responsive-web-design/basic-css/index.js`.
## How to Run Tests
> [!NOTE] If using Gitpod, please see [Cypress-Gitpod Setup](how-to-add-cypress-tests.md#cypress-gitpod-setup)
### 1. Ensure that MongoDB and Client Applications are Running
- [Start MongoDB and seed the database](how-to-setup-freecodecamp-locally.md#step-3-start-mongodb-and-seed-the-database)
- [Start the freeCodeCamp client application and API server](how-to-setup-freecodecamp-locally.md#step-4-start-the-freecodecamp-client-application-and-api-server)
### 2. Run the Cypress Tests
To run tests against production builds, replace `dev` with `prd` below.
- To run all tests in the `./cypress` directory:
```bash
pnpm run cypress:dev:run
```
- To run a single test:
```bash
pnpm run cypress run --spec=cypress/<path_to_test_file>
```
For example:
```bash
pnpm run cypress run --spec=cypress/e2e/default/landing.ts
```
- To create a development build, start the development server, and run all existing cypress end-to-end tests:
```bash
pnpm run e2e:dev:run
```
## Cypress-Gitpod Setup
### 1. Ensure Development Environment is Running
If starting the Gitpod environment did not automatically develop the environment:
- Follow the [MongoDB installation guide](https://www.mongodb.com/basics/get-started).
- Create a config file.
```bash
pnpm run create:shared
```
- Seed the database
```bash
pnpm run seed
```
- Develop the server and client
```bash
pnpm run develop
```
### 2. Install Cypress Build Tools
```bash
pnpm run cypress:install-build-tools
```
- When prompted in the terminal, select your keyboard layout by language/area
Now, [Cypress can be run](how-to-add-cypress-tests.md#_2-run-the-cypress-tests)
## Troubleshooting
### Unable to Connect to Port 8000
If Cypress fails to run with the following error:
```
CypressError: `cy.visit()` failed trying to load:
http://localhost:3000/signin
We attempted to make an http request to this URL but the request failed without a response.
We received this error at the network level:
> Error: connect ECONNREFUSED 127.0.0.1:8000
Common situations why this would fail:
- you don't have internet access
- you forgot to run / boot your web server
- your web server isn't accessible
- you have weird network configuration settings on your computer
This error occurred while creating the session. Because the session setup failed, we failed the test.
```
You can resolve the issue by:
- Going to the root `package.json` file and adding `--host 0.0.0.0` to the `develop:client` command:
```json
"scripts": {
"develop:client": "cd ./client && pnpm run develop --host 0.0.0.0"
}
```
- Then, re-running `pnpm run develop`
@@ -1,345 +0,0 @@
# How to add Playwright tests
## Installation
To install Playwright run:
```bash
pnpm run playwright:install-build-tools
```
Alternatively you can follow official documentation referenced below:
To install and configure Playwright on your machine check out this [documentation](https://playwright.dev/docs/intro#installing-playwright).
To learn how to write Playwright tests, or 'specs', please see Playwright's official [documentation](https://playwright.dev/docs/writing-tests).
## Where to Add a Test
- Playwright tests are in the `./e2e` directory.
- Playwright test files are always with a `.spec.ts` extension.
## Best Practices for writing E2E tests
This section will explain in detail about best practices for writing and documenting E2E tests based on Playwright documentation and our community code-style.
### - Imports
Always start with necessary imports at the beginning of the file.
For example:
```ts
import { test, expect, type Page } from '@playwright/test';
```
### - Identifying a DOM element
Playwright comes with [multiple built-in locators](https://playwright.dev/docs/locators#quick-guide), but we recommend prioritizing the following locators:
- `getByRole` for querying semantic elements, whose role is important and allows assistive technology to perceive the page correctly.
- `getByText` for querying non-semantic elements such as `div`, `span`, or `p`.
For example:
```ts
await expect(page.getByRole('heading', { name: 'Sign up' })).toBeVisible();
await expect(page.getByText('Hello World')).toBeVisible();
```
In cases where the elements cannot be queried using the above-mentioned locators, you can use the `data-playwright-test-label` attribute as the last resort. This attribute is used to identify elements in the DOM for testing with playwright only. It is not used for styling or any other purpose.
For example:
```html
<div data-playwright-test-label="landing-page-figure">
<img src="..." alt="..." />
</div>
```
In the test file, you can use the `getByTestId` method to identify the element.
For example:
```ts
await expect(page.getByTestId('landing-page-figure')).toBeVisible();
```
### - Constants
Define any constant elements, data sets, or configurations used throughout your tests for easy reference.
For example:
```ts
const landingPageElements = { ... };
const superBlocks = [ ... ];
```
### - Shared Context
If tests depend on a shared context (like a loaded web page), use beforeAll and afterAll hooks to set up and tear down that context.
For example:
```ts
let page: Page;
beforeAll(async ({ browser }) => {
page = await browser.newPage();
});
afterAll(async () => {
await page.close();
});
```
### - Descriptive test names
Each test block should have a clear and concise name describing exactly what it's testing.
For example:
```ts
test('The component landing-top renders correctly', async ({ page }) => {
// ...
});
```
### - Human readable assertions
Each assertion should be as human readable as possible. This makes it easier to understand what the test is doing and what it's expecting.
For example:
```ts
await expect(landingHeading1).toHaveText('Learn to code — for free.');
```
### - Keep it DRY
Make sure that the tests are not repeating the same code over and over again. If you find yourself repeating the same code, consider refactoring it as a loop or a function.
For example:
```ts
for (const logo of await logos.all()) {
await expect(logo).toBeVisible();
}
```
### - Tests for mobile screens
Use the `isMobile` argument to run tests that include logic that varies for mobile screens.
For example:
```ts
test('The campers landing page figure is visible on desktop and hidden on mobile view', async ({
isMobile
}) => {
const landingPageImage = page.getByTestId('landing-page-figure');
if (isMobile) {
await expect(landingPageImage).toBeHidden();
} else {
await expect(landingPageImage).toBeVisible();
}
});
```
### - Group related tests
Group related tests together using describe blocks. This makes it easier to understand what the tests are doing and what they're testing.
For example:
```ts
describe('The campers landing page', () => {
test('The campers landing page figure is visible on desktop and hidden on mobile view', async ({
isMobile
}) => {
// ...
});
test('The campers landing page figure has the correct image', async () => {
// ...
});
});
```
## How to Run Tests
### 1. Ensure that MongoDB and Client Applications are Running
- [Start MongoDB and seed the database](how-to-setup-freecodecamp-locally.md#step-3-start-mongodb-and-seed-the-database). In order for Playwright tests to work, be sure that you use the `pnpm run seed:certified-user` command.
- [Start the freeCodeCamp client application and API server](how-to-setup-freecodecamp-locally.md#step-4-start-the-freecodecamp-client-application-and-api-server)
### 2. Run the Playwright Tests
To run tests with Playwright check the following below
- Make sure you navigate to the e2e repo first
```bash
cd e2e
```
- To run tests in UI helper mode:
```bash
npx playwright test --ui
```
- To run a single test:
```bash
npx playwright test <filename>
```
For example:
```bash
npx playwright test landing-page.spec.ts
```
- Run a set of test files in respective folders:
```bash
npx playwright test <pathToFolder1> <pathToFolder2>
```
For example:
```bash
npx playwright test tests/todo-page/ tests/landing-page/
```
- Run the test with the title:
```bash
npx playwright test -g <title>
```
For example:
```bash
npx playwright test -g "add a todo item"
```
### 3. Debugging Tests
Since Playwright runs in Node.js, you can debug it with your debugger of choice e.g. using console.log or inside your IDE
- Debugging all tests:
```bash
npx playwright test --debug
```
- Debugging one test file:
```bash
npx playwright test example.spec.ts --debug
```
### 4. Generate Test Reports
The HTML Reporter shows you a full report of your tests allowing you to filter the report by browsers, passed tests, failed tests, skipped tests and flaky tests.
```bash
npx playwright show-report
```
### 5. Troubleshooting
Playwright is generally a solid bullet-proof tool. The contributor has already configured the tests to run on all OS machines, including major distributions of Windows, MacOS and Linux.
- (MacOs and Linux) If running Playwright results in an error due to kernel dependencies, run the following command:
```bash
pnpm run playwright:install-build-tools-linux
```
- A common error seen in playwright is as follows:
```bash
Error: page.goto: Could not connect: Connection refused
=========================== logs ===========================
navigating to "https://127.0.0.1:8000/", waiting until "load"
============================================================
```
You can fix the above error with the following steps:
1. **Check the URL:** Ensure that the URL you're trying to navigate to is correct and properly formatted. Make sure there are no typos in the URL.
2. **Server Status:** Check whether the server at the URL is running and accessible. You might encounter this error if the server is not running or is not accessible.
3. **Port Availability:** Verify that the port mentioned in the URL (8000 in this case) is the correct port and is available for use. Make sure no other process is already using that port.
4. **Firewall or Security Software:** Sometimes, firewall or security software can block connections to specific ports. Check your firewall settings to ensure that the port is allowed.
5. **Network Connectivity:** Ensure that your system has a working network connection and can access external resources.
- Another common error seen in playwright is as follows:
```bash
Protocol error (Network.getResponseBody): Request content was evicted from inspector cache
```
1. The network request was made using a method that does not include a response body, such as HEAD or CONNECT.
2. The network request was made over a secure (HTTPS) connection, and the response body is not available for security reasons.
3. The network request was made by a third-party resource (such as an advertisement or a tracking pixel) that is not controlled by the script.
4. The network request was made by a script that has been paused or stopped before the response was received.
**For more insights on issues visit the official documentation.**
## Playwright-Gitpod Setup
### 1. Ensure Development Environment is Running
If starting the Gitpod environment did not automatically develop the environment:
- Follow the [MongoDB installation guide](https://www.mongodb.com/basics/get-started).
- Create the .env
```bash
cp sample.env .env
```
- Create a config file.
```bash
pnpm run create:shared
```
- Seed the database
```bash
pnpm run seed:certified-user
```
- Develop the server and client
```bash
pnpm run develop
```
### 2. Install Playwright Build Tools
To install necessary dependencies for running Playwright run the following command:
```bash
pnpm run playwright:install-build-tools
```
### 3. Run the Playwright Tests on Gitpod
To run all Playwright tests, run the following command:
```bash
cd e2e
npx playwright test
```
@@ -1,111 +0,0 @@
> **注意:** 這是一個 **可選的** 步驟,並且僅在處理電子郵件工作流時需要
- [Introduction](#introduction)
- [Installing MailHog](#installing-mailhog)
- [Using MailHog](#using-mailhog)
- [Useful Links](#useful-links)
## Introduction
Some email workflows, like updating a user's email, require the back-end API server to send outgoing emails. MailHog is an alternative to using an email service provider to send actual email messages. It is a developer tool for email testing that will catch the email messages sent by your freeCodeCamp instance.
## Installing MailHog
MailHog can be installed on macOS, Windows, and Linux or used via Docker.
<details><summary>Installing MailHog with Docker</summary>
If you have Docker installed then you can use
```bash
docker run -d --name mailhog --network host --rm mailhog/mailhog
```
to start MailHog in the background and
```bash
docker stop mailhog
```
to stop it.
When the installation completes, you can start [using MailHog](#using-mailhog).
</details>
<details><summary>Installing MailHog on macOS</summary>
使用 [Homebrew](https://brew.sh/) 在 macOS 上安裝 MailHog:
```bash
brew install mailhog
brew services start mailhog
```
The above commands will start a MailHog service in the background.
安裝完成後,你可以開始[使用 MailHog](#using-mailhog)。
</details>
<details><summary>Installing MailHog on Windows</summary>
Download the latest version of MailHog from [MailHog's official repository](https://github.com/mailhog/MailHog/releases). Locate and click on the link for your Windows version (32 or 64 bit) and a `.exe` file will be downloaded to your computer.
下載完成後,單擊以打開文件。 可能會出現 Windows 防火牆通知,爲 MailHog 請求訪問權限。 一旦授予防火牆訪問權限,將打開一個標準的 Windows 命令行提示符,MailHog 將在其中運行。
通過關閉命令提示符窗口來關閉 MailHog。 To start MailHog again, click on the MailHog executable (`.exe`) file that was downloaded initially - it is not necessary to download a new MailHog installation file.
開始[使用 MailHog](#using-mailhog)。
</details>
<details><summary>Installing MailHog on Linux</summary>
首先,安裝 [Go](https://golang.org)。
在基於 Debian 的系統(如 Ubuntu 和 Linux Mint)上,運行以下命令安裝 GO。
```bash
sudo apt-get install golang
```
在基於 RPM 的系統(如 CentOS、Fedora、Red Hat Linux 等)上,運行以下命令安裝 GO。
```bash
sudo dnf install golang
```
或者,運行以下命令來安裝 GO。
```bash
sudo yum install golang
```
現在使用以下命令設置 Go 的路徑。
```bash
echo "export GOPATH=$HOME/go" >> ~/.profile
echo 'export PATH=$PATH:/usr/local/go/bin:$GOPATH/bin' >> ~/.profile
source ~/.profile
```
最後,輸入以下命令來安裝和運行 MailHog。
```bash
go get github.com/mailhog/MailHog
sudo cp /home/$(whoami)/go/bin/MailHog /usr/local/bin/mailhog
mailhog
```
開始[使用 MailHog](#using-mailhog)。
</details>
## Using MailHog
Open a new browser tab or window and navigate to [http://localhost:8025](http://localhost:8025) to open your MailHog inbox when the MailHog installation has been completed and MailHog is running.
## Useful Links
- Check out the [MailHog](https://github.com/mailhog/MailHog) repository for further information related to MailHog. Additional information is also available regarding custom MailHog configurations.
@@ -1,216 +0,0 @@
Follow these guidelines to contribute to the codebase. This is highly recommended if you want to contribute regularly.
Ignoring these steps may soil your copy which makes the contributing, maintaining, and reviewing processes difficult.
## Contributing to the Codebase
You can now make changes to files and commit your changes to your fork, which you can prepare by reading [how to set up freeCodeCamp locally](how-to-setup-freecodecamp-locally.md).
Follow these steps:
1. Validate that you are on the `main` branch:
```bash
git status
```
You should get an output like this:
```bash
On branch main
Your branch is up-to-date with 'origin/main'.
nothing to commit, working directory clean
```
If you got a different message, then you aren't on main or your working directory isn't clean, resolve any outstanding files/commits and checkout `main`:
```bash
git checkout main
```
2. Sync the latest changes from the freeCodeCamp upstream `main` branch to your `main` fork branch:
> [!WARNING] If you have any outstanding pull requests that you made from the `main` branch of your fork, you will lose them at the end of this step.
>
> You should ensure your pull request is merged by a moderator before performing this step. To avoid this scenario, you should **always** work on a branch other than the `main`.
This step **will sync the latest changes** from the main repository of freeCodeCamp.
Update your copy of the freeCodeCamp upstream repository:
```bash
git fetch upstream
```
Hard reset your main branch with the freeCodeCamp main:
```bash
git reset --hard upstream/main
```
Push your main branch to your origin to have a clean history on your fork on GitHub:
```bash
git push origin main --force
```
You can validate that your current main matches the upstream/main by performing a diff:
```bash
git diff upstream/main
```
The resulting output should be empty. This process is important, because you will be rebasing your branch on top of the latest `upstream/main` as often as possible to avoid conflicts later.
3. Create a fresh new branch:
Working on a separate branch for each issue helps you keep your work copy clean. You should never work on the `main`. This will soil your copy of freeCodeCamp and you may have to start over with a fresh clone or fork.
Check that you are on `main` as explained previously, and branch off from there:
```bash
git checkout -b fix/update-guide-for-xyz
```
Your branch name should start with a `fix/`, `feat/`, `docs/`, etc. Avoid using issue numbers in branches. Keep them short, meaningful and unique.
Some examples of good branch names are:
```md
fix/update-challenges-for-react
fix/update-guide-for-html-css
fix/platform-bug-sign-in-issues
feat/add-guide-article-for-javascript
translate/add-spanish-basic-html
```
4. Edit pages and work on code in your favorite text editor.
5. Once you are happy with the changes you should optionally run freeCodeCamp to preview the changes.
6. Make sure you fix any errors and check the formatting of your changes.
7. Check and confirm the files you are updating:
```bash
git status
```
This should show a list of `unstaged` files that you have edited.
```bash
On branch feat/documentation
Your branch is up to date with 'upstream/feat/documentation'.
Changes were not staged for commit:
(use "git add/rm <file>..." to update what will be committed)
(use "git checkout -- <file>..." to discard changes in the working directory)
modified: CONTRIBUTING.md
modified: docs/README.md
modified: docs/how-to-setup-freecodecamp-locally.md
modified: docs/how-to-work-on-guide-articles.md
...
```
8. Stage the changes and make a commit:
In this step, you should only mark files that you have edited or added yourself. You can perform a reset and resolve files that you did not intend to change if needed.
```bash
git add path/to/my/changed/file.ext
```
Or you can add all the `unstaged` files to the staging area:
```bash
git add .
```
Only the files that were moved to the staging area will be added when you make a commit.
```bash
git status
```
Output:
```bash
On branch feat/documentation
Your branch is up to date with 'upstream/feat/documentation'.
Changes to be committed:
(use "git reset HEAD <file>..." to unstage)
modified: CONTRIBUTING.md
modified: docs/README.md
modified: docs/how-to-setup-freecodecamp-locally.md
modified: docs/how-to-work-on-guide-articles.md
```
Now, you can commit your changes with a short message like so:
```bash
git commit -m "fix: my short commit message"
```
Some examples:
```md
fix: add test for JavaScript - for loop step
feat: add link for article for alexa skills
```
Make a conventional commit message. This is a good practice as a developer, and you will be following standard practices.
Some examples of conventional commit messages are:
```md
fix: improve HTML step
fix: fix build scripts for Travis-CI
feat: add link to JavaScript hoisting article
docs: update contributing guidelines
```
Keep these short, not more than 50 characters. You can always add additional information in the description of the commit message.
This does not take any more time than an unconventional message like 'update file' or 'add index.md'
You can learn more about why you should use conventional commits [here](https://www.conventionalcommits.org/en/v1.0.0-beta.2/#why-use-conventional-commits).
9. If you realize that you need to edit a file or update the commit message after making a commit you can do so after editing the files with:
```bash
git commit --amend
```
This will open up a default text editor like `nano` or `vi` where you can edit the commit message title and add/edit the description.
10. Next, you can push your changes to your fork:
```bash
git push origin branch/name-here
```
## Proposing a Pull Request (PR)
After you've committed your changes, check here for [how to open a Pull Request](how-to-open-a-pull-request.md).
## Quick commands reference
A quick reference to the commands that you will need when working.
| command | description |
| ----------------------------------------------------------------- | ----------------------------------------------------------------------------------- |
| `pnpm test` | Run all JS tests in the system, including client, server, lint and challenge tests. |
| `pnpm run test-client` | Run the client test suite. |
| `pnpm run test-client -u` | Run the client test suite, updating the Jest snapshots that are out of sync. |
| `pnpm run test:curriculum` | Run the curriculum test suite. |
| `FCC_BLOCK='Basic HTML and HTML5' pnpm run test:curriculum` | Test a specific Block. |
| `FCC_SUPERBLOCK='responsive-web-design' pnpm run test:curriculum` | Test a specific SuperBlock. |
| `pnpm run test-curriculum-full-output` | Run the curriculum test suite, without bailing after the first error |
| `pnpm run test-server` | Run the server test suite. |
| `pnpm run e2e` | Run the Cypress end to end tests. |
| `pnpm run clean` | Uninstalls all dependencies and cleans up caches. |
| `pnpm run storybook` | Starts Storybook for component library development. |
@@ -1,458 +0,0 @@
# Deploying New Languages on `/learn`
To enable a new language on `/learn` (curriculum), you need to complete the following steps:
- Complete translating and approving the first 3 certifications on Crowdin. (New Responsive Web Design, JavaScript Algorithms and Data Structures, and Front End Development Libraries)
- Complete translating and approving all strings in Learn UI project on Crowdin.
- Update Crowdin settings to add a custom language code for the new language.
- Open the 1st PR to configure GitHub Actions. You need to update 2 files:
- `crowdin-download.client-ui.yml`
- `crowdin-download.curriculum.yml`
- Open the 2nd PR to add other configurations. You need to update/add the following files:
- Update `i18n.ts`
- Update `superblocks.ts`
- Update `algolia-locale-setup.ts`
- Add `links.json`
- Add `meta-tags.json`
- Add `motivation.json`
- Ask infrastructure team to spin up the VM for the new language.
- Once the VM is ready, open the 3rd PR to show the new language in the navigation menu.
We will explain each step in the following sections.
## Updating Crowdin Settings
Before you can release a new language, you will need to allow the languages to download from Crowdin. To configure that, you need to add a custom language code for your language.
In the `Curriculum` and `Learn UI` projects on Crowdin, you will need to select `Settings` > `Languages` from the sidebar. Then scroll down to `Language Mapping`, where you will see an option to add custom language codes. Add a new entry for the language you are releasing, selecting `language` as the `Placeholder` value, and entering a URL-friendly lower-case spelling of your language's name for the `Custom code`. If you aren't sure what to use, or you don't have an admin role and can't see the settings, reach out in our contributor chat and we will assist you.
## Updating Workflows for GitHub Actions
Then you need to configure the syncing between Crowdin and GitHub.
You will need to add a step to the [`crowdin-download.client-ui.yml`](https://github.com/freeCodeCamp/freeCodeCamp/blob/main/.github/workflows/crowdin-download.client-ui.yml) and [`crowdin-download.curriculum.yml`](https://github.com/freeCodeCamp/freeCodeCamp/blob/main/.github/workflows/crowdin-download.curriculum.yml). The step for these will be the same. For example, if you want to enable Dothraki downloads:
```yml
##### Download Dothraki #####
- name: Crowdin Download Dothraki Translations
uses: crowdin/github-action@master
# options: https://github.com/crowdin/github-action/blob/master/action.yml
with:
# uploads
upload_sources: false
upload_translations: false
auto_approve_imported: false
import_eq_suggestions: false
# downloads
download_translations: true
download_language: mis
skip_untranslated_files: false
export_only_approved: true
push_translations: false
# pull-request
create_pull_request: false
# global options
config: './crowdin-config.yml'
base_url: ${{ secrets.CROWDIN_BASE_URL_FCC }}
# Uncomment below to debug
# dryrun_action: true
```
Note that the `download_language` key needs to be set to the language code displayed on Crowdin.
## Enabling a Language
> [!NOTE] The above section with updating the workflows should be completed before proceeding - these need to be done in separate steps or the builds will fail.
There are a few steps to take in order to allow the codebase to build in your desired language.
First, visit the [`shared/config/i18n.ts`](https://github.com/freeCodeCamp/freeCodeCamp/blob/main/shared/config/i18n.ts) file to add the language to the list of available languages and configure the values. There are several objects here.
- `Languages`: Add the new language to `Languages` enum, similar to the others. The string value here will be used in the `.env` file to set a build language later.
- `availableLangs`: Add the new property from the `Languages` enum to both the `client` and `curriculum` arrays.
- `i18nextCodes`:這些是每種語言的 ISO 語言代碼。 You will need to add the appropriate ISO code for the language you are enabling. These do need to be unique for each language.
- `LangNames`: These are the display names for the language selector in the navigation menu.
- `LangCodes`: These are the language codes used for formatting dates and numbers. These should be Unicode CLDR codes instead of ISO codes.
- `hiddenLangs`: These languages will not be displayed in the navigation menu. This is used for languages that are not yet ready for release. Include your language in this array in the first PR and ask staff team to prepare the VM instance for your language. When the VM is ready, make another PR to remove it from the array.
- `rtlLangs`: These are languages that read from right to left.
As an example, if you wanted to enable Dothraki as a language, your `i18n.ts` objects should look like this:
```js
export enum Languages {
English = 'english',
Espanol = 'espanol',
Chinese = 'chinese',
ChineseTraditional = 'chinese-traditional',
Dothraki = 'dothraki'
}
export const availableLangs = {
client: [
Languages.English,
Languages.Espanol,
Languages.Chinese,
Languages.ChineseTraditional,
Languages.Dothraki
],
curriculum: [
Languages.English,
Languages.Espanol,
Languages.Chinese,
Languages.ChineseTraditional,
Languages.Dothraki
]
};
export const i18nextCodes = {
[Languages.English]: 'en',
[Languages.Espanol]: 'es',
[Languages.Chinese]: 'zh',
[Languages.ChineseTraditional]: 'zh-Hant',
[Languages.Dothraki]: 'mis'
};
export enum LangNames = {
[Languages.English]: 'English',
[Languages.Espanol]: 'Español',
[Languages.Chinese]: '中文(簡體字)',
[Languages.ChineseTraditional]: '中文(繁體字)',
[Languages.Dothraki]: 'Dothraki'
};
export enum LangCodes = {
[Languages.English]: 'en-US',
[Languages.Espanol]: 'es-419',
[Languages.Chinese]: 'zh',
[Languages.ChineseTraditional]: 'zh-Hant',
[Languages.Dothraki]: 'mis'
};
export const hiddenLangs = ['dothraki'];
export const rtlLangs = [''];
```
> [!NOTE] When a language has been set up in the deployment pipeline AND has a public `/learn` instance live, it can be removed from the `hiddenLangs` array and be made available to the public.
### Set Translated SuperBlocks
In the [shared/config/superblocks.ts](https://github.com/freeCodeCamp/freeCodeCamp/blob/main/shared/config/superblocks.ts) file, add the new language to the `notAuditedSuperBlocks` object. This lists all the superblocks which are not fully translated. Add an array of superblocks that have not been fully translated to it. For example:
```js
export const notAuditedSuperBlocks: NotAuditedSuperBlocks = {
...
[Languages.Dothraki]: [
SuperBlocks.DataVis,
SuperBlocks.RelationalDb,
SuperBlocks.BackEndDevApis,
SuperBlocks.QualityAssurance,
SuperBlocks.SciCompPy,
SuperBlocks.DataAnalysisPy,
SuperBlocks.InfoSec,
SuperBlocks.MachineLearningPy,
SuperBlocks.CollegeAlgebraPy,
SuperBlocks.FoundationalCSharp,
SuperBlocks.CodingInterviewPrep,
SuperBlocks.ProjectEuler,
SuperBlocks.JsAlgoDataStructNew,
SuperBlocks.TheOdinProject
]
}
```
Be sure to only add the superblocks that are **not** fully translated and approved. The translated superblocks will be calculated from this object. When a new superblock is finished being fully translated, remove it from the array for that language.
See the `SuperBlocks` enum at the beginning of the same file for the full list of superblocks.
### Configure Search
Next, open the [`client/src/utils/algolia-locale-setup.ts`](https://github.com/freeCodeCamp/freeCodeCamp/blob/main/client/src/utils/algolia-locale-setup.ts) file. This data is used for the search bar that loads `/news` articles. While it is unlikely that you are going to test this functionality, missing the data for your language can lead to errors when attempting to build the codebase locally.
Add an object for your language to the `algoliaIndices` object. You should use the same values as the `english` object for local testing, replacing the `english` key with your language's `availableLangs` value.
> [!NOTE] If we have already deployed an instance of news in your target language, you can update the values to reflect the live instance. Otherwise, use the English values.
If you were to add Dothraki:
```js
const algoliaIndices = {
english: {
name: 'news',
searchPage: 'https://www.freecodecamp.org/news/search/'
},
espanol: {
name: 'news-es',
searchPage: 'https://www.freecodecamp.org/espanol/news/search/'
},
chinese: {
name: 'news-zh',
searchPage: 'https://chinese.freecodecamp.org/news/search/'
},
'chinese-traditional': {
name: 'news-zh',
searchPage: 'https://chinese.freecodecamp.org/news/search'
},
dothraki: {
name: 'news',
searchPage: 'https://www.freecodecamp.org/news/search/'
}
// If we already have /news in the target language up and running, you can update the values like this:
// dothraki: {
// name: 'news-mis',
// searchPage: 'https://www.freecodecamp.org/dothraki/news/search/'
// }
};
```
### Client UI
You will need to take an additional step to handle the client UI translations.
The Crowdin workflows will automatically pull down _some_ of the UI translations, but there are a couple of files that need to be moved manually.
You will want to copy the following files from [`/client/i18n/locales/english`](https://github.com/freeCodeCamp/freeCodeCamp/tree/main/client/i18n/locales/english) to `/client/i18n/locales/<your-language>`, and apply translations as needed:
- `links.json`
- `meta-tags.json`
- `motivation.json`
You don't have to have everything in these 3 files translated at first. It's possible to translate only the relevant parts and make adjustments later.
#### `links.json`
You can replace any URLs that you have corresponding pages ready in your language.
For example, if you have a publication in your language, you can replace the URL for `"news"`. If you want to translate articles listed in the footer links, see [How to Translate Articles in the Footer Links](language-lead-handbook.md#how-to-translate-articles-in-the-footer-links).
#### `meta-tags.json`
This file contains metadata for the web page of `/learn` in your language. You can translate the values for `"title"`, `"description"`, and `"social-description"`. The value for `"youre-unsubscribed"` is used when someone unsubscribes from Quincy's weekly email.
Also, you can translate or add relevant keywords in your language to the `"keywords"` array.
#### `motivation.json`
This file contains the compliments that will be displayed to campers when they complete a challenge, and motivational quotes that are displayed on the top page of `/learn`.
You can translate them, or even replace them with relevant compliments/quotes of your choice in your language.
### Enabling Localized Videos
This section is applicable only if you have localized videos in the challenges. Otherwise, you can skip this section.
For the video challenges, you need to change a few things. First, add the new locale to the GraphQL query in the [`client/src/templates/Challenges/video/Show.tsx`](https://github.com/freeCodeCamp/freeCodeCamp/blob/main/client/src/templates/Challenges/video/show.tsx) file. For example, adding Dothraki to the query:
```tsx
query VideoChallenge($slug: String!) {
challengeNode(fields: { slug: { eq: $slug } }) {
videoId
videoLocaleIds {
espanol
italian
portuguese
dothraki
}
...
```
Then add an id for the new language to any video challenge in an audited block. For example, if `auditedCerts` in `i18n.ts` includes `scientific-computing-with-python` for `dothraki`, then you must add a `dothraki` entry in `videoLocaleIds`. The frontmatter should then look like this:
```yml
videoLocaleIds:
espanol: 3muQV-Im3Z0
italian: hiRTRAqNlpE
portuguese: AelGAcoMXbI
dothraki: new-id-here
dashedName: introduction-why-program
---
```
Update the `VideoLocaleIds` interface in `client/src/redux/prop-types` to include the new language.
```ts
export interface VideoLocaleIds {
espanol?: string;
italian?: string;
portuguese?: string;
dothraki?: string;
}
```
And finally, update the challenge schema in `curriculum/schema/challengeSchema.js`.
```js
videoLocaleIds: Joi.when('challengeType', {
is: challengeTypes.video,
then: Joi.object().keys({
espanol: Joi.string(),
italian: Joi.string(),
portuguese: Joi.string(),
dothraki: Joi.string()
})
}),
```
## Testing Translations Locally
If you would like to test translations locally, before adding them to our main repository - skip the Crowdin workflow changes. Follow the steps for enabling a language, then download the translations from Crowdin and load them into your local code.
Because the language has not been approved for production, our scripts are not automatically downloading the translations yet. Only staff have access to directly download the translations - you are welcome to reach out to us in our [contributors chat room](https://discord.gg/PRyKn3Vbay), or you can translate the English markdown files locally for testing purposes.
Once you have the files, you will need to place them in the correct directory. For the curriculum challenges, you should place the certification folders (i.e. `01-responsive-web-design`) within the `curriculum/challenges/{lang}` directory. For our Dothraki translations, this would be `curriculum/challenges/dothraki`. The client translation `.json` files will go in the `client/i18n/locales/{lang}` directory.
Update your `.env` file to use your new language for `CLIENT_LOCALE` and `CURRICULUM_LOCALE`.
Once these are in place, you should be able to run `pnpm run develop` to view your translated version of freeCodeCamp.
> [!TIP] If you build the client in one language and then want to build it in a different language, you will need to use the command `pnpm run clean-and-develop` after changing the `.env` file, as Gatsby will cache the first language.
> [!ATTENTION] While you may perform translations locally for the purpose of testing, we remind everyone that translations should _not_ be submitted through GitHub and should only be done through Crowdin. Be sure to reset your local codebase after you are done testing.
## Show the language in the navigation menu
When your prior PR is merged and the VM for your language is ready, make another PR to show your language in the navigation menu.
In [`shared/config/i18n.ts`](https://github.com/freeCodeCamp/freeCodeCamp/blob/main/shared/config/i18n.ts) file, you have included your language in `hiddenLangs` array in the prior PR. Remove it from the array now.
```js
export const hiddenLangs = []; // Remove your language from the array
```
When this PR is merged and deployed, the curriculum in your language will be live.
# Deploying New Languages on `/news`
To deploy News for a new language, you'll need to create two PRs. One PR will be to the [CDN repo](https://github.com/freeCodeCamp/cdn), and the other will be to the [News repo](https://github.com/freeCodeCamp/news).
## Prep the CDN Repo for the New Language
News sources trending links and article titles from our CDN during the build and adds them to the footer. News also fetches Day.js files from the CDN during the build to localize dates and times for each language.
### Add a YAML File for Trending Articles
Clone the [CDN repo](https://github.com/freeCodeCamp/cdn) and create a new branch.
In the [`build/universal/trending`](https://github.com/freeCodeCamp/cdn/tree/main/build/universal/trending) directory, create a new file and name it `language.yaml`. For example, if you are launching Dothraki News, name the file `dothraki.yaml`.
Then copy the contents of the [`english.yaml`](https://github.com/freeCodeCamp/cdn/blob/main/build/universal/trending/english.yaml) trending file and paste it into the new YAML file you just created.
The contents will look something like this:
```yaml
article0title: 'Learn JavaScript'
article0link: 'https://www.freecodecamp.org/news/learn-javascript-free-js-courses-for-beginners/'
article1title: 'Linux ln Example'
article1link: 'https://www.freecodecamp.org/news/linux-ln-how-to-create-a-symbolic-link-in-linux-example-bash-command'
article2title: 'JS document.ready()'
article2link: 'https://www.freecodecamp.org/news/javascript-document-ready-jquery-example/'
article3title: ...
article3link: ...
...
```
### Add a Day.js Locale File for the New Language
By default, Day.js only includes English as a locale. To enable it to work with other languages, you need to add a new Day.js locale file to the CDN.
In the [`build/news-assets/dayjs/<version>/locale`](https://github.com/freeCodeCamp/cdn/tree/main/build/news-assets/dayjs/1.10.4/locale) directory, create a new file and name it `isocode.min.js`. For example, if you are launching Dothraki News, name the file `mis.min.js`.
> [!NOTE] The version number will change as the dependencies are updated.
Then, visit [this page on cdnjs](https://cdnjs.com/libraries/dayjs/1.10.4) with all available Day.js files for the version we're using, find the `https://cdnjs.cloudflare.com/ajax/libs/dayjs/<version>/locale/isocode.min.js` link for the new language, and open it in a new tab.
> [!NOTE] You only need to add the .../dayjs/\<version\>/_locale_/isocode.min.js locale file. You do not need to add any other Day.js files.
Copy the Day.js locale code from the new tab into the new file you created. For example, here is an un-minified version of the English locale code for Day.js:
```js
!(function (e, n) {
'object' == typeof exports && 'undefined' != typeof module
? (module.exports = n())
: 'function' == typeof define && define.amd
? define(n)
: (e.dayjs_locale_en = n());
})(this, function () {
'use strict';
return {
name: 'en',
weekdays: 'Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday'.split(
'_'
),
months:
'January_February_March_April_May_June_July_August_September_October_November_December'.split(
'_'
)
};
});
```
Then open a PR to the CDN repo to add both the YAML and Day.js files for review.
## Prep the News Repo for the New Language
The [News repo](https://github.com/freeCodeCamp/news) pulls data from a Ghost instance, the files you added to the CDN, builds News, and deploys it.
> [!WARN] Pull requests to the News repo _must_ come from the same repo. You should not work off of a fork for this step.
### Modify the Main Config File
Clone the News repo and create a new branch.
Open the `config/index.js` file to add the new language and configure the necessary values. There are a few objects and arrays to modify:
- `locales`: This array contains the active and upcoming News languages. These are the values that are used in the `.env` file to choose the Ghost instance and UI to use for each build. Add the text name of the new language in lowercase to this array.
- `localeCodes`: This object is a map of ISO codes for each language, and is used to configure i18next before building the UI. To add a new language, use the lowercase language name as the _key_ and the ISO 639-1 language code as the _value_.
- `algoliaIndices`: This object is a map of Algolia indices for each language. To add a new language, use the lowercase language name as the _key_, and `news-` followed by the lowercase ISO 639-1 language code as the _value_.
> [!NOTE] If you are unsure about the string to use while setting `algoliaIndices`, send a message to Kris (@scissorsneedfoodtoo), or someone else with access to Algolia, and ask them to check.
For example, if you are launching Dothraki News, here are what the objects / arrays above should look like:
```js
const locales = ['arabic', 'bengali', 'chinese', 'english', 'dothraki'];
const localeCodes = {
arabic: 'ar',
bengali: 'bn',
chinese: 'zh',
english: 'en',
dothraki: 'mis'
};
const algoliaIndices = {
arabic: 'news-ar',
bengali: 'news-bn',
chinese: 'news-zh',
english: 'news',
dothraki: 'news-mis'
};
```
### Add the i18next JSON Files for the New Language
Next, go to the `shared/config/i18n/locales` directory, create a new folder, and give it the name of the new language you're adding. For example, if you're launching Dothraki News, create a new folder named `dothraki`.
Then copy the JSON files from the `english` directory to your new folder.
In your new folder, open the `redirects.json` file and replace its contents with an empty array:
```json
[]
```
Then commit and push your branch directly to the News repo.
> [!NOTE] You need to be on one of the teams with access to the News repo to push branches directly to News. Currently, only the dev, i18n, and staff teams are allowed to do this.
Finally, open a PR for review.
Once both your PRs to the CDN and News repo have been approved, they can be merged.
> [!NOTE] Deployment will be handled subsequently by the staff. Here is a sample PR: [freeCodeCamp/news#485](https://github.com/freeCodeCamp/news/pull/485) of how they do it and more details are available in the [staff-wiki](https://staff-wiki.freecodecamp.org/docs/flight-manuals/news-instances#jamstack---news--assets).
@@ -1,203 +0,0 @@
# How to Help with Video Challenges
Video challenges are a new type of challenge in the freeCodeCamp curriculum.
A video challenge is a small section of a full-length video course on a particular topic. A video challenge page embeds a YouTube video. Each challenge page has a single multiple-choice question related to the video. A user must answer the question correctly before moving on to the next video challenge in the course.
The video challenge pages are created by members of the freeCodeCamp team. YouTube videos are also uploaded by members of the freeCodeCamp team. Many of the video challenges do not yet have questions associated with them.
You can help by creating multiple-choice questions related to video sections and adding the questions to the markdown files for the video challenges.
## Challenge Template
Below is a template of what the challenge markdown files look like.
````md
---
id: Unique identifier (alphanumerical, MongoDB_id)
title: Challenge Title
challengeType: 11
videoId: 'YouTube videoId for video challenge'
forumTopicId: 12345
---
# --description--
Challenge description text, in markdown
```html
<div>example code</div>
````
# --question--
These fields are currently used for the multiple-choice Python challenges.
## --text--
The question text goes here.
## --answers--
Answer 1
---
Answer 2
---
More answers
## --video-solution--
The number for the correct answer goes here.
````
## Creating Questions for Video Challenges
### Access the Video Challenge Markdown Files
You can find the markdown files for video challenges at the following locations in the curriculum:
- [Data Analysis with Python Course](https://github.com/freeCodeCamp/freeCodeCamp/tree/main/curriculum/challenges/english/08-data-analysis-with-python/data-analysis-with-python-course)
- [TensorFlow 2.0 Course](https://github.com/freeCodeCamp/freeCodeCamp/tree/main/curriculum/challenges/english/11-machine-learning-with-python/tensorflow)
- [Numpy Course](https://github.com/freeCodeCamp/freeCodeCamp/tree/main/curriculum/challenges/english/08-data-analysis-with-python/numpy)
- [How Neural Networks Work Course](https://github.com/freeCodeCamp/freeCodeCamp/tree/main/curriculum/challenges/english/11-machine-learning-with-python/how-neural-networks-work)
Pick a challenge markdown file from the options above.
### Skim through the video associated with the challenge and create a multiple-choice question
First, find the `videoId`.
For example, in the following code from the header of a video challenge markdown file, the `videoId` is "nVAaxZ34khk". On GitHub, the information should be laid out in a table format.
````
---
id: 5e9a093a74c4063ca6f7c14d title: Data Analysis Example A challengeType: 11
videoId: nVAaxZ34khk
---
```
Next, access the YouTube video with that `videoId`. The URL for the video will be:
https://www.youtube.com/watch?v=[videoId] (replace `videoId` in the URL with the video's ID - without square brackets)
In the example above, the URL is https://www.youtube.com/watch?v=nVAaxZ34khk
Skim the YouTube video with that `videoId` and think of a multiple-choice question based on the content of the video.
### Add the Question to the Markdown File
You can add the question locally or using the GitHub interface. To add the question locally, you need to [set up freeCodeCamp locally](how-to-setup-freecodecamp-locally.md). You can also find the file on GitHub and click the edit button to add the question right in your browser.
If a question has not yet been added to a particular video challenge, it will have the following default question:
```md
# --question--
## --text--
Question text
## --answers--
Answer 1
---
Answer 2
---
More answers
## --video-solution--
1
```
Add/Update the question text under the part that shows:
```
# --question--
## --text--
```
Add/Update answers (`Answer 1`, `Answer 2`, and so on) under `## --answers--`. Make sure to update the number under `## --video-solution--` with the correct answer number. You can add more possible answers using the same format. The questions and answers can be surrounded with quotation marks.
### Question examples
````md
# --question--
## --text--
What does this JavaScript code log to the console?
```js
console.log('hello world');
````
## --answers--
hello _world_
---
**hello** world
---
hello world
---
## --video-solution--
3
````
````md
# --question--
## --text--
What will print out after running this code:
```py
width = 15
height = 12.0
print(height/3)
````
## --answers--
39
---
4
---
4.0
---
5.0
---
5
## --video-solution--
3 ````
For more examples, you can look at the markdown files for the following video course. All the challenges already have questions: [Python for Everybody Course](https://github.com/freeCodeCamp/freeCodeCamp/tree/main/curriculum/challenges/english/07-scientific-computing-with-python/python-for-everybody)
## Open a Pull Request
After creating one or more questions, you can commit the changes to a new branch and [open a pull request](how-to-open-a-pull-request.md).
@@ -1,207 +0,0 @@
# How to open a Pull Request (PR)
A pull request (PR), enables you to send changes from your fork on GitHub to freeCodeCamp.org's main repository. Once you are done making changes to the code, you can follow these guidelines to open a PR.
We expect our contributors to be aware of the process specific to this project. Following the guidelines carefully earns you the respect of fellow maintainers and saves everyone time.
Some examples of this are:
1. Do not edit files directly through GitHub – while you can, it's not a good idea.
2. Make sure the PR title follows [our convention](#prepare-a-good-pr-title).
3. Make sure you follow the PR checklist and not just tick things off; otherwise, we won't take you seriously.
4. Use the correct way to link issues in the description of the PR by updating the `XXXXXX`. Do not just add issue numbers everywhere and anywhere you feel like.
5. Do not "@mention" or request someone for reviews too many times.
We understand you are excited about contributing. As much as a maintainer will love to get back to you, they are busy people looking after hundreds of requests just like yours. Be patient, someone will get to you sooner or later.
6. Do not work directly off your `main` branch - create a new branch for the changes you are working on.
> [!NOTE] Your PR should be targeting changes to the English curriculum only. Read [this guide](index.md#translations) instead for contributing to translations.
## Prepare a Good PR Title
We use [conventional title and messages](https://www.conventionalcommits.org/) for commits and pull requests. The convention has the following format:
> `<type>([optional scope(s)]): <description>`
>
> For example:
>
> `fix(learn): tests for the do...while loop challenge`
Whenever you open a Pull Request (PR), you can use the below to determine the type, scope (optional), and description.
**Type:**
| Type | When to select |
|:----- |:------------------------------------------------------------------------------- |
| fix | Changed or updated/improved functionality, tests, the wording of a lesson, etc. |
| feat | Only if you are adding new functionality, tests, etc. |
| chore | Changes that are not related to code, tests, or verbiage of a lesson. |
| docs | Changes to `/docs` directory or the contributing guidelines, etc. |
**Scope:**
You can select a scope from [this list of labels](https://github.com/freeCodeCamp/freeCodeCamp/labels?q=scope).
**Description:**
Keep it short (less than 30 characters) and simple; you can add more information in the PR description box and comments.
Some examples of good PR titles would be:
- `fix(a11y): improved search bar contrast`
- `feat: add more tests to HTML and CSS challenges`
- `fix(api,client): prevent CORS errors on form submission`
- `docs(i18n): fix links to be relative instead of absolute`
## Proposing a Pull Request
1. Once the edits have been committed, you will be prompted to create a pull request on your fork's GitHub Page.
<details>
<summary>See screenshot</summary>
![Image - Compare & pull request prompt on GitHub](https://contribute.freecodecamp.org/images/github/compare-pull-request-prompt.png)
</details>
2. By default, all pull requests should be against the freeCodeCamp main repo, `main` branch.
Make sure that your Base Fork is set to freeCodeCamp/freeCodeCamp when raising a Pull Request.
<details>
<summary>See screenshot</summary>
![Image - Comparing forks when making a pull request](https://contribute.freecodecamp.org/images/github/comparing-forks-for-pull-request.png)
</details>
3. Submit the pull request from your branch to freeCodeCamp's `main` branch.
4. Include a more detailed summary of the changes you made and how your changes are helpful in the body of your PR.
- You will be presented with a pull request template. This is a checklist that you should have followed before opening the pull request.
- Fill in the details as you see fit. Ensure that you give the reviewers enough context to review the changes. If the PR makes changes to the UI, be sure to include screenshots of the changes as well. All of this information will be reviewed and the reviewers will decide whether or not your pull request is accepted.
- If the PR is meant to address an existing GitHub Issue then, at the end of your PR's description body, use the keyword _Closes_ with the issue number to [automatically close that issue if the PR is accepted and merged](https://help.github.com/en/articles/closing-issues-using-keywords).
> Example: `Closes #123` will close issue 123
5. Indicate if you have tested on a local copy of the site or not.
- This is very important when making changes that are not just edits to text content like documentation or a challenge description. Examples of changes that need local testing include JavaScript, CSS, or HTML, which could change the functionality or layout of a page.
- If your PR affects the behavior of a page, it should be accompanied by corresponding [Playwright integration tests](how-to-add-playwright-tests.md).
## Feedback on Pull Requests
> :tada: Congratulations on making a PR and thanks a lot for taking the time to contribute.
Our moderators will now take a look and leave you feedback. Please be patient with the fellow moderators and respect their time. All pull requests are reviewed in due course.
And as always, feel free to ask questions on the ['Contributors' category on our forum](https://forum.freecodecamp.org/c/contributors) or [the contributors chat room](https://discord.gg/PRyKn3Vbay).
> [!TIP] If you are to be contributing more pull requests, we recommend you read the [making changes and syncing](how-to-setup-freecodecamp-locally.md#making-changes-locally) guidelines to avoid having to delete your fork.
## Conflicts on a Pull Request
Conflicts can arise because many contributors work on the repository, and changes can break your PR which is pending a review and merge.
Since we squash all commits, you may not need to do a rebase. However, if a rebase is requested, check our [For Usual Bug Fixes and Features](#for-usual-bug-fixes-and-features) or [For Upcoming Curriculum and Features](#for-upcoming-curriculum-and-features) guides to learn how to do this process for your corresponding PR.
### For Usual Bug Fixes and Features
When you are working on regular bugs and features on our development branch `main`, you are able to do a simple rebase:
1. Rebase your local copy:
```bash
git checkout <pr-branch>
git pull --rebase upstream main
```
2. Resolve any conflicts and add / edit commits
```bash
# Either
git add .
git commit -m "chore: resolve conflicts"
# Or
git add .
git commit --amend --no-edit
```
3. Push back your changes to the PR
```bash
git push --force origin <pr-branch>
```
### For Upcoming Curriculum and Features
When you are working on features for our upcoming curriculum `next-*` branches, you have to do a `cherry-pick`:
1. Make sure your upstream comes in sync with your local:
```bash
git checkout main
git fetch --all --prune
git checkout next-python-projects
git reset --hard upstream/next-python-projects
```
2. Take a backup
a. Either delete your local branch after taking a backup (if you still have it locally):
```bash
git checkout <pr-branch-name>
# example:
# git checkout feat/add-numpy-video-question
git checkout -b <backup-branch-name>
# example:
# git checkout -b backup-feat/add-numpy-video-question
git branch -D <pr-branch-name>
```
b. Or just a backup of your PR branch (if you do not have it locally):
```bash
git checkout -b <backup-branch-name> origin/<pr-branch-name>
# example:
# git checkout -b backup-feat/add-numpy-video-question origin/feat/add-numpy-video-question
```
3. Start off with a clean slate:
```bash
git checkout -b <pr-branch-name> next-python-projects
git cherry-pick <commit-hash>
```
4. Resolve any conflicts, cleanup, and install dependencies and run tests
```bash
pnpm run clean
pnpm install
FCC_SUPERBLOCK='<superblock-name>' pnpm run test:curriculum
# example:
# FCC_SUPERBLOCK='python-for-everybody' pnpm run test:curriculum
```
5. If everything looks good, push back to the PR
```bash
git push --force origin <pr-branch-name>
```
@@ -1,54 +0,0 @@
# 如何校對譯文
Our proofreading team is responsible for ensuring that translations accurately reflect the source text. We trust our proofreaders to ensure that we have very high quality translations.
All our translations are done by hand, by real humans. Proofreading ensures that there is a consistent tone across all our translated resources like the curriculum.
To begin proofreading, visit [our translation platform](https://translate.freecodecamp.org) and login. Select "Go to console" in the top navigation bar to switch from the public view to the workspace view.
## 選擇文件
You should see the list of projects you have been granted access to. Select the project that you would like to proofread, then select the language.
![Image - Proofreading File Tree](https://contribute.freecodecamp.org/images/crowdin/proof-file-tree.png)
You should now see the list of available files. Choose your file by selecting the `Proofread` button on the right of that file, then choosing `Proofreading` from the drop-down menu that appears.
> [!NOTE] If you are in this workspace view, but want to work on [translating a file](how-to-translate-files.md) instead of proofreading, you may select `Crowdsourcing` from the dropdown menu instead.
## 校對譯文
![Image - Proofreading View](https://contribute.freecodecamp.org/images/crowdin/proofread.png)
<!--Add proofread/crowdsource button to the image-->
Here you will see the list of strings in the selected file, with their related translations. The translation that is displayed here is the translation that has received the highest score (between upvotes and downvotes) from the translation community.
While you can view _all_ proposed translations for a given string, the community scores (determined by the upvotes and downvotes) should be taken into consideration when choosing which translation to approve. The community can review proposed translations and recommend which one is most accurate and clear.
1. 這是源文件的字符串(英文)。
2. 這是相匹配的翻譯的字符串。 此處將顯示基於贊同和反對票數的最受歡迎的譯文建議。
3. 點擊這個選擇標記按鈕確認該譯文。
4. Crowdin 將顯示每個字符串的狀態。 `Done` 的意思是已經確認了譯文,我們將在下次從 Crowdin 拉取內容的時候下載已確認的譯文。 `Todo` 的意思是字符串的譯文還未被校對確認。 `Hidden` means the string is locked and _should not be translated_. `Comment` 的意思是對此字符串有評論消息。
5. 可以使用復框選擇多條譯文,並在此處一次性批量確認。
6. 你可以在此處查看社區建議的譯文,社區對其的評分,以及 Crowdin 建議的譯文。
7. 這個按鈕顯示/隱藏右側的顯示窗口,你可以在其中查看翻譯、評論、翻譯記憶和詞彙表術語。
8. Crowdin 在此處顯示來自質量保證檢查的報錯消息。 也就是說,如果譯文中有不正確的地方,Crowdin 會通知你。 請仔細校對確認出現報錯消息的譯文。
No additional actions are required once a file has been proofread.
> [!NOTE] Approving a string in the proofreading view will mark it as complete and it will be downloaded in our next pull from Crowdin to GitHub.
## Becoming a Proofreader
If you have any questions, or are interested in becoming a proofreader, feel free to reach out to us in our [contributors chat room](https://discord.gg/PRyKn3Vbay). We will typically grant you proofreading access if you have been contributing to freeCodeCamp for a while.
Our staff team and community moderators teams are always looking for kind volunteers like you who help us make high quality translations available to the world.
> [!NOTE] Crowdin 會允許你校對你自己的譯文。 一般來說,最好是讓另一位校對者審覈你的譯文,以確保最終內容的準確性。
## Creating a Channel on Chat for a World Language
For the most part, we encourage you to use the [contributors chat](https://discord.gg/PRyKn3Vbay) room for all correspondence. However if the team of volunteer translators grows for a certain language, we can consider creating an additional break-out channel for the language.
If you are already a proofreader and are interested in having a dedicated channel on our chat servers for a specific language, [fill out this form](https://forms.gle/XU5CyutrYCgDYaVZA).
@@ -1,289 +0,0 @@
Follow these guidelines for setting up a development environment for freeCodeCamp. This is highly recommended if you want to contribute regularly.
## Choose between Gitpod or your Own Machine (local setup)
> [!ATTENTION] - freeCodeCamp does not build and run natively on Windows, you will [need to use WSL2](how-to-setup-wsl.md) for a Linux-like setup on Windows. - You can't use Windows Command Prompt, Git Bash or PowerShell to build and run the codebase. - Note that if using Windows, the hardware requirements need to be more than [what we mention](how-to-setup-freecodecamp-locally?id=how-to-prepare-your-local-machine) to accommodate for WSL-based setup.
If you are looking to make a one-off contribution, you should use Gitpod to make changes. The Gitpod setup launches a ready-to-code environment in a few minutes in your web browser. To contribute long-term, we recommend you set up freeCodeCamp on your local machine.
Here are some pros and cons which should help you decide which option is best for you:
| Gitpod | Your own machine (local setup) |
| ----------------------------------------------------------------- | --------------------------------------------------------------------- |
| No minimum hardware requirements | Specific and minimum requirements |
| No need to install any software | Additional software required |
| Always up to date copy of repository | Need to maintain a local copy of the repository |
| Slower and can take a few minutes to launch | Faster and can be launched in seconds |
| Need an internet connection to work | Minimal internet connection required (once setup) |
| Some tasks like compilation and tests can take longer to complete | Faster completion of tasks (depending on your machine's capabilities) |
### How to Prepare a Gitpod Workspace
We have automated the process of installing all the dependencies & tools you will need. With Gitpod you get a free ready-to-code environment in a few minutes, and is useful if you do not have access to a computer or want to make one-time changes.
There are various ways to launch a Gitpod workspace:
1. **(Fastest)** Prepend `gitpod.io/#` in front of any URL from GitHub.
For example, if you visit your fork at `https://github.com/YOUR_USER_NAME/freeCodeCamp.git`, add `gitpod.io/#` in the front of the URL in the address bar and hit enter.
That is you can navigate to `gitpod.io/#https://github.com/YOUR_USER_NAME/freeCodeCamp.git` and you should see a workspace created for you. This works for any repository or pull-request on GitHub.
2. Alternatively install one of the below extensions for your browser.
- [Chrome Webstore](https://chrome.google.com/webstore/detail/gitpod-always-ready-to-co/dodmmooeoklaejobgleioelladacbeki) - works with Chromium-based browsers like Google Chrome, Brave, Edge, etc.
- [Firefox Add-on](https://addons.mozilla.org/en-US/firefox/addon/gitpod) - Firefox
Once installed you will see a 'Gitpod' button on every repository, pull-request, etc. as a handy shortcut to launch a workspace from there. See the extension page for details, screenshots, etc.
That's it, you can now skip to the 'syncing up from parent' section after you have launched a Gitpod workspace. Most parts of this guide applies to Gitpod workspaces, but be mindful of [how the URLs & Ports work within a Gitpod](https://www.gitpod.io/docs/configure/workspaces/ports) workspace.
**Note: Troubleshooting port issues on Gitpod**
Sometimes the service on port `8000` doesn't go live. This is common when you are restarting an inactive workspace.
If the service is not coming up on port `8000`, you can troubleshoot using these steps:
- **Start the server**: Run `pnpm run develop:server` in one terminal window from the root project directory (`/workspace/freeCodeCamp`) to start the server.
- **Start the client**: In another terminal window, run `pnpm run develop -- -H '0.0.0.0'` from the client directory (`/workspace/freeCodeCamp/client`) to start the client.
This should make port `8000` available.
### How to Prepare your Local Machine
Here is a minimum system requirement for running freeCodeCamp locally:
- 8 GB RAM
- Relatively fast CPU (4+ cores)
- Windows 10 or 11 (with WSL), macOS, or Linux
Start by installing the prerequisite software for your operating system.
We primarily support development on Linux and Unix-based systems like Ubuntu and macOS. You can develop on Windows 10 or 11 with WSL2 only. You can follow [this guide](how-to-setup-wsl.md) to set up WSL2. You can't use Command Prompt, Git Bash or PowerShell to run freeCodeCamp natively within windows.
#### Prerequisites:
| Prerequisite | Version | Notes |
| --------------------------------------------------------------------------------------------- | ------- | ------------------------------------------------------------------------------------------- |
| [Node.js](http://nodejs.org) | `20.x` | We use the "Active LTS" version, See [LTS Schedule](https://nodejs.org/en/about/releases/). |
| [pnpm](https://pnpm.io/installation) | `8.x` | - |
| [MongoDB Community Server](https://docs.mongodb.com/manual/administration/install-community/) | `5.0.x` | - |
> [!ATTENTION] If you have a different version, please install the recommended version. We can only support installation issues for recommended versions. See [troubleshooting section](troubleshooting-development-issues.md) for details.
If Node.js is already installed on your machine, run the following commands to validate the versions:
```bash
node -v
pnpm -v
```
> [!TIP] We highly recommend updating to the latest stable releases of the software listed above, also known as Long Term Support (LTS) releases.
Once you have the prerequisites installed, you need to prepare your development environment. This is common for many development workflows, and you will only need to do this once.
##### Follow these steps to get your development environment ready:
1. Install [Git](https://git-scm.com/) or your favorite Git client, if you haven't already. Update to the latest version; the version that came bundled with your OS may be outdated.
2. (Optional but recommended) [Set up an SSH Key](https://help.github.com/articles/generating-an-ssh-key/) for GitHub.
3. Install a code editor of your choice. If you aren't sure which one to use, we recommend [Visual Studio Code](https://code.visualstudio.com/) — it's free and open source.
4. Set up linting for your code editor.
You should have [ESLint running in your editor](http://eslint.org/docs/user-guide/integrations.html), and it will highlight anything that doesn't conform to [freeCodeCamp's JavaScript Style Guide](http://forum.freecodecamp.org/t/free-code-camp-javascript-style-guide/19121).
> [!TIP] Please do not ignore any linting errors. They are meant to **help** you and to ensure a clean and simple codebase.
## Fork the Repository on GitHub
[Forking](https://help.github.com/articles/about-forks/) is a step where you get your own copy of freeCodeCamp's main repository (a.k.a _repo_) on GitHub.
This is essential, as it allows you to work on your own copy of freeCodeCamp on GitHub, or to download (clone) your repository to work on locally. Later, you will be able to request changes to be pulled into the main repository from your fork via a pull request (PR).
> [!TIP] The main repository at `https://github.com/freeCodeCamp/freeCodeCamp` is often referred to as the `upstream` repository.
>
> Your fork at `https://github.com/YOUR_USER_NAME/freeCodeCamp` is often referred to as the `origin` repository. `YOUR_USER_NAME` would be replaced with your GitHub username.
**Follow these steps to fork the `https://github.com/freeCodeCamp/freeCodeCamp` repository:**
1. Go to the freeCodeCamp repository on GitHub: <https://github.com/freeCodeCamp/freeCodeCamp>
2. Click the "Fork" Button in the upper right-hand corner of the interface ([More Details Here](https://help.github.com/articles/fork-a-repo/))
3. After the repository has been forked, you will be taken to your copy of the freeCodeCamp repository at `https://github.com/YOUR_USER_NAME/freeCodeCamp` (`YOUR_USER_NAME` would be replaced with your GitHub user name.)
<details>
<summary>
How to fork freeCodeCamp on GitHub (screenshot)
</summary>
<br>
<img src="https://raw.githubusercontent.com/freeCodeCamp/freeCodeCamp/main/docs/images/github/how-to-fork-freeCodeCamp.gif" alt="How to fork freeCodeCamp on GitHub" />
</details>
## Clone your Fork from GitHub
[Cloning](https://help.github.com/articles/cloning-a-repository/) is where you **download** a copy of a repository from a `remote` location that is either owned by you or by someone else. In your case, this remote location is your `fork` of freeCodeCamp's repository that should be available at `https://github.com/YOUR_USER_NAME/freeCodeCamp`. (`YOUR_USER_NAME` would be replaced with your GitHub user name.)
> [!WARNING] If you are working on a WSL2 Linux Distro, you might get performance and stability issues by running this project in a folder which is shared between Windows and WSL2 (e.g. `/mnt/c/Users/`). Therefore we recommend to clone this repo into a folder which is mainly used by your WSL2 Linux Distro and not directly shared with Windows (e.g. `~/PROJECTS/`).
>
> See [this GitHub Issue](https://github.com/freeCodeCamp/freeCodeCamp/issues/40632) for further information about this problem.
Run these commands on your local machine:
1. Open a Terminal / Command Prompt / Shell in your projects directory
_i.e.: `/yourprojectsdirectory/`_
2. Clone your fork of freeCodeCamp, replacing `YOUR_USER_NAME` with your GitHub Username
```bash
git clone --depth=1 https://github.com/YOUR_USER_NAME/freeCodeCamp.git
```
This will download the entire freeCodeCamp repository to your projects directory.
Note: `--depth=1` creates a shallow clone of your fork, with only the most recent history/commit.
## Set up Syncing from Parent
Now that you have downloaded a copy of your fork, you will need to set up an `upstream` remote to the parent repository.
[As mentioned earlier](#fork-the-repository-on-github), the main repository is referred to as the `upstream` repository. Your fork is referred to as the `origin` repository.
You need a reference from your local clone to the `upstream` repository in addition to the `origin` repository. This is so that you can sync changes from the main repository without the requirement of forking and cloning repeatedly.
1. Change the directory to the new freeCodeCamp directory:
```bash
cd freeCodeCamp
```
2. Add a remote reference to the main freeCodeCamp repository:
```bash
git remote add upstream https://github.com/freeCodeCamp/freeCodeCamp.git
```
3. Ensure the configuration looks correct:
```bash
git remote -v
```
The output should look something like below (replacing `YOUR_USER_NAME` with your GitHub username):
```bash
origin https://github.com/YOUR_USER_NAME/freeCodeCamp.git (fetch)
origin https://github.com/YOUR_USER_NAME/freeCodeCamp.git (push)
upstream https://github.com/freeCodeCamp/freeCodeCamp.git (fetch)
upstream https://github.com/freeCodeCamp/freeCodeCamp.git (push)
```
## Running freeCodeCamp Locally
Now that you have a local copy of freeCodeCamp, you can follow these instructions to run it locally. This will allow you to:
- Preview edits to pages as they would appear on the learning platform.
- Work on UI related issues and enhancements.
- Debug and fix issues with the application servers and client apps.
If you do run into issues, first perform a web search for your issue and see if it has already been answered. If you cannot find a solution, please search our [GitHub issues](https://github.com/freeCodeCamp/freeCodeCamp/issues) page for a solution and report the issue if it has not yet been reported.
And as always, feel free to ask questions on the ['Contributors' category on our forum](https://forum.freecodecamp.org/c/contributors) or [our chat server](https://discord.gg/PRyKn3Vbay).
### Configuring Dependencies
#### Step 1: Set up the Environment Variable File
The default API keys and environment variables are stored in the file `sample.env`. This file needs to be copied to a new file named `.env` that is accessed dynamically during the installation step.
```bash
# Create a copy of the "sample.env" and name it ".env".
# Populate it with the necessary API keys and secrets
```
```bash
cp sample.env .env
```
The keys in the `.env` file are _not_ required to be changed to run the app locally. You can leave the default values copied over from `sample.env` as-is.
> [!TIP] Keep in mind if you want to use services like Auth0 or Algolia, you'll have to acquire your own API keys for those services and edit the entries accordingly in the `.env` file.
#### Step 2: Install Dependencies
This step will install the dependencies required for the application to run:
```bash
pnpm install && pnpm run create:shared
```
#### Step 3: Start MongoDB and Seed the Database
Before you can run the application locally, you will need to start the MongoDB service.
> [!NOTE] Unless you have MongoDB running in a setup different than the default, the URL stored as the `MONGOHQ_URL` value in the `.env` file should work fine. If you are using a custom configuration, modify this value as needed.
>
> If you followed along with the [Windows 10 via WSL2 Setup Guide](how-to-setup-wsl.md), then you should be able to skip this step if the MongoDB server from that guide is already running. You can confirm this by checking that you can reach `http://localhost:27017` on your local machine.
Start the MongoDB server in a separate terminal:
```bash
mongod
```
> [!TIP] You can avoid having to start MongoDB every time by installing it as a background service. You can [learn more about it in their documentation for your OS](https://docs.mongodb.com/manual/administration/install-community/)
Next, let's seed the database. In this step, we run the below command that fills the MongoDB server with some initial data sets that are required by services. These include a few schemas, among other things.
```bash
pnpm run seed
```
By default, you will be signed in as a new user without any completed certifications. Run the following command if you need to develop with completed certifications or write Playwright tests:
```bash
pnpm run seed:certified-user
```
> [!WARNING] Running `pnpm run seed:certified-user` will log you out. You will have to clear your browser cookies and sign in again.
#### Step 4: Start the freeCodeCamp Client Application and API Server
You can now start up the API server and the client applications.
```bash
pnpm run develop
```
This single command will fire up all the services, including the API server and the client applications available for you to work on.
Once ready, open a web browser and visit <http://localhost:8000>. If the app loads, sign in. Congratulations – you're all set! You now have a copy of freeCodeCamp's entire learning platform running on your local machine.
The API server serves endpoints at `http://localhost:3000`. The Gatsby app serves the client application at `http://localhost:8000`.
While you are logged in, if you visit <http://localhost:3000/explorer> you should see the available APIs.
> [!WARNING] Clearing your cookies or running `pnpm run seed:certified-user` will log you out, and you will have to sign in again.
If you have issues while installing it, check out the [troubleshooting section](troubleshooting-development-issues.md).
## Quick Commands Reference
A quick reference to the commands that you will need when working locally.
| command | description |
| ------------------------------ | ------------------------------------------------------------------------------------------------------------- |
| `pnpm install` | Installs / re-installs all dependencies and bootstraps the different services. |
| `pnpm run seed` | Creates authorized test users and inserts them into MongoDB. Also runs `seed:exams` and `seed:surveys` below. |
| `pnpm run seed:certified-user` | Creates authorized test users with certifications fully completed, and inserts them into MongoDB. |
| `pnpm run seed:exams` | Creates exams and inserts them into MongoDB. |
| `pnpm run seed:surveys` | Creates surveys for defaults users and inserts them into MongoDB. |
| `pnpm run develop` | Starts the freeCodeCamp API Server and Client Applications. |
| `pnpm run clean` | Uninstalls all dependencies and cleans up caches. |
@@ -1,499 +0,0 @@
Follow this guide for setting up the freeCodeCamp mobile app locally on your system. This is highly recommended if you want to contribute regularly.
Some of the contribution workflows – like fixing bugs in the codebase – need you to run the freeCodeCamp app locally.
## How to Prepare your Local Machine
Start by installing the prerequisite software for your operating system.
### Prerequisites
| Prerequisite | Version | Notes |
| --------------------------------- | ------- | ---------------------------------------- |
| [Flutter](https://flutter.dev/) | `3.x` | - |
| Dart (comes bundled with Flutter) | `3.x` | We use the version bundled with Flutter. |
> [!ATTENTION] If you have a different version, please install the recommended version. We can only support installation issues for recommended versions.
If Flutter is already installed on your machine, run the following commands to validate the versions:
```bash
flutter --version
dart --version
```
> [!TIP] We highly recommend updating to the latest stable releases of the software listed above.
Once you have the prerequisites installed, you need to prepare your development environment. This is common for many development workflows, and you will only need to do this once.
#### Follow these steps to get your development environment ready:
1. Install [Git](https://git-scm.com/) or your favorite Git client, if you haven't already. Update to the latest version; the version that came bundled with your OS may be outdated.
2. Set up [Android Studio](https://developer.android.com/studio) and [Android Emulators](https://developer.android.com/studio/run/managing-avds) with the latest released Android version. We recommend using the Pixel 3a XL and Nexus One(for emulating smaller screens).
3. (Optional for MacOS) Set up Xcode and iOS Simulator with the latest released iOS version.
4. (Optional but recommended) [Set up an SSH Key](https://help.github.com/articles/generating-an-ssh-key/) for GitHub.
5. Install a code editor of your choice.
We highly recommend using [Visual Studio Code](https://code.visualstudio.com/) or Android Studio. We also recommend installing the official [extensions](https://docs.flutter.dev/get-started/editor?tab=vscode).
## Fork the Repository on GitHub
[Forking](https://help.github.com/articles/about-forks/) is a step where you get your own copy of the repository (a.k.a _repo_) on GitHub.
This is essential, as it allows you to work on your own copy of the freeCodeCamp mobile app on GitHub, or to download (clone) your repository to work on locally. Later, you will be able to request changes to be pulled into the main repository from your fork via a pull request (PR).
> [!TIP] The main repository at `https://github.com/freeCodeCamp/mobile` is often referred to as the `upstream` repository.
>
> Your fork at `https://github.com/YOUR_USER_NAME/mobile` is often referred to as the `origin` repository. `YOUR_USER_NAME` would be replaced with your GitHub username.
**Follow these steps to fork the `https://github.com/freeCodeCamp/mobile` repository:**
1. Go to the freeCodeCamp mobile repository on GitHub: <https://github.com/freeCodeCamp/mobile>
2. Click the "Fork" Button in the upper right-hand corner of the interface ([More Details Here](https://help.github.com/articles/fork-a-repo/))
3. After the repository has been forked, you will be taken to your copy of the repository at `https://github.com/YOUR_USER_NAME/mobile` (`YOUR_USER_NAME` would be replaced with your GitHub user name.)
## Clone your Fork from GitHub
[Cloning](https://help.github.com/articles/cloning-a-repository/) is where you **download** a copy of a repository from a `remote` location that is either owned by you or by someone else. In your case, this remote location is your `fork` of freeCodeCamp's repository which should be available at `https://github.com/YOUR_USER_NAME/mobile`. (`YOUR_USER_NAME` would be replaced with your GitHub user name.)
Run these commands on your local machine:
1. Open a Terminal / Command Prompt / Shell in your projects directory
_i.e.: `/yourprojectsdirectory/`_
2. Clone your fork of freeCodeCamp, replacing `YOUR_USER_NAME` with your GitHub Username
```bash
git clone --depth=1 https://github.com/YOUR_USER_NAME/mobile.git
```
This will download the entire freeCodeCamp mobile repository to your projects directory.
Note: `--depth=1` creates a shallow clone of your fork, with only the most recent history/commit.
## Set up Syncing from Parent
Now that you have downloaded a copy of your fork, you will need to set up an `upstream` remote to the parent repository.
[As mentioned earlier](#fork-the-repository-on-github), the main repository is referred to as the `upstream` repository. Your fork is referred to as the `origin` repository.
You need a reference from your local clone to the `upstream` repository in addition to the `origin` repository. This is so that you can sync changes from the main repository without the requirement of forking and cloning repeatedly.
1. Change directory to the new `mobile` directory:
```bash
cd mobile
```
2. Add a remote reference to the main freeCodeCamp mobile repository:
```bash
git remote add upstream https://github.com/freeCodeCamp/mobile.git
```
3. Ensure the configuration looks correct:
```bash
git remote -v
```
The output should look something like below (replacing `YOUR_USER_NAME` with your GitHub username):
```bash
origin https://github.com/YOUR_USER_NAME/mobile.git (fetch)
origin https://github.com/YOUR_USER_NAME/mobile.git (push)
upstream https://github.com/freeCodeCamp/mobile.git (fetch)
upstream https://github.com/freeCodeCamp/mobile.git (push)
```
## Running freeCodeCamp Mobile App Locally
Now that you have a local copy of the mobile app, you can follow these instructions to run it locally.
If you do run into issues, first perform a web search for your issue and see if it has already been answered. If you cannot find a solution, please search our [GitHub issues](https://github.com/freeCodeCamp/mobile/issues) page for a solution and report the issue if it has not yet been reported.
And as always, feel free to ask questions on the ['Contributors' category on our forum](https://forum.freecodecamp.org/c/contributors) or [our chat server](https://discord.gg/PRyKn3Vbay).
> [!NOTE] The `mobile` directory contains two folders ie. `mobile-api` and `mobile-app`. `mobile-api` contains the API code used for serving the podcasts. `mobile-app` contains the Flutter app which is where you should be when you follow the below steps.
### Configuring Dependencies
#### Step 1: Set Up the Environment Variable File
The default API keys and environment variables are stored in the file `sample.env`. This file needs to be copied to a new file named `.env` which is accessed dynamically during the installation step. Remember to change the directory to `mobile-app` before running the following commands.
```bash
# Create a copy of the "sample.env" and name it ".env".
# Populate it with the necessary API keys and secrets:
```
#### **macOS/Linux**
```bash
cp sample.env .env
```
#### **Windows**
```bash
copy sample.env .env
```
The keys in the `.env` file are _not_ required to be changed to run the app locally. You can leave the default values copied over from `sample.env` as-is.
#### Step 2: Install dependencies
This step will install the dependencies required for the application to run:
```bash
flutter pub get
```
#### Step 3: Start the freeCodeCamp mobile app
Start the emulator of your choice(Android or iOS) and wait for the bootup process to complete.
You can now start the app by running the following command:
```bash
flutter run
```
> [!TIP] If you're using VSCode or Android Studio then you can easily start the app without having to execute any terminal commands. More information [here](https://docs.flutter.dev/get-started/test-drive).
## Making Changes Locally
You can now make changes to files and commit your changes to the local clone of your fork.
Follow these steps:
1. Validate that you are on the `main` branch:
```bash
git status
```
You should get an output like this:
```bash
On branch main
Your branch is up-to-date with 'origin/main'.
nothing to commit, working directory clean
```
If you are not on main or your working directory is not clean, resolve any outstanding files/commits and checkout `main`:
```bash
git checkout main
```
2. Sync the latest changes from the upstream `main` branch to your local main branch:
> [!WARNING] If you have any outstanding pull request that you made from the `main` branch of your fork, you will lose them at the end of this step.
>
> You should ensure your pull request is merged by a moderator before performing this step. To avoid this scenario, you should **always** work on a branch other than the `main`.
This step **will sync the latest changes** from the main repository of freeCodeCamp mobile. It is important that you rebase your branch on top of the latest `upstream/main` as often as possible to avoid conflicts later.
Update your local copy of the freeCodeCamp mobile upstream repository:
```bash
git fetch upstream
```
Hard reset your main branch with the freeCodeCamp mobile main:
```bash
git reset --hard upstream/main
```
Push your main branch to your origin to have a clean history on your fork on GitHub:
```bash
git push origin main --force
```
You can validate that your current main matches the upstream/main by performing a diff:
```bash
git diff upstream/main
```
The resulting output should be empty.
3. Create a fresh new branch:
Working on a separate branch for each issue helps you keep your local work copy clean. You should never work on the `main`. This will soil your copy of freeCodeCamp mobile and you may have to start over with a fresh clone or fork.
Check that you are on `main` as explained previously, and branch off from there:
```bash
git checkout -b fix/update-guide-for-xyz
```
Your branch name should start with a `fix/`, `feat/`, `docs/`, etc. Avoid using issue numbers in branches. Keep them short, meaningful, and unique.
Some examples of good branch names are:
```md
fix/update-challenges-for-react
fix/update-guide-for-html-css
fix/platform-bug-sign-in-issues
feat/add-guide-article-for-javascript
translate/add-spanish-basic-html
```
4. Edit pages and work on code in your favorite text editor.
5. Once you are happy with the changes you should optionally run the mobile app locally to preview the changes.
6. Make sure you fix any errors and check the formatting of your changes.
7. Check and confirm the files you are updating:
```bash
git status
```
This should show a list of `unstaged` files that you have edited.
```bash
On branch feat/documentation
Your branch is up to date with 'upstream/feat/documentation'.
Changes were not staged for commit:
(use "git add/rm <file>..." to update what will be committed)
(use "git checkout -- <file>..." to discard changes in the working directory)
modified: README.md
modified: mobile-app/lib/main.dart
...
```
8. Stage the changes and make a commit:
In this step, you should only mark files that you have edited or added yourself. You can perform a reset and resolve files that you did not intend to change if needed.
```bash
git add path/to/my/changed/file.ext
```
Or you can add all the `unstaged` files to the staging area:
```bash
git add .
```
Only the files that were moved to the staging area will be added when you make a commit.
```bash
git status
```
Output:
```bash
On branch feat/documentation
Your branch is up to date with 'upstream/feat/documentation'.
Changes to be committed:
(use "git reset HEAD <file>..." to unstage)
modified: README.md
modified: mobile-app/lib/main.dart
```
Now, you can commit your changes with a short message like so:
```bash
git commit -m "fix: my short commit message"
```
Some examples:
```md
fix: update guide article for Java - for loop
feat: add guide article for alexa skills
```
Optional:
We highly recommend making a conventional commit message. This is a good practice that you will see on some of the popular Open Source repositories. As a developer, this encourages you to follow standard practices.
Some examples of conventional commit messages are:
```md
fix: update HTML guide article
fix: update build scripts for Travis-CI
feat: add article for JavaScript hoisting
docs: update contributing guidelines
```
Keep these short, not more than 50 characters. You can always add additional information in the description of the commit message.
This does not take any additional time than an unconventional message like 'update file' or 'add index.md'
You can learn more about why you should use conventional commits [here](https://www.conventionalcommits.org/en/v1.0.0-beta.2/#why-use-conventional-commits).
9. If you realize that you need to edit a file or update the commit message after making a commit you can do so after editing the files with:
```bash
git commit --amend
```
This will open up a default text editor like `nano` or `vi` where you can edit the commit message title and add/edit the description.
10. Next, you can push your changes to your fork:
```bash
git push origin branch/name-here
```
## Running mobile curriculum tests
> [!NOTE] You only need to follow this section if you're modifying the challenge test runner in the mobile app. Otherwise, you can go to the next section on [how to open a pull request](#proposing-a-pull-request-pr).
1. Clone a copy of the [freeCodeCamp repo](https://github.com/freeCodeCamp/freeCodeCamp) locally outside of your local copy of the freeCodeCamp mobile repo. Your folder structure should look like this:
```bash
├── freeCodeCamp
├── mobile
```
2. Change the directory to the freeCodeCamp repo:
```bash
cd freeCodeCamp
```
3. Make a copy of the `.env` file:
#### **macOS/Linux**
```bash
cp sample.env .env
```
#### **Windows**
```bash
copy sample.env .env
```
4. Install the dependencies for the freeCodeCamp repo:
```bash
pnpm install && pnpm run create:shared
```
5. Generate the challenge data JSON file:
```bash
pnpm run build:curriculum
```
6. Copy the generated JSON file to the mobile app:
#### **macOS/Linux**
```bash
cp ./shared/config/curriculum.json ../mobile/mobile-app/curriculum.json
```
#### **Windows**
```bash
copy .\shared\config\curriculum.json ..\mobile\mobile-app\curriculum.json
```
7. Change directory to the mobile app:
```bash
cd ../mobile/mobile-app
```
8. Install the dependencies for the mobile app:
```bash
flutter pub get
```
9. Update the test file to use the challenge data JSON file:
```bash
sed -i '' 's/..\/..\/shared\/config\/curriculum.json/.\/curriculum.json/g' test/widget_test.dart
```
10. Generate the challenge files:
```bash
flutter test test/widget_test.dart
```
11. Start a local server to serve the challenge files with the help of `serve` package:
```bash
npx serve
```
12. In a different terminal go back to the freeCodeCamp repo:
```bash
cd ../../freeCodeCamp
```
13. Run the cypress tests:
```bash
pnpm cypress run --config retries=1,screenshotOnRunFailure=false,video=false,baseUrl=http://localhost:3000/generated-tests/,specPattern=cypress/e2e/mobile-learn/test-challenges.js -s cypress/e2e/mobile-learn/test-challenges.js -b chrome
```
## Proposing a Pull Request (PR)
After you've committed your changes, check here for [how to open a Pull Request](how-to-open-a-pull-request.md).
<!-- ## Quick commands reference - NEED TO DISCUSS ABOUT THIS
A quick reference to the commands that you will need when working locally.
| command | description |
| -------------------------------------------------------------- | ----------------------------------------------------------------------------------- |
| `npm ci` | Installs / re-install all dependencies and bootstraps the different services. |
| `npm run seed` | Parses all the challenge markdown files and inserts them into MongoDB. | -->
## Troubleshooting
### Issues with installing the recommended prerequisites
We regularly develop on the latest or most popular operating systems like macOS 10.15 or later, Ubuntu 18.04 or later, and Windows 10 (with WSL2).
It is recommended to research your specific issue on resources such as Google, Stack Overflow, and Stack Exchange. There is a good chance that someone has faced the same issue and there is already an answer to your specific query.
If you are on a different OS and/or are still running into issues, see [getting help](#getting-help).
### Issues with the UI, build errors, etc.
If you face issues with the UI, or build errors a cleanup can be useful:
```bash
flutter clean
```
### Issues Installing Dependencies
If you get errors while installing the dependencies, please make sure that you are not in a restricted network or that your firewall settings do not prevent you from accessing resources.
Be patient as the first-time setup can take a while depending on your network bandwidth.
## Getting Help
If you are stuck and need help, feel free to ask questions on the ['Contributors' category on our forum](https://forum.freecodecamp.org/c/contributors) or [the contributors chat room](https://discord.gg/PRyKn3Vbay).
There might be an error in the console of your browser or in Bash / Terminal / Command Line that will help identify the problem. Provide this error message in your problem description so others can more easily identify the issue and help you find a resolution.
@@ -1,224 +0,0 @@
# Set up freeCodeCamp on Windows Subsystem for Linux (WSL)
> [!NOTE] Before you follow these instructions make sure your system meets the requirements.
>
> **WSL 2**: Windows 10 64-bit (Version 2004, Build 19041 or higher) - available for all distributions including Windows 10 Home.
>
> **Docker Desktop for Windows**: See respective requirements for [Windows 10 Pro](https://docs.docker.com/docker-for-windows/install/#system-requirements) and [Windows 10 Home](https://docs.docker.com/docker-for-windows/install-windows-home/#system-requirements)
This guide covers some common steps with the setup of WSL2. Once some of the common issues with WSL2 are addressed, you should be able to follow [this local setup guide](how-to-setup-freecodecamp-locally.md) to work with freeCodeCamp on Windows running a WSL distro like Ubuntu.
## Enable WSL
Follow the instructions on the [official documentation](https://docs.microsoft.com/en-us/windows/wsl/install-win10) to install WSL2.
## Install Ubuntu
1. We recommended using Ubuntu-18.04 or above with WSL2.
> [!NOTE]
>
> While you may use other non-Debian-based distributions, they all come with their own 'gotchas' that are beyond the scope of this guide.
As of November 2023, Ubuntu and Debian are the only Linux distributions [officially supported by Playwright](https://playwright.dev/docs/intro#system-requirements), the end-to-end testing library used by freeCodeCamp.
2. Update the dependencies for the OS
```bash
sudo apt update
sudo apt upgrade -y
# cleanup
sudo apt autoremove -y
```
## Set up Git
Git comes pre-installed with Ubuntu 18.04, verify your Git version with `git --version`.
```output
~
❯ git --version
git version 2.25.1
```
(Optional but recommended) You can now proceed to [setting up your ssh keys](https://help.github.com/articles/generating-an-ssh-key) with GitHub.
## Installing a Code Editor
We highly recommend installing [Visual Studio Code](https://code.visualstudio.com) on Windows 10. It has great support for WSL and automatically installs all the necessary extensions on your WSL distribution.
Essentially, you will edit and store your code on Ubuntu-18.04 with VS Code installed on Windows.
If you use [IntelliJ Idea](https://www.jetbrains.com/idea/), you may need to update your Node interpreter and npm package manager to what is installed on your WSL distro.
You can check these settings by going to Settings > Languages & Frameworks > Node.js and npm.
## Installing Docker Desktop
**Docker Desktop for Windows** allows you to install and run databases like MongoDB and other services like NGINX and more. This is useful to avoid common pitfalls with installing MongoDB or other services directly on Windows or WSL2.
Follow the instructions on the [official documentation](https://docs.docker.com/docker-for-windows/install) and install Docker Desktop for your Windows distribution.
There are some minimum hardware requirements for the best experience.
## Configure Docker Desktop for WSL
Once Docker Desktop is installed, [follow these instructions](https://docs.docker.com/docker-for-windows/wsl) and configure it to use the Ubuntu-18.04 installation as a backend.
This makes it so that the containers run on the WSL side instead of running on Windows. You will be able to access the services over `http://localhost` on both Windows and Ubuntu.
## Install MongoDB from Docker Hub
Once you have configured Docker Desktop to work with WSL2, follow these steps to start a MongoDB service:
1. Launch a new Ubuntu terminal
2. Pull MongoDB from Docker Hub. Please refer to the [Prerequisites](how-to-setup-freecodecamp-locally.md#Prerequisites) table for the current version of MongoDB used by freeCodeCamp. For example, if the version number is `5.0.x`, replace `<x.y>` with `5.0` in the following two code snippets.
```bash
docker pull mongo:<x.y>
```
3. Start the MongoDB service at port `27017`, and configure it to run automatically on system restarts
```bash
docker run -it \
-v mongodata:/data/db \
-p 27017:27017 \
--name mongodb \
--restart unless-stopped \
-d mongo:<x.y>
```
4. You can now access the service from both Windows or Ubuntu at `mongodb://localhost:27017`.
## Installing Node.js and pnpm
We recommend you install the LTS release for Node.js with a node version manager - [nvm](https://github.com/nvm-sh/nvm#installing-and-updating).
Once installed use this command to install and use the latest Node.js LTS version:
```bash
nvm install --lts
```
For instructions on installing and using a different version of Node.js, please refer to the [nvm docs](https://github.com/nvm-sh/nvm#usage).
Node.js comes bundled with `npm`, which you can use to install `pnpm`:
```bash
npm install -g pnpm
```
## Set up freeCodeCamp Locally
Now that you have installed the pre-requisites, follow [our local setup guide](how-to-setup-freecodecamp-locally.md) to clone, install and set up freeCodeCamp locally on your machine.
> [!WARNING]
>
> Please note, at this time the setup for Cypress tests (and related GUI needs) is a work in progress. You should still be able to work on most of the codebase.
## Optimize Windows and WSL
> [!NOTE]
>
> The following tips were collected from across the web and have not gone through vigorous testing. Your mileage may vary.
### Adjust processor scheduling for background services
This may reduce incidents of Docker containers crashing due to lack of resources.
Open the System Properties control panel by pressing <kbd>Win + R</kbd> and entering `sysdm.cpl`
<details>
<summary>
Enter <code>sysdm.cpl</code> in the Run dialog (screenshot)
</summary>
<br>
<img src="https://raw.githubusercontent.com/freeCodeCamp/freeCodeCamp/main/docs/images/wsl/run-sysdm.png" alt="Enter `sysdm.cpl` in the Run dialog" />
</details>
<br>
Go to Advanced -> Performance -> Settings…
<details>
<summary>
Performance Settings button under Advanced tab in System Properties (screenshot)
</summary>
<br>
<img src="https://raw.githubusercontent.com/freeCodeCamp/freeCodeCamp/main/docs/images/wsl/advanced-performance-settings.png" alt="Performance Settings button under Advanced tab in System Properties" />
</details>
<br>
Under Advanced -> Processor scheduling, choose "Background services". Do not close the window. Continue to the next tip.
<details>
<summary>
Background services radio button under Advanced tab in Performance Options (screenshot)
</summary>
<br>
<img src="https://raw.githubusercontent.com/freeCodeCamp/freeCodeCamp/main/docs/images/wsl/background-services.png" alt="Background services radio button under Advanced tab in Performance Options" />
</details>
### Increase the size of Windows paging file for the system drive
Under Advanced -> Virtual memory, click "Change…"
<details>
<summary>
Change virtual memory button under Advanced tab in Performance Options (screenshot)
</summary>
<br>
<img src="https://raw.githubusercontent.com/freeCodeCamp/freeCodeCamp/main/docs/images/wsl/advanced-virtual-memory.png" alt="Change virtual memory button under Advanced tab in Performance Options" />
</details>
<br>
Choose "Custom size". Set the initial size to 1.5x and the maximum size to 3x of your physical memory. Then click "Set".
<details>
<summary>
Set custom size button in Virtual Memory window (screenshot)
</summary>
<br>
<img src="https://raw.githubusercontent.com/freeCodeCamp/freeCodeCamp/main/docs/images/wsl/set-custom-size.png" alt="Set custom size button in Virtual Memory window" />
</details>
### Increase the size of memory allocated to WSL
Create a [`.wslconfig` file](https://learn.microsoft.com/en-us/windows/wsl/wsl-config#configuration-setting-for-wslconfig) in your [`%UserProfile%` directory](https://learn.microsoft.com/en-us/windows/wsl/wsl-config#wslconfig) (typically `C:\Users\<UserName>\.wslconfig`). Please read the [WSL documentation](https://learn.microsoft.com/en-us/windows/wsl/wsl-config#configuration-setting-for-wslconfig) carefully and replace `x` with values that suit your own needs:
```ini
# Settings apply across all Linux distros running on WSL 2
[wsl2]
# How much memory to assign to the WSL 2 VM. The default value might not be enough
memory=xGB
# How much swap space to add to the WSL 2 VM, default is 25% of available RAM
swap=xGB
```
### Increase Node.js max old space size
This fixes the ["JavaScript heap out of memory" error](https://stackoverflow.com/a/54456814) with ESLint. Add the following to your `~/.bashrc` or `~/.zshrc`:
```sh
export NODE_OPTIONS="--max-old-space-size=4096"
```
### Avoid `pnpm run test`
Instead, use the script [appropriate to your PR](https://forum.freecodecamp.org/t/wsl-performance-issues-while-working-on-the-codebase/644215/2#:~:text=usually%2C%20you%20just%20want%20to%20test%20something%20specific%20to%20either%20the%20curriculum%20or%20the%20client%20or%20the%20api%20-%20almost%20never%20all%203.); either `pnpm run test:api`, `pnpm run test:curriculum`, or `pnpm run test-client`.
## Useful Links
- [A WSL2 Dev Setup with Ubuntu 20.04, Node.js, MongoDB, VS Code, and Docker](https://hn.mrugesh.dev/wsl2-dev-setup-with-ubuntu-nodejs-mongodb-and-docker) - an article by Mrugesh Mohapatra (Staff Developer at freeCodeCamp.org)
- Frequently asked questions on:
- [Windows Subsystem for Linux](https://docs.microsoft.com/en-us/windows/wsl/faq)
- [Docker Desktop for Windows](https://docs.docker.com/docker-for-windows/faqs)
@@ -1,222 +0,0 @@
# How to Test Translations Locally
> [!NOTE] This process is not required, but documented in case you would like to preview what your translations will look like.
If you would like to test your translations on a local instance of the freeCodeCamp `/learn` site, first ensure you have [set up the codebase](how-to-setup-freecodecamp-locally.md).
## Enabling a Language
There are a few steps to take in order to allow the codebase to build in your desired language.
First, visit the `config/i18n/all-langs.ts` file to add the language to the available languages list and configure the values. There are four objects here.
- `availableLangs`: For both the `client` and `curriculum` arrays, add the text name of the language. This is the value that will be used in the `.env` file later.
- `auditedCerts`: Add the text name of the language as the _key_, and add an array of `SuperBlocks.{cert}` variables as the _value_. This tells the client which certifications are fully translated.
- `i18nextCodes`: These are the ISO language codes for each language. You will need to add the appropriate ISO code for the language you are enabling. These do need to be unique for each language.
- `LangNames`: These are the display names for the language selector in the navigation menu.
- `LangCodes`: These are the language codes used for formatting dates and numbers. These should be Unicode CLDR codes instead of ISO codes.
As an example, if you wanted to enable Dothraki as a language, your `all-langs.js` objects should look like this:
```js
export const availableLangs = {
client: ['english', 'espanol', 'chinese', 'chinese-traditional', 'dothraki'],
curriculum: [
'english',
'espanol',
'chinese',
'chinese-traditional',
'dothraki'
]
};
export const auditedCerts = {
espanol: [
SuperBlocks.RespWebDesign,
SuperBlocks.JsAlgoDataStruct,
SuperBlocks.FrontEndDevLibs,
SuperBlocks.DataVis,
SuperBlocks.BackEndDevApis
],
chinese: [
SuperBlocks.RespWebDesign,
SuperBlocks.JsAlgoDataStruct,
SuperBlocks.FrontEndDevLibs,
SuperBlocks.DataVis,
SuperBlocks.BackEndDevApis,
SuperBlocks.QualityAssurance,
SuperBlocks.SciCompPy,
SuperBlocks.DataAnalysisPy,
SuperBlocks.InfoSec,
SuperBlocks.MachineLearningPy
],
'chinese-traditional': [
SuperBlocks.RespWebDesign,
SuperBlocks.JsAlgoDataStruct,
SuperBlocks.FrontEndDevLibs,
SuperBlocks.DataVis,
SuperBlocks.BackEndDevApis,
SuperBlocks.QualityAssurance,
SuperBlocks.SciCompPy,
SuperBlocks.DataAnalysisPy,
SuperBlocks.InfoSec,
SuperBlocks.MachineLearningPy
],
dothraki: [
SuperBlocks.RespWebDesign,
SuperBlocks.JsAlgoDataStruct,
SuperBlocks.FrontEndDevLibs
]
};
export const i18nextCodes = {
english: 'en',
espanol: 'es',
chinese: 'zh',
'chinese-traditional': 'zh-Hant',
dothraki: 'mis'
};
export enum LangNames = {
english: 'English',
espanol: 'Español',
chinese: '中文(簡體字)',
'chinese-traditional': '中文(繁體字)',
dothraki: 'Dothraki'
};
export enum LangCodes = {
english: 'en-US',
espanol: 'es-419',
chinese: 'zh',
'chinese-traditional': 'zh-Hant',
dothraki: 'mis'
};
```
Next, open the `client/src/utils/algolia-locale-setup.ts` file. This data is used for the search bar that loads `/news` articles. While it is unlikely that you are going to test this functionality, missing the data for your language can lead to errors when attempting to build the codebase locally.
Add an object for your language to the `algoliaIndices` object. You should use the the same values as the `english` object for local testing, replacing the `english` key with your language's `availableLangs` value.
> [!NOTE] If we have already deployed an instance of news in your target language, you can update the values to reflect the live instance. Otherwise, use the English values.
If you were to add Dothraki:
```js
const algoliaIndices = {
english: {
name: 'news',
searchPage: 'https://www.freecodecamp.org/news/search/'
},
espanol: {
name: 'news-es',
searchPage: 'https://www.freecodecamp.org/espanol/news/search/'
},
chinese: {
name: 'news-zh',
searchPage: 'https://chinese.freecodecamp.org/news/search/'
},
'chinese-traditional': {
name: 'news-zh',
searchPage: 'https://chinese.freecodecamp.org/news/search'
},
dothraki: {
name: 'news',
searchPage: 'https://www.freecodecamp.org/news/search/'
}
};
```
Finally, in your `.env` file, set `CLIENT_LOCALE` and `CURRICULUM_LOCALE` to your new language (use the `availableLangs` value.)
```txt
CLIENT_LOCALE=dothraki
CURRICULUM_LOCALE=dothraki
```
### Releasing a Superblock
After a superblock has been fully translated into a language, there are two steps to release it. First add the superblock enum to that language's `auditedCerts` array. So, if you want to release the new Responsive Web Design superblock for Dothraki, the array should look like this:
```ts
export const auditedCerts = {
// other languages
dothraki: [
SuperBlocks.RespWebDesignNew, // the newly translated superblock
SuperBlocks.RespWebDesign,
SuperBlocks.JsAlgoDataStruct,
SuperBlocks.FrontEndDevLibs
]
```
Finally, the `languagesWithAuditedBetaReleases` array should be updated to include the new language like this:
```ts
export const languagesWithAuditedBetaReleases: ['english', 'dothraki'];
```
This will move the new superblock to the correct place in the curriculum map on `/learn`.
## Enabling Localized Videos
For the video challenges, you need to change a few things. First add the new locale to the GraphQL query in the `client/src/templates/Challenges/video/Show.tsx` file. For example, adding Dothraki to the query:
```tsx
query VideoChallenge($slug: String!) {
challengeNode(fields: { slug: { eq: $slug } }) {
videoId
videoLocaleIds {
espanol
italian
portuguese
dothraki
}
...
```
Then add an id for the new language to any video challenge in an audited block. For example, if `auditedCerts` in `all-langs.ts` includes `scientific-computing-with-python` for `dothraki`, then you must add a `dothraki` entry in `videoLocaleIds`. The frontmatter should then look like this:
```yml
videoLocaleIds:
espanol: 3muQV-Im3Z0
italian: hiRTRAqNlpE
portuguese: AelGAcoMXbI
dothraki: new-id-here
dashedName: introduction-why-program
---
```
Update the `VideoLocaleIds` interface in `client/src/redux/prop-types` to include the new language.
```ts
export interface VideoLocaleIds {
espanol?: string;
italian?: string;
portuguese?: string;
dothraki?: string;
}
```
And finally update the challenge schema in `curriculum/schema/challengeSchema.js`.
```js
videoLocaleIds: Joi.when('challengeType', {
is: challengeTypes.video,
then: Joi.object().keys({
espanol: Joi.string(),
italian: Joi.string(),
portuguese: Joi.string(),
dothraki: Joi.string()
})
}),
```
## Loading Translations
Because the language has not been approved for production, our scripts are not automatically downloading the translations yet. Only staff have the access to directly download the translations - you are welcome to reach out to us in our [contributors chat room](https://discord.gg/PRyKn3Vbay), or you can translate the English markdown files locally for testing purposes.
Once you have the files, you will need to place them in the correct directory. For the curriculum challenges, you should place the certification folders (i.e. `01-responsive-web-design`) within the `curriculum/challenges/{lang}` directory. For our Dothraki translations, this would be `curriculum/challenges/dothraki`. The client translation `.json` files will go in the `client/i18n/locales/{lang}` directory.
Once these are in place, you should be able to run `npm run develop` to view your translated version of freeCodeCamp.
> [!ATTENTION] While you may perform translations locally for the purpose of testing, we remind everyone that translations should _not_ be submitted through GitHub and should only be done through Crowdin. Be sure to reset your local codebase after you are done testing.
@@ -1,337 +0,0 @@
# 如何翻譯 freeCodeCamp 的資源
## Prepare yourself for Contributions
> The freeCodeCamp Localization Roadmap – There Are No Speed Limits
> [!TIP] You can start by reading [this announcement](https://www.freecodecamp.org/news/help-translate-freecodecamp-language/). We recommend joining [our community forum](https://forum.freecodecamp.org/c/contributors/3) and [Discord chat server](https://discord.gg/PRyKn3Vbay).
You can translate as much as you want, when you want. It's only a matter of how much time and energy you are willing to invest as a volunteer translator.
We just ask that you understand the following:
1. **翻譯是一件團隊協作的事情。**
翻譯 freeCodeCamp 的資源是對貢獻者來說最有趣和最有意義的經歷之一。如果你邀請與你使用同一種語言的朋友和同事參與,那麼效果最好。
You can start by reading [this announcement](https://www.freecodecamp.org/news/help-translate-freecodecamp-language/). We recommend joining [our community forum](https://forum.freecodecamp.org/c/contributors/3) and [Discord chat server](https://discord.gg/PRyKn3Vbay) with your friends and showing your interest before starting off with translations. Crowdin and other tools make it easy to contribute translations, but it's still a lot of work.
我們希望你在貢獻過程感到快樂,而不是感到疲憊,然後失去興趣。
如果你們有一個四到五人的小組,就可以開始翻譯一種新的語言了。 你可以再招募更多的朋友來加入這個隊伍。
2. **爲每種語言版本提供服務器,需要較高的成本。**
表面上來看,技術棧可能看起來沒那麼複雜,但是實際上消耗了很多資源來讓引擎跑起來。 這包括提供額外的服務器和專職人員來管理它們。
freeCodeCamp.org is committed to providing these for free as always, however we need to prioritize resources for those who need them the most. 我們非常不想看到某種語言的翻譯活動結束了,並且內容過時了,然後我們不得不關閉相應的服務器。
For translating the curriculum, once a language reaches at least a few certifications we can begin deploying the language live on [`/learn`](https://www.freecodecamp.org/learn), while you continue to translate the remaining certifications.
舉個例子, 當我們正式上線一個新的語言版本的時候,我們希望至少上線整個前端認證的內容。
3. **但是,如果一種語言沒有在翻譯平臺上列出來,怎麼辦呢?**
我們已經查看了我們的用戶羣,並且在翻譯平臺的可用語言列表上添加了三十多種的常用語言。 有一些語言,例如中文和西班牙語,已經在 **"/learn"** 上線了。
然而遺憾的是,這個語言列表並沒有涵蓋所有的世界語言。 我們每天都能收到許多像你一樣的貢獻者的需求, 希望將我們的資源翻譯成他們的語言。
我們當然希望在這個列表上增加更多的語言種類, 但是你可能已經猜到了, 假如我們有足夠的人來翻譯某一語言才能讓這件事變得實際。
假如你希望我們增加某一種新的語言, 我們建議你鼓動你的朋友一起來參與貢獻。
如果你們有一個組的人(至少四到五人)對某一種語言感興趣,並且承諾翻譯這種語言, 那麼我們可以在翻譯平臺上增加這種語言。 我們會解釋一切的細節,並且幫助你掌握這些翻譯工具和理解這些翻譯的過程。
## Overview of Crowdin
It's our dream to provide you with the resources to learn, no matter the world language you speak. To help us with this massive effort, we have integrated our open-source codebase & curriculum with [Crowdin](https://crowdin.com/) - A tool to help us localize our code-base.
> [!NOTE] We use a different tool and workflow for translating [news articles](https://www.freecodecamp.org/news). If you are interested in translating articles, read [this announcement](https://www.freecodecamp.org/news/help-translate-freecodecamp-language/) and reach out to your Language Lead.
The translation workflow is split into two main activities:
- **翻譯**課程文件、文檔和 UI 元素(如按鈕、標籤):
譯者可以在[我們的翻譯平臺](https://translate.freecodecamp.org)註冊,然後從 30+ 種語言版本中選擇要參與貢獻的版本,進行翻譯。
- **校對**上述翻譯。
校對者確認社區成員貢獻的譯文語調一致,沒有錯別字等常見問題。 簡而言之,校對者需要確保譯文是高質量的。 注意,我們不使用任何機器翻譯。
> [!WARNING] We are no longer using GitHub to translate files directly, if you are a returning contributor head to our [translation platform](https://translate.freecodecamp.org/) instead.
## Getting Started
First, make sure you come say "Hi" in our [Discord](https://discord.gg/PRyKn3Vbay). 我們會在聊天室定期更新翻譯的資源和回答很多問題。
其次,去我們的[翻譯平臺](https://translate.freecodecamp.org/)並且登陸(假如你以前沒有貢獻翻譯過,你需要創建一個新賬戶)。
最後,瀏覽下面提供的細節圖來理解怎麼使用翻譯工具和流程。
祝你在翻譯過程中感到快樂哦!
## Select a Project and File
當你訪問翻譯平臺,你應該可以看到很多不同的等待翻譯的項目:
1. [貢獻文檔](https://translate.freecodecamp.org/contributing-docs)項目,其中包含此文檔站點的文件。
2. [編程課程](https://translate.freecodecamp.org/curriculum)項目,其中包含我們課程的挑戰文件。
3. [學習用戶界面](https://translate.freecodecamp.org/learn-ui)項目,其中包含我們學習平臺的按鈕、標籤等 UI 元素的字符串。
選擇你想參與的任何項目,你將看到可供翻譯的語言列表。
![圖片 - 可翻譯語言版本列表](https://contribute.freecodecamp.org/images/crowdin/languages.png)
選擇你要使用的語言,你將看到完整的文件樹。
![圖片 - 可翻譯文件列表](https://contribute.freecodecamp.org/images/crowdin/file-tree.png)
每個文件和文件夾都會顯示一個進度條。 進度條的**藍色**部分表示多少百分比的文件已經被翻譯了,而**綠色**部分表示多少百分比的文件已經被校對團隊審覈確認。
選擇你想翻譯的文件,然後 Crowdin 會打開編輯界面。
> [!NOTE] When the editor view opens, you will need to click the settings icon (shown as a gear) and switch the 'HTML tags displaying' setting to 'SHOW'. This will ensure you can see tags such as `<code></code>` instead of `<0></0>`.
## Translate Curriculum
![圖片 - 編輯界面](https://contribute.freecodecamp.org/images/crowdin/editor.png)
Crowdin 將文檔分成可翻譯的“字符串”,通常是句子。 每個字符串都被單獨翻譯。 參考上圖:
1. 以綠色標示的字符串已經有了一個建議的翻譯。
2. 以紅色標示的字符串_沒有_建議的翻譯。
3. 帶有灰色文本的字符串不可翻譯。 對於代碼塊和其他必須不被翻譯的內容,就是這種情況。 你將無法在編輯器中選擇這些字符串。
4. 如果某位貢獻者對某個字符串有建議的譯文,那麼 Crowdin 將在此處顯示所有的建議。 你無法保存相同的譯文。如果某個譯文是正確的,那麼你可以點擊 `+` 圖標,給它投票表示贊同。 如果你覺得某個譯文不正確,那麼你可以點擊 `-` 圖標,投反對票。
5. Crowdin 將基於翻譯記憶(TM)或機器翻譯(MT)推薦譯文。 翻譯記憶是指我們已在其他文件中翻譯過/批准過的相似的或相同的字符串。 機器翻譯是指由 Crowdin 系統推薦的翻譯。
6. 這是編輯器窗口,你可以在其中輸入你對於所選字符串建議的譯文。
7. 編輯窗口當前選中的字符串將被標註爲黃色。
8. 這裏的標籤是表示字符串的狀態。 `Done` 標籤表示字符串有至少一個建議的譯文。 `Todo` 標籤表示字符串還沒有建議的譯文。
9. 這裏是評論窗口。 如果你對某個字符串有疑問或疑慮,可以在此處對字符串發表評論,以便其他翻譯人員查看。
10. 點擊這兩個“窗格”按鈕,可以隱藏左邊的(文件)視圖和右邊的(評論)視圖。
> [!NOTE] If you see a hidden string that includes translations, please notify us in the [Discord](https://discord.gg/PRyKn3Vbay) so we can remove the translation from memory.
當你翻譯完一個字符串,請點擊 `Save` 按鈕,將你的譯文保存在 Crowdin 中。 然後其他貢獻者可以給你的譯文投票,而校對者也將審覈確認你的譯文。
你想翻譯多少字符串,都可以,我們非常歡迎你貢獻!當你翻譯完某個文件或某個字符串之後,你不需要採取其他步驟。 你只需要點擊 `Save` 按鈕,就能保存你的譯文了。
> [!NOTE] If you see something in the English source file that is inaccurate or incorrect, please do not fix it through the translation flow. Instead, leave a comment on the string to notify us that there is a discrepancy, or create a GitHub issue.
## Translate the Learn Interface
Our `/learn` interface relies on JSON files loaded into an i18n plugin to generate translated text. This translation effort is split across both Crowdin and GitHub.
### On GitHub
The `links.json`, `meta-tags.json`, `motivation.json`, and `trending.json` files contain information that needs to be updated to reflect your language. However, we cannot load these into Crowdin, as the content isn't something that would be a one-to-one translation.
These files will most likely be maintained by your language lead but you are welcome to [read about how to translate them](language-lead-handbook.md).
### On Crowdin
> [!ATTENTION] Do not edit the following files through a GitHub PR.
The `intro.json` and `translations.json` files are both translated on Crowdin, in the Learn User Interface project. Translating these can be a bit tricky, as each individual JSON value appears as its own string and sometimes the context is missing.
However, the `Context` information provided in Crowdin can help understand where the string fits in to the larger structure.
![Image with an arrow pointing to Crowdin's context information](https://contribute.freecodecamp.org/images/crowdin/context.png)
If you have any questions about where a string fits in to the prose, reach out to us in our [contributor chat](https://discord.gg/PRyKn3Vbay).
## Translate Documentation
Translating our contributing documentation is a similar flow to translating our curriculum files.
> [!NOTE] Our contributing documentation is powered by `docsify`, and we have special parsing for message boxes like this one. If you see strings that start with `[!NOTE]`, `[!WARNING]`, or `[!TIP]`, these words should NOT be translated.
### How to Translate Documentation with Internal Links
When you work on translating contributing documentation, watch out for internal links targeting a different section of the documentation.
Make sure to replace the id of the target section (the part after `#`) with the id on the translated document. For example, it will look like this in Japanese:
Before translation
```
// in HTML
<a href="target-file-name.md#target-section-heading-id">Link text</a>
<a href="#target-section-heading-id">Link text</a>
// in Markdown
[Link text](target-file-name.md#target-section-heading-id)
[Link text](#target-section-heading-id)
```
After translation
```
// in HTML
<a href="target-file-name.md#翻訳後の-id">翻訳後のリンクテキスト</a>
<a href="#翻訳後の-id">翻訳後のリンクテキスト</a>
// in Markdown
[翻訳後のリンクテキスト](target-file-name.md#翻訳後の-id)
[翻訳後のリンクテキスト](#翻訳後の-id)
```
The actual files in docs are written in Markdown, but they will appear as HTML tags on Crowdin.
You can find out how `docsify` converts a string in your language into an id by looking into the translated pages. If the translation is not deployed yet, you can preview it by [running the docs site locally](how-to-work-on-the-docs-theme.md#serving-the-documentation-site-locally).
You can learn more about [internal links in our docs here](how-to-work-on-the-docs-theme.md#how-to-create-an-internal-link).
## Translate the LearnToCode RPG
The LearnToCode RPG runs on Ren'Py, which uses special syntax for translated strings: (See [Ren'Py Text documentation](https://www.renpy.org/doc/html/text.html))
- The sentences to be translated are always between `""`. These are dialogues or UI strings. The keywords that come before or after the dialogue are game engine control keywords and will be explained in details in subsequent rules. Please note that this first rule governs all subsequent rules listed.
- In case of `new "..."` Do not translate the `new` keyword.
- Prefixes like `player`, `annika`, `layla`, `marco` (or variants like `player happy`, `player @ happy`) should not be translated. These are control keywords to correctly display the character sprite in the game.
- Postfixes like `nointeract` should not be translated.
- Do not translate things between `[]` and `{}`. These are variable interpolations and text tags. These must remain halfwidth parentheses `[]` and `{}` instead of their fullwidth counterparts `【】` and `「」`
- Do not translate the `nointeract` keyword at the end of the sentence.
- If we try to use fullwidth parentheses `()`, a QA warning will show. To avoid the QA warning, use halfwidth parentheses `()`
### Examples
---
#### Before translation
```renpy
# "[player_name]? What a coincidence! Our VIP team member {a=[vip_profile_url]}[player_name]{/a} will be honored to hear that."
"[player_name]? What a coincidence! Our VIP team member {a=[vip_profile_url]}[player_name]{/a} will be honored to hear that." <--- this is the line that needs to be translated. see translation below
```
#### After translation
```renpy
# "[player_name]? What a coincidence! Our VIP team member {a=[vip_profile_url]}[player_name]{/a} will be honored to hear that."
"[player_name]?好巧,我們的VIP隊友{a=[vip_profile_url]}[player_name]{/a}會很高興的。"
```
Note: The `[]` and `{}` tags should be left intact.
---
#### Before translation
```renpy
old "{icon=icon-fast-forward} Skip"
new "{icon=icon-fast-forward} Skip" <-- translate this line, see below
```
#### After translation
```renpy
old "{icon=icon-fast-forward} Skip"
new "{icon=icon-fast-forward} 跳過"
```
Note: Again, the `new` prefix and the `{icon=icon-fast-forward}` tag should be left intact.
---
#### Before translation
```renpy
# layla @ neutral "Hehe, [player_name], you are a fun one. I'm sure you will enjoy your work as a developer."
layla @ neutral "Hehe, [player_name], you are a fun one. I'm sure you will enjoy your work as a developer."
```
#### After translation
```renpy
# layla @ neutral "Hehe, [player_name], you are a fun one. I'm sure you will enjoy your work as a developer."
layla @ neutral "哈哈,[player_name],你真有趣。我相信你一定會喜歡你的開發者工作的。"
```
Note: `layla @ neutral` and `[player_name]` are left unchanged.
---
#### Before translation
```renpy
# player "Maybe this is all a dream?" nointeract
player "Maybe this is all a dream?" nointeract
```
#### After translation
```renpy
# player "Maybe this is all a dream?" nointeract
player "也許這都是一場夢?" nointeract
```
---
### A Note on How Crowdin Segments a Sentence
Pay attention to how Crowdin segments a line of dialogue wrapped between opening and closing quotes `""`. When we are translating the dialogue, we need to make sure to retain the opening and closing quotes, even if the quotes appear in different segments.
This is the line to be translated:
```renpy
player @ surprised "{b}Full-stack{/b}... What is that? I better take notes so I can learn more about it."
```
Crowdin segments it into three parts like below:
<img width="836" alt="Screen Shot 2022-01-23 at 10 36 43" src="https://user-images.githubusercontent.com/35674052/150693962-d3b091e5-2432-44d0-9d24-195ea7d7aeda.png" />
```renpy
# original
player @ surprised "{b}Full-stack{/b}
# translated, keeping the opening quotes `"`
player @ surprised "{b}全棧{/b}
```
<img width="750" alt="Screen Shot 2022-01-23 at 10 36 49" src="https://user-images.githubusercontent.com/35674052/150693965-15411504-791a-4db3-8b14-bc9177be6375.png" />
```renpy
# original
What is that?
# translated, no quotes on either side
這是什麼?
```
<img width="857" alt="Screen Shot 2022-01-23 at 10 36 54" src="https://user-images.githubusercontent.com/35674052/150693969-062e3268-580f-4ad2-97db-cab6240b6095.png" />
```renpy
# original
I better take notes so I can learn more about it."
# translated, keeping the closing quotes `"`
我最好做筆記,這樣我可以學習更多東西。"
```
## Rate Translations
Crowdin allows you to rate the existing proposed translations. If you attempt to save a translation, you may see a message indicating that you cannot save a duplicate translation - this means another contributor has proposed that identical translation. If you agree with that translation, click the `+` button to "upvote" the translation.
If you see a translation that is inaccurate or does not provide the same clarity as the original string, click the `-` button to "downvote" the translation.
Crowdin uses these votes to give a score to each proposed translation for a string, which helps the proofreading team determine which translation is the best fit for each string.
## Quality Assurance Checks
We have enabled some quality assurance steps that will verify a translation is as accurate as possible - this helps our proofreaders review proposed translations.
When you attempt to save a translation, you may see a warning message appear with a notification regarding your proposed translation.
![Image - QA Warning Message](https://contribute.freecodecamp.org/images/crowdin/qa-message.png)
This message appears when Crowdin's QA system has identified a potential error in the proposed translation. In this example, we have modified the text of a `<code>` tag and Crowdin has caught that.
> [!WARNING] You have the option to save a translation in spite of errors. If you do, by clicking "Save Anyway", you should also tag a proofreader or project manager and explain why the QA message needs to be ignored in this case.
## Translation Best Practices
Follow these guidelines to ensure our translations are as accurate as possible:
- Do not translate the content within `<code>` tags. These tags indicate text that is found in code and should be left in English.
- Do not add additional content. If you feel a challenge requires changes in the text content or additional information, you should propose the changes through a GitHub issue or a pull request that modifies the English file.
- Do not change the order of content.
If you have any questions, feel free to reach out to us in our [Discord](https://discord.gg/PRyKn3Vbay) and we will be happy to assist you.
@@ -1,200 +0,0 @@
The client/react side of our website is translated into various world languages using [react-i18next](https://react.i18next.com/) and [i18next](https://www.i18next.com/).
> [!NOTE] Curriculum lesson content is [translated separately](./how-to-translate-files.md).
## File Structure
The files for translating the website are located in the `client/i18n` folder. Each language has a folder within that containing JSON files with the translations.
The values in the `translations.json` file contain the majority of the text that appears on the website. The keys are used in the codebase to get the correct text for whatever language is set. This file needs to have the exact same keys in all languages.
The `intro.json` file contains the key-value pairs for the introduction text on the certification pages.
The `motivation.json` files are not required to have the same quotes, compliments, or array length. Just the same JSON structure. These are not translated via Crowdin.
The `trending.json` file contians the titles and links for the trending news articles in the website's footer. These are not translated via Crowdin.
The `meta-tags.json` file contains the information for our website's meta tag information. These are not translated via Crowdin.
## Adding a Language
To add a new language, create a folder with the language name as the title next to the other languages and copy the JSON files from another language into your new folder.
In the `all-langs.js` file, add the language to the `client` array in the first variable. Then, follow the instructions in the comments to add the rest of the necessary variables.
## How to Translate
Translating the `intro.json` and `translations.json` are done through [our translation site](https://translate.freecodecamp.org). View our [translation documentation for that site](/how-to-translate-files.md).
Modifications to the `trending.json`, `meta-tags.json`, and `motivation.json` files should typically only be done by staff.
## Running it Locally
Set the `CLIENT_LOCALE` variable in your `.env` file to the locale you want to build.
> [!NOTE] The value needs to be one of the client languages available in `config/i18n/all-langs.js`
## How to Structure Components
### Functional Component
```js
import { useTranslation } from 'react-i18next';
// in the render method:
const { t } = useTranslation();
// call the "t" function with a key from the JSON file:
<p>{t('key')}</p> // more details below
```
### Class Component
```js
import { withTranslation } from 'react-i18next';
// withTranslation adds the "t" function to props:
const { t } = this.props;
// call the "t" function with a key from the JSON file:
<h1>{t('key')}</h1> // more details below
// export without redux:
export default withTranslation()(Component);
// or with redux:
export default connect(...)(withTranslation()(Component));
```
## Translate Using the "t" Function
### Basic Translation
```js
// in the component:
<p>{t('p1')}</p>
// in the JSON file:
{
"p1": "My paragraph"
}
// output:
<p>My paragraph</p>
```
### With Dynamic Data
```js
// in the component:
const username = 'moT';
<p>{t('welcome', { username: username })}</p>
// in the JSON file:
{
"welcome": "Welcome {{username}}"
}
// output:
<p>Welcome moT</p>
```
The above example passes an object to the `t` function with a `username` variable. The variable will be used in the JSON value where `{{username}}` is.
## Translate with the `Trans` Component
The general rule is to use the "t" function when you can. But there's a `Trans` component for when that isn't enough, usually when you have elements embedded in the text. You can use the `Trans` component with any type of react component.
### Basic Elements Nested
```js
// in the component:
import { Trans } from 'react-i18next'
<p>
<Trans>fcc.greeting</Trans>
</p>
// in the JSON file:
{
"fcc": {
"greeting": "Welcome to <strong>freeCodeCamp</strong>"
}
}
// output:
<p>Welcome to <strong>freeCodeCamp</strong></p>
```
You can place the key inside the component tags like the above example if the text contains "simple" tags with no attributes. `br`, `strong`, `i`, and `p` are the default, but that list can be expanded in the i18n config.
### Complex Elements Nested
Other times, you will want to have certain text inside another element, an anchor tag is a good example:
```js
// in the component:
<p>
<Trans i18nKey='check-forum'>
<a href='https://forum.freecodecamp.org/'>placeholder</a>
</Trans>
</p>
// in the JSON file:
{
"check-forum": "Check out <0>our forum</0>."
}
// output:
<p>Check out <a href='https://forum.freecodecamp.org/'>our forum</a></p>
```
In the above example, the key is set in the attributes of the `Trans` component. The `<0>` and `</0>` in the JSON represent the first child of the component, in this case, the anchor element. If there were more children, they would just count up from there using the same syntax. You can find the children of a component in the react dev tools by inspecting it. `placeholder` is simply there because the linter was complaining at me about an empty `<a>` element.
### With a Variable
```js
// in the component:
const email = 'team@freecodecamp.org';
<p>
<Trans email={email} i18nKey='fcc.email'>
<a href={`mailto:${email}`}>
{{ email }}
</a>
</Trans>
</p>
// in the JSON file:
{
"fcc": {
"email": "Send us an email at: <0>{{email}}</0>"
}
}
// output:
<p>Send us an email at: <a href='mailto:team@freecodecamp.org'>team@freecodecamp.org</a><p>
```
In the above example, the key and a variable are set in the attributes of the `Trans` component. `{{ email }}` needs to be somewhere in the `Trans` component as well, it doesn't matter where.
## Changing Text
To change text on the client side of things, go to the relevant `.json` file, find the key that is being used in the React component, and change the value to the new text you want. You should search the codebase for that key to make sure it isn't being used elsewhere. Or, if it is, that the changes make sense in all places.
## Adding Text
If the text you want to add to the client exists in the relevant `.json` file, use the existing key. Otherwise, create a new key.
The English file is the "source of truth" for all of the `.json` files sharing the same name. If you need to add a new key, add it there. Then, add the key to **all** of the `translations.json` files.
> [!NOTE] Use English text for all languages if the file is translated through Crowdin. The tests will fail if you don't.
It would be nice to keep the keys in the same order across all the files as well. Also, try to put all punctuation, spacing, quotes, etc in the JSON files and not in the components or server files.
> [!NOTE] The underscore (`_`) is a reserved character for keys in the client side files. See [the documentation](https://www.i18next.com/translation-function/plurals) for how they are used.
## Helpful Documentation
- [react-i18next docs](https://react.i18next.com/latest/usetranslation-hook)
- [i18next docs](https://www.i18next.com/translation-function/essentials)
@@ -1,15 +0,0 @@
# How to use Docker on Windows Home
There are a few pitfalls to be avoided when setting up Docker on Windows Home. First of all, you have to use [Docker Toolbox](https://docs.docker.com/toolbox/toolbox_install_windows/) as Administrator. Unfortunately Windows Home does not support Docker for Windows Desktop, so Toolbox must be used instead. It has to be run as Administrator as the installation uses symlinks, which cannot be created otherwise.
Once you've installed the toolbox, run Docker Quickstart Terminal as Administrator. This will create a `default` virtual machine if it does not already exist. Once that has happened, close the terminal and open VirtualBox (again as Administrator). You should be able to see the `default` machine. The site is quite resource-intensive, so stop the virtual machine and raise the settings as much as you can - memory in particular. It has been confirmed to work with 4GB of RAM.
Once you're happy that Docker is working, clone the freeCodeCamp repository to a directory inside `C:\Users`. These directories are shared giving Docker access to the local directories, which it needs during installation.
If you see messages like
```shell
bash: change_volumes_owner.sh: No such file or directory
```
when you `pnpm run docker:init` this is likely the culprit.
@@ -1,730 +0,0 @@
# How to work on coding challenges
Our goal is to develop a fun and clear interactive learning experience.
Designing interactive coding challenges is difficult. It would be much easier to write a lengthy explanation or to create a video tutorial. But for our core curriculum, we're sticking with what works best for most people - a fully interactive, video game-like experience.
We want campers to achieve a flow state. We want them to build momentum and blast through our curriculum with as few snags as possible. We want them to go into the projects with confidence and gain wide exposure to programming concepts.
Note that for Version 7.0 of the freeCodeCamp curriculum, we are moving toward [an entirely project-focused model with a lot more repetition](https://www.freecodecamp.org/news/python-curriculum-is-live/).
Creating these challenges requires immense creativity and attention to detail. There's plenty of help available. You'll have support from a whole team of contributors to whom you can bounce ideas off and demo your challenges.
And as always, feel free to ask questions on the ['Contributors' category on our forum](https://forum.freecodecamp.org/c/contributors) or [the contributors chat room](https://discord.gg/PRyKn3Vbay).
With your help, we can design an interactive coding curriculum that will help millions of people learn to code for years to come.
The content for each challenge is stored in its markdown file. This markdown file is later converted to HTML using our tools to create interactive web pages.
You can find all of freeCodeCamp.org's curricular content in the [`/curriculum/challenges`](https://github.com/freeCodeCamp/freeCodeCamp/tree/main/curriculum/challenges) directory.
## Set up the tooling for the curriculum
Before you work on the curriculum, you would need to set up some tooling to help you test your changes. You can use any option from the below:
- You can [set up freeCodeCamp locally](how-to-setup-freecodecamp-locally.md). This is **highly recommended** for regular/repeat contributions. This setup allows you to work and test your changes.
- Use Gitpod, a free online dev environment. Clicking the button below will start a ready-to-code dev environment for freeCodeCamp in your browser. It only takes a few minutes.
[![Open in Gitpod](https://gitpod.io/button/open-in-gitpod.svg)](https://gitpod.io/#https://github.com/freeCodeCamp/freeCodeCamp)
### How to work on practice projects
The practice projects have some additional tooling to help create new projects and steps. To read more, see [these docs](how-to-work-on-practice-projects.md)
## Challenge Template
````md
---
id: Unique identifier (alphanumerical, MongoDB_id)
title: 'Challenge Title'
challengeType: Integer, defined in `client/utils/challenge-types.js`
videoUrl: 'url of video explanation'
forumTopicId: 12345
---
# --description--
Challenge description text, in markdown
```html
<div>example code</div>
````
# --instructions--
Challenge instruction text, in markdown
# --hints--
Tests to run against user code, in pairs of markdown text and code block test code.
```js
Code for test one
```
If you want dynamic output based on the user's code, --fcc-expected-- and --fcc-actual-- will be replaced with the expected and actual values of the test's assertion. Take care if you have multiple assertions since the first failing assertion will determine the values of --fcc-expected-- and --fcc-actual--.
```js
assert.equal(
'this will replace --fcc-actual--',
'this will replace --fcc-expected--'
);
```
# --notes--
Extra information for a challenge, in markdown
# --seed--
## --before-user-code--
```lang
Code evaluated before the user’s code.
```
## --after-user-code--
```lang
Code evaluated after the user’s code, and just before the tests
```
## --seed-contents--
Boilerplate code to render to the editor. This section should only contain code inside backticks, like the following:
```html
<body>
<p class="main-text">Hello world!</p>
</body>
```
```css
body {
margin: 0;
background-color: #3a3240;
}
.main-text {
color: #aea8d3;
}
```
```js
console.log('freeCodeCamp is awesome!');
```
# --solutions--
Solutions are used for the CI tests to ensure that changes to the hints will still pass as intended
```js
// first solution - the language(s) should match the seed.
```
---
```js
// second solution - so if the seed is written in HTML...
```
---
```js
// third solution etc. - Your solutions should be in HTML.
```
# --assignments--
This will show a checkbox that campers have to check before completing a challenge
---
This will show another checkbox that campers have to check before completing a challenge
# --question--
These fields are currently used for the multiple-choice Python challenges.
## --text--
The question text goes here.
## --answers--
Answer 1
### --feedback--
This will be shown as feedback when campers guess this answer
---
Answer 2
---
More answers
## --video-solution--
The number for the correct answer goes here.
# --fillInTheBlank--
These are for the English curriculum challenges.
## --sentence--
Sentence to be shown with with blanks that campers have to fill in. Example:
`Hello, You _ the new graphic designer, _?`
The two underscores will show up as blanks. The sentence must be surrounded in backticks.
## --blanks--
The solution for the first blank in the sentence above. Example:
`are`
### --feedback--
Feedback shown when campers input the wrong solution for this blank.
---
Solution for the second blank. Example:
`right`
If no feedback is here, a generic "wrong answer" message will be shown.
# --scene--
```json
// # --scene-- can only consist of a single json object
{
// Setup the scene. Properties not marked optional are required.
"setup": {
// Background file to start the scene. A list of scene asset filenames can be found here: https://github.com/freeCodeCamp/cdn/pull/233/files
"background": "company2-center.png",
// Array of all characters that will appear in the scene
"characters": [
{
// Name of character. See list of available characters in scene-assets.tsx
"character": "Maria",
// Where to start the character. Maria will start off screen to the left
"position": { "x": -25, "y": 0, "z": 1 }
},
{
"character": "Tom",
// Tom will start 70% from the left of the screen and 1.5 times regular size
"position": { "x": 70, "y": 0, "z": 1.5 },
// Optional, defaults to 1. Tom will start invisible
"opacity": 0
}
],
"audio": {
// Audio filename
"filename": "1.1-1.mp3",
// Seconds after the scene starts before the audio starts playing
"startTime": 1.3,
// Optional. Timestamp of the audio file where it starts playing from.
"startTimestamp": 0,
// Optional. Timestamp of the audio file where is stops playing. If these two aren't used, the whole audio file will play.
"finishTimestamp": 8.4
},
// Optional, defaults to false. Use this for the long dialogues. It stops the accessibility icon from showing which gives campers the option to show or hide the dialogue text
"alwaysShowDialogue": true
},
// Array of commands that make up the scene
"commands": [
{
// Character that will have an action for this command
"character": "Maria",
// Optional, defaults to previous value. Maria will move to 25% from the left of the screen. The movement takes 0.5 seconds
"position": { "x": 25, "y": 0, "z": 1 },
// When the command will start. Zero seconds after the camper presses play
"startTime": 0
},
{
"character": "Tom",
// Optional, defaults to previous value. Tom will fade into view. The transition take 0.5 seconds. Movement and Opacity transitions take 0.5 seconds
"opacity": 1,
// Tom will fade into view 0.5 seconds into the scene (immediately after Maria finishes moving on screen)
"startTime": 0.5
},
{
"character": "Maria",
// When the command starts: Maria will start saying this line 1.3 seconds into the scene. Note that this is the same time as the audio.startTime above. It doesn't have to match that (maybe there's a pause at the beginning of the audio or something)
"startTime": 1.3,
// The character will stop moving their mouth at the finishTime
"finishTime": 4.95,
"dialogue": {
// Text that will appear if the dialogue is visible
"text": "Hello! You're the new graphic designer, right? I'm Maria, the team lead.",
// Where the dialogue text will be aligned. Can be 'left', 'center', or 'right'
"align": "left"
}
},
{
// background will change to this at 5.4 seconds into the scene
"background": "company2-breakroom.png",
"character": "Tom",
"startTime": 5.4,
"finishTime": 9.4,
"dialogue": {
"text": "Hi, that's right! I'm Tom McKenzie. It's a pleasure to meet you.",
// Tom's text will be aligned to the right since he is on the right side of the screen
"align": "right"
}
},
{
"character": "Tom",
// Tom will fade to 0 opacity
"opacity": 0,
// I like to move characters off screen or fade them 0.5 second after the last talking command
"startTime": 9.9
},
{
"character": "Maria",
// Maria will slide back off the screen to the left
"position": { "x": -25, "y": 0, "z": 1 },
// The animation will stop playing 0.5 seconds after the 'finishTime' of the last command - or 0.5 seconds after 'startTime' if 'finishTime' isn't there.
"startTime": 10.4
}
]
}
```
````
> [!NOTE]
>
> 1. In the above sections, examples of `lang` are:
>
> - `html` - HTML/CSS
> - `js` - JavaScript
> - `jsx` - JSX
## Numbering Challenges
Every challenge needs an `id`. If you don't specify one, then MongoDB will create a new random one when it saves the data; however, we don't want it to do that, since we want the challenge ids to be consistent across different environments (staging, production, lots of different developers, etc.).
To generate a new one in a shell (assuming MongoDB is running separately):
1. Run `mongo` command.
2. Run `ObjectId()` command.
For example:
```bash
$ mongo
MongoDB shell version v3.6.1
connecting to: mongodb://127.0.0.1:27017
MongoDB server version: 3.4.10
...
$ ObjectId()
ObjectId("5a474d78df58bafeb3535d34")
````
The result is a new id, for example, `5a474d78df58bafeb3535d34` above.
Once you have your id, put it into the markdown file as the `id` field at the top, e.g.
```yml
---
id: 5a474d78df58bafeb3535d34
title: Challenge Title
```
## Naming challenges
Naming things is hard. We've made it easier by imposing some constraints.
All challenge titles should be explicit and should follow this pattern:
\[verb\]\[object clause\]
Here are some example challenge names:
- Use Clockwise Notation to Specify the Padding of an Element
- Condense arrays with .reduce
- Use Bracket Notation to Find the First Character in a String
## Challenge descriptions/instructions
Sentences should be clear and concise with minimal jargon. If used, jargon should be immediately defined in plain English.
Keep paragraphs short (around 1-4 sentences). People are more likely to read several short paragraphs than a wall of text.
Use american english, e.g., use `labeled` instead of `labelled`.
Challenge text should use the second person ("you") to help to give it a conversational tone. This way the text and instructions seem to speak directly to the camper working through the challenge. Try to avoid using the first person ("I", "we", "let's", and "us").
Don't use outbound links. These interrupt the flow. Campers should never have to google anything during these challenges. If there are resources you think campers would benefit from, add them to the challenge's Guide-related article.
You can add diagrams if necessary.
Don't use emojis or emoticons in challenges. freeCodeCamp has a global community, and the cultural meaning of an emoji or emoticon may be different around the world. Also, emojis can render differently on different systems.
Proper nouns should use correct capitalization when possible. Below is a list of words as they should appear in the challenges.
- JavaScript (capital letters in "J" and "S" and no abbreviations)
- Node.js
- Although sometimes inaccurate, non-hyphenated forms of 'back end' and 'front end' should be used, as they are more widely used.
### The 2-minute rule
Each challenge should be solvable within 120 seconds by a native English speaker who has completed the challenges leading up to it. This includes the amount of time it takes to read the directions/instructions understand the seeded code, write their code and get all the tests to pass.
If it takes longer than two minutes to complete the challenge, you have two options:
- Simplify the challenge, or
- Split the challenge into two challenges.
The 2-minute rule forces you, the challenge designer, to make your directions concise, your seed code clear, and your tests straightforward.
We track how long it takes for campers to solve challenges and use this information to identify challenges that need to be simplified or split.
### Modularity
Each challenge should teach exactly one concept, and that concept should be apparent from the challenge's name.
We can reinforce previously covered concepts through repetition and variations - for example, introducing h1 elements in one challenge, then h3 elements a few challenges later.
Our goal is to have thousands of 2-minute challenges. These can flow together and reiterate previously-covered concepts.
### Formatting challenge text
Here are specific formatting guidelines for challenge text and examples:
- Language keywords go in `` \` `` backticks. For example, HTML tag names or CSS property names.
- References to code parts (i.e. function, method, or variable names) should be wrapped in `` \` `` backticks. See example below:
```md
Use `parseInt` to convert the variable `realNumber` into an integer.
```
- References to file names and path directories (e.g. `package.json`, `src/components`) should be wrapped in `` \` `` backticks.
- Multi-line code blocks **must be preceded by an empty line**. The next line must start with three backticks followed immediately by one of the [supported languages](https://prismjs.com/#supported-languages). To complete the code block, you must start a new line that only has three backticks and **another empty line**. See example below:
- Whitespace matters in Markdown, so we recommend that you make it visible in your editor.
**Note:** If you are going to use an example code in YAML, use `yaml` instead of `yml` for the language to the right of the backticks.
The following is an example of code:
````md
```{language}
[YOUR CODE HERE]
````
````
- Additional information in the form of a note should be surrounded by blank lines, and formatted: `**Note:** Rest of note text...`
- If multiple notes are needed, then list all of the notes in separate sentences using the format: `**Notes:** First note text. Second note text.`
- Use single quotes where applicable
**Note:** The equivalent _Markdown_ should be used in place of _HTML_ tags.
## Writing tests
Challenges should have the minimum number of tests necessary to verify that a camper understands a concept.
Our goal is to communicate the single point that the challenge is trying to teach, and test that they have understood that point.
Challenge tests can make use of the Node.js and Chai.js assertion libraries. Also, if needed, user-generated code can be accessed in the `code` variable. In addition, the `__helpers` object exposes several functions that simplify the process of writing tests. The available functions are defined in the [curriculum-helpers](https://github.com/freeCodeCamp/curriculum-helpers/blob/main/lib/index.ts) repo.
## Formatting Seed Code
Here are specific formatting guidelines for the challenge seed code:
- Use two spaces to indent
- JavaScript statements end with a semicolon
- Use double quotes where applicable
### Seed Code Comments
We have a [comment dictionary](https://github.com/freeCodeCamp/freeCodeCamp/blob/main/curriculum/dictionaries/english/comments.json) that contains the only comments that can be used within the seed code. The exact case and spacing of the dictionary comment must be used. The comment dictionary should not be expanded without prior discussion with the dev-team.
Comments used should have a space between the comment characters and the comment themselves. In general, comments should be used sparingly. Always consider rewriting a challenge's description or instructions if it could avoid using a seed code comment.
Example of a valid single-line JavaScript comment:
```js
// Only change code below this line
````
Example of a valid CSS comment:
```css
/* Only change code above this line */
```
If a challenge only has a single place where code changes are needed, please use the comments in the following example to instruct the user where changes should be made.
```js
var a = 3;
var b = 17;
var c = 12;
// Only change code below this line
a = a + 12;
b = 9 + b;
c = c + 7;
```
If a challenge has multiple places where the user is expected to change code (i.e. the React challenges)
```jsx
class MyComponent extends React.Component {
constructor(props) {
super(props);
this.state = {
text: 'Hello'
};
// Change code below this line
// Change code above this line
}
handleClick() {
this.setState({
text: 'You clicked!'
});
}
render() {
return (
<div>
{/* Change code below this line */}
<button>Click Me</button>
{/* Change code above this line */}
<h1>{this.state.text}</h1>
</div>
);
}
}
```
### Translation of Seed Code Comments
There are separate comment dictionaries for each language. The [English version of the comment dictionary](https://github.com/freeCodeCamp/freeCodeCamp/blob/main/curriculum/dictionaries/english/comments.json) is the basis for the translations found in the corresponding non-English versions of the files. The non-English version of the Chinese comment dictionary would be located at `/curriculum/dictionaries/chinese/comments.json`. Each dictionary consists of an array of objects with a unique `id` property and a `text` property. Only the `text` should be modified to encompass the translation of the corresponding English comment.
Some comments may contain a word/phrase that should not be translated. For example, variable names or proper library names like "React" should not be translated. See the comment below as an example. The word `myGlobal` should not be translated.
```text
Declare the myGlobal variable below this line
```
> [!NOTE]
>
> We are working on an integration to make it possible to work on i18n for the comment dictionary.
## Hints and Solutions
Each challenge has a `Get a Hint` button, so a user can access any hints/solutions which have been created for the challenge. Curriculum hints/solutions topics are located on [our forum](https://forum.freecodecamp.org/c/guide) under the `Guide` category.
If you find a problem with an existing challenge's hints/solutions topic, you can make suggestions in the [contributors category](https://forum.freecodecamp.org/c/contributors) on the forum. Moderators and users with trust level 3 will review the comments and decide whether or not to include the changes in the corresponding hint/solutions topic.
### Adding new Challenge hints/solutions Topics
Take the following steps when adding a new challenge hints/solutions-related topic.
1. Start by following the same steps for creating a new topic but review the next for creating the title.
2. The title of the topic should start with `freeCodeCamp Challenge Guide:` concatenated with the actual title of the curriculum challenge. For example, if the challenge is named "`Chunky Monkey`", the topic title would be "`freeCodeCamp Challenge Guide: Chunky Monkey`".
3. `camperbot` should be the owner of these topics/posts, so you will need to request an admin to change the ownership of the main post to `camperbot`.
4. Once the new topic is created, a forum topic id is created. It is located at the end of the forum topic URL. This id must be added to the frontmatter of the curriculum challenge file via the normal pull request process for the `Get a Hint` button to link to the topic.
### Guidelines for Content of Hints and Solutions Topics
When proposing a solution for a curriculum challenge-related Guide topic, the full code must be added. This includes all the original seed code plus any changes needed to pass all the challenge tests. The following template should be used when creating new hints/solutions topics:
````md
# Challenge Name Goes Here
---
## Problem Explanation
This summarizes what needs to be done without just restating the challenge description and/or instructions. This is an optional section
#### Relevant Links
- [Link Text](link_url_goes_here)
- [Link Text](link_url_goes_here)
---
## Hints
### Hint 1
Hint goes here
### Hint 2
Hint goes here
---
## Solutions
<details><summary>Solution 1 (Click to Show/Hide)</summary>
```js
function myFunc() {
console.log('Hello World!');
}
````
#### Code Explanation
- Code explanation goes here
- Code explanation goes here
#### Relevant Links
- [Link Text](link_url_goes_here)
- [Link Text](link_url_goes_here)
</details>
````
## Testing Challenges
Before you [create a pull request](how-to-open-a-pull-request.md) for your changes, you need to validate that the changes you have made do not inadvertently cause problems with the challenge.
1. To test all challenges run the below command from the root directory
````
pnpm run test:curriculum
```
2. To test single challenge, you can use it challenge id with following command
```
FCC_CHALLENGE_ID=646cf6cbca98e258da65c979 pnpm run test:curriculum
```
3. You can also test a block or a superblock of challenges with these commands
```
FCC_BLOCK='Basic HTML and HTML5' pnpm run test:curriculum
```
```
FCC_SUPERBLOCK='responsive-web-design' pnpm run test:curriculum
```
You are also able to test challenges by title by performing the following steps:
1. Switch to the `curriculum` directory:
```
cd curriculum
```
2. Run the following for each challenge file for which you have changed (replacing `challenge-title-goes-here` with the full title of the challenge):
```
pnpm run test -- -g challenge-title-goes-here
```
> [!TIP]
> You can set the environment variable `LOCALE` in the `.env` to the language of the challenge(s) you need to test.
>
> The currently accepted values are `english` and `chinese`, with `english` being set by default.
## Proposing a Pull Request (PR)
After you've committed your changes, check here for [how to open a Pull Request](how-to-open-a-pull-request.md).
## Useful Links
Creating and Editing Challenges:
1. [Challenge types](https://github.com/freeCodeCamp/freeCodeCamp/blob/main/client/utils/challenge-types.js#L1-L13) - what the numeric challenge type values mean (enum).
2. [Contributing to FreeCodeCamp - Writing ES6 Challenge Tests](https://www.youtube.com/watch?v=iOdD84OSfAE#t=2h49m55s) - a video following [Ethan Arrowood](https://twitter.com/ArrowoodTech) as he contributes to the old version of the curriculum.
## Helper Scripts
> [!NOTE]
> If you are working with the step-based challenges, refer to the [Work on Practice Projects](how-to-work-on-practice-projects.md) section.
There are a few helper scripts that can be used to manage the challenges in a block. Note that these commands should all be run in the block directory. For example:
```bash
cd curriculum/challenges/english/02-javascript-algorithms-and-data-structures/basic-algorithm-scripting
```
### Add New Challenge
To add a new challenge at the end of a block, call the script:
```bash
pnpm run create-next-challenge
```
This will prompt you for the challenge information and create the challenge file, updating the `meta.json` file with the new challenge information.
### Delete a Challenge
To delete a challenge, call the script:
```bash
pnpm run delete-challenge
```
This will prompt you to select which challenge should be deleted, then delete the file and update the `meta.json` file to remove the challenge from the order.
### Insert a Challenge
To insert a challenge before an existing challenge, call the script:
```bash
pnpm run insert-challenge
```
This will prompt you for the challenge information, then for the challenge to insert before. For example, if your choices are:
```bash
a
b
c
```
If you choose `b`, your new order will be:
```bash
a
new challenge
b
c
```
### Update Challenge Order
If you need to manually re-order the challenges, call the script:
```bash
pnpm run update-challenge-order
```
This will take you through an interactive process to select the order of the challenges.
## Troubleshooting
### Infinite Loop Detected
If you see the following error in the console while previewing a challenge:
```text
Potential infinite loop detected on line <number>...
```
This means that the loop-protect plugin has found a long-running loop or recursive function. If your challenge needs to do that (e.g. it contains an event loop that is supposed to run indefinitely), then you can prevent the plugin from being used in the preview. To do so, add `disableLoopProtectPreview: true` to the block's `meta.json` file.
If your tests are computationally intensive, then you may see this error when they run. If this happens then you can add `disableLoopProtectTests: true` to the block's `meta.json` file.
It's not typically necessary to have both set to true, so only set them as needed.
@@ -1,280 +0,0 @@
# How to Work on Localized Client Webapp
The React-based client web app that powers our learning platform is built using Gatsby. It is translated into various world languages using [react-i18next](https://react.i18next.com/) and [i18next](https://www.i18next.com/).
You can learn more about setting up the client application locally for development by following [our local setup guide here](how-to-setup-freecodecamp-locally.md). By default, the application is available only in English.
Once you have set up the project locally you should be able to follow this documentation to run the client in the language of your choice from the list of available languages.
This could be helpful when you are working on a feature that specifically targets something that involves localization, and requires you to validate for instance a button's label in a different language.
> [!TIP] You do not need to follow this document to translate freeCodeCamp's curriculum or contributing documentation. Read [this guide here](how-to-translate-files.md) instead.
Let's understand how the i18n frameworks and tooling work.
## File Structure
Most of the files for translating the platform are located in the [`client/i18n`](https://github.com/freeCodeCamp/freeCodeCamp/tree/main/client/i18n) folder. Each language has a directory that contains JSON files with the translations.
```bash
config
└── i18n.ts
...
client/i18n
├── configForTests.js
├── config.js
├── locales
│   ├── chinese
│   │   ├── intro.json
│   │   ├── links.json
│   │   ├── meta-tags.json
│   │   ├── motivation.json
│   │   └── translations.json
... ...
│   ├── dothraki
│   │   ├── intro.json
│   │   ├── links.json
│   │   ├── meta-tags.json
│   │   ├── motivation.json
│   │   └── translations.json
... ...
│   ├── english
│   │   ├── intro.json
│   │   ├── links.json
│   │   ├── meta-tags.json
│   │   ├── motivation.json
│   │   └── translations.json
│   └── espanol
│   ├── intro.json
│   ├── links.json
│   ├── meta-tags.json
│   ├── motivation.json
│   └── translations.json
├── locales.test.js
├── schema-validation.js
└── validate-keys.ts
```
Some of these files are translated on our translation platform (Crowdin) and some are translated or created via PRs on GitHub.
**Files translated on our translation platform:**
- The `translations.json` file contains the majority of the text that appears on the user interface elements. The keys are used in the codebase to get the correct text for whatever language is set. This file needs to have the same keys in all languages.
- The `intro.json` file contains the key-value pairs for the introduction text on the certification pages.
If you want to add/update translations for the keys please [read this guide here](how-to-translate-files.md).
**Files NOT translated on our translations platform:**
- The `motivation.json` files are not required to have the same quotes, compliments, or array length. Just the same JSON structure.
- The `meta-tags.json` file contains the information for our website's meta tag information.
Changes to these files are typically done by the staff team. If you see something out of the ordinary we recommend you reach us in the [contributors chat room](https://discord.gg/PRyKn3Vbay).
## Testing the Client App in a World Language
You can test the client app in any language available in the [list of `availableLangs` here](https://github.com/freeCodeCamp/freeCodeCamp/blob/main/shared/config/i18n.ts).
```js
export const availableLangs = {
client: [
Languages.English,
Languages.Espanol,
Languages.Chinese,
Languages.ChineseTraditional,
Languages.Italian,
Languages.Portuguese,
Languages.Ukrainian,
Languages.Japanese,
Languages.German,
Languages.Arabic
],
...
};
```
If you are testing a new language, create a folder with the language name as the title next to the other languages and copy the JSON files from another language into your new folder.
Add the new language to the `Languages` enum and the `client` array at the top of the [`shared/config/i18n.ts`](https://github.com/freeCodeCamp/freeCodeCamp/blob/main/shared/config/i18n.ts) file.
Next, follow the instructions in the comments in the same file to add/update the rest of the variables as needed.
Finally, set the `CLIENT_LOCALE` variable in your `.env` file to the string of the locale you want to build from the `Languages` enum in the above file.
## How to Structure Components
If you are working on a feature or a bug for the client web app, say for example adding new UI items on the settings page, you should follow the guidelines below. They will help you prepare the components for localization into all the supported world languages.
### Functional Component
```js
import { useTranslation } from 'react-i18next';
// in the render method:
const { t } = useTranslation();
// call the "t" function with a key from the JSON file:
<p>{t('key')}</p>; // more details below
```
### Class Component
```js
import { withTranslation } from 'react-i18next';
// withTranslation adds the "t" function to props:
const { t } = this.props;
// call the "t" function with a key from the JSON file:
<h1>{t('key')}</h1> // more details below
// export without redux:
export default withTranslation()(Component);
// or with redux:
export default connect(...)(withTranslation()(Component));
```
## Translate Using the "t" Function
### Basic Translation
```js
// in the component:
<p>{t('p1')}</p>
// in the JSON file:
{
"p1": "My paragraph"
}
// output:
<p>My paragraph</p>
```
### With Dynamic Data
```js
// in the component:
const username = 'moT';
<p>{t('welcome', { username: username })}</p>
// in the JSON file:
{
"welcome": "Welcome {{username}}"
}
// output:
<p>Welcome moT</p>
```
The above example passes an object to the `t` function with a `username` variable. The variable will be used in the JSON value where `{{username}}` is.
## Translate with the `Trans` Component
The general rule is to use the "t" function when you can. But there's a `Trans` component for when that isn't enough, usually when you have elements embedded in the text. You can use the `Trans` component with any type of react component.
### Basic Elements Nested
```js
// in the component:
import { Trans } from 'react-i18next'
<p>
<Trans>fcc.greeting</Trans>
</p>
// in the JSON file:
{
"fcc": {
"greeting": "Welcome to <strong>freeCodeCamp</strong>"
}
}
// output:
<p>Welcome to <strong>freeCodeCamp</strong></p>
```
You can place the key inside the component tags like in the above example if the text contains "simple" tags with no attributes. `br`, `strong`, `i`, and `p` are the default, but that list can be expanded in the i18n config.
### Complex Elements Nested
Other times, you will want to have certain text inside another element, an anchor tag is a good example:
```js
// in the component:
<p>
<Trans i18nKey='check-forum'>
<a href='https://forum.freecodecamp.org/'>placeholder</a>
</Trans>
</p>
// in the JSON file:
{
"check-forum": "Check out <0>our forum</0>."
}
// output:
<p>Check out <a href='https://forum.freecodecamp.org/'>our forum</a></p>
```
In the above example, the key is set in the attributes of the `Trans` component. The `<0>` and `</0>` in the JSON represent the first child of the component, in this case, the anchor element. If there were more children, they would just count up from there using the same syntax. You can find the children of a component in the react dev tools by inspecting it. `placeholder` is simply there because the linter complains about empty `<a>` elements.
### With a Variable
```js
// in the component:
const email = 'team@freecodecamp.org';
<p>
<Trans email={email} i18nKey='fcc.email'>
<a href={`mailto:${email}`}>
{{ email }}
</a>
</Trans>
</p>
// in the JSON file:
{
"fcc": {
"email": "Send us an email at: <0>{{email}}</0>"
}
}
// output:
<p>Send us an email at: <a href='mailto:team@freecodecamp.org'>team@freecodecamp.org</a><p>
```
In the above example, the key and a variable are set in the attributes of the `Trans` component. `{{ email }}` needs to be somewhere in the `Trans` component as well, it doesn't matter where.
## Changing Text
To change text on the client side of things, go to the relevant `.json` file, find the key that is being used in the React component, and change the value to the new text you want. You should search the codebase for that key to make sure it isn't being used elsewhere. Or, if it is, that the changes make sense in all places.
Run `pnpm run clean-and-develop` to apply the change.
## Adding Text
If the text you want to add to the client exists in the relevant `.json` file, use the existing key. Otherwise, create a new key.
The English file is the "source of truth" for all of the `.json` files sharing the same name. If you need to add a new key, add it there. Then, add the key to **all** of the `translations.json` files.
> [!NOTE] Use English text for all languages if the file is translated through Crowdin. The tests will fail if you don't.
It would be nice to keep the keys in the same order across all the files as well. Also, try to put all punctuation, spacing, quotes, etc. in the JSON files and not in the components or server files.
> [!NOTE] The underscore (`_`) is a reserved character for keys in the client-side files. See [the documentation](https://www.i18next.com/translation-function/plurals) for how they are used.
Run `pnpm run clean-and-develop` to apply the change.
## Proposing a Pull Request (PR)
After you've committed your changes, check here for [how to open a Pull Request](how-to-open-a-pull-request.md).
## Helpful Documentation
- [react-i18next docs](https://react.i18next.com/latest/usetranslation-hook)
- [i18next docs](https://www.i18next.com/translation-function/essentials)
@@ -1,152 +0,0 @@
# How to Work on Practice Projects
Our practice projects use a step-based approach to teach concepts to campers. A project will consist of multiple files, which we refer to as **"steps"**. These files are named by the challenge ID, to avoid issues with the translation flow. Unfortunately, this makes it difficult to find the file associated with a specific step.
We've built a challenge editor tool that helps remedy this. This tool allows you to navigate the available projects, and the steps for each project (in order). There's also an embedded code editor you can use to work on the files directly.
## Using the Challenge Editor
These instructions will tell you how to use our challenge editor tool to work on the practice projects.
### Starting the Editor
To start the editor, make sure you are in the root freeCodeCamp directory. Then, run `pnpm run challenge-editor` to start both the client and the API that powers the editor.
The client will run on port `3300`, so you can access it at `http://localhost:3300`. The API runs on port `3200`, to avoid conflicts with the learn client and server. This will allow you to run the freeCodeCamp application at the same time as the editor, so you can test your changes locally.
### Navigating the Editor
The default view will list the available `superblocks` - these are the certifications. Click on the certification link you want to work on.
This will take you to the list of blocks. These are the practice projects. Click on the project link you want to work on.
This will take you to a list of steps for the project. If you are working on an existing step, you can click on the step link to open the editor. If you are adding or removing steps, click the `Use the step tools` link to switch to the step tools for that challenge.
### Editing Steps
When you click on a step, you'll be taken to the editor. This is a basic text editor that offers syntax highlighting.
After you have made your changes, click the `Save Changes` button to save your changes. You will get a browser alert letting you know that your changes are ready to commit. Note that you'll need to use `git` manually to stage and commit your files - this tool will not do that for you.
### Step Tools
When you click the `Use the step tools` link, you'll be taken to the step tools page. This allows you to add or remove steps from the project.
#### Create Next Step
Clicking this button will add a new step at the end of the project. This step will use the previous step's code as the seed.
#### Create Empty Steps
Enter the number of steps you want to add in the input. Then, clicking the button will create many empty steps at the end of the project.
#### Insert Step
Enter the step number that you want to add. Then, click the `Insert Step` button to add the step. The following steps will be re-ordered.
#### Delete Step
Enter the step number you want to delete. Then click the `Delete Step` button to remove that step. This will automatically update the step numbers for the remaining steps.
#### Update Step Titles
You should not have to use this tool unless you've manually deleted or added steps. This tool will reorder the step numbers.
## Using the Scripts Manually
If you want to work on the steps manually, in your local IDE, you can run the step management scripts directly.
The `tools/challenge-helper-scripts` folder contains tools to help facilitate the creation and maintenance of the freeCodeCamp project-based curriculum.
### Create a New Project
Change directory to `tools/challenge-helper-scripts` and run `pnpm run create-project`. This opens up a command line UI that guides you through the process. Once that has finished, there should be a new challenge in the English curriculum that you can use for the first step of the project. For example, if you created a project called `test-project` in the Responsive Web Design certification, it would be in `curriculum/challenges/english/01-responsive-web-design/test-project`.
If you want to create new steps, the following tools simplify that process.
### create-next-step
A one-off script that will automatically add the next step based on the last step in the project. The challenge seed code will use the previous step's challenge seed code.
#### How to Run the Script
1. Change to the directory of the project.
2. Run the following command:
```bash
pnpm run create-next-step
```
### create-empty-steps
A one-off script that automatically adds a specified number of steps. The challenge seed code for all steps created will be empty.
**Note:** This script also runs [update-step-titles](#update-step-titles).
#### How to Run the Script
1. Change to the directory of the project.
2. Run the following command:
```bash
pnpm run create-empty-steps X # where X is the number of steps to create.
```
### insert-step
A one-off script that automatically adds a new step at a specified position, incrementing all subsequent steps (both their titles and in their meta.json). The challenge seed code will use the previous step's challenge seed code with the editable region markers (ERMs) removed.
**Note:** This script also runs [update-step-titles](#update-step-titles).
#### How to Run the Script
1. Change to the directory of the project.
2. Run the following command:
```bash
pnpm run insert-step X # where X is the position to insert the new step.
```
### delete-step
A one-off script that deletes an existing step, decrementing all subsequent steps (both their titles and in their meta.json)
**Note:** This script also runs [update-step-titles](#update-step-titles).
#### How to Run the Script
1. Change to the directory of the project.
2. Run the following command:
```bash
pnpm run delete-step X # where X is the step number to be deleted.
```
### update-step-titles
A one-off script that automatically updates the frontmatter in a project's markdown files so that they are consistent with the project's meta.json. It ensures that each step's title (and dashedName) matches the meta's `challengeOrder`.
#### How to Run the Script
1. Change to the directory of the project.
2. Run the following command:
```bash
pnpm run update-step-titles
```
### repair-meta
One-off script to parse the step names from the project and update the meta.json order to reflect those steps. Useful if you've accidentally lost the changes to the meta.json file when adding/removing steps.
#### How to Run the Script
1. Change to the directory of the project.
2. Run the following command:
```bash
pnpm run repair-meta
```
## Proposing a Pull Request (PR)
After you've committed your changes, check here for [how to open a Pull Request](how-to-open-a-pull-request.md).
@@ -1,111 +0,0 @@
# How to Work on the Component Library
Welcome to freeCodeCamp's `ui-components` library. The components are built mostly from scratch with basic HTML elements and [Tailwind CSS](https://tailwindcss.com/).
> [!NOTE]
>
> freeCodeCamp has been using Bootstrap components in the UI. However, we are moving away from it and building our own component library, which helps standardize our UX/UI patterns and improve accessibility. The project is tracked in [this GitHub issue](https://github.com/freeCodeCamp/freeCodeCamp/issues/44668).
The following steps are recommended when working on a new component:
- Research and planning
- Implement the component
- Display the use cases on Storybook
- Write unit tests
## Researching and Planning
Before building a component, you need to research and document on how the existing version behaves and looks, to ensure that the new one has matching styles and supports all the current usages. In order to meet the web accessibility requirements, you should also pay attention to the accessibility aspect of the component, see which HTML elements and ARIA attributes are used under the hood.
Once you have gathered enough information about the component, you can start thinking about the props interface. Ideally, the interface should be as similar to the current version as possible, to ease the adoption later on. Since we are using Bootstrap components, the simplest approach is to mimic [their implementation](https://github.com/react-bootstrap/react-bootstrap/tree/master/src).
We prefer smaller pull requests rather than a large one, because they speed up the review time and reduce cognitive overload for the reviewers. For that reason, you should think about how you would break down the implementation and come up with a delivery plan.
We recommend opening a separate GitHub issue for each component and include all the notes in the issue description. It can be used as a place to host all of your working notes, as well as a way to communicate the approach with the reviewers. We will use the issue thread for further discussion if needed. [The issue for Button component](https://github.com/freeCodeCamp/freeCodeCamp/issues/45357) can be used as a reference.
## Implementing the Component
A new component can be created using the following command from the root directory:
```bash
cd tools/ui-components
pnpm run gen-component MyComponent
```
The command will generate a new folder inside the `ui-components` directory, with the following files:
| File name | Purpose |
| -------------------------- | ---------------------------------------------------------- |
| `index.ts` | It is used for exporting the component and its types. |
| `my-component.stories.tsx` | It is used for demoing the component on Storybook. |
| `my-component.test.tsx` | It is a test file. |
| `my-component.tsx` | It is where we implement the component. |
| `types.ts` | It is where we locate the component's interface and types. |
Each component is different, but in general, a component should:
- Support forwarding ref
- Be styled for both light and dark themes
- Be styled internally based on their props (the consumers should not need to restyle the component with the `className` prop)
- Utilize the built-in styling system from Tailwind instead of having custom styles
### Using Colors
There are two color "layers" in the component library:
- The base layer, where the color names describe what the colors are, e.g. `gray00`, `blue50`
- The semantic layer, where the color names describe what the colors are for, e.g. `foreground-primary`, `background-danger`
Generally, when using colors in a component, you should choose semantic variables over the base ones. There are exceptions, however, specifically when you are styling the component's states such as hover, active, disabled, etc. In these cases, we recommend using the base variables directly instead of creating new semantic variables, since each component can have different styles for its states.
> [!NOTE] Color definition can be found in the [`colors.css` file](https://github.com/freeCodeCamp/freeCodeCamp/blob/main/tools/ui-components/src/colors.css). A color is only available for use if it is added to the [`tailwind.config.js` file](https://github.com/freeCodeCamp/freeCodeCamp/blob/main/tools/ui-components/tailwind.config.js) under the `colors` property.
### Useful Links
- [Tailwind CSS Configuration](https://tailwindcss.com/docs/configuration)
- [React Bootstrap v0.33 Docs](https://react-bootstrap-v3.netlify.app)
- [Bootstrap 3.3.7 stylesheet](https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.7/css/bootstrap.css)
- [React Bootstrap current implementation](https://github.com/react-bootstrap/react-bootstrap/tree/master/src)
- [React Bootstrap current tests](https://github.com/react-bootstrap/react-bootstrap/tree/master/test)
## Displaying the Use Cases on Storybook
Use cases of the component should be added to the Storybook file (`.stories.tsx`).
To start Storybook, run the following command from the root directory:
```bash
pnpm run storybook
```
The Storybook page is available on [http://localhost:6006](http://localhost:6006).
## Writing Unit Tests
We use [React Testing Library](https://testing-library.com/docs/react-testing-library/intro/) to write unit tests. The tests should assert that the components behave as expected and are accessible.
To run tests against the component library, run the following command from the root directory:
```bash
pnpm run test-ui-components
```
## Proposing a Pull Request (PR)
After you've committed your changes, check here for [how to open a Pull Request](how-to-open-a-pull-request.md).
## Adding Packages to the UI-Component Library
We restrict adding new packages to the UI Components to help with the project's maintainability. In the rare chance that you think a dependency is needed, please check with the maintainers first and then use the following command to add a package:
```bash
cd tools/ui-components
pnpm add package_name
```
## Useful Links
- [Testing for Accessibility](https://testing-library.com/docs/dom-testing-library/api-accessibility)
- [Order of priority of React Testing Library's queries](https://testing-library.com/docs/queries/about/#priority)
- [Common mistakes with React Testing Library](https://kentcdodds.com/blog/common-mistakes-with-react-testing-library)
@@ -1,58 +0,0 @@
# How to Work on Documentation
## Work on the Content of the Docs
To work on the contributing guidelines, you can edit or add files in the `docs` directory [available here](https://github.com/freeCodeCamp/freeCodeCamp/tree/main/docs). When your changes are merged, they will be made available automatically at the documentation site.
When adding a new file to the `docs` directory, you should evaluate if the file should also be added to the sidebar navigation. We typically create a link in the [`_sidebar.md`](_sidebar.md) file for new and independent guides. Alternatively, You may follow the instructions below on creating an internal link for supporting guides.
### How to Create an Internal Link
If you want to create a link targeting a different section of the contributing guidelines, follow this format:
```md
[Link text](target-file-name.md#target-section-heading-id)
// If the target section is within the same page, you can omit the file name
[Link text](#target-section-heading-id)
```
Make sure you include the file extension (`.md`). Don't specify the full URL or append `/` before the file name.
This is necessary to make these links work for the translated version of the document. Otherwise, they will redirect to the English version of the page regardless of the language.
#### Translating docs with internal links
When you work on translating docs on Crowdin, make sure to replace the `#target-section-heading-id` with the id on the translated document. [Learn more about translating docs here](how-to-translate-files.md#translate-documentation).
## Work on the Docs Theme
> [!NOTE] A quick reminder that you do not need to set up anything for working on the content for the documentation site.
>
> To work on the contributing guidelines, see [work on the docs content](#work-on-the-docs-content) section.
### Structure of the Docs Website
The site is generated using [`docsify`](https://docsify.js.org) and served using GitHub pages.
Typically you would not need to change any configuration or build the site locally. In case you are interested, here is how it works:
- 此站點的主頁源在 [`docs/index.html`](index.html) 中。
- 我們使用 `docsify` 和 GitHub Pages 將這個文件作爲一個 SPA。
- The `docsify` script generates the content of `markdown` files in the `docs` directory on demand.
- 主頁是由 [`_coverpage.md`](_coverpage.md) 生成的。
- The sidebar navigation is generated from [`_sidebar.md`](_sidebar.md).
### Serving the Documentation Site Locally
Install freeCodeCamp locally ([see the local setup guide](how-to-setup-freecodecamp-locally)), we bundled the CLI with the development tools so you can run the command below as needed from the root of the repo:
```bash
pnpm run docs:serve
```
> The documentation site should be available at <http://localhost:3400>
## Proposing a Pull Request (PR)
After you've committed your changes, check here for [how to open a Pull Request](how-to-open-a-pull-request.md).
@@ -1,100 +0,0 @@
# How to work on freeCodeCamp.org's developer news theme
The developer news also known as [`/news`](https://www.freecodecamp.org/news) site is powered by [Ghost](https://ghost.org/). We use a custom theme for the look and feel of the site. The source code of the theme is available here: <https://github.com/freeCodeCamp/news-theme>.
## The Theme
Ghost uses a simple templating language called [Handlebars](http://handlebarsjs.com/) for its themes. The theme used on `/news` is based off of the default [casper theme](https://github.com/TryGhost/Casper).
The default theme is commented pretty heavily so that it should be fairly easy to work out what's going on just by reading the code and the comments. Once you feel comfortable with how everything works, Ghost also has a full [theme API documentation](https://themes.ghost.org) which explains every possible Handlebars helper and template.
**The main files are:**
- `default.hbs` - The main template file
- `index.hbs` - Used for the home page
- `post.hbs` - Used for individual posts
- `page.hbs` - Used for individual pages
- `tag.hbs` - Used for tag archives
- `author.hbs` - Used for author archives
One really neat trick is that you can also create custom one-off templates just by adding the slug of a page to a template file. For example:
- `page-about.hbs` - Custom template for the `/about/` page
- `tag-news.hbs` - Custom template for `/tag/news/` archive
- `author-ali.hbs` - Custom template for `/author/ali/` archive
## Development
1. Get Ghost installed locally.
```sh
npm install -g ghost-cli@latest
mkdir ghost-local-site
cd ghost-local-site
```
```sh
ghost install local
ghost start
```
> Note: Currently freeCodeCamp uses Ghost version `2.9.0`, so make sure you are using a version higher than that.
Be sure to run `ghost` commands from the `ghost-local-site` directory. Follow additional instructions on [Ghost's official documentation](https://docs.ghost.org) if are not familiar with its interface.
2. Fork and clone the repository in your theme directory (replacing `YOUR_USERNAME` with your GitHub username):
```sh
cd content/themes/
git clone https://github.com/YOUR_USERNAME/news-theme.git
```
3. Make sure you have all the pre-requisites.
The theme styles are compiled using Gulp/PostCSS to polyfill future CSS spec. You'll need [Node.js](https://nodejs.org/). Make sure that your Node.js version is compatible with `ghost`.
4. Install dependencies and develop the theme
```sh
npm ci
npm run develop
```
5. Now you can edit `/assets/css/` files, which will be compiled to `/assets/built/` automatically.
6. Access the development site.
a. Enter `http://localhost:2368/ghost/` into your address bar. Continue with the setup prompted on the page (if running ghost for the first time).
b. _(One-time only, during setup)_ Restart Ghost, on a separate terminal once to ensure the theme is available.
```sh
cd ghost-local-site
ghost restart
```
c. _(One-time only, during setup)_ Once you've done this, go to `http://localhost:2368/ghost/#/settings/design` and scroll to the bottom. Make sure you click activate on the `freecodecamp-news-theme`.
7. Zip the final code and make a pull-request
The `zip` Gulp task packages the theme files into `dist/<theme-name>.zip`, which we can then upload to the production site.
When you make a PR, please make sure you have run the below script prior to commiting the code and sending a PR.
```sh
npm run zip
```
## Other Reference and resources
### PostCSS Features Used
- Autoprefixer - Don't worry about writing browser prefixes of any kind, it's all done automatically with support for the latest 2 major versions of every browser.
- Variables - Simple pure CSS variables
- [Color Function](https://github.com/postcss/postcss-color-function)
### SVG Icons
The theme uses inline SVG icons, included via Handlebars partials. You can find all icons inside `/partials/icons`. To use an icon just include the name of the relevant file, eg. To include the SVG icon in `/partials/icons/rss.hbs` - use `{{> "icons/rss"}}`.
You can add your own SVG icons in the same manner.
@@ -1,138 +0,0 @@
This page describes how to contribute to the freeCodeCamp tutorials and projects that are completed using the CodeRoad VS Code extension.
## How the Tutorials Work
Each of the freeCodeCamp tutorials that use CodeRoad has its own repo under the freeCodeCamp GitHub organization. They all start with `learn-`. For example, `https://github.com/freeCodeCamp/learn-bash-by-building-a-boilerplate/`.
Each tutorial repo has a `main` branch and a "version" branch, e.g. `v1.0.0`.
The two main files on the `main` branch are `TUTORIAL.md` and `coderoad.yaml`. `TUTORIAL.md` contains all the instructions, hints, titles, and so on, for the tutorial. `coderoad.yaml` contains instructions for CodeRoad, such as what commands to run and when, what files to watch for changes, and what version branch to use for the steps.
The "version" branch contains the commits that will be loaded on each step of a tutorial. The commit messages on this branch have to be specific. The first commit needs `INIT` for its message and contains all the files to load before the first lesson.
Subsequent commit messages have to match the step number in `TUTORIAL.md` from the `main` branch. For example, the commit with the message `10.1` will be loaded when a user goes to step `10.1`.
In order to make changes to commits on a version branch, you would need to rebase and edit the commits you want to change. This will rewrite the Git history, so we cannot accept PRs to these types of branches. Once a version branch is on the freeCodeCamp repo, it should never change.
> [!WARNING]
>
> Never make or push changes to a version branch that is on one of the freeCodeCamp repos. Always create a new one
## How to Contribute
### Prerequisites
Install the [CodeRoad CLI tools](https://www.npmjs.com/package/@coderoad/cli) with `npm install -g @coderoad/cli`.
There have been some issues with the latest version. If `coderoad --version` doesn't work after installing, downgrade to `0.7.0` with `npm install -g @coderoad/cli@0.7.0`.
### Working on `main`
This set of instructions is for PRs that only make minor changes on `main` to **existing lessons**. That mainly consists of typo, grammar, hint, and instructional changes or fixes in the `TUTORIAL.md` file.
For everything else, including adding or deleting lessons, follow the [working on a version branch instructions](#working-on-version-branch). You will not need to create a new version branch for this - you can create a PR following the instructions below.
> [!NOTE]
>
> These changes will use the existing version branch. If they are substantial, feel free to add them to `CHANGELOG.md`. Most of the time, a good commit message should work
You never need to modify the `tutorial.json` file directly. That will be created with the CLI tools.
If you are only making minor changes like fixing a typo or grammatical error, you don't have to test your changes.
Follow these instructions to make a PR, keeping in mind that instructions usually use the lessons around them for context:
- Create a copy of the latest version branch with `git branch vX.X.X upstream/vX.X.X` - you do not need to check this branch out, it just needs to exist.
- Create and checkout a new branch off of `main`
- Make **and commit** your changes. Reminder: You don't need to change anything in the `tutorial.json` file. You likely only need to make changes to `TUTORIAL.md`
- Run `coderoad build` to recreate the `tutorial.json` file
- Commit the changes with `update json` as the message
- Make a PR
### Testing Changes on `main`
If you want to test your changes to `main` after using the above instructions, follow these instructions:
- Follow the instructions on the [rdb-alpha repo](https://github.com/freeCodeCamp/rdb-alpha) to run a container
- Start the tutorial using the `tutorial.json` file on the new branch
### Reviewing PRs to `main`
If reviewing a PR that only changes `main` with instructional or grammar issues as described above, the changes in `TUTORIAL.md` should match the changes in `tutorial.json`.
The `tutorial.json` file should not have changes to commit hashes, or step/level ids. Startup or level commands or file watchers likely should not be changed either. There are exceptions if there's an issue with a step, but they should be treated with more caution.
Also, keep in mind that instructions usually use the lessons around them for context, so make sure they make sense.
### Working on Version Branch
> [!WARNING]
>
> Reminder: Never make or push changes to a version branch that is on one of the freeCodeCamp repos. Always create a new one
There's no easy way to see exactly what changed between version branches since the Git history will be rewritten. Accepting new version branches to use will need to be done with careful consideration and testing.
These instructions are for changing anything on a "version" branch, such as tests, test text, reset files, adding and deleting steps, among other things.
Follow these instructions to create a new version:
- Checkout the **latest** version branch with `git checkout -b vX.X.X upstream/vX.X.X`
- Create a new branch off of that, incrementing the version, with `git checkout -b vX.X.Y`
- Make your changes to the version branch. See more info in the [CodeRoad Documentation](https://coderoad.github.io/docs/edit-tutorial) for how to work with tutorials
- Push the new branch to your fork with `git push -u origin vX.X.Y`
- Checkout the `main` branch
- Create a new branch off `main`. e.g. `feat/version-X.X.Y`
- Change the `uri` in `coderoad.yaml` to your fork of the repo. This is so you and reviewers can test it before pushing it to the freeCodeCamp repo. Change the version to the new branch in the two spots of that file. Add your changes for the new version to `CHANGELOG.md`. Make any other changes you need.
- Commit your changes with the message `feat: release version X.X.Y - <optional description>`
- Run `coderoad build` to create a new `tutorial.json` file
- Add and commit the file
- Push the changes to your fork
- Test your changes following the [testing instructions below](#testing-changes-to-a-version-branch). Make any additional changes and commit them as you just did, or, if you are satisfied, follow the rest of the instructions
- Make a PR to `main` using your new `feat/version-X.X.Y` branch. Give it a title of `version X.X.Y ready for review`. This will not be merged, it is just to let reviewers know that there is a new version ready
- Leave it here for reviewers
### Testing Changes to a Version Branch
- Follow the instructions on the [rdb-alpha repo](https://github.com/freeCodeCamp/rdb-alpha) to run a container
- Start the tutorial using the `tutorial.json` file on whatever fork the changes are on. Make sure to use the file on the `feat: version-X.X.Y` branch and not the `main` branch
### Pushing a New Version
Before pushing a new version, view the new `feat/version-vX.X.Y` (will be merged to `main`) branch on the user's fork. Make sure there are additions to the `CHANGELOG.md` file that include the new changes, and the version in the two spots of `coderoad.yaml` matches the new version branch.
If you have write access to the freeCodeCamp repo, have verified the `CHANGELOG` and `coderoad.yaml` files, have tested the changes using the instructions above, and want to push a new version of a tutorial:
> [!WARNING]
>
> Reminder: Never make or push changes to a version branch that is on one of the freeCodeCamp repos. Always create a new one
- If you don't have a remote to where the new changes exist, create a remote to the user's fork with `git remote add <users_fork>`
- Delete any **local** branches that share a name with the new branches. Likely named either `vX.X.Y` or `feat/version-X.X.Y`
- Checkout the new version branch with `git checkout -b vX.X.Y <remote>/vX.X.Y`
- Push the new version branch to the freeCodeCamp repo with `git push -u upstream/vX.X.Y`. You need to push the new branch before you update `main` with the new `tutorial.json` file
- Checkout the users branch that will be merged into `main` with `git checkout -b feat/version-X.X.Y <remote>/feat/version-X.X.Y`
- Change the `uri` in `coderoad.yaml` back to the freeCodeCamp repo
- Add and commit the changes
- Run `coderoad build` to create the new `tutorial.json` file
- Add and commit the file
- Push the changes to your fork with `git push -u origin/feat/version-X.X.Y`
- Make a PR to `main` on the freeCodeCamp repo
- If you are satisfied, merge it or leave it and ask for a review from someone
- After the PR is merged, open the tutorial by following the instructions on the [rdb-alpha repo](https://github.com/freeCodeCamp/rdb-alpha) to make sure it's loading properly, and that you can get through a few steps
- Finally, if any PRs for this version exist, close them
### How to Revert to a Previous Version
- Create a new branch off of the latest `main` with `git checkout -b revert/to-version-X.X.X`
- Revert all commits on this branch up to and including the commit of the version after the one you want to revert to. For example, you may have commits that look like this:
```
fix: typo
release: version 1.0.1
fix: typo
release: version 1.0.0
```
If you want to revert to v1.0.0, revert all the commits from `release: version 1.0.1` and after
- Create a PR. Give it a title of `revert: to version X.X.X`
-45
View File
@@ -1,45 +0,0 @@
因爲有成千上萬像你這樣善良的志願者,[freeCodeCamp.org](https://freecodecamp.org) 才成爲了可能。 如果你想利用業餘時間貢獻你的專業知識,我們將很高興地歡迎你加入社區。
> [!NOTE] 在你繼續之前,請花 2 分鐘時間快速地閱讀我們的[行爲守則](https://chinese.freecodecamp.org/news/code-of-conduct/)。 我們在社區中嚴格執行行爲規範,爲 freeCodeCamp.org 的所有貢獻者營造安全、包容的氛圍。
You are welcome to create, update and fix bugs in our [curriculum](#curriculum), help us fix bugs in freeCodeCamp.org's [learning platform](#learning-platform), or [help us translate](#translations) freeCodeCamp.org to world languages.
We answer the most common questions about contributing [in our contributor FAQ](FAQ.md).
Happy contributing.
---
## 課程
我們的課程由 freeCodeCamp 全球社區的貢獻者協作創建。 因此,我們能夠吸收像你這樣的志願者的專業知識。
你可以幫助擴展和改進課程。 你也可以更新項目需求以更好地解釋概念。 你可以改進我們的自動化測試,以便我們能夠更準確地測試人們的代碼。
**如果你對改進我們的課程感興趣,請查看 [如何爲課程做出貢獻](how-to-work-on-coding-challenges.md)。**
## 翻譯
We are localizing freeCodeCamp.org to major world languages.
Certifications are already live in some major world languages like below:
- [Chinese (中文)](https://www.freecodecamp.org/chinese/learn)
- [Spanish (Español)](https://www.freecodecamp.org/espanol/learn)
- [Italian (Italiano)](https://www.freecodecamp.org/italian/learn)
- [Portuguese (Português)](https://www.freecodecamp.org/portuguese/learn)
- [Ukrainian (Українська)](https://www.freecodecamp.org/ukrainian/learn)
- [Japanese (日本語)](https://www.freecodecamp.org/japanese/learn)
- [German (Deutsch)](https://www.freecodecamp.org/german/learn)
We encourage you to read the [announcement here](https://www.freecodecamp.org/news/help-translate-freecodecamp-language/) and share it with your friends to get them excited about this.
**If you're interested in translating, here's [how to translate freeCodeCamp's resources](how-to-translate-files.md).**
## 學習平臺
Our learning platform runs on a modern JavaScript stack. It has various components, tools, and libraries. These include Node.js, MongoDB, OAuth 2.0, React, Gatsby, Webpack, and more.
Broadly, we have a Node.js based API server, a set of React-based client applications, testing scripts to evaluate camper-submitted curriculum projects, and more. If you want to productively contribute to the learning platform, we recommend some familiarity with these tools.
**If you want to help us improve our codebase here's [how to set up freeCodeCamp](how-to-setup-freecodecamp-locally.md).**
@@ -1,350 +0,0 @@
# The Official freeCodeCamp Language Lead Handbook
This handbook will help you set up and use the tools for your localization efforts.
## How to Invite New Contributors to Ghost
Ghost allows you to set contributors with different levels of authorization.
Most of your invites will be for the "Contributor" level. This level allows the user to create drafts. Select this role when inviting a new translator.
The "Author" level allows the user to create Drafts and publish them.
The "Editor" level allows the user to access all Drafts and publish them. Select this role when inviting a new proofreader.
The "Administrator" level is reserved for freeCodeCamp staff and Language Leads.
### How are the Articles Built
We use a [JAMStack](https://www.google.com/search?q=what+is+jamstack)-based approach to build and deploy the articles. This strategy makes for a speedy static site cached and served from a CDN.
[Ghost](https://ghost.org) acts as our content management platform, and [11ty](https://11ty.dev) builds the articles into static assets – plain HTML, JavaScript, and CSS. Only these static assets are deployed to our servers.
This process is automated and runs periodically. If you publish something now, it will be available on the news site in a few hours.
You can find the up-to-date build schedules and status here: https://github.com/freeCodeCamp/news#build
## How to Mention the Original Author of a Translated Article
The original author and the original article are linked automatically adding this code to the Code Injection -> head section in the Draft Settings on Ghost.
```html
<script>
const fccOriginalPost = 'link';
</script>
```
With `link` being the link of the original article.
## How to Update Trending Articles
> [!TIP] Changing the articles in the footer at least once a month means giving a boost to the linked articles on Google results.
To update the trending articles in the footer, you need to update the [yaml file in the CDN repository](https://github.com/freeCodeCamp/cdn/tree/main/build/universal/trending) for your language. Both the curriculum and the publication reference this file.
For example, here is the file content for the first 6 articles:
```yaml
article0title: 'Unire CSV con Python'
article0link: 'https://www.freecodecamp.org/italian/news/come-combinare-file-multipli-in-formato-csv-con-8-righe-di-codice/'
article1title: 'Il comando Git push'
article1link: 'https://www.freecodecamp.org/italian/news/il-comando-git-push-spiegato/'
article2title: 'Centrare immagini in CSS'
article2link: 'https://www.freecodecamp.org/italian/news/come-centrare-un-immagine-usando/'
article3title: 'I codici Alt'
article3link: 'https://www.freecodecamp.org/italian/news/codici-alt/'
article4title: 'Tenere a bada il footer'
article4link: 'https://www.freecodecamp.org/italian/news/come-mantenere-il-footer-al-suo-posto/'
article5title: 'Cosa è API?'
article5link: 'https://www.freecodecamp.org/italian/news/cose-un-api-in-italiano-per-favore/'
```
Each number represents one of the 30 articles in the footer. Make sure to match the title and the link correctly.
For each article, you will need to create a shorter title to use in the footer. Each title must stay on a single line and not go to a new line.
You will want to [build the translated client locally](how-to-enable-new-languages.md) to see if the titles have the right length. You can preview the changes by editing the `trending.json` file in your local environment:
1. Update your `.env` file to use your language for `CLIENT_LOCALE` and `CURRICULUM_LOCALE`.
2. Run `pnpm run create:shared`. This will automatically generate the `trending.json` file for your language under the `/client/i18n/locales/` directory.
3. Start the server by running `pnpm run develop:server` in one terminal window.
4. Edit the `trending.json` to contain the titles you want to preview. You may want to convert your `.yaml` file into JSON format with an automatic tool.
5. In another terminal window, run `pnpm run clean:client`, and then `pnpm run develop:client`
## How to Translate Articles in the Footer Links
There are some links listed at the bottom of the footer (About, Alumni Network, Open Source, etc.) and some of them can be translated into your language in the same way as other articles.
Articles that can be translated:
- About
- Support
- Academic Honesty
- Code of Conduct
The following articles should **not** be translated:
- Shop
- Sponsors
- Privacy Policy
- Terms of Service
- Copyright Policy
The following links are pointing to external sites and cannot be translated:
- Alumni Network
- Open Source
### Change the Footer Links in the News
Once you have translated and published the articles listed as "can be translated" above, you can update the links in the footer for `/news` by editing the file at `news/config/i18n/locales/<your language>/links.json` in the [freeCodeCamp/news](https://github.com/freeCodeCamp/news) repository.
> [!NOTE] Pull requests to this repository are currently limited to staff only. If you want to update this file, ask someone on the staff team for help.
Update the following part in the file:
```json
{
...
"footer": {
"about": "https://www.freecodecamp.org/news/about/",
"support": "https://www.freecodecamp.org/news/support/",
"honesty": "https://www.freecodecamp.org/news/academic-honesty-policy/",
"coc": "https://www.freecodecamp.org/news/code-of-conduct/"
}
}
```
### Change the Footer Links in the Curriculum
When you have translated and published the articles listed as "can be translated" above, as well as when the curriculum in your language is ready for launch, you can update the links in the footer for `/learn` by editing the file at `client/i18n/locales/<your language>/links.json` in the [freeCodeCamp/freeCodeCamp](https://github.com/freeCodeCamp/freeCodeCamp) repository.
> [!WARNING] Only "About", "Support", "Academic Honesty", and "Code of Conduct" can be translated. Leave other URLs unchanged.
Update the following part in the file:
```json
{
...
"footer": {
"about-url": "https://www.freecodecamp.org/news/about/",
"shop-url": "https://www.freecodecamp.org/shop/",
"support-url": "https://www.freecodecamp.org/news/support/",
"sponsors-url": "https://www.freecodecamp.org/news/sponsors/",
"honesty-url": "https://www.freecodecamp.org/news/academic-honesty-policy/",
"coc-url": "https://www.freecodecamp.org/news/code-of-conduct/",
"privacy-url": "https://www.freecodecamp.org/news/privacy-policy/",
"tos-url": "https://www.freecodecamp.org/news/terms-of-service/",
"copyright-url": "https://www.freecodecamp.org/news/copyright-policy/"
},
...
}
```
## How to Translate the Info Boxes Headers in the Documentation
You can find these boxes all around the documentation:
> [!NOTE] I am a note box
> [!TIP] I am a tip box
> [!WARNING] I am a warning box
> [!ATTENTION] I am an attention box
By default, their headers appear in English even in the translated docs.
You can have the headers translated in the docs in your language by changing the file `docs/index.html`, in this way:
Inside the `script` element there is an object, find the `flexibleAlerts` property, which has this shape:
```js
flexibleAlerts: {
note: {
label: {
'/': 'Note'
}
},
tip: {
label: {
'/': 'Tip'
}
},
warning: {
label: {
'/': 'Warning'
}
},
attention: {
label: {
'/': 'Attention'
}
}
}
```
Inside the object of the label property, before the `'/'` property, you would add a new property for your language, like `/i18n/<language>/`.
For example, adding the translations for Portuguese would appear like this:
```js
flexibleAlerts: {
note: {
label: {
'/i18n/portuguese/': 'Observação',
'/': 'Note'
}
},
tip: {
label: {
'/i18n/portuguese/': 'Dica',
'/': 'Tip'
}
},
warning: {
label: {
'/i18n/portuguese/': 'Aviso',
'/': 'Warning'
}
},
attention: {
label: {
'/i18n/portuguese/': 'Atenção',
'/': 'Attention'
}
}
}
```
## How to Translate the Motivational Quotes
The motivational quotes can be found in the [curriculum repository](https://github.com/freeCodeCamp/freeCodeCamp/) in the `/client/i18n/locales/<language>/motivation.json` file.
This file has a general structure of:
```json
{
"compliments": [],
"motivationalQuotes": []
}
```
The compliments are the short sentences that appear at the completion of a challenge.
You don't need to directly translate the sentences used in English, you can write a set of short sentences that are appropriate to show at the completion of a challenge.
The `compliments` array is an array of strings. So, for example, you would write:
```json
{
"compliments": ["A tutta birra!", "Pikachu, scelgo te!"],
"motivationalQuotes": []
}
```
> [!TIP] You should start with at least a dozen compliments to have some variety when users complete challenges.
The motivational quotes are the quotes that appear at https://freecodecamp.org/learn.
The `motivationalQuotes` array is an array of objects, these objects should include a `quote` property and an `author` property. like this:
```json
{
"compliments": [],
"motivationalQuotes": [
{
"quote": "Se i costruttori costruissero come i programmatori programmano, il primo picchio che passa potrebbe distruggere la civiltà.",
"author": "Artur Bloch, Seconda legge di Weinberg"
},
{
"quote": "I bravi programmatori sanno cosa scrivere. I migliori sanno cosa riscrivere.",
"author": "Eric Steven Raymond"
}
]
}
```
> [!TIP] You should start with at least a dozen quotes, to have some variety. A new quote is shown every time the user reloads the page.
## How to Update the Common Links
We maintain a file of common links used throughout our [curriculum site](https://github.com/freecodecamp/freecodecamp) in the `/client/i18n/locales/<language>/links.json` file.
Some of these links will not change - but you should update the `/news` article links to point to your language's translated version of that article when it is published.
You should also update the `help` categories to point to your language's subforum (usually `language/category`, like `Italiano/HTML-CSS`). This will allow campers to create "help posts" in the correct forum location.
## How to Update the Site Meta-Data
The site meta-data is in the `/client/i18n/locales/<language>/meta-tags.json` file. This file has five keys: `title`, `description`, `social-description`, `keywords`, and `youre-unsubscribed`.
The `youre-unsubscribed` value should be directly translated. The other values will need to be translated as closely as possible, while also considering common search terms and phrases used in your language.
If you need help with this, reach out to us in the [contributor chat](https://discord.gg/PRyKn3Vbay)
## Pre-Translate Workflow on Crowdin
The Pre-Translate workflow can be used to apply translations from the Translation Memory to strings.
> [!TIP] Really useful to restore a lot of translations from the Translation Memory in bulk when a lot of files have been updated.
You can find the Pre-Translation workflow at the top of the page in the console of a project. If you see "Go to console" in the upper right corner, click there first.
![go to console button](./images/crowdin/pre-translate2.png)
![pre-translate workflow](./images/crowdin/pre-translate1.png)
You can choose "From Machine Translation" or "From Translation Memory". Choose "Translation Memory" to recover translations from memory.
Then there are three steps to complete:
1. Files. Choose which files to translate, you can do all the projects, or specific folders or files.
2. Languages. Set your language here.
3. Existing Translations. The best combination here is "100% match" and "Apply to untranslated strings only". Do not approve automatically, as it's always best to have a human eye on things.
![pre-translate existing translations](./images/crowdin/pre-translate3.png)
When you have finished setting this, press the Pre-Translate button and wait. It will alert you once it has finished. The time it takes depends on how many untranslated strings are in the chosen files.
## How to Update Crowdin Glossary
> [!TIP] An updated glossary helps in having a homogeneous translation of technical terms.
The Crowdin Glossary is kept in the [crowdin-glossaries](https://github.com/freeCodeCamp/crowdin-glossaries) repository.
In the `glossaries` folder, there are various `*.csv` (comma,separated values) files, one for each of the crowdin projects that have a glossary that can be updated from this workflow.
The `client.csv` file is for the Learn User Interface project, the `curriculum.csv` file is for the Coding Curriculum project, the `docs.csv` file is for the Contributing Documentation project.
To update the Crowdin Glossaries, you need to clone this repo locally. Open the `.csv` file with an appropriate program, for example, Microsoft Excel.
In the `.csv` file you will find that the English language occupies the first three columns, `Term:English` is the column for the English term, `Description:English` is the column for the English description, and `Part:English` is for the part of speech (e.g., noun, verb etc.) of the term.
Then, each target language has two columns. If you translate to Dothraki, you will be interested in the columns `Term:Dothraki` and `Description:Dothraki`. The column `Term:Dothraki` is for the translation of the term in Dothraki, and the column `Description:Dothraki` is for a description of the term in Dothraki.
> [!TIP] In programs like Microsoft Excel, you can hide the columns of the other languages to free up screen real-estate and see the English columns and the target language columns near each other.
After you have made the changes and saved the file, you will need to make a PR with the proposed changes. After the PR is accepted, you will need to run the GitHub Action workflow to update the Crowdin Glossary. Your glossary changes will not have immediate effects, but they will come.
## How to Promote a Contributor to Proofreader
If you consider that a contributor could become a Crowdin Proofreader, you can give the proofreader role to them this way:
In Crowdin, individuate the `User management` on the left-hand side menu.
This will open the user management tools, you will be able to see the list of all the users.
Search for the user who will become a proofreader. Use the three dots menu on the user row to open a menu and select "Add to team". The proofreader teams have a standard name of `Proof Readers (<language>)`, you can search the team using the language name. Once you have selected the team, use the "ADD" button at the bottom of the page to finalize the thing.
The user is now a proofreader.
> [!TIP] The newly promoted proofreader could benefit from reading the [How to Proofread Files](how-to-proofread-files.md) documentation.
## How to Add or Update a Language
Check out the [how to enable new language](how-to-enable-new-languages.md) docs. If you are updating a language the section on [set translated superblocks](how-to-enable-new-languages.md#set-translated-superblocks) should be helpful.
@@ -1,366 +0,0 @@
# freeCodeCamp 官方管理員手冊
該手冊將幫助您管理我們社區中的不同地方。 This covers conversations and interactions in issues and pull request threads on GitHub, the community forum, the chat rooms, and other official communities that we foster.
> [!NOTE] 所有 freeCodeCamp 管理員都是全社區管理員。 That means we trust you to oversee any of these places.
你可以在你感興趣的任何平臺上擔任管理員。 一些管理員只在 GitHub 上提供幫助,而其他管理員在論壇上提供幫助。 一些管理員在各個地方都很活躍。
最重要的是,我們希望你享受作爲管理員的樂趣,並將你寶貴的時間投入到你感興趣的地方。
> “擁有權利的同時也被賦予了重大的責任。” - 本叔叔
作爲一名管理員,氣質比技術能力更重要。
聆聽。 Be helpful. 不要濫用你的權力。
freeCodeCamp 是一個包容的社區,我們需要保持這種狀態。
We have a single [Code of Conduct](https://code-of-conduct.freecodecamp.org) that governs our entire community. 規則越少,就越容易記住。 你可以在[這裏](https://code-of-conduct.freecodecamp.org)閱讀這些規則,並把它們記在心裏。
> [!NOTE] As a moderator, we would add you to one or more teams on GitHub, our community forums & chat servers. If you are missing access to a platform that you would like to moderate, please [reach out to a staff member](FAQ.md#additional-assistance).
## 管理 GitHub
管理員在 GitHub 上有兩個主要職責:
1. Triaging and responding to issues.
2. Reviewing and merging pull requests (aka QA).
### 管理 GitHub Issue
We use our main [`freeCodeCamp/freeCodeCamp`](https://github.com/freeCodeCamp/freeCodeCamp/issues) repository as a common issue tracker for all of our repositories. We get new issues every day, all of which need to be triaged, labeled, and addressed. 這也是一個開始幫助開源代碼庫貢獻的好地方。
#### Issue 分流
[分流](https://en.wikipedia.org/wiki/Triage)是一個優先關注每個新 issue 報告的過程。 我們有一個廣泛的標籤列表,用於標記每個 issue 的優先級、類別、狀態和範圍。
你可以通過從[這個列表](https://github.com/freeCodeCamp/freeCodeCamp/labels)中使用標籤來幫助我們組織和分類 issue 報告。 通常,標籤旁邊有描述說明其含義。
請特別注意標籤 `"help wanted"`(“需要幫助”)和 `"first timers only"`(“僅限新手使用”)。 這些標籤將添加到你認爲可以向潛在貢獻者開放,以便他們提出拉取請求的主題中。
For triaging a trivial issue such as a typo fix, it is recommended to apply a "first timers only" label along with additional information. You can utilize the [reply template](reply-templates.md#first-timer-only-issues) provided for this purpose.
#### 關閉陳舊的、過時的、不活躍的 issue 和拉取請求
- Stale issues or PRs are those that have not seen any activity from the author for 21 days (3 weeks from the last activity), but only after a moderator has requested more information/changes.
- Activity is defined as: Comments requesting an update on the PR and triages like `status: update needed` label, etc.
- If the contributor asks for additional assistance or even time, the above can be relaxed and revisited after a response is given. In any case, the mods should use their best judgment to resolve the outstanding PR's status.
> [!TIP] We recommend you use this list of standard [reply templates](reply-templates.md) while triaging issues.
### 管理拉取請求(Pull Requests)
Pull Requests (PRs) are how contributors submit changes to freeCodeCamp's repository. We must perform Quality Assurance (QA) on pull requests before we decide whether to merge them, request changes, or close them.
#### Types of Pull Requests
1. **Challenge instruction edits**
These are changes to the text of challenges - the description, instructions, or test text.
You can also review these right on GitHub and decide whether to merge them. 因爲會有無數的人通過 freeCodeCamp 課程讀到這段文字, 所以我們應該要更加認真對待。 Does the pull request make the text more clear without making it much longer? Are the edits relevant and not overly pedantic? Remember that our goal is for challenges to be as clear and as short as possible. They aren't the place for obscure details. Contributors may try to add links to resources to the challenges.
You can close invalid pull requests and reply to them with these [reply templates](reply-templates.md#closing-invalid-pull-requests).
If the changes look good, please ensure to leave an approval with a "LGTM" (Looks Good To Me) comment. Once a pull request gets at least two approvals (including yours) from the moderators or the dev-team, you can go ahead and merge it.
2. **Challenge code edits**
These are changes to the code in a challenge - the challenge seed, challenge solution, and test strings.
These pull requests need to be pulled down from GitHub and tested on your local computer or Gitpod to make sure the challenge tests can still be passed with the current solution and to make sure the new code doesn't introduce any errors.
Some contributors may try to add additional tests to cover pedantic corner-cases. We need to be careful to not make the challenge too complicated. These challenges and their tests should be as simple and intuitive as possible. Aside from the algorithm challenges and interview prep section, learners should be able to solve each challenge within about 2 minutes.
You can close invalid pull requests and reply to them with these [reply templates](reply-templates.md#closing-invalid-pull-requests).
If the changes look good, please ensure to leave an approval with an "LGTM" comment. Once a pull request gets at least two approvals (including yours) from the moderators or the dev-team, you can go ahead and merge it.
3. **Platform changes**
These code edits change the functionality of the freeCodeCamp platform itself.
Sometimes contributors try to make changes without much explanation, but for code changes, we need to make sure there's a genuine need for the change. These pull requests should reference an existing GitHub issue where the reasons for the change are discussed. Then you can open the pull request on your computer and test them out locally.
After you've done so, if the changes look good, don't merge them quite yet. You can comment on the pull request saying "LGTM", then mention **"@freeCodeCamp/dev-team"** so they can take a final look.
4. **Automated PRs (Dependabot)**
Some PRs are automated dependency updates made via an integration. You should not merge or approve these PRs. One of the dev-team members will take care of reviewing and merging such automated PRs.
#### How to Review, Merge, or Close Pull Requests
##### Assign yourself to a Pull Request:
First of all, when you choose a pull request to review, you should assign yourself to it. You can do this by clicking the "assign yourself" link below the "assignees" part on the right-hand column of GitHub's interface.
Depending on the type of pull request it is, follow the corresponding rules listed previously.
##### Ensure the CI Checks are Passing:
Before merging any pull request, make sure that GitHub is reporting all checks to be passing (green check marks) on the pull requests. If you see any of the checks failing, please investigate and clarify the root cause. Is the change being made breaking our tests? Will the site build correctly if the PR is merged? These checks are critical for the stability of the platform.
> [!WARNING] Merging a PR that fails CI/CD checks can cause difficulties for all stakeholders, including the dev-team and contributors.
##### Handling Merge Conflicts:
Sometimes there will be a merge conflict.
This means that another pull request has made a change to that same part of that same file. GitHub has a tool for addressing these merge conflicts right on GitHub. You can try to address these conflicts. Use your best judgment.
The pull request's changes will be on top, and the main branch's changes will be on the bottom. Sometimes there will be redundant information in there that can be deleted. Before you finish, be sure to delete the `<<<<<<`, `======`, and `>>>>>>` that Git adds to indicate areas of conflict.
If you are uncertain, please ask one of the fellow moderators or the dev-team for assistance.
##### Merging a Valid Pull Request:
If the pull request looks ready to merge (and doesn't require additional approvals - remember we require at least two), you can go ahead and merge it. Be sure to use the default **"Squash and Merge"** option. This will squash all the pull requests commits down into a single commit, making the Git history much easier to read.
> You should then comment on the pull request, thanking the contributor in your own personal way!
If the pull request author is a "first-time contributor" you should also congratulate them on their first merged pull request to the repository. You can look at the upper right-hand corner of the PR's body to determine a first-time contributor. It will show `First-time contributor` as shown below:
<details>
<summary>
First-time contributor badge on pull requests (screenshot)
</summary>
<br>
<img src="https://i.imgur.com/dTQMjGM.png" alt="First time contributor badge on pull requests" />
</details>
If the pull request doesn't look ready to merge, you can politely reply telling the author what they should do to get it ready. Hopefully, they will reply and get their pull request closer to ready.
If you need a second opinion on a pull request, go ahead and leave your comments on the pull request, then add the "discussing" label to the pull request.
##### Closing an Invalid Pull Request:
Often, a pull request will be low effort. You can usually tell this immediately when the contributor didn't bother checking the checkboxes in the Pull Request Template or used a generic pull request title like "Made changes" or "Update index.md".
There are also situations where the contributor is trying to add a link to their website, include a library they created, or have a frivolous edit that doesn't help anyone but themselves.
You can close these invalid pull requests and reply to them with these [reply templates](reply-templates.md#closing-invalid-pull-requests).
#### Filtering Pull Requests
To sort Pull Requests for Quality Assurance for quick access to PRs that are ready for review, do not have a merge conflict, are not blocked, and have all status checks in green, use the following link to apply the filters:
[Direct link with filter applied](https://github.com/freeCodeCamp/freeCodeCamp/pulls?q=is%3Aopen+is%3Apr+-label%3A%22status%3A+blocked%22+-label%3A%22status%3A+merge+conflict%22+status%3Asuccess+draft%3Afalse)
#### Other Guidelines for Moderators on GitHub
Though you will have write access to freeCodeCamp's repository, **you should never push code directly to freeCodeCamp repositories**. All code should enter freeCodeCamp's codebase in the form of a pull request from a fork of the repository.
Also, you should never accept your own PRs. They must be reviewed by another moderator, just like any other PR.
If you notice anyone breaking the [Code of Conduct](https://code-of-conduct.freecodecamp.org) on GitHub issues, or opening pull requests with malicious content or code, email `support[at]freecodecamp.org` with a link to the offending pull request, and we can consider banning them from freeCodeCamp's GitHub organization entirely.
## 管理論壇
As a moderator, you help keep our community an enjoyable place for anyone to learn and get help. You will deal with flagged posts and handle spam, off-topic, and other inappropriate conversations.
Note that once you are a moderator on the forum, you will start to see blue moderator hints about forum members, like "this is the first time [person] has posted - let's welcome them to the community!" or "[person] hasn't posted in a long time - let's welcome them back."
![A blue text message saying "This is the first time [person] has posted - let's welcome them to the community!](https://i.imgur.com/mPmVgzK.png)
These are opportunities for you to welcome them and make them feel extra special. You never know which person who's marginally involved may become our next super-helper, helping many other people in their coding journey. Even the slightest kindness may trigger a cascade of good deeds.
### Deleting Forum Posts
Forum moderators can delete users' posts. You should only do this for the following instances:
1. Someone has posted a pornographic or graphically violent image.
2. Someone has posted a link or code that is malicious in nature and could harm other campers who click on it.
3. Someone has flooded a thread with a lot of spam messages.
4. An account has been created, beyond a reasonable doubt, to spam.
### Dealing with Spam
For the first spam post of a legitimate user (ie. whose intent isn't to spam the forum but to learn/contribute to the forum), send them a message explaining the problem, and remove the link or post as appropriate. Leave a note on the user's profile explaining the action you have taken. If the problem persists, then quietly block the user from posting (using the silence option on the User Admin panel). Send the user a warning with the [Code of Conduct](https://code-of-conduct.freecodecamp.org). Check the box in the private message indicating that your message is a "formal warning."
As a moderator, you can ask questions and report incidents in the [mod-team forum section](https://forum.freecodecamp.org/c/mod-team/4).
### Dealing with Off-Topic Conversations
Posts or topics that seem to be in the wrong place can be recategorized or renamed to whatever would be appropriate.
In exceptional circumstances, it may be appropriate for a moderator to fork a discussion into multiple threads.
Again, if you have any problems or questions, make a post with your actions in the `"Staff"` category, and tag another moderator if you want them to review your moderating actions.
### Dealing with Posted Solutions
If a user replies in a help thread for the freeCodeCamp curriculum with a solution, remove it and use the **Solution Instead of Help** canned reply (or a similar response in your own words).
If the OP (Original Poster) replies within a freeCodeCamp curriculum help thread with their final solution, blur it, and use the **Blurred Spoiler Solution** canned reply.
If a user creates a thread asking for feedback on a solution, move the thread to the feedback subforum and blur the solution, as necessary. If the user is only posting the solution to show it off, then unlist the thread and use the **Solutions Thread** canned reply.
### Underage Users
Our [Terms of Service](https://freecodecamp.org/terms) require that freeCodeCamp users be at least 13 years of age. If a user reveals that they are under the age of 13, send them the message below, suspend their account, then email the link of their forum account to `support[at]freecodecamp.org` for their freeCodeCamp /learn and forum accounts removal.
```markdown
SUBJECT: Users under 13 are not allowed to use the forum per our Terms of Service.
It has come to our attention that you are under 13 years of age. Per the [freeCodeCamp Terms of Service](https://freecodecamp.org/terms), you must be at least 13 years old to use the site or the forum. We will be deleting both your freeCodeCamp account and your forum account. This restriction keeps us in compliance with United States laws.
Please rejoin once you have reached at least 13 years of age.
Thank you for understanding.
```
### Account Deletion Requests
If a user requests their account to be deleted, send the following:
```markdown
Deleting an account with many posts disrupts the flow of conversation, and could remove helpful information for other Campers.
We can anonymize your account, which will remove your username along with any other public information associated with your forum account. Your posts will remain, but will be attributed to an anonymous user, and you will be unable to log in to the account, as it will no longer be associated with an email address.
If you would like to proceed with this, please reply to this message with your consent.
```
If a user insists on having their account deleted, ask them to email `support[at]freecodecamp.org` with a link to their forum account.
### Moderating Via Cell Phone
Moderating the forum is possible via a cell phone but you may encounter some usage quirks. This is not an exhaustive list.
- When trying to include a "Canned reply" in a response, if the menu doesn't open (after clicking on the gear), click on the text area first then try it again.
- The moderator's 'wrench' is at the bottom of the view-port but if you click it and cannot see the "Select Posts" button because it has scrolled out of view, you may need to try to scroll to it, though sometimes that doesn't work in which case moving to a desktop/laptop monitor may be needed.
- Sometimes clicking on the three-dot menu below a post can hide the reply icon. Reload the page to get it back.
## 管理 Facebook 小組
If you see anything that seems to break our [Code of Conduct](https://code-of-conduct.freecodecamp.org/), you should delete it immediately.
Sometimes people will post things that they think are funny. They don't realize that what they said or what they shared could be interpreted as offensive. You should delete such posts, but not necessarily ban the person. Hopefully, the user will come to understand that what they posted was inappropriate because the post was deleted.
But if it is an egregious offense that can't reasonably be attributed to a cultural difference or a misunderstanding of the English language. In that case, you should strongly consider blocking the member from the Facebook group.
## Moderating Discord
Here's how moderators deal with violations of our [Code of Conduct](https://code-of-conduct.freecodecamp.org/) on our chat server:
> [!NOTE] Camperbot serves as our moderation bot, and all of the commands use Discord's native slash command interface. You can see a list of all of the commands by typing `/` in any channel.
1. **Make sure the user intended to violate the [Code of Conduct](https://code-of-conduct.freecodecamp.org).**
Not all violations of the [Code of Conduct](https://code-of-conduct.freecodecamp.org) were intended as such. A new camper might post a large amount of code for help, unaware that this can be disruptive to the conversation. In these cases, you can just ask them to paste their code with services like CodePen or Pastebin.
2. **If the camper clearly and intentionally violates the [Code of Conduct](https://code-of-conduct.freecodecamp.org), the moderator will proceed as follows:**
For minor offences, a warning may be issued with the `/warn` command. For more egregious offences, you can remove the member from the server temporarily with the `/kick` command, or permanently with the `/ban` command. In some cases, a member may just need some time to cool off and collect their thoughts - the `/mute` command allows you to prevent them from engaging with our community for a set period of time. A muted member can see the conversation, but cannot post messages or add reactions.
All moderation commands will take a `reason` parameter, which should be a short explanation of why the action was taken. Moderation actions done with the bot will be logged in `#mod-actions`, which allows us all to stay on the same page. As such, we should avoid using Discord's built-in moderation tools, as they will not be logged.
> [!WARNING] The reason provided to a moderation command will also be included in the DM notification to the camper. Please remember to be professional here.
3. **Creating a private discussion**
There may be situations where you need to address a concern with a camper privately. This should not be done through DMs, which can lead to situations where you claim one thing and the camper claims another. Instead, use the bot's functionality to create a private discussion:
- Call the `/private` command, where `target` is the camper you want to open a private channel with.
- The bot will create a new channel, and add the mentioned camper and all moderators with the `Your Friendly Moderator` role. While all moderators are added to the channel for transparency, the moderator who calls this command should be the only one to interact with the camper unless they request assistance.
- When the conversation is complete, click the `❌ Close` button _on the first message in the private channel_ to have the bot close and delete that channel.
4. **Deleting messages**
Our moderation bot is configured to log deleted messages automatically in the `#mod-actions` channel. If a message is not in line with our Code of Conduct, or otherwise not appropriate for our community, you are generally safe to delete it.
Note that if the message contains content that violates Discord's terms of service, you'll want to report it via https://dis.gd/report **prior to** deleting it.
5. **Don’t threaten to take action**
If a camper breaks the [Code of Conduct](https://code-of-conduct.freecodecamp.org), don’t threaten to take moderator action, and never warn them in public. Instead, talk to them privately using the bot's `/private` command, or use the bot's moderation commands.
If a violation was clearly unintended and doesn't warrant moderation action or private conversation, make the offending camper aware of their actions without making it come across as a warning.
For example:
- Camper posts a wall of code to request help:
Moderator: **@username** Please use CodePen or Pastebin when posting large amounts of code.
- Or if you really have to explain why:
Moderator: **@username** Please use CodePen or Pastebin when posting large amounts of code, because it disrupts the chat for everyone and could be considered spamming according to our [Code of Conduct](https://code-of-conduct.freecodecamp.org).
- For mild and unintentional violations of the [Code of Conduct](https://code-of-conduct.freecodecamp.org):
Moderator: This is a friendly reminder for everyone to follow the [Code of Conduct](https://code-of-conduct.freecodecamp.org): https://code-of-conduct.freecodecamp.org/
6. **Don’t brag about being a moderator**
Do not see yourself as above the community. **You are the community.** And the community has trusted you to help protect something rare that we all share - a _welcoming_ place for new developers.
If you brag about being a moderator, people may feel uneasy around you, in the same way that people may feel uneasy around a police officer, even if they’re doing nothing wrong. This is just human nature.
7. **Don’t contradict other moderators**
If you disagree with a moderator's action, talk with them in private or bring it up in the #mod-chat channel. Never override a moderator's action, and never contradict the other moderator(s) publicly. Instead, have a cool-headed discussion in `#mod-chat` and convince the moderator that they themselves should reverse their ban or change their PoV (Point of View).
_Remember: We’re all on the same team. We want to dignify the role of moderators and present a unified front._
8. **Talk with other moderators**
We have a `#mod-chat` room for moderators only. Use it! If you feel uncomfortable with handling a certain situation, ask other moderators for help. If you think something should be discussed, do it. You're part of the team, and we value every team member's input! Even if you totally disagree with anything in these guidelines or the [Code of Conduct](https://code-of-conduct.freecodecamp.org)!
9. **Temporarily inactive**
If you're not going to be active as a Moderator for a while due to vacation, illness, or any other reason, make sure to let the others know in the `#mod-chat` channel. This is so we know if we can count on you to be regularly active on the server or not.
## How to Become a Moderator
Suppose you are helping people in the community consistently over time. In that case, our moderator team will eventually take notice, and one of them will mention you as a possible moderator to [our staff](https://forum.freecodecamp.org/g/Team). There are no shortcuts to becoming a moderator.
If you are approved, we will add you to our moderator teams on [GitHub](https://github.com/orgs/freeCodeCamp/teams/moderators), [forum](https://forum.freecodecamp.org/g/moderators), chat, etc.
> [!NOTE] For GitHub: After you've been accepted as a moderator, you will receive a Github repository invitation. You'll need to head over towards [freeCodeCamp GitHub Organization Invitation](https://github.com/orgs/freeCodeCamp/invitation) to be able to accept the invitation.
>
> This is required for us to be able to give you write access to some of our repositories.
## How Our Contributors Room Works
Anyone is welcome in the [contributors room on our chat server](https://discord.gg/PRyKn3Vbay). It is the designated chat room for moderators and other campers who contribute to our community in any number of ways, including through study groups.
We assume contributors will read anything in this room that directly mentions them with an **@username**. Everything else is optional, but feel free to read anything anyone posts in there and interact.
## Dealing with Solicitors
You may be approached by organizations who want to partner or co-brand with freeCodeCamp somehow. Once you realize that this is what they're after, **please stop talking to them** and tell them to email `team[at]freecodecamp.org`.
We get proposals like this all the time, and the staff are in the best position to judge whether such a relationship will be worth it for our community (and it rarely is).
## Dealing with (Mental) Health Inquiries
You may come across situations where users seek medical advice or are dealing with mental health issues and are looking for support.
As a matter of policy, you should avoid talking privately about these matters. Should the situation reflect back to freeCodeCamp, we want to have the conversation(s) on record. Make it clear that we are not medical professionals and that you encourage the user to find professional help.
As difficult as it sometimes can be, avoid giving any tips or advice and rather point the user in the direction of seeking professional help!
If this happens on our chat server: Create a private channel for the user and the moderator team. This can be done with the bot's `private` command.
- The user is guaranteed some privacy.
- Public chat is no longer disrupted.
- Other team members can pitch in, should you feel uncomfortable dealing with the situation yourself.
Helpful URLs:
http://suicide.org/international-suicide-hotlines.html
## A Note on Free Speech
Sometimes people will defend something offensive or incendiary that they said as "free speech."
This XKCD comic summarizes perfectly most communities' thoughts on free speech.
<div align="center"><img src='./images/github/xkcd-free-speech.png' width="400" height="400" /></div>
Thanks for reading this, and thanks for helping the developer community!
@@ -1,50 +0,0 @@
# The Official freeCodeCamp Moderator Onboarding Guide
This guide will help new moderators get up and running with the processes and procedures followed by experienced moderators on the freeCodeCamp community forum and other official communities we foster.
> [!NOTE] If you haven't read [The Moderator Handbook](https://contribute.freecodecamp.org/#/moderator-handbook) yet, you should start there first.
## The Forum
### First Steps
The first thing you may notice after being given moderator status on the forum is that your interface will look somewhat different, with new admin tools to explore and access to the Mod-Team subforum.
Some of the new tools will appear inside a new menu item that looks like a wrench. Some will appear as new tabs or buttons, or even new enabled options within the forum menus.
To get familiar with the new tools and powers, you can combine one or more of the following methods during your first week with this elevated role:
> [!TIP] The first two are the most important.
### Become Familiar with the Discourse Admin Tools
The freeCodeCamp forum is a Discourse forum and follows many of the same guidelines of other forums built on Discourse. To begin to get familiar with Discourse and the moderation role, start by reading Discourse's [new user guide](https://meta.discourse.org/t/discourse-new-user-guide/96331) and Discourse's [new moderator guide](https://meta.discourse.org/t/discourse-moderation-guide/63116).
### Shadow a Mod
All moderator actions can be followed by reviewing the [action logs](https://forum.freecodecamp.org/admin/logs/staff_action_logs). The actions taken by automated tools like `Akismet` or `system` can mostly be ignored until they result in a post that needs to be reviewed. Posts to be reviewed will show up in the [Review](https://forum.freecodecamp.org/review) area of the forum.
For the first week or so you will want to pay attention to what is getting flagged and what is being reviewed, and compare that to the actions being taken upon the flagged posts. You may see the system account flag a post because the user created it too quickly. In many cases, the moderators will unflag the post by clicking on the "Approve Post" button or mark it as "Not Spam" (depending on the flag type).
Commonly, spam flags can also be raised by members or moderators. Common duplicitous behavior would involve opening an account, making a post that seems harmless, then editing that post later on to add a link to an external site to advertise it. In this case, the member account is usually fairly new and has only made this one post thus far, which indicates that the account was opened solely for spamming the community. The decision should be made to delete the account after the first offense in this case. The same applies to accounts whose first post is deemed to be spam.
You may notice moderators performing a procedure called 'split topic'. This may be a case where a moderator has split a post that was made erroneously on an existing topic into a new topic, or a moderator merged duplicate topics that a single user has created for the same question. Watching this procedure will highlight different actions and their causes.
Another useful feature that becomes enabled for all moderators is the ability to post a "Canned Reply" which is a pre-written response that was worked out with the mod team to quickly respond to some well-known and repetitive scenarios. These include:
- Welcoming a new forum member who has posted code without a question -> "Welcome - remind question"
- Reminding members not to post code solutions but to provide hints and tips instead -> "Solutions Instead of Help"
- Responding to a situation where someone's code works for you but not for them -> "Browser Issues"
- Encouraging members to open GitHub issues when a possible bug is found -> "Bug Report"
There are more, which you can read through to become familiar with their respective uses. You can also find discussions around the templates in the mod-team subforum, and you are welcome to ask questions if you aren't sure how a template should be used.
### Read Mod-Team Subforum Posts
The Mod-Team subforum contains several posts from past and current moderators discussing the different requirements and/or challenges of moderating the forum.
Reading back through these posts can help uncover some of the underlying goals and processes that concern forum moderators. Some of the threads may also shed some light on the handling of spam and inappropriate content on the forum.
## Where to Ask for Help
To get help dealing with a situation that you are either uncomfortable with or unsure of how to handle, discuss with your fellow moderators on either the [Mod-Team Subforum](https://forum.freecodecamp.org/c/mod-team/4) or the [#mod-chat](https://discord.com/channels/692816967895220344/693157007418720277) on Discord.
@@ -1,250 +0,0 @@
# Reply Templates
These are some of the standard reply templates that you may use while reviewing pull requests and triaging issues/pull requests.
> You can make your own saved replies with GitHub's built-in [saved replies](https://github.com/settings/replies/) feature or use the ones below.
## Thank You
```markdown
Thank you for your contribution to the page! 👍
We are happy to accept these changes and look forward to future contributions. 🎉
```
## Thank you and congrats
> For thanking and encouraging first-time contributors.
```markdown
Hi @username. Congrats on your first pull request (PR)! 🎉
Thank you for your contribution to the page! 👍
We are happy to accept these changes and look forward to future contributions. 📝
```
## Build Error
```markdown
Hey @username
We would love to be able to merge your changes but it looks like there is an error with the CI build. ⚠️
Once you resolve these issues, we will be able to review your PR and merge it. 😊
---
Feel free to reference the [contributing guidelines](https://contribute.freecodecamp.org/#/how-to-work-on-coding-challenges.md?id=testing-challenges) for instructions on running the CI build locally. ✅
```
## Syncing Fork
> When PR is not up to date with the `main` branch.
````markdown
Hey @username
We would love to be able to merge your changes, but it looks like the branch is not up to date. ⚠️
To resolve this error, you will have to sync the latest changes from the `main` branch of the `freeCodeCamp/freeCodeCamp` repo.
Using the command line, you can do this in three easy steps:
```bash
git remote add upstream git://github.com/freeCodeCamp/freeCodeCamp.git
git fetch upstream
git pull upstream main
```
If you're using a GUI, you can simply `Add a new remote...` and use the link `git://github.com/freeCodeCamp/freeCodeCamp.git` from above.
Once you sync your fork and pass the build, we will be able to review your PR and merge it. 😊
---==crwdHRulesLBB_2_BBsuleRHdwrc==
Feel free to reference the ["Syncing a fork"](https://help.github.com/articles/syncing-a-fork/) article on GitHub for more insight on how to keep your fork up-to-date with the upstream repository. 🔄
````
## Merge Conflicts
> When PR has merge conflicts that need to be resolved.¹
```markdown
Hey @username
We would love to be able to merge your changes, but it looks like you have some merge conflicts. ⚠️
Once you resolve these conflicts, we will be able to review your PR and merge it. 😊
---
If you're not familiar with the merge conflict process, feel free to look over GitHub's guide on ["Resolving a merge conflict"](https://help.github.com/articles/resolving-a-merge-conflict-on-github/). 🔍️
Also, it's good practice on GitHub to write a brief description of your changes when creating a PR. 📝
```
¹ If a first-time-contributor has a merge conflict, maintainers will resolve the conflict for them.
## Duplicate
> When PR is repetitive or a duplicate.
```markdown
Hey @username
This PR seems to make similar changes as the existing PR <#number>. As such, we are going to close this as a duplicate.
If you feel you have additional changes to expand upon this PR, please feel free to push your commits and request this PR be reopened.
Thanks again! 😊
---
If you have any questions, feel free to ask questions on the ["Contributors" category on our forum](https://forum.freecodecamp.org/c/contributors) or [the contributors chat room](https://discord.gg/PRyKn3Vbay).
```
## Closing Invalid Pull Requests
> When PR is invalid.
```markdown
Hey there,
Thank you for opening this pull request.
This is a standard message notifying you that we've reviewed your pull request and have decided not to merge it. We would welcome future pull requests from you.
Thank you and happy coding.
```
> When PR adds links to external resources.
```markdown
Thank you for your pull request.
We are closing this pull request. Please suggest links and other details to add the challenge's corresponding guide post through [a forum topic](https://forum.freecodecamp.org/new-topic?category=Contributors&title=&body=**What%20is%20your%20hint%20or%20solution%20suggestion%3F**%0A%0A%0A%0A%0A**Challenge%3A**%0A%0A%0A**Link%20to%20the%20challenge%3A**) instead.
If you think we're wrong in closing this issue, please request for it to be reopened and add further clarification. Thank you and happy coding.
```
## Adding Comment About Newbie Mistakes
```markdown
Hello,
Firstly, thank you for submitting this pull request!
As you navigate through the process, we have a PR checklist to ensure consistency and quality in our contributions. We kindly ask that you genuinely follow through with each point. This not only facilitates the review process but also demonstrates a mutual respect for the community's efforts.
If you're unfamiliar with certain aspects, our [contributing guidelines](https://contribute.freecodecamp.org) are a helpful resource to get you up to speed.
<details>
<summary>**Friendly Pointers (click to expand)**</summary>
1. **Editing on GitHub:** While it's possible to edit files directly on GitHub, it's typically better not to. This helps avoid inadvertent mistakes like typos that can disrupt tests.
2. **Pull Request Title:** Please ensure the PR title follows [our convention](https://contribute.freecodecamp.org/#/how-to-open-a-pull-request?id=prepare-a-good-pr-title).
3. **Linking Issues:** Please ensure you link issues using the designated method. Simply update the `XXXXXX` in the PR description to include the issue number. This keeps our records organized and clear.
4. **Engaging with the Team:** We know you're eager, but kindly keep mentions and review requests limited. Our maintainers are always on the lookout and will attend to PRs in the order they come in.
5. **Branch Management:** It's a good practice not to work directly off your `main` branch. Creating separate branches for different changes allows you to smoothly update your PR even as the main repository progresses.
</details>
Please note, there's no need to close this PR. If you have questions or need guidance refining your contribution, don't hesitate to ask. Our community is here to assist.
Thank you for your enthusiasm in contributing to our project. We eagerly await more contributions from you!
**Happy Contributing!** 🌟
```
## PR Opened While Issue Is Not Triaged
> When a PR is opened for an issue that hasn't been triaged and marked as ready for contribution.
```markdown
Hi there,
Thanks for creating this pull request.
The linked issue has not been triaged yet, and a solution has not been agreed upon. Once the issue is open for contribution, you are welcome to update this pull request to reflect the issue consensus. Until the issue is open for contribution, we will not be able to review your pull request.
```
## Closing Invalid Issues
> When an issue relates to the camper's code.
```markdown
Thank you for reporting this issue.
This is a standard message notifying you that this issue seems to be a request for help. Instead of asking for help here, please click the **"Get Help"** button on the challenge on freeCodeCamp and choose the **"Ask for help"** option, which will help you create a question in the right part of the forum. Volunteers on the forum usually respond to questions within a few hours and can help determine if there is an issue with your code or the challenge's tests.
If the forum members determine there is nothing wrong with your code, you can request this issue to be reopened.
Thank you and happy coding.
```
> When an issue is a duplicate of an earlier issue.
```markdown
Thank you for reporting this issue.
This is a standard message notifying you that this issue appears to be very similar to issue #XXXXX, so we are closing it as a duplicate.
If you think we're wrong in closing this issue, please request for it to be reopened and add further clarification. Thank you and happy coding.
```
> When an issue is fixed in staging.
```markdown
Thank you for reporting this issue.
This is a standard message notifying you that the problem you mentioned here is present in production, but that it has already been fixed in staging. This means that the next time we push our staging branch to production, this problem should be fixed. Because of this, we're closing this issue.
If you think we're wrong in closing this issue, please request for it to be reopened and add further clarification. Thank you and happy coding.
```
## `first timer only` Issues
> When an issue is deemed to be eligible for first-time code contributors.
```markdown
Thanks for opening this issue.
This looks like something that can be fixed by "first-time" code contributors to this repository. Here are the files that you should be looking at to work on a fix:
List of files:
1. ...
2. ...
3. ...
Please make sure you read our [guidelines for contributing](https://contribute.freecodecamp.org/#/), we prioritize contributors following the instructions in our guides. Join us in our [chat room](https://discord.gg/PRyKn3Vbay) or our [forum](https://forum.freecodecamp.org/c/contributors/3) if you need help contributing; our moderators will guide you through this.
Sometimes we may get more than one pull request. We typically accept the most quality contribution followed by the one that is made first.
Happy contributing.
```
## Requests for Assignment
```md
We typically do not assign issues. Instead, we accept the first pull request that comprehensively solves the issue.
Issues labeled with `help wanted` or `first timers only` are open for contributions.
Please make sure you read [our guidelines for contributing](https://contribute.freecodecamp.org/#/). We prioritize contributors following the instructions in our guide. Join us in [our chat room](https://discord.gg/PRyKn3Vbay) or [the forum](https://forum.freecodecamp.org/c/contributors/3) if you need help contributing - our community will be happy to assist you.
```
## Requests for Assignment While Issue Is Not Triaged
> When a contributor requests for assignment but the issue hasn't been triaged or marked as ready for contribution.
```md
Hi there,
Thanks for your interest in contributing.
This issue has not been triaged yet, and a solution has not been agreed upon. Once the issue is open for contribution, you are welcome to create a pull request to reflect the issue consensus. Please also note that we typically do not assign issues. Instead, we accept the first pull request that comprehensively solves the issue.
```
@@ -1,12 +0,0 @@
# Responsible Disclosure - Hall of Fame
We appreciate any responsible disclosure of vulnerabilities that might impact the integrity of our platforms and users. If you are interested in contributing to the security of our platform, please read our [security policy outlined here](security.md).
While we do not offer any bounties or swags at the moment, we are grateful to these awesome people for helping us keep the platform safe for everyone:
- Mehul Mohan from [codedamn](https://codedamn.com) ([@mehulmpt](https://twitter.com/mehulmpt)) - [Vulnerability Fix](https://github.com/freeCodeCamp/freeCodeCamp/blob/bb5a9e815313f1f7c91338e171bfe5acb8f3e346/client/src/components/Flash/index.js)
- Peter Samir https://www.linkedin.com/in/peter-samir/
- Laurence Tennant ([@hyperreality](https://github.com/hyperreality)) working with IncludeSecurity.com - [GHSA-cc3r-grh4-27gj](https://github.com/freeCodeCamp/freeCodeCamp/security/advisories/GHSA-cc3r-grh4-27gj)
- Michal Biesiada ([@mbiesiad](https://github.com/mbiesiad)) - [GHSA-6c37-r62q-7xf4](https://github.com/freeCodeCamp/freeCodeCamp/security/advisories/GHSA-6c37-r62q-7xf4)
> **Thank you for your contributions :pray:**
-54
View File
@@ -1,54 +0,0 @@
# freeCodeCamp.org's Security Policy
This document outlines our security policy for the codebases, platforms that we operate, and how to report vulnerabilities.
## Reporting a Vulnerability
> [!NOTE] If you think you have found a vulnerability, **please report it responsibly**. Do not create GitHub issues for security issues. Instead, follow this guide.
### Guidelines
We appreciate responsible disclosure of vulnerabilities that might impact the integrity of our platforms and users. In the interest of saving everyone time, we encourage you to report vulnerabilities with these in mind:
1. Ensure that you are using the **latest**, **stable**, and **updated** versions of the Operating System and Web Browser(s) available to you on your machine.
2. We consider using tools & online utilities to report issues with SPF & DKIM configs, SSL Server tests, etc., in the category of ["beg bounties"](https://www.troyhunt.com/beg-bounties) and are unable to respond to these reports.
3. While we do not offer any bounties or swags at the moment, we'll be happy to list your name in our [Hall of Fame](security-hall-of-fame.md) list, provided the reports are not low-effort.
### Reporting
After confirming the above guidelines, please feel free to send an email to `possible-security-issue [at] freecodecamp.org`. You can also send us a PGP encrypted message at `flowcrypt.com/me/freecodecamp`.
Once you report a vulnerability, we will look into it and ensure that it is not a false positive. If we need to clarify any details, we will get back to you. You can submit separate reports for each issue you find. Please note that we will not be able to respond to any issues that we think are outside the guidelines.
## Platforms and Codebases
Here is a list of the platforms and codebases we are accepting reports for:
### Learn Platform
| Version | Branch | Supported | Website active |
| ----------- | -------------- | --------- | ------------------------ |
| production | `prod-current` | Yes | `freecodecamp.org/learn` |
| staging | `prod-staging` | Yes | `freecodecamp.dev/learn` |
| development | `main` | No | |
### Publication Platform
| Version | Supported | Website active |
| ---------- | --------- | ---------------------------------------- |
| production | Yes | `freecodecamp.org/news` |
| localized | Yes | `freecodecamp.org/<language>/news` |
### Mobile App
| Version | Supported | Website active |
| ---------- | --------- | ---------------------------------------------------------------- |
| production | Yes | `https://play.google.com/store/apps/details?id=org.freecodecamp` |
### Other Platforms
Apart from the above, we are also accepting reports for repositories hosted on GitHub under the freeCodeCamp organization.
### Other Self-hosted Applications
We self-host some of our platforms using open-source software like Ghost & Discourse. If you are reporting a vulnerability, please ensure that it is not a bug in the upstream software.
@@ -1,91 +0,0 @@
If you are facing an issue, there is a high chance that the resolution is in this documentation.
## Issues with Installing the Recommended Prerequisites
We regularly develop on the latest or most popular operating systems like macOS 10.15 or later, Ubuntu 18.04 or later, and Windows 10 (with WSL2).
It is recommended to research your specific issue on resources such as Google, Stack Overflow, and Stack Exchange. There is a good chance that someone has faced the same issue and there is already an answer to your specific query.
If you are on a different OS or are still facing issues, see [getting help](#getting-help).
> [!WARNING]
>
> Please avoid creating GitHub issues for problems with the prerequisite technologies. They are out of the scope of this project.
## Issues with Missing UI, Fonts, Language Strings, or Build Errors
When you build the client, Gatsby will cache the fonts, language strings, and UI. If one of them isn't cached, run the following:
```bash
pnpm run clean
pnpm install
pnpm run seed
pnpm run develop
```
OR
Use the shortcut
```
pnpm run clean-and-develop
```
If you continue to face issues with the build, cleaning up the workspace is recommended.
Use `git clean` in interactive mode:
```
git clean -ifdX
```
<details>
<summary>
How to clean git untracked files (screenshot)
</summary>
<br>
<img src="https://user-images.githubusercontent.com/1884376/94270515-ca579400-ff5d-11ea-8ff1-152cade31654.gif" alt="How to clean git untracked files" />
</details>
## Issues with API, login, Challenge Submissions, etc.
If you can't sign in, and instead you see a banner with an error message saying that the error will be reported to freeCodeCamp, please double-check that your local port `3000` is not in use by a different program.
#### **From Terminal:**
```bash
netstat -a | grep "3000"
tcp4 0 0 0.0.0.0:3000 DESKTOP LISTEN
```
## Issues Signing Out while Navigating
While in development, your session is stored as cookies. Clearing them will sign you out of your development account.
Running `pnpm run seed:certified-user` will log you out, too. It will overwrite the development user in your local database.
## Issue Getting 404 when Navigating Profile Page
When you try to navigate to http://localhost:8000/developmentuser to view the profile page, Gatsby takes over serving the client-side pages and hence you will get a 404 page for the user profile when working.
There is a "Preview Custom 404 Page" button, click it to see the profile.
## Issues Installing Dependencies
If you get errors while installing the dependencies, please make sure that you are not in a restricted network or your firewall settings do not prevent you from accessing resources.
The first time setup can take a while depending on your network bandwidth. Be patient, and if you are still stuck we recommend using Gitpod instead of an offline setup.
> [!NOTE] If you are using Apple Devices with M1 Chip to run the application locally, it is suggested to use Node v14.7 or above. You might run into issues with dependencies like Sharp otherwise.
## Working With Other Languages
To see how the client renders in another language go to [testing the client app in a world language.](how-to-work-on-localized-client-webapp.md#Testing-the-Client-App-in-a-World-Language)
## Getting Help
If you are stuck and need help, feel free to ask questions in the ['Contributors' category on our forum](https://forum.freecodecamp.org/c/contributors) or [the contributors chat room](https://discord.gg/PRyKn3Vbay).
There might be an error in the console of your browser or in Bash / Terminal / Command Line that will help identify the problem. Provide this error message in your problem description so others can more easily identify the issue and help you find a resolution.
@@ -1,15 +0,0 @@
# How the User Token Workflow Works
User tokens are used to identify users to third parties so challenges completed using those services can be saved to a user's account.
## How they are Created
At the moment, the tokens are only used to submit the Relational Database challenges. A token gets created when a signed-in user clicks the "Click here to start the course" or "Click here to start the project" buttons to start one of the Relational Database courses or projects.
## When they Get Deleted
A user token will be deleted when a user signs out of freeCodeCamp, resets their progress, deletes their account, or manually deletes the token using the widget on the settings page.
## How they Work
Tokens are stored in a `UserToken` collection in the database. Each record has a unique `_id`, which is the token, and a `user_id` that links to the user's account from the `user` collection. The token is encoded using JWT and sent to the client when it's created. That encoded token is then given to third-party services that need it and sent to our API by them when a challenge is completed. When our API gets it, it is decoded so we can identify the user submitting a challenge and save the completed challenge to their `completedChallenges`.
-109
View File
@@ -1,109 +0,0 @@
# Frequently Asked Questions
Answers to common questions.
## I am new to GitHub and Open Source. Where should I start?
Read our ["How to Contribute to Open Source Guide"](https://github.com/freeCodeCamp/how-to-contribute-to-open-source). It's a comprehensive reference for first-timer-friendly projects. And it includes a lot of open-source contribution tips.
## What do I need to know to contribute to the codebase?
freeCodeCamp runs on a modern JavaScript stack. If you're interested in contributing to our codebase, you will need some familiarity with JavaScript and some of the technologies we use like Node.js, MongoDB, OAuth 2.0, React, Gatsby, and Webpack.
## Can I translate freeCodeCamp's resources?
Yes - You can contribute to any of the 30+ languages we have enabled on our translation platform.
We have user-contributed translations live in some languages. We intend to localize freeCodeCamp into several major world languages. You can read all about this in our [announcement here](https://www.freecodecamp.org/news/help-translate-freecodecamp-language/).
If you are interested in contributing to translations please make sure you [read this guide](how-to-translate-files.md) first.
## Can I contribute articles to freeCodeCamp News or videos to freeCodeCamp's YouTube channel?
Yes - you can contribute to our publication blog and YouTube channel.
If you're interested in writing articles for freeCodeCamp News, please visit this [publication guide](https://www.freecodecamp.org/news/how-to-write-for-freecodecamp/). In addition, please read our [style guide](https://www.freecodecamp.org/news/developer-news-style-guide/) as this will help you write stronger and more effective articles.
To help us make educational videos for our YouTube channel, you can follow the [YouTube channel guide here](https://www.freecodecamp.org/news/how-to-contribute-to-the-freecodecamp-community-youtube-channel-b86bce4c865/).
## How can I report a new bug?
If you think you've found a bug, first read the ["How to Report a Bug"](https://www.freecodecamp.org/news/how-to-report-a-bug-to-freecodecamp/) article and follow its instructions.
If you're confident it's a new bug, go ahead and create a new GitHub issue. Be sure to include as much information as possible so that we can reproduce the bug. We have a pre-defined issue template to help you through this.
Please note that these GitHub issues are for codebase-related issues and discussions – not for getting help with learning to code. Whenever in doubt, you should [seek assistance on the forum](https://forum.freecodecamp.org) before creating a GitHub issue.
## How can I report a security issue?
Please don't create GitHub issues for security issues. Instead, please [follow our security policy](https://contribute.freecodecamp.org/#/security).
## I am a student. Can I work on a feature for academic credits?
Yes. Please note we are unable to commit to any timelines or paperwork that may be a requirement by your college or university. We receive many pull-requests and code contributions from volunteer developers, and we respect their time and efforts. Out of respect for all of our other contributors, we will not give any PR special priority just because it happens to be school-related.
We request you to plan ahead and work on code contributions with this in mind.
## What do these different labels that are tagged on issues mean?
The code maintainers [triage](https://en.wikipedia.org/wiki/Software_bug#Bug_management) issues and pull requests based on their priority, severity, and other factors. You can [find a complete glossary of their meanings here](https://github.com/freecodecamp/freecodecamp/labels).
## Where do I start if I want to work on an issue?
You should go through [**`help wanted`**](https://github.com/freeCodeCamp/freeCodeCamp/issues?q=is%3Aopen+is%3Aissue+label%3A%22help+wanted%22) or [**`first timers only`**](https://github.com/freeCodeCamp/freeCodeCamp/issues?q=is%3Aopen+is%3Aissue+label%3A%22first+timers+only%22) issues for a quick overview of what is available for you to work on.
> [!TIP] **`help wanted`** issues are up for grabs, and you do not need to seek permission before working on them. 然而,具有 **`first timers only`** 标签的 issue 是特别为以前没有为 freeCodeCodeCamp 代码库贡献的人设计的任务。
## I found a typo. Should I report an issue before I can make a pull request?
For typos and other wording changes, you can directly open pull requests without creating an issue first. Please be sure to mention details in the pull request description to help us understand and review your contribution – even if it's just a minor change.
Please do create an issue if you want to discuss bigger aspects of the codebase or curriculum.
## How can I get an issue assigned to me?
We typically do not assign issues to anyone other than long-time contributors. Instead, we follow the below policy to be fair to everyone:
1. We are most likely to merge the first pull request that addresses the issue.
2. In the case of multiple contributors opening a pull request for the same issue at around the same time, we will give priority to the pull request that best addresses the issue. Some of the things we consider:
- Did you include tests?
- 你是否考虑了所有用例?
- 你是否确保通过所有测试,并确认所有东西在本地正常运行?
3. Finally, we give priority to pull requests which follow our recommended guidelines.
- Did you follow the pull request checklist?
- Did you give your pull request a meaningful title?
## I am interested in being a moderator at freeCodeCamp. Where should I start?
Our community moderators are our heroes. Their voluntary contributions make freeCodeCamp a safe and welcoming community.
First and foremost, we would need you to be an active participant in the community, and live by our [code of conduct](https://www.freecodecamp.org/news/code-of-conduct/) (not just enforce it).
Here are some recommended paths for some of our platforms:
- To be a **Discord/Chat** moderator, have an active presence in our chat and have positive engagements with others, while also learning and practicing how to deal with potential conflicts that may arise.
- To be a **Forum** moderator, similar to a chat moderator, have an active presence and engage with other forum posters, supporting others in their learning journey, and even giving feedback when asked. Take a look at [The Subforum Leader Handbook](https://forum.freecodecamp.org/t/the-subforum-leader-handbook/326326) for more information.
- To be a **GitHub** moderator, help process GitHub issues that are brought up to see if they are valid and (ideally) try to propose solutions for these issues to be picked up by others (or yourself).
Altogether, be respectful to others. We are humans from all around the world. With that in mind, please also consider using encouraging or supportive language and be mindful of cross-cultural communication.
If you practice the above **consistently for a while** and our fellow moderator members recommend you, a staff member will reach out and onboard you to the moderators' team. Open source work is voluntary work and our time is limited. We acknowledge that this is probably true in your case as well. So we emphasize being **consistent** rather than engaging in the community 24/7.
Take a look at our [Moderator Handbook](moderator-handbook.md) for a more exhaustive list of other responsibilities and expectations we have of our moderators.
## I am stuck on something that is not included in this documentation.
**Feel free to ask for help in:**
- The `Contributors` category of [our community forum](https://forum.freecodecamp.org/c/contributors).
- The `#Contributors` channel on [our chat server](https://discord.gg/PRyKn3Vbay).
We are excited to help you contribute to any of the topics that you would like to work on. If you ask us questions on the related issue threads, we will be glad to clarify. Be sure to search for your question before posting a new one.
Thanks in advance for being polite and patient. Remember – this community is run mainly by volunteers.
## Additional Assistance
If you have queries about the stack, architecture of the codebase, translations, or anything else, feel free to reach out to our staff team [on the forum](https://forum.freecodecamp.org/g/team).
**You can email our developer staff at: `dev[at]freecodecamp.org`**
-48
View File
@@ -1,48 +0,0 @@
- **准备开始**
- [介绍](index.md "为 freeCodeCamp.org 社区贡献")
- [常见问题](FAQ.md)
- [Reporting a Vulnerability](security.md)
- **Translation Contribution**
- [Work on translating resources](how-to-translate-files.md)
- [Work on proofreading translations](how-to-proofread-files.md)
- **Code Contribution**
- [Set up freeCodeCamp](how-to-setup-freecodecamp-locally.md)
- [Follow best-practices](codebase-best-practices.md)
- [Work on Codebase](how-to-contribute-to-the-codebase.md)
- [Work on Coding Challenges](how-to-work-on-coding-challenges.md)
- [Use the Curriculum Helpers](curriculum-help.md)
- [Work on Component Library](how-to-work-on-the-component-library.md)
- [Work on Practice Projects](how-to-work-on-practice-projects.md)
- [Work on Mobile app](how-to-setup-freecodecamp-mobile-app-locally.md)
- [Work on tutorials with CodeRoad](how-to-work-on-tutorials-that-use-coderoad.md)
- [Work on Localized Web App](how-to-work-on-localized-client-webapp.md)
- [Work on Playwright Tests](how-to-add-playwright-tests.md)
- [Work on Video Challenges](how-to-help-with-video-challenges.md)
- [Work on Documentation](how-to-work-on-the-docs-theme.md)
- [Open a pull request](how-to-open-a-pull-request.md)
- **Additional Guides**
- [Understand the curriculum file structure](curriculum-file-structure.md)
- [Debug outgoing emails locally](how-to-catch-outgoing-emails-locally.md)
- [Work on Cypress Tests](how-to-add-cypress-tests.md)
- [Set up freeCodeCamp on Windows (WSL)](how-to-setup-wsl.md)
- [Use Docker on Windows Home](how-to-use-docker-on-windows-home.md)
- [User Token Workflow](user-token-workflow.md)
- [Troubleshooting Development Issues](troubleshooting-development-issues.md)
- [Authors Analytics Manual](authors-analytics-manual.md)
---
- **飞行手册**(针对员工 & 维护人员)
- [维护人员手册](moderator-handbook.md)
- [Reply Templates](reply-templates.md)
- [Language Lead Handbook](language-lead-handbook.md)
- [DevOps Handbook](devops.md)
- [Courses VSCode Extension](courses-vscode-extension.md)
- [Enable New Language](how-to-enable-new-languages.md)
---
- **我们的社区**
- [**GitHub**](https://github.com/freecodecamp/freecodecamp)
- [**Discourse 论坛**](https://freecodecamp.org/forum/c/contributors)
- [**聊天室**](https://discord.gg/PRyKn3Vbay)
@@ -1,27 +0,0 @@
# Authors Analytics Manual
If you are an author with access to the publication's Google Analytics Property (News), you can use this guide to view your article engagement and search for articles by publication language.
## Search by Language
To search for engagement reports in a specific language:
![Image - Show steps to search by language on googla analytics](https://contribute.freecodecamp.org/images/google-analytics/search-by-language.png)
1. From the top dropdown menu, select `News`.
1. From the sidebar, click on `Reports`.
1. From the secondary sidebar, select `Engagement`.
1. Click on `Pages and Screens`.
1. In the search bar, type the subpath for the desired language.
1. From the dropdown under the search bar, choose `Page path and screen class`.
## Filter Reports by Author
After arriving at the `Pages and Screens` reports mentioned above, use the following steps to filter the results by specific authors.
![Image - Show steps to search by language on googla analytics](https://contribute.freecodecamp.org/images/google-analytics/filter-by-author.png)
1. Click on the `Add filter` button.
1. From the side navigation include `Author`.
1. From the `Dimensions values` dropdown, choose an author's name.
1. Click on the `Apply` button to apply changes.
@@ -1,188 +0,0 @@
# Codebase Best Practices
## Styling a component
We recommend styling components using our [design style guide](https://design-style-guide.freecodecamp.org/).
The colors are defined in [`variable.css`](/client/src/components/layouts/variables.css), and the fonts are in [`fonts.css`](/client/src/components/layouts/fonts.css).
We are strongly opinionated about adding new variables/tokens to the colors. After careful research, the colors have been chosen to respect the freeCodeCamp brand identity, developer experience, and accessibility.
The `!important` keyword may be used to override values in some cases (e.g. accessibility concerns). You should add a comment describing the issue, so it doesn't get removed in future refactoring.
### RTL support
We are striving to support right-to-left (RTL) layout in the codebase for languages that are read in this direction. For this, you need to be mindful of how to style components. Here are some quick rules of thumb to follow:
- Don't use `float` properties
- Use Flexbox and Grid layouts instead, as they have RTL support already built-in, and those will be easier to maintain and review.
- Don't define the direction while using `margin` and `padding`: it may seem harmless to use `padding-right` and `margin-left`, but these directions aren't mirrored when the layout changes to RTL, and adding counter values for them in the RTL file makes maintaining the codebase harder.
- Use logical properties for them: You can add the same spacing by using `padding-inline-end` and `margin-inline-start`, and you won't need to worry about RTL layout, as they follow where the line starts and ends, and you won't need to add any extra values in the RTL files, so people won't need to remember to change the same values in two files.
- Don't use `!important` in `font-family`: RTL layout uses different fonts compared to the LTR layout, when you add `!important` in the `font-family` property it affects the RTL layout too.
## General JavaScript
In most cases, our [linter](how-to-setup-freecodecamp-locally.md#follow-these-steps-to-get-your-development-environment-ready) will warn of any formatting which goes against this codebase's preferred practice.
It is encouraged to use functional components over class-based components.
## Specific TypeScript
### Migrating a JavaScript File to TypeScript
#### Retaining Git File History
Sometimes changing the file from `<filename>.js` to `<filename>.ts` (or `.tsx`) causes the original file to be deleted, and a new one created, and other times the filename just changes - in terms of Git. Ideally, we want the file history to be preserved.
The best bet at achieving this is to:
1. Rename the file
2. Commit with the flag `--no-verify` to prevent Husky from complaining about the lint errors
3. Refactor to TypeScript for migration, in a separate commit
> [!NOTE] Editors like VSCode are still likely to show you the file has been deleted and a new one created. If you use the CLI to `git add .`, then VSCode will show the file as renamed in stage
### Naming Conventions
#### Interfaces and Types
For the most part, it is encouraged to use interface declarations over type declarations.
React Component Props - suffix with `Props`
```typescript
interface MyComponentProps {}
// type MyComponentProps = {};
const MyComponent = (props: MyComponentProps) => {};
```
React Stateful Components - suffix with `State`
```typescript
interface MyComponentState {}
// type MyComponentState = {};
class MyComponent extends Component<MyComponentProps, MyComponentState> {}
```
Default - object name in PascalCase
```typescript
interface MyObject {}
// type MyObject = {};
const myObject: MyObject = {};
```
<!-- #### Redux Actions -->
<!-- TODO: Once refactored to TS, showcase naming convention for Reducers/Actions and how to type dispatch funcs -->
## Redux
### Action Definitions
```typescript
enum AppActionTypes = {
actionFunction = 'actionFunction'
}
export const actionFunction = (
arg: Arg
): ReducerPayload<AppActionTypes.actionFunction> => ({
type: AppActionTypes.actionFunction,
payload: arg
});
```
### How to Reduce
```typescript
// Base reducer action without payload
type ReducerBase<T> = { type: T };
// Logic for handling optional payloads
type ReducerPayload<T extends AppActionTypes> =
T extends AppActionTypes.actionFunction
? ReducerBase<T> & {
payload: AppState['property'];
}
: ReducerBase<T>;
// Switch reducer exported to Redux combineReducers
export const reducer = (
state: AppState = initialState,
action: ReducerPayload<AppActionTypes>
): AppState => {
switch (action.type) {
case AppActionTypes.actionFunction:
return { ...state, property: action.payload };
default:
return state;
}
};
```
### How to Dispatch
Within a component, import the actions and selectors needed.
```tsx
// Add type definition
interface MyComponentProps {
actionFunction: typeof actionFunction;
}
// Connect to Redux store
const mapDispatchToProps = {
actionFunction
};
// Example React Component connected to store
const MyComponent = ({ actionFunction }: MyComponentProps): JSX.Element => {
const handleClick = () => {
// Dispatch function
actionFunction();
};
return <button onClick={handleClick}>freeCodeCamp is awesome!</button>;
};
export default connect(null, mapDispatchToProps)(MyComponent);
```
<!-- ### Redux Types File -->
<!-- The types associated with the Redux store state are located in `client/src/redux/types.ts`... -->
## API
### Testing
The `api/` tests are split into two parts:
1. Unit tests
2. Integration tests
#### Unit Tests
Unit tests isolate a single function or component. The tests do not need mocking, but will require fixtures.
The unit tests are located in a new file adjacent to the file exporting that is being tested:
```text
api/
├── src/
│ ├── utils.ts
│ ├── utils.test.ts
```
#### Integration Tests
Integration tests test the API as a whole. The tests will require mocking and should not require fixtures beyond the database seeding data and a method for authentication.
Typically, each integration test file will be directly related to a route. The integration tests are located in the `api/tests/` directory:
```text
api/
├── tests/
│ ├── settings.ts
```
## Further Literature
- [TypeScript Docs](https://www.typescriptlang.org/docs/)
- [TypeScript with React CheatSheet](https://github.com/typescript-cheatsheets/react#readme)
@@ -1,41 +0,0 @@
# Courses VSCode Extension
This details the maintenance guidelines for the [freeCodeCamp/courses-vscode-extension](https://github.com/freeCodeCamp/courses-vscode-extension) repository which contains the source code for the [freeCodeCamp - Courses](https://marketplace.visualstudio.com/items?itemName=freeCodeCamp.freecodecamp-courses) extension.
## Publishing the Extension
A GitHub Action automagically publishes the extension to the Visual Studio Marketplace, on the release of a new GitHub Release.
1. Package a new version of the extension:
```bash
npm run pack -- <tag_type>
```
Where `<tag_type>` is one of: `major`, `minor`, `patch`.
2. Push the new version to `main`:
```bash
git commit -am "<tag_type>(<version>): <description>"
git push
```
Optionally, you can push directly to `upstream/main`, but opening a new PR is recommended for a sanity check.
3. Create a new GitHub Release using the GitHub UI:
- Correctly increment the version number, when creating a new tag.
- Upload the `.vsix` file with the release.
- Publish the release, and confirm the action succeeded.
> [!NOTE] Creating a release requires write access to the `freeCodeCamp/courses-vscode-extension` repository.
## Manually Publishing the Extension
A manual upload to the Visual Studio Marketplace can be achieved, by following these steps:
1. Visit https://marketplace.visualstudio.com/ and sign in
2. Navigate to the [freeCodeCamp Publisher page](https://marketplace.visualstudio.com/manage/publishers/freecodecamp)
3. Select the relevant extension, and select `Update`
4. Upload the file from your local files
@@ -1,105 +0,0 @@
# Curriculum File Structure
Our core instructional content is located within the conveniently named `curriculum` directory. This page will break down how these files are organized.
## Terminology
There are a few terms we use when discussing our curriculum content.
- `certification` : When referring to a certification in this instance, it is talking about the actual certificate that users claim. Which is separate from the name of the superBlock.
- `superBlock` : A superblock is the top level collection of challenges. Each superblock corresponds to a certification in the curriculum (e.g. Responsive Web Design).
- `block` : A block is a section within a superblock. A block corresponds to a group of challenges in a given certification (e.g. Basic HTML and HTML5)
- `challenge` : A challenge is a single lesson within the curriculum (e.g. Say Hello to HTML Elements)
## File Tree
Using those terms, here is how the file structure would be defined:
<!-- prettier-ignore -->
```md
curriculum/
├─ _meta/
│ ├─ {block}/
│ │ ├─ meta.json
├─ {language}/
│ ├─ {superBlock}/
│ │ ├─ {block}/
│ │ │ ├─ {challenge}.md
```
## The `_meta` Directory
The `_meta` directory is a special directory which contains `.json` files. These files correspond to each block in the curriculum, and are used to determine which superBlock a block belongs to, and the order of the challenges within that block.
## Renaming Files
There may be times when you need to rename a certificate, superblock, block, or challenge. This section will outline the steps needed to avoid build errors when doing so.
> [!ATTENTION] Renaming files within the curriculum structure will often change the path (or URL) of the content on the main webpage. Doing so should be done with care, as redirects have to be set up for each change that is made.
### Renaming a Certification
When renaming a certification, you will likely want to rename the associated superblock along with it. Do the following to rename only the certificate:
1. Rename the `curriculum/challenges/_meta/{superBlock}-certificate` folder to the new name.
1. In the `meta.json` file of that folder, rename the values in `name`, `dashedName`, and `challengeOrder` to the new cert name.
1. In `curriculum/challenges/english/12-certificate`, rename the `{superBlock}-certificate` folder, and the YAML file within it, to the new name.
1. In the YAML file, change the `title` to the new name.
1. Rename the file and folder from step 3 for the rest of the curriculum languages.
1. Update `client/src/redux/index.ts` to use the correct `title`.
1. Optionally, update the `certSlug` for the superblock in the same file. **Note** that renaming a `certSlug` will change the URL for certifications and should only be done with careful consideration.
1. Update the `title` in `client/src/resources/cert-and-project-map.ts` to the new value. **Note** that changing the `title` here **will break** the superBlock page for the associated certification. It relies on the superBlock title to match the certification title. You will likely want to rename the superBlock at the same time.
1. If you renamed the `certSlug` in step 7, change it here for the cert and all the nested `projects` values.
1. In `shared/config/certification-settings.js`, update the value of `certTypeTitleMap` to the new name.
1. If you renamed the `certSlug` in step 7, update the key of `certSlugTypeMap` in the same file.
1. Update the certificate name in the `legacyCerts` array of the `client/src/client-only-routes/show-project-links.tsx` if needed.
1. Update the main `README.md` file to the new name.
### Renaming a Superblock
> [!NOTE] When you rename a superBlock, the new folder name is used as the path and should be considered the "correct" name. All other values should be updated to reflect that change.
Also, you will likely want to rename the certificate and the `{superBlock}-projects` block when you rename a superBlock since they all share a name. To rename only a superBlock you need to:
1. Rename the superBlock folder in the `curriculum/challenges/english` directory.
1. Rename the superBlock folder in _all_ other `curriculum/challenges/{language}` directories.
1. For each block within that superBlock, update the `superBlock` value in the `meta.json` file to its dashedName. You don't need to rename any folders here. Do that when renaming a block.
1. Rename the superblock folder in `client/src/pages/learn`.
1. Update the `index.md` file in the above folder, changing the `title` and `superBlock` values to the new name.
1. For each block folder within the above, update the `index.md` to use the correct `superBlock` value.
1. In the `client/src/resources/cert-and-project-map.ts` file, update the path for the cert at the top of the file, and the `title` value for that superBlock. **Note** that changing the `title` here **will break** the ability to view the actual certification for this superBlock. It relies on the superBlock title to match the certification title. You will likely want to rename the certification at the same time.
1. Update the `superBlockCertTypeMap` key in `shared/config/certification-settings.js` to the new superBlock name.
1. Update the path value in `client/src/assets/icons/index.tsx`.
1. For each language in `client/i18n/locales`, update the `intro.json` file to use the new superBlock `dashedName`. In the English file, also update the `title`.
1. Check the `shared/config/i18n/all-langs.js` file to see if the superBlock is enabled in i18n builds. Update all the values where it is used.
1. Update the main `README.md` file to the new name.
### Renaming a Block
When renaming a curriculum block, you need to:
1. Change the name of the block folder in the `curriculum/challenges/english/{superBlock}` directory.
1. Change the name of the same block folder in _all_ of the other language directories to match. These must all be the same as the English structure or the build will error out.
1. Change the name of the block folder in the `_meta` directory.
1. Update the `name` and `dashedName` property for that block's `meta.json` file.
1. Update the block folder in `client/src/pages/learn/{superBlock}`.
1. In the `index.md` file of the above folder, update the `block` value in the frontmatter.
1. In the `client/i18n/locales/{language}/intro.json` files, update the block name to the new name for all the languages. In the English `intro.json` file, update the `title` as well.
1. Update the main `README.md` file to the new name.
### Renaming a Challenge
When renaming a single challenge file, you need to:
1. Change the name of the challenge file in the `curriculum/challenges/english` directory.
1. Change the name of the `title` and `dashedName` within that file.
1. Change the name of the file, and the `dashedName` in those files for _all_ of the other language directories to match.
1. Update the name of the challenge in the relevant `meta.json` file. The challenge names here are not used in the build, but provide a user-friendly way to identify the challenge order.
1. If the challenge is a certificate project, update the YAML file in `curriculum/english/12-certificates/<superBlock>` to the new name.
1. If the challenge is a certificate project, update the `title` and `link` in `client/src/resources/cert-and-project-map.ts`
1. If the challenge is a certificate project, update the main `README.md` file to the new name.
## The `dashedName` Property
The `dashedName` property is used to generate the URL path for the superblock, block, or challenge. These should generally match what the `/utils/slugs.js` helper would output for the file name.
-161
View File
@@ -1,161 +0,0 @@
# Using the Curriculum Helpers
The test runner has access to a few helpers that can assist with testing campers' code.
## CSS Helper
To instantiate the helper within a test block, use this:
```js
const helper = new __helpers.CSSHelp(document);
```
In that example, the `document` variable refers to the document object of the test runner's iframe.
### Methods
There are a few methods available for parsing and testing CSS.
#### `.getStyle()`
The `.getStyle()` method takes a CSS selector and returns a CSS style declaration object.
For example, if the camper has written the following CSS:
```css
body {
background: linear-gradient(45deg, rgb(118, 201, 255), rgb(247, 255, 222));
margin: 0;
padding: 0;
width: 100%;
height: 100vh;
overflow: hidden;
}
```
You would get an object that looks like this:
```js
{
0: "background-image",
1: "background-position-x",
2: "background-position-y",
3: "background-size",
4: "background-repeat-x",
5: "background-repeat-y",
6: "background-attachment",
7: "background-origin",
8: "background-clip",
9: "background-color",
10: "margin-top",
11: "margin-right",
12: "margin-bottom",
13: "margin-left",
14: "padding-top",
15: "padding-right",
16: "padding-bottom",
17: "padding-left",
18: "width",
19: "height",
20: "overflow-x",
21: "overflow-y",
"accentColor": "",
"additiveSymbols": "",
"alignContent": "",
"alignItems": "",
...
}
```
This method allows you to test that specific properties have been set:
```js
assert.strictEqual(helper.getStyle('body')?.width, '100%');
```
The helper attaches a `.getPropVal()` method to the style declaration object that allows you to get the value of a specific property:
```js
assert.strictEqual(helper.getStyle('body').getPropVal('width'), '100%');
```
#### `.getCSSRules()`
The `.getCSSRules()` takes an at-rule type from the union `media | fontface | import | keyframes`, and returns an array of CSS rules matching that at-rule.
For example, if the camper has written the following code:
```css
@media (max-width: 100px) {
body {
background-color: green;
}
}
```
Then the returned value of `helper.getCSSRules('media')` would be this array:
```js
[
{
conditionText: "(max-width: 100px)",
cssRules: [
selectorText: 'body',
style: CSSStyleDeclaration,
styleMap: StylePropertyMap,
cssRules: CSSRuleList,
type: 1,
...
],
cssText: "@media (max-width: 100px) {\n body { background-color: green; }\n}",
...
}
]
```
You can then test that the camper has written the correct media query:
```js
const hasCorrectHeight = helper.getCSSRules('media').some(x => x.style.height === '3px');;
assert.isTrue(hasCorrectHeight);
```
#### `.getRuleListsWithinMedia()`
The `.getRuleListsWithinMedia()` method takes a media text (e.g. `("max-width: 200")`) and returns the CSS rules within that media query.
The return result is the equivalent of that media rule's `cssRules` property from the return value of `.getCSSRules("media")`.
### Less Frequent Methods
These methods are not as commonly used, but are available if needed.
#### `.getStyleDeclarations()`
The `.getStyleDeclarations()` method takes a CSS selector and returns an array of CSS style declaration objects (from the `.getStyle()` method).
#### `.isPropertyUsed()`
The `.isPropertyUsed()` method takes a CSS **property** and checks if it has been set/used anywhere in the camper's CSS.
#### `.getStyleRule()`
The `.getStyleRule()` method takes a CSS selector and returns the CSS Style Declaration, much like `.getStyle()`. However, the declaration returned from this method includes an additional `.isDeclaredAfter()` method which takes a selector and returns whether this rule is declared after the selector passed in.
#### `.getStyleSheet()`
The `.getStyleSheet()` method returns the camper's CSS, parsed into a CSS Style Sheet object.
## Strip Content
There are a few methods on the `__helpers` object to remove content from the camper's code.
These do NOT need to be instantiated they are static methods.
### Removing Comments
Using `__helpers.removeCssComments()`, `__helpers.removeHTMLComments()`, or `__helpers.removeJSComments()` allows you to pass the camper's code (through the `code` variable) to remove comments matching the language's comment syntax.
### Removing Whitespace
Using `__helpers.removeWhitespace()` allows you to pass the camper's code (through the `code` variable) to remove all whitespace.
-979
View File
@@ -1,979 +0,0 @@
# DevOps Handbook
This guide will help you understand our infrastructure stack and how we maintain our platforms. While this guide does not have exhaustive details for all operations, it could be used as a reference for your understanding of the systems.
Let us know if you have feedback or queries and we will be happy to clarify.
## Flight Manual - Code Deployments
This repository is continuously built, tested, and deployed to **separate sets of infrastructure (Servers, Databases, CDNs, etc.)**.
This involves three steps to be followed in sequence:
1. New changes (both fixes and features) are merged into our primary development branch (`main`) via pull requests.
2. These changes are run through a series of automated tests.
3. Once the tests pass we release the changes (or update them if needed) to deployments on our infrastructure.
### Building the codebase - Mapping Git Branches to Deployments
Typically, [`main`](https://github.com/freeCodeCamp/freeCodeCamp/tree/main) (the default development branch) is merged into the [`prod-staging`](https://github.com/freeCodeCamp/freeCodeCamp/tree/prod-staging) branch once a day and is released into an isolated infrastructure.
This is an intermediate release for our developers and volunteer contributors. It is also known as our "staging" or "beta" release.
It is identical to our live production environment at `freeCodeCamp.org`, other than it using a separate set of databases, servers, web-proxies, etc. This isolation lets us test ongoing development and features in a "production" like scenario, without affecting regular users of freeCodeCamp.org's main platforms.
Once the developer team [`@freeCodeCamp/dev-team`](https://github.com/orgs/freeCodeCamp/teams/dev-team/members) is happy with the changes on the staging platform, these changes are moved every few days to the [`prod-current`](https://github.com/freeCodeCamp/freeCodeCamp/tree/prod-current) branch.
This is the final release that moves changes to our production platforms on freeCodeCamp.org.
### Testing changes - Integration and User Acceptance Testing
We employ various levels of integration and acceptance testing to check on the quality of the code. All our tests are done through software like [GitHub Actions CI](https://github.com/freeCodeCamp/freeCodeCamp/actions) and [Azure Pipelines](https://dev.azure.com/freeCodeCamp-org/freeCodeCamp).
We have unit tests for testing our challenge solutions, Server APIs, and Client User interfaces. These help us test the integration between different components.
> [!NOTE] We are also in the process of writing end user tests which will help in replicating real-world scenarios like updating an email or making a call to the API or third-party services.
Together these tests help in preventing issues from repeating themselves and ensure we do not introduce a bug while working on another bug or a feature.
### Deploying Changes - Pushing changes to servers
We have configured continuous delivery software to push changes to our development and production servers.
Once the changes are pushed to the protected release branches, a build pipeline is automatically triggered for the branch. The build pipelines are responsible for building artifacts and keeping them in a cold storage for later use.
The build pipeline goes on to trigger a corresponding release pipeline if it completes a successful run. The release pipelines are responsible for collecting the build artifacts, moving them to the servers, and going live.
The statuses of builds and releases are [available here](#build-test-and-deployment-status).
## Trigger a Build, Test, and Deploy
Currently, only members of the developer team can push to the production branches. The changes to the `production-*` branches can land only via fast-forward merge to the [`upstream`](https://github.com/freeCodeCamp/freeCodeCamp).
> [!NOTE] In the upcoming days, we would improve this flow to be done via pull requests, for better access management and transparency.
### Pushing changes to Staging Applications
1. Configure your remotes correctly.
```sh
git remote -v
```
**Results:**
```
origin git@github.com:raisedadead/freeCodeCamp.git (fetch)
origin git@github.com:raisedadead/freeCodeCamp.git (push)
upstream git@github.com:freeCodeCamp/freeCodeCamp.git (fetch)
upstream git@github.com:freeCodeCamp/freeCodeCamp.git (push)
```
2. Make sure your `main` branch is pristine and in sync with the upstream.
```sh
git checkout main
git fetch --all --prune
git reset --hard upstream/main
```
3. Check that the GitHub CI is passing on the `main` branch for upstream.
The [continuous integration](https://github.com/freeCodeCamp/freeCodeCamp/actions) tests should be green and PASSING for the `main` branch. Click the green check mark next to the commit hash when viewing the `main` branch code.
<details> <summary> Checking status on GitHub Actions (screenshot) </summary>
<br>
![Check build status on GitHub Actions](https://raw.githubusercontent.com/freeCodeCamp/freeCodeCamp/main/docs/images/devops/github-actions.png)
</details>
If this is failing you should stop and investigate the errors.
4. Confirm that you are able to build the repository locally.
```
pnpm run clean-and-develop
```
5. Move changes from `main` to `prod-staging` via a fast-forward merge
```
git checkout prod-staging
git merge main
git push upstream
```
> [!NOTE] You will not be able to force push and if you have re-written the history in any way, these commands will error out.
>
> If they do, you may have done something incorrectly and you should just start over.
The above steps will automatically trigger a run on the build pipeline for the `prod-staging` branch. Once the build is complete, the artifacts are saved as `.zip` files in a cold storage to be retrieved and used later.
The release pipeline is triggered automatically when a fresh artifact is available from the connected build pipeline. For staging platforms, this process does not involve manual approval, and the artifacts are pushed to the Client CDN and API servers.
### Pushing changes to Production Applications
The process is mostly the same as the staging platforms, with a few extra checks in place. This is just to make sure, we do not break anything on freeCodeCamp.org which can see hundreds of users using it at any moment.
| Do NOT execute these commands unless you have verified that everything is working on the staging platform. You should not bypass or skip any testing on staging before proceeding further. |
|:------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| |
1. Make sure your `prod-staging` branch is pristine and in sync with the upstream.
```sh
git checkout prod-staging
git fetch --all --prune
git reset --hard upstream/prod-staging
```
2. Move changes from `prod-staging` to `prod-current` via a fast-forward merge
```
git checkout prod-current
git merge prod-staging
git push upstream
```
> [!NOTE] You will not be able to force push and if you have re-written the history in any way, these commands will error out.
>
> If they do, you may have done something incorrectly and you should just start over.
The above steps will automatically trigger a run on the build pipeline for the `prod-current` branch. Once a build artifact is ready, it will trigger a run on the release pipeline.
**Additional Steps for Staff Action**
Once a release run is triggered, members of the developer staff team will receive an automated manual intervention email. They can either _approve_ or _reject_ the release run.
If the changes are working nicely and have been tested on the staging platform, then it can be approved. The approval must be given within 4 hours of the release being triggered before getting rejected automatically. A staff can re-trigger the release run manually for rejected runs, or wait for the next cycle of release.
For staff use:
| Check your email for a direct link or [go to the release dashboard](https://dev.azure.com/freeCodeCamp-org/freeCodeCamp/_release) after the build run is complete. |
|:------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| |
Once one of the staff members approves a release, the pipeline will push the changes live to freeCodeCamp.org's production CDN and API servers.
## Build, Test and Deployment Status
Here is the current test, build and deployment status of the codebase.
| Branch | Unit Tests | Integration Tests | Builds & Deployments |
|:-------------------------------------------------------------------------------- |:-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |:--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |:--------------------------------------------------------------------------------------------------------------------------------- |
| [`main`](https://github.com/freeCodeCamp/freeCodeCamp/tree/main) | [![Node.js CI](https://github.com/freeCodeCamp/freeCodeCamp/workflows/Node.js%20CI/badge.svg?branch=main)](https://github.com/freeCodeCamp/freeCodeCamp/actions?query=workflow%3A%22Node.js+CI%22) | [![Cypress E2E 测试](https://img.shields.io/endpoint?url=https://dashboard.cypress.io/badge/simple/ke77ns/main&style=flat&logo=cypress)](https://dashboard.cypress.io/projects/ke77ns/analytics/runs-over-time) | - |
| [`prod-staging`](https://github.com/freeCodeCamp/freeCodeCamp/tree/prod-staging) | [![Node.js CI](https://github.com/freeCodeCamp/freeCodeCamp/workflows/Node.js%20CI/badge.svg?branch=prod-staging)](https://github.com/freeCodeCamp/freeCodeCamp/actions?query=workflow%3A%22Node.js+CI%22+branch%3Aprod-staging) | [![Cypress E2E 测试](https://img.shields.io/endpoint?url=https://dashboard.cypress.io/badge/simple/ke77ns/prod-staging&style=flat&logo=cypress)](https://dashboard.cypress.io/projects/ke77ns/analytics/runs-over-time) | [Azure Pipelines](https://dev.azure.com/freeCodeCamp-org/freeCodeCamp/_dashboards/dashboard/d59f36b9-434a-482d-8dbd-d006b71713d4) |
| [`prod-current`](https://github.com/freeCodeCamp/freeCodeCamp/tree/prod-current) | [![Node.js CI](https://github.com/freeCodeCamp/freeCodeCamp/workflows/Node.js%20CI/badge.svg?branch=prod-current)](https://github.com/freeCodeCamp/freeCodeCamp/actions?query=workflow%3A%22Node.js+CI%22+branch%3Aprod-current) | [![Cypress E2E 测试](https://img.shields.io/endpoint?url=https://dashboard.cypress.io/badge/simple/ke77ns/prod-current&style=flat&logo=cypress)](https://dashboard.cypress.io/projects/ke77ns/analytics/runs-over-time) | [Azure Pipelines](https://dev.azure.com/freeCodeCamp-org/freeCodeCamp/_dashboards/dashboard/d59f36b9-434a-482d-8dbd-d006b71713d4) |
| `prod-next` (experimental, upcoming) | - | - | - |
## Early Access and Beta Testing
We welcome you to test these releases in a **"public beta testing"** mode and get early access to upcoming features to the platforms. Sometimes these features/changes are referred to as **next, beta, staging,** etc. interchangeably.
Your contributions via feedback and issue reports will help us in making the production platforms at `freeCodeCamp.org` more **resilient**, **consistent**, and **stable** for everyone.
We thank you for reporting bugs that you encounter and help in making freeCodeCamp.org better. You rock!
### Identifying the Upcoming Version of the Platforms
Currently, a public beta testing version is available at:
| Application | Language | URL |
|:----------- |:-------- |:---------------------------------------- |
| Learn | English | <https://www.freecodecamp.dev> |
| | Espanol | <https://www.freecodecamp.dev/espanol> |
| | Chinese | <https://www.freecodecamp.dev/chinese> |
| News | English | <https://www.freecodecamp.dev/news> |
| Forum | English | <https://forum.freecodecamp.dev> |
| | Chinese | <https://freecodecamp.dev/chinese/forum> |
| API | - | `https://api.freecodecamp.dev` |
> [!NOTE] The domain name is different than **`freeCodeCamp.org`**. This is intentional to prevent search engine indexing and avoid confusion for regular users of the platform.
>
> The above list is not exhaustive of all the applications that we provision. Also, not all language variants are deployed in staging to conserve resources.
### Identifying the Current Version of the Platforms
**The current version of the platform is always available at [`freeCodeCamp.org`](https://www.freecodecamp.org).**
The dev-team merges changes from the `prod-staging` branch to `prod-current` when they release changes. The top commit should be what you see live on the site.
You can identify the exact version deployed by visiting the build and deployment logs available in the status section. Alternatively, you can also ping us in the [contributors chat room](https://discord.gg/PRyKn3Vbay) for a confirmation.
### Known Limitations
There are some known limitations and tradeoffs when using the beta version of the platform.
- **All data / personal progress on these beta platforms will NOT be saved or carried over to production**
**Users on the beta version will have a separate account from the production.** The beta version uses a physically separate database from production. This gives us the ability to prevent any accidental loss of data or modifications. The dev-team may purge the database on this beta version as needed.
- **The beta platforms do not provide any assurances regarding uptime and reliability**
Deployment is expected to be frequent and in rapid iterations, sometimes multiple times a day. As a result, there will be unexpected downtime at times or broken functionality on the beta version.
- **To ensure the effectiveness of the fix, it is advised not to direct regular users to this site for verification purposes.**
The beta site is and always has been to augment local development and testing, nothing else. It's not a promise of what’s coming, but a glimpse of what is being worked upon.
- **Sign in page may look different than production**
We use a test tenant for freeCodeCamp.dev on Auth0, and hence do not have the ability to set a custom domain. This makes it so that all the redirect callbacks and the login page appear at a default domain like: `https://freecodecamp-dev.auth0.com/`. This does not affect the functionality and is as close to production as we can get.
## Reporting issues and leaving feedback
Please open fresh issues for discussions and reporting bugs.
You may send an email to `dev[at]freecodecamp.org` if you have any queries. As always all security vulnerabilities should be reported to `security[at]freecodecamp.org` instead of the public tracker and forum.
## Flight Manual - Server Maintenance
> [!WARNING]
>
> 1. The guide applies to the **freeCodeCamp Staff members only**.
> 2. These instructions should not be considered exhaustive, please use caution.
As a member of the staff, you may have been given access to our cloud service providers like Azure, Digital Ocean, etc.
Here are some handy commands that you can use to work on the Virtual Machines (VM), for instance performing maintenance updates or doing general housekeeping.
## Get a list of the VMs
> [!NOTE] While you may already have SSH access to the VMs, that alone will not let you list VMs unless you have been granted access to the cloud portals as well.
### Azure
Install Azure CLI `az`: https://docs.microsoft.com/en-us/cli/azure/install-azure-cli
> **(One-time) Install on macOS with [`homebrew`](https://brew.sh):**
```
brew install azure-cli
```
> **(One-time) Login:**
```
az login
```
> **Get the list of VM names and IP addresses:**
```
az vm list-ip-addresses --output table
```
### Digital Ocean
Install Digital Ocean CLI `doctl`: https://github.com/digitalocean/doctl#installing-doctl
> **(One-time) Install on macOS with [`homebrew`](https://brew.sh):**
```
brew install doctl
```
> **(One-time) Login:**
Authentication and context switching: https://github.com/digitalocean/doctl#authenticating-with-digitalocean
```
doctl auth init
```
> **Get the list of VM names and IP addresses:**
```
doctl compute droplet list --format "ID,Name,PublicIPv4"
```
## Spin New Resources
We are working on creating our IaC setup, and while that is in works you can use the Azure portal or the Azure CLI to spin new virtual machines and other resources.
> [!TIP] No matter your choice of spinning resources, we have a few [handy cloud-init config files](https://github.com/freeCodeCamp/infra/tree/main/cloud-init) to help you do some of the basic provisioning like installing docker or adding SSH keys, etc.
## Keep VMs Updated
You should keep the VMs up to date by performing updates and upgrades. This will ensure that the virtual machine is patched with the latest security fixes.
> [!WARNING] Before you run these commands:
>
> - Make sure that the VM has been provisioned completely and that there are no post-install steps running.
> - If you are updating packages on a VM that is already serving an application, make sure the app has been stopped / saved. Package updates will cause network bandwidth, memory and/or CPU usage spikes leading to outages on running applications.
Update package information
```bash
sudo apt update
```
Upgrade installed packages
```bash
sudo apt upgrade -y
```
Cleanup unused packages
```bash
sudo apt autoremove -y
```
## Work on Web Servers (Proxy)
We are running load balanced (Azure Load Balancer) instances for our web servers. These servers are running NGINX which reverse proxy all of the traffic to freeCodeCamp.org from various applications running on their own infrastructures.
The NGINX config is available on [this repository](https://github.com/freeCodeCamp/nginx-config).
### First Install
Provisioning VMs with the Code
1. Install NGINX and configure from repository.
```bash
sudo su
cd /var/www/html
git clone https://github.com/freeCodeCamp/error-pages
cd /etc/
rm -rf nginx
git clone https://github.com/freeCodeCamp/nginx-config nginx
cd /etc/nginx
```
2. Install Cloudflare origin certificates and upstream application config.
Get the Cloudflare origin certificates from the secure storage and install at required locations.
**OR**
Move over existing certificates:
```bash
# Local
scp -r username@source-server-public-ip:/etc/nginx/ssl ./
scp -pr ./ssl username@target-server-public-ip:/tmp/
# Remote
rm -rf ./ssl
mv /tmp/ssl ./
```
Update Upstream Configurations:
```bash
vi configs/upstreams.conf
```
Add/update the source/origin application IP addresses.
3. Set up networking and firewalls.
Configure Azure firewalls and `ufw` as needed for ingress origin addresses.
4. Add the VM to the load balancer backend pool.
Configure and add rules to load balancer if needed. You may also need to add the VMs to load balancer backend pool if needed.
### Logging and Monitoring
1. Check status for NGINX service using the below command:
```bash
sudo systemctl status nginx
```
2. Logging and monitoring for the servers are available at:
NGINX Amplify: [https://amplify.nginx.com]('https://amplify.nginx.com'), our current basic monitoring dashboard. We are working on more granular metrics for better observability
### Updating Instances (Maintenance)
Config changes to our NGINX instances are maintained on GitHub, these should be deployed on each instance like so:
1. SSH into the instance and enter sudo
```bash
sudo su
```
2. Get the latest config code.
```bash
cd /etc/nginx
git fetch --all --prune
git reset --hard origin/main
```
3. Test and reload the config [with Signals](https://docs.nginx.com/nginx/admin-guide/basic-functionality/runtime-control/#controlling-nginx).
```bash
nginx -t
nginx -s reload
```
## Work on API Instances
1. Install build tools for node binaries (`node-gyp`) etc.
```bash
sudo apt install build-essential
```
### First Install
Provisioning VMs with the Code
1. Install Node LTS.
2. Install pnpm globally.
```bash
npm install -g pnpm
```
3. Install pm2 globally.
```bash
npm install -g pm2
```
4. Clone freeCodeCamp, set up env, and keys.
```bash
git clone https://github.com/freeCodeCamp/freeCodeCamp.git
cd freeCodeCamp
git checkout prod-current # or any other branch to be deployed
```
5. Create the `.env` from the secure credentials storage.
6. Install dependencies
```bash
pnpm install
```
7. Setup pm2 `logrotate` and startup on boot
```bash
pm2 install pm2-logrotate
pm2 startup
```
8. Build the server
```bash
pnpm prebuild && pnpm build:curriculum && pnpm build:server
```
9. Start Instances
```bash
pnpm start:server
```
### Logging and Monitoring
```bash
pm2 logs
```
```bash
pm2 monit
```
### Updating Instances (Maintenance)
Code changes need to be deployed to the API instances from time to time. It can be a rolling update or a manual update. The latter is essential when changing dependencies or adding environment variables.
> [!ATTENTION] The automated pipelines are not handling dependencies updates at the minute. We need to do a manual update before any deployment pipeline runs.
#### 1. Manual Updates - Used for updating dependencies, env variables.
1. Stop all instances
```bash
pm2 stop all
```
2. Install dependencies
```bash
pnpm install
```
3. Build the server
```bash
pnpm prebuild && pnpm build:curriculum && pnpm build:server
```
4. Start Instances
```bash
pnpm start:server && pm2 logs
```
#### 2. Rolling updates - Used for logical changes to code.
```bash
pnpm reload:server && pm2 logs
```
> [!NOTE] We are handling rolling updates to code and logic via pipelines. You should not need to run these commands. These are here for documentation.
#### 3. Updating Node
1. Install new Node version
2. Update pm2 to use the new version
```bash
pm2 update
```
## Work on Client Instances
1. Install build tools for node binaries (`node-gyp`) etc.
```bash
sudo apt install build-essential
```
### First Install
Provisioning VMs with the Code
1. Install Node LTS.
2. Update `npm` and install PM2 and setup `logrotate` and startup on boot
```bash
npm i -g npm@8
npm i -g pm2@4
npm install -g serve@13
pm2 install pm2-logrotate
pm2 startup
```
3. Clone client config, setup env and keys.
```bash
git clone https://github.com/freeCodeCamp/client-config.git client
cd client
```
Start placeholder instances for the web client, these will be updated with artifacts from the Azure pipeline.
> Todo: This setup needs to move to S3 or Azure Blob storage
>
> ```bash
> echo "serve -c ../serve.json -p 50505 www" > client-start-primary.sh
> chmod +x client-start-primary.sh
> pm2 delete client-primary
> pm2 start ./client-start-primary.sh --name client-primary
> echo "serve -c ../serve.json -p 52525 www" > client-start-secondary.sh
> chmod +x client-start-secondary.sh
> pm2 delete client-secondary
> pm2 start ./client-start-secondary.sh --name client-secondary
> ```
### Logging and Monitoring
```bash
pm2 logs
```
```bash
pm2 monit
```
### Updating Instances (Maintenance)
Code changes need to be deployed to the API instances from time to time. It can be a rolling update or a manual update. The later is essential when changing dependencies or adding environment variables.
> [!ATTENTION] The automated pipelines are not handling dependencies updates at the minute. We need to do a manual update before any deployment pipeline runs.
#### 1. Manual Updates - Used for updating dependencies, env variables.
1. Stop all instances
```bash
pm2 stop all
```
2. Install or update dependencies
3. Start Instances
```bash
pm2 start all --update-env && pm2 logs
```
#### 2. Rolling updates - Used for logical changes to code.
```bash
pm2 reload all --update-env && pm2 logs
```
> [!NOTE] We are handling rolling updates to code, logic, via pipelines. You should not need to run these commands. These are here for documentation.
## Work on Chat Servers
Our chat servers are available with a HA configuration [recommended in Rocket.Chat docs](https://docs.rocket.chat/installation/docker-containers/high-availability-install). The `docker-compose` file for this is [available here](https://github.com/freeCodeCamp/chat-config).
We provision redundant NGINX instances which are themselves load balanced (Azure Load Balancer) in front of the Rocket.Chat cluster. The NGINX configuration file are [available here](https://github.com/freeCodeCamp/chat-nginx-config).
### First Install
Provisioning VMs with the Code
**NGINX Cluster:**
1. Install NGINX and configure from repository.
```bash
sudo su
cd /var/www/html
git clone https://github.com/freeCodeCamp/error-pages
cd /etc/
rm -rf nginx
git clone https://github.com/freeCodeCamp/chat-nginx-config nginx
cd /etc/nginx
```
2. Install Cloudflare origin certificates and upstream application config.
Get the Cloudflare origin certificates from the secure storage and install at required locations.
**OR**
Move over existing certificates:
```bash
# Local
scp -r username@source-server-public-ip:/etc/nginx/ssl ./
scp -pr ./ssl username@target-server-public-ip:/tmp/
# Remote
rm -rf ./ssl
mv /tmp/ssl ./
```
Update Upstream Configurations:
```bash
vi configs/upstreams.conf
```
Add/update the source/origin application IP addresses.
3. Set up networking and firewalls.
Configure Azure firewalls and `ufw` as needed for ingress origin addresses.
4. Add the VM to the load balancer backend pool.
Configure and add rules to load balancer if needed. You may also need to add the VMs to load balancer backend pool if needed.
**Docker Cluster:**
1. Install Docker and configure from the repository
```bash
git clone https://github.com/freeCodeCamp/chat-config.git chat
cd chat
```
2. Configure the required environment variables and instance IP addresses.
3. Run rocket-chat server
```bash
docker-compose config
docker-compose up -d
```
### Logging and Monitoring
1. Check status for NGINX service using the below command:
```bash
sudo systemctl status nginx
```
2. Check status for running docker instances with:
```bash
docker ps
```
### Updating Instances (Maintenance)
**NGINX Cluster:**
Config changes to our NGINX instances are maintained on GitHub, these should be deployed on each instance like so:
1. SSH into the instance and enter sudo
```bash
sudo su
```
2. Get the latest config code.
```bash
cd /etc/nginx
git fetch --all --prune
git reset --hard origin/main
```
3. Test and reload the config [with Signals](https://docs.nginx.com/nginx/admin-guide/basic-functionality/runtime-control/#controlling-nginx).
```bash
nginx -t
nginx -s reload
```
**Docker Cluster:**
1. SSH into the instance and navigate to the chat config path
```bash
cd ~/chat
```
2. Get the latest config code.
```bash
git fetch --all --prune
git reset --hard origin/main
```
3. Pull down the latest docker image for Rocket.Chat
```bash
docker-compose pull
```
4. Update the running instances
```bash
docker-compose up -d
```
5. Validate the instances are up
```bash
docker ps
```
6. Cleanup extraneous resources
```bash
docker system prune --volumes
```
Output:
```bash
WARNING! This will remove:
- all stopped containers
- all networks not used by at least one container
- all volumes not used by at least one container
- all dangling images
- all dangling build cache
Are you sure you want to continue? [y/N] y
```
Select yes (y) to remove everything that is not in use. This will remove all stopped containers, all networks and volumes not used by at least one container, and all dangling images and build caches.
## Work on Contributor Tools
### Deploy Updates
ssh into the VM (hosted on Digital Ocean).
```bash
cd tools
git pull origin master
pnpm install
pnpm run build
pm2 restart contribute-app
```
## Updating Node.js Versions on VMs
List currently installed node & npm versions
```bash
nvm -v
node -v
npm -v
nvm ls
```
Install the latest Node.js LTS, and reinstall any global packages
```bash
nvm install --lts --reinstall-packages-from=default
```
Verify installed packages
```bash
npm ls -g --depth=0
```
Alias the `default` Node.js version to the current LTS (pinned to the latest major version)
```bash
nvm alias default 16
```
(Optional) Uninstall old versions
```bash
nvm uninstall <version>
```
> [!ATTENTION] For client applications, the shell script can't be resurrected between Node.js versions with `pm2 resurrect`. Deploy processes from scratch instead. This should become nicer when we move to a docker-based setup.
>
> If using PM2 for processes you would also need to bring up the applications and save the process list for automatic recovery on restarts.
Get the uninstall instructions/commands with the `unstartup` command and use the output to remove the systemctl services
```bash
pm2 unstartup
```
Get the install instructions/commands with the `startup` command and use the output to add the systemctl services
```bash
pm2 startup
```
Quick commands for PM2 to list, resurrect saved processes, etc.
```bash
pm2 ls
```
```bash
pm2 resurrect
```
```bash
pm2 save
```
```bash
pm2 logs
```
## Installing and Updating Azure Pipeline Agents
See: https://docs.microsoft.com/en-us/azure/devops/pipelines/agents/v2-linux?view=azure-devops and follow the instructions to stop, remove, and reinstall agents. Broadly you can follow the steps listed here.
You would need a PAT, that you can grab from here: https://dev.azure.com/freeCodeCamp-org/_usersSettings/tokens
### Installing Agents on Deployment targets
Navigate to [Azure Devops](https://dev.azure.com/freeCodeCamp-org) and register the agent from scratch in the requisite [deployment groups](https://dev.azure.com/freeCodeCamp-org/freeCodeCamp/_machinegroup).
> [!NOTE] 你应该在主目录运行脚本,并确保没有其他 `azagent` 目录存在。
### Updating Agents
Currently updating agents requires them to be removed and reconfigured. This is required for them to correctly pick up `PATH` values and other system environment variables. 例如,我们需要在部署目标虚拟机上更新 Node.js 时这样做。
1. Navigate and check status of the service
```bash
cd ~/azagent
sudo ./svc.sh status
```
2. Stop the service
```bash
sudo ./svc.sh stop
```
3. Uninstall the service
```bash
sudo ./svc.sh uninstall
```
4. Remove the agent from the pipeline pool
```bash
./config.sh remove
```
5. Remove the config files
```bash
cd ~
rm -rf ~/azagent
```
Once You have completed the steps above, you can repeat the same steps as installing the agent.
## Flight Manual - Email Blast
We use [a CLI tool](https://github.com/freecodecamp/sendgrid-email-blast) to send out the weekly newsletter. To spin this up and begin the process:
1. Sign in to DigitalOcean, and spin up new droplets under the `Sendgrid` project. Use the Ubuntu Sendgrid snapshot with the most recent date. This comes pre-loaded with the CLI tool and the script to fetch emails from the database. With the current volume, three droplets are sufficient to send the emails in a timely manner.
2. Set up the script to fetch the email list.
```bash
cd /home/freecodecamp/scripts/emails
cp sample.env .env
```
You will need to replace the placeholder values in the `.env` file with your credentials.
3. Run the script.
```bash
node get-emails.js emails.csv
```
This will save the email list in an `emails.csv` file.
4. Break the emails down into multiple files, depending on the number of droplets you need. This is easiest to do by using `scp` to pull the email list locally and using your preferred text editor to split them into multiple files. Each file will need the `email,unsubscribeId` header.
5. Switch to the CLI directory with `cd /home/sendgrid-email-blast` and configure the tool [per the documentation](https://github.com/freeCodeCamp/sendgrid-email-blast/blob/main/README.md).
6. Run the tool to send the emails, following the [usage documentation](https://github.com/freeCodeCamp/sendgrid-email-blast/blob/main/docs/cli-steps.md).
7. When the email blast is complete, verify that no emails have failed before destroying the droplets.
## Flight Manual - Adding news instances for new languages
### Theme Changes
We use a custom [theme](https://github.com/freeCodeCamp/news-theme) for our news publication. Adding the following changes to the theme enables the addition of new languages.
1. Include an `else if` statement for the new [ISO language code](https://www.loc.gov/standards/iso639-2/php/code_list.php) in [`setup-locale.js`](https://github.com/freeCodeCamp/news-theme/blob/main/assets/config/setup-locale.js)
2. Create an initial config folder by duplicating the [`assets/config/en`](https://github.com/freeCodeCamp/news-theme/tree/main/assets/config/en) folder and changing its name to the new language code. (`en` —> `es` for Spanish)
3. Inside the new language folder, change the variable names in `main.js` and `footer.js` to the relevant language short code (`enMain` —> `esMain` for Spanish)
4. Duplicate the [`locales/en.json`](https://github.com/freeCodeCamp/news-theme/blob/main/locales/en.json) and rename it to the new language code.
5. In [`partials/i18n.hbs`](https://github.com/freeCodeCamp/news-theme/blob/main/partials/i18n.hbs), add scripts for the newly created config files.
6. Add the related language `day.js` script from [cdnjs](https://cdnjs.com/libraries/dayjs/1.10.4) to the [freeCodeCamp CDN](https://github.com/freeCodeCamp/cdn/tree/main/build/news-assets/dayjs/1.10.4/locale)
### Ghost Dashboard Changes
Update the publication assets by going to the Ghost dashboard > settings > general and uploading the publications's [icon](https://github.com/freeCodeCamp/design-style-guide/blob/master/assets/fcc-puck-500-favicon.png), [logo](https://github.com/freeCodeCamp/design-style-guide/blob/master/downloads/fcc_primary_large.png), and [cover](https://github.com/freeCodeCamp/design-style-guide/blob/master/assets/fcc_ghost_publication_cover.png).
@@ -1,119 +0,0 @@
# How to add Cypress tests
When making changes to JavaScript, CSS, or HTML which could change the functionality or layout of a page, it's important to add corresponding [Cypress](https://docs.cypress.io) integration tests.
To learn how to write Cypress tests, or 'specs', please see Cypress' official [documentation](https://docs.cypress.io/guides/getting-started/writing-your-first-test.html).
## Where to Add a Test
- Cypress tests are in the `./cypress` directory.
- Cypress tests for a curriculum module are in the corresponding curriculum directory, i.e. `cypress/integration/learn/responsive-web-design/basic-css/index.js`.
## How to Run Tests
> [!NOTE] If using Gitpod, please see [Cypress-Gitpod Setup](how-to-add-cypress-tests.md#cypress-gitpod-setup)
### 1. Ensure that MongoDB and Client Applications are Running
- [Start MongoDB and seed the database](how-to-setup-freecodecamp-locally.md#step-3-start-mongodb-and-seed-the-database)
- [Start the freeCodeCamp client application and API server](how-to-setup-freecodecamp-locally.md#step-4-start-the-freecodecamp-client-application-and-api-server)
### 2. Run the Cypress Tests
To run tests against production builds, replace `dev` with `prd` below.
- To run all tests in the `./cypress` directory:
```bash
pnpm run cypress:dev:run
```
- To run a single test:
```bash
pnpm run cypress run --spec=cypress/<path_to_test_file>
```
For example:
```bash
pnpm run cypress run --spec=cypress/e2e/default/landing.ts
```
- To create a development build, start the development server, and run all existing cypress end-to-end tests:
```bash
pnpm run e2e:dev:run
```
## Cypress-Gitpod Setup
### 1. Ensure Development Environment is Running
If starting the Gitpod environment did not automatically develop the environment:
- Follow the [MongoDB installation guide](https://www.mongodb.com/basics/get-started).
- Create a config file.
```bash
pnpm run create:shared
```
- Seed the database
```bash
pnpm run seed
```
- Develop the server and client
```bash
pnpm run develop
```
### 2. Install Cypress Build Tools
```bash
pnpm run cypress:install-build-tools
```
- When prompted in the terminal, select your keyboard layout by language/area
Now, [Cypress can be run](how-to-add-cypress-tests.md#_2-run-the-cypress-tests)
## Troubleshooting
### Unable to Connect to Port 8000
If Cypress fails to run with the following error:
```
CypressError: `cy.visit()` failed trying to load:
http://localhost:3000/signin
We attempted to make an http request to this URL but the request failed without a response.
We received this error at the network level:
> Error: connect ECONNREFUSED 127.0.0.1:8000
Common situations why this would fail:
- you don't have internet access
- you forgot to run / boot your web server
- your web server isn't accessible
- you have weird network configuration settings on your computer
This error occurred while creating the session. Because the session setup failed, we failed the test.
```
You can resolve the issue by:
- Going to the root `package.json` file and adding `--host 0.0.0.0` to the `develop:client` command:
```json
"scripts": {
"develop:client": "cd ./client && pnpm run develop --host 0.0.0.0"
}
```
- Then, re-running `pnpm run develop`
@@ -1,345 +0,0 @@
# How to add Playwright tests
## Installation
To install Playwright run:
```bash
pnpm run playwright:install-build-tools
```
Alternatively you can follow official documentation referenced below:
To install and configure Playwright on your machine check out this [documentation](https://playwright.dev/docs/intro#installing-playwright).
To learn how to write Playwright tests, or 'specs', please see Playwright's official [documentation](https://playwright.dev/docs/writing-tests).
## Where to Add a Test
- Playwright tests are in the `./e2e` directory.
- Playwright test files are always with a `.spec.ts` extension.
## Best Practices for writing E2E tests
This section will explain in detail about best practices for writing and documenting E2E tests based on Playwright documentation and our community code-style.
### - Imports
Always start with necessary imports at the beginning of the file.
For example:
```ts
import { test, expect, type Page } from '@playwright/test';
```
### - Identifying a DOM element
Playwright comes with [multiple built-in locators](https://playwright.dev/docs/locators#quick-guide), but we recommend prioritizing the following locators:
- `getByRole` for querying semantic elements, whose role is important and allows assistive technology to perceive the page correctly.
- `getByText` for querying non-semantic elements such as `div`, `span`, or `p`.
For example:
```ts
await expect(page.getByRole('heading', { name: 'Sign up' })).toBeVisible();
await expect(page.getByText('Hello World')).toBeVisible();
```
In cases where the elements cannot be queried using the above-mentioned locators, you can use the `data-playwright-test-label` attribute as the last resort. This attribute is used to identify elements in the DOM for testing with playwright only. It is not used for styling or any other purpose.
For example:
```html
<div data-playwright-test-label="landing-page-figure">
<img src="..." alt="..." />
</div>
```
In the test file, you can use the `getByTestId` method to identify the element.
For example:
```ts
await expect(page.getByTestId('landing-page-figure')).toBeVisible();
```
### - Constants
Define any constant elements, data sets, or configurations used throughout your tests for easy reference.
For example:
```ts
const landingPageElements = { ... };
const superBlocks = [ ... ];
```
### - Shared Context
If tests depend on a shared context (like a loaded web page), use beforeAll and afterAll hooks to set up and tear down that context.
For example:
```ts
let page: Page;
beforeAll(async ({ browser }) => {
page = await browser.newPage();
});
afterAll(async () => {
await page.close();
});
```
### - Descriptive test names
Each test block should have a clear and concise name describing exactly what it's testing.
For example:
```ts
test('The component landing-top renders correctly', async ({ page }) => {
// ...
});
```
### - Human readable assertions
Each assertion should be as human readable as possible. This makes it easier to understand what the test is doing and what it's expecting.
For example:
```ts
await expect(landingHeading1).toHaveText('Learn to code — for free.');
```
### - Keep it DRY
Make sure that the tests are not repeating the same code over and over again. If you find yourself repeating the same code, consider refactoring it as a loop or a function.
For example:
```ts
for (const logo of await logos.all()) {
await expect(logo).toBeVisible();
}
```
### - Tests for mobile screens
Use the `isMobile` argument to run tests that include logic that varies for mobile screens.
For example:
```ts
test('The campers landing page figure is visible on desktop and hidden on mobile view', async ({
isMobile
}) => {
const landingPageImage = page.getByTestId('landing-page-figure');
if (isMobile) {
await expect(landingPageImage).toBeHidden();
} else {
await expect(landingPageImage).toBeVisible();
}
});
```
### - Group related tests
Group related tests together using describe blocks. This makes it easier to understand what the tests are doing and what they're testing.
For example:
```ts
describe('The campers landing page', () => {
test('The campers landing page figure is visible on desktop and hidden on mobile view', async ({
isMobile
}) => {
// ...
});
test('The campers landing page figure has the correct image', async () => {
// ...
});
});
```
## How to Run Tests
### 1. Ensure that MongoDB and Client Applications are Running
- [Start MongoDB and seed the database](how-to-setup-freecodecamp-locally.md#step-3-start-mongodb-and-seed-the-database). In order for Playwright tests to work, be sure that you use the `pnpm run seed:certified-user` command.
- [Start the freeCodeCamp client application and API server](how-to-setup-freecodecamp-locally.md#step-4-start-the-freecodecamp-client-application-and-api-server)
### 2. Run the Playwright Tests
To run tests with Playwright check the following below
- Make sure you navigate to the e2e repo first
```bash
cd e2e
```
- To run tests in UI helper mode:
```bash
npx playwright test --ui
```
- To run a single test:
```bash
npx playwright test <filename>
```
For example:
```bash
npx playwright test landing-page.spec.ts
```
- Run a set of test files in respective folders:
```bash
npx playwright test <pathToFolder1> <pathToFolder2>
```
For example:
```bash
npx playwright test tests/todo-page/ tests/landing-page/
```
- Run the test with the title:
```bash
npx playwright test -g <title>
```
For example:
```bash
npx playwright test -g "add a todo item"
```
### 3. Debugging Tests
Since Playwright runs in Node.js, you can debug it with your debugger of choice e.g. using console.log or inside your IDE
- Debugging all tests:
```bash
npx playwright test --debug
```
- Debugging one test file:
```bash
npx playwright test example.spec.ts --debug
```
### 4. Generate Test Reports
The HTML Reporter shows you a full report of your tests allowing you to filter the report by browsers, passed tests, failed tests, skipped tests and flaky tests.
```bash
npx playwright show-report
```
### 5. Troubleshooting
Playwright is generally a solid bullet-proof tool. The contributor has already configured the tests to run on all OS machines, including major distributions of Windows, MacOS and Linux.
- (MacOs and Linux) If running Playwright results in an error due to kernel dependencies, run the following command:
```bash
pnpm run playwright:install-build-tools-linux
```
- A common error seen in playwright is as follows:
```bash
Error: page.goto: Could not connect: Connection refused
=========================== logs ===========================
navigating to "https://127.0.0.1:8000/", waiting until "load"
============================================================
```
You can fix the above error with the following steps:
1. **Check the URL:** Ensure that the URL you're trying to navigate to is correct and properly formatted. Make sure there are no typos in the URL.
2. **Server Status:** Check whether the server at the URL is running and accessible. You might encounter this error if the server is not running or is not accessible.
3. **Port Availability:** Verify that the port mentioned in the URL (8000 in this case) is the correct port and is available for use. Make sure no other process is already using that port.
4. **Firewall or Security Software:** Sometimes, firewall or security software can block connections to specific ports. Check your firewall settings to ensure that the port is allowed.
5. **Network Connectivity:** Ensure that your system has a working network connection and can access external resources.
- Another common error seen in playwright is as follows:
```bash
Protocol error (Network.getResponseBody): Request content was evicted from inspector cache
```
1. The network request was made using a method that does not include a response body, such as HEAD or CONNECT.
2. The network request was made over a secure (HTTPS) connection, and the response body is not available for security reasons.
3. The network request was made by a third-party resource (such as an advertisement or a tracking pixel) that is not controlled by the script.
4. The network request was made by a script that has been paused or stopped before the response was received.
**For more insights on issues visit the official documentation.**
## Playwright-Gitpod Setup
### 1. Ensure Development Environment is Running
If starting the Gitpod environment did not automatically develop the environment:
- Follow the [MongoDB installation guide](https://www.mongodb.com/basics/get-started).
- Create the .env
```bash
cp sample.env .env
```
- Create a config file.
```bash
pnpm run create:shared
```
- Seed the database
```bash
pnpm run seed:certified-user
```
- Develop the server and client
```bash
pnpm run develop
```
### 2. Install Playwright Build Tools
To install necessary dependencies for running Playwright run the following command:
```bash
pnpm run playwright:install-build-tools
```
### 3. Run the Playwright Tests on Gitpod
To run all Playwright tests, run the following command:
```bash
cd e2e
npx playwright test
```
@@ -1,111 +0,0 @@
> **注意:** 这是一个 **可选的** 步骤,并且仅在处理电子邮件工作流时需要
- [Introduction](#introduction)
- [Installing MailHog](#installing-mailhog)
- [Using MailHog](#using-mailhog)
- [Useful Links](#useful-links)
## Introduction
Some email workflows, like updating a user's email, require the back-end API server to send outgoing emails. MailHog is an alternative to using an email service provider to send actual email messages. It is a developer tool for email testing that will catch the email messages sent by your freeCodeCamp instance.
## Installing MailHog
MailHog can be installed on macOS, Windows, and Linux or used via Docker.
<details><summary>Installing MailHog with Docker</summary>
If you have Docker installed then you can use
```bash
docker run -d --name mailhog --network host --rm mailhog/mailhog
```
to start MailHog in the background and
```bash
docker stop mailhog
```
to stop it.
When the installation completes, you can start [using MailHog](#using-mailhog).
</details>
<details><summary>Installing MailHog on macOS</summary>
使用 [Homebrew](https://brew.sh/) 在 macOS 上安装 MailHog:
```bash
brew install mailhog
brew services start mailhog
```
The above commands will start a MailHog service in the background.
安装完成后,你可以开始[使用 MailHog](#using-mailhog)。
</details>
<details><summary>Installing MailHog on Windows</summary>
Download the latest version of MailHog from [MailHog's official repository](https://github.com/mailhog/MailHog/releases). Locate and click on the link for your Windows version (32 or 64 bit) and a `.exe` file will be downloaded to your computer.
下载完成后,单击以打开文件。 可能会出现 Windows 防火墙通知,为 MailHog 请求访问权限。 一旦授予防火墙访问权限,将打开一个标准的 Windows 命令行提示符,MailHog 将在其中运行。
通过关闭命令提示符窗口来关闭 MailHog。 To start MailHog again, click on the MailHog executable (`.exe`) file that was downloaded initially - it is not necessary to download a new MailHog installation file.
开始[使用 MailHog](#using-mailhog)。
</details>
<details><summary>Installing MailHog on Linux</summary>
首先,安装 [Go](https://golang.org)。
在基于 Debian 的系统(如 Ubuntu 和 Linux Mint)上,运行以下命令安装 GO。
```bash
sudo apt-get install golang
```
在基于 RPM 的系统(如 CentOS、Fedora、Red Hat Linux 等)上,运行以下命令安装 GO。
```bash
sudo dnf install golang
```
或者,运行以下命令来安装 GO。
```bash
sudo yum install golang
```
现在使用以下命令设置 Go 的路径。
```bash
echo "export GOPATH=$HOME/go" >> ~/.profile
echo 'export PATH=$PATH:/usr/local/go/bin:$GOPATH/bin' >> ~/.profile
source ~/.profile
```
最后,输入以下命令来安装和运行 MailHog。
```bash
go get github.com/mailhog/MailHog
sudo cp /home/$(whoami)/go/bin/MailHog /usr/local/bin/mailhog
mailhog
```
开始[使用 MailHog](#using-mailhog)。
</details>
## Using MailHog
Open a new browser tab or window and navigate to [http://localhost:8025](http://localhost:8025) to open your MailHog inbox when the MailHog installation has been completed and MailHog is running.
## Useful Links
- Check out the [MailHog](https://github.com/mailhog/MailHog) repository for further information related to MailHog. Additional information is also available regarding custom MailHog configurations.
@@ -1,216 +0,0 @@
Follow these guidelines to contribute to the codebase. This is highly recommended if you want to contribute regularly.
Ignoring these steps may soil your copy which makes the contributing, maintaining, and reviewing processes difficult.
## Contributing to the Codebase
You can now make changes to files and commit your changes to your fork, which you can prepare by reading [how to set up freeCodeCamp locally](how-to-setup-freecodecamp-locally.md).
Follow these steps:
1. Validate that you are on the `main` branch:
```bash
git status
```
You should get an output like this:
```bash
On branch main
Your branch is up-to-date with 'origin/main'.
nothing to commit, working directory clean
```
If you got a different message, then you aren't on main or your working directory isn't clean, resolve any outstanding files/commits and checkout `main`:
```bash
git checkout main
```
2. Sync the latest changes from the freeCodeCamp upstream `main` branch to your `main` fork branch:
> [!WARNING] If you have any outstanding pull requests that you made from the `main` branch of your fork, you will lose them at the end of this step.
>
> You should ensure your pull request is merged by a moderator before performing this step. To avoid this scenario, you should **always** work on a branch other than the `main`.
This step **will sync the latest changes** from the main repository of freeCodeCamp.
Update your copy of the freeCodeCamp upstream repository:
```bash
git fetch upstream
```
Hard reset your main branch with the freeCodeCamp main:
```bash
git reset --hard upstream/main
```
Push your main branch to your origin to have a clean history on your fork on GitHub:
```bash
git push origin main --force
```
You can validate that your current main matches the upstream/main by performing a diff:
```bash
git diff upstream/main
```
The resulting output should be empty. This process is important, because you will be rebasing your branch on top of the latest `upstream/main` as often as possible to avoid conflicts later.
3. Create a fresh new branch:
Working on a separate branch for each issue helps you keep your work copy clean. You should never work on the `main`. This will soil your copy of freeCodeCamp and you may have to start over with a fresh clone or fork.
Check that you are on `main` as explained previously, and branch off from there:
```bash
git checkout -b fix/update-guide-for-xyz
```
Your branch name should start with a `fix/`, `feat/`, `docs/`, etc. Avoid using issue numbers in branches. Keep them short, meaningful and unique.
Some examples of good branch names are:
```md
fix/update-challenges-for-react
fix/update-guide-for-html-css
fix/platform-bug-sign-in-issues
feat/add-guide-article-for-javascript
translate/add-spanish-basic-html
```
4. Edit pages and work on code in your favorite text editor.
5. Once you are happy with the changes you should optionally run freeCodeCamp to preview the changes.
6. Make sure you fix any errors and check the formatting of your changes.
7. Check and confirm the files you are updating:
```bash
git status
```
This should show a list of `unstaged` files that you have edited.
```bash
On branch feat/documentation
Your branch is up to date with 'upstream/feat/documentation'.
Changes were not staged for commit:
(use "git add/rm <file>..." to update what will be committed)
(use "git checkout -- <file>..." to discard changes in the working directory)
modified: CONTRIBUTING.md
modified: docs/README.md
modified: docs/how-to-setup-freecodecamp-locally.md
modified: docs/how-to-work-on-guide-articles.md
...
```
8. Stage the changes and make a commit:
In this step, you should only mark files that you have edited or added yourself. You can perform a reset and resolve files that you did not intend to change if needed.
```bash
git add path/to/my/changed/file.ext
```
Or you can add all the `unstaged` files to the staging area:
```bash
git add .
```
Only the files that were moved to the staging area will be added when you make a commit.
```bash
git status
```
Output:
```bash
On branch feat/documentation
Your branch is up to date with 'upstream/feat/documentation'.
Changes to be committed:
(use "git reset HEAD <file>..." to unstage)
modified: CONTRIBUTING.md
modified: docs/README.md
modified: docs/how-to-setup-freecodecamp-locally.md
modified: docs/how-to-work-on-guide-articles.md
```
Now, you can commit your changes with a short message like so:
```bash
git commit -m "fix: my short commit message"
```
Some examples:
```md
fix: add test for JavaScript - for loop step
feat: add link for article for alexa skills
```
Make a conventional commit message. This is a good practice as a developer, and you will be following standard practices.
Some examples of conventional commit messages are:
```md
fix: improve HTML step
fix: fix build scripts for Travis-CI
feat: add link to JavaScript hoisting article
docs: update contributing guidelines
```
Keep these short, not more than 50 characters. You can always add additional information in the description of the commit message.
This does not take any more time than an unconventional message like 'update file' or 'add index.md'
You can learn more about why you should use conventional commits [here](https://www.conventionalcommits.org/en/v1.0.0-beta.2/#why-use-conventional-commits).
9. If you realize that you need to edit a file or update the commit message after making a commit you can do so after editing the files with:
```bash
git commit --amend
```
This will open up a default text editor like `nano` or `vi` where you can edit the commit message title and add/edit the description.
10. Next, you can push your changes to your fork:
```bash
git push origin branch/name-here
```
## Proposing a Pull Request (PR)
After you've committed your changes, check here for [how to open a Pull Request](how-to-open-a-pull-request.md).
## Quick commands reference
A quick reference to the commands that you will need when working.
| command | description |
| ----------------------------------------------------------------- | ----------------------------------------------------------------------------------- |
| `pnpm test` | Run all JS tests in the system, including client, server, lint and challenge tests. |
| `pnpm run test-client` | Run the client test suite. |
| `pnpm run test-client -u` | Run the client test suite, updating the Jest snapshots that are out of sync. |
| `pnpm run test:curriculum` | Run the curriculum test suite. |
| `FCC_BLOCK='Basic HTML and HTML5' pnpm run test:curriculum` | Test a specific Block. |
| `FCC_SUPERBLOCK='responsive-web-design' pnpm run test:curriculum` | Test a specific SuperBlock. |
| `pnpm run test-curriculum-full-output` | Run the curriculum test suite, without bailing after the first error |
| `pnpm run test-server` | Run the server test suite. |
| `pnpm run e2e` | Run the Cypress end to end tests. |
| `pnpm run clean` | Uninstalls all dependencies and cleans up caches. |
| `pnpm run storybook` | Starts Storybook for component library development. |
@@ -1,458 +0,0 @@
# Deploying New Languages on `/learn`
To enable a new language on `/learn` (curriculum), you need to complete the following steps:
- Complete translating and approving the first 3 certifications on Crowdin. (New Responsive Web Design, JavaScript Algorithms and Data Structures, and Front End Development Libraries)
- Complete translating and approving all strings in Learn UI project on Crowdin.
- Update Crowdin settings to add a custom language code for the new language.
- Open the 1st PR to configure GitHub Actions. You need to update 2 files:
- `crowdin-download.client-ui.yml`
- `crowdin-download.curriculum.yml`
- Open the 2nd PR to add other configurations. You need to update/add the following files:
- Update `i18n.ts`
- Update `superblocks.ts`
- Update `algolia-locale-setup.ts`
- Add `links.json`
- Add `meta-tags.json`
- Add `motivation.json`
- Ask infrastructure team to spin up the VM for the new language.
- Once the VM is ready, open the 3rd PR to show the new language in the navigation menu.
We will explain each step in the following sections.
## Updating Crowdin Settings
Before you can release a new language, you will need to allow the languages to download from Crowdin. To configure that, you need to add a custom language code for your language.
In the `Curriculum` and `Learn UI` projects on Crowdin, you will need to select `Settings` > `Languages` from the sidebar. Then scroll down to `Language Mapping`, where you will see an option to add custom language codes. Add a new entry for the language you are releasing, selecting `language` as the `Placeholder` value, and entering a URL-friendly lower-case spelling of your language's name for the `Custom code`. If you aren't sure what to use, or you don't have an admin role and can't see the settings, reach out in our contributor chat and we will assist you.
## Updating Workflows for GitHub Actions
Then you need to configure the syncing between Crowdin and GitHub.
You will need to add a step to the [`crowdin-download.client-ui.yml`](https://github.com/freeCodeCamp/freeCodeCamp/blob/main/.github/workflows/crowdin-download.client-ui.yml) and [`crowdin-download.curriculum.yml`](https://github.com/freeCodeCamp/freeCodeCamp/blob/main/.github/workflows/crowdin-download.curriculum.yml). The step for these will be the same. For example, if you want to enable Dothraki downloads:
```yml
##### Download Dothraki #####
- name: Crowdin Download Dothraki Translations
uses: crowdin/github-action@master
# options: https://github.com/crowdin/github-action/blob/master/action.yml
with:
# uploads
upload_sources: false
upload_translations: false
auto_approve_imported: false
import_eq_suggestions: false
# downloads
download_translations: true
download_language: mis
skip_untranslated_files: false
export_only_approved: true
push_translations: false
# pull-request
create_pull_request: false
# global options
config: './crowdin-config.yml'
base_url: ${{ secrets.CROWDIN_BASE_URL_FCC }}
# Uncomment below to debug
# dryrun_action: true
```
Note that the `download_language` key needs to be set to the language code displayed on Crowdin.
## Enabling a Language
> [!NOTE] The above section with updating the workflows should be completed before proceeding - these need to be done in separate steps or the builds will fail.
There are a few steps to take in order to allow the codebase to build in your desired language.
First, visit the [`shared/config/i18n.ts`](https://github.com/freeCodeCamp/freeCodeCamp/blob/main/shared/config/i18n.ts) file to add the language to the list of available languages and configure the values. There are several objects here.
- `Languages`: Add the new language to `Languages` enum, similar to the others. The string value here will be used in the `.env` file to set a build language later.
- `availableLangs`: Add the new property from the `Languages` enum to both the `client` and `curriculum` arrays.
- `i18nextCodes`:这些是每种语言的 ISO 语言代码。 You will need to add the appropriate ISO code for the language you are enabling. These do need to be unique for each language.
- `LangNames`: These are the display names for the language selector in the navigation menu.
- `LangCodes`: These are the language codes used for formatting dates and numbers. These should be Unicode CLDR codes instead of ISO codes.
- `hiddenLangs`: These languages will not be displayed in the navigation menu. This is used for languages that are not yet ready for release. Include your language in this array in the first PR and ask staff team to prepare the VM instance for your language. When the VM is ready, make another PR to remove it from the array.
- `rtlLangs`: These are languages that read from right to left.
As an example, if you wanted to enable Dothraki as a language, your `i18n.ts` objects should look like this:
```js
export enum Languages {
English = 'english',
Espanol = 'espanol',
Chinese = 'chinese',
ChineseTraditional = 'chinese-traditional',
Dothraki = 'dothraki'
}
export const availableLangs = {
client: [
Languages.English,
Languages.Espanol,
Languages.Chinese,
Languages.ChineseTraditional,
Languages.Dothraki
],
curriculum: [
Languages.English,
Languages.Espanol,
Languages.Chinese,
Languages.ChineseTraditional,
Languages.Dothraki
]
};
export const i18nextCodes = {
[Languages.English]: 'en',
[Languages.Espanol]: 'es',
[Languages.Chinese]: 'zh',
[Languages.ChineseTraditional]: 'zh-Hant',
[Languages.Dothraki]: 'mis'
};
export enum LangNames = {
[Languages.English]: 'English',
[Languages.Espanol]: 'Español',
[Languages.Chinese]: '中文(简体字)',
[Languages.ChineseTraditional]: '中文(繁體字)',
[Languages.Dothraki]: 'Dothraki'
};
export enum LangCodes = {
[Languages.English]: 'en-US',
[Languages.Espanol]: 'es-419',
[Languages.Chinese]: 'zh',
[Languages.ChineseTraditional]: 'zh-Hant',
[Languages.Dothraki]: 'mis'
};
export const hiddenLangs = ['dothraki'];
export const rtlLangs = [''];
```
> [!NOTE] When a language has been set up in the deployment pipeline AND has a public `/learn` instance live, it can be removed from the `hiddenLangs` array and be made available to the public.
### Set Translated SuperBlocks
In the [shared/config/superblocks.ts](https://github.com/freeCodeCamp/freeCodeCamp/blob/main/shared/config/superblocks.ts) file, add the new language to the `notAuditedSuperBlocks` object. This lists all the superblocks which are not fully translated. Add an array of superblocks that have not been fully translated to it. For example:
```js
export const notAuditedSuperBlocks: NotAuditedSuperBlocks = {
...
[Languages.Dothraki]: [
SuperBlocks.DataVis,
SuperBlocks.RelationalDb,
SuperBlocks.BackEndDevApis,
SuperBlocks.QualityAssurance,
SuperBlocks.SciCompPy,
SuperBlocks.DataAnalysisPy,
SuperBlocks.InfoSec,
SuperBlocks.MachineLearningPy,
SuperBlocks.CollegeAlgebraPy,
SuperBlocks.FoundationalCSharp,
SuperBlocks.CodingInterviewPrep,
SuperBlocks.ProjectEuler,
SuperBlocks.JsAlgoDataStructNew,
SuperBlocks.TheOdinProject
]
}
```
Be sure to only add the superblocks that are **not** fully translated and approved. The translated superblocks will be calculated from this object. When a new superblock is finished being fully translated, remove it from the array for that language.
See the `SuperBlocks` enum at the beginning of the same file for the full list of superblocks.
### Configure Search
Next, open the [`client/src/utils/algolia-locale-setup.ts`](https://github.com/freeCodeCamp/freeCodeCamp/blob/main/client/src/utils/algolia-locale-setup.ts) file. This data is used for the search bar that loads `/news` articles. While it is unlikely that you are going to test this functionality, missing the data for your language can lead to errors when attempting to build the codebase locally.
Add an object for your language to the `algoliaIndices` object. You should use the same values as the `english` object for local testing, replacing the `english` key with your language's `availableLangs` value.
> [!NOTE] If we have already deployed an instance of news in your target language, you can update the values to reflect the live instance. Otherwise, use the English values.
If you were to add Dothraki:
```js
const algoliaIndices = {
english: {
name: 'news',
searchPage: 'https://www.freecodecamp.org/news/search/'
},
espanol: {
name: 'news-es',
searchPage: 'https://www.freecodecamp.org/espanol/news/search/'
},
chinese: {
name: 'news-zh',
searchPage: 'https://chinese.freecodecamp.org/news/search/'
},
'chinese-traditional': {
name: 'news-zh',
searchPage: 'https://chinese.freecodecamp.org/news/search'
},
dothraki: {
name: 'news',
searchPage: 'https://www.freecodecamp.org/news/search/'
}
// If we already have /news in the target language up and running, you can update the values like this:
// dothraki: {
// name: 'news-mis',
// searchPage: 'https://www.freecodecamp.org/dothraki/news/search/'
// }
};
```
### Client UI
You will need to take an additional step to handle the client UI translations.
The Crowdin workflows will automatically pull down _some_ of the UI translations, but there are a couple of files that need to be moved manually.
You will want to copy the following files from [`/client/i18n/locales/english`](https://github.com/freeCodeCamp/freeCodeCamp/tree/main/client/i18n/locales/english) to `/client/i18n/locales/<your-language>`, and apply translations as needed:
- `links.json`
- `meta-tags.json`
- `motivation.json`
You don't have to have everything in these 3 files translated at first. It's possible to translate only the relevant parts and make adjustments later.
#### `links.json`
You can replace any URLs that you have corresponding pages ready in your language.
For example, if you have a publication in your language, you can replace the URL for `"news"`. If you want to translate articles listed in the footer links, see [How to Translate Articles in the Footer Links](language-lead-handbook.md#how-to-translate-articles-in-the-footer-links).
#### `meta-tags.json`
This file contains metadata for the web page of `/learn` in your language. You can translate the values for `"title"`, `"description"`, and `"social-description"`. The value for `"youre-unsubscribed"` is used when someone unsubscribes from Quincy's weekly email.
Also, you can translate or add relevant keywords in your language to the `"keywords"` array.
#### `motivation.json`
This file contains the compliments that will be displayed to campers when they complete a challenge, and motivational quotes that are displayed on the top page of `/learn`.
You can translate them, or even replace them with relevant compliments/quotes of your choice in your language.
### Enabling Localized Videos
This section is applicable only if you have localized videos in the challenges. Otherwise, you can skip this section.
For the video challenges, you need to change a few things. First, add the new locale to the GraphQL query in the [`client/src/templates/Challenges/video/Show.tsx`](https://github.com/freeCodeCamp/freeCodeCamp/blob/main/client/src/templates/Challenges/video/show.tsx) file. For example, adding Dothraki to the query:
```tsx
query VideoChallenge($slug: String!) {
challengeNode(fields: { slug: { eq: $slug } }) {
videoId
videoLocaleIds {
espanol
italian
portuguese
dothraki
}
...
```
Then add an id for the new language to any video challenge in an audited block. For example, if `auditedCerts` in `i18n.ts` includes `scientific-computing-with-python` for `dothraki`, then you must add a `dothraki` entry in `videoLocaleIds`. The frontmatter should then look like this:
```yml
videoLocaleIds:
espanol: 3muQV-Im3Z0
italian: hiRTRAqNlpE
portuguese: AelGAcoMXbI
dothraki: new-id-here
dashedName: introduction-why-program
---
```
Update the `VideoLocaleIds` interface in `client/src/redux/prop-types` to include the new language.
```ts
export interface VideoLocaleIds {
espanol?: string;
italian?: string;
portuguese?: string;
dothraki?: string;
}
```
And finally, update the challenge schema in `curriculum/schema/challengeSchema.js`.
```js
videoLocaleIds: Joi.when('challengeType', {
is: challengeTypes.video,
then: Joi.object().keys({
espanol: Joi.string(),
italian: Joi.string(),
portuguese: Joi.string(),
dothraki: Joi.string()
})
}),
```
## Testing Translations Locally
If you would like to test translations locally, before adding them to our main repository - skip the Crowdin workflow changes. Follow the steps for enabling a language, then download the translations from Crowdin and load them into your local code.
Because the language has not been approved for production, our scripts are not automatically downloading the translations yet. Only staff have access to directly download the translations - you are welcome to reach out to us in our [contributors chat room](https://discord.gg/PRyKn3Vbay), or you can translate the English markdown files locally for testing purposes.
Once you have the files, you will need to place them in the correct directory. For the curriculum challenges, you should place the certification folders (i.e. `01-responsive-web-design`) within the `curriculum/challenges/{lang}` directory. For our Dothraki translations, this would be `curriculum/challenges/dothraki`. The client translation `.json` files will go in the `client/i18n/locales/{lang}` directory.
Update your `.env` file to use your new language for `CLIENT_LOCALE` and `CURRICULUM_LOCALE`.
Once these are in place, you should be able to run `pnpm run develop` to view your translated version of freeCodeCamp.
> [!TIP] If you build the client in one language and then want to build it in a different language, you will need to use the command `pnpm run clean-and-develop` after changing the `.env` file, as Gatsby will cache the first language.
> [!ATTENTION] While you may perform translations locally for the purpose of testing, we remind everyone that translations should _not_ be submitted through GitHub and should only be done through Crowdin. Be sure to reset your local codebase after you are done testing.
## Show the language in the navigation menu
When your prior PR is merged and the VM for your language is ready, make another PR to show your language in the navigation menu.
In [`shared/config/i18n.ts`](https://github.com/freeCodeCamp/freeCodeCamp/blob/main/shared/config/i18n.ts) file, you have included your language in `hiddenLangs` array in the prior PR. Remove it from the array now.
```js
export const hiddenLangs = []; // Remove your language from the array
```
When this PR is merged and deployed, the curriculum in your language will be live.
# Deploying New Languages on `/news`
To deploy News for a new language, you'll need to create two PRs. One PR will be to the [CDN repo](https://github.com/freeCodeCamp/cdn), and the other will be to the [News repo](https://github.com/freeCodeCamp/news).
## Prep the CDN Repo for the New Language
News sources trending links and article titles from our CDN during the build and adds them to the footer. News also fetches Day.js files from the CDN during the build to localize dates and times for each language.
### Add a YAML File for Trending Articles
Clone the [CDN repo](https://github.com/freeCodeCamp/cdn) and create a new branch.
In the [`build/universal/trending`](https://github.com/freeCodeCamp/cdn/tree/main/build/universal/trending) directory, create a new file and name it `language.yaml`. For example, if you are launching Dothraki News, name the file `dothraki.yaml`.
Then copy the contents of the [`english.yaml`](https://github.com/freeCodeCamp/cdn/blob/main/build/universal/trending/english.yaml) trending file and paste it into the new YAML file you just created.
The contents will look something like this:
```yaml
article0title: 'Learn JavaScript'
article0link: 'https://www.freecodecamp.org/news/learn-javascript-free-js-courses-for-beginners/'
article1title: 'Linux ln Example'
article1link: 'https://www.freecodecamp.org/news/linux-ln-how-to-create-a-symbolic-link-in-linux-example-bash-command'
article2title: 'JS document.ready()'
article2link: 'https://www.freecodecamp.org/news/javascript-document-ready-jquery-example/'
article3title: ...
article3link: ...
...
```
### Add a Day.js Locale File for the New Language
By default, Day.js only includes English as a locale. To enable it to work with other languages, you need to add a new Day.js locale file to the CDN.
In the [`build/news-assets/dayjs/<version>/locale`](https://github.com/freeCodeCamp/cdn/tree/main/build/news-assets/dayjs/1.10.4/locale) directory, create a new file and name it `isocode.min.js`. For example, if you are launching Dothraki News, name the file `mis.min.js`.
> [!NOTE] The version number will change as the dependencies are updated.
Then, visit [this page on cdnjs](https://cdnjs.com/libraries/dayjs/1.10.4) with all available Day.js files for the version we're using, find the `https://cdnjs.cloudflare.com/ajax/libs/dayjs/<version>/locale/isocode.min.js` link for the new language, and open it in a new tab.
> [!NOTE] You only need to add the .../dayjs/\<version\>/_locale_/isocode.min.js locale file. You do not need to add any other Day.js files.
Copy the Day.js locale code from the new tab into the new file you created. For example, here is an un-minified version of the English locale code for Day.js:
```js
!(function (e, n) {
'object' == typeof exports && 'undefined' != typeof module
? (module.exports = n())
: 'function' == typeof define && define.amd
? define(n)
: (e.dayjs_locale_en = n());
})(this, function () {
'use strict';
return {
name: 'en',
weekdays: 'Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday'.split(
'_'
),
months:
'January_February_March_April_May_June_July_August_September_October_November_December'.split(
'_'
)
};
});
```
Then open a PR to the CDN repo to add both the YAML and Day.js files for review.
## Prep the News Repo for the New Language
The [News repo](https://github.com/freeCodeCamp/news) pulls data from a Ghost instance, the files you added to the CDN, builds News, and deploys it.
> [!WARN] Pull requests to the News repo _must_ come from the same repo. You should not work off of a fork for this step.
### Modify the Main Config File
Clone the News repo and create a new branch.
Open the `config/index.js` file to add the new language and configure the necessary values. There are a few objects and arrays to modify:
- `locales`: This array contains the active and upcoming News languages. These are the values that are used in the `.env` file to choose the Ghost instance and UI to use for each build. Add the text name of the new language in lowercase to this array.
- `localeCodes`: This object is a map of ISO codes for each language, and is used to configure i18next before building the UI. To add a new language, use the lowercase language name as the _key_ and the ISO 639-1 language code as the _value_.
- `algoliaIndices`: This object is a map of Algolia indices for each language. To add a new language, use the lowercase language name as the _key_, and `news-` followed by the lowercase ISO 639-1 language code as the _value_.
> [!NOTE] If you are unsure about the string to use while setting `algoliaIndices`, send a message to Kris (@scissorsneedfoodtoo), or someone else with access to Algolia, and ask them to check.
For example, if you are launching Dothraki News, here are what the objects / arrays above should look like:
```js
const locales = ['arabic', 'bengali', 'chinese', 'english', 'dothraki'];
const localeCodes = {
arabic: 'ar',
bengali: 'bn',
chinese: 'zh',
english: 'en',
dothraki: 'mis'
};
const algoliaIndices = {
arabic: 'news-ar',
bengali: 'news-bn',
chinese: 'news-zh',
english: 'news',
dothraki: 'news-mis'
};
```
### Add the i18next JSON Files for the New Language
Next, go to the `shared/config/i18n/locales` directory, create a new folder, and give it the name of the new language you're adding. For example, if you're launching Dothraki News, create a new folder named `dothraki`.
Then copy the JSON files from the `english` directory to your new folder.
In your new folder, open the `redirects.json` file and replace its contents with an empty array:
```json
[]
```
Then commit and push your branch directly to the News repo.
> [!NOTE] You need to be on one of the teams with access to the News repo to push branches directly to News. Currently, only the dev, i18n, and staff teams are allowed to do this.
Finally, open a PR for review.
Once both your PRs to the CDN and News repo have been approved, they can be merged.
> [!NOTE] Deployment will be handled subsequently by the staff. Here is a sample PR: [freeCodeCamp/news#485](https://github.com/freeCodeCamp/news/pull/485) of how they do it and more details are available in the [staff-wiki](https://staff-wiki.freecodecamp.org/docs/flight-manuals/news-instances#jamstack---news--assets).
@@ -1,203 +0,0 @@
# How to Help with Video Challenges
Video challenges are a new type of challenge in the freeCodeCamp curriculum.
A video challenge is a small section of a full-length video course on a particular topic. A video challenge page embeds a YouTube video. Each challenge page has a single multiple-choice question related to the video. A user must answer the question correctly before moving on to the next video challenge in the course.
The video challenge pages are created by members of the freeCodeCamp team. YouTube videos are also uploaded by members of the freeCodeCamp team. Many of the video challenges do not yet have questions associated with them.
You can help by creating multiple-choice questions related to video sections and adding the questions to the markdown files for the video challenges.
## Challenge Template
Below is a template of what the challenge markdown files look like.
````md
---
id: Unique identifier (alphanumerical, MongoDB_id)
title: Challenge Title
challengeType: 11
videoId: 'YouTube videoId for video challenge'
forumTopicId: 12345
---
# --description--
Challenge description text, in markdown
```html
<div>example code</div>
````
# --question--
These fields are currently used for the multiple-choice Python challenges.
## --text--
The question text goes here.
## --answers--
Answer 1
---
Answer 2
---
More answers
## --video-solution--
The number for the correct answer goes here.
````
## Creating Questions for Video Challenges
### Access the Video Challenge Markdown Files
You can find the markdown files for video challenges at the following locations in the curriculum:
- [Data Analysis with Python Course](https://github.com/freeCodeCamp/freeCodeCamp/tree/main/curriculum/challenges/english/08-data-analysis-with-python/data-analysis-with-python-course)
- [TensorFlow 2.0 Course](https://github.com/freeCodeCamp/freeCodeCamp/tree/main/curriculum/challenges/english/11-machine-learning-with-python/tensorflow)
- [Numpy Course](https://github.com/freeCodeCamp/freeCodeCamp/tree/main/curriculum/challenges/english/08-data-analysis-with-python/numpy)
- [How Neural Networks Work Course](https://github.com/freeCodeCamp/freeCodeCamp/tree/main/curriculum/challenges/english/11-machine-learning-with-python/how-neural-networks-work)
Pick a challenge markdown file from the options above.
### Skim through the video associated with the challenge and create a multiple-choice question
First, find the `videoId`.
For example, in the following code from the header of a video challenge markdown file, the `videoId` is "nVAaxZ34khk". On GitHub, the information should be laid out in a table format.
````
---
id: 5e9a093a74c4063ca6f7c14d title: Data Analysis Example A challengeType: 11
videoId: nVAaxZ34khk
---
```
Next, access the YouTube video with that `videoId`. The URL for the video will be:
https://www.youtube.com/watch?v=[videoId] (replace `videoId` in the URL with the video's ID - without square brackets)
In the example above, the URL is https://www.youtube.com/watch?v=nVAaxZ34khk
Skim the YouTube video with that `videoId` and think of a multiple-choice question based on the content of the video.
### Add the Question to the Markdown File
You can add the question locally or using the GitHub interface. To add the question locally, you need to [set up freeCodeCamp locally](how-to-setup-freecodecamp-locally.md). You can also find the file on GitHub and click the edit button to add the question right in your browser.
If a question has not yet been added to a particular video challenge, it will have the following default question:
```md
# --question--
## --text--
Question text
## --answers--
Answer 1
---
Answer 2
---
More answers
## --video-solution--
1
```
Add/Update the question text under the part that shows:
```
# --question--
## --text--
```
Add/Update answers (`Answer 1`, `Answer 2`, and so on) under `## --answers--`. Make sure to update the number under `## --video-solution--` with the correct answer number. You can add more possible answers using the same format. The questions and answers can be surrounded with quotation marks.
### Question examples
````md
# --question--
## --text--
What does this JavaScript code log to the console?
```js
console.log('hello world');
````
## --answers--
hello _world_
---
**hello** world
---
hello world
---
## --video-solution--
3
````
````md
# --question--
## --text--
What will print out after running this code:
```py
width = 15
height = 12.0
print(height/3)
````
## --answers--
39
---
4
---
4.0
---
5.0
---
5
## --video-solution--
3 ````
For more examples, you can look at the markdown files for the following video course. All the challenges already have questions: [Python for Everybody Course](https://github.com/freeCodeCamp/freeCodeCamp/tree/main/curriculum/challenges/english/07-scientific-computing-with-python/python-for-everybody)
## Open a Pull Request
After creating one or more questions, you can commit the changes to a new branch and [open a pull request](how-to-open-a-pull-request.md).
@@ -1,207 +0,0 @@
# How to open a Pull Request (PR)
A pull request (PR), enables you to send changes from your fork on GitHub to freeCodeCamp.org's main repository. Once you are done making changes to the code, you can follow these guidelines to open a PR.
We expect our contributors to be aware of the process specific to this project. Following the guidelines carefully earns you the respect of fellow maintainers and saves everyone time.
Some examples of this are:
1. Do not edit files directly through GitHub – while you can, it's not a good idea.
2. Make sure the PR title follows [our convention](#prepare-a-good-pr-title).
3. Make sure you follow the PR checklist and not just tick things off; otherwise, we won't take you seriously.
4. Use the correct way to link issues in the description of the PR by updating the `XXXXXX`. Do not just add issue numbers everywhere and anywhere you feel like.
5. Do not "@mention" or request someone for reviews too many times.
We understand you are excited about contributing. As much as a maintainer will love to get back to you, they are busy people looking after hundreds of requests just like yours. Be patient, someone will get to you sooner or later.
6. Do not work directly off your `main` branch - create a new branch for the changes you are working on.
> [!NOTE] Your PR should be targeting changes to the English curriculum only. Read [this guide](index.md#translations) instead for contributing to translations.
## Prepare a Good PR Title
We use [conventional title and messages](https://www.conventionalcommits.org/) for commits and pull requests. The convention has the following format:
> `<type>([optional scope(s)]): <description>`
>
> For example:
>
> `fix(learn): tests for the do...while loop challenge`
Whenever you open a Pull Request (PR), you can use the below to determine the type, scope (optional), and description.
**Type:**
| Type | When to select |
|:----- |:------------------------------------------------------------------------------- |
| fix | Changed or updated/improved functionality, tests, the wording of a lesson, etc. |
| feat | Only if you are adding new functionality, tests, etc. |
| chore | Changes that are not related to code, tests, or verbiage of a lesson. |
| docs | Changes to `/docs` directory or the contributing guidelines, etc. |
**Scope:**
You can select a scope from [this list of labels](https://github.com/freeCodeCamp/freeCodeCamp/labels?q=scope).
**Description:**
Keep it short (less than 30 characters) and simple; you can add more information in the PR description box and comments.
Some examples of good PR titles would be:
- `fix(a11y): improved search bar contrast`
- `feat: add more tests to HTML and CSS challenges`
- `fix(api,client): prevent CORS errors on form submission`
- `docs(i18n): fix links to be relative instead of absolute`
## Proposing a Pull Request
1. Once the edits have been committed, you will be prompted to create a pull request on your fork's GitHub Page.
<details>
<summary>See screenshot</summary>
![Image - Compare & pull request prompt on GitHub](https://contribute.freecodecamp.org/images/github/compare-pull-request-prompt.png)
</details>
2. By default, all pull requests should be against the freeCodeCamp main repo, `main` branch.
Make sure that your Base Fork is set to freeCodeCamp/freeCodeCamp when raising a Pull Request.
<details>
<summary>See screenshot</summary>
![Image - Comparing forks when making a pull request](https://contribute.freecodecamp.org/images/github/comparing-forks-for-pull-request.png)
</details>
3. Submit the pull request from your branch to freeCodeCamp's `main` branch.
4. Include a more detailed summary of the changes you made and how your changes are helpful in the body of your PR.
- You will be presented with a pull request template. This is a checklist that you should have followed before opening the pull request.
- Fill in the details as you see fit. Ensure that you give the reviewers enough context to review the changes. If the PR makes changes to the UI, be sure to include screenshots of the changes as well. All of this information will be reviewed and the reviewers will decide whether or not your pull request is accepted.
- If the PR is meant to address an existing GitHub Issue then, at the end of your PR's description body, use the keyword _Closes_ with the issue number to [automatically close that issue if the PR is accepted and merged](https://help.github.com/en/articles/closing-issues-using-keywords).
> Example: `Closes #123` will close issue 123
5. Indicate if you have tested on a local copy of the site or not.
- This is very important when making changes that are not just edits to text content like documentation or a challenge description. Examples of changes that need local testing include JavaScript, CSS, or HTML, which could change the functionality or layout of a page.
- If your PR affects the behavior of a page, it should be accompanied by corresponding [Playwright integration tests](how-to-add-playwright-tests.md).
## Feedback on Pull Requests
> :tada: Congratulations on making a PR and thanks a lot for taking the time to contribute.
Our moderators will now take a look and leave you feedback. Please be patient with the fellow moderators and respect their time. All pull requests are reviewed in due course.
And as always, feel free to ask questions on the ['Contributors' category on our forum](https://forum.freecodecamp.org/c/contributors) or [the contributors chat room](https://discord.gg/PRyKn3Vbay).
> [!TIP] If you are to be contributing more pull requests, we recommend you read the [making changes and syncing](how-to-setup-freecodecamp-locally.md#making-changes-locally) guidelines to avoid having to delete your fork.
## Conflicts on a Pull Request
Conflicts can arise because many contributors work on the repository, and changes can break your PR which is pending a review and merge.
Since we squash all commits, you may not need to do a rebase. However, if a rebase is requested, check our [For Usual Bug Fixes and Features](#for-usual-bug-fixes-and-features) or [For Upcoming Curriculum and Features](#for-upcoming-curriculum-and-features) guides to learn how to do this process for your corresponding PR.
### For Usual Bug Fixes and Features
When you are working on regular bugs and features on our development branch `main`, you are able to do a simple rebase:
1. Rebase your local copy:
```bash
git checkout <pr-branch>
git pull --rebase upstream main
```
2. Resolve any conflicts and add / edit commits
```bash
# Either
git add .
git commit -m "chore: resolve conflicts"
# Or
git add .
git commit --amend --no-edit
```
3. Push back your changes to the PR
```bash
git push --force origin <pr-branch>
```
### For Upcoming Curriculum and Features
When you are working on features for our upcoming curriculum `next-*` branches, you have to do a `cherry-pick`:
1. Make sure your upstream comes in sync with your local:
```bash
git checkout main
git fetch --all --prune
git checkout next-python-projects
git reset --hard upstream/next-python-projects
```
2. Take a backup
a. Either delete your local branch after taking a backup (if you still have it locally):
```bash
git checkout <pr-branch-name>
# example:
# git checkout feat/add-numpy-video-question
git checkout -b <backup-branch-name>
# example:
# git checkout -b backup-feat/add-numpy-video-question
git branch -D <pr-branch-name>
```
b. Or just a backup of your PR branch (if you do not have it locally):
```bash
git checkout -b <backup-branch-name> origin/<pr-branch-name>
# example:
# git checkout -b backup-feat/add-numpy-video-question origin/feat/add-numpy-video-question
```
3. Start off with a clean slate:
```bash
git checkout -b <pr-branch-name> next-python-projects
git cherry-pick <commit-hash>
```
4. Resolve any conflicts, cleanup, and install dependencies and run tests
```bash
pnpm run clean
pnpm install
FCC_SUPERBLOCK='<superblock-name>' pnpm run test:curriculum
# example:
# FCC_SUPERBLOCK='python-for-everybody' pnpm run test:curriculum
```
5. If everything looks good, push back to the PR
```bash
git push --force origin <pr-branch-name>
```
@@ -1,54 +0,0 @@
# 如何校对译文
Our proofreading team is responsible for ensuring that translations accurately reflect the source text. We trust our proofreaders to ensure that we have very high quality translations.
All our translations are done by hand, by real humans. Proofreading ensures that there is a consistent tone across all our translated resources like the curriculum.
To begin proofreading, visit [our translation platform](https://translate.freecodecamp.org) and login. Select "Go to console" in the top navigation bar to switch from the public view to the workspace view.
## 选择文件
You should see the list of projects you have been granted access to. Select the project that you would like to proofread, then select the language.
![Image - Proofreading File Tree](https://contribute.freecodecamp.org/images/crowdin/proof-file-tree.png)
You should now see the list of available files. Choose your file by selecting the `Proofread` button on the right of that file, then choosing `Proofreading` from the drop-down menu that appears.
> [!NOTE] If you are in this workspace view, but want to work on [translating a file](how-to-translate-files.md) instead of proofreading, you may select `Crowdsourcing` from the dropdown menu instead.
## 校对译文
![Image - Proofreading View](https://contribute.freecodecamp.org/images/crowdin/proofread.png)
<!--Add proofread/crowdsource button to the image-->
Here you will see the list of strings in the selected file, with their related translations. The translation that is displayed here is the translation that has received the highest score (between upvotes and downvotes) from the translation community.
While you can view _all_ proposed translations for a given string, the community scores (determined by the upvotes and downvotes) should be taken into consideration when choosing which translation to approve. The community can review proposed translations and recommend which one is most accurate and clear.
1. 这是源文件的字符串(英文)。
2. 这是相匹配的翻译的字符串。 此处将显示基于赞同和反对票数的最受欢迎的译文建议。
3. 点击这个选择标记按钮确认该译文。
4. Crowdin 将显示每个字符串的状态。 `Done` 的意思是已经确认了译文,我们将在下次从 Crowdin 拉取内容的时候下载已确认的译文。 `Todo` 的意思是字符串的译文还未被校对确认。 `Hidden` means the string is locked and _should not be translated_. `Comment` 的意思是对此字符串有评论消息。
5. 可以使用复框选择多条译文,并在此处一次性批量确认。
6. 你可以在此处查看社区建议的译文,社区对其的评分,以及 Crowdin 建议的译文。
7. 这个按钮显示/隐藏右侧的显示窗口,你可以在其中查看翻译、评论、翻译记忆和词汇表术语。
8. Crowdin 在此处显示来自质量保证检查的报错消息。 也就是说,如果译文中有不正确的地方,Crowdin 会通知你。 请仔细校对确认出现报错消息的译文。
No additional actions are required once a file has been proofread.
> [!NOTE] Approving a string in the proofreading view will mark it as complete and it will be downloaded in our next pull from Crowdin to GitHub.
## Becoming a Proofreader
If you have any questions, or are interested in becoming a proofreader, feel free to reach out to us in our [contributors chat room](https://discord.gg/PRyKn3Vbay). We will typically grant you proofreading access if you have been contributing to freeCodeCamp for a while.
Our staff team and community moderators teams are always looking for kind volunteers like you who help us make high quality translations available to the world.
> [!NOTE] Crowdin 会允许你校对你自己的译文。 一般来说,最好是让另一位校对者审核你的译文,以确保最终内容的准确性。
## Creating a Channel on Chat for a World Language
For the most part, we encourage you to use the [contributors chat](https://discord.gg/PRyKn3Vbay) room for all correspondence. However if the team of volunteer translators grows for a certain language, we can consider creating an additional break-out channel for the language.
If you are already a proofreader and are interested in having a dedicated channel on our chat servers for a specific language, [fill out this form](https://forms.gle/XU5CyutrYCgDYaVZA).
@@ -1,289 +0,0 @@
Follow these guidelines for setting up a development environment for freeCodeCamp. This is highly recommended if you want to contribute regularly.
## Choose between Gitpod or your Own Machine (local setup)
> [!ATTENTION] - freeCodeCamp does not build and run natively on Windows, you will [need to use WSL2](how-to-setup-wsl.md) for a Linux-like setup on Windows. - You can't use Windows Command Prompt, Git Bash or PowerShell to build and run the codebase. - Note that if using Windows, the hardware requirements need to be more than [what we mention](how-to-setup-freecodecamp-locally?id=how-to-prepare-your-local-machine) to accommodate for WSL-based setup.
If you are looking to make a one-off contribution, you should use Gitpod to make changes. The Gitpod setup launches a ready-to-code environment in a few minutes in your web browser. To contribute long-term, we recommend you set up freeCodeCamp on your local machine.
Here are some pros and cons which should help you decide which option is best for you:
| Gitpod | Your own machine (local setup) |
| ----------------------------------------------------------------- | --------------------------------------------------------------------- |
| No minimum hardware requirements | Specific and minimum requirements |
| No need to install any software | Additional software required |
| Always up to date copy of repository | Need to maintain a local copy of the repository |
| Slower and can take a few minutes to launch | Faster and can be launched in seconds |
| Need an internet connection to work | Minimal internet connection required (once setup) |
| Some tasks like compilation and tests can take longer to complete | Faster completion of tasks (depending on your machine's capabilities) |
### How to Prepare a Gitpod Workspace
We have automated the process of installing all the dependencies & tools you will need. With Gitpod you get a free ready-to-code environment in a few minutes, and is useful if you do not have access to a computer or want to make one-time changes.
There are various ways to launch a Gitpod workspace:
1. **(Fastest)** Prepend `gitpod.io/#` in front of any URL from GitHub.
For example, if you visit your fork at `https://github.com/YOUR_USER_NAME/freeCodeCamp.git`, add `gitpod.io/#` in the front of the URL in the address bar and hit enter.
That is you can navigate to `gitpod.io/#https://github.com/YOUR_USER_NAME/freeCodeCamp.git` and you should see a workspace created for you. This works for any repository or pull-request on GitHub.
2. Alternatively install one of the below extensions for your browser.
- [Chrome Webstore](https://chrome.google.com/webstore/detail/gitpod-always-ready-to-co/dodmmooeoklaejobgleioelladacbeki) - works with Chromium-based browsers like Google Chrome, Brave, Edge, etc.
- [Firefox Add-on](https://addons.mozilla.org/en-US/firefox/addon/gitpod) - Firefox
Once installed you will see a 'Gitpod' button on every repository, pull-request, etc. as a handy shortcut to launch a workspace from there. See the extension page for details, screenshots, etc.
That's it, you can now skip to the 'syncing up from parent' section after you have launched a Gitpod workspace. Most parts of this guide applies to Gitpod workspaces, but be mindful of [how the URLs & Ports work within a Gitpod](https://www.gitpod.io/docs/configure/workspaces/ports) workspace.
**Note: Troubleshooting port issues on Gitpod**
Sometimes the service on port `8000` doesn't go live. This is common when you are restarting an inactive workspace.
If the service is not coming up on port `8000`, you can troubleshoot using these steps:
- **Start the server**: Run `pnpm run develop:server` in one terminal window from the root project directory (`/workspace/freeCodeCamp`) to start the server.
- **Start the client**: In another terminal window, run `pnpm run develop -- -H '0.0.0.0'` from the client directory (`/workspace/freeCodeCamp/client`) to start the client.
This should make port `8000` available.
### How to Prepare your Local Machine
Here is a minimum system requirement for running freeCodeCamp locally:
- 8 GB RAM
- Relatively fast CPU (4+ cores)
- Windows 10 or 11 (with WSL), macOS, or Linux
Start by installing the prerequisite software for your operating system.
We primarily support development on Linux and Unix-based systems like Ubuntu and macOS. You can develop on Windows 10 or 11 with WSL2 only. You can follow [this guide](how-to-setup-wsl.md) to set up WSL2. You can't use Command Prompt, Git Bash or PowerShell to run freeCodeCamp natively within windows.
#### Prerequisites:
| Prerequisite | Version | Notes |
| --------------------------------------------------------------------------------------------- | ------- | ------------------------------------------------------------------------------------------- |
| [Node.js](http://nodejs.org) | `20.x` | We use the "Active LTS" version, See [LTS Schedule](https://nodejs.org/en/about/releases/). |
| [pnpm](https://pnpm.io/installation) | `8.x` | - |
| [MongoDB Community Server](https://docs.mongodb.com/manual/administration/install-community/) | `5.0.x` | - |
> [!ATTENTION] If you have a different version, please install the recommended version. We can only support installation issues for recommended versions. See [troubleshooting section](troubleshooting-development-issues.md) for details.
If Node.js is already installed on your machine, run the following commands to validate the versions:
```bash
node -v
pnpm -v
```
> [!TIP] We highly recommend updating to the latest stable releases of the software listed above, also known as Long Term Support (LTS) releases.
Once you have the prerequisites installed, you need to prepare your development environment. This is common for many development workflows, and you will only need to do this once.
##### Follow these steps to get your development environment ready:
1. Install [Git](https://git-scm.com/) or your favorite Git client, if you haven't already. Update to the latest version; the version that came bundled with your OS may be outdated.
2. (Optional but recommended) [Set up an SSH Key](https://help.github.com/articles/generating-an-ssh-key/) for GitHub.
3. Install a code editor of your choice. If you aren't sure which one to use, we recommend [Visual Studio Code](https://code.visualstudio.com/) — it's free and open source.
4. Set up linting for your code editor.
You should have [ESLint running in your editor](http://eslint.org/docs/user-guide/integrations.html), and it will highlight anything that doesn't conform to [freeCodeCamp's JavaScript Style Guide](http://forum.freecodecamp.org/t/free-code-camp-javascript-style-guide/19121).
> [!TIP] Please do not ignore any linting errors. They are meant to **help** you and to ensure a clean and simple codebase.
## Fork the Repository on GitHub
[Forking](https://help.github.com/articles/about-forks/) is a step where you get your own copy of freeCodeCamp's main repository (a.k.a _repo_) on GitHub.
This is essential, as it allows you to work on your own copy of freeCodeCamp on GitHub, or to download (clone) your repository to work on locally. Later, you will be able to request changes to be pulled into the main repository from your fork via a pull request (PR).
> [!TIP] The main repository at `https://github.com/freeCodeCamp/freeCodeCamp` is often referred to as the `upstream` repository.
>
> Your fork at `https://github.com/YOUR_USER_NAME/freeCodeCamp` is often referred to as the `origin` repository. `YOUR_USER_NAME` would be replaced with your GitHub username.
**Follow these steps to fork the `https://github.com/freeCodeCamp/freeCodeCamp` repository:**
1. Go to the freeCodeCamp repository on GitHub: <https://github.com/freeCodeCamp/freeCodeCamp>
2. Click the "Fork" Button in the upper right-hand corner of the interface ([More Details Here](https://help.github.com/articles/fork-a-repo/))
3. After the repository has been forked, you will be taken to your copy of the freeCodeCamp repository at `https://github.com/YOUR_USER_NAME/freeCodeCamp` (`YOUR_USER_NAME` would be replaced with your GitHub user name.)
<details>
<summary>
How to fork freeCodeCamp on GitHub (screenshot)
</summary>
<br>
<img src="https://raw.githubusercontent.com/freeCodeCamp/freeCodeCamp/main/docs/images/github/how-to-fork-freeCodeCamp.gif" alt="How to fork freeCodeCamp on GitHub" />
</details>
## Clone your Fork from GitHub
[Cloning](https://help.github.com/articles/cloning-a-repository/) is where you **download** a copy of a repository from a `remote` location that is either owned by you or by someone else. In your case, this remote location is your `fork` of freeCodeCamp's repository that should be available at `https://github.com/YOUR_USER_NAME/freeCodeCamp`. (`YOUR_USER_NAME` would be replaced with your GitHub user name.)
> [!WARNING] If you are working on a WSL2 Linux Distro, you might get performance and stability issues by running this project in a folder which is shared between Windows and WSL2 (e.g. `/mnt/c/Users/`). Therefore we recommend to clone this repo into a folder which is mainly used by your WSL2 Linux Distro and not directly shared with Windows (e.g. `~/PROJECTS/`).
>
> See [this GitHub Issue](https://github.com/freeCodeCamp/freeCodeCamp/issues/40632) for further information about this problem.
Run these commands on your local machine:
1. Open a Terminal / Command Prompt / Shell in your projects directory
_i.e.: `/yourprojectsdirectory/`_
2. Clone your fork of freeCodeCamp, replacing `YOUR_USER_NAME` with your GitHub Username
```bash
git clone --depth=1 https://github.com/YOUR_USER_NAME/freeCodeCamp.git
```
This will download the entire freeCodeCamp repository to your projects directory.
Note: `--depth=1` creates a shallow clone of your fork, with only the most recent history/commit.
## Set up Syncing from Parent
Now that you have downloaded a copy of your fork, you will need to set up an `upstream` remote to the parent repository.
[As mentioned earlier](#fork-the-repository-on-github), the main repository is referred to as the `upstream` repository. Your fork is referred to as the `origin` repository.
You need a reference from your local clone to the `upstream` repository in addition to the `origin` repository. This is so that you can sync changes from the main repository without the requirement of forking and cloning repeatedly.
1. Change the directory to the new freeCodeCamp directory:
```bash
cd freeCodeCamp
```
2. Add a remote reference to the main freeCodeCamp repository:
```bash
git remote add upstream https://github.com/freeCodeCamp/freeCodeCamp.git
```
3. Ensure the configuration looks correct:
```bash
git remote -v
```
The output should look something like below (replacing `YOUR_USER_NAME` with your GitHub username):
```bash
origin https://github.com/YOUR_USER_NAME/freeCodeCamp.git (fetch)
origin https://github.com/YOUR_USER_NAME/freeCodeCamp.git (push)
upstream https://github.com/freeCodeCamp/freeCodeCamp.git (fetch)
upstream https://github.com/freeCodeCamp/freeCodeCamp.git (push)
```
## Running freeCodeCamp Locally
Now that you have a local copy of freeCodeCamp, you can follow these instructions to run it locally. This will allow you to:
- Preview edits to pages as they would appear on the learning platform.
- Work on UI related issues and enhancements.
- Debug and fix issues with the application servers and client apps.
If you do run into issues, first perform a web search for your issue and see if it has already been answered. If you cannot find a solution, please search our [GitHub issues](https://github.com/freeCodeCamp/freeCodeCamp/issues) page for a solution and report the issue if it has not yet been reported.
And as always, feel free to ask questions on the ['Contributors' category on our forum](https://forum.freecodecamp.org/c/contributors) or [our chat server](https://discord.gg/PRyKn3Vbay).
### Configuring Dependencies
#### Step 1: Set up the Environment Variable File
The default API keys and environment variables are stored in the file `sample.env`. This file needs to be copied to a new file named `.env` that is accessed dynamically during the installation step.
```bash
# Create a copy of the "sample.env" and name it ".env".
# Populate it with the necessary API keys and secrets
```
```bash
cp sample.env .env
```
The keys in the `.env` file are _not_ required to be changed to run the app locally. You can leave the default values copied over from `sample.env` as-is.
> [!TIP] Keep in mind if you want to use services like Auth0 or Algolia, you'll have to acquire your own API keys for those services and edit the entries accordingly in the `.env` file.
#### Step 2: Install Dependencies
This step will install the dependencies required for the application to run:
```bash
pnpm install && pnpm run create:shared
```
#### Step 3: Start MongoDB and Seed the Database
Before you can run the application locally, you will need to start the MongoDB service.
> [!NOTE] Unless you have MongoDB running in a setup different than the default, the URL stored as the `MONGOHQ_URL` value in the `.env` file should work fine. If you are using a custom configuration, modify this value as needed.
>
> If you followed along with the [Windows 10 via WSL2 Setup Guide](how-to-setup-wsl.md), then you should be able to skip this step if the MongoDB server from that guide is already running. You can confirm this by checking that you can reach `http://localhost:27017` on your local machine.
Start the MongoDB server in a separate terminal:
```bash
mongod
```
> [!TIP] You can avoid having to start MongoDB every time by installing it as a background service. You can [learn more about it in their documentation for your OS](https://docs.mongodb.com/manual/administration/install-community/)
Next, let's seed the database. In this step, we run the below command that fills the MongoDB server with some initial data sets that are required by services. These include a few schemas, among other things.
```bash
pnpm run seed
```
By default, you will be signed in as a new user without any completed certifications. Run the following command if you need to develop with completed certifications or write Playwright tests:
```bash
pnpm run seed:certified-user
```
> [!WARNING] Running `pnpm run seed:certified-user` will log you out. You will have to clear your browser cookies and sign in again.
#### Step 4: Start the freeCodeCamp Client Application and API Server
You can now start up the API server and the client applications.
```bash
pnpm run develop
```
This single command will fire up all the services, including the API server and the client applications available for you to work on.
Once ready, open a web browser and visit <http://localhost:8000>. If the app loads, sign in. Congratulations – you're all set! You now have a copy of freeCodeCamp's entire learning platform running on your local machine.
The API server serves endpoints at `http://localhost:3000`. The Gatsby app serves the client application at `http://localhost:8000`.
While you are logged in, if you visit <http://localhost:3000/explorer> you should see the available APIs.
> [!WARNING] Clearing your cookies or running `pnpm run seed:certified-user` will log you out, and you will have to sign in again.
If you have issues while installing it, check out the [troubleshooting section](troubleshooting-development-issues.md).
## Quick Commands Reference
A quick reference to the commands that you will need when working locally.
| command | description |
| ------------------------------ | ------------------------------------------------------------------------------------------------------------- |
| `pnpm install` | Installs / re-installs all dependencies and bootstraps the different services. |
| `pnpm run seed` | Creates authorized test users and inserts them into MongoDB. Also runs `seed:exams` and `seed:surveys` below. |
| `pnpm run seed:certified-user` | Creates authorized test users with certifications fully completed, and inserts them into MongoDB. |
| `pnpm run seed:exams` | Creates exams and inserts them into MongoDB. |
| `pnpm run seed:surveys` | Creates surveys for defaults users and inserts them into MongoDB. |
| `pnpm run develop` | Starts the freeCodeCamp API Server and Client Applications. |
| `pnpm run clean` | Uninstalls all dependencies and cleans up caches. |
@@ -1,499 +0,0 @@
Follow this guide for setting up the freeCodeCamp mobile app locally on your system. This is highly recommended if you want to contribute regularly.
Some of the contribution workflows – like fixing bugs in the codebase – need you to run the freeCodeCamp app locally.
## How to Prepare your Local Machine
Start by installing the prerequisite software for your operating system.
### Prerequisites
| Prerequisite | Version | Notes |
| --------------------------------- | ------- | ---------------------------------------- |
| [Flutter](https://flutter.dev/) | `3.x` | - |
| Dart (comes bundled with Flutter) | `3.x` | We use the version bundled with Flutter. |
> [!ATTENTION] If you have a different version, please install the recommended version. We can only support installation issues for recommended versions.
If Flutter is already installed on your machine, run the following commands to validate the versions:
```bash
flutter --version
dart --version
```
> [!TIP] We highly recommend updating to the latest stable releases of the software listed above.
Once you have the prerequisites installed, you need to prepare your development environment. This is common for many development workflows, and you will only need to do this once.
#### Follow these steps to get your development environment ready:
1. Install [Git](https://git-scm.com/) or your favorite Git client, if you haven't already. Update to the latest version; the version that came bundled with your OS may be outdated.
2. Set up [Android Studio](https://developer.android.com/studio) and [Android Emulators](https://developer.android.com/studio/run/managing-avds) with the latest released Android version. We recommend using the Pixel 3a XL and Nexus One(for emulating smaller screens).
3. (Optional for MacOS) Set up Xcode and iOS Simulator with the latest released iOS version.
4. (Optional but recommended) [Set up an SSH Key](https://help.github.com/articles/generating-an-ssh-key/) for GitHub.
5. Install a code editor of your choice.
We highly recommend using [Visual Studio Code](https://code.visualstudio.com/) or Android Studio. We also recommend installing the official [extensions](https://docs.flutter.dev/get-started/editor?tab=vscode).
## Fork the Repository on GitHub
[Forking](https://help.github.com/articles/about-forks/) is a step where you get your own copy of the repository (a.k.a _repo_) on GitHub.
This is essential, as it allows you to work on your own copy of the freeCodeCamp mobile app on GitHub, or to download (clone) your repository to work on locally. Later, you will be able to request changes to be pulled into the main repository from your fork via a pull request (PR).
> [!TIP] The main repository at `https://github.com/freeCodeCamp/mobile` is often referred to as the `upstream` repository.
>
> Your fork at `https://github.com/YOUR_USER_NAME/mobile` is often referred to as the `origin` repository. `YOUR_USER_NAME` would be replaced with your GitHub username.
**Follow these steps to fork the `https://github.com/freeCodeCamp/mobile` repository:**
1. Go to the freeCodeCamp mobile repository on GitHub: <https://github.com/freeCodeCamp/mobile>
2. Click the "Fork" Button in the upper right-hand corner of the interface ([More Details Here](https://help.github.com/articles/fork-a-repo/))
3. After the repository has been forked, you will be taken to your copy of the repository at `https://github.com/YOUR_USER_NAME/mobile` (`YOUR_USER_NAME` would be replaced with your GitHub user name.)
## Clone your Fork from GitHub
[Cloning](https://help.github.com/articles/cloning-a-repository/) is where you **download** a copy of a repository from a `remote` location that is either owned by you or by someone else. In your case, this remote location is your `fork` of freeCodeCamp's repository which should be available at `https://github.com/YOUR_USER_NAME/mobile`. (`YOUR_USER_NAME` would be replaced with your GitHub user name.)
Run these commands on your local machine:
1. Open a Terminal / Command Prompt / Shell in your projects directory
_i.e.: `/yourprojectsdirectory/`_
2. Clone your fork of freeCodeCamp, replacing `YOUR_USER_NAME` with your GitHub Username
```bash
git clone --depth=1 https://github.com/YOUR_USER_NAME/mobile.git
```
This will download the entire freeCodeCamp mobile repository to your projects directory.
Note: `--depth=1` creates a shallow clone of your fork, with only the most recent history/commit.
## Set up Syncing from Parent
Now that you have downloaded a copy of your fork, you will need to set up an `upstream` remote to the parent repository.
[As mentioned earlier](#fork-the-repository-on-github), the main repository is referred to as the `upstream` repository. Your fork is referred to as the `origin` repository.
You need a reference from your local clone to the `upstream` repository in addition to the `origin` repository. This is so that you can sync changes from the main repository without the requirement of forking and cloning repeatedly.
1. Change directory to the new `mobile` directory:
```bash
cd mobile
```
2. Add a remote reference to the main freeCodeCamp mobile repository:
```bash
git remote add upstream https://github.com/freeCodeCamp/mobile.git
```
3. Ensure the configuration looks correct:
```bash
git remote -v
```
The output should look something like below (replacing `YOUR_USER_NAME` with your GitHub username):
```bash
origin https://github.com/YOUR_USER_NAME/mobile.git (fetch)
origin https://github.com/YOUR_USER_NAME/mobile.git (push)
upstream https://github.com/freeCodeCamp/mobile.git (fetch)
upstream https://github.com/freeCodeCamp/mobile.git (push)
```
## Running freeCodeCamp Mobile App Locally
Now that you have a local copy of the mobile app, you can follow these instructions to run it locally.
If you do run into issues, first perform a web search for your issue and see if it has already been answered. If you cannot find a solution, please search our [GitHub issues](https://github.com/freeCodeCamp/mobile/issues) page for a solution and report the issue if it has not yet been reported.
And as always, feel free to ask questions on the ['Contributors' category on our forum](https://forum.freecodecamp.org/c/contributors) or [our chat server](https://discord.gg/PRyKn3Vbay).
> [!NOTE] The `mobile` directory contains two folders ie. `mobile-api` and `mobile-app`. `mobile-api` contains the API code used for serving the podcasts. `mobile-app` contains the Flutter app which is where you should be when you follow the below steps.
### Configuring Dependencies
#### Step 1: Set Up the Environment Variable File
The default API keys and environment variables are stored in the file `sample.env`. This file needs to be copied to a new file named `.env` which is accessed dynamically during the installation step. Remember to change the directory to `mobile-app` before running the following commands.
```bash
# Create a copy of the "sample.env" and name it ".env".
# Populate it with the necessary API keys and secrets:
```
#### **macOS/Linux**
```bash
cp sample.env .env
```
#### **Windows**
```bash
copy sample.env .env
```
The keys in the `.env` file are _not_ required to be changed to run the app locally. You can leave the default values copied over from `sample.env` as-is.
#### Step 2: Install dependencies
This step will install the dependencies required for the application to run:
```bash
flutter pub get
```
#### Step 3: Start the freeCodeCamp mobile app
Start the emulator of your choice(Android or iOS) and wait for the bootup process to complete.
You can now start the app by running the following command:
```bash
flutter run
```
> [!TIP] If you're using VSCode or Android Studio then you can easily start the app without having to execute any terminal commands. More information [here](https://docs.flutter.dev/get-started/test-drive).
## Making Changes Locally
You can now make changes to files and commit your changes to the local clone of your fork.
Follow these steps:
1. Validate that you are on the `main` branch:
```bash
git status
```
You should get an output like this:
```bash
On branch main
Your branch is up-to-date with 'origin/main'.
nothing to commit, working directory clean
```
If you are not on main or your working directory is not clean, resolve any outstanding files/commits and checkout `main`:
```bash
git checkout main
```
2. Sync the latest changes from the upstream `main` branch to your local main branch:
> [!WARNING] If you have any outstanding pull request that you made from the `main` branch of your fork, you will lose them at the end of this step.
>
> You should ensure your pull request is merged by a moderator before performing this step. To avoid this scenario, you should **always** work on a branch other than the `main`.
This step **will sync the latest changes** from the main repository of freeCodeCamp mobile. It is important that you rebase your branch on top of the latest `upstream/main` as often as possible to avoid conflicts later.
Update your local copy of the freeCodeCamp mobile upstream repository:
```bash
git fetch upstream
```
Hard reset your main branch with the freeCodeCamp mobile main:
```bash
git reset --hard upstream/main
```
Push your main branch to your origin to have a clean history on your fork on GitHub:
```bash
git push origin main --force
```
You can validate that your current main matches the upstream/main by performing a diff:
```bash
git diff upstream/main
```
The resulting output should be empty.
3. Create a fresh new branch:
Working on a separate branch for each issue helps you keep your local work copy clean. You should never work on the `main`. This will soil your copy of freeCodeCamp mobile and you may have to start over with a fresh clone or fork.
Check that you are on `main` as explained previously, and branch off from there:
```bash
git checkout -b fix/update-guide-for-xyz
```
Your branch name should start with a `fix/`, `feat/`, `docs/`, etc. Avoid using issue numbers in branches. Keep them short, meaningful, and unique.
Some examples of good branch names are:
```md
fix/update-challenges-for-react
fix/update-guide-for-html-css
fix/platform-bug-sign-in-issues
feat/add-guide-article-for-javascript
translate/add-spanish-basic-html
```
4. Edit pages and work on code in your favorite text editor.
5. Once you are happy with the changes you should optionally run the mobile app locally to preview the changes.
6. Make sure you fix any errors and check the formatting of your changes.
7. Check and confirm the files you are updating:
```bash
git status
```
This should show a list of `unstaged` files that you have edited.
```bash
On branch feat/documentation
Your branch is up to date with 'upstream/feat/documentation'.
Changes were not staged for commit:
(use "git add/rm <file>..." to update what will be committed)
(use "git checkout -- <file>..." to discard changes in the working directory)
modified: README.md
modified: mobile-app/lib/main.dart
...
```
8. Stage the changes and make a commit:
In this step, you should only mark files that you have edited or added yourself. You can perform a reset and resolve files that you did not intend to change if needed.
```bash
git add path/to/my/changed/file.ext
```
Or you can add all the `unstaged` files to the staging area:
```bash
git add .
```
Only the files that were moved to the staging area will be added when you make a commit.
```bash
git status
```
Output:
```bash
On branch feat/documentation
Your branch is up to date with 'upstream/feat/documentation'.
Changes to be committed:
(use "git reset HEAD <file>..." to unstage)
modified: README.md
modified: mobile-app/lib/main.dart
```
Now, you can commit your changes with a short message like so:
```bash
git commit -m "fix: my short commit message"
```
Some examples:
```md
fix: update guide article for Java - for loop
feat: add guide article for alexa skills
```
Optional:
We highly recommend making a conventional commit message. This is a good practice that you will see on some of the popular Open Source repositories. As a developer, this encourages you to follow standard practices.
Some examples of conventional commit messages are:
```md
fix: update HTML guide article
fix: update build scripts for Travis-CI
feat: add article for JavaScript hoisting
docs: update contributing guidelines
```
Keep these short, not more than 50 characters. You can always add additional information in the description of the commit message.
This does not take any additional time than an unconventional message like 'update file' or 'add index.md'
You can learn more about why you should use conventional commits [here](https://www.conventionalcommits.org/en/v1.0.0-beta.2/#why-use-conventional-commits).
9. If you realize that you need to edit a file or update the commit message after making a commit you can do so after editing the files with:
```bash
git commit --amend
```
This will open up a default text editor like `nano` or `vi` where you can edit the commit message title and add/edit the description.
10. Next, you can push your changes to your fork:
```bash
git push origin branch/name-here
```
## Running mobile curriculum tests
> [!NOTE] You only need to follow this section if you're modifying the challenge test runner in the mobile app. Otherwise, you can go to the next section on [how to open a pull request](#proposing-a-pull-request-pr).
1. Clone a copy of the [freeCodeCamp repo](https://github.com/freeCodeCamp/freeCodeCamp) locally outside of your local copy of the freeCodeCamp mobile repo. Your folder structure should look like this:
```bash
├── freeCodeCamp
├── mobile
```
2. Change the directory to the freeCodeCamp repo:
```bash
cd freeCodeCamp
```
3. Make a copy of the `.env` file:
#### **macOS/Linux**
```bash
cp sample.env .env
```
#### **Windows**
```bash
copy sample.env .env
```
4. Install the dependencies for the freeCodeCamp repo:
```bash
pnpm install && pnpm run create:shared
```
5. Generate the challenge data JSON file:
```bash
pnpm run build:curriculum
```
6. Copy the generated JSON file to the mobile app:
#### **macOS/Linux**
```bash
cp ./shared/config/curriculum.json ../mobile/mobile-app/curriculum.json
```
#### **Windows**
```bash
copy .\shared\config\curriculum.json ..\mobile\mobile-app\curriculum.json
```
7. Change directory to the mobile app:
```bash
cd ../mobile/mobile-app
```
8. Install the dependencies for the mobile app:
```bash
flutter pub get
```
9. Update the test file to use the challenge data JSON file:
```bash
sed -i '' 's/..\/..\/shared\/config\/curriculum.json/.\/curriculum.json/g' test/widget_test.dart
```
10. Generate the challenge files:
```bash
flutter test test/widget_test.dart
```
11. Start a local server to serve the challenge files with the help of `serve` package:
```bash
npx serve
```
12. In a different terminal go back to the freeCodeCamp repo:
```bash
cd ../../freeCodeCamp
```
13. Run the cypress tests:
```bash
pnpm cypress run --config retries=1,screenshotOnRunFailure=false,video=false,baseUrl=http://localhost:3000/generated-tests/,specPattern=cypress/e2e/mobile-learn/test-challenges.js -s cypress/e2e/mobile-learn/test-challenges.js -b chrome
```
## Proposing a Pull Request (PR)
After you've committed your changes, check here for [how to open a Pull Request](how-to-open-a-pull-request.md).
<!-- ## Quick commands reference - NEED TO DISCUSS ABOUT THIS
A quick reference to the commands that you will need when working locally.
| command | description |
| -------------------------------------------------------------- | ----------------------------------------------------------------------------------- |
| `npm ci` | Installs / re-install all dependencies and bootstraps the different services. |
| `npm run seed` | Parses all the challenge markdown files and inserts them into MongoDB. | -->
## Troubleshooting
### Issues with installing the recommended prerequisites
We regularly develop on the latest or most popular operating systems like macOS 10.15 or later, Ubuntu 18.04 or later, and Windows 10 (with WSL2).
It is recommended to research your specific issue on resources such as Google, Stack Overflow, and Stack Exchange. There is a good chance that someone has faced the same issue and there is already an answer to your specific query.
If you are on a different OS and/or are still running into issues, see [getting help](#getting-help).
### Issues with the UI, build errors, etc.
If you face issues with the UI, or build errors a cleanup can be useful:
```bash
flutter clean
```
### Issues Installing Dependencies
If you get errors while installing the dependencies, please make sure that you are not in a restricted network or that your firewall settings do not prevent you from accessing resources.
Be patient as the first-time setup can take a while depending on your network bandwidth.
## Getting Help
If you are stuck and need help, feel free to ask questions on the ['Contributors' category on our forum](https://forum.freecodecamp.org/c/contributors) or [the contributors chat room](https://discord.gg/PRyKn3Vbay).
There might be an error in the console of your browser or in Bash / Terminal / Command Line that will help identify the problem. Provide this error message in your problem description so others can more easily identify the issue and help you find a resolution.
-224
View File
@@ -1,224 +0,0 @@
# Set up freeCodeCamp on Windows Subsystem for Linux (WSL)
> [!NOTE] Before you follow these instructions make sure your system meets the requirements.
>
> **WSL 2**: Windows 10 64-bit (Version 2004, Build 19041 or higher) - available for all distributions including Windows 10 Home.
>
> **Docker Desktop for Windows**: See respective requirements for [Windows 10 Pro](https://docs.docker.com/docker-for-windows/install/#system-requirements) and [Windows 10 Home](https://docs.docker.com/docker-for-windows/install-windows-home/#system-requirements)
This guide covers some common steps with the setup of WSL2. Once some of the common issues with WSL2 are addressed, you should be able to follow [this local setup guide](how-to-setup-freecodecamp-locally.md) to work with freeCodeCamp on Windows running a WSL distro like Ubuntu.
## Enable WSL
Follow the instructions on the [official documentation](https://docs.microsoft.com/en-us/windows/wsl/install-win10) to install WSL2.
## Install Ubuntu
1. We recommended using Ubuntu-18.04 or above with WSL2.
> [!NOTE]
>
> While you may use other non-Debian-based distributions, they all come with their own 'gotchas' that are beyond the scope of this guide.
As of November 2023, Ubuntu and Debian are the only Linux distributions [officially supported by Playwright](https://playwright.dev/docs/intro#system-requirements), the end-to-end testing library used by freeCodeCamp.
2. Update the dependencies for the OS
```bash
sudo apt update
sudo apt upgrade -y
# cleanup
sudo apt autoremove -y
```
## Set up Git
Git comes pre-installed with Ubuntu 18.04, verify your Git version with `git --version`.
```output
~
❯ git --version
git version 2.25.1
```
(Optional but recommended) You can now proceed to [setting up your ssh keys](https://help.github.com/articles/generating-an-ssh-key) with GitHub.
## Installing a Code Editor
We highly recommend installing [Visual Studio Code](https://code.visualstudio.com) on Windows 10. It has great support for WSL and automatically installs all the necessary extensions on your WSL distribution.
Essentially, you will edit and store your code on Ubuntu-18.04 with VS Code installed on Windows.
If you use [IntelliJ Idea](https://www.jetbrains.com/idea/), you may need to update your Node interpreter and npm package manager to what is installed on your WSL distro.
You can check these settings by going to Settings > Languages & Frameworks > Node.js and npm.
## Installing Docker Desktop
**Docker Desktop for Windows** allows you to install and run databases like MongoDB and other services like NGINX and more. This is useful to avoid common pitfalls with installing MongoDB or other services directly on Windows or WSL2.
Follow the instructions on the [official documentation](https://docs.docker.com/docker-for-windows/install) and install Docker Desktop for your Windows distribution.
There are some minimum hardware requirements for the best experience.
## Configure Docker Desktop for WSL
Once Docker Desktop is installed, [follow these instructions](https://docs.docker.com/docker-for-windows/wsl) and configure it to use the Ubuntu-18.04 installation as a backend.
This makes it so that the containers run on the WSL side instead of running on Windows. You will be able to access the services over `http://localhost` on both Windows and Ubuntu.
## Install MongoDB from Docker Hub
Once you have configured Docker Desktop to work with WSL2, follow these steps to start a MongoDB service:
1. Launch a new Ubuntu terminal
2. Pull MongoDB from Docker Hub. Please refer to the [Prerequisites](how-to-setup-freecodecamp-locally.md#Prerequisites) table for the current version of MongoDB used by freeCodeCamp. For example, if the version number is `5.0.x`, replace `<x.y>` with `5.0` in the following two code snippets.
```bash
docker pull mongo:<x.y>
```
3. Start the MongoDB service at port `27017`, and configure it to run automatically on system restarts
```bash
docker run -it \
-v mongodata:/data/db \
-p 27017:27017 \
--name mongodb \
--restart unless-stopped \
-d mongo:<x.y>
```
4. You can now access the service from both Windows or Ubuntu at `mongodb://localhost:27017`.
## Installing Node.js and pnpm
We recommend you install the LTS release for Node.js with a node version manager - [nvm](https://github.com/nvm-sh/nvm#installing-and-updating).
Once installed use this command to install and use the latest Node.js LTS version:
```bash
nvm install --lts
```
For instructions on installing and using a different version of Node.js, please refer to the [nvm docs](https://github.com/nvm-sh/nvm#usage).
Node.js comes bundled with `npm`, which you can use to install `pnpm`:
```bash
npm install -g pnpm
```
## Set up freeCodeCamp Locally
Now that you have installed the pre-requisites, follow [our local setup guide](how-to-setup-freecodecamp-locally.md) to clone, install and set up freeCodeCamp locally on your machine.
> [!WARNING]
>
> Please note, at this time the setup for Cypress tests (and related GUI needs) is a work in progress. You should still be able to work on most of the codebase.
## Optimize Windows and WSL
> [!NOTE]
>
> The following tips were collected from across the web and have not gone through vigorous testing. Your mileage may vary.
### Adjust processor scheduling for background services
This may reduce incidents of Docker containers crashing due to lack of resources.
Open the System Properties control panel by pressing <kbd>Win + R</kbd> and entering `sysdm.cpl`
<details>
<summary>
Enter <code>sysdm.cpl</code> in the Run dialog (screenshot)
</summary>
<br>
<img src="https://raw.githubusercontent.com/freeCodeCamp/freeCodeCamp/main/docs/images/wsl/run-sysdm.png" alt="Enter `sysdm.cpl` in the Run dialog" />
</details>
<br>
Go to Advanced -> Performance -> Settings…
<details>
<summary>
Performance Settings button under Advanced tab in System Properties (screenshot)
</summary>
<br>
<img src="https://raw.githubusercontent.com/freeCodeCamp/freeCodeCamp/main/docs/images/wsl/advanced-performance-settings.png" alt="Performance Settings button under Advanced tab in System Properties" />
</details>
<br>
Under Advanced -> Processor scheduling, choose "Background services". Do not close the window. Continue to the next tip.
<details>
<summary>
Background services radio button under Advanced tab in Performance Options (screenshot)
</summary>
<br>
<img src="https://raw.githubusercontent.com/freeCodeCamp/freeCodeCamp/main/docs/images/wsl/background-services.png" alt="Background services radio button under Advanced tab in Performance Options" />
</details>
### Increase the size of Windows paging file for the system drive
Under Advanced -> Virtual memory, click "Change…"
<details>
<summary>
Change virtual memory button under Advanced tab in Performance Options (screenshot)
</summary>
<br>
<img src="https://raw.githubusercontent.com/freeCodeCamp/freeCodeCamp/main/docs/images/wsl/advanced-virtual-memory.png" alt="Change virtual memory button under Advanced tab in Performance Options" />
</details>
<br>
Choose "Custom size". Set the initial size to 1.5x and the maximum size to 3x of your physical memory. Then click "Set".
<details>
<summary>
Set custom size button in Virtual Memory window (screenshot)
</summary>
<br>
<img src="https://raw.githubusercontent.com/freeCodeCamp/freeCodeCamp/main/docs/images/wsl/set-custom-size.png" alt="Set custom size button in Virtual Memory window" />
</details>
### Increase the size of memory allocated to WSL
Create a [`.wslconfig` file](https://learn.microsoft.com/en-us/windows/wsl/wsl-config#configuration-setting-for-wslconfig) in your [`%UserProfile%` directory](https://learn.microsoft.com/en-us/windows/wsl/wsl-config#wslconfig) (typically `C:\Users\<UserName>\.wslconfig`). Please read the [WSL documentation](https://learn.microsoft.com/en-us/windows/wsl/wsl-config#configuration-setting-for-wslconfig) carefully and replace `x` with values that suit your own needs:
```ini
# Settings apply across all Linux distros running on WSL 2
[wsl2]
# How much memory to assign to the WSL 2 VM. The default value might not be enough
memory=xGB
# How much swap space to add to the WSL 2 VM, default is 25% of available RAM
swap=xGB
```
### Increase Node.js max old space size
This fixes the ["JavaScript heap out of memory" error](https://stackoverflow.com/a/54456814) with ESLint. Add the following to your `~/.bashrc` or `~/.zshrc`:
```sh
export NODE_OPTIONS="--max-old-space-size=4096"
```
### Avoid `pnpm run test`
Instead, use the script [appropriate to your PR](https://forum.freecodecamp.org/t/wsl-performance-issues-while-working-on-the-codebase/644215/2#:~:text=usually%2C%20you%20just%20want%20to%20test%20something%20specific%20to%20either%20the%20curriculum%20or%20the%20client%20or%20the%20api%20-%20almost%20never%20all%203.); either `pnpm run test:api`, `pnpm run test:curriculum`, or `pnpm run test-client`.
## Useful Links
- [A WSL2 Dev Setup with Ubuntu 20.04, Node.js, MongoDB, VS Code, and Docker](https://hn.mrugesh.dev/wsl2-dev-setup-with-ubuntu-nodejs-mongodb-and-docker) - an article by Mrugesh Mohapatra (Staff Developer at freeCodeCamp.org)
- Frequently asked questions on:
- [Windows Subsystem for Linux](https://docs.microsoft.com/en-us/windows/wsl/faq)
- [Docker Desktop for Windows](https://docs.docker.com/docker-for-windows/faqs)
@@ -1,222 +0,0 @@
# How to Test Translations Locally
> [!NOTE] This process is not required, but documented in case you would like to preview what your translations will look like.
If you would like to test your translations on a local instance of the freeCodeCamp `/learn` site, first ensure you have [set up the codebase](how-to-setup-freecodecamp-locally.md).
## Enabling a Language
There are a few steps to take in order to allow the codebase to build in your desired language.
First, visit the `config/i18n/all-langs.ts` file to add the language to the available languages list and configure the values. There are four objects here.
- `availableLangs`: For both the `client` and `curriculum` arrays, add the text name of the language. This is the value that will be used in the `.env` file later.
- `auditedCerts`: Add the text name of the language as the _key_, and add an array of `SuperBlocks.{cert}` variables as the _value_. This tells the client which certifications are fully translated.
- `i18nextCodes`: These are the ISO language codes for each language. You will need to add the appropriate ISO code for the language you are enabling. These do need to be unique for each language.
- `LangNames`: These are the display names for the language selector in the navigation menu.
- `LangCodes`: These are the language codes used for formatting dates and numbers. These should be Unicode CLDR codes instead of ISO codes.
As an example, if you wanted to enable Dothraki as a language, your `all-langs.js` objects should look like this:
```js
export const availableLangs = {
client: ['english', 'espanol', 'chinese', 'chinese-traditional', 'dothraki'],
curriculum: [
'english',
'espanol',
'chinese',
'chinese-traditional',
'dothraki'
]
};
export const auditedCerts = {
espanol: [
SuperBlocks.RespWebDesign,
SuperBlocks.JsAlgoDataStruct,
SuperBlocks.FrontEndDevLibs,
SuperBlocks.DataVis,
SuperBlocks.BackEndDevApis
],
chinese: [
SuperBlocks.RespWebDesign,
SuperBlocks.JsAlgoDataStruct,
SuperBlocks.FrontEndDevLibs,
SuperBlocks.DataVis,
SuperBlocks.BackEndDevApis,
SuperBlocks.QualityAssurance,
SuperBlocks.SciCompPy,
SuperBlocks.DataAnalysisPy,
SuperBlocks.InfoSec,
SuperBlocks.MachineLearningPy
],
'chinese-traditional': [
SuperBlocks.RespWebDesign,
SuperBlocks.JsAlgoDataStruct,
SuperBlocks.FrontEndDevLibs,
SuperBlocks.DataVis,
SuperBlocks.BackEndDevApis,
SuperBlocks.QualityAssurance,
SuperBlocks.SciCompPy,
SuperBlocks.DataAnalysisPy,
SuperBlocks.InfoSec,
SuperBlocks.MachineLearningPy
],
dothraki: [
SuperBlocks.RespWebDesign,
SuperBlocks.JsAlgoDataStruct,
SuperBlocks.FrontEndDevLibs
]
};
export const i18nextCodes = {
english: 'en',
espanol: 'es',
chinese: 'zh',
'chinese-traditional': 'zh-Hant',
dothraki: 'mis'
};
export enum LangNames = {
english: 'English',
espanol: 'Español',
chinese: '中文(简体字)',
'chinese-traditional': '中文(繁體字)',
dothraki: 'Dothraki'
};
export enum LangCodes = {
english: 'en-US',
espanol: 'es-419',
chinese: 'zh',
'chinese-traditional': 'zh-Hant',
dothraki: 'mis'
};
```
Next, open the `client/src/utils/algolia-locale-setup.ts` file. This data is used for the search bar that loads `/news` articles. While it is unlikely that you are going to test this functionality, missing the data for your language can lead to errors when attempting to build the codebase locally.
Add an object for your language to the `algoliaIndices` object. You should use the the same values as the `english` object for local testing, replacing the `english` key with your language's `availableLangs` value.
> [!NOTE] If we have already deployed an instance of news in your target language, you can update the values to reflect the live instance. Otherwise, use the English values.
If you were to add Dothraki:
```js
const algoliaIndices = {
english: {
name: 'news',
searchPage: 'https://www.freecodecamp.org/news/search/'
},
espanol: {
name: 'news-es',
searchPage: 'https://www.freecodecamp.org/espanol/news/search/'
},
chinese: {
name: 'news-zh',
searchPage: 'https://chinese.freecodecamp.org/news/search/'
},
'chinese-traditional': {
name: 'news-zh',
searchPage: 'https://chinese.freecodecamp.org/news/search'
},
dothraki: {
name: 'news',
searchPage: 'https://www.freecodecamp.org/news/search/'
}
};
```
Finally, in your `.env` file, set `CLIENT_LOCALE` and `CURRICULUM_LOCALE` to your new language (use the `availableLangs` value.)
```txt
CLIENT_LOCALE=dothraki
CURRICULUM_LOCALE=dothraki
```
### Releasing a Superblock
After a superblock has been fully translated into a language, there are two steps to release it. First add the superblock enum to that language's `auditedCerts` array. So, if you want to release the new Responsive Web Design superblock for Dothraki, the array should look like this:
```ts
export const auditedCerts = {
// other languages
dothraki: [
SuperBlocks.RespWebDesignNew, // the newly translated superblock
SuperBlocks.RespWebDesign,
SuperBlocks.JsAlgoDataStruct,
SuperBlocks.FrontEndDevLibs
]
```
Finally, the `languagesWithAuditedBetaReleases` array should be updated to include the new language like this:
```ts
export const languagesWithAuditedBetaReleases: ['english', 'dothraki'];
```
This will move the new superblock to the correct place in the curriculum map on `/learn`.
## Enabling Localized Videos
For the video challenges, you need to change a few things. First add the new locale to the GraphQL query in the `client/src/templates/Challenges/video/Show.tsx` file. For example, adding Dothraki to the query:
```tsx
query VideoChallenge($slug: String!) {
challengeNode(fields: { slug: { eq: $slug } }) {
videoId
videoLocaleIds {
espanol
italian
portuguese
dothraki
}
...
```
Then add an id for the new language to any video challenge in an audited block. For example, if `auditedCerts` in `all-langs.ts` includes `scientific-computing-with-python` for `dothraki`, then you must add a `dothraki` entry in `videoLocaleIds`. The frontmatter should then look like this:
```yml
videoLocaleIds:
espanol: 3muQV-Im3Z0
italian: hiRTRAqNlpE
portuguese: AelGAcoMXbI
dothraki: new-id-here
dashedName: introduction-why-program
---
```
Update the `VideoLocaleIds` interface in `client/src/redux/prop-types` to include the new language.
```ts
export interface VideoLocaleIds {
espanol?: string;
italian?: string;
portuguese?: string;
dothraki?: string;
}
```
And finally update the challenge schema in `curriculum/schema/challengeSchema.js`.
```js
videoLocaleIds: Joi.when('challengeType', {
is: challengeTypes.video,
then: Joi.object().keys({
espanol: Joi.string(),
italian: Joi.string(),
portuguese: Joi.string(),
dothraki: Joi.string()
})
}),
```
## Loading Translations
Because the language has not been approved for production, our scripts are not automatically downloading the translations yet. Only staff have the access to directly download the translations - you are welcome to reach out to us in our [contributors chat room](https://discord.gg/PRyKn3Vbay), or you can translate the English markdown files locally for testing purposes.
Once you have the files, you will need to place them in the correct directory. For the curriculum challenges, you should place the certification folders (i.e. `01-responsive-web-design`) within the `curriculum/challenges/{lang}` directory. For our Dothraki translations, this would be `curriculum/challenges/dothraki`. The client translation `.json` files will go in the `client/i18n/locales/{lang}` directory.
Once these are in place, you should be able to run `npm run develop` to view your translated version of freeCodeCamp.
> [!ATTENTION] While you may perform translations locally for the purpose of testing, we remind everyone that translations should _not_ be submitted through GitHub and should only be done through Crowdin. Be sure to reset your local codebase after you are done testing.
-337
View File
@@ -1,337 +0,0 @@
# 如何翻译 freeCodeCamp 的资源
## Prepare yourself for Contributions
> The freeCodeCamp Localization Roadmap – There Are No Speed Limits
> [!TIP] You can start by reading [this announcement](https://www.freecodecamp.org/news/help-translate-freecodecamp-language/). We recommend joining [our community forum](https://forum.freecodecamp.org/c/contributors/3) and [Discord chat server](https://discord.gg/PRyKn3Vbay).
You can translate as much as you want, when you want. It's only a matter of how much time and energy you are willing to invest as a volunteer translator.
We just ask that you understand the following:
1. **翻译是一件团队协作的事情。**
翻译 freeCodeCamp 的资源是对贡献者来说最有趣和最有意义的经历之一。如果你邀请与你使用同一种语言的朋友和同事参与,那么效果最好。
You can start by reading [this announcement](https://www.freecodecamp.org/news/help-translate-freecodecamp-language/). We recommend joining [our community forum](https://forum.freecodecamp.org/c/contributors/3) and [Discord chat server](https://discord.gg/PRyKn3Vbay) with your friends and showing your interest before starting off with translations. Crowdin and other tools make it easy to contribute translations, but it's still a lot of work.
我们希望你在贡献过程感到快乐,而不是感到疲惫,然后失去兴趣。
如果你们有一个四到五人的小组,就可以开始翻译一种新的语言了。 你可以再招募更多的朋友来加入这个队伍。
2. **为每种语言版本提供服务器,需要较高的成本。**
表面上来看,技术栈可能看起来没那么复杂,但是实际上消耗了很多资源来让引擎跑起来。 这包括提供额外的服务器和专职人员来管理它们。
freeCodeCamp.org is committed to providing these for free as always, however we need to prioritize resources for those who need them the most. 我们非常不想看到某种语言的翻译活动结束了,并且内容过时了,然后我们不得不关闭相应的服务器。
For translating the curriculum, once a language reaches at least a few certifications we can begin deploying the language live on [`/learn`](https://www.freecodecamp.org/learn), while you continue to translate the remaining certifications.
举个例子, 当我们正式上线一个新的语言版本的时候,我们希望至少上线整个前端认证的内容。
3. **但是,如果一种语言没有在翻译平台上列出来,怎么办呢?**
我们已经查看了我们的用户群,并且在翻译平台的可用语言列表上添加了三十多种的常用语言。 有一些语言,例如中文和西班牙语,已经在 **"/learn"** 上线了。
然而遗憾的是,这个语言列表并没有涵盖所有的世界语言。 我们每天都能收到许多像你一样的贡献者的需求, 希望将我们的资源翻译成他们的语言。
我们当然希望在这个列表上增加更多的语言种类, 但是你可能已经猜到了, 假如我们有足够的人来翻译某一语言才能让这件事变得实际。
假如你希望我们增加某一种新的语言, 我们建议你鼓动你的朋友一起来参与贡献。
如果你们有一个组的人(至少四到五人)对某一种语言感兴趣,并且承诺翻译这种语言, 那么我们可以在翻译平台上增加这种语言。 我们会解释一切的细节,并且帮助你掌握这些翻译工具和理解这些翻译的过程。
## Overview of Crowdin
It's our dream to provide you with the resources to learn, no matter the world language you speak. To help us with this massive effort, we have integrated our open-source codebase & curriculum with [Crowdin](https://crowdin.com/) - A tool to help us localize our code-base.
> [!NOTE] We use a different tool and workflow for translating [news articles](https://www.freecodecamp.org/news). If you are interested in translating articles, read [this announcement](https://www.freecodecamp.org/news/help-translate-freecodecamp-language/) and reach out to your Language Lead.
The translation workflow is split into two main activities:
- **翻译**课程文件、文档和 UI 元素(如按钮、标签):
译者可以在[我们的翻译平台](https://translate.freecodecamp.org)注册,然后从 30+ 种语言版本中选择要参与贡献的版本,进行翻译。
- **校对**上述翻译。
校对者确认社区成员贡献的译文语调一致,没有错别字等常见问题。 简而言之,校对者需要确保译文是高质量的。 注意,我们不使用任何机器翻译。
> [!WARNING] We are no longer using GitHub to translate files directly, if you are a returning contributor head to our [translation platform](https://translate.freecodecamp.org/) instead.
## Getting Started
First, make sure you come say "Hi" in our [Discord](https://discord.gg/PRyKn3Vbay). 我们会在聊天室定期更新翻译的资源和回答很多问题。
其次,去我们的[翻译平台](https://translate.freecodecamp.org/)并且登陆(假如你以前没有贡献翻译过,你需要创建一个新账户)。
最后,浏览下面提供的细节图来理解怎么使用翻译工具和流程。
祝你在翻译过程中感到快乐哦!
## Select a Project and File
当你访问翻译平台,你应该可以看到很多不同的等待翻译的项目:
1. [贡献文档](https://translate.freecodecamp.org/contributing-docs)项目,其中包含此文档站点的文件。
2. [编程课程](https://translate.freecodecamp.org/curriculum)项目,其中包含我们课程的挑战文件。
3. [学习用户界面](https://translate.freecodecamp.org/learn-ui)项目,其中包含我们学习平台的按钮、标签等 UI 元素的字符串。
选择你想参与的任何项目,你将看到可供翻译的语言列表。
![图片 - 可翻译语言版本列表](https://contribute.freecodecamp.org/images/crowdin/languages.png)
选择你要使用的语言,你将看到完整的文件树。
![图片 - 可翻译文件列表](https://contribute.freecodecamp.org/images/crowdin/file-tree.png)
每个文件和文件夹都会显示一个进度条。 进度条的**蓝色**部分表示多少百分比的文件已经被翻译了,而**绿色**部分表示多少百分比的文件已经被校对团队审核确认。
选择你想翻译的文件,然后 Crowdin 会打开编辑界面。
> [!NOTE] When the editor view opens, you will need to click the settings icon (shown as a gear) and switch the 'HTML tags displaying' setting to 'SHOW'. This will ensure you can see tags such as `<code></code>` instead of `<0></0>`.
## Translate Curriculum
![图片 - 编辑界面](https://contribute.freecodecamp.org/images/crowdin/editor.png)
Crowdin 将文档分成可翻译的“字符串”,通常是句子。 每个字符串都被单独翻译。 参考上图:
1. 以绿色标示的字符串已经有了一个建议的翻译。
2. 以红色标示的字符串_没有_建议的翻译。
3. 带有灰色文本的字符串不可翻译。 对于代码块和其他必须不被翻译的内容,就是这种情况。 你将无法在编辑器中选择这些字符串。
4. 如果某位贡献者对某个字符串有建议的译文,那么 Crowdin 将在此处显示所有的建议。 你无法保存相同的译文。如果某个译文是正确的,那么你可以点击 `+` 图标,给它投票表示赞同。 如果你觉得某个译文不正确,那么你可以点击 `-` 图标,投反对票。
5. Crowdin 将基于翻译记忆(TM)或机器翻译(MT)推荐译文。 翻译记忆是指我们已在其他文件中翻译过/批准过的相似的或相同的字符串。 机器翻译是指由 Crowdin 系统推荐的翻译。
6. 这是编辑器窗口,你可以在其中输入你对于所选字符串建议的译文。
7. 编辑窗口当前选中的字符串将被标注为黄色。
8. 这里的标签是表示字符串的状态。 `Done` 标签表示字符串有至少一个建议的译文。 `Todo` 标签表示字符串还没有建议的译文。
9. 这里是评论窗口。 如果你对某个字符串有疑问或疑虑,可以在此处对字符串发表评论,以便其他翻译人员查看。
10. 点击这两个“窗格”按钮,可以隐藏左边的(文件)视图和右边的(评论)视图。
> [!NOTE] If you see a hidden string that includes translations, please notify us in the [Discord](https://discord.gg/PRyKn3Vbay) so we can remove the translation from memory.
当你翻译完一个字符串,请点击 `Save` 按钮,将你的译文保存在 Crowdin 中。 然后其他贡献者可以给你的译文投票,而校对者也将审核确认你的译文。
你想翻译多少字符串,都可以,我们非常欢迎你贡献!当你翻译完某个文件或某个字符串之后,你不需要采取其他步骤。 你只需要点击 `Save` 按钮,就能保存你的译文了。
> [!NOTE] If you see something in the English source file that is inaccurate or incorrect, please do not fix it through the translation flow. Instead, leave a comment on the string to notify us that there is a discrepancy, or create a GitHub issue.
## Translate the Learn Interface
Our `/learn` interface relies on JSON files loaded into an i18n plugin to generate translated text. This translation effort is split across both Crowdin and GitHub.
### On GitHub
The `links.json`, `meta-tags.json`, `motivation.json`, and `trending.json` files contain information that needs to be updated to reflect your language. However, we cannot load these into Crowdin, as the content isn't something that would be a one-to-one translation.
These files will most likely be maintained by your language lead but you are welcome to [read about how to translate them](language-lead-handbook.md).
### On Crowdin
> [!ATTENTION] Do not edit the following files through a GitHub PR.
The `intro.json` and `translations.json` files are both translated on Crowdin, in the Learn User Interface project. Translating these can be a bit tricky, as each individual JSON value appears as its own string and sometimes the context is missing.
However, the `Context` information provided in Crowdin can help understand where the string fits in to the larger structure.
![Image with an arrow pointing to Crowdin's context information](https://contribute.freecodecamp.org/images/crowdin/context.png)
If you have any questions about where a string fits in to the prose, reach out to us in our [contributor chat](https://discord.gg/PRyKn3Vbay).
## Translate Documentation
Translating our contributing documentation is a similar flow to translating our curriculum files.
> [!NOTE] Our contributing documentation is powered by `docsify`, and we have special parsing for message boxes like this one. If you see strings that start with `[!NOTE]`, `[!WARNING]`, or `[!TIP]`, these words should NOT be translated.
### How to Translate Documentation with Internal Links
When you work on translating contributing documentation, watch out for internal links targeting a different section of the documentation.
Make sure to replace the id of the target section (the part after `#`) with the id on the translated document. For example, it will look like this in Japanese:
Before translation
```
// in HTML
<a href="target-file-name.md#target-section-heading-id">Link text</a>
<a href="#target-section-heading-id">Link text</a>
// in Markdown
[Link text](target-file-name.md#target-section-heading-id)
[Link text](#target-section-heading-id)
```
After translation
```
// in HTML
<a href="target-file-name.md#翻訳後の-id">翻訳後のリンクテキスト</a>
<a href="#翻訳後の-id">翻訳後のリンクテキスト</a>
// in Markdown
[翻訳後のリンクテキスト](target-file-name.md#翻訳後の-id)
[翻訳後のリンクテキスト](#翻訳後の-id)
```
The actual files in docs are written in Markdown, but they will appear as HTML tags on Crowdin.
You can find out how `docsify` converts a string in your language into an id by looking into the translated pages. If the translation is not deployed yet, you can preview it by [running the docs site locally](how-to-work-on-the-docs-theme.md#serving-the-documentation-site-locally).
You can learn more about [internal links in our docs here](how-to-work-on-the-docs-theme.md#how-to-create-an-internal-link).
## Translate the LearnToCode RPG
The LearnToCode RPG runs on Ren'Py, which uses special syntax for translated strings: (See [Ren'Py Text documentation](https://www.renpy.org/doc/html/text.html))
- The sentences to be translated are always between `""`. These are dialogues or UI strings. The keywords that come before or after the dialogue are game engine control keywords and will be explained in details in subsequent rules. Please note that this first rule governs all subsequent rules listed.
- In case of `new "..."` Do not translate the `new` keyword.
- Prefixes like `player`, `annika`, `layla`, `marco` (or variants like `player happy`, `player @ happy`) should not be translated. These are control keywords to correctly display the character sprite in the game.
- Postfixes like `nointeract` should not be translated.
- Do not translate things between `[]` and `{}`. These are variable interpolations and text tags. These must remain halfwidth parentheses `[]` and `{}` instead of their fullwidth counterparts `【】` and `「」`
- Do not translate the `nointeract` keyword at the end of the sentence.
- If we try to use fullwidth parentheses `()`, a QA warning will show. To avoid the QA warning, use halfwidth parentheses `()`
### Examples
---
#### Before translation
```renpy
# "[player_name]? What a coincidence! Our VIP team member {a=[vip_profile_url]}[player_name]{/a} will be honored to hear that."
"[player_name]? What a coincidence! Our VIP team member {a=[vip_profile_url]}[player_name]{/a} will be honored to hear that." <--- this is the line that needs to be translated. see translation below
```
#### After translation
```renpy
# "[player_name]? What a coincidence! Our VIP team member {a=[vip_profile_url]}[player_name]{/a} will be honored to hear that."
"[player_name]?好巧,我们的VIP队友{a=[vip_profile_url]}[player_name]{/a}会很高兴的。"
```
Note: The `[]` and `{}` tags should be left intact.
---
#### Before translation
```renpy
old "{icon=icon-fast-forward} Skip"
new "{icon=icon-fast-forward} Skip" <-- translate this line, see below
```
#### After translation
```renpy
old "{icon=icon-fast-forward} Skip"
new "{icon=icon-fast-forward} 跳过"
```
Note: Again, the `new` prefix and the `{icon=icon-fast-forward}` tag should be left intact.
---
#### Before translation
```renpy
# layla @ neutral "Hehe, [player_name], you are a fun one. I'm sure you will enjoy your work as a developer."
layla @ neutral "Hehe, [player_name], you are a fun one. I'm sure you will enjoy your work as a developer."
```
#### After translation
```renpy
# layla @ neutral "Hehe, [player_name], you are a fun one. I'm sure you will enjoy your work as a developer."
layla @ neutral "哈哈,[player_name],你真有趣。我相信你一定会喜欢你的开发者工作的。"
```
Note: `layla @ neutral` and `[player_name]` are left unchanged.
---
#### Before translation
```renpy
# player "Maybe this is all a dream?" nointeract
player "Maybe this is all a dream?" nointeract
```
#### After translation
```renpy
# player "Maybe this is all a dream?" nointeract
player "也许这都是一场梦?" nointeract
```
---
### A Note on How Crowdin Segments a Sentence
Pay attention to how Crowdin segments a line of dialogue wrapped between opening and closing quotes `""`. When we are translating the dialogue, we need to make sure to retain the opening and closing quotes, even if the quotes appear in different segments.
This is the line to be translated:
```renpy
player @ surprised "{b}Full-stack{/b}... What is that? I better take notes so I can learn more about it."
```
Crowdin segments it into three parts like below:
<img width="836" alt="Screen Shot 2022-01-23 at 10 36 43" src="https://user-images.githubusercontent.com/35674052/150693962-d3b091e5-2432-44d0-9d24-195ea7d7aeda.png" />
```renpy
# original
player @ surprised "{b}Full-stack{/b}
# translated, keeping the opening quotes `"`
player @ surprised "{b}全栈{/b}
```
<img width="750" alt="Screen Shot 2022-01-23 at 10 36 49" src="https://user-images.githubusercontent.com/35674052/150693965-15411504-791a-4db3-8b14-bc9177be6375.png" />
```renpy
# original
What is that?
# translated, no quotes on either side
这是什么?
```
<img width="857" alt="Screen Shot 2022-01-23 at 10 36 54" src="https://user-images.githubusercontent.com/35674052/150693969-062e3268-580f-4ad2-97db-cab6240b6095.png" />
```renpy
# original
I better take notes so I can learn more about it."
# translated, keeping the closing quotes `"`
我最好做笔记,这样我可以学习更多东西。"
```
## Rate Translations
Crowdin allows you to rate the existing proposed translations. If you attempt to save a translation, you may see a message indicating that you cannot save a duplicate translation - this means another contributor has proposed that identical translation. If you agree with that translation, click the `+` button to "upvote" the translation.
If you see a translation that is inaccurate or does not provide the same clarity as the original string, click the `-` button to "downvote" the translation.
Crowdin uses these votes to give a score to each proposed translation for a string, which helps the proofreading team determine which translation is the best fit for each string.
## Quality Assurance Checks
We have enabled some quality assurance steps that will verify a translation is as accurate as possible - this helps our proofreaders review proposed translations.
When you attempt to save a translation, you may see a warning message appear with a notification regarding your proposed translation.
![Image - QA Warning Message](https://contribute.freecodecamp.org/images/crowdin/qa-message.png)
This message appears when Crowdin's QA system has identified a potential error in the proposed translation. In this example, we have modified the text of a `<code>` tag and Crowdin has caught that.
> [!WARNING] You have the option to save a translation in spite of errors. If you do, by clicking "Save Anyway", you should also tag a proofreader or project manager and explain why the QA message needs to be ignored in this case.
## Translation Best Practices
Follow these guidelines to ensure our translations are as accurate as possible:
- Do not translate the content within `<code>` tags. These tags indicate text that is found in code and should be left in English.
- Do not add additional content. If you feel a challenge requires changes in the text content or additional information, you should propose the changes through a GitHub issue or a pull request that modifies the English file.
- Do not change the order of content.
If you have any questions, feel free to reach out to us in our [Discord](https://discord.gg/PRyKn3Vbay) and we will be happy to assist you.
@@ -1,200 +0,0 @@
The client/react side of our website is translated into various world languages using [react-i18next](https://react.i18next.com/) and [i18next](https://www.i18next.com/).
> [!NOTE] Curriculum lesson content is [translated separately](./how-to-translate-files.md).
## File Structure
The files for translating the website are located in the `client/i18n` folder. Each language has a folder within that containing JSON files with the translations.
The values in the `translations.json` file contain the majority of the text that appears on the website. The keys are used in the codebase to get the correct text for whatever language is set. This file needs to have the exact same keys in all languages.
The `intro.json` file contains the key-value pairs for the introduction text on the certification pages.
The `motivation.json` files are not required to have the same quotes, compliments, or array length. Just the same JSON structure. These are not translated via Crowdin.
The `trending.json` file contians the titles and links for the trending news articles in the website's footer. These are not translated via Crowdin.
The `meta-tags.json` file contains the information for our website's meta tag information. These are not translated via Crowdin.
## Adding a Language
To add a new language, create a folder with the language name as the title next to the other languages and copy the JSON files from another language into your new folder.
In the `all-langs.js` file, add the language to the `client` array in the first variable. Then, follow the instructions in the comments to add the rest of the necessary variables.
## How to Translate
Translating the `intro.json` and `translations.json` are done through [our translation site](https://translate.freecodecamp.org). View our [translation documentation for that site](/how-to-translate-files.md).
Modifications to the `trending.json`, `meta-tags.json`, and `motivation.json` files should typically only be done by staff.
## Running it Locally
Set the `CLIENT_LOCALE` variable in your `.env` file to the locale you want to build.
> [!NOTE] The value needs to be one of the client languages available in `config/i18n/all-langs.js`
## How to Structure Components
### Functional Component
```js
import { useTranslation } from 'react-i18next';
// in the render method:
const { t } = useTranslation();
// call the "t" function with a key from the JSON file:
<p>{t('key')}</p> // more details below
```
### Class Component
```js
import { withTranslation } from 'react-i18next';
// withTranslation adds the "t" function to props:
const { t } = this.props;
// call the "t" function with a key from the JSON file:
<h1>{t('key')}</h1> // more details below
// export without redux:
export default withTranslation()(Component);
// or with redux:
export default connect(...)(withTranslation()(Component));
```
## Translate Using the "t" Function
### Basic Translation
```js
// in the component:
<p>{t('p1')}</p>
// in the JSON file:
{
"p1": "My paragraph"
}
// output:
<p>My paragraph</p>
```
### With Dynamic Data
```js
// in the component:
const username = 'moT';
<p>{t('welcome', { username: username })}</p>
// in the JSON file:
{
"welcome": "Welcome {{username}}"
}
// output:
<p>Welcome moT</p>
```
The above example passes an object to the `t` function with a `username` variable. The variable will be used in the JSON value where `{{username}}` is.
## Translate with the `Trans` Component
The general rule is to use the "t" function when you can. But there's a `Trans` component for when that isn't enough, usually when you have elements embedded in the text. You can use the `Trans` component with any type of react component.
### Basic Elements Nested
```js
// in the component:
import { Trans } from 'react-i18next'
<p>
<Trans>fcc.greeting</Trans>
</p>
// in the JSON file:
{
"fcc": {
"greeting": "Welcome to <strong>freeCodeCamp</strong>"
}
}
// output:
<p>Welcome to <strong>freeCodeCamp</strong></p>
```
You can place the key inside the component tags like the above example if the text contains "simple" tags with no attributes. `br`, `strong`, `i`, and `p` are the default, but that list can be expanded in the i18n config.
### Complex Elements Nested
Other times, you will want to have certain text inside another element, an anchor tag is a good example:
```js
// in the component:
<p>
<Trans i18nKey='check-forum'>
<a href='https://forum.freecodecamp.org/'>placeholder</a>
</Trans>
</p>
// in the JSON file:
{
"check-forum": "Check out <0>our forum</0>."
}
// output:
<p>Check out <a href='https://forum.freecodecamp.org/'>our forum</a></p>
```
In the above example, the key is set in the attributes of the `Trans` component. The `<0>` and `</0>` in the JSON represent the first child of the component, in this case, the anchor element. If there were more children, they would just count up from there using the same syntax. You can find the children of a component in the react dev tools by inspecting it. `placeholder` is simply there because the linter was complaining at me about an empty `<a>` element.
### With a Variable
```js
// in the component:
const email = 'team@freecodecamp.org';
<p>
<Trans email={email} i18nKey='fcc.email'>
<a href={`mailto:${email}`}>
{{ email }}
</a>
</Trans>
</p>
// in the JSON file:
{
"fcc": {
"email": "Send us an email at: <0>{{email}}</0>"
}
}
// output:
<p>Send us an email at: <a href='mailto:team@freecodecamp.org'>team@freecodecamp.org</a><p>
```
In the above example, the key and a variable are set in the attributes of the `Trans` component. `{{ email }}` needs to be somewhere in the `Trans` component as well, it doesn't matter where.
## Changing Text
To change text on the client side of things, go to the relevant `.json` file, find the key that is being used in the React component, and change the value to the new text you want. You should search the codebase for that key to make sure it isn't being used elsewhere. Or, if it is, that the changes make sense in all places.
## Adding Text
If the text you want to add to the client exists in the relevant `.json` file, use the existing key. Otherwise, create a new key.
The English file is the "source of truth" for all of the `.json` files sharing the same name. If you need to add a new key, add it there. Then, add the key to **all** of the `translations.json` files.
> [!NOTE] Use English text for all languages if the file is translated through Crowdin. The tests will fail if you don't.
It would be nice to keep the keys in the same order across all the files as well. Also, try to put all punctuation, spacing, quotes, etc in the JSON files and not in the components or server files.
> [!NOTE] The underscore (`_`) is a reserved character for keys in the client side files. See [the documentation](https://www.i18next.com/translation-function/plurals) for how they are used.
## Helpful Documentation
- [react-i18next docs](https://react.i18next.com/latest/usetranslation-hook)
- [i18next docs](https://www.i18next.com/translation-function/essentials)
@@ -1,15 +0,0 @@
# How to use Docker on Windows Home
There are a few pitfalls to be avoided when setting up Docker on Windows Home. First of all, you have to use [Docker Toolbox](https://docs.docker.com/toolbox/toolbox_install_windows/) as Administrator. Unfortunately Windows Home does not support Docker for Windows Desktop, so Toolbox must be used instead. It has to be run as Administrator as the installation uses symlinks, which cannot be created otherwise.
Once you've installed the toolbox, run Docker Quickstart Terminal as Administrator. This will create a `default` virtual machine if it does not already exist. Once that has happened, close the terminal and open VirtualBox (again as Administrator). You should be able to see the `default` machine. The site is quite resource-intensive, so stop the virtual machine and raise the settings as much as you can - memory in particular. It has been confirmed to work with 4GB of RAM.
Once you're happy that Docker is working, clone the freeCodeCamp repository to a directory inside `C:\Users`. These directories are shared giving Docker access to the local directories, which it needs during installation.
If you see messages like
```shell
bash: change_volumes_owner.sh: No such file or directory
```
when you `pnpm run docker:init` this is likely the culprit.
@@ -1,730 +0,0 @@
# How to work on coding challenges
Our goal is to develop a fun and clear interactive learning experience.
Designing interactive coding challenges is difficult. It would be much easier to write a lengthy explanation or to create a video tutorial. But for our core curriculum, we're sticking with what works best for most people - a fully interactive, video game-like experience.
We want campers to achieve a flow state. We want them to build momentum and blast through our curriculum with as few snags as possible. We want them to go into the projects with confidence and gain wide exposure to programming concepts.
Note that for Version 7.0 of the freeCodeCamp curriculum, we are moving toward [an entirely project-focused model with a lot more repetition](https://www.freecodecamp.org/news/python-curriculum-is-live/).
Creating these challenges requires immense creativity and attention to detail. There's plenty of help available. You'll have support from a whole team of contributors to whom you can bounce ideas off and demo your challenges.
And as always, feel free to ask questions on the ['Contributors' category on our forum](https://forum.freecodecamp.org/c/contributors) or [the contributors chat room](https://discord.gg/PRyKn3Vbay).
With your help, we can design an interactive coding curriculum that will help millions of people learn to code for years to come.
The content for each challenge is stored in its markdown file. This markdown file is later converted to HTML using our tools to create interactive web pages.
You can find all of freeCodeCamp.org's curricular content in the [`/curriculum/challenges`](https://github.com/freeCodeCamp/freeCodeCamp/tree/main/curriculum/challenges) directory.
## Set up the tooling for the curriculum
Before you work on the curriculum, you would need to set up some tooling to help you test your changes. You can use any option from the below:
- You can [set up freeCodeCamp locally](how-to-setup-freecodecamp-locally.md). This is **highly recommended** for regular/repeat contributions. This setup allows you to work and test your changes.
- Use Gitpod, a free online dev environment. Clicking the button below will start a ready-to-code dev environment for freeCodeCamp in your browser. It only takes a few minutes.
[![Open in Gitpod](https://gitpod.io/button/open-in-gitpod.svg)](https://gitpod.io/#https://github.com/freeCodeCamp/freeCodeCamp)
### How to work on practice projects
The practice projects have some additional tooling to help create new projects and steps. To read more, see [these docs](how-to-work-on-practice-projects.md)
## Challenge Template
````md
---
id: Unique identifier (alphanumerical, MongoDB_id)
title: 'Challenge Title'
challengeType: Integer, defined in `client/utils/challenge-types.js`
videoUrl: 'url of video explanation'
forumTopicId: 12345
---
# --description--
Challenge description text, in markdown
```html
<div>example code</div>
````
# --instructions--
Challenge instruction text, in markdown
# --hints--
Tests to run against user code, in pairs of markdown text and code block test code.
```js
Code for test one
```
If you want dynamic output based on the user's code, --fcc-expected-- and --fcc-actual-- will be replaced with the expected and actual values of the test's assertion. Take care if you have multiple assertions since the first failing assertion will determine the values of --fcc-expected-- and --fcc-actual--.
```js
assert.equal(
'this will replace --fcc-actual--',
'this will replace --fcc-expected--'
);
```
# --notes--
Extra information for a challenge, in markdown
# --seed--
## --before-user-code--
```lang
Code evaluated before the user’s code.
```
## --after-user-code--
```lang
Code evaluated after the user’s code, and just before the tests
```
## --seed-contents--
Boilerplate code to render to the editor. This section should only contain code inside backticks, like the following:
```html
<body>
<p class="main-text">Hello world!</p>
</body>
```
```css
body {
margin: 0;
background-color: #3a3240;
}
.main-text {
color: #aea8d3;
}
```
```js
console.log('freeCodeCamp is awesome!');
```
# --solutions--
Solutions are used for the CI tests to ensure that changes to the hints will still pass as intended
```js
// first solution - the language(s) should match the seed.
```
---
```js
// second solution - so if the seed is written in HTML...
```
---
```js
// third solution etc. - Your solutions should be in HTML.
```
# --assignments--
This will show a checkbox that campers have to check before completing a challenge
---
This will show another checkbox that campers have to check before completing a challenge
# --question--
These fields are currently used for the multiple-choice Python challenges.
## --text--
The question text goes here.
## --answers--
Answer 1
### --feedback--
This will be shown as feedback when campers guess this answer
---
Answer 2
---
More answers
## --video-solution--
The number for the correct answer goes here.
# --fillInTheBlank--
These are for the English curriculum challenges.
## --sentence--
Sentence to be shown with with blanks that campers have to fill in. Example:
`Hello, You _ the new graphic designer, _?`
The two underscores will show up as blanks. The sentence must be surrounded in backticks.
## --blanks--
The solution for the first blank in the sentence above. Example:
`are`
### --feedback--
Feedback shown when campers input the wrong solution for this blank.
---
Solution for the second blank. Example:
`right`
If no feedback is here, a generic "wrong answer" message will be shown.
# --scene--
```json
// # --scene-- can only consist of a single json object
{
// Setup the scene. Properties not marked optional are required.
"setup": {
// Background file to start the scene. A list of scene asset filenames can be found here: https://github.com/freeCodeCamp/cdn/pull/233/files
"background": "company2-center.png",
// Array of all characters that will appear in the scene
"characters": [
{
// Name of character. See list of available characters in scene-assets.tsx
"character": "Maria",
// Where to start the character. Maria will start off screen to the left
"position": { "x": -25, "y": 0, "z": 1 }
},
{
"character": "Tom",
// Tom will start 70% from the left of the screen and 1.5 times regular size
"position": { "x": 70, "y": 0, "z": 1.5 },
// Optional, defaults to 1. Tom will start invisible
"opacity": 0
}
],
"audio": {
// Audio filename
"filename": "1.1-1.mp3",
// Seconds after the scene starts before the audio starts playing
"startTime": 1.3,
// Optional. Timestamp of the audio file where it starts playing from.
"startTimestamp": 0,
// Optional. Timestamp of the audio file where is stops playing. If these two aren't used, the whole audio file will play.
"finishTimestamp": 8.4
},
// Optional, defaults to false. Use this for the long dialogues. It stops the accessibility icon from showing which gives campers the option to show or hide the dialogue text
"alwaysShowDialogue": true
},
// Array of commands that make up the scene
"commands": [
{
// Character that will have an action for this command
"character": "Maria",
// Optional, defaults to previous value. Maria will move to 25% from the left of the screen. The movement takes 0.5 seconds
"position": { "x": 25, "y": 0, "z": 1 },
// When the command will start. Zero seconds after the camper presses play
"startTime": 0
},
{
"character": "Tom",
// Optional, defaults to previous value. Tom will fade into view. The transition take 0.5 seconds. Movement and Opacity transitions take 0.5 seconds
"opacity": 1,
// Tom will fade into view 0.5 seconds into the scene (immediately after Maria finishes moving on screen)
"startTime": 0.5
},
{
"character": "Maria",
// When the command starts: Maria will start saying this line 1.3 seconds into the scene. Note that this is the same time as the audio.startTime above. It doesn't have to match that (maybe there's a pause at the beginning of the audio or something)
"startTime": 1.3,
// The character will stop moving their mouth at the finishTime
"finishTime": 4.95,
"dialogue": {
// Text that will appear if the dialogue is visible
"text": "Hello! You're the new graphic designer, right? I'm Maria, the team lead.",
// Where the dialogue text will be aligned. Can be 'left', 'center', or 'right'
"align": "left"
}
},
{
// background will change to this at 5.4 seconds into the scene
"background": "company2-breakroom.png",
"character": "Tom",
"startTime": 5.4,
"finishTime": 9.4,
"dialogue": {
"text": "Hi, that's right! I'm Tom McKenzie. It's a pleasure to meet you.",
// Tom's text will be aligned to the right since he is on the right side of the screen
"align": "right"
}
},
{
"character": "Tom",
// Tom will fade to 0 opacity
"opacity": 0,
// I like to move characters off screen or fade them 0.5 second after the last talking command
"startTime": 9.9
},
{
"character": "Maria",
// Maria will slide back off the screen to the left
"position": { "x": -25, "y": 0, "z": 1 },
// The animation will stop playing 0.5 seconds after the 'finishTime' of the last command - or 0.5 seconds after 'startTime' if 'finishTime' isn't there.
"startTime": 10.4
}
]
}
```
````
> [!NOTE]
>
> 1. In the above sections, examples of `lang` are:
>
> - `html` - HTML/CSS
> - `js` - JavaScript
> - `jsx` - JSX
## Numbering Challenges
Every challenge needs an `id`. If you don't specify one, then MongoDB will create a new random one when it saves the data; however, we don't want it to do that, since we want the challenge ids to be consistent across different environments (staging, production, lots of different developers, etc.).
To generate a new one in a shell (assuming MongoDB is running separately):
1. Run `mongo` command.
2. Run `ObjectId()` command.
For example:
```bash
$ mongo
MongoDB shell version v3.6.1
connecting to: mongodb://127.0.0.1:27017
MongoDB server version: 3.4.10
...
$ ObjectId()
ObjectId("5a474d78df58bafeb3535d34")
````
The result is a new id, for example, `5a474d78df58bafeb3535d34` above.
Once you have your id, put it into the markdown file as the `id` field at the top, e.g.
```yml
---
id: 5a474d78df58bafeb3535d34
title: Challenge Title
```
## Naming challenges
Naming things is hard. We've made it easier by imposing some constraints.
All challenge titles should be explicit and should follow this pattern:
\[verb\]\[object clause\]
Here are some example challenge names:
- Use Clockwise Notation to Specify the Padding of an Element
- Condense arrays with .reduce
- Use Bracket Notation to Find the First Character in a String
## Challenge descriptions/instructions
Sentences should be clear and concise with minimal jargon. If used, jargon should be immediately defined in plain English.
Keep paragraphs short (around 1-4 sentences). People are more likely to read several short paragraphs than a wall of text.
Use american english, e.g., use `labeled` instead of `labelled`.
Challenge text should use the second person ("you") to help to give it a conversational tone. This way the text and instructions seem to speak directly to the camper working through the challenge. Try to avoid using the first person ("I", "we", "let's", and "us").
Don't use outbound links. These interrupt the flow. Campers should never have to google anything during these challenges. If there are resources you think campers would benefit from, add them to the challenge's Guide-related article.
You can add diagrams if necessary.
Don't use emojis or emoticons in challenges. freeCodeCamp has a global community, and the cultural meaning of an emoji or emoticon may be different around the world. Also, emojis can render differently on different systems.
Proper nouns should use correct capitalization when possible. Below is a list of words as they should appear in the challenges.
- JavaScript (capital letters in "J" and "S" and no abbreviations)
- Node.js
- Although sometimes inaccurate, non-hyphenated forms of 'back end' and 'front end' should be used, as they are more widely used.
### The 2-minute rule
Each challenge should be solvable within 120 seconds by a native English speaker who has completed the challenges leading up to it. This includes the amount of time it takes to read the directions/instructions understand the seeded code, write their code and get all the tests to pass.
If it takes longer than two minutes to complete the challenge, you have two options:
- Simplify the challenge, or
- Split the challenge into two challenges.
The 2-minute rule forces you, the challenge designer, to make your directions concise, your seed code clear, and your tests straightforward.
We track how long it takes for campers to solve challenges and use this information to identify challenges that need to be simplified or split.
### Modularity
Each challenge should teach exactly one concept, and that concept should be apparent from the challenge's name.
We can reinforce previously covered concepts through repetition and variations - for example, introducing h1 elements in one challenge, then h3 elements a few challenges later.
Our goal is to have thousands of 2-minute challenges. These can flow together and reiterate previously-covered concepts.
### Formatting challenge text
Here are specific formatting guidelines for challenge text and examples:
- Language keywords go in `` \` `` backticks. For example, HTML tag names or CSS property names.
- References to code parts (i.e. function, method, or variable names) should be wrapped in `` \` `` backticks. See example below:
```md
Use `parseInt` to convert the variable `realNumber` into an integer.
```
- References to file names and path directories (e.g. `package.json`, `src/components`) should be wrapped in `` \` `` backticks.
- Multi-line code blocks **must be preceded by an empty line**. The next line must start with three backticks followed immediately by one of the [supported languages](https://prismjs.com/#supported-languages). To complete the code block, you must start a new line that only has three backticks and **another empty line**. See example below:
- Whitespace matters in Markdown, so we recommend that you make it visible in your editor.
**Note:** If you are going to use an example code in YAML, use `yaml` instead of `yml` for the language to the right of the backticks.
The following is an example of code:
````md
```{language}
[YOUR CODE HERE]
````
````
- Additional information in the form of a note should be surrounded by blank lines, and formatted: `**Note:** Rest of note text...`
- If multiple notes are needed, then list all of the notes in separate sentences using the format: `**Notes:** First note text. Second note text.`
- Use single quotes where applicable
**Note:** The equivalent _Markdown_ should be used in place of _HTML_ tags.
## Writing tests
Challenges should have the minimum number of tests necessary to verify that a camper understands a concept.
Our goal is to communicate the single point that the challenge is trying to teach, and test that they have understood that point.
Challenge tests can make use of the Node.js and Chai.js assertion libraries. Also, if needed, user-generated code can be accessed in the `code` variable. In addition, the `__helpers` object exposes several functions that simplify the process of writing tests. The available functions are defined in the [curriculum-helpers](https://github.com/freeCodeCamp/curriculum-helpers/blob/main/lib/index.ts) repo.
## Formatting Seed Code
Here are specific formatting guidelines for the challenge seed code:
- Use two spaces to indent
- JavaScript statements end with a semicolon
- Use double quotes where applicable
### Seed Code Comments
We have a [comment dictionary](https://github.com/freeCodeCamp/freeCodeCamp/blob/main/curriculum/dictionaries/english/comments.json) that contains the only comments that can be used within the seed code. The exact case and spacing of the dictionary comment must be used. The comment dictionary should not be expanded without prior discussion with the dev-team.
Comments used should have a space between the comment characters and the comment themselves. In general, comments should be used sparingly. Always consider rewriting a challenge's description or instructions if it could avoid using a seed code comment.
Example of a valid single-line JavaScript comment:
```js
// Only change code below this line
````
Example of a valid CSS comment:
```css
/* Only change code above this line */
```
If a challenge only has a single place where code changes are needed, please use the comments in the following example to instruct the user where changes should be made.
```js
var a = 3;
var b = 17;
var c = 12;
// Only change code below this line
a = a + 12;
b = 9 + b;
c = c + 7;
```
If a challenge has multiple places where the user is expected to change code (i.e. the React challenges)
```jsx
class MyComponent extends React.Component {
constructor(props) {
super(props);
this.state = {
text: 'Hello'
};
// Change code below this line
// Change code above this line
}
handleClick() {
this.setState({
text: 'You clicked!'
});
}
render() {
return (
<div>
{/* Change code below this line */}
<button>Click Me</button>
{/* Change code above this line */}
<h1>{this.state.text}</h1>
</div>
);
}
}
```
### Translation of Seed Code Comments
There are separate comment dictionaries for each language. The [English version of the comment dictionary](https://github.com/freeCodeCamp/freeCodeCamp/blob/main/curriculum/dictionaries/english/comments.json) is the basis for the translations found in the corresponding non-English versions of the files. The non-English version of the Chinese comment dictionary would be located at `/curriculum/dictionaries/chinese/comments.json`. Each dictionary consists of an array of objects with a unique `id` property and a `text` property. Only the `text` should be modified to encompass the translation of the corresponding English comment.
Some comments may contain a word/phrase that should not be translated. For example, variable names or proper library names like "React" should not be translated. See the comment below as an example. The word `myGlobal` should not be translated.
```text
Declare the myGlobal variable below this line
```
> [!NOTE]
>
> We are working on an integration to make it possible to work on i18n for the comment dictionary.
## Hints and Solutions
Each challenge has a `Get a Hint` button, so a user can access any hints/solutions which have been created for the challenge. Curriculum hints/solutions topics are located on [our forum](https://forum.freecodecamp.org/c/guide) under the `Guide` category.
If you find a problem with an existing challenge's hints/solutions topic, you can make suggestions in the [contributors category](https://forum.freecodecamp.org/c/contributors) on the forum. Moderators and users with trust level 3 will review the comments and decide whether or not to include the changes in the corresponding hint/solutions topic.
### Adding new Challenge hints/solutions Topics
Take the following steps when adding a new challenge hints/solutions-related topic.
1. Start by following the same steps for creating a new topic but review the next for creating the title.
2. The title of the topic should start with `freeCodeCamp Challenge Guide:` concatenated with the actual title of the curriculum challenge. For example, if the challenge is named "`Chunky Monkey`", the topic title would be "`freeCodeCamp Challenge Guide: Chunky Monkey`".
3. `camperbot` should be the owner of these topics/posts, so you will need to request an admin to change the ownership of the main post to `camperbot`.
4. Once the new topic is created, a forum topic id is created. It is located at the end of the forum topic URL. This id must be added to the frontmatter of the curriculum challenge file via the normal pull request process for the `Get a Hint` button to link to the topic.
### Guidelines for Content of Hints and Solutions Topics
When proposing a solution for a curriculum challenge-related Guide topic, the full code must be added. This includes all the original seed code plus any changes needed to pass all the challenge tests. The following template should be used when creating new hints/solutions topics:
````md
# Challenge Name Goes Here
---
## Problem Explanation
This summarizes what needs to be done without just restating the challenge description and/or instructions. This is an optional section
#### Relevant Links
- [Link Text](link_url_goes_here)
- [Link Text](link_url_goes_here)
---
## Hints
### Hint 1
Hint goes here
### Hint 2
Hint goes here
---
## Solutions
<details><summary>Solution 1 (Click to Show/Hide)</summary>
```js
function myFunc() {
console.log('Hello World!');
}
````
#### Code Explanation
- Code explanation goes here
- Code explanation goes here
#### Relevant Links
- [Link Text](link_url_goes_here)
- [Link Text](link_url_goes_here)
</details>
````
## Testing Challenges
Before you [create a pull request](how-to-open-a-pull-request.md) for your changes, you need to validate that the changes you have made do not inadvertently cause problems with the challenge.
1. To test all challenges run the below command from the root directory
````
pnpm run test:curriculum
```
2. To test single challenge, you can use it challenge id with following command
```
FCC_CHALLENGE_ID=646cf6cbca98e258da65c979 pnpm run test:curriculum
```
3. You can also test a block or a superblock of challenges with these commands
```
FCC_BLOCK='Basic HTML and HTML5' pnpm run test:curriculum
```
```
FCC_SUPERBLOCK='responsive-web-design' pnpm run test:curriculum
```
You are also able to test challenges by title by performing the following steps:
1. Switch to the `curriculum` directory:
```
cd curriculum
```
2. Run the following for each challenge file for which you have changed (replacing `challenge-title-goes-here` with the full title of the challenge):
```
pnpm run test -- -g challenge-title-goes-here
```
> [!TIP]
> You can set the environment variable `LOCALE` in the `.env` to the language of the challenge(s) you need to test.
>
> The currently accepted values are `english` and `chinese`, with `english` being set by default.
## Proposing a Pull Request (PR)
After you've committed your changes, check here for [how to open a Pull Request](how-to-open-a-pull-request.md).
## Useful Links
Creating and Editing Challenges:
1. [Challenge types](https://github.com/freeCodeCamp/freeCodeCamp/blob/main/client/utils/challenge-types.js#L1-L13) - what the numeric challenge type values mean (enum).
2. [Contributing to FreeCodeCamp - Writing ES6 Challenge Tests](https://www.youtube.com/watch?v=iOdD84OSfAE#t=2h49m55s) - a video following [Ethan Arrowood](https://twitter.com/ArrowoodTech) as he contributes to the old version of the curriculum.
## Helper Scripts
> [!NOTE]
> If you are working with the step-based challenges, refer to the [Work on Practice Projects](how-to-work-on-practice-projects.md) section.
There are a few helper scripts that can be used to manage the challenges in a block. Note that these commands should all be run in the block directory. For example:
```bash
cd curriculum/challenges/english/02-javascript-algorithms-and-data-structures/basic-algorithm-scripting
```
### Add New Challenge
To add a new challenge at the end of a block, call the script:
```bash
pnpm run create-next-challenge
```
This will prompt you for the challenge information and create the challenge file, updating the `meta.json` file with the new challenge information.
### Delete a Challenge
To delete a challenge, call the script:
```bash
pnpm run delete-challenge
```
This will prompt you to select which challenge should be deleted, then delete the file and update the `meta.json` file to remove the challenge from the order.
### Insert a Challenge
To insert a challenge before an existing challenge, call the script:
```bash
pnpm run insert-challenge
```
This will prompt you for the challenge information, then for the challenge to insert before. For example, if your choices are:
```bash
a
b
c
```
If you choose `b`, your new order will be:
```bash
a
new challenge
b
c
```
### Update Challenge Order
If you need to manually re-order the challenges, call the script:
```bash
pnpm run update-challenge-order
```
This will take you through an interactive process to select the order of the challenges.
## Troubleshooting
### Infinite Loop Detected
If you see the following error in the console while previewing a challenge:
```text
Potential infinite loop detected on line <number>...
```
This means that the loop-protect plugin has found a long-running loop or recursive function. If your challenge needs to do that (e.g. it contains an event loop that is supposed to run indefinitely), then you can prevent the plugin from being used in the preview. To do so, add `disableLoopProtectPreview: true` to the block's `meta.json` file.
If your tests are computationally intensive, then you may see this error when they run. If this happens then you can add `disableLoopProtectTests: true` to the block's `meta.json` file.
It's not typically necessary to have both set to true, so only set them as needed.
@@ -1,280 +0,0 @@
# How to Work on Localized Client Webapp
The React-based client web app that powers our learning platform is built using Gatsby. It is translated into various world languages using [react-i18next](https://react.i18next.com/) and [i18next](https://www.i18next.com/).
You can learn more about setting up the client application locally for development by following [our local setup guide here](how-to-setup-freecodecamp-locally.md). By default, the application is available only in English.
Once you have set up the project locally you should be able to follow this documentation to run the client in the language of your choice from the list of available languages.
This could be helpful when you are working on a feature that specifically targets something that involves localization, and requires you to validate for instance a button's label in a different language.
> [!TIP] You do not need to follow this document to translate freeCodeCamp's curriculum or contributing documentation. Read [this guide here](how-to-translate-files.md) instead.
Let's understand how the i18n frameworks and tooling work.
## File Structure
Most of the files for translating the platform are located in the [`client/i18n`](https://github.com/freeCodeCamp/freeCodeCamp/tree/main/client/i18n) folder. Each language has a directory that contains JSON files with the translations.
```bash
config
└── i18n.ts
...
client/i18n
├── configForTests.js
├── config.js
├── locales
│   ├── chinese
│   │   ├── intro.json
│   │   ├── links.json
│   │   ├── meta-tags.json
│   │   ├── motivation.json
│   │   └── translations.json
... ...
│   ├── dothraki
│   │   ├── intro.json
│   │   ├── links.json
│   │   ├── meta-tags.json
│   │   ├── motivation.json
│   │   └── translations.json
... ...
│   ├── english
│   │   ├── intro.json
│   │   ├── links.json
│   │   ├── meta-tags.json
│   │   ├── motivation.json
│   │   └── translations.json
│   └── espanol
│   ├── intro.json
│   ├── links.json
│   ├── meta-tags.json
│   ├── motivation.json
│   └── translations.json
├── locales.test.js
├── schema-validation.js
└── validate-keys.ts
```
Some of these files are translated on our translation platform (Crowdin) and some are translated or created via PRs on GitHub.
**Files translated on our translation platform:**
- The `translations.json` file contains the majority of the text that appears on the user interface elements. The keys are used in the codebase to get the correct text for whatever language is set. This file needs to have the same keys in all languages.
- The `intro.json` file contains the key-value pairs for the introduction text on the certification pages.
If you want to add/update translations for the keys please [read this guide here](how-to-translate-files.md).
**Files NOT translated on our translations platform:**
- The `motivation.json` files are not required to have the same quotes, compliments, or array length. Just the same JSON structure.
- The `meta-tags.json` file contains the information for our website's meta tag information.
Changes to these files are typically done by the staff team. If you see something out of the ordinary we recommend you reach us in the [contributors chat room](https://discord.gg/PRyKn3Vbay).
## Testing the Client App in a World Language
You can test the client app in any language available in the [list of `availableLangs` here](https://github.com/freeCodeCamp/freeCodeCamp/blob/main/shared/config/i18n.ts).
```js
export const availableLangs = {
client: [
Languages.English,
Languages.Espanol,
Languages.Chinese,
Languages.ChineseTraditional,
Languages.Italian,
Languages.Portuguese,
Languages.Ukrainian,
Languages.Japanese,
Languages.German,
Languages.Arabic
],
...
};
```
If you are testing a new language, create a folder with the language name as the title next to the other languages and copy the JSON files from another language into your new folder.
Add the new language to the `Languages` enum and the `client` array at the top of the [`shared/config/i18n.ts`](https://github.com/freeCodeCamp/freeCodeCamp/blob/main/shared/config/i18n.ts) file.
Next, follow the instructions in the comments in the same file to add/update the rest of the variables as needed.
Finally, set the `CLIENT_LOCALE` variable in your `.env` file to the string of the locale you want to build from the `Languages` enum in the above file.
## How to Structure Components
If you are working on a feature or a bug for the client web app, say for example adding new UI items on the settings page, you should follow the guidelines below. They will help you prepare the components for localization into all the supported world languages.
### Functional Component
```js
import { useTranslation } from 'react-i18next';
// in the render method:
const { t } = useTranslation();
// call the "t" function with a key from the JSON file:
<p>{t('key')}</p>; // more details below
```
### Class Component
```js
import { withTranslation } from 'react-i18next';
// withTranslation adds the "t" function to props:
const { t } = this.props;
// call the "t" function with a key from the JSON file:
<h1>{t('key')}</h1> // more details below
// export without redux:
export default withTranslation()(Component);
// or with redux:
export default connect(...)(withTranslation()(Component));
```
## Translate Using the "t" Function
### Basic Translation
```js
// in the component:
<p>{t('p1')}</p>
// in the JSON file:
{
"p1": "My paragraph"
}
// output:
<p>My paragraph</p>
```
### With Dynamic Data
```js
// in the component:
const username = 'moT';
<p>{t('welcome', { username: username })}</p>
// in the JSON file:
{
"welcome": "Welcome {{username}}"
}
// output:
<p>Welcome moT</p>
```
The above example passes an object to the `t` function with a `username` variable. The variable will be used in the JSON value where `{{username}}` is.
## Translate with the `Trans` Component
The general rule is to use the "t" function when you can. But there's a `Trans` component for when that isn't enough, usually when you have elements embedded in the text. You can use the `Trans` component with any type of react component.
### Basic Elements Nested
```js
// in the component:
import { Trans } from 'react-i18next'
<p>
<Trans>fcc.greeting</Trans>
</p>
// in the JSON file:
{
"fcc": {
"greeting": "Welcome to <strong>freeCodeCamp</strong>"
}
}
// output:
<p>Welcome to <strong>freeCodeCamp</strong></p>
```
You can place the key inside the component tags like in the above example if the text contains "simple" tags with no attributes. `br`, `strong`, `i`, and `p` are the default, but that list can be expanded in the i18n config.
### Complex Elements Nested
Other times, you will want to have certain text inside another element, an anchor tag is a good example:
```js
// in the component:
<p>
<Trans i18nKey='check-forum'>
<a href='https://forum.freecodecamp.org/'>placeholder</a>
</Trans>
</p>
// in the JSON file:
{
"check-forum": "Check out <0>our forum</0>."
}
// output:
<p>Check out <a href='https://forum.freecodecamp.org/'>our forum</a></p>
```
In the above example, the key is set in the attributes of the `Trans` component. The `<0>` and `</0>` in the JSON represent the first child of the component, in this case, the anchor element. If there were more children, they would just count up from there using the same syntax. You can find the children of a component in the react dev tools by inspecting it. `placeholder` is simply there because the linter complains about empty `<a>` elements.
### With a Variable
```js
// in the component:
const email = 'team@freecodecamp.org';
<p>
<Trans email={email} i18nKey='fcc.email'>
<a href={`mailto:${email}`}>
{{ email }}
</a>
</Trans>
</p>
// in the JSON file:
{
"fcc": {
"email": "Send us an email at: <0>{{email}}</0>"
}
}
// output:
<p>Send us an email at: <a href='mailto:team@freecodecamp.org'>team@freecodecamp.org</a><p>
```
In the above example, the key and a variable are set in the attributes of the `Trans` component. `{{ email }}` needs to be somewhere in the `Trans` component as well, it doesn't matter where.
## Changing Text
To change text on the client side of things, go to the relevant `.json` file, find the key that is being used in the React component, and change the value to the new text you want. You should search the codebase for that key to make sure it isn't being used elsewhere. Or, if it is, that the changes make sense in all places.
Run `pnpm run clean-and-develop` to apply the change.
## Adding Text
If the text you want to add to the client exists in the relevant `.json` file, use the existing key. Otherwise, create a new key.
The English file is the "source of truth" for all of the `.json` files sharing the same name. If you need to add a new key, add it there. Then, add the key to **all** of the `translations.json` files.
> [!NOTE] Use English text for all languages if the file is translated through Crowdin. The tests will fail if you don't.
It would be nice to keep the keys in the same order across all the files as well. Also, try to put all punctuation, spacing, quotes, etc. in the JSON files and not in the components or server files.
> [!NOTE] The underscore (`_`) is a reserved character for keys in the client-side files. See [the documentation](https://www.i18next.com/translation-function/plurals) for how they are used.
Run `pnpm run clean-and-develop` to apply the change.
## Proposing a Pull Request (PR)
After you've committed your changes, check here for [how to open a Pull Request](how-to-open-a-pull-request.md).
## Helpful Documentation
- [react-i18next docs](https://react.i18next.com/latest/usetranslation-hook)
- [i18next docs](https://www.i18next.com/translation-function/essentials)
@@ -1,152 +0,0 @@
# How to Work on Practice Projects
Our practice projects use a step-based approach to teach concepts to campers. A project will consist of multiple files, which we refer to as **"steps"**. These files are named by the challenge ID, to avoid issues with the translation flow. Unfortunately, this makes it difficult to find the file associated with a specific step.
We've built a challenge editor tool that helps remedy this. This tool allows you to navigate the available projects, and the steps for each project (in order). There's also an embedded code editor you can use to work on the files directly.
## Using the Challenge Editor
These instructions will tell you how to use our challenge editor tool to work on the practice projects.
### Starting the Editor
To start the editor, make sure you are in the root freeCodeCamp directory. Then, run `pnpm run challenge-editor` to start both the client and the API that powers the editor.
The client will run on port `3300`, so you can access it at `http://localhost:3300`. The API runs on port `3200`, to avoid conflicts with the learn client and server. This will allow you to run the freeCodeCamp application at the same time as the editor, so you can test your changes locally.
### Navigating the Editor
The default view will list the available `superblocks` - these are the certifications. Click on the certification link you want to work on.
This will take you to the list of blocks. These are the practice projects. Click on the project link you want to work on.
This will take you to a list of steps for the project. If you are working on an existing step, you can click on the step link to open the editor. If you are adding or removing steps, click the `Use the step tools` link to switch to the step tools for that challenge.
### Editing Steps
When you click on a step, you'll be taken to the editor. This is a basic text editor that offers syntax highlighting.
After you have made your changes, click the `Save Changes` button to save your changes. You will get a browser alert letting you know that your changes are ready to commit. Note that you'll need to use `git` manually to stage and commit your files - this tool will not do that for you.
### Step Tools
When you click the `Use the step tools` link, you'll be taken to the step tools page. This allows you to add or remove steps from the project.
#### Create Next Step
Clicking this button will add a new step at the end of the project. This step will use the previous step's code as the seed.
#### Create Empty Steps
Enter the number of steps you want to add in the input. Then, clicking the button will create many empty steps at the end of the project.
#### Insert Step
Enter the step number that you want to add. Then, click the `Insert Step` button to add the step. The following steps will be re-ordered.
#### Delete Step
Enter the step number you want to delete. Then click the `Delete Step` button to remove that step. This will automatically update the step numbers for the remaining steps.
#### Update Step Titles
You should not have to use this tool unless you've manually deleted or added steps. This tool will reorder the step numbers.
## Using the Scripts Manually
If you want to work on the steps manually, in your local IDE, you can run the step management scripts directly.
The `tools/challenge-helper-scripts` folder contains tools to help facilitate the creation and maintenance of the freeCodeCamp project-based curriculum.
### Create a New Project
Change directory to `tools/challenge-helper-scripts` and run `pnpm run create-project`. This opens up a command line UI that guides you through the process. Once that has finished, there should be a new challenge in the English curriculum that you can use for the first step of the project. For example, if you created a project called `test-project` in the Responsive Web Design certification, it would be in `curriculum/challenges/english/01-responsive-web-design/test-project`.
If you want to create new steps, the following tools simplify that process.
### create-next-step
A one-off script that will automatically add the next step based on the last step in the project. The challenge seed code will use the previous step's challenge seed code.
#### How to Run the Script
1. Change to the directory of the project.
2. Run the following command:
```bash
pnpm run create-next-step
```
### create-empty-steps
A one-off script that automatically adds a specified number of steps. The challenge seed code for all steps created will be empty.
**Note:** This script also runs [update-step-titles](#update-step-titles).
#### How to Run the Script
1. Change to the directory of the project.
2. Run the following command:
```bash
pnpm run create-empty-steps X # where X is the number of steps to create.
```
### insert-step
A one-off script that automatically adds a new step at a specified position, incrementing all subsequent steps (both their titles and in their meta.json). The challenge seed code will use the previous step's challenge seed code with the editable region markers (ERMs) removed.
**Note:** This script also runs [update-step-titles](#update-step-titles).
#### How to Run the Script
1. Change to the directory of the project.
2. Run the following command:
```bash
pnpm run insert-step X # where X is the position to insert the new step.
```
### delete-step
A one-off script that deletes an existing step, decrementing all subsequent steps (both their titles and in their meta.json)
**Note:** This script also runs [update-step-titles](#update-step-titles).
#### How to Run the Script
1. Change to the directory of the project.
2. Run the following command:
```bash
pnpm run delete-step X # where X is the step number to be deleted.
```
### update-step-titles
A one-off script that automatically updates the frontmatter in a project's markdown files so that they are consistent with the project's meta.json. It ensures that each step's title (and dashedName) matches the meta's `challengeOrder`.
#### How to Run the Script
1. Change to the directory of the project.
2. Run the following command:
```bash
pnpm run update-step-titles
```
### repair-meta
One-off script to parse the step names from the project and update the meta.json order to reflect those steps. Useful if you've accidentally lost the changes to the meta.json file when adding/removing steps.
#### How to Run the Script
1. Change to the directory of the project.
2. Run the following command:
```bash
pnpm run repair-meta
```
## Proposing a Pull Request (PR)
After you've committed your changes, check here for [how to open a Pull Request](how-to-open-a-pull-request.md).

Some files were not shown because too many files have changed in this diff Show More