Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 13 additions & 35 deletions .github/workflows/language-check.yml
Original file line number Diff line number Diff line change
@@ -1,46 +1,24 @@
name: Check README Suffixes
name: Validate README Navigation

on:
pull_request:
paths:
- 'README-*'
- 'README*.md'
- 'scripts/validate_readmes.rb'
- '.github/workflows/language-check.yml'

jobs:
check-readme-suffixes:
validate-readmes:
runs-on: ubuntu-latest

steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Checkout repository
uses: actions/checkout@v4

- name: Set up Ruby
uses: ruby/setup-ruby@v1
with:
ruby-version: 3.0
- name: Set up Ruby
uses: ruby/setup-ruby@v1
with:
ruby-version: '3.3'

- name: Install dependencies
run: |
gem install nokogiri

- name: Check README suffixes
run: |
# Scrape ISO 639 language codes from the Wiki page
wget -qO- https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes | \
nokogiri -e 'puts $_.css(".wikitable td:nth-child(2)").map(&:text)' | \
sed -nr '/^.{0,2}$/p' | # Grab only two letter values
tr '[:lower:]' '[:upper:]' > iso639.txt # Covert letters to uppercase

# Get list of README file names
readme_suffixes=$(ls README-* | sed 's/README-//g; s/.md//g')

# Check if README suffixes are valid ISO 639 language codes
for suffix in $readme_suffixes; do
if ! grep -qw "$suffix" iso639.txt; then
echo "Error: Invalid README suffix found: $suffix"
exit 1
fi
done

echo "All README suffixes are valid ISO 639 language codes."

# Add more steps for your existing workflow, e.g., running tests or other checks
- name: Validate README links and translation index
run: ruby scripts/validate_readmes.rb
5 changes: 1 addition & 4 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,7 @@ jobs:
continue-on-error: true
run: |
gem install awesome_bot
awesome_bot \
-f README*.md \
--allow 302,429 \
--white-list https://www.firsttimersonly.com/,https://github.com/github,https://creativecommons.org/licenses/by-sa/4.0/,https://github.com/kentcdodds
awesome_bot -f README*.md --allow 302,429 --white-list https://www.firsttimersonly.com/,https://github.com/github,https://creativecommons.org/licenses/by-sa/4.0/,https://github.com/kentcdodds

# - name: Run Danger
# uses: MeilCli/danger-action@v5
Expand Down
9 changes: 7 additions & 2 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -164,16 +164,21 @@ The main `README.md` file is written in English. That file will be the template

This repository is about contributing to open source and generally, translation is important to reach diverse audiences. It is recommended that you provide language-specific resources links instead of the English-resource links.

The non-English README files are named `README-XX.md`, where `xx` is the
The non-English README files are named `README-XX.md`, where `XX` usually
follows the
[two letter language code](https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes)
for the language.
for the language. Some existing translations use established variants such as
`pt-BR`, so follow the naming convention already used in the repository when
you update or add localized files.

You can contribute to the non-English README files by taking links that are in the English README but are not in the language of your choosing. When making a pull request with these changes, please tag someone who can verify your language contribution by adding `@` in front of their GitHub username to the pull request.

If your language does not exist yet, feel free to start it yourself. If you decide to do this, please add more than just the title. If you do not have the time to create one, feel free to
[create an issue](https://github.com/freeCodeCamp/how-to-contribute-to-open-source/issues/new/choose)
to crowdsource help.

When you add a new translation, also add it to the language list at the top of the main `README.md` so contributors can discover it easily. The README workflow validates that README-to-README links point to existing files and that every translation is represented in the main language picker.

### Adding to the Project File

We have a
Expand Down
50 changes: 25 additions & 25 deletions PROJECTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,47 +4,47 @@ This file contains a list of projects and organizations that are friendly to
contributions, along with quick links to relevant documents you should reference
before contributing.

- `[Babel](https://github.com/babel/babel)` (project)
- [Babel](https://github.com/babel/babel) (project)
- [Contributing Guide](https://github.com/babel/babel/blob/master/CONTRIBUTING.md)
- Issue labels:
- [Good First Issue](https://github.com/babel/babel/issues?q=is%3Aissue+is%3Aopen+label%3A%22good+first+issue%22)
- `[BeeWare](https://beeware.org/)` (org)
- [BeeWare](https://beeware.org/) (org)
- [Contributing Guide](https://beeware.org/contributing/how/first-time/)
- [Batavia](https://github.com/beeware/batavia) (project)
- Issue labels:
- [first-timers-only](https://github.com/beeware/batavia/issues?q=is%3Aopen+is%3Aissue+label%3Afirst-timers-only)
- [VOC](https://github.com/beeware/voc) (project)
- Issue labels:
- [first-timers-only](https://github.com/beeware/voc/issues?q=is%3Aopen+is%3Aissue+label%3Afirst-timers-only)
- `[DITA Open Toolkit](https://www.dita-ot.org/)`
- [DITA Open Toolkit](https://www.dita-ot.org/)
- [Contributing Guide](https://www.dita-ot.org/contributing)
- Issue label:
- [good first issue](https://github.com/dita-ot/dita-ot/issues?utf8=%E2%9C%93&q=is%3Aissue+is%3Aopen+label%3A%22good+first+issue%22)
- `[Docker](https://github.com/docker)` (project)
- [Docker](https://github.com/docker) (project)
- [Contributing Guide](https://docs.docker.com/opensource/)
- Issue labels:
- [Open Issue](https://github.com/search?q=org%3Adocker+is%3Aissue+is%3Aopen)
- [exp/beginner](https://github.com/docker/docker/issues?q=is%3Aopen+is%3Aissue+label%3Aexp%2Fbeginner+sort%3Aupdated-desc)
- `[freeCodeCamp.org](https://www.freecodecamp.org/)` (org)
- [freeCodeCamp.org](https://www.freecodecamp.org/) (org)
- [freeCodeCamp.org](https://github.com/freeCodeCamp/freeCodeCamp/) (project)
- [Contributing guide](https://contribute.freecodecamp.org)
- Issue labels:
- [first-timers-only](https://github.com/FreeCodeCamp/FreeCodeCamp/issues?q=is%3Aopen+is%3Aissue+label%3Afirst-timers-only)
- [help wanted](https://github.com/freeCodeCamp/freeCodeCamp/issues?q=is%3Aopen+is%3Aissue+label%3A%22help+wanted%22)
- `[GitLab](https://gitlab.com/gitlab-org)` (org)
- [GitLab](https://gitlab.com/gitlab-org) (org)
- [Contributing Guide](https://gitlab.com/gitlab-org/gitlab-ce/blob/master/CONTRIBUTING.md)
- [Development Guides](https://docs.gitlab.com/ce/development/README.html)
- [Development Kit](https://gitlab.com/gitlab-org/gitlab-development-kit)
- Issue labels:
- [1st contribution](https://gitlab.com/gitlab-org/gitlab-ce/issues?scope=all&utf8=%E2%9C%93&state=opened&label_name[]=1st%20contribution)
- `[GNOME](https://www.gnome.org/)` (org)
- [GNOME](https://www.gnome.org/) (org)
- [Contributing Guide](https://wiki.gnome.org/Newcomers)
- Great big example application (org)
- [Great-big-example-application](https://github.com/dancancro/great-big-angular2-example) (project)
- [Contributing Guide](https://github.com/dancancro/great-big-example-application/projects/1)
- `[Hoa](https://hoa-project.net)` (project)
- [Hoa](https://hoa-project.net) (project)
- [Contributing Guide](https://hoa-project.net/En/Literature/Contributor/Guide.html)
- `[Hoodiehq](http://hood.ie/)` (org)
- [Hoodiehq](http://hood.ie/) (org)
- [Camp](https://github.com/hoodiehq/camp) (project)
- Issue labels:
- [first-timers-only](https://github.com/hoodiehq/camp/labels/first-timers-only)
Expand All @@ -55,77 +55,77 @@ before contributing.
- [first-timers-only](https://github.com/hoodiehq/hoodie/labels/first-timers-only)
- [help wanted](https://github.com/hoodiehq/hoodie/labels/help%20wanted)
- [starter](https://github.com/hoodiehq/hoodie/labels/starter)
- `[Metamaps](https://metamaps.cc/)` (org)
- [Metamaps](https://metamaps.cc/) (org)
- [Metamaps](https://github.com/metamaps/metamaps) (project)
- [Contribution Guide](https://github.com/metamaps/metamaps/blob/develop/doc/CONTRIBUTING.md)
- `nteract` (org)
- nteract (org)
- [nteract](https://github.com/nteract/nteract) (project)
- [Contributing Guide](https://github.com/nteract/nteract/blob/master/CONTRIBUTING.md)
- Issue labels:
- [new-contributor-friendly](https://github.com/nteract/nteract/issues?q=is%3Aissue+label%3Anew-contributor-friendly+is%3Aopen)
- [mentoring-available](https://github.com/nteract/nteract/issues?q=is%3Aissue+is%3Aopen+label%3Amentoring-available)
- `Public Lab` (org)
- Public Lab (org)
- [Plots2](https://github.com/publiclab/plots2) (project)
- [Contributing guide](https://github.com/publiclab/plots2/blob/master/CONTRIBUTING.md)
- Issue labels:
- [first-timers-only](https://github.com/publiclab/plots2/issues?q=is%3Aissue+is%3Aopen+label%3Afirst-timers-only)
- [help-wanted](https://github.com/publiclab/plots2/issues?q=is%3Aissue+is%3Aopen+label%3Ahelp-wanted)
- [fto-candidate](https://github.com/publiclab/plots2/issues?q=is%3Aissue+is%3Aopen+label%3Afto-candidate)
- `React` (org)
- React (org)
- [React](https://github.com/facebook/react) (project)
- [Contributing Guide](https://reactjs.org/docs/how-to-contribute.html)
- Issue labels:
- [good first issue](https://github.com/facebook/react/issues?page=1&q=is%3Aissue+is%3Aopen)
- `Read the Docs` (org)
- Read the Docs (org)
- [Read the Docs](http://docs.readthedocs.io/en/latest/index.html) (site)
- Issue labels:
- [Good First Bug](https://github.com/rtfd/readthedocs.org/issues?q=is%3Aopen+is%3Aissue+label%3A%22Good+First+Bug%22)
- `Redfin` (org)
- Redfin (org)
- [react-server](https://github.com/redfin/react-server) (project)
- [Contributing Guide](https://github.com/redfin/react-server/blob/master/CONTRIBUTING.md)
- Issue labels:
- [good first contribution](https://github.com/redfin/react-server/labels/good%20first%20contribution)
- `Servo` (org)
- Servo (org)
- [Servo](https://starters.servo.org/) (project)
- [Contributing guide](https://github.com/servo/servo/blob/master/CONTRIBUTING.md)
- Issue labels:
- [Easy](https://github.com/servo/servo/issues?q=is%3Aissue+is%3Aopen+label%3AE-easy)
- `[Sympy](https://github.com/sympy/sympy)` (project)
- [Sympy](https://github.com/sympy/sympy) (project)
- [Dev Wiki](https://github.com/sympy/sympy/wiki#development)
- [Work Flow](https://github.com/sympy/sympy/wiki/Development-workflow)
- [Contributing Guide](https://github.com/sympy/sympy/wiki/Introduction-to-contributing)
- Issue labels:
- [Easy to fix](https://github.com/sympy/sympy/issues?q=is%3Aissue+is%3Aopen+label%3A%22Easy+to+Fix%22)
- `TEAMMATES` (org)
- TEAMMATES (org)
- [TEAMMATES](https://github.com/TEAMMATES/teammates) (project)
- [Contributing Guide](https://github.com/TEAMMATES/teammates/blob/master/docs/CONTRIBUTING.md)
- Issue labels:
- [d.FirstTimers](https://github.com/TEAMMATES/teammates/issues?q=is%3Aopen+is%3Aissue+label%3Ad.FirstTimers)
- [d.Contributors](https://github.com/TEAMMATES/teammates/issues?q=is%3Aopen+is%3Aissue+label%3Ad.Contributors)
- `Zulip` (org)
- Zulip (org)
- [Zulip](https://github.com/zulip) (project)
- [Contributing Guide](https://github.com/zulip/zulip/blob/master/CONTRIBUTING.md)
- Issue labels:
- [Good First Issue](https://github.com/zulip/zulip/issues?q=is%3Aissue+is%3Aopen+label%3A%22good+first+issue%22)
- [Help Wanted](https://github.com/zulip/zulip/issues?q=is%3Aissue+is%3Aopen+label%3A%22help+wanted%22)
- `[Rust](https://github.com/rust-lang/rust)` (project)
- [Rust](https://github.com/rust-lang/rust) (project)
- [Contributing Guide](https://github.com/rust-lang/rust/blob/master/CONTRIBUTING.md)
- Issue labels:
- [E-easy](https://github.com/rust-lang/rust/issues?q=is%3Aissue+is%3Aopen+label%3AE-easy)
- `[Test Kitchen](https://github.com/test-kitchen/test-kitchen)` (project)
- [Test Kitchen](https://github.com/test-kitchen/test-kitchen) (project)
- [Contributing Guide](https://github.com/test-kitchen/test-kitchen/blob/master/CONTRIBUTING.md)
- Issue labels:
- [*](https://github.com/test-kitchen/test-kitchen/issues?q=is%3Aopen+is%3Aissue+label%3A%E2%AD%90%EF%B8%8F)
- `Django` (Framework)
- Django (Framework)
- [Contributing Guide](https://github.com/django/django)
- `[tsParticles](https://github.com/matteobruni/tsparticles)` (Library)
- [tsParticles](https://github.com/matteobruni/tsparticles) (Library)
- [Contributing Guide](https://github.com/matteobruni/tsparticles/blob/master/CONTRIBUTING.md)
- Issue labels:
- [Good First Issue](https://github.com/matteobruni/tsparticles/labels/good%20first%20issue)
- [Help Wanted](https://github.com/matteobruni/tsparticles/labels/help%20wanted)
- `[Jenkins](https://github.com/jenkinsci/jenkins)` (Project)
- [Jenkins](https://github.com/jenkinsci/jenkins) (Project)
- [Contributing Guide](https://wiki.jenkins.io/display/JENKINS/Beginners+Guide+to+Contributing)
- `[ifme](https://github.com/ifmeorg/ifme)` (Project)
- [ifme](https://github.com/ifmeorg/ifme) (Project)
- [Contributing Guide](https://github.com/ifmeorg/ifme/blob/main/CONTRIBUTING.md)
- Issue labels:
- [first-timers-only](https://github.com/ifmeorg/ifme/issues?q=is%3Aopen+is%3Aissue+label%3Afirst-timers-only)
Expand Down
2 changes: 1 addition & 1 deletion README-VI.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
<li><a href="./README-FR.md"> Français </a></li>
<li><a href="./README-KO.md"> 한국어 </a></li>
<li><a href="./README-JA.md"> 日本語 </a></li>
<li><a href="./README-VN.md"> Tiếng Việt </a></li>
<li><a href="./README-VI.md"> Tiếng Việt </a></li>
</ul>
</details>
<!-- Do not translate this -->
Expand Down
12 changes: 12 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,20 @@
<li><a href="./README-FA.md"> فارسی </a></li>
<li><a href="./README-UR.md">اردو </a></li>
<li><a href="./README-AR.md">اللغة العربية </a></li>
<li><a href="./README-BG.md"> български </a></li>
<li><a href="./README-GU.md"> ગુજરાતી </a></li>
<li><a href="./README-HY.md"> Armenian </a></li>
<li><a href="./README-MS.md"> Bahasa Melayu </a></li>
<li><a href="./README-NL.md"> Nederlands </a></li>
<li><a href="./README-PL.md"> Polski </a></li>
<li><a href="./README-SA.md"> संस्कृतम् </a></li>
<li><a href="./README-SI.md"> සිංහල </a></li>
<li><a href="./README-SL.md"> Slovenščina </a></li>
<li><a href="./README-TA.md">தமிழ்</a></li>
<li><a href="./README-TE.md"> తెలుగు </a></li>
<li><a href="./README-NE.md">नेपाली</a></li>
<li><a href="./README-UK.md"> Українська </a></li>
<li><a href="./README-VI.md"> Tiếng Việt </a></li>
<li><a href="./README-ML.md">മലയാളം</a></li>
</ul>
</details>
Expand Down
38 changes: 38 additions & 0 deletions scripts/validate_readmes.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
#!/usr/bin/env ruby
# frozen_string_literal: true

root = File.expand_path("..", __dir__)
readme_paths = Dir.glob(File.join(root, "README*.md")).sort
readme_files = readme_paths.map { |path| File.basename(path) }
translation_files = readme_files.grep(/^README-.+\.md$/).sort
readme_link_pattern = /href="\.\/(README[^"]+\.md)"/

errors = []

readme_paths.each do |path|
basename = File.basename(path)
content = File.read(path)
linked_files = content.scan(readme_link_pattern).flatten
missing_targets = linked_files.reject { |target| readme_files.include?(target) }.uniq

next if missing_targets.empty?

errors << "#{basename} links to missing README files: #{missing_targets.join(', ')}"
end

main_readme_path = File.join(root, "README.md")
main_readme_links = File.read(main_readme_path).scan(readme_link_pattern).flatten.uniq
missing_from_main = translation_files.reject { |target| main_readme_links.include?(target) }

unless missing_from_main.empty?
errors << "README.md is missing language-picker entries for: #{missing_from_main.join(', ')}"
end

if errors.empty?
puts "README validation passed for #{readme_files.length} files."
exit 0
end

warn "README validation failed:"
errors.each { |error| warn "- #{error}" }
exit 1