Multi-language support

Configure languages, translations, stable links, search, and RTL.

OINK uses Hugo’s multilingual page model rather than site-specific domain or template assumptions. The included site makes English the primary language, and Simplified Chinese (zh) the second language.

Configure languages

Define the default language and every enabled language in hugo.yaml:

defaultContentLanguage: en

languages:
  en:
    label: English
    locale: en-US
    weight: 1
    title: Product Documentation
    params:
      description: Product guides and reference
  zh:
    label: 简体中文
    locale: zh-CN
    weight: 2
    title: 产品文档
    params:
      description: 产品指南与参考资料
      time_format_default: 2006年1月2日
      time_format_blog: 2006年1月2日

weight controls both language ordering and the selector order. label is shown in that language’s own script. locale supplies standards-friendly language tags for HTML, alternate links, and Open Graph metadata.

Language-specific parameters override global values; other parameters inherit their global value. Put translated menus under each language when labels differ.

Organize translated content

OINK’s starter colocates translations:

content/docs/
├── install.md
└── install.zh.md

The base name makes the files translations of one page. Keep dates, weights, aliases, resources, and route-affecting metadata aligned unless a deliberate language-specific difference is required.

Translate all visible text, including front matter titles and descriptions, summaries, menu labels, tags, image alternatives, callouts, and shortcode arguments. Preserve commands, identifiers, configuration keys, filenames, URLs, and product names.

Sites with very large independently maintained language trees may use Hugo’s language-specific contentDir model instead. Do not mix layouts casually: pick one model, document it, and verify how Hugo associates translations.

Automatic heading IDs depend on the heading text, so translated headings would normally break shared fragment links. Use the English page’s actual rendered ID as an explicit ID in the translation:

## Configure local search
## 配置本地搜索 {#configure-local-search}

Inspect rendered HTML rather than guessing. Inline HTML, punctuation, badges, and shortcodes can affect Hugo’s generated ID. Corresponding pages should have the same heading order and rendered ID list.

Language selector behavior

The selector is generated from Hugo’s configured sites and page translations. It is hidden for a single language. With two or more languages it renders one consistent language button: a direct click advances to the next language by configured weight, while hovering for half a second or focusing the control reveals the complete language menu.

For each target language, the selector links to the current page’s translation when it exists. If it does not exist, it links to that language’s home page instead of producing a dead or falsely translated route. The current language has visible and aria-current state.

SEO and document metadata

Every page emits:

  • the correct HTML lang and dir values;
  • its canonical URL;
  • rel="alternate" links with hreflang for configured languages;
  • Open Graph locale and alternate-locale metadata.

Alternate targets follow the same translated-page-or-language-home fallback as the visible selector. Use a correct production baseURL; subpath deployments are supported and must not be replaced by hardcoded absolute paths in layouts.

Right-to-left languages

Set direction: rtl on an RTL language:

languages:
  ar:
    label: العربية
    locale: ar
    direction: rtl
    weight: 4

The theme loads its committed local Bootstrap RTL artifact and uses logical CSS properties in its own shell. LTR and RTL sites use the same command:

hugo --gc --minify

Consumer sites do not install RTLCSS, PostCSS, or npm. Test actual RTL content, navigation, code, tables, diagrams, and mixed-direction strings rather than assuming stylesheet selection is sufficient.

UI translation bundles

Theme UI strings live in theme/i18n/. OINK includes English, Simplified Chinese, Traditional Chinese, and other inherited bundles. A site can override only the strings it needs by creating its own i18n/<language>.yaml; remaining values fall back to the theme bundle.

During translation work, run:

hugo server --printI18nWarnings

Contribute generally useful translations to the theme. Keep product-specific language in the site bundle.

Search by language

With offlineSearch: true, OINK generates a separate same-origin index for each language. The Simplified Chinese index uses the theme’s CJK fallback. Search results stay within the active language.

Verify that both offline-search-index.en.json and offline-search-index.zh.json are generated, contain the expected pages, and resolve under the deployed baseURL.

Translation checklist

  • Every source page in the supported scope has a .zh.md peer.
  • Front matter identity and route metadata match.
  • Visible prose, UI strings, alternative text, and metadata are translated.
  • Every translated Markdown heading has an explicit stable ID.
  • English and Chinese rendered heading ID lists match.
  • Internal links and fragments resolve in both languages.
  • Navigation, breadcrumbs, previous/next links, and search stay in language.
  • Dates, punctuation, spacing, and technical terminology follow the target language’s editorial conventions.
  • The production build emits correct canonical and alternate metadata.

For Hugo’s underlying model, see Multilingual mode.