An item's language and the other editions of it, for the targets whose resource keeps one record
per language, joined by language_group_id (MishkaCmsCore.LanguageEditions): the core's pages
(MishkaCmsMigration.Targets.CmsPage) and the Blog's posts, categories and tags
(MishkaCmsMigration.Targets.BlogPost, MishkaCmsMigration.Targets.BlogCollection,
MishkaCmsMigration.Targets.BlogTag). A source names them in the item's "language" and
"translations" (%{"en" => "121"}, the source id of each other edition by language), as the
WordPress source reads them from Polylang or WPML (MishkaCmsMigration.Sources.WordPress,
"Languages").
Its record
The CMS keeps a record in several languages as one main record, its master, and a translation
of it per other language: each a record of its own, in its language (attrs/3), whose
language_group_id is the master's id, the key the master's own language_group_id holds too
(MishkaCmsCore.LanguageEditions, MishkaCmsCore.Runtime.Resources.Changes.SetLanguageGroupId).
The CMS's Add translation writes a translation the same way: the resource's create, with the
master's group (MishkaCmsCore.Runtime.PageEditions.translate/4).
The master is the group's original: the edition in the site's main language, else the first by
code, since the CMS lets a record in any language lead its group. The original is written as a
group of its own, which the resource's create makes it, and every other edition joins the group
of the records its editions' items (MishkaCmsMigration.MigrationItem) were written to. An
original written after other editions of it, by a later page of the source or a later run, then
takes them over (lead/4): they, and any translation an admin added to them in the CMS, move to
its group through the resource's update action, and their items record the new updated_at, so
a later run does not take the move for an edit in the CMS. So the editions are one group, led by
the original, whatever order the source lists them in, and whichever of them an earlier run
wrote. That costs two queries for an item with editions, its editions' items and their records,
one more and an update each when the original takes them over, and none for one without.
A language the site does not publish in
An item in a language that is not one of the site's (MishkaCmsCore.Runtime.Languages.site/1)
waits for an admin's decision on "language_missing", its reason naming the code
("language_missing: fa"), in a dry run (waiting/2) and in an import (call/2), for an item an
earlier import wrote as for a new one. Add the language to the site ("import") adds it to the
end of the site's site.languages as the admin (MishkaCmsCore.Settings.put_as/4) before the
item is written, and the report says so ("language_added: fa"); the items in that language
written after it then wait on nothing. Leave the translation out leaves the item out.
A language the source does not say
On a run whose source runs a language plugin (MishkaCmsMigration.Target's context, languages),
an item that names no language waits for an admin's decision on "language_unknown": writing it
in the site's language could mislabel a translation. Polylang's free plugin names an entry's
language over the REST API only by the address it serves it under, which the WordPress source
reads (MishkaCmsMigration.Sources.WordPress, "Languages"), so this waits only for an entry no
language's address holds. Import it in the site's main language ("import") writes it so;
Wait ("keep") skips it as "waits_for_language", for a run of the site's export file, which
carries every entry's language. An item that names no language on a run of a source with no
language plugin is in the site's main language (MishkaCmsCore.Runtime.Languages.primary/1).
One language for the run
A run whose New import window chose one language (one_language of its options,
MishkaCmsMigration.MigrationRun.one_language/2, one of the site's languages) asks neither
decision: an item that names no language, and one in a language the site does not publish in, is
written in that language and waits for nothing, and the Items page says so in one line. An item
in one of the site's languages keeps it, and the editions the source links stay linked.
What the report says
note/3: "translations: fa, de" for the group's original, the edition in the site's main
language (else the first by code), naming its other editions, and "translation_of: <title> (<code>)" for every other edition, with the original's title as the item an earlier run or
this one recorded it (#<source id> before any did), in a dry run and in an import; and
"language_added: <code>" once an admin decided to add the item's language.
Summary
Functions
The language and group a target writes item with, to the records of resource: its
language, and its language_group_id when an edition of it was written already (see "Its
record"), which the input leaves out otherwise.
What a target's prepare/3 asks first: :ok for an item in one of the site's languages, or one
an admin decided to import, after adding its language to the site; else {:undecided, conflict},
{:skipped, "waits_for_language"}, or the core's refusal of the setting.
The language item is written in: its own, else the site's main language; on a run that puts
such items in one language (see "One language for the run"), that language for an item with none
or with one the site does not publish in.
Runs write, the import's write of item by target, and, when item is the original of its
group (see "Its record"), moves the editions written before it into its group, as the admin,
with target's update action. Answers what write does, or the CMS's refusal of a move.
What the report says of item's language and editions (see "What the report says"), followed by
also, a target's own note, joined by "; ", or nil when neither says anything.
The prepare/3 of target, a target whose write waits on nothing else
(MishkaCmsMigration.Target): write.(context), led by lead/4, once call/2 answers :ok,
else what it answers.
Functions
@spec attrs( MishkaCmsMigration.Source.Item.t(), MishkaCmsMigration.Target.context(), Ash.Resource.t() ) :: map()
The language and group a target writes item with, to the records of resource: its
language, and its language_group_id when an edition of it was written already (see "Its
record"), which the input leaves out otherwise.
@spec call(MishkaCmsMigration.Source.Item.t(), MishkaCmsMigration.Target.context()) :: :ok | {:error, term()} | {:skipped, String.t()} | {:undecided, String.t()}
What a target's prepare/3 asks first: :ok for an item in one of the site's languages, or one
an admin decided to import, after adding its language to the site; else {:undecided, conflict},
{:skipped, "waits_for_language"}, or the core's refusal of the setting.
@spec language( MishkaCmsMigration.Source.Item.t(), MishkaCmsMigration.Target.context() ) :: String.t()
The language item is written in: its own, else the site's main language; on a run that puts
such items in one language (see "One language for the run"), that language for an item with none
or with one the site does not publish in.
@spec lead( MishkaCmsMigration.Source.Item.t(), MishkaCmsMigration.Target.context(), module(), (MishkaCmsMigration.Target.context() -> result) ) :: result | {:error, term()} when result: term()
Runs write, the import's write of item by target, and, when item is the original of its
group (see "Its record"), moves the editions written before it into its group, as the admin,
with target's update action. Answers what write does, or the CMS's refusal of a move.
@spec note( MishkaCmsMigration.Source.Item.t(), MishkaCmsMigration.Target.context(), String.t() | nil ) :: String.t() | nil
What the report says of item's language and editions (see "What the report says"), followed by
also, a target's own note, joined by "; ", or nil when neither says anything.
@spec prepare( MishkaCmsMigration.Source.Item.t(), MishkaCmsMigration.Target.context(), module(), (MishkaCmsMigration.Target.context() -> result) ) :: result | {:error, term()} | {:skipped, String.t()} | {:undecided, String.t()} when result: term()
The prepare/3 of target, a target whose write waits on nothing else
(MishkaCmsMigration.Target): write.(context), led by lead/4, once call/2 answers :ok,
else what it answers.
@spec waiting(MishkaCmsMigration.Source.Item.t(), MishkaCmsMigration.Target.context()) :: MishkaCmsMigration.Target.found() | nil
What a target's waiting/2 answers in a dry run: what call/2 would, without writing.