Internationalization
Every user-facing string goes through @ngx-translate. English is currently the
only language, but the mechanism is fully in place.
Loader
The app uses a local loader rather than fetching JSON at runtime:
// src/app/translate-loader.ts
const languages = {
en: {
load: () => fromPromise(import('../assets/i18n/en')).pipe(map(res => res.default)),
},
};
export class LocalTranslateLoader implements TranslateLoader {
getTranslation(lang: string): Observable<any> {
return languages[lang].load();
}
}
Translations are a TypeScript module, dynamically imported and bundled by webpack — not a static JSON asset.
|
|
The translation file
src/assets/i18n/en.ts — around 3,800 lines, exporting a nested object as the
default export.
Because it is TypeScript, it can import:
import { CrossSellProductEnum } from '@payability/pyb-ng2-api';
import { MIN_INSTANT_TRANSFER_AMOUNT } from '.../transfer-funds.const';
import { APP_CONFIG } from '../../app/core/_config/app-config/app-config';
import { descriptionLinkClassName } from '.../transfer-error-modal.const';
const i18n = {
AUTH: {
CHANGE: {
CURRENT: 'Current password',
FORGOT: 'Forgot password?',
// …
},
},
};
Enum members become computed keys, and constants can be interpolated directly, so a value such as a minimum transfer amount is defined once and reused in copy.
|
The translation file imports from |
Initialization
Loading is an APP_INITIALIZER that blocks bootstrap:
const translateFactory = (translate: TranslateService) => {
return async () => {
translate.setDefaultLang(DEFAULT_LANGUAGE);
translate.use(DEFAULT_LANGUAGE);
return new Promise(resolve => translate.onLangChange.subscribe(change => resolve(change)));
};
};
Nothing renders until translations are ready, which is why raw keys are never briefly visible.
DEFAULT_LANGUAGE is 'en', defined in
core/_base/layout/services/translation.service.ts. TranslationService
registers the available languages and sets the fallback.
Using translations
In templates:
<span>{{ 'AUTH.CHANGE.HEADER' | translate }}</span>
<span>{{ 'BANNERS.CANCELLATION.PENDING.LAST_DAY' | translate: { marketplaceName, optOutDate } }}</span>
In code:
this.translateService.instant('MODALS.INSTANT_ADVANCE.SUCCESS.TITLE');
this.translateService.instant('FEATURES.ADVANCE_LINE.MODALS.SUCCESS.HEADER', { amount });
this.translateService.get('CTA.AIRWALLEX_PCARD_TERMS.SUCCESS').subscribe(({ HEADER, DESCRIPTION }) => { /* … */ });
|
|
Key naming
|
Authentication screens. |
|
Account settings, mirroring the tab structure. |
|
Dialog copy — |
|
Banner copy — |
|
Notification CTA copy — |
|
Feature-specific copy — |
|
Suspension copy, keyed by the stripped reason code. |
|
Product card copy, keyed by |
|
Card status and provider labels. |
|
Onboarding step titles. |
|
Navigation labels. |
|
Shared words — |
|
Instant Transfer copy, including the failure modals. |
|
PayShield plan names and descriptions. |
Computed keys
Several places build keys at runtime. Grep will not find them, so they need care.
Suspension |
|
Product offerings |
|
Onboarding steps |
|
Card status |
|
CTA success |
|
|
A missing computed key renders as the raw key string, and only for the cohort that hits that branch. Adding a suspension reason, a product, or an accept-able notification means adding its key and exercising that branch. |
Extraction
$ npm run extract-translations
runs:
ngx-translate-extract --input ./src --output ./src/assets/i18n/*.json --sort --format namespaced-json
|
The extractor writes |
make i18n is the Makefile equivalent.
HTML in copy
Keys ending _HTML (for example
INSTANT_TRANSFER.FAILURE_ADDRESS_MODAL.DESCRIPTION_HTML) contain markup and are
rendered through the html-render component or the safe pipe. HyperlinkService
can also inject links into plain text at runtime, using the class from
HYPER_LINK_CONFIG_TOKEN.
Known exceptions
|
Some strings are hardcoded English rather than translated:
These should move into |
Adding a language
-
Add
src/assets/i18n/<lang>.tswith the same key structure. -
Add an entry to the
languagesmap insrc/app/translate-loader.ts. -
Register the language with
TranslationService. -
Add a language selector and persist the choice.
-
Review date and currency formatting —
DateFormatsEnumis US-centric (MM/dd/yyyy) andCurrencyPipeis used without an explicit locale.