{"result":{"depiction_url":null,"edges":{"refers":{"objects":[{"created":"2026-11-02T11:36:17Z","object_id":{"id":1381,"is_a":["text","documentation","reference","template_tag"],"name":"doc_template_tag_tag_trans_ext","title":"trans_ext","uri":"https:\/\/zotonic.com\/id\/1381"},"seq":1000000},{"created":"2026-11-02T11:36:17Z","object_id":{"id":3131,"is_a":["text","documentation","developerguide"],"name":"doc_guide_translations","title":"Translating interface messages","uri":"https:\/\/zotonic.com\/id\/3131"},"seq":1000000}],"predicate":{"id":2409,"is_a":["meta","predicate"],"name":"refers","title":{"_type":"trans","tr":{"en":"Refers"}},"uri":"https:\/\/zotonic.com\/id\/refers"}},"subject":{"objects":[{"created":"2026-11-02T11:36:17Z","object_id":{"id":2555,"is_a":["categorization","keyword","keyword_information_type"],"name":"zotonic_topic_reference","title":"Reference","uri":"https:\/\/zotonic.com\/id\/2555"},"seq":1},{"created":"2026-11-02T11:36:17Z","object_id":{"id":2564,"is_a":["categorization","keyword","keyword_audience"],"name":"zotonic_topic_backend_developer","title":"Backend developer","uri":"https:\/\/zotonic.com\/id\/2564"},"seq":2},{"created":"2026-11-02T11:36:17Z","object_id":{"id":2588,"is_a":["categorization","keyword","keyword_domain"],"name":"zotonic_topic_localization_and_translation","title":"Localization and translation","uri":"https:\/\/zotonic.com\/id\/2588"},"seq":3},{"created":"2026-11-02T11:36:17Z","object_id":{"id":2669,"is_a":["categorization","keyword","keyword_data_type"],"name":"zotonic_topic_translated_text","title":"Translated text","uri":"https:\/\/zotonic.com\/id\/2669"},"seq":4}],"predicate":{"id":308,"is_a":["meta","predicate"],"name":"subject","title":{"_type":"trans","tr":{"en":"Keyword"}},"uri":"http:\/\/purl.org\/dc\/elements\/1.1\/subject"}}},"export_revision":41,"id":3132,"is_a":["text","documentation","reference"],"links":[{"rel":"self","target":"https:\/\/zotonic.com\/.zotonic\/websub\/topic\/3132"},{"rel":"hub","target":"https:\/\/zotonic.com\/.zotonic\/websub"}],"medium":null,"medium_url":null,"name":"doc_reference_z_trans","page_url":{"en":"https:\/\/zotonic.com\/docs\/3132\/erlang-translation-api-z_trans","x-default":"https:\/\/zotonic.com\/docs\/3132\/erlang-translation-api-z_trans"},"preview_url":null,"resource":{"version":41,"pivot_location_lat":null,"title":"Erlang translation API: z_trans","is_authoritative":true,"body":"<h1>Erlang translation API: z_trans<\/h1>\n<p><code>z_trans<\/code> is part of <code>zotonic_core<\/code>. It resolves gettext interface messages and\nlanguage alternatives. For concepts and catalog authoring, see the\n<a href=\"\/id\/doc_guide_translations\">translation guide<\/a>. For template calls, see\n<a href=\"\/id\/doc_template_tag_tag_trans_ext\">the extended trans tag<\/a>.<\/p>\n<p>Supply literal English source text and literal message contexts for POT\nextraction. The functions below accept binaries or strings for these arguments;\nselected translations are binaries. They do not substitute placeholders.<\/p>\n<h2>Singular messages<\/h2>\n<pre class=\"notranslate\"><code class=\"notranslate language-erlang\">z_trans:trans(&lt;&lt;&quot;Open&quot;&gt;&gt;, Context).\nz_trans:trans(&lt;&lt;&quot;Open&quot;&gt;&gt;, nl, Context).\nz_trans:translations(&lt;&lt;&quot;Open&quot;&gt;&gt;, Context).\n<\/code><\/pre>\n<p><code>trans\/2<\/code> selects text using the request context&#39;s languages. <code>trans\/3<\/code> accepts\nan explicit language. <code>translations\/2<\/code> returns a <code>#trans{}<\/code> record containing\nlanguage alternatives, including an English fallback.<\/p>\n<p>The macros in <code>zotonic.hrl<\/code> provide the same operations:<\/p>\n<pre class=\"notranslate\"><code class=\"notranslate language-erlang\">?__(&lt;&lt;&quot;Open&quot;&gt;&gt;, Context).   % Selected text: trans\/2.\n?___(&lt;&lt;&quot;Open&quot;&gt;&gt;, Context).  % Language alternatives: translations\/2.\n<\/code><\/pre>\n<h2>Message context<\/h2>\n<pre class=\"notranslate\"><code class=\"notranslate language-erlang\">z_trans:trans_msgctxt(&lt;&lt;&quot;Open&quot;&gt;&gt;, &lt;&lt;&quot;action&quot;&gt;&gt;, Context).\nz_trans:trans_msgctxt(&lt;&lt;&quot;Open&quot;&gt;&gt;, &lt;&lt;&quot;action&quot;&gt;&gt;, nl, Context).\nz_trans:translations(&lt;&lt;&quot;Open&quot;&gt;&gt;, &lt;&lt;&quot;action&quot;&gt;&gt;, Context).\n?__(&lt;&lt;&quot;Open&quot;&gt;&gt;, &lt;&lt;&quot;action&quot;&gt;&gt;, Context).\n?___(&lt;&lt;&quot;Open&quot;&gt;&gt;, &lt;&lt;&quot;action&quot;&gt;&gt;, Context).\n<\/code><\/pre>\n<p>These APIs are strict: they try the requested message context in the selected\nlanguages, then fall back to the English source. They do not borrow contextless\ntranslations. The module&#39;s <code>-mod_msgctxt<\/code> attribute applies to templates only.<\/p>\n<p>Use <code>lookup\/2,3<\/code> or <code>lookup_fallback\/2,3<\/code> to select a language from a resolved\nsingular <code>#trans{}<\/code> record. Passing that record to <code>trans\/3<\/code> can re-fetch\ntranslations using only its English text, losing the message context.<\/p>\n<h2>Plural messages<\/h2>\n<pre class=\"notranslate\"><code class=\"notranslate language-erlang\">z_trans:trans_plural(&lt;&lt;&quot;{n} hour&quot;&gt;&gt;, &lt;&lt;&quot;{n} hours&quot;&gt;&gt;, N, Context).\nz_trans:trans_plural(\n    &lt;&lt;&quot;{n} hour&quot;&gt;&gt;, &lt;&lt;&quot;{n} hours&quot;&gt;&gt;, N, &lt;&lt;&quot;relative time: past&quot;&gt;&gt;, Context).\n<\/code><\/pre>\n<p><code>N<\/code> must be a non-negative integer. These functions return the selected text;\ncallers substitute <code>{n}<\/code> and other placeholders separately. The contextual form\nis strict, just like <code>trans_msgctxt<\/code>. Its source pair is extracted into <code>msgid<\/code>\nand <code>msgid_plural<\/code>, with <code>msgctxt<\/code> for the five-argument form.<\/p>\n<p>For all language alternatives, use:<\/p>\n<pre class=\"notranslate\"><code class=\"notranslate language-erlang\">z_trans:plural_translations(Singular, Plural, Context).\nz_trans:plural_translations(Singular, Plural, MsgCtxt, Context).\n<\/code><\/pre>\n<p>The returned <code>#trans{}<\/code> holds plural values, not selected text. Each language&#39;s\nvalue pairs a parsed plural rule with a tuple of forms. Keep the rule and forms\ntogether: indices from one catalog must not select forms from another catalog.<\/p>\n<h2>Contextless fallback<\/h2>\n<p>Opt into contextual-then-contextless lookup with:<\/p>\n<pre class=\"notranslate\"><code class=\"notranslate language-erlang\">z_trans:translations(Text, MsgCtxt, true, Context).\nz_trans:plural_translations(Singular, Plural, MsgCtxt, true, Context).\n<\/code><\/pre>\n<p>For plural messages, a language can contain ordered candidates: the contextual\nentry first, followed by the contextless entry. For example:<\/p>\n<pre class=\"notranslate\"><code class=\"notranslate language-erlang\">Trans = z_trans:plural_translations(\n    &lt;&lt;&quot;{n} item&quot;&gt;&gt;, &lt;&lt;&quot;{n} items&quot;&gt;&gt;, &lt;&lt;&quot;basket&quot;&gt;&gt;, true, Context).\n<\/code><\/pre>\n<p>The Dutch entry in <code>Trans#trans.tr<\/code> might be:<\/p>\n<pre class=\"notranslate\"><code class=\"notranslate language-erlang\">{nl, {plural_candidates, [\n    %% Contextual entry, with its plural form still untranslated.\n    {{2, {&#39;!=&#39;, n, 1}}, {&lt;&lt;&quot;{n} artikel&quot;&gt;&gt;, &lt;&lt;&gt;&gt;}},\n    %% Contextless entry, with its own plural rule.\n    {{2, {&#39;!=&#39;, n, 1}}, {&lt;&lt;&quot;{n} item&quot;&gt;&gt;, &lt;&lt;&quot;{n} items&quot;&gt;&gt;}}\n]}}\n<\/code><\/pre>\n<p>For <code>N = 1<\/code>, this selects <code>&lt;&lt;&quot;{n} artikel&quot;&gt;&gt;<\/code>. For <code>N = 2<\/code>, the contextual\nform is empty, so it selects <code>&lt;&lt;&quot;{n} items&quot;&gt;&gt;<\/code> from the contextless entry.\nCandidates can have different rules; each evaluates the count independently.<\/p>\n<p>Resolve the count before selecting the language, so missing forms still allow\nfallback to another language:<\/p>\n<pre class=\"notranslate\"><code class=\"notranslate language-erlang\">Source = {template_compiler_plural:english(),\n          {&lt;&lt;&quot;{n} item&quot;&gt;&gt;, &lt;&lt;&quot;{n} items&quot;&gt;&gt;}},\nResolved = template_compiler_plural:resolve(Trans, N, Source),\nText = z_trans:lookup_fallback(Resolved, Context).\n<\/code><\/pre>\n<p><code>Resolved<\/code> contains selected text per available language. If all candidates for\na language lack a usable form, that language is omitted. English source fallback\nuses the English plural rule. Placeholder substitution remains the caller&#39;s task.<\/p>","slug":"erlang-translation-api-z_trans","is_protected":false,"visible_for":0,"tz":"UTC","language":["en"],"doc_source_hash":"ec6dc6524bc2dd94be01c379f1ab9fda779fb7515f56a75cf8f849ad8336df30","is_featured":false,"content_group_id":{"id":2551,"is_a":["meta","content_group"],"name":"content_group_imported_docs","title":"Imported documentation","uri":"https:\/\/zotonic.com\/id\/content_group_imported_docs"},"category_id":{"id":319,"is_a":["meta","category"],"name":"reference","title":"Reference","uri":"https:\/\/zotonic.com\/id\/reference"},"doc_source_path":"doc\/reference\/z_trans.md","publication_start":"2026-11-02T11:36:17Z","github_url":"https:\/\/github.com\/zotonic\/zotonic\/blob\/master\/doc\/reference\/z_trans.md","pivot_location_lng":null,"doc_source_kind":"reference","name":"doc_reference_z_trans","is_unfindable":false,"is_published":true,"pivot_geocode":null,"created":"2026-11-02T11:36:17Z","uri":null,"doc_status":"current","is_dependent":false,"publication_end":"9999-06-01T00:00:00Z","modifier_id":{"id":1,"is_a":["person"],"name":"administrator","title":"Site Administrator","uri":"https:\/\/zotonic.com\/id\/1"},"privacy":0,"doc_source_commit":"f3c6a9a2dde17cb5b121dd3e3018d9ef4b1b3943\n","creator_id":{"id":1,"is_a":["person"],"name":"administrator","title":"Site Administrator","uri":"https:\/\/zotonic.com\/id\/1"},"modified":"2026-11-09T21:40:03Z","title_slug":"erlang-translation-api-z_trans"},"uri":"https:\/\/zotonic.com\/id\/3132","uri_template":"https:\/\/zotonic.com\/id\/:id","version":41,"websub":{"hub":"https:\/\/zotonic.com\/.zotonic\/websub","topic":"https:\/\/zotonic.com\/.zotonic\/websub\/topic\/3132"}},"status":"ok"}