1. PHP BASED TRANSLATIONS
Translations let you display the same page in different languages. Store your text in App/media/translations/translations.php, then use translate() in your templates.
Language Settings
Start with the language settings in config/config.php:
define("ENABLE_LANGUAGES", true);
define("DEFAULT_LANGUAGE", "en");
define("AVAILABLE_LANGUAGES", ["en", "fi", "sv"]);
Use lowercase language codes, and include the default language in the available languages.
With ENABLE_LANGUAGES enabled, URLs begin with a language code, such as /en/home/. The router reads that code to choose the page’s language. A missing or unsupported code redirects to the default-language homepage.
Note!
Register ordinary routes with their language prefixes, as shown in Routes. Only homepage language routes are added automatically.
See Defining Routes for the registration example. You can still use translate() when URL language prefixes are disabled.
Adding Translations
Add your text to the array returned by translations.php. Each text key has a value for each language:
<?php
return [
"Welcome" => [
"en" => "Welcome",
"fi" => "Tervetuloa",
"sv" => "Välkommen",
],
"Save changes" => [
"en" => "Save changes",
"fi" => "Tallenna muutokset",
"sv" => "Spara ändringar",
],
];
Use that key in your template:
<h1><?= esc_html(translate("Welcome")); ?></h1>
<button type="submit"><?= esc_html(translate("Save changes")); ?></button>
When the selected language is Finnish, the heading displays “Tervetuloa”. esc_html() makes the translated text safe to display in HTML.
If a key or language value is missing, translate() returns the original key. Missing translations are logged when debug logging is enabled.
Variables in Translations
Use %s for a changing piece of text, such as a name. Add this entry to the same translation array:
"Hello, %s!" => [
"en" => "Hello, %s!",
"fi" => "Hei, %s!",
"sv" => "Hej, %s!",
],
Pass the name as the second argument to translate():
<p><?= esc_html(translate("Hello, %s!", ["Alex"])); ?></p>
This displays “Hello, Alex!” in English or “Hei, Alex!” in Finnish. For more than one placeholder, pass the values in the same order. PHP’s vsprintf() handles the replacements.
Changing the PHP Language
Use getAppLocale() to read the selected language and setAppLocale() to change it:
$language = getAppLocale();
setAppLocale("fi");
Only languages listed in AVAILABLE_LANGUAGES are accepted.
When URLs include a language code, the next page request uses that code again. To switch to Finnish and open its homepage:
setAppLocale("fi");
redirect(route(""));
2. JAVASCRIPT BASED TRANSLATIONS
JavaScript translations update text in the browser without reloading the page. The javascript based translations are stored in a json file located at App/media/translations/translations.json.
Note!
The PHP and JSON translation files are separate. If you use both approaches, add the text to each file where it is needed.
Important!
Javascript based translations are not good for search engine optimization.
Adding Translations
Add your text to translations.json:
{
"Welcome": {
"en": "Welcome",
"fi": "Tervetuloa",
"sv": "Välkommen"
},
"Save changes": {
"en": "Save changes",
"fi": "Tallenna muutokset",
"sv": "Spara ändringar"
},
"Your name": {
"en": "Your name",
"fi": "Nimesi",
"sv": "Ditt namn"
}
}
Each key contains the text for every language you offer. Use valid JSON with double quotes and no trailing commas.
Translating Page Content
Add a translationKey attribute that matches a key in the JSON file:
<h1 translationKey="Welcome">Welcome</h1>
<button type="button" translationKey="Save changes">Save changes</button>
<input type="text" translationKey="Your name" placeholder="Your name">
The translator replaces the heading and button text. For an input with a placeholder, it changes the placeholder instead. On images, it changes the alt text.
Important!
Keep translation files under your control. Normal text elements receive translated HTML. Include every selectable language for each key; the browser helper does not provide the same missing-language fallback as PHP.
Changing the Browser Language
Add these buttons to your page template:
<button type="button" id="en-button" switchLanguage="en">English</button>
<button type="button" id="fi-button" switchLanguage="fi">Suomi</button>
<button type="button" id="sv-button" switchLanguage="sv">Svenska</button>
Clicking a button updates the translated elements. The matching button receives the active class, which you can style in your stylesheet.
Once the JSON file has loaded, you can also change the language from your own JavaScript:
setLanguage("fi");
The browser saves the selection in localStorage under Kristal_Language. On the next visit, it uses that saved language first, then the language supplied by PHP, then English.
Note!
Browser language changes do not change the PHP session, URL or HTML lang attribute. A saved browser language can differ from the language used to render the page in PHP.
Translating Tooltips
For Bootstrap tooltips, add tooltipTranslationKey:
<button type="button"
data-bs-toggle="tooltip"
data-bs-title="Save changes"
tooltipTranslationKey="Save changes"
translationKey="Save changes">
Save changes
</button>
The helper updates the tooltip text and recreates the Bootstrap tooltip. Bootstrap’s JavaScript must be loaded; it is included by the supplied header.
New Elements and Troubleshooting
If your JavaScript adds an element after the first translation pass, translate it after adding it. For an element with the ID new-message and a translationKey attribute:
$("#new-message").translate();
Call this after the JSON file has loaded. For a new tooltip, use .tooltipTranslate() instead.
If text doesn’t change, check the browser console, JSON file URL and translation keys. The browser helper does not replace PHP-style placeholders such as %s.
If edits to the JSON file don’t appear, reload with the browser cache disabled. The current translator checks production mode against the string “false”, while PHPJS supplies a boolean, so its automatic development cache refresh does not activate.
