translation_tree
Tree translation API. get/<id> returns language counts, get/status/<id> returns
job progress and post/<id> starts a job. Reads require edit access to the root;
tree traversal requires visibility of every member. Each page must still be editable
when the worker reaches it; otherwise it is skipped. Trees include their root and
unique menu/haspart descendants. No caller privileges are elevated.
The bulk_dialog postback accepts an ids list for bulk-update selections. It checks
edit access to every selected page, deduplicates the IDs, and stores a selection for
one day. Its bulk- token can be used instead of a resource ID on the same model
paths. Only the authenticated user who created the selection can access it. Bulk
jobs process exactly the selected pages, without traversing their descendants, and
check each page's edit permission again before changing it.
For example, m.translation_tree[123] returns the following data for a tree with
three unique pages, two available in English and all three available in Dutch:
#{total => 3, languages => [{en, 2}, {nl, 3}]}
The total includes the root. Language counts can overlap because a page can have
multiple languages. The model callback wraps this data as {ok, {Data, Rest}},
where Rest is the unused model path.
m.translation_tree.status[123] can return this progress map:
#{root => 123,
job => <<"example-job-id">>,
state => running,
operation => <<"translate">>,
total => 3,
done => 2,
skipped => 1,
failed => 0}
done counts all processed pages, including skipped and failed pages. total is
zero until traversal finishes. The state becomes complete when every page has
been processed, even if individual pages failed; failed as a state indicates a
job-level failure. With no known job the response is #{root => 123, state => idle}.
A successful post/<id> returns {ok, Progress} as soon as the job starts.
The event/2 handler opens the translation dialog using a signed dialog postback
with an id argument identifying the tree root. For example:
{% button text=_"Translate all pages"
postback={dialog id=tree_id} delegate="m_translation_tree" %}
The handler checks edit access to the root and visibility of the tree, then renders
_dialog_translation_tree.tpl with the resolved id and the language-count map as
tree. If these checks fail, it displays an error growl. Opening the dialog does
not start a job; the dialog submits a confirmed operation through post/<id>.