| 
									
										
										
										
											2016-12-31 22:27:40 +08:00
										 |  |  | /** | 
					
						
							|  |  |  |  *  Translation Manager | 
					
						
							|  |  |  |  *  Handles the JavaScript side of translating strings | 
					
						
							|  |  |  |  *  in a way which fits with Laravel. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | class Translator { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /** | 
					
						
							|  |  |  |      * Create an instance, Passing in the required translations | 
					
						
							|  |  |  |      * @param translations | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  |     constructor(translations) { | 
					
						
							| 
									
										
										
										
											2019-07-06 21:52:25 +08:00
										 |  |  |         this.store = new Map(); | 
					
						
							|  |  |  |         this.parseTranslations(); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /** | 
					
						
							|  |  |  |      * Parse translations out of the page and place into the store. | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  |     parseTranslations() { | 
					
						
							|  |  |  |         const translationMetaTags = document.querySelectorAll('meta[name="translation"]'); | 
					
						
							|  |  |  |         for (let tag of translationMetaTags) { | 
					
						
							|  |  |  |             const key = tag.getAttribute('key'); | 
					
						
							|  |  |  |             const value = tag.getAttribute('value'); | 
					
						
							|  |  |  |             this.store.set(key, value); | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2016-12-31 22:27:40 +08:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /** | 
					
						
							|  |  |  |      * Get a translation, Same format as laravel's 'trans' helper | 
					
						
							|  |  |  |      * @param key | 
					
						
							|  |  |  |      * @param replacements | 
					
						
							|  |  |  |      * @returns {*} | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  |     get(key, replacements) { | 
					
						
							| 
									
										
										
										
											2019-07-06 21:52:25 +08:00
										 |  |  |         const text = this.getTransText(key); | 
					
						
							| 
									
										
										
										
											2017-09-03 23:37:51 +08:00
										 |  |  |         return this.performReplacements(text, replacements); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /** | 
					
						
							|  |  |  |      * Get pluralised text, Dependant on the given count. | 
					
						
							|  |  |  |      * Same format at laravel's 'trans_choice' helper. | 
					
						
							|  |  |  |      * @param key | 
					
						
							|  |  |  |      * @param count | 
					
						
							|  |  |  |      * @param replacements | 
					
						
							|  |  |  |      * @returns {*} | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  |     getPlural(key, count, replacements) { | 
					
						
							| 
									
										
										
										
											2019-07-06 21:52:25 +08:00
										 |  |  |         const text = this.getTransText(key); | 
					
						
							| 
									
										
										
										
											2020-07-29 01:19:18 +08:00
										 |  |  |         return this.parsePlural(text, count, replacements); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /** | 
					
						
							|  |  |  |      * Parse the given translation and find the correct plural option | 
					
						
							|  |  |  |      * to use. Similar format at laravel's 'trans_choice' helper. | 
					
						
							|  |  |  |      * @param {String} translation | 
					
						
							|  |  |  |      * @param {Number} count | 
					
						
							|  |  |  |      * @param {Object} replacements | 
					
						
							|  |  |  |      * @returns {String} | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  |     parsePlural(translation, count, replacements) { | 
					
						
							|  |  |  |         const splitText = translation.split('|'); | 
					
						
							| 
									
										
										
										
											2019-07-06 21:52:25 +08:00
										 |  |  |         const exactCountRegex = /^{([0-9]+)}/; | 
					
						
							|  |  |  |         const rangeRegex = /^\[([0-9]+),([0-9*]+)]/; | 
					
						
							| 
									
										
										
										
											2017-09-03 23:37:51 +08:00
										 |  |  |         let result = null; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-08-25 18:02:58 +08:00
										 |  |  |         for (let t of splitText) { | 
					
						
							| 
									
										
										
										
											2017-09-03 23:37:51 +08:00
										 |  |  |             // Parse exact matches
 | 
					
						
							| 
									
										
										
										
											2019-07-06 21:52:25 +08:00
										 |  |  |             const exactMatches = t.match(exactCountRegex); | 
					
						
							| 
									
										
										
										
											2017-09-03 23:37:51 +08:00
										 |  |  |             if (exactMatches !== null && Number(exactMatches[1]) === count) { | 
					
						
							|  |  |  |                 result = t.replace(exactCountRegex, '').trim(); | 
					
						
							|  |  |  |                 break; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             // Parse range matches
 | 
					
						
							| 
									
										
										
										
											2019-07-06 21:52:25 +08:00
										 |  |  |             const rangeMatches = t.match(rangeRegex); | 
					
						
							| 
									
										
										
										
											2017-09-03 23:37:51 +08:00
										 |  |  |             if (rangeMatches !== null) { | 
					
						
							| 
									
										
										
										
											2019-07-06 21:52:25 +08:00
										 |  |  |                 const rangeStart = Number(rangeMatches[1]); | 
					
						
							| 
									
										
										
										
											2017-09-03 23:37:51 +08:00
										 |  |  |                 if (rangeStart <= count && (rangeMatches[2] === '*' || Number(rangeMatches[2]) >= count)) { | 
					
						
							|  |  |  |                     result = t.replace(rangeRegex, '').trim(); | 
					
						
							|  |  |  |                     break; | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if (result === null && splitText.length > 1) { | 
					
						
							|  |  |  |             result = (count === 1) ? splitText[0] : splitText[1]; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-08-25 18:02:58 +08:00
										 |  |  |         if (result === null) { | 
					
						
							|  |  |  |             result = splitText[0]; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-09-03 23:37:51 +08:00
										 |  |  |         return this.performReplacements(result, replacements); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /** | 
					
						
							|  |  |  |      * Fetched translation text from the store for the given key. | 
					
						
							|  |  |  |      * @param key | 
					
						
							|  |  |  |      * @returns {String|Object} | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  |     getTransText(key) { | 
					
						
							| 
									
										
										
										
											2019-07-06 21:52:25 +08:00
										 |  |  |         const value = this.store.get(key); | 
					
						
							| 
									
										
										
										
											2016-12-31 22:27:40 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |         if (value === undefined) { | 
					
						
							| 
									
										
										
										
											2019-07-06 21:52:25 +08:00
										 |  |  |             console.warn(`Translation with key "${key}" does not exist`); | 
					
						
							| 
									
										
										
										
											2016-12-31 22:27:40 +08:00
										 |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-09-03 23:37:51 +08:00
										 |  |  |         return value; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2016-12-31 22:27:40 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-09-03 23:37:51 +08:00
										 |  |  |     /** | 
					
						
							|  |  |  |      * Perform replacements on a string. | 
					
						
							|  |  |  |      * @param {String} string | 
					
						
							|  |  |  |      * @param {Object} replacements | 
					
						
							|  |  |  |      * @returns {*} | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  |     performReplacements(string, replacements) { | 
					
						
							|  |  |  |         if (!replacements) return string; | 
					
						
							| 
									
										
										
										
											2019-07-06 21:52:25 +08:00
										 |  |  |         const replaceMatches = string.match(/:([\S]+)/g); | 
					
						
							| 
									
										
										
										
											2017-09-03 23:37:51 +08:00
										 |  |  |         if (replaceMatches === null) return string; | 
					
						
							| 
									
										
										
										
											2016-12-31 22:27:40 +08:00
										 |  |  |         replaceMatches.forEach(match => { | 
					
						
							| 
									
										
										
										
											2019-07-06 21:52:25 +08:00
										 |  |  |             const key = match.substring(1); | 
					
						
							| 
									
										
										
										
											2016-12-31 22:27:40 +08:00
										 |  |  |             if (typeof replacements[key] === 'undefined') return; | 
					
						
							| 
									
										
										
										
											2017-09-03 23:37:51 +08:00
										 |  |  |             string = string.replace(match, replacements[key]); | 
					
						
							| 
									
										
										
										
											2016-12-31 22:27:40 +08:00
										 |  |  |         }); | 
					
						
							| 
									
										
										
										
											2017-09-03 23:37:51 +08:00
										 |  |  |         return string; | 
					
						
							| 
									
										
										
										
											2016-12-31 22:27:40 +08:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-11-10 05:17:35 +08:00
										 |  |  | export default Translator; |