2018-06-18 10:55:43 -04:00
/ * *
* @license
2020-05-19 15:08:49 -04:00
* Copyright Google LLC All Rights Reserved .
2018-06-18 10:55:43 -04:00
*
* Use of this source code is governed by an MIT - style license that can be
* found in the LICENSE file at https : //angular.io/license
* /
2018-11-13 03:36:30 -05:00
import { noop } from '../../../compiler/src/render3/view/util' ;
2019-05-17 21:49:21 -04:00
import { getTranslationForTemplate , ɵ ɵ i18nAttributes , ɵ ɵ i18nPostprocess , ɵ ɵ i18nStart } from '../../src/render3/i18n' ;
2019-05-31 11:11:57 -04:00
import { setDelayProjection , ɵ ɵ elementEnd , ɵ ɵ elementStart } from '../../src/render3/instructions/all' ;
2019-05-06 09:33:34 -04:00
import { COMMENT_MARKER , ELEMENT_MARKER , I18nMutateOpCode , I18nUpdateOpCode , I18nUpdateOpCodes , TI18n } from '../../src/render3/interfaces/i18n' ;
2019-04-04 14:41:52 -04:00
import { HEADER_OFFSET , LView , TVIEW } from '../../src/render3/interfaces/view' ;
2019-05-06 09:33:34 -04:00
import { getNativeByIndex } from '../../src/render3/util/view_utils' ;
import { TemplateFixture } from './render_util' ;
2018-10-30 20:03:01 -04:00
2018-06-18 10:55:43 -04:00
describe ( 'Runtime i18n' , ( ) = > {
2020-04-13 19:40:21 -04:00
afterEach ( ( ) = > {
setDelayProjection ( false ) ;
} ) ;
2018-11-13 03:36:30 -05:00
describe ( 'getTranslationForTemplate' , ( ) = > {
it ( 'should crop messages for the selected template' , ( ) = > {
let message = ` simple text ` ;
expect ( getTranslationForTemplate ( message ) ) . toEqual ( message ) ;
message = ` Hello <20> 0<EFBFBD> ! ` ;
expect ( getTranslationForTemplate ( message ) ) . toEqual ( message ) ;
message = ` Hello <20> #2<> <32> 0<EFBFBD> <30> /#2<> ! ` ;
expect ( getTranslationForTemplate ( message ) ) . toEqual ( message ) ;
// Embedded sub-templates
message = ` <EFBFBD> 0<EFBFBD> is rendered as: <20> *2:1<> before<72> *1:2<> middle<6C> /*1:2<> after<65> /*2:1<> !` ;
expect ( getTranslationForTemplate ( message ) ) . toEqual ( '<27> 0<EFBFBD> is rendered as: <20> *2:1<> <31> /*2:1<> !' ) ;
expect ( getTranslationForTemplate ( message , 1 ) ) . toEqual ( 'before<72> *1:2<> <32> /*1:2<> after' ) ;
expect ( getTranslationForTemplate ( message , 2 ) ) . toEqual ( 'middle' ) ;
// Embedded & sibling sub-templates
message =
` <EFBFBD> 0<EFBFBD> is rendered as: <20> *2:1<> before<72> *1:2<> middle<6C> /*1:2<> after<65> /*2:1<> and also <20> *4:3<> before<72> *1:4<> middle<6C> /*1:4<> after<65> /*4:3<> !` ;
expect ( getTranslationForTemplate ( message ) )
. toEqual ( '<27> 0<EFBFBD> is rendered as: <20> *2:1<> <31> /*2:1<> and also <20> *4:3<> <33> /*4:3<> !' ) ;
expect ( getTranslationForTemplate ( message , 1 ) ) . toEqual ( 'before<72> *1:2<> <32> /*1:2<> after' ) ;
expect ( getTranslationForTemplate ( message , 2 ) ) . toEqual ( 'middle' ) ;
expect ( getTranslationForTemplate ( message , 3 ) ) . toEqual ( 'before<72> *1:4<> <34> /*1:4<> after' ) ;
expect ( getTranslationForTemplate ( message , 4 ) ) . toEqual ( 'middle' ) ;
} ) ;
2018-07-09 14:59:43 -04:00
2018-11-13 03:36:30 -05:00
it ( 'should throw if the template is malformed' , ( ) = > {
const message = ` <EFBFBD> *2:1<> message!` ;
expect ( ( ) = > getTranslationForTemplate ( message ) ) . toThrowError ( /Tag mismatch/ ) ;
} ) ;
2018-06-18 10:55:43 -04:00
} ) ;
2018-11-13 03:36:30 -05:00
function prepareFixture (
createTemplate : ( ) = > void , updateTemplate : ( ( ) = > void ) | null , nbConsts = 0 ,
nbVars = 0 ) : TemplateFixture {
return new TemplateFixture ( createTemplate , updateTemplate || noop , nbConsts , nbVars ) ;
}
function getOpCodes (
createTemplate : ( ) = > void , updateTemplate : ( ( ) = > void ) | null , nbConsts : number ,
index : number ) : TI18n | I18nUpdateOpCodes {
const fixture = prepareFixture ( createTemplate , updateTemplate , nbConsts ) ;
const tView = fixture . hostView [ TVIEW ] ;
return tView . data [ index + HEADER_OFFSET ] as TI18n ;
}
describe ( 'i18nStart' , ( ) = > {
it ( 'for text' , ( ) = > {
const MSG_DIV = ` simple text ` ;
const nbConsts = 1 ;
const index = 0 ;
2020-04-13 19:40:21 -04:00
const opCodes = getOpCodes ( ( ) = > {
ɵ ɵ i18nStart ( index , MSG_DIV ) ;
} , null , nbConsts , index ) ;
2018-11-13 03:36:30 -05:00
2019-03-15 18:04:34 -04:00
// Check debug
2020-04-13 19:40:21 -04:00
const debugOps = ( opCodes as any ) . create . debug ! . operations ;
2019-03-15 18:04:34 -04:00
expect ( debugOps [ 0 ] . __raw_opCode ) . toBe ( 'simple text' ) ;
expect ( debugOps [ 0 ] . type ) . toBe ( 'Create Text Node' ) ;
expect ( debugOps [ 0 ] . nodeIndex ) . toBe ( 1 ) ;
expect ( debugOps [ 0 ] . text ) . toBe ( 'simple text' ) ;
expect ( debugOps [ 1 ] . __raw_opCode ) . toBe ( 1 ) ;
expect ( debugOps [ 1 ] . type ) . toBe ( 'AppendChild' ) ;
expect ( debugOps [ 1 ] . nodeIndex ) . toBe ( 0 ) ;
2018-11-13 03:36:30 -05:00
expect ( opCodes ) . toEqual ( {
vars : 1 ,
2019-01-13 05:10:04 -05:00
create : [
'simple text' , nbConsts ,
index << I18nMutateOpCode . SHIFT_PARENT | I18nMutateOpCode . AppendChild
] ,
2018-11-13 03:36:30 -05:00
update : [ ] ,
icus : null
2018-11-13 03:36:30 -05:00
} ) ;
2018-11-13 03:36:30 -05:00
} ) ;
2018-06-18 10:55:43 -04:00
2018-11-13 03:36:30 -05:00
it ( 'for elements' , ( ) = > {
const MSG_DIV = ` Hello <20> #2<> world<6C> /#2<> and <20> #3<> universe<73> /#3<> ! ` ;
// Template: `<div>Hello <div>world</div> and <span>universe</span>!`
// 3 consts for the 2 divs and 1 span + 1 const for `i18nStart` = 4 consts
const nbConsts = 4 ;
const index = 1 ;
const elementIndex = 2 ;
const elementIndex2 = 3 ;
2020-04-13 19:40:21 -04:00
const opCodes = getOpCodes ( ( ) = > {
ɵ ɵ i18nStart ( index , MSG_DIV ) ;
} , null , nbConsts , index ) ;
2018-11-13 03:36:30 -05:00
expect ( opCodes ) . toEqual ( {
vars : 5 ,
create : [
'Hello ' ,
2019-01-13 05:10:04 -05:00
nbConsts ,
2018-11-13 03:36:30 -05:00
index << I18nMutateOpCode . SHIFT_PARENT | I18nMutateOpCode . AppendChild ,
elementIndex << I18nMutateOpCode . SHIFT_REF | I18nMutateOpCode . Select ,
index << I18nMutateOpCode . SHIFT_PARENT | I18nMutateOpCode . AppendChild ,
'world' ,
2019-01-13 05:10:04 -05:00
nbConsts + 1 ,
2018-11-13 03:36:30 -05:00
elementIndex << I18nMutateOpCode . SHIFT_PARENT | I18nMutateOpCode . AppendChild ,
elementIndex << I18nMutateOpCode . SHIFT_REF | I18nMutateOpCode . ElementEnd ,
' and ' ,
2019-01-13 05:10:04 -05:00
nbConsts + 2 ,
2018-11-13 03:36:30 -05:00
index << I18nMutateOpCode . SHIFT_PARENT | I18nMutateOpCode . AppendChild ,
elementIndex2 << I18nMutateOpCode . SHIFT_REF | I18nMutateOpCode . Select ,
index << I18nMutateOpCode . SHIFT_PARENT | I18nMutateOpCode . AppendChild ,
'universe' ,
2019-01-13 05:10:04 -05:00
nbConsts + 3 ,
2018-11-13 03:36:30 -05:00
elementIndex2 << I18nMutateOpCode . SHIFT_PARENT | I18nMutateOpCode . AppendChild ,
elementIndex2 << I18nMutateOpCode . SHIFT_REF | I18nMutateOpCode . ElementEnd ,
'!' ,
2019-01-13 05:10:04 -05:00
nbConsts + 4 ,
2018-11-13 03:36:30 -05:00
index << I18nMutateOpCode . SHIFT_PARENT | I18nMutateOpCode . AppendChild ,
] ,
update : [ ] ,
icus : null
} ) ;
} ) ;
2018-06-18 10:55:43 -04:00
2018-11-13 03:36:30 -05:00
it ( 'for simple bindings' , ( ) = > {
const MSG_DIV = ` Hello <20> 0<EFBFBD> ! ` ;
const nbConsts = 2 ;
const index = 1 ;
2020-04-13 19:40:21 -04:00
const opCodes = getOpCodes ( ( ) = > {
ɵ ɵ i18nStart ( index , MSG_DIV ) ;
} , null , nbConsts , index ) ;
2018-11-14 13:23:21 -05:00
2019-03-15 18:04:34 -04:00
expect ( ( opCodes as any ) . update . debug . operations ) . toEqual ( [
{ __raw_opCode : 8 , checkBit : 1 , type : 'Text' , nodeIndex : 2 , text : 'Hello <20> 0<EFBFBD> !' }
] ) ;
2018-11-13 03:36:30 -05:00
expect ( opCodes ) . toEqual ( {
vars : 1 ,
2019-01-13 05:10:04 -05:00
create :
[ '' , nbConsts , index << I18nMutateOpCode . SHIFT_PARENT | I18nMutateOpCode . AppendChild ] ,
2018-11-13 03:36:30 -05:00
update : [
0 b1 , // bindings mask
4 , // if no update, skip 4
'Hello ' ,
- 1 , // binding index
'!' , ( index + 1 ) << I18nUpdateOpCode . SHIFT_REF | I18nUpdateOpCode . Text
] ,
icus : null
} ) ;
} ) ;
2018-06-18 10:55:43 -04:00
2018-11-13 03:36:30 -05:00
it ( 'for multiple bindings' , ( ) = > {
const MSG_DIV = ` Hello <20> 0<EFBFBD> and <20> 1<EFBFBD> , again <20> 0<EFBFBD> ! ` ;
const nbConsts = 2 ;
const index = 1 ;
2020-04-13 19:40:21 -04:00
const opCodes = getOpCodes ( ( ) = > {
ɵ ɵ i18nStart ( index , MSG_DIV ) ;
} , null , nbConsts , index ) ;
2018-11-14 13:23:21 -05:00
2018-11-13 03:36:30 -05:00
expect ( opCodes ) . toEqual ( {
2018-08-18 14:14:50 -04:00
vars : 1 ,
2019-01-13 05:10:04 -05:00
create :
[ '' , nbConsts , index << I18nMutateOpCode . SHIFT_PARENT | I18nMutateOpCode . AppendChild ] ,
2018-11-13 03:36:30 -05:00
update : [
0 b11 , // bindings mask
8 , // if no update, skip 8
'Hello ' , - 1 , ' and ' , - 2 , ', again ' , - 1 , '!' ,
( index + 1 ) << I18nUpdateOpCode . SHIFT_REF | I18nUpdateOpCode . Text
] ,
icus : null
2018-06-18 10:55:43 -04:00
} ) ;
2018-11-13 03:36:30 -05:00
} ) ;
2018-06-18 10:55:43 -04:00
2018-11-13 03:36:30 -05:00
it ( 'for sub-templates' , ( ) = > {
// Template:
// <div>
// {{value}} is rendered as:
// <span *ngIf>
// before <b *ngIf>middle</b> after
// </span>
// !
// </div>
const MSG_DIV =
` <EFBFBD> 0<EFBFBD> is rendered as: <20> *2:1<> <31> #1:1<> before<72> *2:2<> <32> #1:2<> middle<6C> /#1:2<> <32> /*2:2<> after<65> /#1:1<> <31> /*2:1<> !` ;
2018-06-18 10:55:43 -04:00
2018-11-13 03:36:30 -05:00
/**** Root template ****/
// <20> 0<EFBFBD> is rendered as: <20> *2:1<> <31> /*2:1<> !
let nbConsts = 3 ;
let index = 1 ;
const firstTextNode = 3 ;
2020-02-11 17:44:13 -05:00
const rootTemplate = 2 ;
2020-04-13 19:40:21 -04:00
let opCodes = getOpCodes ( ( ) = > {
ɵ ɵ i18nStart ( index , MSG_DIV ) ;
} , null , nbConsts , index ) ;
2018-06-18 10:55:43 -04:00
2018-11-13 03:36:30 -05:00
expect ( opCodes ) . toEqual ( {
vars : 2 ,
create : [
'' ,
2019-01-13 05:10:04 -05:00
nbConsts ,
2018-11-13 03:36:30 -05:00
index << I18nMutateOpCode . SHIFT_PARENT | I18nMutateOpCode . AppendChild ,
2020-02-11 17:44:13 -05:00
~ rootTemplate << I18nMutateOpCode . SHIFT_REF | I18nMutateOpCode . Select ,
2018-11-13 03:36:30 -05:00
index << I18nMutateOpCode . SHIFT_PARENT | I18nMutateOpCode . AppendChild ,
'!' ,
2019-01-13 05:10:04 -05:00
nbConsts + 1 ,
2018-11-13 03:36:30 -05:00
index << I18nMutateOpCode . SHIFT_PARENT | I18nMutateOpCode . AppendChild ,
] ,
update : [
0 b1 , // bindings mask
3 , // if no update, skip 3
- 1 , // binding index
' is rendered as: ' , firstTextNode << I18nUpdateOpCode . SHIFT_REF | I18nUpdateOpCode . Text
] ,
icus : null
} ) ;
2018-06-18 10:55:43 -04:00
2018-11-13 03:36:30 -05:00
/**** First sub-template ****/
// <20> #1:1<> before<72> *2:2<> middle<6C> /*2:2<> after<65> /#1:1<>
nbConsts = 3 ;
index = 0 ;
const spanElement = 1 ;
const bElementSubTemplate = 2 ;
2020-04-13 19:40:21 -04:00
opCodes = getOpCodes ( ( ) = > {
ɵ ɵ i18nStart ( index , MSG_DIV , 1 ) ;
} , null , nbConsts , index ) ;
2018-06-18 10:55:43 -04:00
2018-11-13 03:36:30 -05:00
expect ( opCodes ) . toEqual ( {
2018-08-21 03:03:21 -04:00
vars : 2 ,
2018-11-13 03:36:30 -05:00
create : [
spanElement << I18nMutateOpCode . SHIFT_REF | I18nMutateOpCode . Select ,
index << I18nMutateOpCode . SHIFT_PARENT | I18nMutateOpCode . AppendChild ,
'before' ,
2019-01-13 05:10:04 -05:00
nbConsts ,
2018-11-13 03:36:30 -05:00
spanElement << I18nMutateOpCode . SHIFT_PARENT | I18nMutateOpCode . AppendChild ,
2020-02-11 17:44:13 -05:00
~ bElementSubTemplate << I18nMutateOpCode . SHIFT_REF | I18nMutateOpCode . Select ,
2018-11-13 03:36:30 -05:00
spanElement << I18nMutateOpCode . SHIFT_PARENT | I18nMutateOpCode . AppendChild ,
'after' ,
2019-01-13 05:10:04 -05:00
nbConsts + 1 ,
2018-11-13 03:36:30 -05:00
spanElement << I18nMutateOpCode . SHIFT_PARENT | I18nMutateOpCode . AppendChild ,
spanElement << I18nMutateOpCode . SHIFT_REF | I18nMutateOpCode . ElementEnd ,
] ,
update : [ ] ,
icus : null
2018-06-18 10:55:43 -04:00
} ) ;
2018-11-13 03:36:30 -05:00
/**** Second sub-template ****/
// middle
nbConsts = 2 ;
index = 0 ;
const bElement = 1 ;
2020-04-13 19:40:21 -04:00
opCodes = getOpCodes ( ( ) = > {
ɵ ɵ i18nStart ( index , MSG_DIV , 2 ) ;
} , null , nbConsts , index ) ;
2018-06-18 10:55:43 -04:00
2018-11-13 03:36:30 -05:00
expect ( opCodes ) . toEqual ( {
vars : 1 ,
create : [
bElement << I18nMutateOpCode . SHIFT_REF | I18nMutateOpCode . Select ,
index << I18nMutateOpCode . SHIFT_PARENT | I18nMutateOpCode . AppendChild ,
'middle' ,
2019-01-13 05:10:04 -05:00
nbConsts ,
2018-11-13 03:36:30 -05:00
bElement << I18nMutateOpCode . SHIFT_PARENT | I18nMutateOpCode . AppendChild ,
bElement << I18nMutateOpCode . SHIFT_REF | I18nMutateOpCode . ElementEnd ,
] ,
update : [ ] ,
icus : null
} ) ;
} ) ;
2018-06-18 10:55:43 -04:00
2018-11-13 03:36:30 -05:00
it ( 'for ICU expressions' , ( ) = > {
2019-02-20 17:21:20 -05:00
const MSG_DIV = ` {<7B> 0<EFBFBD> , plural,
= 0 { no < b title = "none" > emails < / b > ! }
= 1 { one < i > email < / i > }
2018-11-13 03:36:30 -05:00
other { <EFBFBD> 0 <EFBFBD> < span title = "<22> 1<EFBFBD> " > emails < / span > }
} ` ;
const nbConsts = 1 ;
const index = 0 ;
2020-04-13 19:40:21 -04:00
const opCodes = getOpCodes ( ( ) = > {
ɵ ɵ i18nStart ( index , MSG_DIV ) ;
} , null , nbConsts , index ) ;
2018-11-13 03:36:30 -05:00
const tIcuIndex = 0 ;
const icuCommentNodeIndex = index + 1 ;
2019-01-13 05:10:04 -05:00
const firstTextNodeIndex = index + 2 ;
2018-11-13 03:36:30 -05:00
const bElementNodeIndex = index + 3 ;
const iElementNodeIndex = index + 3 ;
const spanElementNodeIndex = index + 3 ;
const innerTextNode = index + 4 ;
const lastTextNode = index + 5 ;
2019-03-15 18:04:34 -04:00
const debugOps = ( opCodes as any ) . update . debug . operations ;
expect ( debugOps [ 0 ] . __raw_opCode ) . toBe ( 6 ) ;
expect ( debugOps [ 0 ] . checkBit ) . toBe ( 1 ) ;
expect ( debugOps [ 0 ] . type ) . toBe ( 'IcuSwitch' ) ;
expect ( debugOps [ 0 ] . nodeIndex ) . toBe ( 1 ) ;
expect ( debugOps [ 0 ] . tIcuIndex ) . toBe ( 0 ) ;
expect ( debugOps [ 0 ] . mainBinding ) . toBe ( '<27> 0<EFBFBD> ' ) ;
expect ( debugOps [ 1 ] . __raw_opCode ) . toBe ( 7 ) ;
expect ( debugOps [ 1 ] . checkBit ) . toBe ( 3 ) ;
expect ( debugOps [ 1 ] . type ) . toBe ( 'IcuUpdate' ) ;
expect ( debugOps [ 1 ] . nodeIndex ) . toBe ( 1 ) ;
expect ( debugOps [ 1 ] . tIcuIndex ) . toBe ( 0 ) ;
const icuDebugOps = ( opCodes as any ) . icus [ 0 ] . create [ 0 ] . debug . operations ;
let op : any ;
let i = 0 ;
op = icuDebugOps [ i ++ ] ;
expect ( op . __raw_opCode ) . toBe ( 'no ' ) ;
expect ( op . type ) . toBe ( 'Create Text Node' ) ;
expect ( op . nodeIndex ) . toBe ( 2 ) ;
expect ( op . text ) . toBe ( 'no ' ) ;
op = icuDebugOps [ i ++ ] ;
expect ( op . __raw_opCode ) . toBe ( 131073 ) ;
expect ( op . type ) . toBe ( 'AppendChild' ) ;
expect ( op . nodeIndex ) . toBe ( 1 ) ;
op = icuDebugOps [ i ++ ] ;
expect ( op . __raw_opCode ) . toEqual ( { marker : 'element' } ) ;
expect ( op . type ) . toBe ( 'ELEMENT_MARKER' ) ;
op = icuDebugOps [ i ++ ] ;
expect ( op . __raw_opCode ) . toBe ( 'b' ) ;
expect ( op . type ) . toBe ( 'Create Text Node' ) ;
expect ( op . nodeIndex ) . toBe ( 3 ) ;
expect ( op . text ) . toBe ( 'b' ) ;
op = icuDebugOps [ i ++ ] ;
expect ( op . __raw_opCode ) . toBe ( 131073 ) ;
expect ( op . type ) . toBe ( 'AppendChild' ) ;
expect ( op . nodeIndex ) . toBe ( 1 ) ;
op = icuDebugOps [ i ++ ] ;
expect ( op . __raw_opCode ) . toBe ( 28 ) ;
expect ( op . type ) . toBe ( 'Attr' ) ;
expect ( op . nodeIndex ) . toBe ( 3 ) ;
expect ( op . attrName ) . toBe ( 'title' ) ;
expect ( op . attrValue ) . toBe ( 'none' ) ;
op = icuDebugOps [ i ++ ] ;
expect ( op . __raw_opCode ) . toBe ( 'emails' ) ;
expect ( op . type ) . toBe ( 'Create Text Node' ) ;
expect ( op . nodeIndex ) . toBe ( 4 ) ;
expect ( op . text ) . toBe ( 'emails' ) ;
op = icuDebugOps [ i ++ ] ;
expect ( op . __raw_opCode ) . toBe ( 393217 ) ;
expect ( op . type ) . toBe ( 'AppendChild' ) ;
expect ( op . nodeIndex ) . toBe ( 3 ) ;
op = icuDebugOps [ i ++ ] ;
expect ( op . __raw_opCode ) . toBe ( '!' ) ;
expect ( op . type ) . toBe ( 'Create Text Node' ) ;
expect ( op . nodeIndex ) . toBe ( 5 ) ;
expect ( op . text ) . toBe ( '!' ) ;
op = icuDebugOps [ i ++ ] ;
expect ( op . __raw_opCode ) . toBe ( 131073 ) ;
expect ( op . type ) . toBe ( 'AppendChild' ) ;
expect ( op . nodeIndex ) . toBe ( 1 ) ;
2018-11-13 03:36:30 -05:00
expect ( opCodes ) . toEqual ( {
vars : 5 ,
create : [
2019-01-13 05:10:04 -05:00
COMMENT_MARKER , 'ICU 1' , icuCommentNodeIndex ,
2018-11-13 03:36:30 -05:00
index << I18nMutateOpCode . SHIFT_PARENT | I18nMutateOpCode . AppendChild
] ,
update : [
0 b1 , // mask for ICU main binding
3 , // skip 3 if not changed
- 1 , // icu main binding
icuCommentNodeIndex << I18nUpdateOpCode . SHIFT_REF | I18nUpdateOpCode . IcuSwitch , tIcuIndex ,
0 b11 , // mask for all ICU bindings
2 , // skip 2 if not changed
icuCommentNodeIndex << I18nUpdateOpCode . SHIFT_REF | I18nUpdateOpCode . IcuUpdate , tIcuIndex
] ,
icus : [ {
type : 1 ,
vars : [ 4 , 3 , 3 ] ,
childIcus : [ [ ] , [ ] , [ ] ] ,
cases : [ '0' , '1' , 'other' ] ,
create : [
[
'no ' ,
2019-01-13 05:10:04 -05:00
firstTextNodeIndex ,
2018-11-13 03:36:30 -05:00
icuCommentNodeIndex << I18nMutateOpCode . SHIFT_PARENT | I18nMutateOpCode . AppendChild ,
ELEMENT_MARKER ,
'b' ,
2019-01-13 05:10:04 -05:00
bElementNodeIndex ,
2018-11-13 03:36:30 -05:00
icuCommentNodeIndex << I18nMutateOpCode . SHIFT_PARENT | I18nMutateOpCode . AppendChild ,
bElementNodeIndex << I18nMutateOpCode . SHIFT_REF | I18nMutateOpCode . Attr ,
'title' ,
'none' ,
'emails' ,
2019-01-13 05:10:04 -05:00
innerTextNode ,
2018-11-13 03:36:30 -05:00
bElementNodeIndex << I18nMutateOpCode . SHIFT_PARENT | I18nMutateOpCode . AppendChild ,
'!' ,
2019-01-13 05:10:04 -05:00
lastTextNode ,
2018-11-13 03:36:30 -05:00
icuCommentNodeIndex << I18nMutateOpCode . SHIFT_PARENT | I18nMutateOpCode . AppendChild ,
] ,
[
2019-01-13 05:10:04 -05:00
'one ' , firstTextNodeIndex ,
2018-11-13 03:36:30 -05:00
icuCommentNodeIndex << I18nMutateOpCode . SHIFT_PARENT | I18nMutateOpCode . AppendChild ,
2019-01-13 05:10:04 -05:00
ELEMENT_MARKER , 'i' , iElementNodeIndex ,
2018-11-13 03:36:30 -05:00
icuCommentNodeIndex << I18nMutateOpCode . SHIFT_PARENT | I18nMutateOpCode . AppendChild ,
2019-01-13 05:10:04 -05:00
'email' , innerTextNode ,
2018-11-13 03:36:30 -05:00
iElementNodeIndex << I18nMutateOpCode . SHIFT_PARENT | I18nMutateOpCode . AppendChild
] ,
[
2019-01-13 05:10:04 -05:00
'' , firstTextNodeIndex ,
2018-11-13 03:36:30 -05:00
icuCommentNodeIndex << I18nMutateOpCode . SHIFT_PARENT | I18nMutateOpCode . AppendChild ,
2019-01-13 05:10:04 -05:00
ELEMENT_MARKER , 'span' , spanElementNodeIndex ,
2018-11-13 03:36:30 -05:00
icuCommentNodeIndex << I18nMutateOpCode . SHIFT_PARENT | I18nMutateOpCode . AppendChild ,
2019-01-13 05:10:04 -05:00
'emails' , innerTextNode ,
2018-11-13 03:36:30 -05:00
spanElementNodeIndex << I18nMutateOpCode . SHIFT_PARENT | I18nMutateOpCode . AppendChild
]
] ,
remove : [
[
2019-01-13 05:10:04 -05:00
firstTextNodeIndex << I18nMutateOpCode . SHIFT_REF | I18nMutateOpCode . Remove ,
2018-11-13 03:36:30 -05:00
innerTextNode << I18nMutateOpCode . SHIFT_REF | I18nMutateOpCode . Remove ,
bElementNodeIndex << I18nMutateOpCode . SHIFT_REF | I18nMutateOpCode . Remove ,
lastTextNode << I18nMutateOpCode . SHIFT_REF | I18nMutateOpCode . Remove ,
] ,
[
2019-01-13 05:10:04 -05:00
firstTextNodeIndex << I18nMutateOpCode . SHIFT_REF | I18nMutateOpCode . Remove ,
2018-11-13 03:36:30 -05:00
innerTextNode << I18nMutateOpCode . SHIFT_REF | I18nMutateOpCode . Remove ,
iElementNodeIndex << I18nMutateOpCode . SHIFT_REF | I18nMutateOpCode . Remove ,
] ,
[
2019-01-13 05:10:04 -05:00
firstTextNodeIndex << I18nMutateOpCode . SHIFT_REF | I18nMutateOpCode . Remove ,
2018-11-13 03:36:30 -05:00
innerTextNode << I18nMutateOpCode . SHIFT_REF | I18nMutateOpCode . Remove ,
spanElementNodeIndex << I18nMutateOpCode . SHIFT_REF | I18nMutateOpCode . Remove ,
]
] ,
update : [
[ ] , [ ] ,
[
0 b1 , // mask for the first binding
3 , // skip 3 if not changed
- 1 , // binding index
' ' , // text string to concatenate to the binding value
2019-01-13 05:10:04 -05:00
firstTextNodeIndex << I18nUpdateOpCode . SHIFT_REF | I18nUpdateOpCode . Text ,
2018-11-13 03:36:30 -05:00
0 b10 , // mask for the title attribute binding
4 , // skip 4 if not changed
- 2 , // binding index
bElementNodeIndex << I18nUpdateOpCode . SHIFT_REF | I18nUpdateOpCode . Attr ,
'title' , // attribute name
null // sanitize function
]
]
} ]
} ) ;
} ) ;
2018-07-09 14:59:43 -04:00
2018-11-13 03:36:30 -05:00
it ( 'for nested ICU expressions' , ( ) = > {
const MSG_DIV = ` {<7B> 0<EFBFBD> , plural,
2019-02-20 17:21:20 -05:00
= 0 { zero }
other { <EFBFBD> 0 <EFBFBD> { <EFBFBD> 1 <EFBFBD> , select ,
cat { cats }
dog { dogs }
2018-11-13 03:36:30 -05:00
other { animals }
} ! }
} ` ;
const nbConsts = 1 ;
const index = 0 ;
2020-04-13 19:40:21 -04:00
const opCodes = getOpCodes ( ( ) = > {
ɵ ɵ i18nStart ( index , MSG_DIV ) ;
} , null , nbConsts , index ) ;
2018-11-13 03:36:30 -05:00
const icuCommentNodeIndex = index + 1 ;
2019-01-13 05:10:04 -05:00
const firstTextNodeIndex = index + 2 ;
2018-11-13 03:36:30 -05:00
const nestedIcuCommentNodeIndex = index + 3 ;
2019-01-13 05:10:04 -05:00
const lastTextNodeIndex = index + 4 ;
const nestedTextNodeIndex = index + 5 ;
2018-11-13 03:36:30 -05:00
const tIcuIndex = 1 ;
const nestedTIcuIndex = 0 ;
expect ( opCodes ) . toEqual ( {
vars : 6 ,
create : [
2019-01-13 05:10:04 -05:00
COMMENT_MARKER , 'ICU 1' , icuCommentNodeIndex ,
2018-11-13 03:36:30 -05:00
index << I18nMutateOpCode . SHIFT_PARENT | I18nMutateOpCode . AppendChild
] ,
update : [
0 b1 , // mask for ICU main binding
3 , // skip 3 if not changed
- 1 , // icu main binding
icuCommentNodeIndex << I18nUpdateOpCode . SHIFT_REF | I18nUpdateOpCode . IcuSwitch , tIcuIndex ,
0 b11 , // mask for all ICU bindings
2 , // skip 2 if not changed
icuCommentNodeIndex << I18nUpdateOpCode . SHIFT_REF | I18nUpdateOpCode . IcuUpdate , tIcuIndex
] ,
icus : [
{
type : 0 ,
vars : [ 1 , 1 , 1 ] ,
childIcus : [ [ ] , [ ] , [ ] ] ,
cases : [ 'cat' , 'dog' , 'other' ] ,
create : [
[
2020-04-13 19:40:21 -04:00
'cats' , nestedTextNodeIndex ,
nestedIcuCommentNodeIndex << I18nMutateOpCode . SHIFT_PARENT |
2018-11-13 03:36:30 -05:00
I18nMutateOpCode . AppendChild
] ,
[
2020-04-13 19:40:21 -04:00
'dogs' , nestedTextNodeIndex ,
nestedIcuCommentNodeIndex << I18nMutateOpCode . SHIFT_PARENT |
2018-11-13 03:36:30 -05:00
I18nMutateOpCode . AppendChild
] ,
[
2020-04-13 19:40:21 -04:00
'animals' , nestedTextNodeIndex ,
nestedIcuCommentNodeIndex << I18nMutateOpCode . SHIFT_PARENT |
2018-11-13 03:36:30 -05:00
I18nMutateOpCode . AppendChild
]
] ,
remove : [
2019-01-13 05:10:04 -05:00
[ nestedTextNodeIndex << I18nMutateOpCode . SHIFT_REF | I18nMutateOpCode . Remove ] ,
[ nestedTextNodeIndex << I18nMutateOpCode . SHIFT_REF | I18nMutateOpCode . Remove ] ,
[ nestedTextNodeIndex << I18nMutateOpCode . SHIFT_REF | I18nMutateOpCode . Remove ]
2018-11-13 03:36:30 -05:00
] ,
update : [ [ ] , [ ] , [ ] ]
} ,
{
type : 1 ,
vars : [ 1 , 4 ] ,
childIcus : [ [ ] , [ 0 ] ] ,
cases : [ '0' , 'other' ] ,
create : [
[
2019-01-13 05:10:04 -05:00
'zero' , firstTextNodeIndex ,
2018-11-13 03:36:30 -05:00
icuCommentNodeIndex << I18nMutateOpCode . SHIFT_PARENT | I18nMutateOpCode . AppendChild
] ,
[
2019-01-13 05:10:04 -05:00
'' , firstTextNodeIndex ,
2018-11-13 03:36:30 -05:00
icuCommentNodeIndex << I18nMutateOpCode . SHIFT_PARENT | I18nMutateOpCode . AppendChild ,
2019-01-13 05:10:04 -05:00
COMMENT_MARKER , 'nested ICU 0' , nestedIcuCommentNodeIndex ,
2018-11-13 03:36:30 -05:00
icuCommentNodeIndex << I18nMutateOpCode . SHIFT_PARENT | I18nMutateOpCode . AppendChild ,
2019-01-13 05:10:04 -05:00
'!' , lastTextNodeIndex ,
2018-11-13 03:36:30 -05:00
icuCommentNodeIndex << I18nMutateOpCode . SHIFT_PARENT | I18nMutateOpCode . AppendChild
]
] ,
remove : [
2019-01-13 05:10:04 -05:00
[ firstTextNodeIndex << I18nMutateOpCode . SHIFT_REF | I18nMutateOpCode . Remove ] ,
2018-11-13 03:36:30 -05:00
[
2019-01-13 05:10:04 -05:00
firstTextNodeIndex << I18nMutateOpCode . SHIFT_REF | I18nMutateOpCode . Remove ,
lastTextNodeIndex << I18nMutateOpCode . SHIFT_REF | I18nMutateOpCode . Remove ,
2018-11-13 03:36:30 -05:00
0 << I18nMutateOpCode . SHIFT_REF | I18nMutateOpCode . RemoveNestedIcu ,
nestedIcuCommentNodeIndex << I18nMutateOpCode . SHIFT_REF | I18nMutateOpCode . Remove ,
]
] ,
update : [
[ ] ,
[
0 b1 , // mask for ICU main binding
3 , // skip 3 if not changed
- 1 , // binding index
' ' , // text string to concatenate to the binding value
2019-01-13 05:10:04 -05:00
firstTextNodeIndex << I18nUpdateOpCode . SHIFT_REF | I18nUpdateOpCode . Text ,
2018-11-13 03:36:30 -05:00
0 b10 , // mask for inner ICU main binding
3 , // skip 3 if not changed
- 2 , // inner ICU main binding
nestedIcuCommentNodeIndex << I18nUpdateOpCode . SHIFT_REF |
I18nUpdateOpCode . IcuSwitch ,
nestedTIcuIndex ,
0 b10 , // mask for all inner ICU bindings
2 , // skip 2 if not changed
nestedIcuCommentNodeIndex << I18nUpdateOpCode . SHIFT_REF |
I18nUpdateOpCode . IcuUpdate ,
nestedTIcuIndex
]
]
2018-06-18 10:55:43 -04:00
}
2018-11-13 03:36:30 -05:00
]
2018-06-18 10:55:43 -04:00
} ) ;
2018-11-13 03:36:30 -05:00
} ) ;
} ) ;
2018-06-18 10:55:43 -04:00
2018-11-13 03:36:30 -05:00
describe ( ` i18nAttribute ` , ( ) = > {
it ( 'for text' , ( ) = > {
const MSG_title = ` Hello world! ` ;
const MSG_div_attr = [ 'title' , MSG_title ] ;
const nbConsts = 2 ;
const index = 1 ;
const fixture = prepareFixture ( ( ) = > {
2019-05-17 21:49:21 -04:00
ɵ ɵ elementStart ( 0 , 'div' ) ;
ɵ ɵ i18nAttributes ( index , MSG_div_attr ) ;
ɵ ɵ elementEnd ( ) ;
2018-11-13 03:36:30 -05:00
} , null , nbConsts , index ) ;
const tView = fixture . hostView [ TVIEW ] ;
const opCodes = tView . data [ index + HEADER_OFFSET ] as I18nUpdateOpCodes ;
expect ( opCodes ) . toEqual ( [ ] ) ;
2018-11-22 00:14:06 -05:00
expect (
( getNativeByIndex ( 0 , fixture . hostView as LView ) as any as Element ) . getAttribute ( 'title' ) )
2018-11-13 03:36:30 -05:00
. toEqual ( MSG_title ) ;
} ) ;
2018-08-16 21:53:21 -04:00
2018-11-13 03:36:30 -05:00
it ( 'for simple bindings' , ( ) = > {
const MSG_title = ` Hello <20> 0<EFBFBD> ! ` ;
const MSG_div_attr = [ 'title' , MSG_title ] ;
const nbConsts = 2 ;
const index = 1 ;
2020-04-13 19:40:21 -04:00
const opCodes = getOpCodes ( ( ) = > {
ɵ ɵ i18nAttributes ( index , MSG_div_attr ) ;
} , null , nbConsts , index ) ;
2018-11-13 03:36:30 -05:00
expect ( opCodes ) . toEqual ( [
0 b1 , // bindings mask
6 , // if no update, skip 4
'Hello ' ,
- 1 , // binding index
'!' , ( index - 1 ) << I18nUpdateOpCode . SHIFT_REF | I18nUpdateOpCode . Attr , 'title' , null
] ) ;
} ) ;
2018-08-16 21:53:21 -04:00
2018-11-13 03:36:30 -05:00
it ( 'for multiple bindings' , ( ) = > {
const MSG_title = ` Hello <20> 0<EFBFBD> and <20> 1<EFBFBD> , again <20> 0<EFBFBD> ! ` ;
const MSG_div_attr = [ 'title' , MSG_title ] ;
const nbConsts = 2 ;
const index = 1 ;
2020-04-13 19:40:21 -04:00
const opCodes = getOpCodes ( ( ) = > {
ɵ ɵ i18nAttributes ( index , MSG_div_attr ) ;
} , null , nbConsts , index ) ;
2018-11-13 03:36:30 -05:00
expect ( opCodes ) . toEqual ( [
0 b11 , // bindings mask
10 , // size
'Hello ' , - 1 , ' and ' , - 2 , ', again ' , - 1 , '!' ,
( index - 1 ) << I18nUpdateOpCode . SHIFT_REF | I18nUpdateOpCode . Attr , 'title' , null
] ) ;
} ) ;
2018-06-18 10:55:43 -04:00
2018-11-13 03:36:30 -05:00
it ( 'for multiple attributes' , ( ) = > {
const MSG_title = ` Hello <20> 0<EFBFBD> ! ` ;
const MSG_div_attr = [ 'title' , MSG_title , 'aria-label' , MSG_title ] ;
const nbConsts = 2 ;
const index = 1 ;
2020-04-13 19:40:21 -04:00
const opCodes = getOpCodes ( ( ) = > {
ɵ ɵ i18nAttributes ( index , MSG_div_attr ) ;
} , null , nbConsts , index ) ;
2018-11-13 03:36:30 -05:00
expect ( opCodes ) . toEqual ( [
0 b1 , // bindings mask
6 , // if no update, skip 4
'Hello ' ,
- 1 , // binding index
'!' , ( index - 1 ) << I18nUpdateOpCode . SHIFT_REF | I18nUpdateOpCode . Attr , 'title' , null ,
0 b1 , // bindings mask
6 , // if no update, skip 4
'Hello ' ,
- 1 , // binding index
'!' , ( index - 1 ) << I18nUpdateOpCode . SHIFT_REF | I18nUpdateOpCode . Attr , 'aria-label' , null
] ) ;
} ) ;
} ) ;
2018-06-18 10:55:43 -04:00
2018-10-18 13:08:51 -04:00
describe ( 'i18nPostprocess' , ( ) = > {
it ( 'should handle valid cases' , ( ) = > {
2019-01-13 19:56:00 -05:00
const arr = [ '<27> *1:1<> <31> #2:1<> ' , '<27> #4:1<> ' , '<27> 6:1<> ' , '<27> /#2:1<> <31> /*1:1<> ' ] ;
2018-10-18 13:08:51 -04:00
const str = ` [ ${ arr . join ( '|' ) } ] ` ;
const cases = [
// empty string
[ '' , { } , '' ] ,
// string without any special cases
[ 'Foo [1,2,3] Bar - no ICU here' , { } , 'Foo [1,2,3] Bar - no ICU here' ] ,
// multi-value cases
[
` Start: ${ str } , ${ str } and ${ str } , ${ str } end. ` , { } ,
` Start: ${ arr [ 0 ] } , ${ arr [ 1 ] } and ${ arr [ 2 ] } , ${ arr [ 3 ] } end. `
] ,
// replace VAR_SELECT
[
'My ICU: {VAR_SELECT, select, =1 {one} other {other}}' , { VAR_SELECT : '<27> 1:2<> ' } ,
'My ICU: {<7B> 1:2<> , select, =1 {one} other {other}}'
] ,
[
'My ICU: {\n\n\tVAR_SELECT_1 \n\n, select, =1 {one} other {other}}' ,
{ VAR_SELECT_1 : '<27> 1:2<> ' } , 'My ICU: {\n\n\t<> 1:2<> \n\n, select, =1 {one} other {other}}'
] ,
// replace VAR_PLURAL
[
'My ICU: {VAR_PLURAL, plural, one {1} other {other}}' , { VAR_PLURAL : '<27> 1:2<> ' } ,
'My ICU: {<7B> 1:2<> , plural, one {1} other {other}}'
] ,
[
'My ICU: {\n\n\tVAR_PLURAL_1 \n\n, select, =1 {one} other {other}}' ,
{ VAR_PLURAL_1 : '<27> 1:2<> ' } , 'My ICU: {\n\n\t<> 1:2<> \n\n, select, =1 {one} other {other}}'
] ,
// do not replace VAR_* anywhere else in a string (only in ICU)
[
'My ICU: {VAR_PLURAL, plural, one {1} other {other}} VAR_PLURAL and VAR_SELECT' ,
{ VAR_PLURAL : '<27> 1:2<> ' } ,
'My ICU: {<7B> 1:2<> , plural, one {1} other {other}} VAR_PLURAL and VAR_SELECT'
] ,
// replace VAR_*'s in nested ICUs
[
'My ICU: {VAR_PLURAL, plural, one {1 - {VAR_SELECT, age, 50 {fifty} other {other}}} other {other}}' ,
{ VAR_PLURAL : '<27> 1:2<> ' , VAR_SELECT : '<27> 5<EFBFBD> ' } ,
'My ICU: {<7B> 1:2<> , plural, one {1 - {<7B> 5<EFBFBD> , age, 50 {fifty} other {other}}} other {other}}'
] ,
[
'My ICU: {VAR_PLURAL, plural, one {1 - {VAR_PLURAL_1, age, 50 {fifty} other {other}}} other {other}}' ,
{ VAR_PLURAL : '<27> 1:2<> ' , VAR_PLURAL_1 : '<27> 5<EFBFBD> ' } ,
'My ICU: {<7B> 1:2<> , plural, one {1 - {<7B> 5<EFBFBD> , age, 50 {fifty} other {other}}} other {other}}'
] ,
// ICU replacement
[
'My ICU #1: <20> I18N_EXP_ICU<43> , My ICU #2: <20> I18N_EXP_ICU<43> ' ,
{ ICU : [ 'ICU_VALUE_1' , 'ICU_VALUE_2' ] } , 'My ICU #1: ICU_VALUE_1, My ICU #2: ICU_VALUE_2'
] ,
// mixed case
[
` Start: ${ str } , ${ str } . ICU: {VAR_SELECT, count, 10 {ten} other {other}}.
Another ICU : <EFBFBD> I18N_EXP_ICU <EFBFBD> and $ { str } , $ { str } and one more ICU : <EFBFBD> I18N_EXP_ICU <EFBFBD> and end . ` ,
{ VAR_SELECT : '<27> 1:2<> ' , ICU : [ 'ICU_VALUE_1' , 'ICU_VALUE_2' ] } ,
` Start: ${ arr [ 0 ] } , ${ arr [ 1 ] } . ICU: {<7B> 1:2<> , count, 10 {ten} other {other}}.
Another ICU : ICU_VALUE_1 and $ { arr [ 2 ] } , $ { arr [ 3 ] } and one more ICU : ICU_VALUE_2 and end . ` ,
] ,
] ;
cases . forEach ( ( [ input , replacements , output ] ) = > {
2019-05-17 21:49:21 -04:00
expect ( ɵ ɵ i18nPostprocess ( input as string , replacements as any ) ) . toEqual ( output as string ) ;
2018-10-18 13:08:51 -04:00
} ) ;
} ) ;
2019-01-13 19:56:00 -05:00
it ( 'should handle nested template represented by multi-value placeholders' , ( ) = > {
/ * *
* < div i18n >
* < span >
* Hello - 1
* < / span >
* < span * ngIf = "visible" >
* Hello - 2
* < span * ngIf = "visible" >
* Hello - 3
* < span * ngIf = "visible" >
* Hello - 4
* < / span >
* < / span >
* < / span >
* < span >
* Hello - 5
* < / span >
* < / div >
* /
const generated = `
[ <EFBFBD> # 2 <EFBFBD> | <EFBFBD> # 4 <EFBFBD> ] Bonjour - 1 [ <EFBFBD> / # 2 <EFBFBD> | <EFBFBD> / # 1 :3 <EFBFBD> <EFBFBD> / * 2 :3 <EFBFBD> | <EFBFBD> / # 1 :2 <EFBFBD> <EFBFBD> / * 2 :2 <EFBFBD> | <EFBFBD> / # 1 :1 <EFBFBD> <EFBFBD> / * 3 :1 <EFBFBD> | <EFBFBD> / # 4 <EFBFBD> ]
[ <EFBFBD> * 3 :1 <EFBFBD> <EFBFBD> # 1 :1 <EFBFBD> | <EFBFBD> * 2 :2 <EFBFBD> <EFBFBD> # 1 :2 <EFBFBD> | <EFBFBD> * 2 :3 <EFBFBD> <EFBFBD> # 1 :3 <EFBFBD> ]
Bonjour - 2
[ <EFBFBD> * 3 :1 <EFBFBD> <EFBFBD> # 1 :1 <EFBFBD> | <EFBFBD> * 2 :2 <EFBFBD> <EFBFBD> # 1 :2 <EFBFBD> | <EFBFBD> * 2 :3 <EFBFBD> <EFBFBD> # 1 :3 <EFBFBD> ]
Bonjour - 3
[ <EFBFBD> * 3 :1 <EFBFBD> <EFBFBD> # 1 :1 <EFBFBD> | <EFBFBD> * 2 :2 <EFBFBD> <EFBFBD> # 1 :2 <EFBFBD> | <EFBFBD> * 2 :3 <EFBFBD> <EFBFBD> # 1 :3 <EFBFBD> ] Bonjour - 4 [ <EFBFBD> / # 2 <EFBFBD> | <EFBFBD> / # 1 :3 <EFBFBD> <EFBFBD> / * 2 :3 <EFBFBD> | <EFBFBD> / # 1 :2 <EFBFBD> <EFBFBD> / * 2 :2 <EFBFBD> | <EFBFBD> / # 1 :1 <EFBFBD> <EFBFBD> / * 3 :1 <EFBFBD> | <EFBFBD> / # 4 <EFBFBD> ]
[ <EFBFBD> / # 2 <EFBFBD> | <EFBFBD> / # 1 :3 <EFBFBD> <EFBFBD> / * 2 :3 <EFBFBD> | <EFBFBD> / # 1 :2 <EFBFBD> <EFBFBD> / * 2 :2 <EFBFBD> | <EFBFBD> / # 1 :1 <EFBFBD> <EFBFBD> / * 3 :1 <EFBFBD> | <EFBFBD> / # 4 <EFBFBD> ]
[ <EFBFBD> / # 2 <EFBFBD> | <EFBFBD> / # 1 :3 <EFBFBD> <EFBFBD> / * 2 :3 <EFBFBD> | <EFBFBD> / # 1 :2 <EFBFBD> <EFBFBD> / * 2 :2 <EFBFBD> | <EFBFBD> / # 1 :1 <EFBFBD> <EFBFBD> / * 3 :1 <EFBFBD> | <EFBFBD> / # 4 <EFBFBD> ]
[ <EFBFBD> # 2 <EFBFBD> | <EFBFBD> # 4 <EFBFBD> ] Bonjour - 5 [ <EFBFBD> / # 2 <EFBFBD> | <EFBFBD> / # 1 :3 <EFBFBD> <EFBFBD> / * 2 :3 <EFBFBD> | <EFBFBD> / # 1 :2 <EFBFBD> <EFBFBD> / * 2 :2 <EFBFBD> | <EFBFBD> / # 1 :1 <EFBFBD> <EFBFBD> / * 3 :1 <EFBFBD> | <EFBFBD> / # 4 <EFBFBD> ]
` ;
const final = `
<EFBFBD> # 2 <EFBFBD> Bonjour - 1 <EFBFBD> / # 2 <EFBFBD>
<EFBFBD> * 3 :1 <EFBFBD>
<EFBFBD> # 1 :1 <EFBFBD>
Bonjour - 2
<EFBFBD> * 2 :2 <EFBFBD>
<EFBFBD> # 1 :2 <EFBFBD>
Bonjour - 3
<EFBFBD> * 2 :3 <EFBFBD>
<EFBFBD> # 1 :3 <EFBFBD> Bonjour - 4 <EFBFBD> / # 1 :3 <EFBFBD>
<EFBFBD> / * 2 :3 <EFBFBD>
<EFBFBD> / # 1 :2 <EFBFBD>
<EFBFBD> / * 2 :2 <EFBFBD>
<EFBFBD> / # 1 :1 <EFBFBD>
<EFBFBD> / * 3 :1 <EFBFBD>
<EFBFBD> # 4 <EFBFBD> Bonjour - 5 <EFBFBD> / # 4 <EFBFBD>
` ;
2019-05-17 21:49:21 -04:00
expect ( ɵ ɵ i18nPostprocess ( generated . replace ( /\s+/g , '' ) ) ) . toEqual ( final . replace ( /\s+/g , '' ) ) ;
2019-01-13 19:56:00 -05:00
} ) ;
2018-10-18 13:08:51 -04:00
it ( 'should throw in case we have invalid string' , ( ) = > {
2019-05-23 09:17:42 -04:00
expect (
( ) = > ɵ ɵ i18nPostprocess (
'My ICU #1: <20> I18N_EXP_ICU<43> , My ICU #2: <20> I18N_EXP_ICU<43> ' , { ICU : [ 'ICU_VALUE_1' ] } ) )
. toThrowError ( ) ;
2018-10-18 13:08:51 -04:00
} ) ;
} ) ;
2018-06-18 10:55:43 -04:00
} ) ;