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+ /* eslint-disable no-inner-declarations */
42+ function getMessage ( globalize , path ) {
43+ return globalize . cldr . get ( [ "globalize-messages/{bundle}" ] . concat ( path ) ) ;
44+ }
45+
46+ function setMessage ( globalize , path , message ) {
47+ var data = { } ;
48+ function set ( data , path , value ) {
49+ var i ;
50+ var node = data ;
51+ var length = path . length ;
52+
53+ for ( i = 0 ; i < length - 1 ; i ++ ) {
54+ if ( ! node [ path [ i ] ] ) {
55+ node [ path [ i ] ] = { } ;
56+ }
57+ node = node [ path [ i ] ] ;
58+ }
59+ node [ path [ i ] ] = value ;
60+ }
61+ set ( data , [ globalize . cldr . attributes . bundle ] . concat ( path ) , message ) ;
62+ Globalize . loadMessages ( data ) ;
63+ }
64+ /* eslint-enable no-inner-declarations */
65+
66+ if ( globalize . cldr ) {
67+ if ( ! getMessage ( globalize , path ) ) {
68+ defaultMessage = defaultMessage || getDefaultMessage ( children ) ;
69+ setMessage ( globalize , path , defaultMessage ) ;
70+ }
71+ }
72+ }
73+ }
74+
75+ function replaceElements ( props , formatted ) {
76+ var elements = props . elements ;
77+
78+ function _replaceElements ( string , elements ) {
79+ if ( typeof string !== "string" ) {
80+ throw new Error ( "Missing or invalid string `" + string + "` (" + typeof string + ")" ) ;
81+ }
82+ if ( typeof elements !== "object" ) {
83+ throw new Error ( "Missing or invalid elements `" + elements + "` (" + typeof elements + ")" ) ;
84+ }
85+
86+ // Given [x, y, z], it returns [x, element, y, element, z].
87+ function spreadElementsInBetweenItems ( array , element ) {
88+ var getElement = typeof element === "function" ? element : function ( ) {
89+ return element ;
90+ } ;
91+ return array . slice ( 1 ) . reduce ( function ( ret , item , i ) {
92+ ret . push ( getElement ( i ) , item ) ;
93+ return ret ;
94+ } , [ array [ 0 ] ] ) ;
95+ }
96+
97+ function splice ( sourceArray , start , deleteCount , itemsArray ) {
98+ [ ] . splice . apply ( sourceArray , [ start , deleteCount ] . concat ( itemsArray ) ) ;
99+ }
100+
101+ return Object . keys ( elements ) . reduce ( function ( ret , key ) {
102+ var element = elements [ key ] ;
103+
104+ ret . forEach ( function ( string , i ) {
105+ var aux , contents , regexp , regexp2 ;
106+
107+ // Insert array into the correct ret position.
108+ function replaceRetItem ( array ) {
109+ splice ( ret , i , 1 , array ) ;
110+ }
111+
112+ if ( typeof string !== "string" ) {
113+ return ; // continue;
114+ }
115+
116+ // Empty tags, e.g., `[foo/]`.
117+ aux = string . split ( "[" + key + "/]" ) ;
118+ if ( aux . length > 1 ) {
119+ aux = spreadElementsInBetweenItems ( aux , element ) ;
120+ replaceRetItem ( aux ) ;
121+ return ; // continue;
122+ }
123+
124+ // Start-end tags, e.g., `[foo]content[/foo]`.
125+ regexp = new RegExp ( "\\[" + key + "\\][\\s\\S]*?\\[\\/" + key + "\\]" , "g" ) ;
126+ regexp2 = new RegExp ( "\\[" + key + "\\]([\\s\\S]*?)\\[\\/" + key + "\\]" ) ;
127+ aux = string . split ( regexp ) ;
128+ if ( aux . length > 1 ) {
129+ contents = string . match ( regexp ) . map ( function ( content ) {
130+ return content . replace ( regexp2 , "$1" ) ;
131+ } ) ;
132+ aux = spreadElementsInBetweenItems ( aux , function ( i ) {
133+ return React . cloneElement ( element , { } , contents [ i ] ) ;
134+ } ) ;
135+ replaceRetItem ( aux ) ;
136+ }
137+ } ) ;
138+
139+ return ret ;
140+ } , [ string ] ) ;
141+ }
142+
143+
144+ // Elements replacement.
145+ if ( elements ) {
146+ formatted = React . DOM . span . apply ( React . DOM . span , [ { } ] . concat ( _replaceElements ( formatted , elements ) ) ) ;
147+ }
148+
149+ return formatted ;
150+ }
151+
152+ function sanitizePath ( pathString ) {
153+ return pathString . trim ( ) . replace ( / \{ / g, "(" ) . replace ( / \} / g, ")" ) . replace ( / \/ / g, "|" ) . replace ( / \n / g, " " ) . replace ( / + / g, " " ) . replace ( / " / g, "'" ) ;
154+ }
155+
156+ // Overload Globalize's `.formatMessage` to allow default message.
157+ var globalizeMessageFormatter = Globalize . messageFormatter ;
158+ Globalize . messageFormatter = Globalize . prototype . messageFormatter = function ( pathOrMessage ) {
159+ var aux = { } ;
160+ var sanitizedPath = sanitizePath ( pathOrMessage ) ;
161+
162+ // Globalize runtime
163+ if ( ! this . cldr ) {
164+ // On runtime, the only way for deciding between using sanitizedPath or
165+ // pathOrMessage as path is by checking which formatter exists.
166+ arguments [ 0 ] = sanitizedPath ;
167+ aux = globalizeMessageFormatter . apply ( this , arguments ) ;
168+ arguments [ 0 ] = pathOrMessage ;
169+ return aux || globalizeMessageFormatter . apply ( this , arguments ) ;
170+ }
171+
172+ var sanitizedPathExists = this . cldr . get ( [ "globalize-messages/{bundle}" , sanitizedPath ] ) !== undefined ;
173+ var pathExists = this . cldr . get ( [ "globalize-messages/{bundle}" , pathOrMessage ] ) !== undefined ;
174+
175+ // Want to distinguish between default message and path value - just checking
176+ // for sanitizedPath won't be enough, because sanitizedPath !== pathOrMessage
177+ // for paths like "salutations/hi".
178+ if ( ! sanitizedPathExists && ! pathExists ) {
179+ aux [ this . cldr . attributes . bundle ] = { } ;
180+ aux [ this . cldr . attributes . bundle ] [ sanitizedPath ] = pathOrMessage ;
181+ Globalize . loadMessages ( aux ) ;
182+ sanitizedPathExists = true ;
183+ }
184+
185+ arguments [ 0 ] = sanitizedPathExists ? sanitizedPath : pathOrMessage ;
186+ return globalizeMessageFormatter . apply ( this , arguments ) ;
187+ } ;
188+
189+
190+ return generator ( "formatMessage" , [ "path" , "variables" ] , {
191+ beforeFormat : function ( ) {
192+ messageSetup ( this . globalize , this . props , this . globalizePropValues ) ;
193+ } ,
194+ afterFormat : function ( formattedValue ) {
195+ return replaceElements ( this . props , formattedValue ) ;
196+ }
197+ } ) ;
198+
199+ } ) ;
0 commit comments