@@ -14,7 +14,7 @@ const getSemicolonReplacements = (
1414 return [ new Lint . Replacement ( absolutePosition , 1 , '; ' ) ] ;
1515} ;
1616
17- type Option = 'check-id' | 'check-i18n ' ;
17+ type Option = 'check-id' | 'check-text ' ;
1818
1919interface ConfigurableVisitor {
2020 getOption ( ) : Option ;
@@ -47,24 +47,41 @@ class I18NAttrVisitor extends BasicTemplateAstVisitor
4747
4848class I18NTextVisitor extends BasicTemplateAstVisitor
4949 implements ConfigurableVisitor {
50- visitAttr ( attr : ast . AttrAst , context : BasicTemplateAstVisitor ) {
51- if ( attr . name === 'i18n' && attr . value ) {
52- const parts = attr . value . split ( '@@' ) ;
53- if ( parts . length <= 1 || parts [ 1 ] . length === 0 ) {
54- const span = attr . sourceSpan ;
50+ private hasI18n = false ;
51+ private nestedElements = [ ] ;
52+ private visited = new Set < ast . TextAst > ( ) ;
53+
54+ visitText ( text : ast . TextAst , context : BasicTemplateAstVisitor ) {
55+ if ( ! this . visited . has ( text ) ) {
56+ this . visited . add ( text ) ;
57+ const textNonEmpty = text . value . trim ( ) . length > 0 ;
58+ if (
59+ ( ! this . hasI18n && textNonEmpty && this . nestedElements . length ) ||
60+ ( textNonEmpty && ! this . nestedElements . length )
61+ ) {
62+ const span = text . sourceSpan ;
5563context . addFailure (
5664 context . createFailure (
5765 span . start . offset ,
5866 span . end . offset - span . start . offset ,
59- 'Missing custom message identifier. For more information visit https://angular.io/guide/ i18n'
67+ 'Each element containing text node should has an i18n attribute '
6068 )
6169) ;
6270 }
6371 }
64- super . visitAttr ( attr , context ) ;
72+ super . visitText ( text , context ) ;
73+ }
74+
75+ visitElement ( element : ast . ElementAst , context : BasicTemplateAstVisitor ) {
76+ this . hasI18n = element . attrs . some ( e => e . name === 'i18n' ) ;
77+ this . nestedElements . push ( element . name ) ;
78+ super . visitElement ( element , context ) ;
79+ this . nestedElements . pop ( ) ;
80+ this . hasI18n = false ;
6581 }
82+
6683 getOption ( ) : Option {
67- return 'check-id ' ;
84+ return 'check-text ' ;
6885 }
6986}
7087
@@ -97,6 +114,26 @@ class I18NTemplateVisitor extends BasicTemplateAstVisitor {
97114 . forEach ( f => this . addFailure ( f ) ) ;
98115 super . visitAttr ( attr , context ) ;
99116 }
117+
118+ visitElement ( element : ast . ElementAst , context : any ) : any {
119+ const options = this . getOptions ( ) ;
120+ this . visitors
121+ . filter ( v => options . indexOf ( v . getOption ( ) ) >= 0 )
122+ . map ( v => v . visitElement ( element , this ) )
123+ . filter ( f => ! ! f )
124+ . forEach ( f => this . addFailure ( f ) ) ;
125+ super . visitElement ( element , context ) ;
126+ }
127+
128+ visitText ( text : ast . TextAst , context : any ) : any {
129+ const options = this . getOptions ( ) ;
130+ this . visitors
131+ . filter ( v => options . indexOf ( v . getOption ( ) ) >= 0 )
132+ . map ( v => v . visitText ( text , this ) )
133+ . filter ( f => ! ! f )
134+ . forEach ( f => this . addFailure ( f ) ) ;
135+ super . visitText ( text , context ) ;
136+ }
100137}
101138
102139export class Rule extends Lint . Rules . AbstractRule {
0 commit comments