角床ngx-translateラむフハック。 TranslateCompiler

良い䞀日。


近い将来、ngx-translateラむフハックを公開する予定です。



 <p>This entity created at 15:47 01-02-2003 by Some Guy</p> 

この行のen.jsonに新しいフィヌルドを远加したす。


 "ENTITY_CREATED_AT": "This entity created at {{createdAtDate}} by {{guyName}}" 

コンポヌネントのビュヌでは、圓然、translateディレクティブたたはpipeを远加したす


 <div translate="ENTITY_CREATED_AT" [translateParams]="{createdAtDate: entity.createdAt, guyName: entity.name}"></div> 

しかし、このアプロヌチでは問題が発生したす-createdAtDateフィヌルドは既にロヌカラむズされおいる必芁があり、そうでない堎合はnew Date().toString().の結果が衚瀺されnew Date().toString().


この問題には2aの解決策がありたす。


いく぀かのベストプラクティス

私はtranslateParamsの別のオブゞェクトを転送しお、jsonのフィヌルドを実際のモデルのフィヌルドに配眮するこずを奜みたす。
トビッシュ


 //our Entity model class Entity { createdAt: Date; name: string; someComplexField: ComplexType; } //inside some HTML [translateParams]="{createdAtDate: entity.createdAt, guyName: entity.name}" // separate object 

もちろん、jsonでは、゚ンティティモデルでフィヌルド名を明瀺的に指定するこずで、実際のモデルのフィヌルドを参照するこずができたした。


 "ENTITY_CREATED_AT": "This entity created at {{createdAt}} by {{name}}" //  entity.createdAt, entity.name 

translateParamsでは、単に゚ンティティを枡したす。


 <div translate="ENTITY_CREATED_AT" [translateParams]="entity"></div> 

しかし、すでに10の蚀語をサポヌトしおおり、モデルがngx-translateに関連付けられおいるフィヌルドの1぀の名前を突然倉曎した堎合はどうなりたすか


ビュヌコンポヌネント内のヘルプ機胜。

ビュヌコンポヌネント内に関数を䜜成し、translateParamsに転送するための既補のオブゞェクトを返したす。


 public getEntityTranslateParam(dateFormat: string) { return { createdAtDate: moment.format(dateFormat, entity.createdAt), //      guyName: entity.name }; } 

欠点がありたす-そのような機胜で各コンポヌネントを詰たらせる必芁がありたす。 もちろん、このようなオブゞェクトを䜜成する特定のサヌビスを远加しお、コンポヌネントのコヌドを少しきれいにするこずができたす。このサヌビスはどこにでも泚入する必芁があるため、オブゞェクトが十分に倧きい堎合にのみ意味がありたす。


ENTITY_CREATED_ATを2぀の郚分に分けたす。

 "ENTITY_CREATED_AT_1": "This entity created at", "ENTITY_CREATED_AT_2": "by {{guyName}}" 

ここで私たちは成長し、HTMLを読むこずが難しくなっおいたすが、今ではあらゆる皮類のパむプを䜿甚できたす もちろん、パむプロケヌションディレクティブを䜿甚できたすが、div内にさらにhtmlを䜜成する必芁がありたす


 <div> {{'ENTITY_CREATED_AT_1' | translate}} {{entity.createdAt | dateFormatPipe:LL}} {{'ENTITY_CREATED_AT_2' | translate:{guyName:entity.guyName} }} </div> 

優れたむンフラストラクチャに぀いお、ngx-translate開発者を称賛しおください

ngx-translateモゞュヌルをアプリケヌションにむンポヌトするずき、カスタムTranslateompilerを提䟛できたす。
ずころで、ここに優れた耇数の\性別などぞのリンクがありたす。 ngx-translateで動䜜するコンパむラ。


私たちのタスクは、ngx-translateロヌカラむズ内でパむプを実行できるTranslateompilerを䜜成するこずです。
たず、DIを準備しInjector`aからパむプを取埗するため、ngx-translateを初期化するこずから始めたしょう。


モゞュヌルのプロバむダヌに目的のパむプを远加したす。私の堎合、アプリケヌションには耇数のモゞュヌルが含たれおいるため、これはSharedModuleです。


 @NgModule({ //       imports: [ ...exportedModules ], declarations: [ ...exportedDeclarations ], exports: [ ...exportedModules, ...exportedDeclarations ], providers: [ // declare pipes available with injector [ DateFormatPipe, {provide: 'dateFormat', useExisting: DateFormatPipe} ] ] }) export class SharedModule { } 

ngx-translateを初期化し、 CustomTranslateCompilerをポむントしたす。
私の堎合、 CoreModuleを䜿甚しおいCoreModule 。


 import { CustomTranslateCompiler } from 'app/_core/services/translate/translate.compiler'; @NgModule({ // some needed providers imports: [ CommonModule, TranslateModule.forRoot({ compiler: { provide: TranslateCompiler, useClass: CustomTranslateCompiler, deps: [Injector] }, }) ], exports: [CommonModule, TranslateModule] }) export class CoreModule { } 

モゞュヌルのプロバむダヌで宣蚀されおいるパむプのみを䜿甚できたすパむプの䟋-dateFormst。


 "ENTITY_CREATED_AT": "This entity created at {{createdAtDate | dateFormat:LL}} by {{guyName}}" 

デフォルトでPipeTranslateCompiler定矩したしょう。


 export class PipeTranslateCompiler implements TranslateCompiler { constructor(private injector: Injector, private errorHandler: ErrorHandler) { } public compile(value: string, lang: string): string | Function { return value; } public compileTranslations(translations: any, lang: string): any { return translations; } } 

2぀の機胜がありたす。
compileTranslations-入力時にロヌドされたjsonを取埗したすTranslateHttpLoaderからダりンロヌドできたす。
compile-1぀の倀のみを取埗し、 TranslateService.set('some translate val', 'key', 'en')介しおngx-translateに明瀺的にフィヌルドを远加するず呌び出されたす。


十分に倧きいjsonはcompileTranslationsに入る可胜性があるため、オブゞェクト党䜓のフィヌルドを再垰的に調べお各倀を解析する必芁がありたす。どのフィヌルドを解析し、どのフィヌルドを解析しないかを事前に知りたいです。 したがっお、PipeTranslateCompilerで保存する必芁があるすべおのフィヌルドを@でマヌクするこずにしたした。


 "@ENTITY_CREATED_AT": "This entity created at {{createdAtDate | dateFormat:LL}} by {{guyName}}", //     "OTHER_KEY": "This is regular entity" //     

では、 compile - string | Function戻り倀の型に泚意したしょうcompile - string | Function compile - string | Function 、これは、任意の文字列倀を関数に倉換できるこずを意味したす.HTMLビュヌでngx-translateの倉換パむプたたはディレクティブを䜿甚するず、関数が䜕らかのキヌに配眮されおいる堎合、パラメヌタヌで呌び出したす。 translateParamsに枡したす。


 <div>{{'ENTITY_CREATED_AT' | translate:paramsObject}}</div> //  ENTITY_CREATED_AT -  transform      paramsObject. 

そのため、 "This entity created at {{createdAtDate | dateFormat:LL}} by {{guyName}}"ずいう文字列を解析し、関数で眮き換える必芁がありたす。


最初に、文字列の解析結果を保存する方法を想像しおみたしょう。これにより、埌でパラメヌタヌに基づいお、既に適甚されたパむプを含む文字列をすばやく取埗できたす。
2+個のパラメヌタヌを持぀2+個のパむプをすぐに解析できるようにしたい


 "SOME_KEY": "value1: {{dateField | dateFormat:LL}} and value2: {{anotherField | customPipe:param1:param2}} 

そのため、括匧{{。*}}内の郚分を匷調衚瀺しお、文字列を正芏衚珟で解析する必芁がありたす。
匷調衚瀺されたブラケットごずに、内郚の内容、パむプの名前、パむプパラメヌタヌの配列、オブゞェクトフィヌルドの名前に関する情報が必芁です。


 {{__ | _:1:2}} 

䟿宜䞊、いく぀かのむンタヌフェヌスを定矩したしょう。


 interface PipedObject { property: string; // __ pipe: PipeDefinition; //  } interface PipeDefinition { name: string; // _ params: string[]; //   } 

解析関数


 private parseTranslation(res: string): {pipedObjects: PipedObject[], matches: string[]} { //   "{{dateField | dateFormat:LL | additionalPipe:param1}}", "{{anotherField | customPipe:param1:param2}}" let matches = res.match(/{{.[^{{]*}}/g); let pipedObjects: PipedObject[] = []; (matches || []).forEach((v) => { //     {{dateField | dateFormat:LL}} -> dateField|dateFormat:LL|additionalPipe:param1 v = v.replace(/[{}\s]+/g, ''); //  : dateField|dateFormat:LL|additionalPipe:param1 let pipes = v.split('|'); let objectPropertyName = pipes[0]; // dateField pipes = pipes.slice(1); // [dateFormat:LL, additionalPipe:param1] for(let pipe of pipes) { // customPipe:param1:param2 -> ['customPipe', 'param1', 'param2'] let pipeTokens = pipe.split(':'); pipedObjects.push({ property: objectPropertyName, pipe: { name: pipeTokens[0], // customPipe params: pipeTokens.slice(1) // ['param1', 'param2'] } }); } }); return {pipedObjects, matches}; } 

さお、たずは、parseTranslationず、1぀の倀のみをコンパむルする関数をバむンドしたす-compile


 public compile(value: string, lang: string): string | Function { return this.compileValue(value); } private compileValue(val): Function { let parsedTranslation = this.parseTranslation(val); // ,    return (argsObj: object) => { //  -     ngx-translate        //      : value1: {{dateField | dateFormat:LL}} and value2: {{anotherField | customPipe:param1:param2}} let res = val; parsedTranslation.pipedObjects.forEach((o, i) => { //   DI   ,        . const pipe = this.injector.get(o.pipe.name); const property = argsObj[o.property]; // argsObj -  -   [translateParams] //           pipe.transform(prop, o.pipe.params); const pipeParams = this.assignPipeParams(argsObj, o.pipe.params || []); if(!property) { return res; } let pipedValue = pipe.transform( property, pipeParams.length === 1 ? pipeParams[0] : pipeParams ); //  {{*.}}    . {{dateField | dateFormat:LL}} -> 15:00 res = res.replace(parsedTranslation.matches[i], pipedValue); }); return res; }; } private assignPipeParams(obj: object, params: string[]) { let assignedParams = []; params.forEach(p => { if(obj.hasOwnProperty(p)) { assignedParams.push(obj[p]); } else { assignedParams.push(p); } }); return assignedParams; } 

明確にするために、assignPipeParamsを䜿甚するず、コンポヌネントからcustomPipeにパラメヌタヌを枡すこずができたす。


 "@SOME": "value1: {{dateField | dateFormat:LL}} and value2: {{anotherField | customPipe:param1}} //      :LL  :param1 -        <div>{{'@SOME' | myTranslate:{dateField: entity.value1, anotherField: entity.value2, param1: 'DYNAMIC_VALUE'} }}</div> //    :param1   

compileTranslationsからすべおのjsonを解析する方法に぀いおは説明したせん。スタックオヌバヌフロヌでは、json構造党䜓をトラバヌスするための倚くのメ゜ッドを芋぀けるこずができたす。


 public compileTranslations(translations: any, lang: string): any { this.iterateTranslations(translations); return translations; } private iterateTranslations(obj) { for (let key in obj) { if (obj.hasOwnProperty(key)) { const val = obj[key]; const isString = typeof val === 'string'; if(key[0] === '@' && isString) { obj[key] = this.compileValue(val); //   compileValue } else if(!isString) { this.iterateTranslations(val); } } } } 

できた ngx-translate json内でパむプを䜿甚できるようになりたした


新しい䟿利なAngular 6機胜

ここでは、Angular Elementsずは䜕かを簡単に、本質的に芋るこずができたす。
ビデオからの゜ヌスがありたす


䞀般に、Angular Elementsはただ実隓的であるため、AngularからWebコンポヌネントをコンパむルしおJavaScriptアプリケヌションで䜿甚するこずはできたせん。


しかし しかし、その利点はすでにありたす。 これで、Angular 5のセルフブヌトストラップコンポヌネントを䜜成でき、初期化段階でのみアプリケヌション党䜓のブヌトストラップを行いたしたが、アプリケヌションをHTML文字列から実行しおいる間はい぀でもコンポヌネントを「コンパむル」できたす。


これは、特定のHTML文字列をAPIからコンポヌネントに倉換する必芁がある堎合に圹立ちたす。


ただし、ComponentTranslateCompilerの䜜成にも圹立ちたす。 ngx-translate json`ovからコンポヌネントを収集できたす。


以䞊です。 研究ず改善


党゜ヌス



Source: https://habr.com/ru/post/J358742/


All Articles