Ns12 Locale Router Plugin Blueprint
Updated: 2026-04-24
Metadata
| Field | Value |
|---|---|
| Source site | uaix.org |
| Source URL | https://uaix.org/ |
| Canonical AIWikis URL | https://aiwikis.org/uaix/files/raw-system-archives-uaix-internal-memory-reorg-2026-05-01-docs-ns12-loca-4bc5eda5/ |
| Source reference | raw/system-archives/uaix/internal-memory-reorg/2026-05-01/docs/ns12_locale_router_plugin_blueprint.md |
| File type | md |
| Content category | memory-file |
| Last fetched | 2026-06-22T01:56:21.9510185Z |
| Last changed | 2026-04-24T01:44:43.1966006Z |
| Content hash | sha256:4bc5eda5a5ec5724db1c050147be213c9ac0919944e2140c232ec66521d8437a |
| Import status | unchanged |
| Raw source layer | data/sources/uaix/raw-system-archives-uaix-internal-memory-reorg-2026-05-01-docs-ns12-locale-router-plugin-bluepri-4bc5eda5a5ec.md |
| Normalized source layer | data/normalized/uaix/raw-system-archives-uaix-internal-memory-reorg-2026-05-01-docs-ns12-locale-router-plugin-bluepri-4bc5eda5a5ec.txt |
Current File Content
Structure Preview
- NS12 Locale Router Plugin Blueprint
- Status
- How To Use This Document
- Purpose
- Goal
- Important reality check
- Standards and WordPress hooks to rely on
- Recommended plugin architecture
- Core data model
- Supported locale record
- Dictionary file structure
- Dictionary template file
- Routing design
- Request rules
- Rewrite strategy
- Better production approach
- Locale resolution order
- Front end
- Admin
- REST API
- Link rewriting rules
- Rewrite these sources
- Do not rewrite
- URL localization example
Raw Version
This public page shows a bounded preview of a large source file. The complete source remains in the raw and normalized source layers named in metadata, with the SHA-256 hash above for verification.
- Source characters:
29045 - Preview characters:
11979
Local absolute paths are redacted in this public view. The source hash and source-side raw layer are based on the unredacted source file.
# NS12 Locale Router Plugin Blueprint
Updated: 2026-04-24
## Status
This is a design and implementation blueprint.
It is useful background, but the implemented plugin source is the authority for current runtime behavior.
## How To Use This Document
- Use this file to understand the intended architecture and design rationale for `ns12-locale-router`.
- Prefer the live plugin source for implemented behavior.
- Prefer `docs/deploy.md` for current deployment and routing policy.
- Treat this as design background, not the current feature backlog. Use `docs/roadmap.md` for future priorities.
## Purpose
This document captures the design intent, data model, and implementation direction for `ns12-locale-router` without replacing the live plugin source as the authority for current behavior.
Current companion references:
- `docs/navigation/implementation-and-runtime.md` for the shortest runtime and ownership path
- `wp-content/plugins/README.md` for plugin-area traversal
- `docs/runtime-architecture.md` for architecture-risk and bootstrap context
- `docs/deploy.md` for current routing and release policy
- `docs/ns12-locale-router-market-research.md` for product and adoption framing
## Goal
Create a WordPress plugin with these properties:
- 100% URL-based locale routing.
- No cookies.
- No session state.
- No JavaScript required for locale persistence.
- Locale segment always first in the path: `/{locale}/...`
- Switching locale on `/en-us/stuff` sends the visitor to `/es-us/stuff`
- Internal links are rewritten automatically so the user stays inside the current locale until they explicitly switch
- Translation content lives in uploaded JSON dictionaries, one file per locale
- Admin tools verify dictionary completeness, key alignment, placeholder integrity, and translation quality workflow status
---
## Important reality check
A plugin should **not** hardcode a supposedly complete finite list of œall locale codes in the world. The safe standard is to support **BCP 47 style locale tags** and maintain an admin-managed list of **supported locales**. Unicode CLDR is the practical source of locale data, and WordPress itself only knows about language files actually present on the site. WordPress also exposes hooks for request locale determination and locale switching. This means the plugin should:
1. Accept valid locale tags.
2. Let admins enable only the locales they actually want.
3. Validate locale tags against a shipped standards dataset.
4. Support importing a full locale catalog for selection in admin.
---
## Standards and WordPress hooks to rely on
- `determine_locale` / `pre_determine_locale` for request locale override.
- `switch_to_locale()` for request-time locale switching.
- `get_available_languages()` for WordPress-installed translation packs.
- Rewrite rules to capture the locale path prefix.
- URL filters such as `home_url`, `post_type_link`, `page_link`, `term_link`, `nav_menu_link_attributes`, and content-level URL rewriting where needed.
---
## Recommended plugin architecture
```text
/wp-content/plugins/ns12-locale-router/
ns12-locale-router.php
/src/
Plugin.php
Router.php
LocaleRepository.php
LocaleValidator.php
DictionaryRepository.php
DictionaryValidator.php
LinkLocalizer.php
Switcher.php
Admin/AdminPages.php
Admin/SettingsPage.php
Admin/DictionariesPage.php
Admin/ValidationPage.php
Support/Path.php
Support/Json.php
Support/Html.php
/data/
cldr-locales.json
default-supported-locales.json
/languages/
/templates/
switcher.php
/assets/
admin.css
front.css
```
---
## Core data model
### Supported locale record
```json
{
"tag": "en-US",
"urlTag": "en-us",
"language": "English",
"nativeName": "English (United States)",
"region": "US",
"script": "Latn",
"isRtl": false,
"enabled": true,
"isDefault": true,
"fallback": "en-US"
}
```
### Dictionary file structure
One JSON file per locale, for example `en-US.json`:
```json
{
"meta": {
"locale": "en-US",
"version": 1,
"fallback": "en-US",
"generatedFrom": "template",
"qualityStatus": "approved"
},
"strings": {
"site.header.home": "Home",
"site.header.about": "About",
"site.footer.contact": "Contact",
"page.contact.title": "Contact Us",
"page.contact.intro": "Send us a message",
"component.search.placeholder": "Search"
}
}
```
### Dictionary template file
This is the source language master file. Every other locale must match its keys exactly.
```json
{
"meta": {
"locale": "template",
"version": 1
},
"strings": {
"site.header.home": "Home",
"site.header.about": "About",
"site.footer.contact": "Contact"
}
}
```
---
## Routing design
### Request rules
- `/` redirects to `/{default-locale}/`
- `/about/` redirects to `/{default-locale}/about/`
- `/en-us/` serves homepage in locale `en-US`
- `/en-us/about/` serves the same content object as `/about/`, but under locale `en-US`
- `/en-us/wp-admin/` is **not** routed through the public locale router
- `/wp-json/`, `/wp-admin/`, `/wp-login.php`, `/feed/`, sitemap endpoints, and static assets must be excluded or handled carefully
### Rewrite strategy
Use a rewrite tag and top-priority rules:
```php
add_rewrite_tag('%ns12_locale%', '([A-Za-z]{2,8}(?:-[A-Za-z0-9]{2,8})*)');
add_rewrite_rule('^([A-Za-z]{2,8}(?:-[A-Za-z0-9]{2,8})?)/(.*)?$', 'index.php?ns12_locale=$matches[1]&pagename=$matches[2]', 'top');
```
That exact example is only a starting point. In production, the plugin should parse the locale prefix first, then hand the remainder back to WordPress request parsing instead of overloading only `pagename`.
### Better production approach
- Parse request URI very early.
- Detect whether first path segment is a supported locale.
- Store current locale in request scope only.
- Strip locale segment before WordPress resolves the route.
- Rebuild canonical URLs with locale prefix later.
This is more reliable than trying to map every request type through one rewrite target.
---
## Locale resolution order
### Front end
1. Locale path segment if present and supported.
2. Default locale if absent.
3. Redirect to localized URL if locale prefix is absent.
### Admin
- Do **not** use front-end locale path switching for admin screens.
- Admin should stay under the users WordPress locale or plugin admin preference.
### REST API
Two choices should be configurable:
1. Keep REST unlocalized.
2. Accept locale-prefixed REST routes for front-end consumers.
Default: keep REST unlocalized for stability.
---
## Link rewriting rules
The plugin must keep the user inside the active locale automatically.
### Rewrite these sources
- `home_url()`
- `site_url()` where appropriate for front-end links
- post permalinks
- page permalinks
- term links
- author links
- menu item URLs
- pagination links
- breadcrumbs if using common filters
- content links in post content output
- logo/home links
- canonical links
- hreflang tags
### Do not rewrite
- admin URLs
- login URLs unless explicitly enabled
- AJAX endpoints unless explicitly enabled
- external links
- mailto, tel, javascript, fragment-only links
- static file URLs
### URL localization example
Current request: `/en-us/products/widget-a/`
- Home link becomes `/en-us/`
- About link becomes `/en-us/about/`
- Contact link becomes `/en-us/contact/`
- Locale switch to Spanish becomes `/es-us/products/widget-a/`
---
## Translation retrieval model
Use a thin translation layer instead of relying only on native WordPress gettext.
### Why
You want every string controlled by a shared dictionary-key system and uploaded JSON files.
### API
```php
function ns12lr_t(String $key, String $fallback = ''): String;
function ns12lr_t_format(String $key, array $replacements, String $fallback = ''): String;
```
### Example usage
```php
echo esc_html(ns12lr_t('site.header.home', 'Home'));
```
### Placeholder enforcement
All placeholders must match across locales:
- `{name}`
- `{count}`
- `{city}`
Validator must reject translations that are missing placeholders or introduce unknown ones.
---
## Admin features
### 1. Settings page
- Enable plugin
- Default locale
- Enabled locales
- URL casing strategy
- Trailing slash strategy
- Redirect behavior for bare URLs
- REST localization mode
- Exclusion patterns
- Fallback locale per locale
- Toggle content link rewriting
### 2. Locale catalog page
- Searchable full locale list
- Add locale to supported set
- Mark default
- Set fallback
- View native name, region, script, RTL flag
- Bulk enable or disable
### 3. Dictionaries page
- Upload locale JSON
- Download template JSON
- View missing keys
- View extra keys
- View placeholder mismatches
- View empty translations
- View untranslated values identical to template
- View last validation result
- Version mismatch warnings
### 4. Validation page
Run full verification suite:
- Missing keys
- Extra keys
- Type mismatches
- Placeholder mismatches
- Invalid JSON
- Invalid locale metadata
- Duplicate keys
- Empty values
- HTML tag mismatches if HTML is allowed
- Variable interpolation mismatches
- Fallback coverage
- Suspected machine-translation artifacts
- Length outliers
- Encoding issues
### 5. Quality workflow page
Each uploaded dictionary can have status:
- draft
- ai-generated
- reviewed
- approved
- rejected
Also record:
- uploader
- upload time
- reviewer
- approval time
- comparison against template version
---
## Content strategy
There are two separate content types to handle.
### A. Theme and plugin UI strings
Use dictionary keys directly in templates and plugin output.
### B. Page and post content
This is the harder part.
For a robust first version, support these modes:
1. **Dictionary token mode**
Authors place tokens like `{{page.contact.title}}` in content.
Render pipeline replaces them with localized strings.
2. **Localized meta mode**
Store translated content per locale in post meta.
3. **Block attribute mode**
For custom blocks, store dictionary keys and render localized text.
Do **not** promise perfect automatic extraction of every existing text fragment in arbitrary HTML content. That becomes fragile fast.
---
## Validation rules for uploaded dictionaries
### Required checks
1. Locale tag matches filename.
2. Locale tag is valid against locale catalog.
3. `meta.version` matches template version.
4. Every key from template exists.
5. No unknown keys unless explicitly allowed.
6. Every value is a string.
7. Required placeholders exactly match template.
8. No control character corruption.
9. JSON is UTF-8.
10. File size and key count are within expected bounds.
11. Fallback locale exists.
12. Strings that should remain unchanged stay unchanged where required.
### Recommended quality checks
1. Detect same-as-source ratio.
2. Detect very short outputs where source is long.
3. Detect repeated punctuation or malformed unicode.
4. Detect suspicious placeholder movement.
5. Detect likely truncation.
6. Detect markup imbalance.
---
## Locale switcher UX
### Requirements
- No JS required.
- Native `<select>` inside a `<form method="get">` or `<form method="post">` is fine, but switching itself should produce a normal URL navigation.
- Nice looking and accessible.
- Keeps current path.
- Preserves query string where appropriate.
### Best no-JS pattern
Use a `<form method="get" action="">` with a `<select name="switch_locale">` and submit button.
For a better look without JavaScript, style the select and visually minimize the submit button.
### Example behavior
Current URL:
`/en-us/stuff/?page=2`
User selects `es-us`
Server redirects to:
`/es-us/stuff/?page=2`
---
## SEO requirements
- Every localized page must emit self canonical in its locale URL.
- Emit `hreflang` tags for all enabled sibling locales.
Why This File Exists
This is a memory-system evidence file from uaix.org. It is shown here because AIWikis.org is demonstrating the real source files that make the UAIX / LLM Wiki memory system work, not only summarizing those systems after the fact.
Role
This file is memory-system evidence. It records source history, archive transfer, intake disposition, or another piece of provenance that should be retrievable without becoming an unsupported public claim.
Structure
The file is structured around these visible headings: NS12 Locale Router Plugin Blueprint; Status; How To Use This Document; Purpose; Goal; Important reality check; Standards and WordPress hooks to rely on; Recommended plugin architecture. Those headings are retrieval anchors: a crawler or LLM can decide whether the file is relevant before reading every line.
Prompt-Size And Retrieval Benefit
Keeping this material in a separate file reduces prompt pressure because an agent can load this exact unit only when its role, source site, category, or hash is relevant. The surrounding index pages point to it, while this page preserves the full content for audit and exact recall.
How To Use It
- Humans should read the metadata first, then inspect the raw content when they need exact wording or provenance.
- LLMs and agents should use the source site, category, hash, headings, and related files to decide whether this file belongs in the active prompt.
- Crawlers should treat the AIWikis page as transparent evidence and follow the source URL/source reference for authority boundaries.
- Future maintainers should regenerate this page whenever the source hash changes, then review the explanation if the role or structure changed.
Update Requirements
When this source file changes, update the raw source layer, normalized source layer, hash history, this rendered page, generated explanation, source-file inventory, changed-files report, and any source-section index that links to it.
Related Pages
- Source overview
- Site file index
- Site report index
- UAI system index
- Source provenance
- Site directory
- Organization reports
Provenance And History
- Current observation:
2026-06-22T01:56:21.9510185Z - Source origin:
current-source-workspace - Retrieval method:
local-source-workspace - Duplicate group:
sfg-372(primary) - Historical hash records are stored in
data/hashes/source-file-history.jsonl.
Machine-Readable Metadata
{
"title": "Ns12 Locale Router Plugin Blueprint",
"source_site": "uaix.org",
"source_url": "https://uaix.org/",
"canonical_url": "https://aiwikis.org/uaix/files/raw-system-archives-uaix-internal-memory-reorg-2026-05-01-docs-ns12-loca-4bc5eda5/",
"source_reference": "raw/system-archives/uaix/internal-memory-reorg/2026-05-01/docs/ns12_locale_router_plugin_blueprint.md",
"file_type": "md",
"content_category": "memory-file",
"content_hash": "sha256:4bc5eda5a5ec5724db1c050147be213c9ac0919944e2140c232ec66521d8437a",
"last_fetched": "2026-06-22T01:56:21.9510185Z",
"last_changed": "2026-04-24T01:44:43.1966006Z",
"import_status": "unchanged",
"duplicate_group_id": "sfg-372",
"duplicate_role": "primary",
"related_files": [
],
"generated_explanation": true,
"explanation_last_generated": "2026-06-22T01:56:21.9510185Z"
} Next Useful Routes
- Start Here A task-first reading path for AIWikis.org, separating newcomer learning, source-memory lookup, maintainer workflow, and AI-agent retrieval.
- Topic Index A tag-oriented index for LLM Wiki, AI memory, UAI, source governance, crawling, and retrieval topics.
- Source Map AIWikis source-governed page for durable AI memory, evidence routing, and agent-readable retrieval.
- UAIX.org UAIX.org source-system overview for transparent AIWikis memory demonstration.
- UAIX.org Source Memory Guide AIWikis source-governed page for durable AI memory, evidence routing, and agent-readable retrieval.
- UAIX.org Files Site-scoped current-source file index for UAIX.org.