Docs / Caching and i18n

Caching and i18n

GoPress treats cache and internationalization as core services because both affect routes, templates, admin labels, settings, SEO, and frontend rendering.

Multi-level Cache

Layer Medium Role
L1 In-process LRU Hot data with no network round trip.
L2 Optional Redis Shared cache for multi-process or multi-node deployments.
Full page Reuses L1 and L2 Returns complete HTML before theme rendering on a hit.
Database PostgreSQL Source of truth for content, options, menus, media, and extension data.

Cache keys include the language dimension so translated pages never share HTML entries. Content writes, menu updates, settings changes, theme switches, and plugin activation changes invalidate the corresponding tags or cache paths. The admin cache page also provides manual all-cache, page-cache, and fragment-cache operations.

Redis is optional. When it is missing or unavailable, GoPress continues with the in-process cache and database rather than making the site unavailable.

Core i18n Architecture

Core owns localization primitives; an optional multilingual plugin contributes database overrides and management UI through public contracts:

core/i18n.Manager
  -> load core, plugin, and theme locale files
  -> T(ctx, key)
  -> TranslateOption / TranslateSettings

core/option registry
  -> RegisterTranslatable(key, section, label)
  -> IsTranslatable / AllTranslatableKeys

resolution priority
  1. database StringTranslation override
     domain="theme" for UI; domain="option" for settings
  2. component locale file
  3. original message ID

This fallback chain keeps a page usable when a translation is incomplete. Core remains a complete single-language CMS when no plugin supplies database translations.

UI Strings

Themes place JSON messages under locales/ and use {{T .Ctx "welcome"}} in templates. A multilingual extension may add or override messages in the database without editing theme files.

Translatable Settings

Themes register copy-oriented option keys such as hero headings or About text. Core translates only registered keys when rendering the settings map:

func registerTranslatableOptions() {
    option.RegisterTranslatable("home_hero_title", "hero", "Hero title")
    option.RegisterTranslatable("home_about_title", "about", "About title")
}

func (p *PageData) TranslateSettings(c *gin.Context, manager *i18n.Manager) {
    p.Settings = manager.TranslateSettings(
        c, p.Settings, option.IsTranslatable, option.AllTranslatableKeys())
}

Template Helpers

{{T .Ctx "welcome"}}
{{currentLang .Ctx}}
{{langPrefixURL .Ctx "/about"}}
{{archiveURL "product"}}
{{contentURL . "product"}}
{{taxonomyURL "category" .Slug}}

product is only an example theme-defined type. The URL helpers consult the rewrite registry, so custom type names and changed rewrite_slug values do not require hard-coded link changes.

Language Scope

A multilingual plugin can add language-aware content and term queries through the generic Content and Taxonomy Scope APIs, resolve per-language menus through menu hooks, and add URL prefixes through core helpers. Core and themes do not import or inspect that plugin; without it, the same APIs retain single-language behavior.

See the Multilingual Plugin for content and Category/Tag translation, canonical URL detection, menu assignment, SEO alternates, and language-switching behavior.