Localization & Translation

How to handle multiple languages in your TYPO3 RestApi

The TYPO3 RestAPI supports retrieving localized (translated) data from the TYPO3 backend.

Localized data could be…

  • records, models or data from any database table
  • individual content elements from pages in the backend
  • complete pages or columns with all content elements
  • configuration-arrays, TypoScript setup arrays etc.
  • translated labels from the TCA to be used in forms in your frontend application


  1. Prerequisites

    In the following example we are assuming that you plan to use the standard TYPO3 procedure to create localized records in the backend:

    • You have defined your languages in your site-configuration, either using the backend module “Sites” or by editing the site’s config.yaml
    • Important: Add a page translation to the root-page of your site (the page that will be resolved when opening https://www.yoursite.com/) for every localization you have configured in the config.yaml
    • You have translated your content-elements or records in the backend and all records are in “connected” mode
    • You have created an Endpoint that returns data or content elements like described in this example
  2. Enable localization in the TYPO3 RestAPI:

    By default, localization is disabled for the TYPO3 RestApi.

    There are two ways to get it up and running. Depending on your use-case, choose one of the following options:

    Enable global localization

    Allow localization for ALL records by setting enabled = 1 in your TypoScript setup:

    plugin.tx_nnrestapi.settings.localization.enabled = 1

    —- OR —-

    Enable localization on a per-endpoint base

    Use this Annotation at your method to enable localization only for individual methods:

  3. Request the language

    Once you have localization enabled you can retrieve the translated records by sending a requests using one of the following options:

    • Add a Accept-Language header to the request, e.g Accept-Language: en-US
    • Use the ?L= parameter in the URL with the languageId, e.g. ?L=1
    • Use the language path in the URL when sending requests to the api, e.g. /en/api/endpoint/

Frontend examples


$url = 'https://www.mysite.com/api/endpoint';
$language = 'en-EN';

$headers = [
   'Accept: application/json',
   'Accept-Language: ' . $language

$curl = curl_init();
curl_setopt($curl, CURLOPT_URL, $url);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
curl_setopt($curl, CURLOPT_HTTPHEADER, $headers);

// only include if you are having problems with SSL certificate
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, 0);

$json = curl_exec($curl);

$data = json_decode( $json, true );

$dump = htmlspecialchars( print_r( $data, true ) );
echo "<pre>{$dump}";
const url = 'https://www.mysite.com/api/endpoint';
const language = 'de-DE';

const xhrConfig = {
   method: 'GET',
   headers: {
      'Content-Type': 'application/json',
      'Accept-Language': language

fetch( url, xhrConfig )
      .then( async response => {

      let data = await response.json()

      if ( !response.ok ) {
         alert( `Error ${response.status}: ${data.error}` );
      } else {
         console.log( data );
         document.getElementById('result').innerText = data.html;
var url = 'https://www.mysite.com/api/endpoint';
var language = 'en-EN';

var xhr = new XMLHttpRequest();

xhr.open('get', url);
xhr.setRequestHeader('Accept-Language', language);

xhr.onload = function () {
   var data = JSON.parse( xhr.responseText );
   if (xhr.status != 200) {
   console.log( data );

xhr.onerror = function () {
   alert('Some other error... probably wrong url?');

const url = 'https://www.mysite.com/api/endpoint';
const language = 'en-EN';

const headers = {
   'Accept-Language': language

   method: 'get',
   url: url,
   headers: headers
}).then( ({data}) => {
   console.log( data );
}).catch( ({response}) => {
   console.log( response.data );
const url = 'https://www.mysite.com/api/endpoint';
const language = 'en-EN';

const headers = {
   'Accept-Language': language

   url: url,
   type: 'GET',
   headers: headers
}).done((data) => {
   console.log( data );
}).fail((error) => {
   alert( `Error ${error.status}: ${error.responseJSON.error}` );

More examples?

You can find more explanations and examples in the following chapters:

Dive deeper?

If you are interested to find out more about localization in TYPO3 and the reason why it is not a trivial topic, head on to this chapter.