Localize custom Freedom UI component implemented using remote module
Localize custom Freedom UI components during development to save time spent on translating the ready-to-use custom Freedom UI component. Implementing localization during development ensures that all user-facing labels, captions, and messages are available in the target language from the first release. This applies to custom Freedom UI components as well as related artifacts such as validators, converters, and request handlers implemented using remote module.
Localize custom validators, converters and request handlers
Localize custom validators, converters and request handlers using Angular DI (dependency injection). To do this:
-
Import the
SysValuesServicefunctionality from the@creatio-devkit/commonlibrary into the component to retrieve the Creatio UI language of the current user from theuserCulturesystem variable. We recommend using a dedicated function for this purpose. TheSysValuesServiceservice is used to localize system variables."some-component.component.ts" file/* Import the required functionality from the libraries. */import { SysValuesService } from '@creatio-devkit/common';constructor() {}public async getUserCulture(): Promise<string> {/* Create an instance of the "SysValuesService" service from "@creatio-devkit/common." */const sysValuesService = new SysValuesService();/* Retrieve the system variable values. */const sysValues = await sysValuesService.loadSysValues();return sysValues.userCulture.displayValue;} -
Use an external library or implement the custom service to localize custom Freedom UI component. We recommend using the
@ngx-translateexternal library for this purpose. Learn more: official vendor documentation (GitHub).For example,
SomeTranslationServiceis an external library or custom service to localize custom Freedom UI components. -
If needed, enable support for emitting type metadata for decorators that works with the
reflect-metadatamodule.- Run the
npm i reflect-metadatacommand in the Visual Studio Code terminal to install thereflect-metadatanpm package if needed. - Open the "tsconfig.json" file of the Angular project and make sure the
experimentalDecoratorsandemitDecoratorMetadataproperties are set totrue.
"tsconfig.json" file{"compilerOptions": {"experimentalDecorators": true,"emitDecoratorMetadata": true,},} - Run the
-
Receive the dependencies of the validator, converter, or request handler.
For Creatio version 8.3.4 and later:
- Open the "runtime.feature-activation.ts" file.
- Ensure that the existing
bootstrapCrtModule()call contains theresolveDependency()method. ThebootstrapCrtModule()call registers the custom validator, converter, or request handler flagged using the@CrtModuledecorator. - Import the required functionality from the libraries into the file.
- Save the file.
"runtime.feature-activation.ts" file/* Import the required functionality from the libraries. */import { ProviderToken } from '@angular/core';import { bootstrapCrtModule } from '@creatio-devkit/common';import { ensureFeatureModuleRef } from '../../remote-app-context';import { RuntimeFeatureModule } from './runtime-feature.module';export async function activateRuntimeFeature(): Promise<string> {const moduleRef = await ensureFeatureModuleRef(RuntimeFeatureModule);const injector = moduleRef.injector;/* Bootstrap CrtModule definitions. */bootstrapCrtModule('some_package', RuntimeFeatureModule, {/* Receive the dependencies. */resolveDependency: (token) =>injector.get(token as ProviderToken<unknown>),});}For Creatio version 8.3.3 and earlier
- Open the "app.module.ts" file.
- If needed, implement the
resolveDependency()method in thebootstrapCrtModule()method. ThebootstrapCrtModule()method registers the custom validator, converter, or request handler flagged using the@CrtModuledecorator. - Import the required functionality from the libraries into the file.
- Save the file.
"app.module.ts" file/* Import the required functionality from the libraries. */import { DoBootstrap, Injector, ProviderToken } from '@angular/core';import { bootstrapCrtModule } from '@creatio-devkit/common';export class AppModule implements DoBootstrap {constructor(private _injector: Injector) {}ngDoBootstrap(): void {/* Bootstrap "CrtModule" definitions. */bootstrapCrtModule('some_package', AppModule, {/* Receive the dependencies. */resolveDependency: (token) =>this._injector.get(<ProviderToken<unknown>>token),});}} -
Retrieve the instance of the translation service.
- Open the file that implements a custom validator, converter or request handler. For example, open the "some-handler.handler.ts" file that implements a custom request handler.
- Receive the instant translated value using the
instant()method. - Import the required functionality from the libraries into the file.
- Save the file.
"some-handler.handler.ts" file/* Import the required functionality from the libraries. */import {BaseRequestHandler,CrtRequestHandler} from "@creatio-devkit/common";import { SomeRequest } from "../requests/some-request.request";import {SomeTranslationService} from "../services/some-translation-service.service";/* Register the SomeHandler as a Freedom UI request handler. */@CrtRequestHandler({type: 'usr.SomeHandler',requestType: 'usr.SomeRequest',})export class SomeHandler extends BaseRequestHandler {constructor(private _someTranslationService: SomeTranslationService) {super();}public async handle(request: SomeRequest): Promise<string> {/* Receive the instant translated value. */const localizedMessage = this._someTranslationService.instant('SomeRequest.Message');alert(localizedMessage);}}
As a result, the custom validator, converter, or request handler will display localized values based on the current Creatio UI language after you add the corresponding artifact to the source code of the Freedom UI page schema.
Localize properties of custom Freedom UI component
To localize properties of custom Freedom UI component (for Creatio version 8.3.4 and later):
-
Use an external library or implement the custom service to localize custom Freedom UI component. We recommend using the
@ngx-translateexternal library for this purpose. Learn more: official vendor documentation (GitHub).For example,
SomeTranslationServiceis an external library or custom service to localize custom Freedom UI components. -
Return translated definitions of Freedom UI Designer.
- Open the "runtime.designer-definitions.ts" file.
- Add the Freedom UI Designer properties of the custom Freedom UI component to the
viewElementscollection returned by theloadRuntimeDesignerDefinitions()function. - Use
context.cultureNameto request the required culture from the shared remote app context. - Return the already translated values of the designer definitions, for example,
captionanddefaultPropertyValues. - Save the file.
The deferred remote entry API does not localize designer definitions automatically. The remote module returns the translated interface designer definitions immediately.
"runtime.designer-definitions.ts" file/* Import the required functionality from the libraries. */import type {RemoteDesignerDefinitionsLoadContext,RemoteFeatureDesignerDefinitions,} from '@creatio-devkit/common';import { ensureRemoteAppContext } from '../../remote-app-context';export async function loadRuntimeDesignerDefinitions(context: RemoteDesignerDefinitionsLoadContext): Promise<RemoteFeatureDesignerDefinitions> {/* The ensureRemoteAppContext() function resolves the shared remoteapplication context, including translateService, using the"remote-app-context.ts" file. */const { translateService } = await ensureRemoteAppContext(context.cultureName);return {viewElements: [{type: 'usr.SomeComponent',toolbarConfig: {/* The localizable name of the component. */caption: translateService.instant('SomeComponent.Caption'),/* The icon of the component displayed in the Freedom UI Designerelement library. Required property. */icon: SOME_COMPONENT_ICON,},defaultPropertyValues: {label: translateService.instant('SomeComponent.DefaultLabel'),},}],};}
Localize properties of custom Freedom UI component (for Creatio version 8.3.3 and earlier)
-
Import the
SysValuesServicefunctionality from the@creatio-devkit/commonlibrary into the component to retrieve the Creatio UI language of the current user from theuserCulturesystem variable. TheSysValuesServiceservice is used to localize system variables."some-component.component.ts" file/* Import the required functionality from the libraries. */import { SysValuesService } from '@creatio-devkit/common';constructor() {}async function getUserCulture(): Promise<string> {/* Create an instance of the "SysValuesService" service from "@creatio-devkit/common." */const sysValuesService = new SysValuesService();/* Retrieve the system variable values. */const sysValues = await sysValuesService.loadSysValues();return sysValues.userCulture.displayValue;} -
Use an external library or implement the custom service to localize custom Freedom UI component. We recommend using the
@ngx-translateexternal library for this purpose. Learn more: official vendor documentation (GitHub).For example,
SomeTranslationServiceis an external library or custom service to localize custom Freedom UI components. -
Flag the properties to localize.
- Open the "some_component.component.ts" file.
- Flag the component using the
@CrtInterfaceDesignerItemdecorator that has thetoolbarConfigproperty. The property manages the element layout in the library of the Freedom UI Designer. - Import the required functionality from the libraries into the component.
- Flag the properties to localize using the
localize()method. - Save the file.
"some_component.component.ts" file/* Import the required functionality from the libraries. */import { CrtInterfaceDesignerItem } from '@creatio-devkit/common';/* Register the SomeComponent as a Freedom UI Designer item. */@CrtInterfaceDesignerItem({/* Manage the element layout in the library of the Freedom UI Designer. */toolbarConfig: {/* The localizable name of the component. */caption: localize('SomeComponent.Caption'),}}) -
Translate the localizable values of the validator, converter or request handler.
- Open the "app.module.ts" file.
- Call the
localizeMetadata()method in thebootstrapCrtModule()method. ThelocalizeMetadata()method is required to translate the properties flagged using thelocalize()method. The key to translate the value is an incoming parameter of thelocalizeMetadata()method. The method returns the translated value. - Import the required functionality from the libraries into the file.
- Save the file.
"app.module.ts" file/* Import the required functionality from the libraries. */import { DoBootstrap, Injector } from '@angular/core';import { bootstrapCrtModule } from '@creatio-devkit/common';import { SomeTranslationService } from "./some-translation-service.service";export class AppModule implements DoBootstrap {constructor(private _injector: Injector) {}ngDoBootstrap(): void {const translationService = this._injector.get(SomeTranslationService);/* Bootstrap CrtModule definitions. */bootstrapCrtModule('some_package', AppModule, {localizeMetadata: (key: string) => translationService.instant(key),});}}
As a result, the Freedom UI Designer will display the localized properties of the custom Freedom UI component, such as captions and default values.
Upload the translations of custom Freedom UI component from static content
To upload the translations of custom Freedom UI component from static content (for Creatio version 8.3.4 and later):
-
Find the URL to upload the translations. To do this, use the
__webpack_public_path__global variable. Learn more: Public Path (official vendor documentation). -
Create a dedicated localization module. For example, create the "remote-localization.module.ts" file.
-
Add an app initializer that retrieves the Creatio UI language of the current user from the
userCulturesystem variable and passes the value to the translation service."remote-localization.module.ts" file/* Import the required functionality from the libraries. */import { HttpClient, HttpClientModule } from '@angular/common/http';import { APP_INITIALIZER, NgModule } from '@angular/core';import { SysValuesService } from '@creatio-devkit/common';import {TranslateLoader,TranslateModule,TranslateService} from '@ngx-translate/core';import { TranslateHttpLoader } from '@ngx-translate/http-loader';import { firstValueFrom } from 'rxjs';declare const __webpack_public_path__: string;const TRANSLATIONS_PATH = 'assets/i18n/';const DEFAULT_CULTURE_NAME = 'en-US';async function getUserCultureNameFromSysValues(): Promise<string> {try {const sysValues = await new SysValuesService().loadSysValues();return sysValues?.userCulture?.displayValue || DEFAULT_CULTURE_NAME;} catch {return DEFAULT_CULTURE_NAME;}}@NgModule({imports: [HttpClientModule,TranslateModule.forRoot({defaultLanguage: DEFAULT_CULTURE_NAME,loader: {provide: TranslateLoader,useFactory: (httpClient: HttpClient) => new TranslateHttpLoader(httpClient,`${__webpack_public_path__}${TRANSLATIONS_PATH}`,'.json'),deps: [HttpClient],},}),],exports: [TranslateModule],providers: [{provide: APP_INITIALIZER,useFactory: (translateService: TranslateService) => async () => {const cultureName = await getUserCultureNameFromSysValues();await firstValueFrom(translateService.use(cultureName));},multi: true,deps: [TranslateService],}],})export class RemoteLocalizationModule {} -
Import the localization module into the "remote-app.module.ts" file.
-
If needed, import the translation module into the runtime and design feature modules.
"remote-app.module.ts" file/* Import the required functionality from the libraries. */import { BrowserModule } from '@angular/platform-browser';import { DoBootstrap, NgModule } from '@angular/core';import {RemoteLocalizationModule} from './localization/remote-localization.module';@NgModule({imports: [BrowserModule, RemoteLocalizationModule],})export class RemoteAppModule implements DoBootstrap {public ngDoBootstrap(): void {}} -
Extend the shared remote app context. Update
remote-app-context.tsto expose theTranslateServiceand switch the active culture whencultureNameis provided."remote-app-context.ts" file/* Import the required functionality from the libraries. */import { Injector, NgModuleRef, Type, createNgModule } from '@angular/core';import { platformBrowser } from '@angular/platform-browser';import { TranslateService } from '@ngx-translate/core';import { firstValueFrom } from 'rxjs';import { RemoteAppModule } from './remote-app.module';export interface RemoteAppContext {injector: Injector;moduleRef: NgModuleRef<RemoteAppModule>;translateService: TranslateService;}let remoteAppContextPromise: Promise<RemoteAppContext> | undefined;const featureModuleRefs = new Map<Type<unknown>, NgModuleRef<unknown>>();async function bootstrapRemoteApp(): Promise<RemoteAppContext> {const moduleRef = await platformBrowser().bootstrapModule(RemoteAppModule);const injector = moduleRef.injector;return {injector,moduleRef,translateService: injector.get(TranslateService),};}export async function ensureRemoteAppContext(cultureName?: string): Promise<RemoteAppContext> {if (!remoteAppContextPromise) {remoteAppContextPromise = bootstrapRemoteApp().catch((error: unknown) => {remoteAppContextPromise = undefined;throw error;});}const context = await remoteAppContextPromise;if (cultureName && context.translateService.currentLang !== cultureName) {await firstValueFrom(context.translateService.use(cultureName));}return context;} -
Save the files.
Upload the translations of custom Freedom UI component from static content (for Creatio version 8.3.3 and earlier)
- Find the URL to upload the translations. To do this, use the
__webpack_public_path__global variable. Learn more: Public Path (official vendor documentation). - Open the "app.module.ts" file.
- Add an app initializer that retrieves the Creatio UI language of the current user from the
userCulturesystem variable and passes the value to the external library or custom service. - Implement the mechanism that uploads translations.
- Save the file.
/* Import the required functionality from the libraries. */
import { BrowserModule } from "@angular/platform-browser";
import { HttpClient, NgModule } from '@angular/core';
import { HttpClientModule } from '@creatio-devkit/common';
import { TranslateModule, TranslateLoader } from '@ngx-translate/core';
import { TranslateHttpLoader } from '@ngx-translate/http-loader';
import { SomeTranslationService } from "./some-translation-service.service";
declare const __webpack_public_path__: string;
@NgModule({
providers: [{
provide: APP_INITIALIZER,
useFactory: (someTranslationService) => async () => {
const culture = await getUserCulture();
someTranslationService.use(culture)
},
multi: true,
deps: [SomeTranslationService],
}],
imports: [
BrowserModule,
HttpClientModule,
TranslateModule.forRoot({
defaultLanguage: 'en-US',
loader: {
provide: TranslateLoader,
useFactory: (httpClient: HttpClient) => {
return new TranslateHttpLoader(
httpClient,
__webpack_public_path__ + '/assets/i18n/',
'.json'
);
},
deps: [HttpClient],
},
}),
],
})
As a result, the custom Freedom UI component will load translations from static content and display localized values based on the current Creatio UI language.
See also
Custom Freedom UI component implemented using remote module
Custom validator implemented using remote module
Custom converter implemented using remote module
Custom request handler implemented using remote module
Resources
Public Path (official vendor documentation)