Plugin Name: JPKCom Simple Lang
Plugin URI: https://github.com/JPKCom/jpkcom-simple-lang
Description: Simple language selection for frontend pages.
Version: 1.1.1
Author: Jean Pierre Kolb jpk@jpkc.com
Author URI: https://www.jpkc.com/
Contributors: JPKCom
Tags: Language, Lang, Locale, Multilingual, Translation, i18n, Hreflang, SEO, Oxygen Builder
Requires at least: 6.8
Tested up to: 6.9
Requires PHP: 8.3
Network: true
Stable tag: 1.1.1
License: GPL-2.0+
License URI: http://www.gnu.org/licenses/gpl-2.0.txt
Text Domain: jpkcom-simple-lang
Domain Path: /languages
A plugin to provide per-post language selection that overrides the site-wide language setting in the frontend.
JPKCom Simple Lang is a lightweight solution for displaying individual pages or posts in different languages than your site's default language. Unlike full-fledged multilingual plugins, Simple Lang focuses on a single task: allowing you to override the WordPress locale on a per-post basis for frontend display.
This is particularly useful for sites that are primarily in one language but occasionally need to display specific pages in another language, without the complexity and overhead of managing multiple translations for every piece of content.
- Per-Post Language Selection: Choose a different language for individual posts, pages, or custom post types
- WordPress Core Languages: Uses WordPress's built-in language system - no additional translation files needed
- Post Type Control: Enable or disable language selection per post type via settings page
- Frontend Locale Override: Automatically switches locale in frontend for proper translation support
- HTML Lang Attribute: Updates the
<html lang="">attribute to match the selected language - Translation Links & Hreflang: Link related posts in different languages and automatically generate SEO-friendly hreflang meta tags
- SEO Plugin Compatible: SEO plugins (Yoast, Rank Math, etc.) automatically detect the locale change and output correct
og:localemeta tags - Plugin Compatibility: Other plugins respect the locale change for their frontend output
- Oxygen Builder Support: Provides conditional logic for Oxygen Builder based on selected language
- Clean Admin UI: Simple dropdown in the post editor sidebar
- Default Fallback: Posts without a custom language use the site's default language
- Multisite Compatible: Works seamlessly with WordPress multisite installations
- Developer-Friendly: Template override system and helper functions for custom development
- Automatic Updates: Secure GitHub-based plugin updates with SHA256 checksum verification
- Modern PHP: Built with PHP 8.3+ strict typing for performance and reliability
- Bilingual Content: Display specific pages in a secondary language while keeping your site primarily in one language
- International Landing Pages: Create marketing pages in different languages without managing full site translations
- Documentation: Provide documentation pages in multiple languages on demand
- Legal Pages: Display terms of service or privacy policies in required languages
- Client Presentations: Create project presentations in your client's language
- Oxygen Builder: Show/hide specific Oxygen elements based on page language
- Admin Settings (
includes/admin-settings.php) - Settings page under Settings → Simple Lang for post type activation - Meta Box (
includes/meta-box.php) - Language selection dropdown in post editor sidebar - Frontend Language (
includes/frontend-language.php) - Locale switching and HTML attribute override logic - Hreflang Translations (
includes/hreflang-translations.php) - Translation links meta box and automatic hreflang tag generation - Oxygen Conditions (
includes/oxygen-conditions.php) - Conditional logic integration for Oxygen Builder - Translation Files (
languages/) - Plugin interface translations (German included) - Automatic Updates (
includes/class-plugin-updater.php) - GitHub-based update system with SHA256 checksum verification
API Documentation: Complete PHPDoc-generated API documentation is available at: https://jpkcom.github.io/jpkcom-simple-lang/docs/
The documentation includes detailed information about all functions, classes, hooks, and filters available in the plugin.
- In the Admin: When editing a post, you'll see a "Frontend Language Select" dropdown in the sidebar
- Select a Language: Choose from any WordPress language installed on your system, or use the default
- Link Translations (Optional): Use the "Translation Links" meta box to link related posts in different languages
- In the Frontend: When visitors view that post, WordPress automatically switches to the selected language
- Locale Override: The entire page renders with translations from the selected language, including:
- WordPress core strings (dates, buttons, messages)
- Theme translations
- Plugin translations that respect the current locale
- HTML
langattribute - SEO plugin meta tags (og:locale via
get_locale()) - Hreflang link tags (if translation links are configured)
Simple Lang includes a powerful translation linking system that helps search engines understand the relationship between your content in different languages.
- Link Related Content: In the post editor sidebar, you'll find a "Translation Links" meta box
- Multi-Select Interface: Posts are grouped by language for easy selection
- Bidirectional Linking: When you link Post A to Post B, both posts automatically link to each other
- Complete Translation Sets: If you link Post 1 (DE) to Post 2 (EN) and Post 3 (FR), all three posts are automatically linked together
- Automatic Hreflang Generation: Linked posts automatically get
<link rel="alternate" hreflang="XX">tags in the HTML<head>
You have three versions of the same page:
- Post 1: German version (de_DE)
- Post 2: English version (en_US)
- Post 3: French version (fr_FR)
Steps:
- Edit Post 1 (German)
- In "Translation Links" select Post 2 and Post 3
- Save Post 1
Result:
- Post 1 now links to Posts 2 & 3
- Post 2 automatically links to Posts 1 & 3
- Post 3 automatically links to Posts 1 & 2
- All three posts display proper hreflang tags
Generated HTML on each page:
<!-- On German page -->
<link rel="alternate" hreflang="de" href="https://example.com/german-page/" />
<link rel="alternate" hreflang="en" href="https://example.com/english-page/" />
<link rel="alternate" hreflang="fr" href="https://example.com/french-page/" />- Language Targeting: Search engines understand which language each page targets
- Duplicate Content Prevention: Signals that pages are translations, not duplicates
- Regional Search Results: Users see the correct language version in their regional search results
- Self-Referencing Tags: Each page includes its own language in hreflang tags (SEO best practice)
- Automatic Updates: Adding or removing translation links automatically updates all related pages
// Get language for a specific post
$language = jpkcom_simplelang_get_post_language( $post_id );
// Returns: 'de_DE', 'fr_FR', etc. or null if using default
// Get language for current post
$language = jpkcom_simplelang_get_post_language();// Get the active language in frontend (after locale switch)
$current_lang = jpkcom_simplelang_get_current_language();
// Returns: 'de_DE', 'fr_FR', etc. or null if using site default// Convert locale (de_DE) to language code (de) for HTML lang attribute
$lang_code = jpkcom_simplelang_get_language_code( 'de_DE' );
// Returns: 'de'If Oxygen Builder is installed, Simple Lang provides three custom conditions:
Check if the current post is set to a specific language.
Usage: Show German-specific content only when post language is German.
Parameters: Select from dropdown of all available languages.
Example: Display a German contact form only on German pages.
Check if the current post has any custom language set (not using site default).
Usage: Show a language indicator badge on posts with custom languages.
Example: Display "This page is available in [Language]" notification.
Check if the current post uses the site default language (no custom language set).
Usage: Show default language content only when no custom language is selected.
Example: Display site-wide navigation only on default language pages.
/**
* Filter the file search paths for template overrides
*
* @param array $paths Default search paths
* @param string $filename The filename being located
*/
add_filter( 'jpkcom_simplelang_file_paths', function( $paths, $filename ) {
// Add custom search path
$paths[] = '/custom/path/to/overrides/' . $filename;
return $paths;
}, 10, 2 );Simple Lang is intentionally simple. It doesn't create separate translations of your content, manage language switchers, or handle complex translation workflows. It simply allows you to tell WordPress "display this specific post in German" without creating a duplicate post or managing translation relationships.
Use Simple Lang when:
- You need occasional pages in different languages
- Your site is primarily one language
- You want minimal overhead and complexity
Use WPML/Polylang when:
- You need full site translations
- You want translation management workflows
- You need language switchers and translation relationships
Simple Lang uses WordPress's built-in language system. Any language pack installed on your WordPress site is automatically available in the dropdown. You can install language packs via Settings → General → Site Language.
WordPress supports 200+ languages. See the full list of available languages.
No. Simple Lang only changes the interface language (WordPress core strings, theme strings, plugin strings). Your post content remains exactly as you write it. You're responsible for writing the content in the target language.
What gets translated:
- WordPress admin bar links (if visible)
- Post date formats
- Comment form labels
- Theme navigation elements
- Plugin interface elements
What doesn't get translated:
- Your post title
- Your post content
- Your custom fields
- Media captions
Yes! Simple Lang works with any page builder. The locale change happens at the WordPress level, so builder elements that use WordPress translation functions will automatically display in the selected language.
For Oxygen Builder, there's built-in support with custom conditions that let you show/hide elements based on the page language.
Yes. Block editor blocks that use WordPress's translation system will display in the selected language. Core blocks and properly internationalized third-party blocks work seamlessly.
Simple Lang automatically generates hreflang tags when you link posts together using the "Translation Links" meta box. The plugin outputs proper <link rel="alternate" hreflang="XX"> tags in the HTML <head> section for all linked translations.
What's included:
- Automatic hreflang tag generation
- Self-referencing hreflang tags (SEO best practice)
- Bidirectional translation linking
- Only published posts appear in hreflang tags
- Tags sorted by language code for consistency
SEO Plugin Compatibility:
- Works alongside Yoast SEO, Rank Math, and other SEO plugins
- SEO plugins automatically output correct
og:localemeta tags - Hreflang tags appear early in
<head>(before most SEO plugins)
What's NOT included:
- x-default hreflang tags (may be added in future versions)
- Automatic translation suggestions
- Language switcher widgets
Yes! Go to Settings → Simple Lang and check/uncheck the post types you want. By default, Posts and Pages have language selection enabled. Custom post types can be enabled individually.
Important: The language dropdown only shows installed languages. Here's how to add more:
Quick Method:
- Go to Settings → General in WordPress admin
- Find the Site Language dropdown
- Select the language you want to install (e.g., "Deutsch", "Français")
- Click Save Changes
- WordPress automatically downloads the language pack (5-10 seconds)
- Optional: Change back to your default language if needed
- The new language now appears in Simple Lang's dropdown!
Why only installed languages?
- Language packs contain WordPress translations (buttons, menus, date formats, etc.)
- Without the pack, switching language would only change the HTML
langattribute - Content would remain untranslated, creating a poor user experience
- This approach ensures every selectable language actually works
Need help?
- Go to Settings → Simple Lang for a detailed step-by-step guide
- Click the "Go to General Settings" button for quick access
- View all 200+ available languages at translate.wordpress.org
Pro Tip: You can install multiple languages without changing your site's default language. Just install each language and switch back to your preferred default afterward. All installed languages remain available!
Yes! Simple Lang is fully compatible with WordPress Multisite installations. Each site in the network can have language selection enabled independently.
No. Simple Lang adds minimal overhead:
- One meta query per post to check for custom language
- Locale switching happens once per request
- No additional database tables
- No frontend JavaScript or CSS
The plugin uses WordPress's native locale switching functions which are highly optimized.
Yes! Simple Lang uses a template override system. You can override any plugin file by placing it in:
- Child theme:
{child-theme}/jpkcom-simple-lang/{filename} - Parent theme:
{parent-theme}/jpkcom-simple-lang/{filename} - MU plugins:
{WPMU_PLUGIN_DIR}/jpkcom-simple-lang-overrides/{filename}
This lets you customize functionality without modifying plugin files directly.
Yes. The language meta is stored as post meta with the key _jpkcom_simplelang_language and is accessible via the REST API if your setup includes post meta in responses.
Nothing breaks. Posts will simply display in your site's default language. The language selection meta data remains in the database, so if you reactivate the plugin later, your language selections are restored.
Not currently. Language selection is done individually per post in the editor. For bulk operations, you'd need to write custom code using update_post_meta() with the meta key _jpkcom_simplelang_language.
Yes, if you enable language selection for the product post type in settings. However, Simple Lang only changes the interface language, not product data. You'll need to manually enter product titles and descriptions in the target language.
Before installing this plugin, ensure you have:
- WordPress 6.8 or higher
- PHP 8.3 or higher
- At least one additional language pack installed (optional but recommended)
- Download the latest release ZIP file from GitHub Releases
- Log in to your WordPress admin panel
- Navigate to Plugins → Add New
- Click Upload Plugin at the top
- Choose the downloaded ZIP file
- Click Install Now
- Click Activate Plugin
- Download and extract the plugin ZIP file
- Upload the
jpkcom-simple-langfolder to/wp-content/plugins/ - Log in to your WordPress admin panel
- Navigate to Plugins
- Find "JPKCom Simple Lang" and click Activate
cd /path/to/wordpress/wp-content/plugins/
git clone https://github.com/JPKCom/jpkcom-simple-lang.gitThen activate via WordPress admin.
-
Configure Post Types (Optional):
- Go to Settings → Simple Lang
- Check/uncheck which post types should have language selection
- Click Save Settings
-
Install Additional Languages (Recommended):
Why is this needed? The language dropdown in the post editor only shows languages that are already installed on your WordPress site. By default, WordPress only includes English. To display pages in other languages, you need to install the corresponding language packs first.
Step-by-Step Guide:
a. Navigate to Language Settings:
- In WordPress admin, go to Settings → General
- Scroll down to find the Site Language dropdown
b. Install a Language Pack:
- Click the Site Language dropdown
- Select the language you want to add (e.g., "Deutsch", "Français", "Español")
- Click Save Changes at the bottom of the page
- WordPress will automatically download and install the language pack (takes 5-10 seconds)
c. Restore Your Default Language (Optional):
- If you don't want to change your site's default language, immediately go back to Settings → General
- Change the Site Language back to your preferred default (e.g., "English (United States)" or "Deutsch")
- Click Save Changes again
d. Verify Installation:
- Go to Settings → Simple Lang
- You'll see a helpful guide with a "Go to General Settings" button for quick access
- The newly installed language is now available in the dropdown!
e. Add More Languages:
- Repeat steps b-c for each additional language you need
- You can install as many languages as you want (WordPress supports 200+ languages)
- Each language pack is typically 1-2 MB in size
Quick Tips:
- You don't need to keep your site in a different language to use it for individual pages
- Language packs remain installed even after you switch back to your default language
- Already installed languages will appear immediately in the post editor dropdown
- View all available languages at translate.wordpress.org
-
Test Language Selection:
- Edit any post or page
- Look for "Frontend Language Select" in the sidebar
- Select a language from the dropdown
- Save/update the post
- View the post in frontend and verify the language changed
The plugin includes automatic update support via GitHub. When a new version is released:
- You'll see an update notification in Plugins
- Click Update Now
- WordPress automatically downloads and installs the update
Updates include SHA256 checksum verification for security.
To remove the plugin:
- Deactivate the plugin via Plugins
- Click Delete
- Confirm deletion
Note: Language selection meta data will remain in the database. If you want to remove this data, run:
DELETE FROM wp_postmeta WHERE meta_key = '_jpkcom_simplelang_language';Bug Fixes
- Fixed duplicate "Settings saved" message on admin settings page
- Fixed Oxygen Builder conditions not displaying dropdown options
- Fixed Oxygen Builder condition callback signatures to match API requirements
Improvements
- Updated Oxygen Builder conditions to use correct API structure with 'options' array
- Added proper operator support (==, !=) for "Post Language Is" condition
- Added Yes/No dropdown options for boolean Oxygen conditions
- Added German translations for Oxygen condition options (Ja/Nein)
- All Oxygen conditions now appear under "Simple Lang" category
Technical Changes
- Renamed callback functions to match Oxygen API conventions:
jpkcom_simplelang_oxygen_post_language_is()with ($value, $operator) parametersjpkcom_simplelang_oxygen_has_custom_language()with ($value, $operator) parametersjpkcom_simplelang_oxygen_uses_default_language()with ($value, $operator) parameters
- Removed redundant
settings_errors()call in admin settings page
New Features
- Translation Links: New meta box for linking posts in different languages
- Hreflang Tags: Automatic generation of SEO-friendly
<link rel="alternate" hreflang="">tags - Bidirectional Linking: Posts automatically link to each other when translation links are created
- Complete Translation Sets: All posts in a translation group are automatically linked together
- Smart Validation: Prevents duplicate languages in translation sets
Bug Fixes
- Fixed locale detection for default site language in translation grouping
- Fixed type casting issue in translation link display
- Improved meta data consistency across all translation sync operations
Improvements
- New helper function:
jpkcom_simplelang_get_site_default_locale() - Enhanced hreflang output with deterministic sorting
- Performance optimization: Single query for all translation posts (prevents N+1 queries)
- Updated German translations (de_DE and de_DE_formal)
Developer Notes
- New module:
includes/hreflang-translations.php - New meta key:
_jpkcom_simplelang_translations(multiple entries per post) - All translation sync operations use loop prevention for data integrity
Initial Release
- Language selection dropdown in post editor sidebar
- Support for all WordPress core languages
- Post type activation settings page
- Frontend locale override (HTML lang attribute and SEO plugin compatibility)
- Oxygen Builder conditional logic integration
- Helper functions for developers
- Template override system
- Automatic GitHub-based updates
- German translations included
- Full documentation and API docs