MishkaCmsCore.Runtime.Translation (Mishka CMS Core v0.0.1)

Copy Markdown View Source

A word a runtime template asks for with t/1, in one language, for one site.

A component, a page or a layout written in the builder is a database row compiled at runtime, so the build-time Gettext pipeline cannot reach it: mix gettext.extract reads files, and a .po only takes effect in a rebuilt backend. This is the runtime counterpart — a row per {site, key, language}, cached in ETS by MishkaCmsCore.Runtime.States.TranslationsState, read by MishkaCmsCore.Runtime.Translations.translate/2 and edited in the admin with no deploy.

Stored per language, listed per key

A row is one key in one language, edited with a plain form. value is nil until somebody writes it, and t/1 renders the key itself until then — the key is the source text, so an untranslated word reads as English, never blank.

The admin list shows one row per key, the way the page list shows one per page: a chip per language, translated or missing, and a modal with every language to fill in. Searching or filtering by language still lists a word once — see Translations.one_row_per_key/2.

Multitenant like MishkaCmsCore.Runtime.Setting

global? true: a row with site_id nil is a translation every site gets, a row with a site_id is that site's own and wins over the global one. A site admin reads their own rows and the global ones, and writes only their own.

Where rows come from

MishkaCmsCore.Runtime.Resources.Changes.RegisterTranslationKeys registers the keys a template asks for whenever a component, page or layout is saved, one row per language the site publishes in. :register never touches a value, so saving a template again cannot erase a translation.

Summary

Functions

Apply the full GuardedStruct pipeline (sanitize → validate → derive → main_validator) to attrs and return either {:ok, transformed_attrs} or {:error, errors}. Wire this into an Ash.Resource.Change to plug guardedstruct rules into Ash's changeset pipeline.

O(1) lookup of a field's compile-time metadata by name. Returns nil for unknown fields.

Compile-time-baked MapSet of every field name owned by the guardedstruct block. Used by GuardedStruct.AshResource.Change to decide, in O(1), whether a key in changeset.atomics belongs to the pipeline.

Validates that the keys in the provided input are valid for at least one action on the resource.

Same as input/1, except restricts the keys to values accepted by the action provided.

Types

t()

@type t() :: %MishkaCmsCore.Runtime.Translation{
  __lateral_join_source__: term(),
  __meta__: term(),
  __metadata__: term(),
  __order__: term(),
  aggregates: term(),
  calculations: term(),
  created_at: term(),
  id: term(),
  key: term(),
  language: term(),
  languages: term(),
  site: term(),
  site_id: term(),
  updated_at: term(),
  used: term(),
  value: term()
}

Functions

__guarded_change__(attrs, error? \\ false)

Apply the full GuardedStruct pipeline (sanitize → validate → derive → main_validator) to attrs and return either {:ok, transformed_attrs} or {:error, errors}. Wire this into an Ash.Resource.Change to plug guardedstruct rules into Ash's changeset pipeline.

The function is named __guarded_change__ because it does more than validate — it can also transform values (trim, downcase, slugify, auto-fill, etc.) before they reach the data layer.

__guarded_field_meta__(name)

O(1) lookup of a field's compile-time metadata by name. Returns nil for unknown fields.

__guarded_field_name_set__()

Compile-time-baked MapSet of every field name owned by the guardedstruct block. Used by GuardedStruct.AshResource.Change to decide, in O(1), whether a key in changeset.atomics belongs to the pipeline.

default_short_name()

input(opts)

@spec input(values :: map() | Keyword.t()) :: map() | no_return()

Validates that the keys in the provided input are valid for at least one action on the resource.

Raises a KeyError error at compile time if not. This exists because generally a struct should only ever be created by Ash as a result of a successful action. You should not be creating records manually in code, e.g %MyResource{value: 1, value: 2}. Generally that is fine, but often with embedded resources it is nice to be able to validate the keys that are being provided, e.g

Resource
|> Ash.Changeset.for_create(:create, %{embedded: EmbeddedResource.input(foo: 1, bar: 2)})
|> Ash.create()

input(opts, action)

@spec input(values :: map() | Keyword.t(), action :: atom()) :: map() | no_return()

Same as input/1, except restricts the keys to values accepted by the action provided.

primary_key_matches?(left, right)