This commit provides the machinery for the new file-based compliance test approach for i18n tests, and migrates the i18n tests to this new format. PR Close #39661
		
			
				
	
	
		
			90 lines
		
	
	
		
			2.7 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
			
		
		
	
	
			90 lines
		
	
	
		
			2.7 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
| /**
 | |
|  * @license
 | |
|  * Copyright Google LLC All Rights Reserved.
 | |
|  *
 | |
|  * Use of this source code is governed by an MIT-style license that can be
 | |
|  * found in the LICENSE file at https://angular.io/license
 | |
|  */
 | |
| const EXTRACT_GENERATED_TRANSLATIONS_REGEXP =
 | |
|     /const\s*(.*?)\s*=\s*goog\.getMsg\("(.*?)",?\s*(.*?)\)/g;
 | |
| 
 | |
| /**
 | |
|  * Verify that placeholders in translation strings match placeholders in the object defined in the
 | |
|  * `goog.getMsg()` function arguments.
 | |
|  */
 | |
| export function verifyPlaceholdersIntegrity(output: string): boolean {
 | |
|   const translations = extractTranslations(output);
 | |
|   translations.forEach(([msg, args]) => {
 | |
|     const bodyPhs = extractPlaceholdersFromMsg(msg);
 | |
|     const argsPhs = extractPlaceholdersFromArgs(args);
 | |
|     if (bodyPhs.size !== argsPhs.size || diff(bodyPhs, argsPhs).size) {
 | |
|       return false;
 | |
|     }
 | |
|   });
 | |
|   return true;
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * Verify that all the variables initialized with `goog.getMsg()` calls have
 | |
|  * unique names.
 | |
|  */
 | |
| export function verifyUniqueConsts(output: string): boolean {
 | |
|   extract(
 | |
|       output, EXTRACT_GENERATED_TRANSLATIONS_REGEXP,
 | |
|       (current: string[], state: Set<string>): string => {
 | |
|         const key = current[1];
 | |
|         if (state.has(key)) {
 | |
|           throw new Error(`Duplicate const ${key} found in generated output!`);
 | |
|         }
 | |
|         return key;
 | |
|       });
 | |
|   return true;
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|  * Extract pairs of `[msg, placeholders]`, in calls to `goog.getMsg()`, from the `source`.
 | |
|  *
 | |
|  * @param source The source code to parse.
 | |
|  */
 | |
| function extractTranslations(source: string): Set<string[]> {
 | |
|   return extract(
 | |
|       source, EXTRACT_GENERATED_TRANSLATIONS_REGEXP,
 | |
|       ([, , msg, placeholders]) => [msg, placeholders]);
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * Extract placeholder names (of the form `{$PLACEHOLDER}`) from the `msg`.
 | |
|  *
 | |
|  * @param msg The text of the message to parse.
 | |
|  */
 | |
| function extractPlaceholdersFromMsg(msg: string): Set<string> {
 | |
|   const regex = /{\$(.*?)}/g;
 | |
|   return extract(msg, regex, ([, placeholders]) => placeholders);
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * Extract the placeholder names (of the form `"PLACEHOLDER": "XXX"`) from the body of the argument
 | |
|  * provided as `args`.
 | |
|  *
 | |
|  * @param args The body of an object literal containing placeholder info.
 | |
|  */
 | |
| function extractPlaceholdersFromArgs(args: string): Set<string> {
 | |
|   const regex = /\s+"(.+?)":\s*".*?"/g;
 | |
|   return extract(args, regex, ([, placeholders]) => placeholders);
 | |
| }
 | |
| 
 | |
| function extract<T>(
 | |
|     from: string, regex: RegExp, transformFn: (match: string[], state: Set<T>) => T): Set<T> {
 | |
|   const result = new Set<T>();
 | |
|   let item;
 | |
|   while ((item = regex.exec(from)) !== null) {
 | |
|     result.add(transformFn(item, result));
 | |
|   }
 | |
|   return result;
 | |
| }
 | |
| 
 | |
| function diff(a: Set<string>, b: Set<string>): Set<string> {
 | |
|   return new Set(Array.from(a).filter(x => !b.has(x)));
 | |
| }
 |