Stub Generation for p5.js Translations
I am a developer from Nepal who loves playing with tech.
Search for a command to run...
I am a developer from Nepal who loves playing with tech.
No comments yet. Be the first to comment.
The p5.js Web Editor is an intuitive, browser-based platform for creative coding with JavaScript. It allows artists, designers, and educators to dive into coding visually, without needing to set up any development environment. But what if you're a de...

Before starting out, let me quickly share what we're building today. Open codesandbox.io or visit gsap-svg-path-animation.netlify.app. Seems interesting, let's start. Introduction You might have visited some websites where when you scroll, things mov...

Build a countdown social media og:image using nextjs and vercel/og

In the fast-paced world of web development, creating an engaging and seamless user experience is important. One effective way to achieve this is by implementing a loading animation on your website. In this tutorial, we'll explore the step-by-step pro...

Have you ever translated something, only to find out later that the original text changed while you were working? Or worse — that a whole new page existed and nobody told you?
For that, I built stub file generation. I'm writing this blog today to explain more.
This summer, I'm working with the Processing Foundation as a Google Summer of Code contributor. My project is called Continued Development of Translation Tracker and my mentor is Divyansh Srivastava, who built the original tracker during GSoC 2025.
Quick background: the p5.js reference documentation lives in five languages — English as the source, plus Spanish (es), Hindi (hi), Korean (ko), and Simplified Chinese (zh-Hans). All of it is maintained by human volunteers.
Divyansh's tracker from last year already solves one problem: when an English page changes, it opens a GitHub issue telling translators what went stale.
But there was a second problem nobody was handling: what about pages that were never translated at all? When a new function is added in p5.js, a new English content page appears and... that's it. No Spanish file. No Hindi file. Simple, no idea and no signal. Translators had to notice missing files by comparing directory trees manually.
So for the last couple of weeks, I built stub file generation. Here's the PR if you want to jump straight to code: #1473
A stub is scaffolding, not a translation.
I want to be super clear here because the p5.js community cares deeply about this: the tool does not translate anything. A machine can't decide how "friendly" should sound in Korean, and it shouldn't try. Humans translate. The tool just removes the boring setup work.
When the tracker finds an English reference page with no counterpart in a language folder, it generates a placeholder MDX file that contains:
The essential English frontmatter only — title, module, submodule, file, description. Not the full API dump, just enough to orient a translator.
A needsTranslation: true flag, so nothing ever mistakes it for finished work
A short placeholder body + an HTML comment linking back to the English source file
The stub lands in the exact mirror location — example/en/foo.mdx becomes example/es/foo.mdx and so on.
The flow looks like this:
Scan the English reference pages (triggered by a push that touches src/content/**/en/**, or manually)
Find missing translations — findMissingTranslations() checks each language folder for a matching file
Generate stubs — generateStubFromEnglish() builds the placeholder from the English source (MDX only for now, .yaml files are skipped — more on that below 😅)
Open one PR per language
Why one PR per language instead of one giant PR? Because the Spanish stewards should review the Spanish batch, and the Hindi stewards should review theirs. A single (or should I say a mega) PR touching four languages at once is hard to review.
And nothing auto-merges... like ever. Maintainers and language stewards review every stub PR. The job of my script is to propose; humans decide.
Note: There's also a cap —
STUB_MAX_FILESlimits stubs to 50 per language per run (per language, not global!). Without this, a full scan of the historical backlog would flood the repo with hundreds of files in one go.
The stub generation runs as its own GitHub Action: .github/workflows/translation-stubs.yml. It runs with GENERATE_STUBS=true, completely separate from the issue-tracking workflow (translation-sync.yml). The two modes are mutually exclusive — when stub mode is on, the issue logic doesn't run at all. We can simply say: different jobs, different outcomes, no interference.
You can also trigger it manually with workflow_dispatch, which supports two inputs: full_scan (scan everything, not just the latest changes) and languages (target specific languages only).
For local development, I added a dry-run command:
npm run test:stubs
This previews everything into a gitignored stub-preview/ folder . It's best if we want to test locally and don't touch src/content/ files locally. I used this frequently to test.
While building this, the tracker's single index.js was getting way too big. After discussing with Divyansh, I split it into focused modules:
| File | What it does |
|---|---|
index.js |
Entry point and orchestration |
constants.js |
Supported languages, content types, stub frontmatter keys |
utils.js |
Path helpers, frontmatter parsing, file scanning |
github-tracker.js |
GitHub API client (issues, diffs, stub PR creation) |
workflows.js |
Translation status checks and stub generation logic |
Much easier to navigate now, and future features (auto-close, dashboard) have obvious homes.
I deleted my local repo. Yes, really. Mid-project. Thankfully like 50% of changes were pushed to my fork, so "disaster recovery" was relatively less painful (I didn't crash :)
Divyansh's review caught a bug. My generateStubFromEnglish assumed MDX frontmatter everywhere, but the scanners also pick up .yaml files. Fine today (stubs are reference-only), but the moment we extend to tutorials and examples, one YAML file would throw and kill the entire batch because I had no per-file try/catch. The fix was to skip .yaml explicitly for now, and wrap each file's generation so one failure becomes a logged warning instead of a dead run.
Per the tracking issue (#1404), coming up:
Auto-close tracker issues when a translation PR merges
A progress dashboard — translation-status.json with per-language coverage, rendered as markdown progress bars
Expanding stub coverage to tutorials/ and examples/ (this is where that YAML handling becomes essential)
The whole point of this script is simple: remove the friction of finding missing files, creating placeholders, opening PRs. It does keep humans in the loop while doing so.
If you speak Spanish, Hindi, Korean, or Chinese and want to contribute to p5.js translations, the stub PRs must make it easier than ever to jump in.