133 lines
		
	
	
		
			4.2 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
		
		
			
		
	
	
			133 lines
		
	
	
		
			4.2 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
							 | 
						||
| 
								 | 
							
								 */
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/**
							 | 
						||
| 
								 | 
							
								 * Unique message id index that is needed to avoid different i18n vars with the same name to appear
							 | 
						||
| 
								 | 
							
								 * in the i18n block while generating an output string (used to verify compiler-generated code).
							 | 
						||
| 
								 | 
							
								 */
							 | 
						||
| 
								 | 
							
								let msgIndex = 0;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/**
							 | 
						||
| 
								 | 
							
								 * Generate a string that represents expected i18n block content for a simple message.
							 | 
						||
| 
								 | 
							
								 */
							 | 
						||
| 
								 | 
							
								export function i18nMsg(message: string, placeholders: Placeholder[], meta: Meta): string {
							 | 
						||
| 
								 | 
							
								  const varName = `$I18N_${msgIndex++}$`;
							 | 
						||
| 
								 | 
							
								  const closurePlaceholders = i18nPlaceholdersToString(placeholders);
							 | 
						||
| 
								 | 
							
								  const locMessageWithPlaceholders = i18nMsgInsertLocalizePlaceholders(message, placeholders);
							 | 
						||
| 
								 | 
							
								  return `
							 | 
						||
| 
								 | 
							
								    let ${varName};
							 | 
						||
| 
								 | 
							
								    if (typeof ngI18nClosureMode !== "undefined" && ngI18nClosureMode) {
							 | 
						||
| 
								 | 
							
								        ${i18nMsgClosureMeta(meta)}
							 | 
						||
| 
								 | 
							
								        const $MSG_EXTERNAL_${msgIndex}$ = goog.getMsg("${message}"${closurePlaceholders});
							 | 
						||
| 
								 | 
							
								        ${varName} = $MSG_EXTERNAL_${msgIndex}$;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    else {
							 | 
						||
| 
								 | 
							
								      ${varName} = $localize \`${i18nMsgLocalizeMeta(meta)}${locMessageWithPlaceholders}\`;
							 | 
						||
| 
								 | 
							
								    }`;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/**
							 | 
						||
| 
								 | 
							
								 * Generate a string that represents expected i18n block content for a message that requires
							 | 
						||
| 
								 | 
							
								 * post-processing.
							 | 
						||
| 
								 | 
							
								 */
							 | 
						||
| 
								 | 
							
								export function i18nMsgWithPostprocess(
							 | 
						||
| 
								 | 
							
								    message: string, placeholders: Placeholder[], meta: Meta,
							 | 
						||
| 
								 | 
							
								    postprocessPlaceholders: Placeholder[]): string {
							 | 
						||
| 
								 | 
							
								  const varName = `$I18N_${msgIndex}$`;
							 | 
						||
| 
								 | 
							
								  const ppPlaceholders = i18nPlaceholdersToString(postprocessPlaceholders);
							 | 
						||
| 
								 | 
							
								  return String.raw`
							 | 
						||
| 
								 | 
							
								        ${i18nMsg(message, placeholders, meta)}
							 | 
						||
| 
								 | 
							
								        ${varName} = $r3$.ɵɵi18nPostprocess($${varName}$${ppPlaceholders});
							 | 
						||
| 
								 | 
							
								      `;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/**
							 | 
						||
| 
								 | 
							
								 * Generates a string that represents expected i18n block content for an ICU.
							 | 
						||
| 
								 | 
							
								 */
							 | 
						||
| 
								 | 
							
								export function i18nIcuMsg(message: string, placeholders: Placeholder[]): string {
							 | 
						||
| 
								 | 
							
								  return i18nMsgWithPostprocess(message, [], {}, placeholders);
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/**
							 | 
						||
| 
								 | 
							
								 * Describes placeholder type used in tests.
							 | 
						||
| 
								 | 
							
								 *
							 | 
						||
| 
								 | 
							
								 * Note: the type is an array (not an object), since it's important to preserve the order of
							 | 
						||
| 
								 | 
							
								 * placeholders (so that we can compare it with generated output).
							 | 
						||
| 
								 | 
							
								 */
							 | 
						||
| 
								 | 
							
								export type Placeholder = [string, string];
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/**
							 | 
						||
| 
								 | 
							
								 * Describes message metadata object.
							 | 
						||
| 
								 | 
							
								 */
							 | 
						||
| 
								 | 
							
								interface Meta {
							 | 
						||
| 
								 | 
							
								  desc?: string;
							 | 
						||
| 
								 | 
							
								  meaning?: string;
							 | 
						||
| 
								 | 
							
								  id?: string;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/**
							 | 
						||
| 
								 | 
							
								 * Convert a set of placeholders to a string (as it's expected from compiler).
							 | 
						||
| 
								 | 
							
								 */
							 | 
						||
| 
								 | 
							
								function i18nPlaceholdersToString(placeholders: Placeholder[]): string {
							 | 
						||
| 
								 | 
							
								  if (placeholders.length === 0) return '';
							 | 
						||
| 
								 | 
							
								  const result = placeholders.map(([key, value]) => `"${key}": ${quotedValue(value)}`);
							 | 
						||
| 
								 | 
							
								  return `, { ${result.join(',')} }`;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/**
							 | 
						||
| 
								 | 
							
								 * Transform a message in a Closure format to a $localize version.
							 | 
						||
| 
								 | 
							
								 */
							 | 
						||
| 
								 | 
							
								function i18nMsgInsertLocalizePlaceholders(message: string, placeholders: Placeholder[]): string {
							 | 
						||
| 
								 | 
							
								  if (placeholders.length > 0) {
							 | 
						||
| 
								 | 
							
								    message = message.replace(/{\$(.*?)}/g, function(_, name) {
							 | 
						||
| 
								 | 
							
								      const value = placeholders.find(([k, _]) => k === name)![1];
							 | 
						||
| 
								 | 
							
								      // e.g. startDivTag -> START_DIV_TAG
							 | 
						||
| 
								 | 
							
								      const key = name.replace(/[A-Z]/g, (ch: string) => '_' + ch).toUpperCase();
							 | 
						||
| 
								 | 
							
								      return '$' +
							 | 
						||
| 
								 | 
							
								          `{${quotedValue(value)}}:${key}:`;
							 | 
						||
| 
								 | 
							
								    });
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								  return message;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/**
							 | 
						||
| 
								 | 
							
								 * Generate a string that represents expected Closure metadata output comment.
							 | 
						||
| 
								 | 
							
								 */
							 | 
						||
| 
								 | 
							
								function i18nMsgClosureMeta(meta?: Meta): string {
							 | 
						||
| 
								 | 
							
								  if (!meta || !(meta.desc || meta.meaning)) return '';
							 | 
						||
| 
								 | 
							
								  return `
							 | 
						||
| 
								 | 
							
								    /**
							 | 
						||
| 
								 | 
							
								     ${meta.desc ? '* @desc ' + meta.desc : ''}
							 | 
						||
| 
								 | 
							
								     ${meta.meaning ? '* @meaning ' + meta.meaning : ''}
							 | 
						||
| 
								 | 
							
								     */
							 | 
						||
| 
								 | 
							
								  `;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/**
							 | 
						||
| 
								 | 
							
								 * Generate a string that represents expected $localize metadata output.
							 | 
						||
| 
								 | 
							
								 */
							 | 
						||
| 
								 | 
							
								function i18nMsgLocalizeMeta(meta?: Meta): string {
							 | 
						||
| 
								 | 
							
								  if (!meta) return '';
							 | 
						||
| 
								 | 
							
								  let localizeMeta = '';
							 | 
						||
| 
								 | 
							
								  if (meta.meaning) localizeMeta += `${meta.meaning}|`;
							 | 
						||
| 
								 | 
							
								  if (meta.desc) localizeMeta += meta.desc;
							 | 
						||
| 
								 | 
							
								  if (meta.id) localizeMeta += `@@${meta.id}`;
							 | 
						||
| 
								 | 
							
								  return localizeMeta !== '' ? `:${localizeMeta}:` : '';
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/**
							 | 
						||
| 
								 | 
							
								 * Wrap a string into quotes if needed.
							 | 
						||
| 
								 | 
							
								 *
							 | 
						||
| 
								 | 
							
								 * Note: if `value` starts with `$` it is a special case in tests when ICU reference is used as a
							 | 
						||
| 
								 | 
							
								 * placeholder value. Such special cases should not be wrapped in quotes.
							 | 
						||
| 
								 | 
							
								 */
							 | 
						||
| 
								 | 
							
								function quotedValue(value: string): string {
							 | 
						||
| 
								 | 
							
								  return value.startsWith('$') ? value : `"${value}"`;
							 | 
						||
| 
								 | 
							
								}
							 |