Custom heading ids for translation

Toru Kobayashi
2 min readMay 2, 2023

Have you ever read translated documents for OSS libraries? If so, did the links with hash fragment (#id) work as expected? That’s the topic of this post.

I’m maintaining some translations for OSS libraries like React, SWR.

There is a difference between the docs. The links with hash fragment in the Japanese React docs work, but the links in the Japanese SWR docs don’t work even if the English version works as expected. Why?

The reason is that their heading ids are also translated.

For example, SWR has a link like https://swr.vercel.app/docs/revalidation#disable-automatic-revalidations .

#disable-automatic-revalidations is a hash fragment that points to a specific heading on the page.

The heading title is “Disable Automatic Revalidations”. The heading id is converted from the heading title.

Disable Automatic Revalidations -> #disable-automatic-revalidations

The markup is the following.

<h2 class="...">
 Disable Automatic Revalidations
 <span class="..." id="disable-automatic-revalidations"></span>
<a href="#disable-automatic-revalidations" class="subheading-anchor" aria-label="Permalink for this section"></a>
</h2>

That’s great! Let’s see the Japanese version.

The link is https://swr.vercel.app/ja/docs/revalidation#%E8%87%AA%E5%8B%95%E5%86%8D%E6%A4%9C%E8%A8%BC%E3%81%AE%E7%84%A1%E5%8A%B9%E5%8C%96, which is URL encoded and decoded text is “自動再検証の無効化”.

The markup is like this.

<h2 class=...">
自動再検証の無効化
<span class="..." id="自動再検証の無効化">
</span><a href="#自動再検証の無効化" class="subheading-anchor" aria-label="Permalink for this section"></a>
</h2>

The heading ids are also translated because it’s based on the heading title. This don’t work because we don’t modify hash fragments for translated docs, which means we still the links like https://swr.vercel.app/ja/docs/revalidation#disable-automatic-revalidations that doesn’t match with any heading ids.

So we have to keep the heading ids original.

Nextra, a site generator framework that SWR uses, has a feature for it.

So I’ve made a PR to fix this.

This PR adds custom ids to all headings in the docs.

- ## Optimistic UI
+ ## Optimistic UI [#optimistic-ui]

You can see the script that I used to make the PR.

React Docs has the same feature, which is a different syntax, as a remark plugin.

## Using React for an entire subroute of your existing website {/*using-react-for-an-entire-subroute-of-your-existing-website*/}

This is a common pitfall for translation projects, and it’s annoying for users. So I hope this helps some projects have translations.

--

--