Database value localization


Outlast Framework makes it easy to store localized text translations in the database. You can save a localized value for any model data and it will act very much like a normal, unlocalized field does. You can access these features once of you have set up and enabled locales for your project.

Fetching data in the current language

Normal way of fetching data in a template:

{{object.data.description}}

The translation-supported way of fetching data in a template:

{{object.translation.description}}

This will work on all fields that are translation-enabled and will return the data in the currently selected language.

Fetching data in PHP is a bit different. Each translation is actually a zajModelLocalizerItem object which happens to implement __toString() and jsonSerialize, so you are able to use echo/print and json_encode() directly on the variable:

echo $object->translation->description;
json_encode(array('id'=>$object->id, 'translation'=>$object->translation->description));

However in certain custom situations you may want to get the actual underlying value (instead of the zajModelLocalizerItem object). For these situations, check out the class documentation.

Fetching data in other languages

If you want to translate data to another language (not the currently selected one) you’ll need to use the |translate filter. This filter takes one parameter, the locale of the language you wish to get the translation in.

{{product.data.name}} <!-- prints the name of the product in the default language/locale -->
{{product.translation.name}} <!-- prints the name of the product in the currently selected language -->
{{product.translation.name|translate:'de_DE'}} <!-- prints the name of the product in the specified language (German in this case) -->

The same can be done in PHP using the zajModelLocalizerItem object (see docs). Since all translation data is retreived as a zajModelLocalizerItem, you can do the following:

$product->translation->name->get_by_locale('de_DE');

Fetching connections

From a template, fetching connections is no different from the usual method:

{{product.translation.wppost.title}} <!-- prints the title of the localized WpPost -->

However, if you are accessing the connections programmatically, you will need to add an additional method. Here’s why:

$product = Product::fetch('an_id'); // Fetch a specific product
// For regular fields, it works as expected...
$default_name_of_product = $product->data->name;
$localized_name_of_product = $product->translation->name;
// For translated connections, there's an added complication...
$default_wordpress_post_object = $product->data->wppost; // This will be a usual WpPost object
$translated_connection_object = $product->translation->wppost; // Instead of the translated WpPost, this will be a zajModelLocalizerItem object (for technical reasons)
$translated_wordpress_post_object = $product->translation->wppost->get(); // Now this is the localized WpPost object!
$translated_wordpress_post_title = $product->translation->wppost->get()->title; // As seen here, you can then directly chain methods and properties of WpPost...

Generating input fields for editing

When you create admin interfaces, you’ll want to easily generate input fields for translation-ready fields. To create an input area, simply use the {% inputlocale %} tag:

{% inputlocale product.name product.translation.name 'de_DE' %}

It’s pretty easy to loop this so that all inputs are displayed for each language/locale:

{% if ofw.locale_all|count > 1 %}
  {% foreach ofw.locale_all as locale %}
    {% if locale != ofw.locale_default %}
      <div class="well">
        <strong>{{locale}}</strong>
        <label>{{#product_name#}}: {% inputlocale product.name product.translation.name locale %}</label>
        <label>{{#product_intro#}}: {% inputlocale product.intro product.translation.intro locale %}</label>
      </div>
    {% endif %}
  {% endforeach %}
{% endif %}

Updating, setting data

Locale inputs are generated such that they send data as $_POST['translation']['name_of_field']['en_US']. This means that when the data is submitted, it is easy to run through and save all the translation values. But how and where to save it? Good question! 🙂

There are two methods of saving localized data. First is batch-saving. This is the recommended method:

$pobj = Product::fetch();
// Set the original language for all fields
$pobj->set_these('name', 'intro', 'featured');
// Set translations for relevant fields
$pobj->set_translations('name', 'intro')->save();

This will save all the locales that were included in the form for each of the fields. Note that you must also use set_these() if you want to also set the default locale’s regular {% input %} fields. The set_translations() method will only set data from {% inputlocale %} tags.

The second method is to save one-by-one. This is only recommended if you need greater control over validation and saving of data:

$pobj = Product::fetch();
$pobj->set_translation('name', $_POST['translation']['name']['en_US'], 'en_US');
$pobj->set_translation('intro', $_POST['translation']['intro']['en_US'], 'en_US');
$pobj->set_translation('name', $_POST['translation']['name']['hu_HU'], 'hu_HU');
$pobj->set_translation('intro', $_POST['translation']['intro']['hu_HU'], 'hu_HU');
$pobj->save();

Although you should use the set() method for your default locale, using set_translation() with the default locale is the same as calling set() – the data is saved directly with the model and not as a Translation object.

Outlast Web & Mobile Development (c) 2023 | Privacy Policy |