This document explains how to configure and override locale strings (text labels) in the IPification Showcase application.
- Overview
- Locale File Structure
- Default Locale File
- Overriding Locale Strings
- Deep Merging Behavior
- Using Locale in Views
- Locale Structure Reference
- Best Practices
- Troubleshooting
- Implementation Details
- Related Documentation
- Examples
The application uses a locale system that allows you to customize all text labels displayed in the user interface. Locale strings are stored in config/locale.json and can be overridden in config/default.json for environment-specific customizations. For config field details, see Sample Config Reference.
The locale system is organized into logical sections:
{
"app": {
"name": "Application name displayed in header"
},
"tabs": {
"pnv": "PNV tab label",
"login": "Login tab label",
"identity": "Identity tab label"
},
"sections": {
"pnv": {
"title": "Section title",
"description": "Section description text",
"button_ip_label": "Optional: Override IP button label for PNV",
"button_ip_plus_label": "Optional: Override IP+ button label for PNV",
"button_im_label": "Optional: Override IM button label for PNV",
"button_sim_label": "Optional: Override SIM button label for PNV",
"button_ip_via_app_label": "Optional: Override IP via App button label for PNV"
},
"login": {
"title": "Section title",
"description": "Section description text",
"button_ip_label": "Optional: Override IP button label for Login",
"button_ip_plus_label": "Optional: Override IP+ button label for Login",
"button_im_label": "Optional: Override IM button label for Login",
"button_sim_label": "Optional: Override SIM button label for Login"
},
"identity": {
"title": "Section title",
"description": "Section description text",
"button_anonymous_identity_label": "Optional: Override Anonymous Identity button label",
"button_kyc_label": "Optional: Override KYC button label"
}
},
"buttons": {
"ip": "IP button label",
"ip_plus": "IP+ button label",
"im": "IM button label",
"sim": "SIM button label",
"ip_via_app": "IP via App button label",
"anonymous_identity": "Anonymous Identity button label",
"kyc": "KYC button label"
},
"footer": {
"viettel_legal": "Legal disclaimer text",
"viettel": "Viettel brand name",
"privacy_policy": "Privacy Policy link text",
"about": "About link text",
"help": "Help link text"
},
"modals": {
"about_title": "About modal title",
"server_label": "Server label",
"state_label": "State label",
"developer_link": "Developer link text",
"phone_required": "Phone number required error message",
"phone_invalid": "Invalid phone number error message"
}
}The default locale strings are stored in config/locale.json. This file contains all the standard English text labels used throughout the application.
Location: config/locale.json
Purpose: Base locale strings that are used by default.
You can override any locale string by adding a locale section to your config/default.json file. See Sample Config Reference for the full config layout. The override system uses deep merging, which means:
- You can override individual nested properties without replacing entire sections
- Only the properties you specify will be overridden
- All other properties will remain from the default locale file
- The application loads
config/locale.jsonas the base locale - If
config/default.jsoncontains alocalesection, it merges the override values - The merged locale is made available to all views via
res.locals.locale
{
"realm": "ipification",
"auth_servers": [...],
"clients": [...],
"locale": {
"app": {
"name": "My Custom IPification App"
}
}
}{
"locale": {
"tabs": {
"pnv": "Phone Verification",
"login": "User Login",
"identity": "User Identity"
}
}
}{
"locale": {
"sections": {
"pnv": {
"title": "Verify Your Phone Number",
"description": "Use IP or IM authentication to verify your phone number."
},
"login": {
"title": "Quick Login",
"description": "Sign in using IP or IM authentication with automatic phone number sharing."
}
}
}
}{
"locale": {
"buttons": {
"ip": "Internet Protocol",
"ip_plus": "IP Plus",
"im": "Instant Messaging",
"kyc": "Know Your Customer"
}
}
}{
"locale": {
"app": {
"name": "Custom Brand Name"
},
"tabs": {
"pnv": "Verification",
"login": "Access"
},
"sections": {
"pnv": {
"title": "Phone Verification",
"description": "Verify your phone number"
}
},
"buttons": {
"ip": "IP Auth",
"im": "IM Auth"
},
"modals": {
"phone_required": "Please provide your phone number",
"phone_invalid": "The phone number format is incorrect"
}
}
}The locale override system uses deep merging, which means:
- Nested objects are merged: If you override
app.name, the entireappobject is not replaced, onlynameis updated - Partial overrides work: You can override just
sections.pnv.titlewithout affectingsections.pnv.description - Arrays are replaced: If a locale property is an array, the entire array is replaced (not merged)
Base locale.json:
{
"sections": {
"pnv": {
"title": "Phone Number Verification",
"description": "Verify phone number through IP or IM auth."
}
}
}Override in default.json:
{
"locale": {
"sections": {
"pnv": {
"title": "Custom Title"
}
}
}
}Result:
{
"sections": {
"pnv": {
"title": "Custom Title",
"description": "Verify phone number through IP or IM auth."
}
}
}Notice that description is preserved from the base locale.
Locale strings are automatically available in all Pug templates via the locale variable. Access nested properties using dot notation:
h3.app-name #{locale.app.name}
p.description_title #{locale.sections.pnv.title}
button #{locale.buttons.ip}Some locale fields support HTML tags for formatting. Use !{} instead of #{} to render HTML:
Escaped (default) - Use #{} for plain text:
p.description #{locale.sections.pnv.title}Unescaped (HTML) - Use !{} for HTML content:
p.description !{locale.sections.pnv.description}Supported HTML tags:
<br/>or<br>- Line breaks<b>,<strong>- Bold text<i>,<em>- Italic text<a>- Links- Other HTML tags as needed
Example with HTML:
{
"sections": {
"pnv": {
"title": "Phone Number Verification",
"description": "Basic - verify your phone number<br/>Advance - verify your phone number with fraud prevention signals"
}
}
}Note: Fields that support HTML are typically description fields. Title and button labels should remain plain text for consistency.
app.name- Application name displayed in the header
tabs.pnv- PNV tab labeltabs.login- Login tab labeltabs.identity- Identity tab label
sections.pnv.title- PNV section titlesections.pnv.description- PNV section descriptionsections.pnv.button_ip_label- Optional: Override IP button label for PNV sectionsections.pnv.button_ip_plus_label- Optional: Override IP+ button label for PNV sectionsections.pnv.button_im_label- Optional: Override IM button label for PNV sectionsections.pnv.button_sim_label- Optional: Override SIM button label for PNV sectionsections.pnv.button_ip_via_app_label- Optional: Override IP via App button label for PNV section
sections.login.title- Login section titlesections.login.description- Login section descriptionsections.login.button_ip_label- Optional: Override IP button label for Login sectionsections.login.button_ip_plus_label- Optional: Override IP+ button label for Login sectionsections.login.button_im_label- Optional: Override IM button label for Login sectionsections.login.button_sim_label- Optional: Override SIM button label for Login section
sections.identity.title- Identity section titlesections.identity.description- Identity section descriptionsections.identity.button_anonymous_identity_label- Optional: Override Anonymous Identity button labelsections.identity.button_kyc_label- Optional: Override KYC button label
buttons.ip- IP button labelbuttons.ip_plus- IP+ button labelbuttons.im- IM button labelbuttons.sim- SIM button labelbuttons.ip_via_app- IP via App button labelbuttons.anonymous_identity- Anonymous Identity button labelbuttons.kyc- KYC button label
footer.viettel_legal- Legal disclaimer textfooter.viettel- Viettel brand namefooter.privacy_policy- Privacy Policy link textfooter.about- About link textfooter.help- Help link text
modals.about_title- About modal titlemodals.server_label- Server label in about modalmodals.state_label- State label in about modalmodals.developer_link- Developer link textmodals.phone_required- Phone number required error messagemodals.phone_invalid- Invalid phone number error message
- Keep base locale complete: Always maintain a complete
locale.jsonwith all required strings - Use overrides sparingly: Only override strings that need to be different in specific environments
- Test overrides: Verify that overrides work correctly and don't break the UI
- Document custom overrides: If you add custom locale strings, document them in your project documentation
- Maintain consistency: Keep naming conventions consistent across locale strings
- Check file location: Ensure
locale.jsonis inconfig/directory - Verify JSON syntax: Use a JSON validator to check for syntax errors
- Check override syntax: Ensure override in
default.jsonuses correct nested structure - Restart application: Changes to locale files require application restart
- Verify deep merge: Check that you're using nested object structure correctly
- Check property names: Ensure property names match exactly (case-sensitive)
- Validate JSON: Ensure both
locale.jsonanddefault.jsonare valid JSON
- Check base locale: Ensure
locale.jsoncontains all required strings - Verify view usage: Check that views are accessing locale properties correctly
- Check for typos: Verify property names match between locale file and view
The locale system is implemented in app.js:
- Loading:
locale.jsonis loaded at application startup - Merging: If
config.localeexists, it's deep-merged with the base locale - Availability: Merged locale is added to
res.locals.localefor all requests - Deep merge: Custom deep merge function handles nested object merging
- Sample Config Reference - Field-by-field config guide
- Architecture Documentation - System architecture details
- Quick Start Guide - Setup and configuration guide
See Sample Config Reference for example locale override configurations.