JPKCom Simple Lang — Guide & Tips

Display individual WordPress pages in a different language on a per-post basis with JPKCom Simple Lang — installation, language selection, hreflang, Oxygen conditions and practical tips.

JPKCom Simple Lang is a lightweight solution for displaying individual pages or posts in a language other than your site's default. Rather than a full multilingual plugin, it does exactly one job: overriding the WordPress locale per post in the frontend — including the <html lang=""> attribute, hreflang tags and Oxygen Builder conditions.

Guide

Requirements

  • WordPress 6.9 or newer (tested up to WordPress 7.1)
  • PHP 8.3 or newer (with strict typing)
  • At least one additional language pack installed (optional but recommended)
  • Multisite is supported (the plugin is network-enabled)

Installation

  1. Download the latest release ZIP from the GitHub Releases page.
  2. In your admin panel: Plugins → Add New → Upload Plugin, choose the ZIP, Install Now, then Activate.

Alternatively upload the jpkcom-simple-lang folder via FTP to /wp-content/plugins/, or clone it for development:

cd /path/to/wordpress/wp-content/plugins/
git clone https://github.com/JPKCom/jpkcom-simple-lang.git

Install language packs

The selection dropdown only shows installed languages. Add more like this:

  1. Go to Settings → General and open the Site Language dropdown.
  2. Select the language you want (e.g. "Deutsch", "Français") and click Save Changes — WordPress downloads the language pack automatically (5–10 seconds).
  3. Optionally switch the default language back afterwards; the installed pack stays available.

An overview of all 200+ languages is available at translate.wordpress.org.

Usage

  1. Enable post types (optional): Under Settings → Simple Lang you decide which post types get a language selector. Posts and Pages are enabled by default.
  2. Select a language: When editing a post, a Frontend Language Select dropdown appears in the sidebar. Choose an installed language or keep the default.
  3. Link translations (optional): Use the Translation Links meta box to connect related posts in different languages. Links are bidirectional — link Post A to B and both link back; an entire translation group is wired together automatically.
  4. In the frontend: On view, WordPress switches to the selected language automatically. Interface strings (core, theme, plugins), the lang attribute and SEO meta tags (og:locale) are translated; linked posts emit <link rel="alternate" hreflang="XX"> tags in the <head>.

Missing language pack: if the locale switch fails because the pack is not installed, the plugin no longer treats that as a success since version 1.2.9 — previously the page advertised lang="fr" and a matching hreflang while serving the site language. The editor now warns when a post's language pack is missing, and the stored language stays selectable in the dropdown. Up to 1.2.8 it vanished from there, so simply pressing Update silently cleared the post's language without anyone touching the field.

Important: Simple Lang does not translate your content. Titles, post body, custom fields and media captions stay exactly as you write them — writing content in the target language is up to you.

Tips & Tricks

  • Pick the right tool: Simple Lang targets occasional pages in a secondary language (landing pages, docs, legal pages, client presentations). If you need full site translations, language switchers or translation workflows, WPML or Polylang are the better fit.
  • Hreflang with no configuration: Linked, published posts get self-referencing hreflang tags, sorted deterministically and emitted early in the <head> (before most SEO plugins). Since version 1.2.9 an x-default is included too — it points at the version in the site's default language, and is omitted when none of the linked versions carries that language.
  • Hreflang now carries the region (1.2.9): The tags are proper BCP 47, i.e. de-DE, de-AT, pt-BR. Previously de_DE and de_AT both came out as hreflang="de" — two different URLs got the same value, and regional variants are exactly what hreflang is for. WordPress variant suffixes are dropped (de_DE_formalde-DE); two versions resolving to the same tag contribute one entry instead of a contradictory pair. The lang attribute on <html> carries the region as well now (lang="de-DE" instead of lang="de"). Re-check your hreflang markup after updating if monitoring or tests relied on the old two-letter values.
  • Locale format: Valid means whatever WordPress knows through get_available_languages(), plus en_US. Since 1.2.9 that includes variant locales such as de_DE_formal, de_CH_informal or pt_PT_ao90 — the meta box offered them before, but saving dropped them without a word.
  • Oxygen Builder conditions: With Oxygen installed, three conditions are available: "Post Language Is" (a specific language), "Post Has Custom Language" (any custom language set) and "Post Uses Default Language" (site default). Use them to show or hide elements per language.
  • Helper functions for developers: jpkcom_simplelang_get_post_language( $post_id ) returns the set locale (or null), jpkcom_simplelang_get_current_language() the active frontend language. For language markup use jpkcom_simplelang_get_bcp47( 'de_DE_formal' ) — it yields de-DE and is what the plugin itself uses for lang and hreflang since 1.2.9. jpkcom_simplelang_get_language_code( 'de_DE' ) still exists and still returns the bare language code (de); it is the poorer choice for markup, because a bare subtag cannot express the region.
  • Template overrides: Plugin files can be overridden in the child theme ({child-theme}/jpkcom-simple-lang/{file}), parent theme or in MU plugins ({WPMU_PLUGIN_DIR}/jpkcom-simple-lang-overrides/{file}). Extend the search paths via the jpkcom_simplelang_file_paths filter.
  • REST API & data: The language is stored as post meta under the key _jpkcom_simplelang_language and is reachable via the REST API when configured. There is no bulk assignment — use update_post_meta() with the same key for that.
  • Deactivation is safe: After disabling, posts simply display in the default language; the meta data remains and applies immediately if you reactivate.
  • Performance: One meta query per post, a single locale switch per request, no extra tables, no frontend JS/CSS.
  • Updates & security: The plugin updates securely via GitHub with SHA256 checksum verification; a preferred match against the manifest's download_url prevents a tampered manifest from bypassing the checksum gate.

Further reading