Skip to content

Latest commit

 

History

1 Commit

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 

Repository files navigation

ReleaseNotes Guide — write the release notes; the JA/EN articles grow on their own

A methods document with a reference implementation for teams that publish open source on GitHub while also running a bilingual (Japanese/English) community website. Publish one GitHub Release, and WordPress automatically creates a paired Japanese and English article — this guide records how the pipeline is built, the release-note writing convention at its core, and the pitfalls we hit.

日本語版 README はこちら / This is the record of a setup built and operated on www.rumicar.com since August 2026. It shares its philosophy with the sibling project AutoPost-Guide (publish an article → front page → Facebook, all automatic); this one automates the release → bilingual articles leg.

How to read this document: it records one setup that works as of August 2026 — not a guarantee. The reference implementation is the actual file running on rumicar.com, site-specific values included. It is material to read and rewrite for your own site, not something to copy and run.

The problem we wanted to solve

We publish open-source software (a simulator, libraries) on GitHub. Every release came with the same manual chore: writing an announcement article for the website — twice, in Japanese and in English — even though the release notes already existed on GitHub. Fabricating the missing language with machine translation is not acceptable for technical writing.

So the requirements were:

  1. After publishing a GitHub Release, zero human steps until the JA/EN pair of articles exists on the site.
  2. The machine must never fabricate a translation — when no translation exists, degrade honestly instead.
  3. Be polite to the external API (GitHub), at the request rate a small site should hold itself to.

The big picture

Publish a GitHub Release (bilingual notes — see the convention below)
        │
        ▼  wp-cron (twice daily) checks the Releases API (1 request per repo)
        │
        ├─ new release found
        │    ├─ split the body by language (mechanical <details> split)
        │    ├─ convert to HTML via GitHub's /markdown API (same markup GitHub renders)
        │    ├─ create the JA and EN posts, pair them via Polylang
        │    └─ translation present → both published /
        │       absent → EN published, JA saved as draft
        │
        └─ record as processed (skipped next time)

The core convention — bilingual release notes

The heart of this system is not code; it is an agreement about how release notes are written. Write the notes in English, and fold the Japanese translation into a <details> block per section:

## What's New
- Added lap-time overlay to the simulator view.

<details><summary>日本語</summary>

- シミュレータ画面にラップタイム表示を追加しました。

</details>

## Bug Fixes
- Fixed camera jitter on corner entry.

<details><summary>日本語</summary>

- コーナー進入時にカメラが揺れる問題を修正しました。

</details>

Why this format earns its keep:

  • It reads well on GitHub as-is. English readers see English; Japanese readers open the fold. No tooling involved on the reading side.
  • The mechanical split is trivial. English version = full text with the <details> blocks removed. Japanese version = headings + the contents of each <details>. A regular expression plus a heading-wise scan — no translation engine anywhere.
  • Forgetting everything fails safe. A release with no Japanese <details> at all produces a Japanese article containing the English text — as a draft, for a human to translate and publish. That is the "never fabricate a translation" policy, implemented. Note the limit: if only some sections lack their <details>, those parts remain English inside a Japanese article that gets published — the convention includes "if you translate, translate every section".

The split condition is the exact string <details><summary>日本語</summary> (the reference implementation tolerates whitespace variation only). Variants like <summary> 日本語訳</summary> are treated as English. Also, one <details> per section is the rule — a second one in the same section is silently dropped from the Japanese version. Keep the convention narrow and rigid — that is what makes it dependable.

Polite polling, and the safety valves

  • Rate: twice daily, one request per repository (six requests per day for our three repos) — roughly 1/240th of GitHub's unauthenticated limit of 60 requests/hour (= 1,440/day). On a day a release is processed, add two /markdown calls per release; the margin barely moves.
  • Failures stay quiet: an API error changes nothing and simply waits for the next run.
  • First-run valve: enabling the plugin does not backfill articles for historical releases; the first run only records the existing releases (the newest five the API returns) as processed. The valve works per repository, so adding a repository to the watch list later also starts with a record-only pass for that repository.
  • State is one option: records of processed releases (repo@tag keys), per-repository initialization markers (init: keys) and skip records, all in a single option. Delete a repo@tag entry to make the next cron run reprocess that release (an existing article with the same slug is reused — title, body and status rewritten — rather than duplicated).

Pitfalls — hit in operation, or caught by pre-publication review

1. Category lookup falls into Polylang's language filter (measured 2026-08-07)

Cron runs in the default-language context, so get_category_by_slug('news-en') comes back empty — the English category is filtered away, and posts land in the default category. The fix is get_terms( ..., 'lang' => '' ) to bypass the language filter (see the comment in rumicar_relnotes_insert()).

2. Writing post content via $wpdb is a trusted-source-only technique (important)

In a cron context, wp_insert_post passes content through kses, which mangles the HTML GitHub produces (<details>, <summary>, …). The reference implementation therefore writes the post body directly via $wpdb. This is acceptable only because the HTML originates from our own releases in our own repositories, rendered by GitHub's /markdown API. Never reuse this technique for untrusted sources (other people's repositories, form input); in those cases keep kses, or sanitize the output yourself.

3. A release with an empty body would have retried forever (caught pre-publication, fixed)

"Failures retry next time" turns into an infinite retry when the condition is permanent. An empty-body release was exactly that: it would have been reprocessed every 12 hours, forever — a latent path found in code review, not an incident we observed. Permanent conditions must be recorded as skipped, not failed. (Fixed. When you write retry logic, classify each failure as transient or permanent first.)

4. A stopped companion plugin took the whole cron down (caught pre-publication, fixed)

Polylang functions were called unguarded, so deactivating Polylang made the cron run fatal. Guarded with function_exists() — the pairing is skipped, the articles still get created. Code called from cron must survive the morning when a dependency is switched off.

5. The Releases API check reads only the newest five

Each check fetches the five most recent releases per repository. Shipping more than five releases in twelve hours would drop some — and would also mean this polling design is the wrong tool; switch to webhooks at that pace.

6. Where verification actually stands (honestly)

What was verified at installation (2026-08-07) is article generation via dry-run (forced-draft mode): the language split, category resolution and Polylang pairing were exercised there, and pitfall #1 was found in the process. What has not happened yet is a real release flowing through the full pipeline in production — no new release has been published since installation (the first-run valve only recorded the existing ones). The next release will be the first live pass. The pre-publication fixes (pitfalls #3, #4 and others) also postdate the dry-run verification, so they too have not seen a live release yet. By design, published articles then ride the sibling pipeline described in AutoPost-Guide (front-page What's New, Facebook post).

The reference implementation

reference/rumicar-release-notes.php — the mu-plugin running on rumicar.com (current version including the pre-publication fixes; one file, about 340 lines), site-specific values included. What to substitute:

Where rumicar.com value Yours
rumicar_relnotes_repos() three RumiCar-group repos repos to watch
category slugs news / news-en your target categories
language pair ja / en match your Polylang setup
RUMICAR_RELNOTES_AUTOPUBLISH true start with false (drafts only)

Polylang is assumed. With WPML and friends the shape — create two posts, pair them — is the same; translate the function calls.

Disclaimer

  • This document records one setup working as of August 2026 and guarantees nothing. GitHub, WordPress and Polylang change.
  • The reference implementation is not meant to be executed as-is. Read pitfall #2 before adapting it to your site.

License

MIT. Quote, republish, adapt freely. The license covers this document and the reference implementation code; it grants no rights over the release notes or articles the pipeline processes.

About

Publish a GitHub Release, get paired JA/EN WordPress articles automatically — a methods guide with the reference implementation from rumicar.com

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages