@@ -32,7 +32,8 @@ export class I18N {
3232 */
3333 processConfig ( options ) {
3434 const { location, ...restOptions } = { ...DEFAULT_CONFIG , ...options }
35- const parsedLocation = location . replace ( / \/ ? $ / , '/' )
35+ // Ensure location ends with a slash
36+ const parsedLocation = location . endsWith ( '/' ) ? location : `${ location } /`
3637 this . config = { location : parsedLocation , ...restOptions }
3738 const { override, preloaded = { } } = this . config
3839 const allLangs = Object . entries ( this . langs ) . concat ( Object . entries ( override || preloaded ) )
@@ -61,7 +62,8 @@ export class I18N {
6162 addLanguage ( locale , lang = { } ) {
6263 lang = typeof lang === 'string' ? I18N . processFile ( lang ) : lang
6364 this . applyLanguage ( locale , lang )
64- this . config . langs . push ( 'locale' )
65+ this . loaded . push ( locale )
66+ this . config . langs . push ( locale )
6567 }
6668
6769 /**
@@ -92,14 +94,14 @@ export class I18N {
9294 */
9395 makeSafe ( str ) {
9496 const mapObj = {
95- '{' : '\\{' ,
96- '}' : '\\}' ,
97- '|' : '\\|' ,
97+ '{' : String . raw `\{` ,
98+ '}' : String . raw `\}` ,
99+ '|' : String . raw `\|` ,
98100 }
99101
100- str = str . replace ( / [ { } | ] / g, matched => mapObj [ matched ] )
102+ const escapedStr = str . replaceAll ( / [ { } | ] / g, matched => mapObj [ matched ] )
101103
102- return new RegExp ( str , 'g' )
104+ return new RegExp ( escapedStr , 'g' )
103105 }
104106
105107 /**
@@ -121,23 +123,32 @@ export class I18N {
121123 * @return {String } updated string translation
122124 */
123125 get ( key , args ) {
124- const _this = this
125126 let value = this . getValue ( key )
126127 if ( ! value ) {
127128 return
128129 }
129130
131+ // No replacement needed if no args provided
132+ if ( ! args ) {
133+ return value
134+ }
135+
130136 const tokens = value . match ( / \{ [ ^ } ] + ?\} / g)
131137
132- if ( args && tokens ) {
133- if ( 'object' === typeof args ) {
134- for ( const token of tokens ) {
135- const key = token . substring ( 1 , token . length - 1 )
136- value = value . replace ( _this . makeSafe ( token ) , args [ key ] || '' )
137- }
138- } else {
139- value = value . replace ( / \{ [ ^ } ] + ?\} / g, args )
138+ // No tokens to replace
139+ if ( ! tokens ) {
140+ return value
141+ }
142+
143+ // Object args: replace each token with corresponding key
144+ if ( typeof args === 'object' ) {
145+ for ( const token of tokens ) {
146+ const tokenKey = token . slice ( 1 , - 1 )
147+ value = value . replace ( this . makeSafe ( token ) , args [ tokenKey ] ?? '' )
140148 }
149+ } else {
150+ // Primitive args: replace all tokens with same value
151+ value = value . replaceAll ( / \{ [ ^ } ] + ?\} / g, args )
141152 }
142153
143154 return value
@@ -149,7 +160,7 @@ export class I18N {
149160 * @return {Object } processed language
150161 */
151162 static processFile ( response ) {
152- return I18N . fromFile ( response . replace ( / \n \n / g , '\n' ) )
163+ return I18N . fromFile ( response . replaceAll ( ' \n\n' , '\n' ) )
153164 }
154165
155166 /**
@@ -165,7 +176,7 @@ export class I18N {
165176 const regex = / ^ ( .+ ?) * ?= * ?( [ ^ \n ] + ) /
166177 matches = regex . exec ( lines [ i ] )
167178 if ( matches ) {
168- lang [ matches [ 1 ] ] = matches [ 2 ] . replace ( / ( ^ \s + | \s + $ ) / g , '' )
179+ lang [ matches [ 1 ] ] = matches [ 2 ] . trim ( )
169180 }
170181 }
171182
@@ -178,28 +189,24 @@ export class I18N {
178189 * @param {Boolean } useCache
179190 * @return {Promise } resolves response
180191 */
181- loadLang ( locale , useCache = true ) {
182- const _this = this
183- return new Promise ( function ( resolve , reject ) {
184- if ( _this . loaded . indexOf ( locale ) !== - 1 && useCache ) {
185- _this . applyLanguage ( _this . langs [ locale ] )
186- return resolve ( _this . langs [ locale ] )
187- } else {
188- const langFile = [ _this . config . location , locale , _this . config . extension ] . join ( '' )
189- return fetchData ( langFile )
190- . then ( lang => {
191- const processedFile = I18N . processFile ( lang )
192- _this . applyLanguage ( locale , processedFile )
193- _this . loaded . push ( locale )
194- return resolve ( _this . langs [ locale ] )
195- } )
196- . catch ( err => {
197- console . error ( err )
198- const lang = _this . applyLanguage ( locale )
199- resolve ( lang )
200- } )
201- }
202- } )
192+ async loadLang ( locale , useCache = true ) {
193+ // Return cached language if already loaded
194+ if ( this . loaded . includes ( locale ) && useCache ) {
195+ return this . langs [ locale ]
196+ }
197+ // Fetch and process language file
198+ const langFile = `${ this . config . location } ${ locale } ${ this . config . extension } `
199+
200+ try {
201+ const lang = await fetchData ( langFile )
202+ const processedFile = I18N . processFile ( lang )
203+ this . applyLanguage ( locale , processedFile )
204+ this . loaded . push ( locale )
205+ return this . langs [ locale ]
206+ } catch ( err ) {
207+ console . error ( err )
208+ return this . applyLanguage ( locale )
209+ }
203210 }
204211
205212 /**
@@ -229,7 +236,10 @@ export class I18N {
229236 * @return {Promise } language
230237 */
231238 async setCurrent ( locale = 'en-US' ) {
232- await this . loadLang ( locale )
239+ if ( ! this . loaded . includes ( locale ) ) {
240+ await this . loadLang ( locale )
241+ }
242+
233243 this . locale = locale
234244 this . current = this . langs [ locale ]
235245
0 commit comments