1
+ define ( [ 'globalize' , 'react' , './generator' , 'globalize/message' , 'globalize/plural' ] , function ( Globalize , React , generator ) {
2
+
3
+ 'use strict' ;
4
+
5
+ function messageSetup ( globalize , props , globalizePropValues ) {
6
+ var defaultMessage ;
7
+ var children = props . children ;
8
+ var scope = props . scope ;
9
+
10
+ function getDefaultMessage ( children ) {
11
+ if ( typeof children === "string" ) {
12
+ return children ;
13
+ } else {
14
+ throw new Error ( "Invalid default message type `" + typeof children + "`" ) ;
15
+ }
16
+ }
17
+
18
+ // Set path - path as props supercedes default value.
19
+ if ( props . path ) {
20
+ // Override generator assumption. The generator assumes the globalizePropValues[0]
21
+ // (path) and props.children to be mutually exclusive, but this isn't
22
+ // true here for messages. Because, it's possible to use props.path (for
23
+ // path) and props.children for defaultMessage, which are two different
24
+ // variables.
25
+ globalizePropValues [ 0 ] = props . path ;
26
+ } else {
27
+ // Although the generator had already set globalizePropValues[0] (path) as
28
+ // props.children, here its type is checked and its value is sanitized.
29
+ defaultMessage = getDefaultMessage ( children ) ;
30
+ globalizePropValues [ 0 ] = sanitizePath ( defaultMessage ) ;
31
+ }
32
+
33
+ // Scope path.
34
+ if ( scope ) {
35
+ globalizePropValues [ 0 ] = scope + "/" + globalizePropValues [ 0 ] ;
36
+ }
37
+
38
+ // Development mode only.
39
+ if ( process . env . NODE_ENV !== "production" ) {
40
+ var path = props . path ? props . path . split ( "/" ) : [ globalizePropValues [ 0 ] ] ;
41
+ var getMessage = function ( globalize , path ) {
42
+ return globalize . cldr . get ( [ "globalize-messages/{bundle}" ] . concat ( path ) ) ;
43
+ } ;
44
+
45
+ var setMessage = function ( globalize , path , message ) {
46
+ var data = { } ;
47
+ function set ( data , path , value ) {
48
+ var i ;
49
+ var node = data ;
50
+ var length = path . length ;
51
+
52
+ for ( i = 0 ; i < length - 1 ; i ++ ) {
53
+ if ( ! node [ path [ i ] ] ) {
54
+ node [ path [ i ] ] = { } ;
55
+ }
56
+ node = node [ path [ i ] ] ;
57
+ }
58
+ node [ path [ i ] ] = value ;
59
+ }
60
+ set ( data , [ globalize . cldr . attributes . bundle ] . concat ( path ) , message ) ;
61
+ Globalize . loadMessages ( data ) ;
62
+ } ;
63
+
64
+ if ( globalize . cldr ) {
65
+ if ( ! getMessage ( globalize , path ) ) {
66
+ defaultMessage = defaultMessage || getDefaultMessage ( children ) ;
67
+ setMessage ( globalize , path , defaultMessage ) ;
68
+ }
69
+ }
70
+ }
71
+ }
72
+
73
+ function replaceElements ( props , formatted ) {
74
+ var elements = props . elements ;
75
+
76
+ function _replaceElements ( string , elements ) {
77
+ if ( typeof string !== "string" ) {
78
+ throw new Error ( "Missing or invalid string `" + string + "` (" + typeof string + ")" ) ;
79
+ }
80
+ if ( typeof elements !== "object" ) {
81
+ throw new Error ( "Missing or invalid elements `" + elements + "` (" + typeof elements + ")" ) ;
82
+ }
83
+
84
+ // Given [x, y, z], it returns [x, element, y, element, z].
85
+ function spreadElementsInBetweenItems ( array , element ) {
86
+ var getElement = typeof element === "function" ? element : function ( ) {
87
+ return element ;
88
+ } ;
89
+ return array . slice ( 1 ) . reduce ( function ( ret , item , i ) {
90
+ ret . push ( getElement ( i ) , item ) ;
91
+ return ret ;
92
+ } , [ array [ 0 ] ] ) ;
93
+ }
94
+
95
+ function splice ( sourceArray , start , deleteCount , itemsArray ) {
96
+ [ ] . splice . apply ( sourceArray , [ start , deleteCount ] . concat ( itemsArray ) ) ;
97
+ }
98
+
99
+ return Object . keys ( elements ) . reduce ( function ( ret , key ) {
100
+ var element = elements [ key ] ;
101
+
102
+ ret . forEach ( function ( string , i ) {
103
+ var aux , contents , regexp , regexp2 ;
104
+
105
+ // Insert array into the correct ret position.
106
+ function replaceRetItem ( array ) {
107
+ splice ( ret , i , 1 , array ) ;
108
+ }
109
+
110
+ if ( typeof string !== "string" ) {
111
+ return ; // continue;
112
+ }
113
+
114
+ // Empty tags, e.g., `[foo/]`.
115
+ aux = string . split ( "[" + key + "/]" ) ;
116
+ if ( aux . length > 1 ) {
117
+ aux = spreadElementsInBetweenItems ( aux , element ) ;
118
+ replaceRetItem ( aux ) ;
119
+ return ; // continue;
120
+ }
121
+
122
+ // Start-end tags, e.g., `[foo]content[/foo]`.
123
+ regexp = new RegExp ( "\\[" + key + "\\][\\s\\S]*?\\[\\/" + key + "\\]" , "g" ) ;
124
+ regexp2 = new RegExp ( "\\[" + key + "\\]([\\s\\S]*?)\\[\\/" + key + "\\]" ) ;
125
+ aux = string . split ( regexp ) ;
126
+ if ( aux . length > 1 ) {
127
+ contents = string . match ( regexp ) . map ( function ( content ) {
128
+ return content . replace ( regexp2 , "$1" ) ;
129
+ } ) ;
130
+ aux = spreadElementsInBetweenItems ( aux , function ( i ) {
131
+ return React . cloneElement ( element , { } , contents [ i ] ) ;
132
+ } ) ;
133
+ replaceRetItem ( aux ) ;
134
+ }
135
+ } ) ;
136
+
137
+ return ret ;
138
+ } , [ string ] ) ;
139
+ }
140
+
141
+
142
+ // Elements replacement.
143
+ if ( elements ) {
144
+ formatted = React . DOM . span . apply ( React . DOM . span , [ { } ] . concat ( _replaceElements ( formatted , elements ) ) ) ;
145
+ }
146
+
147
+ return formatted ;
148
+ }
149
+
150
+ function sanitizePath ( pathString ) {
151
+ return pathString . trim ( ) . replace ( / \{ / g, "(" ) . replace ( / \} / g, ")" ) . replace ( / \/ / g, "|" ) . replace ( / \n / g, " " ) . replace ( / + / g, " " ) . replace ( / " / g, "'" ) ;
152
+ }
153
+
154
+ // Overload Globalize's `.formatMessage` to allow default message.
155
+ var globalizeMessageFormatter = Globalize . messageFormatter ;
156
+ Globalize . messageFormatter = Globalize . prototype . messageFormatter = function ( pathOrMessage ) {
157
+ var aux = { } ;
158
+ var sanitizedPath = sanitizePath ( pathOrMessage ) ;
159
+
160
+ // Globalize runtime
161
+ if ( ! this . cldr ) {
162
+ // On runtime, the only way for deciding between using sanitizedPath or
163
+ // pathOrMessage as path is by checking which formatter exists.
164
+ arguments [ 0 ] = sanitizedPath ;
165
+ aux = globalizeMessageFormatter . apply ( this , arguments ) ;
166
+ arguments [ 0 ] = pathOrMessage ;
167
+ return aux || globalizeMessageFormatter . apply ( this , arguments ) ;
168
+ }
169
+
170
+ var sanitizedPathExists = this . cldr . get ( [ "globalize-messages/{bundle}" , sanitizedPath ] ) !== undefined ;
171
+ var pathExists = this . cldr . get ( [ "globalize-messages/{bundle}" , pathOrMessage ] ) !== undefined ;
172
+
173
+ // Want to distinguish between default message and path value - just checking
174
+ // for sanitizedPath won't be enough, because sanitizedPath !== pathOrMessage
175
+ // for paths like "salutations/hi".
176
+ if ( ! sanitizedPathExists && ! pathExists ) {
177
+ aux [ this . cldr . attributes . bundle ] = { } ;
178
+ aux [ this . cldr . attributes . bundle ] [ sanitizedPath ] = pathOrMessage ;
179
+ Globalize . loadMessages ( aux ) ;
180
+ sanitizedPathExists = true ;
181
+ }
182
+
183
+ arguments [ 0 ] = sanitizedPathExists ? sanitizedPath : pathOrMessage ;
184
+ return globalizeMessageFormatter . apply ( this , arguments ) ;
185
+ } ;
186
+
187
+
188
+ return generator ( "formatMessage" , [ "path" , "variables" ] , {
189
+ beforeFormat : function ( props ) {
190
+ messageSetup ( this . globalize , props , this . globalizePropValues ) ;
191
+ } ,
192
+ afterFormat : function ( formattedValue ) {
193
+ return replaceElements ( this . props , formattedValue ) ;
194
+ }
195
+ } ) ;
196
+
197
+ } ) ;
0 commit comments