Languages & translations.
Manage supported languages, translations, and default locales.
Reward Loyalty runs in many languages. It detects a visitor's preferred language from their browser settings. You can manage active languages, add new translations, and set text direction.
Available languages
The app includes 12 pre-built translations:
| Code | Language | Direction | Status |
|---|---|---|---|
en_US |
English (United States) | LTR | Active by default |
de_DE |
German (Germany) | LTR | Inactive by default |
es_ES |
Spanish (Spain) | LTR | Inactive by default |
fr_FR |
French (France) | LTR | Inactive by default |
id_ID |
Indonesian (Indonesia) | LTR | Inactive by default |
it_IT |
Italian (Italy) | LTR | Inactive by default |
ja_JP |
Japanese (Japan) | LTR | Inactive by default |
nl_NL |
Dutch (Netherlands) | LTR | Inactive by default |
pl_PL |
Polish (Poland) | LTR | Inactive by default |
pt_BR |
Portuguese (Brazil) | LTR | Inactive by default |
tr_TR |
Turkish (Turkey) | LTR | Inactive by default |
ar_SA |
Arabic (Saudi Arabia) | RTL | Inactive by default |
RTL Support: Arabic includes full right-to-left support. All interface elements adjust for RTL languages.
How it works
The app uses a folder-based structure for languages. Each language lives in its own directory within lang/ (e.g., lang/en_US/, lang/pt_BR/).
When a user visits your site:
- The system checks their browser language
- If that language is active, it's shown
- If not, the system falls back to your default language (usually
en_US)
Managing languages
There are two ways to control which languages are active, that is, visible in the language selector and reachable by URL. The recommended way is a single .env setting. The per-folder flag is the fallback.
Activating languages with .env (recommended)
Set APP_ACTIVE_LOCALES in your .env file to a comma-separated allow-list. Only the listed locales are active, regardless of each folder's own config.php flag:
APP_ACTIVE_LOCALES="en_US,nl_NL"
To pick from everything that ships, copy the full list and remove the ones you don't want:
APP_ACTIVE_LOCALES="ar_SA,de_DE,en_US,es_ES,fr_FR,id_ID,it_IT,ja_JP,nl_NL,pl_PL,pt_BR,tr_TR"
This approach is recommended because:
- It lives in one place. All active languages sit on a single line instead of across twelve
config.phpfiles. - It survives updates. Updates always preserve your
.env, so your choice is never overwritten. They do not preserve edits toconfig.phpfiles unless you also protect them (see below). - Matching is forgiving. The app treats
en-us,EN_us, anden_USas the same locale.
Use full locale codes (en_US), not bare language codes (en). Include your default APP_LOCALE in the list, and make sure every entry is an installed locale (a folder under lang/).
Activating a language with config.php (fallback)
When APP_ACTIVE_LOCALES is empty, each language's own folder decides whether it is active:
- Navigate to the language's directory:
lang/<locale>/ - Open the
config.phpfile - Set
'active' => true
return [
'active' => true,
'dir' => 'ltr', // 'ltr' for Left-to-Right, 'rtl' for Right-to-Left
];
Precedence: When
APP_ACTIVE_LOCALESis set, it overrides everyconfig.phpactiveflag. When it is empty, the per-folder flag applies. In demo mode, all installed languages are active regardless of either setting.
Deactivating a language
To hide a language, remove it from APP_ACTIVE_LOCALES. If you use the fallback method instead, set 'active' => false in its config.php. You can also delete the language folder entirely if you're sure you won't need it.
Note: If only one language is active, the language selector hides itself.
Adding a new language
To add a language that isn't included:
- Copy the Base: Duplicate the
lang/en_US/folder - Rename: Rename the new folder to your target locale (e.g.,
nl_NLfor Dutch)- Format:
language_COUNTRY(ISO 639-1 language code + ISO 3166-1 country code)
- Format:
- Translate: Open the files inside the new folder and translate the values
- Activate: Add the new locale to
APP_ACTIVE_LOCALESin.env(or, using the fallback method, set'active' => truein itsconfig.php)
Language file structure
Each language folder contains:
lang/en_US/
├── config.php # Active status and text direction
├── common.php # Main interface strings
├── validation.php # Form validation messages
├── otp.php # Login and verification messages
├── faq.php # FAQ questions and answers (the qa array)
├── install.php # Installer text
├── javascript.php # Strings used by front-end scripts
├── agent.php # Agent API and agent key strings
├── business-page.php # Public business page strings
├── card-studio.php # Card studio designer strings
├── member-cards.php # Member cards feature strings
├── pwa.php # PWA offline page strings
├── qr-studio.php # QR studio strings
└── md/ # Markdown content pages
├── about.md # About page
├── contact.md # Contact page
├── privacy.md # Privacy policy
└── terms.md # Terms of service
Note: Copy from
en_USwhen you create a new language. It is the one folder guaranteed to be complete:install.phpis absent inar_SAandpt_BR.
Editing content pages
The About, Contact, Privacy Policy, and Terms pages are stored as Markdown files.
To edit one of these pages:
- Go to
lang/<locale>/md/ - Open the relevant
.mdfile (for example,privacy.md) - Edit the text using Markdown syntax. The
title,description, andiconat the top of the file (the frontmatter) set the page's heading and hero.
The FAQ is different. It is not a Markdown page. Its questions and answers live in
lang/<locale>/faq.php, inside theqaarray, each entry has aq(question) and ana(answer), and answers may include light HTML. Edit that file to change, add, or remove questions.
Setting the default language
If your application should default to a language other than English, add these variables to your .env file:
APP_LOCALE=pt_BR
APP_FALLBACK_LOCALE=pt_BR
| Variable | Purpose |
|---|---|
APP_LOCALE |
The primary language shown to visitors |
APP_FALLBACK_LOCALE |
Used when a translation key is missing in the current language |
Protecting custom translations during updates
⚠️ Important: When you add or modify translations, you must protect them from being overwritten during automatic updates.
Activation vs. preservation: two different settings.
APP_ACTIVE_LOCALEScontrols which languages are visible.PROTECTED_TRANSLATIONScontrols which language folders survive updates. They are independent: activating a language does not protect its files, and protecting a folder does not make it active. If you translate or customize a language, set both: add the locale toAPP_ACTIVE_LOCALESso people see it, and toPROTECTED_TRANSLATIONSso your edits aren't overwritten on the next update.
Add your custom translation directories to your .env file:
# Protect custom German and French translations
PROTECTED_TRANSLATIONS="de_DE,fr_FR"
Multiple directories are separated by commas. These paths are relative to the lang/ folder.
Why this matters
When you update Reward Loyalty:
- The updater replaces core language files with new versions
- Any customizations you made would be lost
- The updater backs up and restores protected paths
What to protect
Protect any language folder where you have:
- Translated content for a new language
- Modified existing translations
- Added custom Markdown content (privacy policy, terms, etc.)
Protecting other custom files
For custom files or directories outside of translations:
# Protect additional custom paths
PROTECTED_PATHS="custom/branding/,my-config.php"
Learn more: See Updating for complete documentation on how updates work and file preservation.
Related topics
- Updating: How updates work and protecting custom files
- Branding: Customize your installation appearance
- System settings: All admin configuration options