<p>It all starts in Your <code>ElementType</code> where you need to return <code>true</code> on the <code>isLocalized</code> function (Line 62 in <code>BaseElementType.php</code>).</p>

<p>Setting this to true will tell Craft that data is stored per-locale, and it's local choices are based on your Element Model's <code>getLocales</code> function. You can get a basic example from Line 231 of <code>BaseElementModel.php</code>.</p>

<p>Craft's Entry Element actually allows you to choose which locale's are used on a per section basis. You can see an Entry gather its locales on Line 54 in <code>EntryModel.php</code> and Line 57 in <code>SectionModel.php</code>. A section stores its locale options in a related table via <code>SectionLocaleRecord</code>.</p>

<p>The rest should be handled by Craft so long as you set <code>localeEnabled</code> to <code>true</code> and <code>locale</code> to a locale ID in your model before passing it along to <code>saveElement</code>.</p>

<p>The rest of the work is templating, which you can reference how P&amp;T do it in <code>templates/entries/_edit.html</code>.</p>

CC BY-SA 3.0
2016-04-06T07:33:00.213Z
Thanks Bryan. This is a good start. It seems a custom element type would also have to create/manage a second table for the locale such as the `craft_sections_i18n` or `craft_categorygroups_i18n` table. These tables appear to manage information that is specific to the element type and how the locales need to behave for it.  For example, the `craft_sections_i18n` table has an `enabledByDefault` setting and the category groups table doesn't.
Ben Parizek
CC BY-SA 3.0
2016-04-06T13:12:17.083Z
Hrm... Then I will dig deeper and correct my answer.
Bryan Redeagle
CC BY-SA 3.0
2016-04-06T16:00:39.380Z
More topics worth explaining for a canonical answer would be what javascript is being used and how the element data is being handled when saving Elements. `craft.js` has a `Craft.ElementEditor` which includes a `switchLocale` method and calls `elements/getEditorHtml` and an `updateForm` method.  How does the element save data for multiple locales? Does the `saveEntry` method happen once per locale? Or do all the fields and custom field inputs get namespaced when an entry is submitted?  When I use the locale switcher for Entries, it appears the title field for both locales is `name="title"`
Ben Parizek
CC BY-SA 3.0
2016-04-02T13:26:25.873Z
2016-04-02T13:26:25.873Z
Bryan Redeagle
<p><em>I don't believe myself to be an authority on this topic, nor this answer to be complete, but below I try to pull together a summary of several of the things you'll want to consider when adding localization to your plugins. Please correct me where I'm wrong and I'll try to make updates to this as I learn more until proper documentation exists.</em></p>

<hr>

<p>Adding localization to your plugin will require addressing at least three different scenarios in the Control Panel:</p>

<ol>
<li>How are you saving your data in a localized way?</li>
<li>How are you retrieving your data in a localized way?</li>
<li>How are you managing the UI around switching between locales?</li>
</ol>

<p>While there may be related settings, the primary thing that gets localized in Craft is the Element.  As you localize your plugin you may need to ask: how does what I am trying to add localization support for relate to the Elements in the system?</p>

<h2>Craft-managed tables that relate to localization</h2>

<p>I believe Craft will manage the locale-specific behavior for several tables in the database for you:</p>

<ul>
<li>craft_elements_i18n</li>
<li>craft_locales</li>
<li>craft_routes</li>
<li>craft_searchindex</li>
<li>craft_templatecaches</li>
</ul>

<h2>Element-specific tables that relate to localization</h2>

<p>Each respective Element Type will need to manage and make sure locale-related data is saved to the tables that relate to that specific Element Type.</p>

<p>In the case of Entries, Entries manage locale-specific data in the following tables:</p>

<ul>
<li>craft_content</li>
<li>craft_entrydrafts</li>
<li>craft_entryversions</li>
<li>craft_sections_i18n</li>
</ul>

<p>Categories manage locale-specific data with different requirements:</p>

<ul>
<li>craft_categorygroups_i18n</li>
<li>craft_content</li>
</ul>

<h2>Localization and Field Types</h2>

<p>Many fields get added directly to Elements via Field Layouts. By default, fields store the data they save as a field-specific column on the content table that relates to the Element the field has been added to. An Entry With a Plain Text field named <code>stuff</code> will store it's data in the <code>craft_content</code> table with the column name <code>field_stuff</code>.</p>

<p>For fields that use this default method of storing their data, you do not need to add additional localization support. The <code>craft_content</code> table already has a <code>locale</code> column and populating that value will be handled by the Element that your field is assigned to.</p>

<p>For custom fields that are advanced enough to require a field-specific database table to store their data (consider an Address Field, perhaps), the plugin developer will need to add locale support (discussed in more detail below).</p>

<hr>

<h2>How are you saving your data in a localized way?</h2>

<h2>Elements</h2>

<p>Craft does not do much to help you save your Element data in a locale-friendly way. You'll need to manage a lot of this on your own.</p>

<p>To start off, you'll want to give your Element an <code>isLocalized</code> method and return <code>true</code>. One class to read up on to understand a bit more about how localization works on Element Types is the <a href="https://craftcms.com/classreference/elementtypes/IElementType" rel="nofollow noreferrer">IElementType Class</a>.</p>

<p>While Craft appears to manage saving the locale data to <code>craft_elements_i18n</code> for you, it appears Elements that support locales also have a secondary <code>i18n</code> table that relates to something that I don't know what to call but tend to refer to as the Element Group. The Element Group for Entries is Sections, for Categories is Category Groups, for Craft Commerce Products is Product Types.</p>

<p>Entries</p>

<ul>
<li>craft_sections</li>
<li>craft_sections_i18n</li>
</ul>

<p>Categories</p>

<ul>
<li>craft_categorygroups</li>
<li>craft_categorygroups_i18n</li>
</ul>

<p>Commerce Products</p>

<ul>
<li>craft_commerce_producttypes</li>
<li>craft_commerce_producttypes_i18n</li>
</ul>

<p>It would seem that if your Element has URL support, and those URL Format settings are managed on the Element Group for that Element, you will need a similar <code>i18n</code> table in your plugin for your Element.</p>

<h3>Advanced Fields</h3>

<p>Advanced fields will need to:</p>

<ul>
<li>Add a <code>locale</code> column to the database table that stores their field info</li>
<li>Populate that locale column while saving data to their custom table in the Field Types <code>onAfterElementSave</code> method. The locale ID can be found via <code>$this-&gt;element-&gt;locale</code> value in your Field Type class.</li>
</ul>

<hr>

<h2>How are you retrieving your data in a localized way?</h2>

<h3>Elements</h3>

<p>When Elements are retrieved from the database using an Element Query, the Element Types <code>modifyElementsQuery()</code> method will be called. This gives the Element a chance to make changes to the query and is where you will need to update the query to ensure that the locale is being considered.</p>

<p>This is discussed in <a href="https://craftcms.stackexchange.com/a/13000/115">this question here</a> and seems to make sense, however, it doesn't appear to be used in the Entry or Category Elements and I cannot explain why.</p>

<h3>Advanced Fields</h3>

<ul>
<li>Retrieve the locale-specific record from the database when retrieving the field data in the <code>getInputHtml</code> method.  The locale ID can be found via <code>$this-&gt;element-&gt;locale</code> value in your Field Type class.</li>
</ul>

<hr>

<h2>How are you managing the UI around switching between locales?</h2>

<p>When a user switches between locales while editing an Entry a few things need to happen. Craft appears to manage this with entries in part by reloading the page which probably also means they are re-querying the database for the content specific to the locale of the page being loaded.</p>

<pre><code>http://happylager.dev/admin/entries/news/slug-1/en_us
http://happylager.dev/admin/entries/news/slug-1/es
</code></pre>

<p>The switch may actually be triggered by javascript. <code>craft.js</code> has a class called <code>Craft.ElementEditor</code> which includes a <code>switchLocale</code> method and calls elements/getEditorHtml and an updateForm method. I don't know much more than that!</p>

<p>The input field values for the <code>locale</code> will need to be updated to the locale ID of the locale you want to save your data for:</p>

<pre><code>&lt;input type="hidden" name="locale" value="en_us"&gt;
</code></pre>

<p>You will want to give visual indications of which locale is in use as well. This may include the controls the user uses to switch between languages as well as pass the locale value to any form macros that should display a locale indicator.</p>

<pre><code>{{ forms.textField({
    label: "Title"|t,
    locale: element.locale,
    name: 'title',
    value: element.title,
    errors: element.getErrors('title'),
}) }}
</code></pre>

<p>The <code>locale</code> attribute in the above macro will output a locale specific indicator in the <code>label</code> tag of the form: <code>&lt;span class="locale"&gt;{{ locale }}&lt;/span&gt;</code>.</p>

CC BY-SA 3.0
2016-09-02T00:21:01.083Z
2016-09-02T00:31:29.557Z
2017-04-13T12:51:00.303Z
Ben Parizek
<p>We have a plugin with custom Element Types that allows a user to create a field layout using custom fields.</p>

<p>We understand how to setup a localized site and add translation files.  This question is specifically about how to add support for the user to be able to add content in multiple languages via the custom fields as they add new Entries to a Custom Element Type.</p>

<p>It would be nice to see a list of all the steps we need to consider.  Ideally, the answer could double as the page we would have read in the documentation instead of posting this question =)</p>

<p><strong>Update:</strong></p>

<p>For reference, these are the tables that appear to have a <code>locale</code> column in the default Craft database.</p>

<ul>
<li>craft_categorygroups_i18n</li>
<li>craft_content</li>
<li>craft_elements_i18n</li>
<li>craft_entrydrafts</li>
<li>craft_entryversions</li>
<li>craft_locales</li>
<li>craft_matrixblocks (ownerLocale)</li>
<li>craft_matrixcontent_body (and any other Matrix field's content table)</li>
<li>craft_routes</li>
<li>craft_searchindex</li>
<li>craft_sections_i18n</li>
<li>craft_templatecaches</li>
</ul>

<localization><elementtype>
How do you add support to manage content in multiple languages in a plugin with a custom Element Type?
# How do you add support to manage content in multiple languages in a plugin with a custom Element Type?

(Asked by: username_0 on 2015-02-11)

We have a plugin with custom Element Types that allows a user to create a field layout using custom fields.

We understand how to setup a localized site and add translation files. This question is specifically about how to add support for the user to be able to add content in multiple languages via the custom fields as they add new Entries to a Custom Element Type.

It would be nice to see a list of all the steps we need to consider. Ideally, the answer could double as the page we would have read in the documentation instead of posting this question =)

**Update:**

For reference, these are the tables that appear to have a `locale` column in the default Craft database.

* craft\_categorygroups\_i18n
* craft\_content
* craft\_elements\_i18n
* craft\_entrydrafts
* craft\_entryversions
* craft\_locales
* craft\_matrixblocks (ownerLocale)
* craft\_matrixcontent\_body (and any other Matrix field's content table)
* craft\_routes
* craft\_searchindex
* craft\_sections\_i18n
* craft\_templatecaches

**Tags:** localization, elementtype


---

## 2 answers

### Answer by username_1 on 2016-04-02. Score: 2

It all starts in Your `ElementType` where you need to return `true` on the `isLocalized` function (Line 62 in `BaseElementType.php`).

Setting this to true will tell Craft that data is stored per-locale, and it's local choices are based on your Element Model's `getLocales` function. You can get a basic example from Line 231 of `BaseElementModel.php`.

Craft's Entry Element actually allows you to choose which locale's are used on a per section basis. You can see an Entry gather its locales on Line 54 in `EntryModel.php` and Line 57 in `SectionModel.php`. A section stores its locale options in a related table via `SectionLocaleRecord`.

The rest should be handled by Craft so long as you set `localeEnabled` to `true` and `locale` to a locale ID in your model before passing it along to `saveElement`.

The rest of the work is templating, which you can reference how P&T do it in `templates/entries/_edit.html`.

> **Comments:**
> **username_0**: Thanks Bryan. This is a good start. It seems a custom element type would also have to create/manage a second table for the locale such as the `craft_sections_i18n` or `craft_categorygroups_i18n` table. These tables appear to manage information that is specific to the element type and how the locales need to behave for it.  For example, the `craft_sections_i18n` table has an `enabledByDefault` setting and the category groups table doesn't.  
> **username_1**: Hrm... Then I will dig deeper and correct my answer.  
> **username_0**: More topics worth explaining for a canonical answer would be what javascript is being used and how the element data is being handled when saving Elements. `craft.js` has a `Craft.ElementEditor` which includes a `switchLocale` method and calls `elements/getEditorHtml` and an `updateForm` method.  How does the element save data for multiple locales? Does the `saveEntry` method happen once per locale? Or do all the fields and custom field inputs get namespaced when an entry is submitted?  When I use the locale switcher for Entries, it appears the title field for both locales is `name="title"`  

---

### Answer by username_0 on 2016-09-02. Score: 1

I don't believe myself to be an authority on this topic, nor this answer to be complete, but below I try to pull together a summary of several of the things you'll want to consider when adding localization to your plugins. Please correct me where I'm wrong and I'll try to make updates to this as I learn more until proper documentation exists.

Adding localization to your plugin will require addressing at least three different scenarios in the Control Panel:

How are you saving your data in a localized way?
How are you retrieving your data in a localized way?
How are you managing the UI around switching between locales?

While there may be related settings, the primary thing that gets localized in Craft is the Element.  As you localize your plugin you may need to ask: how does what I am trying to add localization support for relate to the Elements in the system?
Craft-managed tables that relate to localization
I believe Craft will manage the locale-specific behavior for several tables in the database for you:

craft_elements_i18n
craft_locales
craft_routes
craft_searchindex
craft_templatecaches

Element-specific tables that relate to localization
Each respective Element Type will need to manage and make sure locale-related data is saved to the tables that relate to that specific Element Type.
In the case of Entries, Entries manage locale-specific data in the following tables:

craft_content
craft_entrydrafts
craft_entryversions
craft_sections_i18n

Categories manage locale-specific data with different requirements:

craft_categorygroups_i18n
craft_content

Localization and Field Types
Many fields get added directly to Elements via Field Layouts. By default, fields store the data they save as a field-specific column on the content table that relates to the Element the field has been added to. An Entry With a Plain Text field named stuff will store it's data in the craft_content table with the column name field_stuff.
For fields that use this default method of storing their data, you do not need to add additional localization support. The craft_content table already has a locale column and populating that value will be handled by the Element that your field is assigned to.
For custom fields that are advanced enough to require a field-specific database table to store their data (consider an Address Field, perhaps), the plugin developer will need to add locale support (discussed in more detail below).

How are you saving your data in a localized way?
Elements
Craft does not do much to help you save your Element data in a locale-friendly way. You'll need to manage a lot of this on your own.
To start off, you'll want to give your Element an isLocalized method and return true. One class to read up on to understand a bit more about how localization works on Element Types is the IElementType Class.
While Craft appears to manage saving the locale data to craft_elements_i18n for you, it appears Elements that support locales also have a secondary i18n table that relates to something that I don't know what to call but tend to refer to as the Element Group. The Element Group for Entries is Sections, for Categories is Category Groups, for Craft Commerce Products is Product Types.
Entries

craft_sections
craft_sections_i18n

Categories

craft_categorygroups
craft_categorygroups_i18n

Commerce Products

craft_commerce_producttypes
craft_commerce_producttypes_i18n

It would seem that if your Element has URL support, and those URL Format settings are managed on the Element Group for that Element, you will need a similar i18n table in your plugin for your Element.
Advanced Fields
Advanced fields will need to:

Add a locale column to the database table that stores their field info
Populate that locale column while saving data to their custom table in the Field Types onAfterElementSave method. The locale ID can be found via $this->element->locale value in your Field Type class.


How are you retrieving your data in a localized way?
Elements
When Elements are retrieved from the database using an Element Query, the Element Types modifyElementsQuery() method will be called. This gives the Element a chance to make changes to the query and is where you will need to update the query to ensure that the locale is being considered.
This is discussed in this question here and seems to make sense, however, it doesn't appear to be used in the Entry or Category Elements and I cannot explain why.
Advanced Fields

Retrieve the locale-specific record from the database when retrieving the field data in the getInputHtml method.  The locale ID can be found via $this->element->locale value in your Field Type class.


How are you managing the UI around switching between locales?
When a user switches between locales while editing an Entry a few things need to happen. Craft appears to manage this with entries in part by reloading the page which probably also means they are re-querying the database for the content specific to the locale of the page being loaded.
http://happylager.dev/admin/entries/news/slug-1/en_us
http://happylager.dev/admin/entries/news/slug-1/es

The switch may actually be triggered by javascript. craft.js has a class called Craft.ElementEditor which includes a switchLocale method and calls elements/getEditorHtml and an updateForm method. I don't know much more than that!
The input field values for the locale will need to be updated to the locale ID of the locale you want to save your data for:


You will want to give visual indications of which locale is in use as well. This may include the controls the user uses to switch between languages as well as pass the locale value to any form macros that should display a locale indicator.
{{ forms.textField({
    label: "Title"|t,
    locale: element.locale,
    name: 'title',
    value: element.title,
    errors: element.getErrors('title'),
}) }}

The locale attribute in the above macro will output a locale specific indicator in the label tag of the form: {{ locale }}.


---

