Appearance
Languages
Overview
Language settings control which languages your vendor offers. You add languages from a fixed supported list, publish them so customers can see them, and pick one published language as the vendor default.
Key Purpose: Configure the set of languages available to customers and choose a default language.
Purpose
This page lets you add, publish, unpublish, delete, and set a default language. Each language you add is created in Unpublished status; only published languages are exposed to customers. The vendor-level default language is used as the fallback throughout the platform.
Key Concepts
- Language as a record: Each language is a document in the tenant
settingscollection withmodel = "language". A language record stores only aname(e.g. "Dutch") and astatus(PublishedorUnpublished). It has no per-channel or toggle fields. - Supported language set: Languages are not free text. The selectable names come from a fixed converter map (
Constants::$LANGUAGE_CONVERTER): Dutch, French, German, Portuguese, Spanish, English, Italian. Each maps to an ISO code (nl,fr,de,pt,es,en,it). The default-language fallback name is English. - Language Status: A language is
Published(visible to customers / returned by the options endpoint) orUnpublished(only visible in the back office). Status is the only editable attribute of a language. - Default Language: The vendor default is stored on the merchant document as
default_language(an ObjectId reference to a language record), not on the language itself. Setting a default also switches the back-office UI locale to that language's ISO code. - Location Preferred Language: Each location stores a
preferred_language, which is the ObjectId of a language record (not an ISO code). A location's preferred language must reference an existing language in thesettingscollection. - Translation Completeness Check:
LanguageService::checkTranslation($language)reports, per entity type, whether any record is still missing a translation in the given language. TheGET /check-incompleteendpoint surfaces this per language. - Auto-Translate Receipt Settings on Create (queued): Adding a language fires a
LanguageCreatedevent; a queued listener (TranslateReceiptSettingsForLanguage, 3 tries with 30/60/120s backoff) then callsReceiptSettingService::translateReceiptSettingForCurrentMerchant, which loops the merchant's locations translating each one's receipt custom text. Because it runs on the queue, the translations appear shortly after the language is created rather than instantly, and they can fail independently of the language itself.
Actions
Add a Language
Open the "Add Language" dialog and pick a name from the list of supported languages that have not already been added. The language is created in Unpublished status, and a queued background job then translates every location's receipt custom text into it — so those translations appear shortly after, not the instant the dialog closes. Languages are not visible to customers until published.
Publish a Language
Publish an unpublished language so it becomes visible to customers and is returned by the language-options endpoint. Publishing fires a ReloadMenu event for every location so devices refresh.
Unpublish a Language
Move a published language back to unpublished. Unpublishing is blocked if the language is the vendor default, or if any location uses it as its preferred_language (the error names the affected location). Unpublishing fires a ReloadMenu event for every location.
Set Default Language
Designate a published language as the vendor default. Attempting to set an unpublished language as default returns a 400 error. Setting the default also changes the back-office interface language to that language.
Delete (Remove) a Language
Delete an unpublished language. Deleting is blocked if the language is the vendor default. (Soft delete; the language record is removed from active records.)
Check Translation Coverage
The /check-incomplete endpoint reports which entity types still have missing translations for each language. See the Business Rules section for the exact entities checked.
Location
- Backoffice Route:
/settings/languages - Backend Controller:
app/Http/Controllers/Api/LanguageController.php - Backend Service:
app/Services/BackOffice/Settings/LanguageService.php - Vue Component:
src/views/settings/LanguagesComponent.vue(add dialog:src/components/dialogs/AddLanguageDialog.vue)
API Endpoints
All routes are under the back-office settings prefix (/back-office/settings/languages):
| Method | Path | Action |
|---|---|---|
| GET | /back-office/settings/languages/ | List all languages (all) |
| GET | /back-office/settings/languages/check-incomplete | Translation completeness per language |
| POST | /back-office/settings/languages/ | Add a language (create) |
| POST | /back-office/settings/languages/set-default/{id} | Set default language |
| POST | /back-office/settings/languages/publish/{id} | Publish a language |
| POST | /back-office/settings/languages/unpublish/{id} | Unpublish a language |
| DELETE | /back-office/settings/languages/delete/{id} | Delete a language |
The selectable language names for the Add Language dialog come from GET /lang-options (ConstantController::langOptions), which returns the 7 supported names from Constants::$LANGUAGE_CONVERTER as plain strings; the dialog then filters out names that have already been added.
GET /back-office/language-options (LanguageController::options) is a different endpoint: it returns only published languages (id + name) and feeds the location form's preferred_language picker, not the add dialog.
Fields
A language record has only two stored fields. There are no auto-detect, show-selector, per-channel, or "available languages" multi-select fields.
Name
| Property | Value |
|---|---|
| Field ID | name |
| Type | Select (from supported list) |
| Required | Yes |
Description: The language name. Must be one of the supported values below. The create endpoint validates language as a required string; the UI restricts the choice to supported, not-yet-added names.
Supported Languages (from Constants::$LANGUAGE_CONVERTER):
| Name | ISO Code |
|---|---|
| English | en |
| Dutch | nl |
| French | fr |
| German | de |
| Spanish | es |
| Portuguese | pt |
| Italian | it |
Status
| Property | Value |
|---|---|
| Field ID | status |
| Type | Enum |
| Values | Published, Unpublished |
| Default | Unpublished (on create) |
Description: Whether the language is visible to customers. Changed via the publish / unpublish actions, never edited directly.
Default Language (merchant-level)
| Property | Value |
|---|---|
| Field ID | default_language (on the merchant document) |
| Type | ObjectId reference to a language record |
Description: The vendor's default language. Not a field on the language record itself; it is stored on the merchant. Only a published language may be set as the default.
Preferred Language (location-level)
| Property | Value |
|---|---|
| Field ID | preferred_language (on each location) |
| Type | ObjectId reference to a language record (string ID, validated to exist) |
Description: A location's own preferred language, referencing a language record by its ObjectId — not an ISO code. Configured on the location, not on this page. Used to block unpublishing a language still in use.
Customer-Facing Display
How published languages are rendered in the customer storefront, Online Ordering, and Kiosk (language selector, menu translation display, receipt language) is handled in those channels and is not verified here. This page only controls which languages exist, their published status, and the vendor default.
Relations
Depends On
- Locations: Each location references a language via
preferred_language(ObjectId). - Merchant: Stores the vendor
default_language(ObjectId).
Affects
- Translations: Which languages content can be translated into.
- Online Ordering / Kiosk: Which languages are offered to customers (rendering not verified here).
- Receipts: Adding a language auto-translates receipt custom text per location (queued, shortly after creation).
Related Features
Business Rules
- A language must be
Publishedbefore it can be set as the vendor default; setting an unpublished language as default aborts with 400 "The language should be published first before setting it as the default". - The default language cannot be unpublished; the request aborts with 400 "Can't unpublish the default language."
- The default language cannot be deleted; the request aborts with 400 "Can't remove the language since it is the default language".
- Unpublishing is blocked if any location uses the language as its
preferred_language; the error names the affected location (e.g. "Can't unpublish the language since it is used by in<Location>") and appends " and N more" when more than one location is affected. - Adding a language with a name that already exists aborts with 400 "Duplicate language" (unless called internally with
throw = false, in which case the existing record is returned). - Adding a language auto-translates receipt custom text into the new language for every location of the current merchant. This runs asynchronously on the queue (
LanguageCreated→TranslateReceiptSettingsForLanguage, 3 tries, 30/60/120s backoff), so it completes shortly after the language is created and can fail without failing the language creation. - Publishing and unpublishing each fire a
ReloadMenuevent for every location so devices refresh; deleting firesReloadMenuonly if the deleted language was published. - Translation completeness (
check-incomplete) checks these entity types: Items, Display Groups, Variant Groups, Categories, Modifiers (modifier groups and their modifiers), Loyalty rewards, Table Sections, plus order/pager instructions and the upsell screen. Notifications and Receipts are placeholders (TODO) and are not yet checked.
FAQs
- "Why can't I unpublish a language?" Either it is the vendor default, or a location is using it as its preferred language. Change the default or update the location's preferred language first.
- "What happens when I add a new language?" It is created in Unpublished status (not yet visible to customers), and a background job then translates receipt custom text for every location into it — those translations show up shortly after, not immediately.
- "Which languages can I add?" English, Dutch, French, German, Spanish, Portuguese, and Italian. Already-added languages are filtered out of the add dialog.
- "Why aren't customers seeing a language I added?" New languages are Unpublished by default; publish it to make it visible to customers.
- "Can each location have a different language?" Each location has its own
preferred_languagereference, but the vendor-wide default language is the global fallback. - "What entities are checked for translation completeness?" Items, display groups, variant groups, categories, modifiers, loyalty rewards, table sections, and order/pager instructions and the upsell screen.
Troubleshooting
Problem: Can't set a language as default
Causes:
- The language is still Unpublished.
Solutions:
- Publish the language first, then set it as default.
Problem: Can't unpublish or delete a language
Causes:
- It is the vendor default language.
- (Unpublish only) A location uses it as its preferred language.
Solutions:
- Set a different published language as default first.
- Change the affected location's preferred language, then retry.
Problem: "Duplicate language" when adding
Causes:
- A language with that name already exists.
Solutions:
- The language is already added; find it in the published or unpublished list instead.
Examples
A language record (as stored)
json
{
"_id": "665f1a2b3c4d5e6f70819203",
"model": "language",
"name": "Dutch",
"status": "Published"
}Language as returned by the list endpoint (LanguageResource)
json
{
"id": "665f1a2b3c4d5e6f70819203",
"name": "Dutch",
"status": "Published",
"is_default": true,
"iso": "nl"
}Published-language option for the location picker (LanguageOptionResource, from /back-office/language-options)
json
{
"id": "665f1a2b3c4d5e6f70819203",
"name": "Dutch"
}Adding a language (request body)
json
{
"language": "French"
}Merchant default and location preferred language (references)
json
{
"merchant": {
"default_language": "665f1a2b3c4d5e6f70819203"
},
"location": {
"preferred_language": "665f1a2b3c4d5e6f70819203"
}
}Both default_language (merchant) and preferred_language (location) hold the ObjectId of a language record, not an ISO code.