Changing front

This commit is contained in:
2023-01-16 17:49:38 +01:00
parent 0b8a93b256
commit 4fe4be7730
48586 changed files with 4725790 additions and 17464 deletions
+8
View File
@@ -0,0 +1,8 @@
Angular
=======
The sources for this package are in the main [Angular](https://github.com/angular/angular) repo. Please file issues and pull requests against that repo.
Usage information and reference details can be found in [Angular documentation](https://angular.io/docs).
License: MIT
+12
View File
@@ -0,0 +1,12 @@
/**
* @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
*/
// DO NOT ADD public exports to this file.
// The public API exports are specified in the `./localize` module, which is checked by the
// public_api_guard rules
export * from './localize';
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi9wYWNrYWdlcy9sb2NhbGl6ZS9pbmRleC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTs7Ozs7O0dBTUc7QUFFSCwwQ0FBMEM7QUFDMUMsMkZBQTJGO0FBQzNGLHlCQUF5QjtBQUV6QixjQUFjLFlBQVksQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogQGxpY2Vuc2VcbiAqIENvcHlyaWdodCBHb29nbGUgTExDIEFsbCBSaWdodHMgUmVzZXJ2ZWQuXG4gKlxuICogVXNlIG9mIHRoaXMgc291cmNlIGNvZGUgaXMgZ292ZXJuZWQgYnkgYW4gTUlULXN0eWxlIGxpY2Vuc2UgdGhhdCBjYW4gYmVcbiAqIGZvdW5kIGluIHRoZSBMSUNFTlNFIGZpbGUgYXQgaHR0cHM6Ly9hbmd1bGFyLmlvL2xpY2Vuc2VcbiAqL1xuXG4vLyBETyBOT1QgQUREIHB1YmxpYyBleHBvcnRzIHRvIHRoaXMgZmlsZS5cbi8vIFRoZSBwdWJsaWMgQVBJIGV4cG9ydHMgYXJlIHNwZWNpZmllZCBpbiB0aGUgYC4vbG9jYWxpemVgIG1vZHVsZSwgd2hpY2ggaXMgY2hlY2tlZCBieSB0aGVcbi8vIHB1YmxpY19hcGlfZ3VhcmQgcnVsZXNcblxuZXhwb3J0ICogZnJvbSAnLi9sb2NhbGl6ZSc7XG4iXX0=
+12
View File
@@ -0,0 +1,12 @@
/**
* @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
*/
import { ɵ$localize as $localize, ɵ_global as _global } from '@angular/localize';
export { $localize };
// Attach $localize to the global context, as a side-effect of this module.
_global.$localize = $localize;
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi9wYWNrYWdlcy9sb2NhbGl6ZS9pbml0L2luZGV4LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOzs7Ozs7R0FNRztBQUNILE9BQU8sRUFBQyxVQUFVLElBQUksU0FBUyxFQUFFLFFBQVEsSUFBSSxPQUFPLEVBQXlELE1BQU0sbUJBQW1CLENBQUM7QUFFdkksT0FBTyxFQUFDLFNBQVMsRUFBMEIsQ0FBQztBQUU1QywyRUFBMkU7QUFDM0UsT0FBTyxDQUFDLFNBQVMsR0FBRyxTQUFTLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyIvKipcbiAqIEBsaWNlbnNlXG4gKiBDb3B5cmlnaHQgR29vZ2xlIExMQyBBbGwgUmlnaHRzIFJlc2VydmVkLlxuICpcbiAqIFVzZSBvZiB0aGlzIHNvdXJjZSBjb2RlIGlzIGdvdmVybmVkIGJ5IGFuIE1JVC1zdHlsZSBsaWNlbnNlIHRoYXQgY2FuIGJlXG4gKiBmb3VuZCBpbiB0aGUgTElDRU5TRSBmaWxlIGF0IGh0dHBzOi8vYW5ndWxhci5pby9saWNlbnNlXG4gKi9cbmltcG9ydCB7ybUkbG9jYWxpemUgYXMgJGxvY2FsaXplLCDJtV9nbG9iYWwgYXMgX2dsb2JhbCwgybVMb2NhbGl6ZUZuIGFzIExvY2FsaXplRm4sIMm1VHJhbnNsYXRlRm4gYXMgVHJhbnNsYXRlRm59IGZyb20gJ0Bhbmd1bGFyL2xvY2FsaXplJztcblxuZXhwb3J0IHskbG9jYWxpemUsIExvY2FsaXplRm4sIFRyYW5zbGF0ZUZufTtcblxuLy8gQXR0YWNoICRsb2NhbGl6ZSB0byB0aGUgZ2xvYmFsIGNvbnRleHQsIGFzIGEgc2lkZS1lZmZlY3Qgb2YgdGhpcyBtb2R1bGUuXG5fZ2xvYmFsLiRsb2NhbGl6ZSA9ICRsb2NhbGl6ZTtcbiJdfQ==
+11
View File
File diff suppressed because one or more lines are too long
+12
View File
@@ -0,0 +1,12 @@
/**
* @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
*/
// This file exports all the `utils` as private exports so that other parts of `@angular/localize`
// can make use of them.
export { $localize as ɵ$localize, _global as ɵ_global } from './src/localize';
export { computeMsgId as ɵcomputeMsgId, findEndOfBlock as ɵfindEndOfBlock, isMissingTranslationError as ɵisMissingTranslationError, makeParsedTranslation as ɵmakeParsedTranslation, makeTemplateObject as ɵmakeTemplateObject, MissingTranslationError as ɵMissingTranslationError, parseMessage as ɵparseMessage, parseMetadata as ɵparseMetadata, parseTranslation as ɵparseTranslation, splitBlock as ɵsplitBlock, translate as ɵtranslate } from './src/utils';
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicHJpdmF0ZS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uL3BhY2thZ2VzL2xvY2FsaXplL3ByaXZhdGUudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7Ozs7OztHQU1HO0FBRUgsa0dBQWtHO0FBQ2xHLHdCQUF3QjtBQUN4QixPQUFPLEVBQUMsU0FBUyxJQUFJLFVBQVUsRUFBRSxPQUFPLElBQUksUUFBUSxFQUF5RCxNQUFNLGdCQUFnQixDQUFDO0FBQ3BJLE9BQU8sRUFBQyxZQUFZLElBQUksYUFBYSxFQUFFLGNBQWMsSUFBSSxlQUFlLEVBQUUseUJBQXlCLElBQUksMEJBQTBCLEVBQUUscUJBQXFCLElBQUksc0JBQXNCLEVBQUUsa0JBQWtCLElBQUksbUJBQW1CLEVBQUUsdUJBQXVCLElBQUksd0JBQXdCLEVBQXVILFlBQVksSUFBSSxhQUFhLEVBQUUsYUFBYSxJQUFJLGNBQWMsRUFBRSxnQkFBZ0IsSUFBSSxpQkFBaUIsRUFBc0UsVUFBVSxJQUFJLFdBQVcsRUFBRSxTQUFTLElBQUksVUFBVSxFQUFDLE1BQU0sYUFBYSxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiLyoqXG4gKiBAbGljZW5zZVxuICogQ29weXJpZ2h0IEdvb2dsZSBMTEMgQWxsIFJpZ2h0cyBSZXNlcnZlZC5cbiAqXG4gKiBVc2Ugb2YgdGhpcyBzb3VyY2UgY29kZSBpcyBnb3Zlcm5lZCBieSBhbiBNSVQtc3R5bGUgbGljZW5zZSB0aGF0IGNhbiBiZVxuICogZm91bmQgaW4gdGhlIExJQ0VOU0UgZmlsZSBhdCBodHRwczovL2FuZ3VsYXIuaW8vbGljZW5zZVxuICovXG5cbi8vIFRoaXMgZmlsZSBleHBvcnRzIGFsbCB0aGUgYHV0aWxzYCBhcyBwcml2YXRlIGV4cG9ydHMgc28gdGhhdCBvdGhlciBwYXJ0cyBvZiBgQGFuZ3VsYXIvbG9jYWxpemVgXG4vLyBjYW4gbWFrZSB1c2Ugb2YgdGhlbS5cbmV4cG9ydCB7JGxvY2FsaXplIGFzIMm1JGxvY2FsaXplLCBfZ2xvYmFsIGFzIMm1X2dsb2JhbCwgTG9jYWxpemVGbiBhcyDJtUxvY2FsaXplRm4sIFRyYW5zbGF0ZUZuIGFzIMm1VHJhbnNsYXRlRm59IGZyb20gJy4vc3JjL2xvY2FsaXplJztcbmV4cG9ydCB7Y29tcHV0ZU1zZ0lkIGFzIMm1Y29tcHV0ZU1zZ0lkLCBmaW5kRW5kT2ZCbG9jayBhcyDJtWZpbmRFbmRPZkJsb2NrLCBpc01pc3NpbmdUcmFuc2xhdGlvbkVycm9yIGFzIMm1aXNNaXNzaW5nVHJhbnNsYXRpb25FcnJvciwgbWFrZVBhcnNlZFRyYW5zbGF0aW9uIGFzIMm1bWFrZVBhcnNlZFRyYW5zbGF0aW9uLCBtYWtlVGVtcGxhdGVPYmplY3QgYXMgybVtYWtlVGVtcGxhdGVPYmplY3QsIE1pc3NpbmdUcmFuc2xhdGlvbkVycm9yIGFzIMm1TWlzc2luZ1RyYW5zbGF0aW9uRXJyb3IsIFBhcnNlZE1lc3NhZ2UgYXMgybVQYXJzZWRNZXNzYWdlLCBQYXJzZWRUcmFuc2xhdGlvbiBhcyDJtVBhcnNlZFRyYW5zbGF0aW9uLCBQYXJzZWRUcmFuc2xhdGlvbnMgYXMgybVQYXJzZWRUcmFuc2xhdGlvbnMsIHBhcnNlTWVzc2FnZSBhcyDJtXBhcnNlTWVzc2FnZSwgcGFyc2VNZXRhZGF0YSBhcyDJtXBhcnNlTWV0YWRhdGEsIHBhcnNlVHJhbnNsYXRpb24gYXMgybVwYXJzZVRyYW5zbGF0aW9uLCBTb3VyY2VMb2NhdGlvbiBhcyDJtVNvdXJjZUxvY2F0aW9uLCBTb3VyY2VNZXNzYWdlIGFzIMm1U291cmNlTWVzc2FnZSwgc3BsaXRCbG9jayBhcyDJtXNwbGl0QmxvY2ssIHRyYW5zbGF0ZSBhcyDJtXRyYW5zbGF0ZX0gZnJvbSAnLi9zcmMvdXRpbHMnO1xuIl19
+10
View File
@@ -0,0 +1,10 @@
/**
* @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
*/
export { _global } from './src/global';
export { $localize } from './src/localize';
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi8uLi9wYWNrYWdlcy9sb2NhbGl6ZS9zcmMvbG9jYWxpemUvaW5kZXgudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7Ozs7OztHQU1HO0FBQ0gsT0FBTyxFQUFDLE9BQU8sRUFBQyxNQUFNLGNBQWMsQ0FBQztBQUNyQyxPQUFPLEVBQUMsU0FBUyxFQUEwQixNQUFNLGdCQUFnQixDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiLyoqXG4gKiBAbGljZW5zZVxuICogQ29weXJpZ2h0IEdvb2dsZSBMTEMgQWxsIFJpZ2h0cyBSZXNlcnZlZC5cbiAqXG4gKiBVc2Ugb2YgdGhpcyBzb3VyY2UgY29kZSBpcyBnb3Zlcm5lZCBieSBhbiBNSVQtc3R5bGUgbGljZW5zZSB0aGF0IGNhbiBiZVxuICogZm91bmQgaW4gdGhlIExJQ0VOU0UgZmlsZSBhdCBodHRwczovL2FuZ3VsYXIuaW8vbGljZW5zZVxuICovXG5leHBvcnQge19nbG9iYWx9IGZyb20gJy4vc3JjL2dsb2JhbCc7XG5leHBvcnQgeyRsb2NhbGl6ZSwgTG9jYWxpemVGbiwgVHJhbnNsYXRlRm59IGZyb20gJy4vc3JjL2xvY2FsaXplJztcbiJdfQ==
+17
View File
@@ -0,0 +1,17 @@
/**
* @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
*/
// Always use __globalThis if available, which is the spec-defined global variable across all
// environments, then fallback to __global first, because in Node tests both __global and
// __window may be defined and _global should be __global in that case. Note: Typeof/Instanceof
// checks are considered side-effects in Terser. We explicitly mark this as side-effect free:
// https://github.com/terser/terser/issues/250.
export const _global = ( /* @__PURE__ */(() => (typeof globalThis !== 'undefined' && globalThis) ||
(typeof global !== 'undefined' && global) || (typeof window !== 'undefined' && window) ||
(typeof self !== 'undefined' && typeof WorkerGlobalScope !== 'undefined' &&
self instanceof WorkerGlobalScope && self))());
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZ2xvYmFsLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vLi4vLi4vLi4vcGFja2FnZXMvbG9jYWxpemUvc3JjL2xvY2FsaXplL3NyYy9nbG9iYWwudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7Ozs7OztHQU1HO0FBb0JILDZGQUE2RjtBQUM3Rix5RkFBeUY7QUFDekYsK0ZBQStGO0FBQy9GLDZGQUE2RjtBQUM3RiwrQ0FBK0M7QUFDL0MsTUFBTSxDQUFDLE1BQU0sT0FBTyxHQUFRLEVBQUMsZUFBZ0IsQ0FDekMsR0FBRyxFQUFFLENBQUMsQ0FBQyxPQUFPLFVBQVUsS0FBSyxXQUFXLElBQUksVUFBVSxDQUFDO0lBQ25ELENBQUMsT0FBTyxNQUFNLEtBQUssV0FBVyxJQUFJLE1BQU0sQ0FBQyxJQUFJLENBQUMsT0FBTyxNQUFNLEtBQUssV0FBVyxJQUFJLE1BQU0sQ0FBQztJQUN0RixDQUFDLE9BQU8sSUFBSSxLQUFLLFdBQVcsSUFBSSxPQUFPLGlCQUFpQixLQUFLLFdBQVc7UUFDdkUsSUFBSSxZQUFZLGlCQUFpQixJQUFJLElBQUksQ0FBQyxDQUFDLEVBQUUsQ0FBQyxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiLyoqXG4gKiBAbGljZW5zZVxuICogQ29weXJpZ2h0IEdvb2dsZSBMTEMgQWxsIFJpZ2h0cyBSZXNlcnZlZC5cbiAqXG4gKiBVc2Ugb2YgdGhpcyBzb3VyY2UgY29kZSBpcyBnb3Zlcm5lZCBieSBhbiBNSVQtc3R5bGUgbGljZW5zZSB0aGF0IGNhbiBiZVxuICogZm91bmQgaW4gdGhlIExJQ0VOU0UgZmlsZSBhdCBodHRwczovL2FuZ3VsYXIuaW8vbGljZW5zZVxuICovXG5cbi8vICoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcbi8vIFRoaXMgY29kZSB0byBhY2Nlc3MgdGhlIGdsb2JhbCBvYmplY3QgaXMgbW9zdGx5IGNvcGllZCBmcm9tIGBwYWNrYWdlcy9jb3JlL3NyYy91dGlsL2dsb2JhbC50c2BcblxuZGVjbGFyZSBnbG9iYWwge1xuICAvLyBUaGUgZGVmaW5pdGlvbiBvZiBgV29ya2VyR2xvYmFsU2NvcGVgIG11c3QgYmUgY29tcGF0aWJsZSB3aXRoIHRoZSBvbmUgaW4gYGxpYi53ZWJ3b3JrZXIuZC50c2AsXG4gIC8vIGJlY2F1c2UgYWxsIGZpbGVzIHVuZGVyIGBwYWNrYWdlcy9gIGFyZSBjb21waWxlZCB0b2dldGhlciBhcyBwYXJ0IG9mIHRoZVxuICAvLyBbbGVnYWN5LXVuaXQtdGVzdHMtc2F1Y2VsYWJzXVsxXSBDSSBqb2IsIGluY2x1ZGluZyB0aGUgYGxpYi53ZWJ3b3JrZXIuZC50c2AgdHlwaW5ncyBicm91Z2h0IGluXG4gIC8vIGJ5IFtzZXJ2aWNlLXdvcmtlci93b3JrZXIvc3JjL3NlcnZpY2Utd29ya2VyLmQudHNdWzJdLlxuICAvL1xuICAvLyBbMV06XG4gIC8vIGh0dHBzOi8vZ2l0aHViLmNvbS9hbmd1bGFyL2FuZ3VsYXIvYmxvYi9mZmVlYTYzZjQzZTZhN2ZkNDZiZTRhOGNkNWE1ZDI1NGM5OGRlYTA4Ly5jaXJjbGVjaS9jb25maWcueW1sI0w2ODFcbiAgLy8gWzJdOlxuICAvLyBodHRwczovL2dpdGh1Yi5jb20vYW5ndWxhci9hbmd1bGFyL2Jsb2IvMzE2ZGMyZjEyY2U4OTMxZjVmZjY2ZmE1ZjhkYTIxYzBkMjUxYTMzNy9wYWNrYWdlcy9zZXJ2aWNlLXdvcmtlci93b3JrZXIvc3JjL3NlcnZpY2Utd29ya2VyLmQudHMjTDlcbiAgaW50ZXJmYWNlIFdvcmtlckdsb2JhbFNjb3BlIGV4dGVuZHMgRXZlbnRUYXJnZXQsIFdpbmRvd09yV29ya2VyR2xvYmFsU2NvcGUge31cblxuICB2YXIgV29ya2VyR2xvYmFsU2NvcGU6IHtwcm90b3R5cGU6IFdvcmtlckdsb2JhbFNjb3BlOyBuZXcgKCk6IFdvcmtlckdsb2JhbFNjb3BlO307XG59XG5cbi8vIEFsd2F5cyB1c2UgX19nbG9iYWxUaGlzIGlmIGF2YWlsYWJsZSwgd2hpY2ggaXMgdGhlIHNwZWMtZGVmaW5lZCBnbG9iYWwgdmFyaWFibGUgYWNyb3NzIGFsbFxuLy8gZW52aXJvbm1lbnRzLCB0aGVuIGZhbGxiYWNrIHRvIF9fZ2xvYmFsIGZpcnN0LCBiZWNhdXNlIGluIE5vZGUgdGVzdHMgYm90aCBfX2dsb2JhbCBhbmRcbi8vIF9fd2luZG93IG1heSBiZSBkZWZpbmVkIGFuZCBfZ2xvYmFsIHNob3VsZCBiZSBfX2dsb2JhbCBpbiB0aGF0IGNhc2UuIE5vdGU6IFR5cGVvZi9JbnN0YW5jZW9mXG4vLyBjaGVja3MgYXJlIGNvbnNpZGVyZWQgc2lkZS1lZmZlY3RzIGluIFRlcnNlci4gV2UgZXhwbGljaXRseSBtYXJrIHRoaXMgYXMgc2lkZS1lZmZlY3QgZnJlZTpcbi8vIGh0dHBzOi8vZ2l0aHViLmNvbS90ZXJzZXIvdGVyc2VyL2lzc3Vlcy8yNTAuXG5leHBvcnQgY29uc3QgX2dsb2JhbDogYW55ID0gKC8qIEBfX1BVUkVfXyAqLyAoXG4gICAgKCkgPT4gKHR5cGVvZiBnbG9iYWxUaGlzICE9PSAndW5kZWZpbmVkJyAmJiBnbG9iYWxUaGlzKSB8fFxuICAgICAgICAodHlwZW9mIGdsb2JhbCAhPT0gJ3VuZGVmaW5lZCcgJiYgZ2xvYmFsKSB8fCAodHlwZW9mIHdpbmRvdyAhPT0gJ3VuZGVmaW5lZCcgJiYgd2luZG93KSB8fFxuICAgICAgICAodHlwZW9mIHNlbGYgIT09ICd1bmRlZmluZWQnICYmIHR5cGVvZiBXb3JrZXJHbG9iYWxTY29wZSAhPT0gJ3VuZGVmaW5lZCcgJiZcbiAgICAgICAgIHNlbGYgaW5zdGFuY2VvZiBXb3JrZXJHbG9iYWxTY29wZSAmJiBzZWxmKSkoKSk7XG4iXX0=
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+11
View File
@@ -0,0 +1,11 @@
/**
* @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
*/
export * from './src/constants';
export * from './src/messages';
export * from './src/translations';
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi8uLi9wYWNrYWdlcy9sb2NhbGl6ZS9zcmMvdXRpbHMvaW5kZXgudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7Ozs7OztHQU1HO0FBQ0gsY0FBYyxpQkFBaUIsQ0FBQztBQUNoQyxjQUFjLGdCQUFnQixDQUFDO0FBQy9CLGNBQWMsb0JBQW9CLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyIvKipcbiAqIEBsaWNlbnNlXG4gKiBDb3B5cmlnaHQgR29vZ2xlIExMQyBBbGwgUmlnaHRzIFJlc2VydmVkLlxuICpcbiAqIFVzZSBvZiB0aGlzIHNvdXJjZSBjb2RlIGlzIGdvdmVybmVkIGJ5IGFuIE1JVC1zdHlsZSBsaWNlbnNlIHRoYXQgY2FuIGJlXG4gKiBmb3VuZCBpbiB0aGUgTElDRU5TRSBmaWxlIGF0IGh0dHBzOi8vYW5ndWxhci5pby9saWNlbnNlXG4gKi9cbmV4cG9ydCAqIGZyb20gJy4vc3JjL2NvbnN0YW50cyc7XG5leHBvcnQgKiBmcm9tICcuL3NyYy9tZXNzYWdlcyc7XG5leHBvcnQgKiBmcm9tICcuL3NyYy90cmFuc2xhdGlvbnMnO1xuIl19
+58
View File
@@ -0,0 +1,58 @@
/**
* @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
*/
/**
* The character used to mark the start and end of a "block" in a `$localize` tagged string.
* A block can indicate metadata about the message or specify a name of a placeholder for a
* substitution expressions.
*
* For example:
*
* ```ts
* $localize`Hello, ${title}:title:!`;
* $localize`:meaning|description@@id:source message text`;
* ```
*/
export const BLOCK_MARKER = ':';
/**
* The marker used to separate a message's "meaning" from its "description" in a metadata block.
*
* For example:
*
* ```ts
* $localize `:correct|Indicates that the user got the answer correct: Right!`;
* $localize `:movement|Button label for moving to the right: Right!`;
* ```
*/
export const MEANING_SEPARATOR = '|';
/**
* The marker used to separate a message's custom "id" from its "description" in a metadata block.
*
* For example:
*
* ```ts
* $localize `:A welcome message on the home page@@myApp-homepage-welcome: Welcome!`;
* ```
*/
export const ID_SEPARATOR = '@@';
/**
* The marker used to separate legacy message ids from the rest of a metadata block.
*
* For example:
*
* ```ts
* $localize `:@@custom-id␟2df64767cd895a8fabe3e18b94b5b6b6f9e2e3f0: Welcome!`;
* ```
*
* Note that this character is the "symbol for the unit separator" (␟) not the "unit separator
* character" itself, since that has no visual representation. See https://graphemica.com/%E2%90%9F.
*
* Here is some background for the original "unit separator character":
* https://stackoverflow.com/questions/8695118/whats-the-file-group-record-unit-separator-control-characters-and-its-usage
*/
export const LEGACY_ID_INDICATOR = '\u241F';
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY29uc3RhbnRzLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vLi4vLi4vLi4vcGFja2FnZXMvbG9jYWxpemUvc3JjL3V0aWxzL3NyYy9jb25zdGFudHMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7Ozs7OztHQU1HO0FBRUg7Ozs7Ozs7Ozs7O0dBV0c7QUFDSCxNQUFNLENBQUMsTUFBTSxZQUFZLEdBQUcsR0FBRyxDQUFDO0FBRWhDOzs7Ozs7Ozs7R0FTRztBQUNILE1BQU0sQ0FBQyxNQUFNLGlCQUFpQixHQUFHLEdBQUcsQ0FBQztBQUVyQzs7Ozs7Ozs7R0FRRztBQUNILE1BQU0sQ0FBQyxNQUFNLFlBQVksR0FBRyxJQUFJLENBQUM7QUFFakM7Ozs7Ozs7Ozs7Ozs7O0dBY0c7QUFDSCxNQUFNLENBQUMsTUFBTSxtQkFBbUIsR0FBRyxRQUFRLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyIvKipcbiAqIEBsaWNlbnNlXG4gKiBDb3B5cmlnaHQgR29vZ2xlIExMQyBBbGwgUmlnaHRzIFJlc2VydmVkLlxuICpcbiAqIFVzZSBvZiB0aGlzIHNvdXJjZSBjb2RlIGlzIGdvdmVybmVkIGJ5IGFuIE1JVC1zdHlsZSBsaWNlbnNlIHRoYXQgY2FuIGJlXG4gKiBmb3VuZCBpbiB0aGUgTElDRU5TRSBmaWxlIGF0IGh0dHBzOi8vYW5ndWxhci5pby9saWNlbnNlXG4gKi9cblxuLyoqXG4gKiBUaGUgY2hhcmFjdGVyIHVzZWQgdG8gbWFyayB0aGUgc3RhcnQgYW5kIGVuZCBvZiBhIFwiYmxvY2tcIiBpbiBhIGAkbG9jYWxpemVgIHRhZ2dlZCBzdHJpbmcuXG4gKiBBIGJsb2NrIGNhbiBpbmRpY2F0ZSBtZXRhZGF0YSBhYm91dCB0aGUgbWVzc2FnZSBvciBzcGVjaWZ5IGEgbmFtZSBvZiBhIHBsYWNlaG9sZGVyIGZvciBhXG4gKiBzdWJzdGl0dXRpb24gZXhwcmVzc2lvbnMuXG4gKlxuICogRm9yIGV4YW1wbGU6XG4gKlxuICogYGBgdHNcbiAqICRsb2NhbGl6ZWBIZWxsbywgJHt0aXRsZX06dGl0bGU6IWA7XG4gKiAkbG9jYWxpemVgOm1lYW5pbmd8ZGVzY3JpcHRpb25AQGlkOnNvdXJjZSBtZXNzYWdlIHRleHRgO1xuICogYGBgXG4gKi9cbmV4cG9ydCBjb25zdCBCTE9DS19NQVJLRVIgPSAnOic7XG5cbi8qKlxuICogVGhlIG1hcmtlciB1c2VkIHRvIHNlcGFyYXRlIGEgbWVzc2FnZSdzIFwibWVhbmluZ1wiIGZyb20gaXRzIFwiZGVzY3JpcHRpb25cIiBpbiBhIG1ldGFkYXRhIGJsb2NrLlxuICpcbiAqIEZvciBleGFtcGxlOlxuICpcbiAqIGBgYHRzXG4gKiAkbG9jYWxpemUgYDpjb3JyZWN0fEluZGljYXRlcyB0aGF0IHRoZSB1c2VyIGdvdCB0aGUgYW5zd2VyIGNvcnJlY3Q6IFJpZ2h0IWA7XG4gKiAkbG9jYWxpemUgYDptb3ZlbWVudHxCdXR0b24gbGFiZWwgZm9yIG1vdmluZyB0byB0aGUgcmlnaHQ6IFJpZ2h0IWA7XG4gKiBgYGBcbiAqL1xuZXhwb3J0IGNvbnN0IE1FQU5JTkdfU0VQQVJBVE9SID0gJ3wnO1xuXG4vKipcbiAqIFRoZSBtYXJrZXIgdXNlZCB0byBzZXBhcmF0ZSBhIG1lc3NhZ2UncyBjdXN0b20gXCJpZFwiIGZyb20gaXRzIFwiZGVzY3JpcHRpb25cIiBpbiBhIG1ldGFkYXRhIGJsb2NrLlxuICpcbiAqIEZvciBleGFtcGxlOlxuICpcbiAqIGBgYHRzXG4gKiAkbG9jYWxpemUgYDpBIHdlbGNvbWUgbWVzc2FnZSBvbiB0aGUgaG9tZSBwYWdlQEBteUFwcC1ob21lcGFnZS13ZWxjb21lOiBXZWxjb21lIWA7XG4gKiBgYGBcbiAqL1xuZXhwb3J0IGNvbnN0IElEX1NFUEFSQVRPUiA9ICdAQCc7XG5cbi8qKlxuICogVGhlIG1hcmtlciB1c2VkIHRvIHNlcGFyYXRlIGxlZ2FjeSBtZXNzYWdlIGlkcyBmcm9tIHRoZSByZXN0IG9mIGEgbWV0YWRhdGEgYmxvY2suXG4gKlxuICogRm9yIGV4YW1wbGU6XG4gKlxuICogYGBgdHNcbiAqICRsb2NhbGl6ZSBgOkBAY3VzdG9tLWlk4pCfMmRmNjQ3NjdjZDg5NWE4ZmFiZTNlMThiOTRiNWI2YjZmOWUyZTNmMDogV2VsY29tZSFgO1xuICogYGBgXG4gKlxuICogTm90ZSB0aGF0IHRoaXMgY2hhcmFjdGVyIGlzIHRoZSBcInN5bWJvbCBmb3IgdGhlIHVuaXQgc2VwYXJhdG9yXCIgKOKQnykgbm90IHRoZSBcInVuaXQgc2VwYXJhdG9yXG4gKiBjaGFyYWN0ZXJcIiBpdHNlbGYsIHNpbmNlIHRoYXQgaGFzIG5vIHZpc3VhbCByZXByZXNlbnRhdGlvbi4gU2VlIGh0dHBzOi8vZ3JhcGhlbWljYS5jb20vJUUyJTkwJTlGLlxuICpcbiAqIEhlcmUgaXMgc29tZSBiYWNrZ3JvdW5kIGZvciB0aGUgb3JpZ2luYWwgXCJ1bml0IHNlcGFyYXRvciBjaGFyYWN0ZXJcIjpcbiAqIGh0dHBzOi8vc3RhY2tvdmVyZmxvdy5jb20vcXVlc3Rpb25zLzg2OTUxMTgvd2hhdHMtdGhlLWZpbGUtZ3JvdXAtcmVjb3JkLXVuaXQtc2VwYXJhdG9yLWNvbnRyb2wtY2hhcmFjdGVycy1hbmQtaXRzLXVzYWdlXG4gKi9cbmV4cG9ydCBjb25zdCBMRUdBQ1lfSURfSU5ESUNBVE9SID0gJ1xcdTI0MUYnO1xuIl19
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+19
View File
@@ -0,0 +1,19 @@
/**
* @license Angular v15.0.4
* (c) 2010-2022 Google LLC. https://angular.io/
* License: MIT
*/
import { ɵ_global, ɵ$localize } from '@angular/localize';
export { ɵ$localize as $localize } from '@angular/localize';
/**
* @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
*/
// Attach $localize to the global context, as a side-effect of this module.
ɵ_global.$localize = ɵ$localize;
//# sourceMappingURL=init.mjs.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"init.mjs","sources":["../../../../../../packages/localize/init/index.ts"],"sourcesContent":["/**\n * @license\n * Copyright Google LLC All Rights Reserved.\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://angular.io/license\n */\nimport {ɵ$localize as $localize, ɵ_global as _global, ɵLocalizeFn as LocalizeFn, ɵTranslateFn as TranslateFn} from '@angular/localize';\n\nexport {$localize, LocalizeFn, TranslateFn};\n\n// Attach $localize to the global context, as a side-effect of this module.\n_global.$localize = $localize;\n"],"names":["_global","$localize"],"mappings":";;;;;;;;;AAAA;;;;;;AAMG;AAKH;AACAA,QAAO,CAAC,SAAS,GAAGC,UAAS"}
+640
View File
@@ -0,0 +1,640 @@
/**
* @license Angular v15.0.4
* (c) 2010-2022 Google LLC. https://angular.io/
* License: MIT
*/
import { computeMsgId } from '@angular/compiler';
export { computeMsgId as ɵcomputeMsgId } from '@angular/compiler';
/**
* @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
*/
/**
* The character used to mark the start and end of a "block" in a `$localize` tagged string.
* A block can indicate metadata about the message or specify a name of a placeholder for a
* substitution expressions.
*
* For example:
*
* ```ts
* $localize`Hello, ${title}:title:!`;
* $localize`:meaning|description@@id:source message text`;
* ```
*/
const BLOCK_MARKER$1 = ':';
/**
* The marker used to separate a message's "meaning" from its "description" in a metadata block.
*
* For example:
*
* ```ts
* $localize `:correct|Indicates that the user got the answer correct: Right!`;
* $localize `:movement|Button label for moving to the right: Right!`;
* ```
*/
const MEANING_SEPARATOR = '|';
/**
* The marker used to separate a message's custom "id" from its "description" in a metadata block.
*
* For example:
*
* ```ts
* $localize `:A welcome message on the home page@@myApp-homepage-welcome: Welcome!`;
* ```
*/
const ID_SEPARATOR = '@@';
/**
* The marker used to separate legacy message ids from the rest of a metadata block.
*
* For example:
*
* ```ts
* $localize `:@@custom-id␟2df64767cd895a8fabe3e18b94b5b6b6f9e2e3f0: Welcome!`;
* ```
*
* Note that this character is the "symbol for the unit separator" (␟) not the "unit separator
* character" itself, since that has no visual representation. See https://graphemica.com/%E2%90%9F.
*
* Here is some background for the original "unit separator character":
* https://stackoverflow.com/questions/8695118/whats-the-file-group-record-unit-separator-control-characters-and-its-usage
*/
const LEGACY_ID_INDICATOR = '\u241F';
/**
* @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
*/
/**
* Parse a `$localize` tagged string into a structure that can be used for translation or
* extraction.
*
* See `ParsedMessage` for an example.
*/
function parseMessage(messageParts, expressions, location, messagePartLocations, expressionLocations = []) {
const substitutions = {};
const substitutionLocations = {};
const associatedMessageIds = {};
const metadata = parseMetadata(messageParts[0], messageParts.raw[0]);
const cleanedMessageParts = [metadata.text];
const placeholderNames = [];
let messageString = metadata.text;
for (let i = 1; i < messageParts.length; i++) {
const { messagePart, placeholderName = computePlaceholderName(i), associatedMessageId } = parsePlaceholder(messageParts[i], messageParts.raw[i]);
messageString += `{$${placeholderName}}${messagePart}`;
if (expressions !== undefined) {
substitutions[placeholderName] = expressions[i - 1];
substitutionLocations[placeholderName] = expressionLocations[i - 1];
}
placeholderNames.push(placeholderName);
if (associatedMessageId !== undefined) {
associatedMessageIds[placeholderName] = associatedMessageId;
}
cleanedMessageParts.push(messagePart);
}
const messageId = metadata.customId || computeMsgId(messageString, metadata.meaning || '');
const legacyIds = metadata.legacyIds ? metadata.legacyIds.filter(id => id !== messageId) : [];
return {
id: messageId,
legacyIds,
substitutions,
substitutionLocations,
text: messageString,
customId: metadata.customId,
meaning: metadata.meaning || '',
description: metadata.description || '',
messageParts: cleanedMessageParts,
messagePartLocations,
placeholderNames,
associatedMessageIds,
location,
};
}
/**
* Parse the given message part (`cooked` + `raw`) to extract the message metadata from the text.
*
* If the message part has a metadata block this function will extract the `meaning`,
* `description`, `customId` and `legacyId` (if provided) from the block. These metadata properties
* are serialized in the string delimited by `|`, `@@` and `␟` respectively.
*
* (Note that `␟` is the `LEGACY_ID_INDICATOR` - see `constants.ts`.)
*
* For example:
*
* ```ts
* `:meaning|description@@custom-id:`
* `:meaning|@@custom-id:`
* `:meaning|description:`
* `:description@@custom-id:`
* `:meaning|:`
* `:description:`
* `:@@custom-id:`
* `:meaning|description@@custom-id␟legacy-id-1␟legacy-id-2:`
* ```
*
* @param cooked The cooked version of the message part to parse.
* @param raw The raw version of the message part to parse.
* @returns A object containing any metadata that was parsed from the message part.
*/
function parseMetadata(cooked, raw) {
const { text: messageString, block } = splitBlock(cooked, raw);
if (block === undefined) {
return { text: messageString };
}
else {
const [meaningDescAndId, ...legacyIds] = block.split(LEGACY_ID_INDICATOR);
const [meaningAndDesc, customId] = meaningDescAndId.split(ID_SEPARATOR, 2);
let [meaning, description] = meaningAndDesc.split(MEANING_SEPARATOR, 2);
if (description === undefined) {
description = meaning;
meaning = undefined;
}
if (description === '') {
description = undefined;
}
return { text: messageString, meaning, description, customId, legacyIds };
}
}
/**
* Parse the given message part (`cooked` + `raw`) to extract any placeholder metadata from the
* text.
*
* If the message part has a metadata block this function will extract the `placeholderName` and
* `associatedMessageId` (if provided) from the block.
*
* These metadata properties are serialized in the string delimited by `@@`.
*
* For example:
*
* ```ts
* `:placeholder-name@@associated-id:`
* ```
*
* @param cooked The cooked version of the message part to parse.
* @param raw The raw version of the message part to parse.
* @returns A object containing the metadata (`placeholderName` and `associatedMessageId`) of the
* preceding placeholder, along with the static text that follows.
*/
function parsePlaceholder(cooked, raw) {
const { text: messagePart, block } = splitBlock(cooked, raw);
if (block === undefined) {
return { messagePart };
}
else {
const [placeholderName, associatedMessageId] = block.split(ID_SEPARATOR);
return { messagePart, placeholderName, associatedMessageId };
}
}
/**
* Split a message part (`cooked` + `raw`) into an optional delimited "block" off the front and the
* rest of the text of the message part.
*
* Blocks appear at the start of message parts. They are delimited by a colon `:` character at the
* start and end of the block.
*
* If the block is in the first message part then it will be metadata about the whole message:
* meaning, description, id. Otherwise it will be metadata about the immediately preceding
* substitution: placeholder name.
*
* Since blocks are optional, it is possible that the content of a message block actually starts
* with a block marker. In this case the marker must be escaped `\:`.
*
* @param cooked The cooked version of the message part to parse.
* @param raw The raw version of the message part to parse.
* @returns An object containing the `text` of the message part and the text of the `block`, if it
* exists.
* @throws an error if the `block` is unterminated
*/
function splitBlock(cooked, raw) {
if (raw.charAt(0) !== BLOCK_MARKER$1) {
return { text: cooked };
}
else {
const endOfBlock = findEndOfBlock(cooked, raw);
return {
block: cooked.substring(1, endOfBlock),
text: cooked.substring(endOfBlock + 1),
};
}
}
function computePlaceholderName(index) {
return index === 1 ? 'PH' : `PH_${index - 1}`;
}
/**
* Find the end of a "marked block" indicated by the first non-escaped colon.
*
* @param cooked The cooked string (where escaped chars have been processed)
* @param raw The raw string (where escape sequences are still in place)
*
* @returns the index of the end of block marker
* @throws an error if the block is unterminated
*/
function findEndOfBlock(cooked, raw) {
for (let cookedIndex = 1, rawIndex = 1; cookedIndex < cooked.length; cookedIndex++, rawIndex++) {
if (raw[rawIndex] === '\\') {
rawIndex++;
}
else if (cooked[cookedIndex] === BLOCK_MARKER$1) {
return cookedIndex;
}
}
throw new Error(`Unterminated $localize metadata block in "${raw}".`);
}
/**
* @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
*/
class MissingTranslationError extends Error {
constructor(parsedMessage) {
super(`No translation found for ${describeMessage(parsedMessage)}.`);
this.parsedMessage = parsedMessage;
this.type = 'MissingTranslationError';
}
}
function isMissingTranslationError(e) {
return e.type === 'MissingTranslationError';
}
/**
* Translate the text of the `$localize` tagged-string (i.e. `messageParts` and
* `substitutions`) using the given `translations`.
*
* The tagged-string is parsed to extract its `messageId` which is used to find an appropriate
* `ParsedTranslation`. If this doesn't match and there are legacy ids then try matching a
* translation using those.
*
* If one is found then it is used to translate the message into a new set of `messageParts` and
* `substitutions`.
* The translation may reorder (or remove) substitutions as appropriate.
*
* If there is no translation with a matching message id then an error is thrown.
* If a translation contains a placeholder that is not found in the message being translated then an
* error is thrown.
*/
function translate$1(translations, messageParts, substitutions) {
const message = parseMessage(messageParts, substitutions);
// Look up the translation using the messageId, and then the legacyId if available.
let translation = translations[message.id];
// If the messageId did not match a translation, try matching the legacy ids instead
if (message.legacyIds !== undefined) {
for (let i = 0; i < message.legacyIds.length && translation === undefined; i++) {
translation = translations[message.legacyIds[i]];
}
}
if (translation === undefined) {
throw new MissingTranslationError(message);
}
return [
translation.messageParts, translation.placeholderNames.map(placeholder => {
if (message.substitutions.hasOwnProperty(placeholder)) {
return message.substitutions[placeholder];
}
else {
throw new Error(`There is a placeholder name mismatch with the translation provided for the message ${describeMessage(message)}.\n` +
`The translation contains a placeholder with name ${placeholder}, which does not exist in the message.`);
}
})
];
}
/**
* Parse the `messageParts` and `placeholderNames` out of a target `message`.
*
* Used by `loadTranslations()` to convert target message strings into a structure that is more
* appropriate for doing translation.
*
* @param message the message to be parsed.
*/
function parseTranslation(messageString) {
const parts = messageString.split(/{\$([^}]*)}/);
const messageParts = [parts[0]];
const placeholderNames = [];
for (let i = 1; i < parts.length - 1; i += 2) {
placeholderNames.push(parts[i]);
messageParts.push(`${parts[i + 1]}`);
}
const rawMessageParts = messageParts.map(part => part.charAt(0) === BLOCK_MARKER$1 ? '\\' + part : part);
return {
text: messageString,
messageParts: makeTemplateObject(messageParts, rawMessageParts),
placeholderNames,
};
}
/**
* Create a `ParsedTranslation` from a set of `messageParts` and `placeholderNames`.
*
* @param messageParts The message parts to appear in the ParsedTranslation.
* @param placeholderNames The names of the placeholders to intersperse between the `messageParts`.
*/
function makeParsedTranslation(messageParts, placeholderNames = []) {
let messageString = messageParts[0];
for (let i = 0; i < placeholderNames.length; i++) {
messageString += `{$${placeholderNames[i]}}${messageParts[i + 1]}`;
}
return {
text: messageString,
messageParts: makeTemplateObject(messageParts, messageParts),
placeholderNames
};
}
/**
* Create the specialized array that is passed to tagged-string tag functions.
*
* @param cooked The message parts with their escape codes processed.
* @param raw The message parts with their escaped codes as-is.
*/
function makeTemplateObject(cooked, raw) {
Object.defineProperty(cooked, 'raw', { value: raw });
return cooked;
}
function describeMessage(message) {
const meaningString = message.meaning && ` - "${message.meaning}"`;
const legacy = message.legacyIds && message.legacyIds.length > 0 ?
` [${message.legacyIds.map(l => `"${l}"`).join(', ')}]` :
'';
return `"${message.id}"${legacy} ("${message.text}"${meaningString})`;
}
/**
* @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
*/
/**
* Load translations for use by `$localize`, if doing runtime translation.
*
* If the `$localize` tagged strings are not going to be replaced at compiled time, it is possible
* to load a set of translations that will be applied to the `$localize` tagged strings at runtime,
* in the browser.
*
* Loading a new translation will overwrite a previous translation if it has the same `MessageId`.
*
* Note that `$localize` messages are only processed once, when the tagged string is first
* encountered, and does not provide dynamic language changing without refreshing the browser.
* Loading new translations later in the application life-cycle will not change the translated text
* of messages that have already been translated.
*
* The message IDs and translations are in the same format as that rendered to "simple JSON"
* translation files when extracting messages. In particular, placeholders in messages are rendered
* using the `{$PLACEHOLDER_NAME}` syntax. For example the message from the following template:
*
* ```html
* <div i18n>pre<span>inner-pre<b>bold</b>inner-post</span>post</div>
* ```
*
* would have the following form in the `translations` map:
*
* ```ts
* {
* "2932901491976224757":
* "pre{$START_TAG_SPAN}inner-pre{$START_BOLD_TEXT}bold{$CLOSE_BOLD_TEXT}inner-post{$CLOSE_TAG_SPAN}post"
* }
* ```
*
* @param translations A map from message ID to translated message.
*
* These messages are processed and added to a lookup based on their `MessageId`.
*
* @see `clearTranslations()` for removing translations loaded using this function.
* @see `$localize` for tagging messages as needing to be translated.
* @publicApi
*/
function loadTranslations(translations) {
// Ensure the translate function exists
if (!$localize.translate) {
$localize.translate = translate;
}
if (!$localize.TRANSLATIONS) {
$localize.TRANSLATIONS = {};
}
Object.keys(translations).forEach(key => {
$localize.TRANSLATIONS[key] = parseTranslation(translations[key]);
});
}
/**
* Remove all translations for `$localize`, if doing runtime translation.
*
* All translations that had been loading into memory using `loadTranslations()` will be removed.
*
* @see `loadTranslations()` for loading translations at runtime.
* @see `$localize` for tagging messages as needing to be translated.
*
* @publicApi
*/
function clearTranslations() {
$localize.translate = undefined;
$localize.TRANSLATIONS = {};
}
/**
* Translate the text of the given message, using the loaded translations.
*
* This function may reorder (or remove) substitutions as indicated in the matching translation.
*/
function translate(messageParts, substitutions) {
try {
return translate$1($localize.TRANSLATIONS, messageParts, substitutions);
}
catch (e) {
console.warn(e.message);
return [messageParts, substitutions];
}
}
/**
* @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
*/
// Always use __globalThis if available, which is the spec-defined global variable across all
// environments, then fallback to __global first, because in Node tests both __global and
// __window may be defined and _global should be __global in that case. Note: Typeof/Instanceof
// checks are considered side-effects in Terser. We explicitly mark this as side-effect free:
// https://github.com/terser/terser/issues/250.
const _global = ( /* @__PURE__ */(() => (typeof globalThis !== 'undefined' && globalThis) ||
(typeof global !== 'undefined' && global) || (typeof window !== 'undefined' && window) ||
(typeof self !== 'undefined' && typeof WorkerGlobalScope !== 'undefined' &&
self instanceof WorkerGlobalScope && self))());
/**
* @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
*/
/**
* Tag a template literal string for localization.
*
* For example:
*
* ```ts
* $localize `some string to localize`
* ```
*
* **Providing meaning, description and id**
*
* You can optionally specify one or more of `meaning`, `description` and `id` for a localized
* string by pre-pending it with a colon delimited block of the form:
*
* ```ts
* $localize`:meaning|description@@id:source message text`;
*
* $localize`:meaning|:source message text`;
* $localize`:description:source message text`;
* $localize`:@@id:source message text`;
* ```
*
* This format is the same as that used for `i18n` markers in Angular templates. See the
* [Angular i18n guide](guide/i18n-common-prepare#mark-text-in-component-template).
*
* **Naming placeholders**
*
* If the template literal string contains expressions, then the expressions will be automatically
* associated with placeholder names for you.
*
* For example:
*
* ```ts
* $localize `Hi ${name}! There are ${items.length} items.`;
* ```
*
* will generate a message-source of `Hi {$PH}! There are {$PH_1} items`.
*
* The recommended practice is to name the placeholder associated with each expression though.
*
* Do this by providing the placeholder name wrapped in `:` characters directly after the
* expression. These placeholder names are stripped out of the rendered localized string.
*
* For example, to name the `items.length` expression placeholder `itemCount` you write:
*
* ```ts
* $localize `There are ${items.length}:itemCount: items`;
* ```
*
* **Escaping colon markers**
*
* If you need to use a `:` character directly at the start of a tagged string that has no
* metadata block, or directly after a substitution expression that has no name you must escape
* the `:` by preceding it with a backslash:
*
* For example:
*
* ```ts
* // message has a metadata block so no need to escape colon
* $localize `:some description::this message starts with a colon (:)`;
* // no metadata block so the colon must be escaped
* $localize `\:this message starts with a colon (:)`;
* ```
*
* ```ts
* // named substitution so no need to escape colon
* $localize `${label}:label:: ${}`
* // anonymous substitution so colon must be escaped
* $localize `${label}\: ${}`
* ```
*
* **Processing localized strings:**
*
* There are three scenarios:
*
* * **compile-time inlining**: the `$localize` tag is transformed at compile time by a
* transpiler, removing the tag and replacing the template literal string with a translated
* literal string from a collection of translations provided to the transpilation tool.
*
* * **run-time evaluation**: the `$localize` tag is a run-time function that replaces and
* reorders the parts (static strings and expressions) of the template literal string with strings
* from a collection of translations loaded at run-time.
*
* * **pass-through evaluation**: the `$localize` tag is a run-time function that simply evaluates
* the original template literal string without applying any translations to the parts. This
* version is used during development or where there is no need to translate the localized
* template literals.
*
* @param messageParts a collection of the static parts of the template string.
* @param expressions a collection of the values of each placeholder in the template string.
* @returns the translated string, with the `messageParts` and `expressions` interleaved together.
*
* @globalApi
* @publicApi
*/
const $localize$1 = function (messageParts, ...expressions) {
if ($localize$1.translate) {
// Don't use array expansion here to avoid the compiler adding `__read()` helper unnecessarily.
const translation = $localize$1.translate(messageParts, expressions);
messageParts = translation[0];
expressions = translation[1];
}
let message = stripBlock(messageParts[0], messageParts.raw[0]);
for (let i = 1; i < messageParts.length; i++) {
message += expressions[i - 1] + stripBlock(messageParts[i], messageParts.raw[i]);
}
return message;
};
const BLOCK_MARKER = ':';
/**
* Strip a delimited "block" from the start of the `messagePart`, if it is found.
*
* If a marker character (:) actually appears in the content at the start of a tagged string or
* after a substitution expression, where a block has not been provided the character must be
* escaped with a backslash, `\:`. This function checks for this by looking at the `raw`
* messagePart, which should still contain the backslash.
*
* @param messagePart The cooked message part to process.
* @param rawMessagePart The raw message part to check.
* @returns the message part with the placeholder name stripped, if found.
* @throws an error if the block is unterminated
*/
function stripBlock(messagePart, rawMessagePart) {
return rawMessagePart.charAt(0) === BLOCK_MARKER ?
messagePart.substring(findEndOfBlock(messagePart, rawMessagePart) + 1) :
messagePart;
}
/**
* @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
*/
/**
* @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
*/
/**
* @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
*/
/**
* @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
*/
export { clearTranslations, loadTranslations, $localize$1 as ɵ$localize, MissingTranslationError as ɵMissingTranslationError, _global as ɵ_global, findEndOfBlock as ɵfindEndOfBlock, isMissingTranslationError as ɵisMissingTranslationError, makeParsedTranslation as ɵmakeParsedTranslation, makeTemplateObject as ɵmakeTemplateObject, parseMessage as ɵparseMessage, parseMetadata as ɵparseMetadata, parseTranslation as ɵparseTranslation, splitBlock as ɵsplitBlock, translate$1 as ɵtranslate };
//# sourceMappingURL=localize.mjs.map
File diff suppressed because one or more lines are too long
+19
View File
@@ -0,0 +1,19 @@
/**
* @license Angular v15.0.4
* (c) 2010-2022 Google LLC. https://angular.io/
* License: MIT
*/
import { ɵ_global, ɵ$localize } from '@angular/localize';
export { ɵ$localize as $localize } from '@angular/localize';
/**
* @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
*/
// Attach $localize to the global context, as a side-effect of this module.
ɵ_global.$localize = ɵ$localize;
//# sourceMappingURL=init.mjs.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"init.mjs","sources":["../../../../../../packages/localize/init/index.ts"],"sourcesContent":["/**\n * @license\n * Copyright Google LLC All Rights Reserved.\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://angular.io/license\n */\nimport {ɵ$localize as $localize, ɵ_global as _global, ɵLocalizeFn as LocalizeFn, ɵTranslateFn as TranslateFn} from '@angular/localize';\n\nexport {$localize, LocalizeFn, TranslateFn};\n\n// Attach $localize to the global context, as a side-effect of this module.\n_global.$localize = $localize;\n"],"names":["_global","$localize"],"mappings":";;;;;;;;;AAAA;;;;;;AAMG;AAKH;AACAA,QAAO,CAAC,SAAS,GAAGC,UAAS"}
+640
View File
@@ -0,0 +1,640 @@
/**
* @license Angular v15.0.4
* (c) 2010-2022 Google LLC. https://angular.io/
* License: MIT
*/
import { computeMsgId } from '@angular/compiler';
export { computeMsgId as ɵcomputeMsgId } from '@angular/compiler';
/**
* @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
*/
/**
* The character used to mark the start and end of a "block" in a `$localize` tagged string.
* A block can indicate metadata about the message or specify a name of a placeholder for a
* substitution expressions.
*
* For example:
*
* ```ts
* $localize`Hello, ${title}:title:!`;
* $localize`:meaning|description@@id:source message text`;
* ```
*/
const BLOCK_MARKER$1 = ':';
/**
* The marker used to separate a message's "meaning" from its "description" in a metadata block.
*
* For example:
*
* ```ts
* $localize `:correct|Indicates that the user got the answer correct: Right!`;
* $localize `:movement|Button label for moving to the right: Right!`;
* ```
*/
const MEANING_SEPARATOR = '|';
/**
* The marker used to separate a message's custom "id" from its "description" in a metadata block.
*
* For example:
*
* ```ts
* $localize `:A welcome message on the home page@@myApp-homepage-welcome: Welcome!`;
* ```
*/
const ID_SEPARATOR = '@@';
/**
* The marker used to separate legacy message ids from the rest of a metadata block.
*
* For example:
*
* ```ts
* $localize `:@@custom-id␟2df64767cd895a8fabe3e18b94b5b6b6f9e2e3f0: Welcome!`;
* ```
*
* Note that this character is the "symbol for the unit separator" (␟) not the "unit separator
* character" itself, since that has no visual representation. See https://graphemica.com/%E2%90%9F.
*
* Here is some background for the original "unit separator character":
* https://stackoverflow.com/questions/8695118/whats-the-file-group-record-unit-separator-control-characters-and-its-usage
*/
const LEGACY_ID_INDICATOR = '\u241F';
/**
* @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
*/
/**
* Parse a `$localize` tagged string into a structure that can be used for translation or
* extraction.
*
* See `ParsedMessage` for an example.
*/
function parseMessage(messageParts, expressions, location, messagePartLocations, expressionLocations = []) {
const substitutions = {};
const substitutionLocations = {};
const associatedMessageIds = {};
const metadata = parseMetadata(messageParts[0], messageParts.raw[0]);
const cleanedMessageParts = [metadata.text];
const placeholderNames = [];
let messageString = metadata.text;
for (let i = 1; i < messageParts.length; i++) {
const { messagePart, placeholderName = computePlaceholderName(i), associatedMessageId } = parsePlaceholder(messageParts[i], messageParts.raw[i]);
messageString += `{$${placeholderName}}${messagePart}`;
if (expressions !== undefined) {
substitutions[placeholderName] = expressions[i - 1];
substitutionLocations[placeholderName] = expressionLocations[i - 1];
}
placeholderNames.push(placeholderName);
if (associatedMessageId !== undefined) {
associatedMessageIds[placeholderName] = associatedMessageId;
}
cleanedMessageParts.push(messagePart);
}
const messageId = metadata.customId || computeMsgId(messageString, metadata.meaning || '');
const legacyIds = metadata.legacyIds ? metadata.legacyIds.filter(id => id !== messageId) : [];
return {
id: messageId,
legacyIds,
substitutions,
substitutionLocations,
text: messageString,
customId: metadata.customId,
meaning: metadata.meaning || '',
description: metadata.description || '',
messageParts: cleanedMessageParts,
messagePartLocations,
placeholderNames,
associatedMessageIds,
location,
};
}
/**
* Parse the given message part (`cooked` + `raw`) to extract the message metadata from the text.
*
* If the message part has a metadata block this function will extract the `meaning`,
* `description`, `customId` and `legacyId` (if provided) from the block. These metadata properties
* are serialized in the string delimited by `|`, `@@` and `␟` respectively.
*
* (Note that `␟` is the `LEGACY_ID_INDICATOR` - see `constants.ts`.)
*
* For example:
*
* ```ts
* `:meaning|description@@custom-id:`
* `:meaning|@@custom-id:`
* `:meaning|description:`
* `:description@@custom-id:`
* `:meaning|:`
* `:description:`
* `:@@custom-id:`
* `:meaning|description@@custom-id␟legacy-id-1␟legacy-id-2:`
* ```
*
* @param cooked The cooked version of the message part to parse.
* @param raw The raw version of the message part to parse.
* @returns A object containing any metadata that was parsed from the message part.
*/
function parseMetadata(cooked, raw) {
const { text: messageString, block } = splitBlock(cooked, raw);
if (block === undefined) {
return { text: messageString };
}
else {
const [meaningDescAndId, ...legacyIds] = block.split(LEGACY_ID_INDICATOR);
const [meaningAndDesc, customId] = meaningDescAndId.split(ID_SEPARATOR, 2);
let [meaning, description] = meaningAndDesc.split(MEANING_SEPARATOR, 2);
if (description === undefined) {
description = meaning;
meaning = undefined;
}
if (description === '') {
description = undefined;
}
return { text: messageString, meaning, description, customId, legacyIds };
}
}
/**
* Parse the given message part (`cooked` + `raw`) to extract any placeholder metadata from the
* text.
*
* If the message part has a metadata block this function will extract the `placeholderName` and
* `associatedMessageId` (if provided) from the block.
*
* These metadata properties are serialized in the string delimited by `@@`.
*
* For example:
*
* ```ts
* `:placeholder-name@@associated-id:`
* ```
*
* @param cooked The cooked version of the message part to parse.
* @param raw The raw version of the message part to parse.
* @returns A object containing the metadata (`placeholderName` and `associatedMessageId`) of the
* preceding placeholder, along with the static text that follows.
*/
function parsePlaceholder(cooked, raw) {
const { text: messagePart, block } = splitBlock(cooked, raw);
if (block === undefined) {
return { messagePart };
}
else {
const [placeholderName, associatedMessageId] = block.split(ID_SEPARATOR);
return { messagePart, placeholderName, associatedMessageId };
}
}
/**
* Split a message part (`cooked` + `raw`) into an optional delimited "block" off the front and the
* rest of the text of the message part.
*
* Blocks appear at the start of message parts. They are delimited by a colon `:` character at the
* start and end of the block.
*
* If the block is in the first message part then it will be metadata about the whole message:
* meaning, description, id. Otherwise it will be metadata about the immediately preceding
* substitution: placeholder name.
*
* Since blocks are optional, it is possible that the content of a message block actually starts
* with a block marker. In this case the marker must be escaped `\:`.
*
* @param cooked The cooked version of the message part to parse.
* @param raw The raw version of the message part to parse.
* @returns An object containing the `text` of the message part and the text of the `block`, if it
* exists.
* @throws an error if the `block` is unterminated
*/
function splitBlock(cooked, raw) {
if (raw.charAt(0) !== BLOCK_MARKER$1) {
return { text: cooked };
}
else {
const endOfBlock = findEndOfBlock(cooked, raw);
return {
block: cooked.substring(1, endOfBlock),
text: cooked.substring(endOfBlock + 1),
};
}
}
function computePlaceholderName(index) {
return index === 1 ? 'PH' : `PH_${index - 1}`;
}
/**
* Find the end of a "marked block" indicated by the first non-escaped colon.
*
* @param cooked The cooked string (where escaped chars have been processed)
* @param raw The raw string (where escape sequences are still in place)
*
* @returns the index of the end of block marker
* @throws an error if the block is unterminated
*/
function findEndOfBlock(cooked, raw) {
for (let cookedIndex = 1, rawIndex = 1; cookedIndex < cooked.length; cookedIndex++, rawIndex++) {
if (raw[rawIndex] === '\\') {
rawIndex++;
}
else if (cooked[cookedIndex] === BLOCK_MARKER$1) {
return cookedIndex;
}
}
throw new Error(`Unterminated $localize metadata block in "${raw}".`);
}
/**
* @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
*/
class MissingTranslationError extends Error {
constructor(parsedMessage) {
super(`No translation found for ${describeMessage(parsedMessage)}.`);
this.parsedMessage = parsedMessage;
this.type = 'MissingTranslationError';
}
}
function isMissingTranslationError(e) {
return e.type === 'MissingTranslationError';
}
/**
* Translate the text of the `$localize` tagged-string (i.e. `messageParts` and
* `substitutions`) using the given `translations`.
*
* The tagged-string is parsed to extract its `messageId` which is used to find an appropriate
* `ParsedTranslation`. If this doesn't match and there are legacy ids then try matching a
* translation using those.
*
* If one is found then it is used to translate the message into a new set of `messageParts` and
* `substitutions`.
* The translation may reorder (or remove) substitutions as appropriate.
*
* If there is no translation with a matching message id then an error is thrown.
* If a translation contains a placeholder that is not found in the message being translated then an
* error is thrown.
*/
function translate$1(translations, messageParts, substitutions) {
const message = parseMessage(messageParts, substitutions);
// Look up the translation using the messageId, and then the legacyId if available.
let translation = translations[message.id];
// If the messageId did not match a translation, try matching the legacy ids instead
if (message.legacyIds !== undefined) {
for (let i = 0; i < message.legacyIds.length && translation === undefined; i++) {
translation = translations[message.legacyIds[i]];
}
}
if (translation === undefined) {
throw new MissingTranslationError(message);
}
return [
translation.messageParts, translation.placeholderNames.map(placeholder => {
if (message.substitutions.hasOwnProperty(placeholder)) {
return message.substitutions[placeholder];
}
else {
throw new Error(`There is a placeholder name mismatch with the translation provided for the message ${describeMessage(message)}.\n` +
`The translation contains a placeholder with name ${placeholder}, which does not exist in the message.`);
}
})
];
}
/**
* Parse the `messageParts` and `placeholderNames` out of a target `message`.
*
* Used by `loadTranslations()` to convert target message strings into a structure that is more
* appropriate for doing translation.
*
* @param message the message to be parsed.
*/
function parseTranslation(messageString) {
const parts = messageString.split(/{\$([^}]*)}/);
const messageParts = [parts[0]];
const placeholderNames = [];
for (let i = 1; i < parts.length - 1; i += 2) {
placeholderNames.push(parts[i]);
messageParts.push(`${parts[i + 1]}`);
}
const rawMessageParts = messageParts.map(part => part.charAt(0) === BLOCK_MARKER$1 ? '\\' + part : part);
return {
text: messageString,
messageParts: makeTemplateObject(messageParts, rawMessageParts),
placeholderNames,
};
}
/**
* Create a `ParsedTranslation` from a set of `messageParts` and `placeholderNames`.
*
* @param messageParts The message parts to appear in the ParsedTranslation.
* @param placeholderNames The names of the placeholders to intersperse between the `messageParts`.
*/
function makeParsedTranslation(messageParts, placeholderNames = []) {
let messageString = messageParts[0];
for (let i = 0; i < placeholderNames.length; i++) {
messageString += `{$${placeholderNames[i]}}${messageParts[i + 1]}`;
}
return {
text: messageString,
messageParts: makeTemplateObject(messageParts, messageParts),
placeholderNames
};
}
/**
* Create the specialized array that is passed to tagged-string tag functions.
*
* @param cooked The message parts with their escape codes processed.
* @param raw The message parts with their escaped codes as-is.
*/
function makeTemplateObject(cooked, raw) {
Object.defineProperty(cooked, 'raw', { value: raw });
return cooked;
}
function describeMessage(message) {
const meaningString = message.meaning && ` - "${message.meaning}"`;
const legacy = message.legacyIds && message.legacyIds.length > 0 ?
` [${message.legacyIds.map(l => `"${l}"`).join(', ')}]` :
'';
return `"${message.id}"${legacy} ("${message.text}"${meaningString})`;
}
/**
* @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
*/
/**
* Load translations for use by `$localize`, if doing runtime translation.
*
* If the `$localize` tagged strings are not going to be replaced at compiled time, it is possible
* to load a set of translations that will be applied to the `$localize` tagged strings at runtime,
* in the browser.
*
* Loading a new translation will overwrite a previous translation if it has the same `MessageId`.
*
* Note that `$localize` messages are only processed once, when the tagged string is first
* encountered, and does not provide dynamic language changing without refreshing the browser.
* Loading new translations later in the application life-cycle will not change the translated text
* of messages that have already been translated.
*
* The message IDs and translations are in the same format as that rendered to "simple JSON"
* translation files when extracting messages. In particular, placeholders in messages are rendered
* using the `{$PLACEHOLDER_NAME}` syntax. For example the message from the following template:
*
* ```html
* <div i18n>pre<span>inner-pre<b>bold</b>inner-post</span>post</div>
* ```
*
* would have the following form in the `translations` map:
*
* ```ts
* {
* "2932901491976224757":
* "pre{$START_TAG_SPAN}inner-pre{$START_BOLD_TEXT}bold{$CLOSE_BOLD_TEXT}inner-post{$CLOSE_TAG_SPAN}post"
* }
* ```
*
* @param translations A map from message ID to translated message.
*
* These messages are processed and added to a lookup based on their `MessageId`.
*
* @see `clearTranslations()` for removing translations loaded using this function.
* @see `$localize` for tagging messages as needing to be translated.
* @publicApi
*/
function loadTranslations(translations) {
// Ensure the translate function exists
if (!$localize.translate) {
$localize.translate = translate;
}
if (!$localize.TRANSLATIONS) {
$localize.TRANSLATIONS = {};
}
Object.keys(translations).forEach(key => {
$localize.TRANSLATIONS[key] = parseTranslation(translations[key]);
});
}
/**
* Remove all translations for `$localize`, if doing runtime translation.
*
* All translations that had been loading into memory using `loadTranslations()` will be removed.
*
* @see `loadTranslations()` for loading translations at runtime.
* @see `$localize` for tagging messages as needing to be translated.
*
* @publicApi
*/
function clearTranslations() {
$localize.translate = undefined;
$localize.TRANSLATIONS = {};
}
/**
* Translate the text of the given message, using the loaded translations.
*
* This function may reorder (or remove) substitutions as indicated in the matching translation.
*/
function translate(messageParts, substitutions) {
try {
return translate$1($localize.TRANSLATIONS, messageParts, substitutions);
}
catch (e) {
console.warn(e.message);
return [messageParts, substitutions];
}
}
/**
* @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
*/
// Always use __globalThis if available, which is the spec-defined global variable across all
// environments, then fallback to __global first, because in Node tests both __global and
// __window may be defined and _global should be __global in that case. Note: Typeof/Instanceof
// checks are considered side-effects in Terser. We explicitly mark this as side-effect free:
// https://github.com/terser/terser/issues/250.
const _global = ( /* @__PURE__ */(() => (typeof globalThis !== 'undefined' && globalThis) ||
(typeof global !== 'undefined' && global) || (typeof window !== 'undefined' && window) ||
(typeof self !== 'undefined' && typeof WorkerGlobalScope !== 'undefined' &&
self instanceof WorkerGlobalScope && self))());
/**
* @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
*/
/**
* Tag a template literal string for localization.
*
* For example:
*
* ```ts
* $localize `some string to localize`
* ```
*
* **Providing meaning, description and id**
*
* You can optionally specify one or more of `meaning`, `description` and `id` for a localized
* string by pre-pending it with a colon delimited block of the form:
*
* ```ts
* $localize`:meaning|description@@id:source message text`;
*
* $localize`:meaning|:source message text`;
* $localize`:description:source message text`;
* $localize`:@@id:source message text`;
* ```
*
* This format is the same as that used for `i18n` markers in Angular templates. See the
* [Angular i18n guide](guide/i18n-common-prepare#mark-text-in-component-template).
*
* **Naming placeholders**
*
* If the template literal string contains expressions, then the expressions will be automatically
* associated with placeholder names for you.
*
* For example:
*
* ```ts
* $localize `Hi ${name}! There are ${items.length} items.`;
* ```
*
* will generate a message-source of `Hi {$PH}! There are {$PH_1} items`.
*
* The recommended practice is to name the placeholder associated with each expression though.
*
* Do this by providing the placeholder name wrapped in `:` characters directly after the
* expression. These placeholder names are stripped out of the rendered localized string.
*
* For example, to name the `items.length` expression placeholder `itemCount` you write:
*
* ```ts
* $localize `There are ${items.length}:itemCount: items`;
* ```
*
* **Escaping colon markers**
*
* If you need to use a `:` character directly at the start of a tagged string that has no
* metadata block, or directly after a substitution expression that has no name you must escape
* the `:` by preceding it with a backslash:
*
* For example:
*
* ```ts
* // message has a metadata block so no need to escape colon
* $localize `:some description::this message starts with a colon (:)`;
* // no metadata block so the colon must be escaped
* $localize `\:this message starts with a colon (:)`;
* ```
*
* ```ts
* // named substitution so no need to escape colon
* $localize `${label}:label:: ${}`
* // anonymous substitution so colon must be escaped
* $localize `${label}\: ${}`
* ```
*
* **Processing localized strings:**
*
* There are three scenarios:
*
* * **compile-time inlining**: the `$localize` tag is transformed at compile time by a
* transpiler, removing the tag and replacing the template literal string with a translated
* literal string from a collection of translations provided to the transpilation tool.
*
* * **run-time evaluation**: the `$localize` tag is a run-time function that replaces and
* reorders the parts (static strings and expressions) of the template literal string with strings
* from a collection of translations loaded at run-time.
*
* * **pass-through evaluation**: the `$localize` tag is a run-time function that simply evaluates
* the original template literal string without applying any translations to the parts. This
* version is used during development or where there is no need to translate the localized
* template literals.
*
* @param messageParts a collection of the static parts of the template string.
* @param expressions a collection of the values of each placeholder in the template string.
* @returns the translated string, with the `messageParts` and `expressions` interleaved together.
*
* @globalApi
* @publicApi
*/
const $localize$1 = function (messageParts, ...expressions) {
if ($localize$1.translate) {
// Don't use array expansion here to avoid the compiler adding `__read()` helper unnecessarily.
const translation = $localize$1.translate(messageParts, expressions);
messageParts = translation[0];
expressions = translation[1];
}
let message = stripBlock(messageParts[0], messageParts.raw[0]);
for (let i = 1; i < messageParts.length; i++) {
message += expressions[i - 1] + stripBlock(messageParts[i], messageParts.raw[i]);
}
return message;
};
const BLOCK_MARKER = ':';
/**
* Strip a delimited "block" from the start of the `messagePart`, if it is found.
*
* If a marker character (:) actually appears in the content at the start of a tagged string or
* after a substitution expression, where a block has not been provided the character must be
* escaped with a backslash, `\:`. This function checks for this by looking at the `raw`
* messagePart, which should still contain the backslash.
*
* @param messagePart The cooked message part to process.
* @param rawMessagePart The raw message part to check.
* @returns the message part with the placeholder name stripped, if found.
* @throws an error if the block is unterminated
*/
function stripBlock(messagePart, rawMessagePart) {
return rawMessagePart.charAt(0) === BLOCK_MARKER ?
messagePart.substring(findEndOfBlock(messagePart, rawMessagePart) + 1) :
messagePart;
}
/**
* @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
*/
/**
* @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
*/
/**
* @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
*/
/**
* @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
*/
export { clearTranslations, loadTranslations, $localize$1 as ɵ$localize, MissingTranslationError as ɵMissingTranslationError, _global as ɵ_global, findEndOfBlock as ɵfindEndOfBlock, isMissingTranslationError as ɵisMissingTranslationError, makeParsedTranslation as ɵmakeParsedTranslation, makeTemplateObject as ɵmakeTemplateObject, parseMessage as ɵparseMessage, parseMetadata as ɵparseMetadata, parseTranslation as ɵparseTranslation, splitBlock as ɵsplitBlock, translate$1 as ɵtranslate };
//# sourceMappingURL=localize.mjs.map
File diff suppressed because one or more lines are too long
+9
View File
@@ -0,0 +1,9 @@
/**
* @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
*/
/// <amd-module name="@angular/localize" />
export * from './localize';
+18
View File
@@ -0,0 +1,18 @@
/**
* @license Angular v15.0.4
* (c) 2010-2022 Google LLC. https://angular.io/
* License: MIT
*/
import { ɵ$localize as $localize } from '@angular/localize';
import { ɵLocalizeFn as LocalizeFn } from '@angular/localize';
import { ɵTranslateFn as TranslateFn } from '@angular/localize';
export { $localize }
export { LocalizeFn }
export { TranslateFn }
export { }
+107
View File
@@ -0,0 +1,107 @@
/**
* @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
*/
/// <amd-module name="@angular/localize/localize" />
import { LocalizeFn } from './src/localize';
export { clearTranslations, loadTranslations } from './src/translate';
export { MessageId, TargetMessage } from './src/utils';
export * from './private';
declare global {
/**
* Tag a template literal string for localization.
*
* For example:
*
* ```ts
* $localize `some string to localize`
* ```
*
* **Providing meaning, description and id**
*
* You can optionally specify one or more of `meaning`, `description` and `id` for a localized
* string by pre-pending it with a colon delimited block of the form:
*
* ```ts
* $localize`:meaning|description@@id:source message text`;
*
* $localize`:meaning|:source message text`;
* $localize`:description:source message text`;
* $localize`:@@id:source message text`;
* ```
*
* This format is the same as that used for `i18n` markers in Angular templates. See the
* [Angular i18n guide](guide/i18n-common-prepare#mark-text-in-component-template).
*
* **Naming placeholders**
*
* If the template literal string contains expressions, then the expressions will be automatically
* associated with placeholder names for you.
*
* For example:
*
* ```ts
* $localize `Hi ${name}! There are ${items.length} items.`;
* ```
*
* will generate a message-source of `Hi {$PH}! There are {$PH_1} items`.
*
* The recommended practice is to name the placeholder associated with each expression though.
*
* Do this by providing the placeholder name wrapped in `:` characters directly after the
* expression. These placeholder names are stripped out of the rendered localized string.
*
* For example, to name the `items.length` expression placeholder `itemCount` you write:
*
* ```ts
* $localize `There are ${items.length}:itemCount: items`;
* ```
*
* **Escaping colon markers**
*
* If you need to use a `:` character directly at the start of a tagged string that has no
* metadata block, or directly after a substitution expression that has no name you must escape
* the `:` by preceding it with a backslash:
*
* For example:
*
* ```ts
* // message has a metadata block so no need to escape colon
* $localize `:some description::this message starts with a colon (:)`;
* // no metadata block so the colon must be escaped
* $localize `\:this message starts with a colon (:)`;
* ```
*
* ```ts
* // named substitution so no need to escape colon
* $localize `${label}:label:: ${}`
* // anonymous substitution so colon must be escaped
* $localize `${label}\: ${}`
* ```
*
* **Processing localized strings:**
*
* There are three scenarios:
*
* * **compile-time inlining**: the `$localize` tag is transformed at compile time by a
* transpiler, removing the tag and replacing the template literal string with a translated
* literal string from a collection of translations provided to the transpilation tool.
*
* * **run-time evaluation**: the `$localize` tag is a run-time function that replaces and
* reorders the parts (static strings and expressions) of the template literal string with strings
* from a collection of translations loaded at run-time.
*
* * **pass-through evaluation**: the `$localize` tag is a run-time function that simply evaluates
* the original template literal string without applying any translations to the parts. This
* version is used during development or where there is no need to translate the localized
* template literals.
*
* @param messageParts a collection of the static parts of the template string.
* @param expressions a collection of the values of each placeholder in the template string.
* @returns the translated string, with the `messageParts` and `expressions` interleaved together.
*/
const $localize: LocalizeFn;
}
+89
View File
@@ -0,0 +1,89 @@
{
"name": "@angular/localize",
"version": "15.0.4",
"description": "Angular - library for localizing messages",
"bin": {
"localize-translate": "./tools/bundles/src/translate/cli.js",
"localize-extract": "./tools/bundles/src/extract/cli.js",
"localize-migrate": "./tools/bundles/src/migrate/cli.js"
},
"exports": {
"./tools": {
"types": "./tools/index.d.ts",
"default": "./tools/bundles/index.js"
},
"./package.json": {
"default": "./package.json"
},
".": {
"types": "./index.d.ts",
"esm2020": "./esm2020/index.mjs",
"es2020": "./fesm2020/localize.mjs",
"es2015": "./fesm2015/localize.mjs",
"node": "./fesm2015/localize.mjs",
"default": "./fesm2020/localize.mjs"
},
"./init": {
"types": "./init/index.d.ts",
"esm2020": "./esm2020/init/index.mjs",
"es2020": "./fesm2020/init.mjs",
"es2015": "./fesm2015/init.mjs",
"node": "./fesm2015/init.mjs",
"default": "./fesm2020/init.mjs"
}
},
"author": "angular",
"license": "MIT",
"engines": {
"node": "^14.20.0 || ^16.13.0 || >=18.10.0"
},
"repository": {
"type": "git",
"url": "https://github.com/angular/angular.git"
},
"schematics": "./schematics/collection.json",
"ng-update": {
"packageGroup": [
"@angular/core",
"@angular/bazel",
"@angular/common",
"@angular/compiler",
"@angular/compiler-cli",
"@angular/animations",
"@angular/elements",
"@angular/platform-browser",
"@angular/platform-browser-dynamic",
"@angular/forms",
"@angular/platform-server",
"@angular/upgrade",
"@angular/router",
"@angular/language-service",
"@angular/localize",
"@angular/service-worker"
]
},
"ng-add": {
"save": "devDependencies"
},
"sideEffects": [
"./esm2020/init/**",
"./fesm2015/init.mjs",
"./fesm2020/init.mjs"
],
"dependencies": {
"@babel/core": "7.19.3",
"glob": "8.0.3",
"yargs": "^17.2.1"
},
"peerDependencies": {
"@angular/compiler": "15.0.4",
"@angular/compiler-cli": "15.0.4"
},
"fesm2020": "./fesm2020/localize.mjs",
"fesm2015": "./fesm2015/localize.mjs",
"esm2020": "./esm2020/index.mjs",
"typings": "./index.d.ts",
"module": "./fesm2015/localize.mjs",
"es2020": "./fesm2020/localize.mjs",
"type": "module"
}
+10
View File
@@ -0,0 +1,10 @@
/**
* @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
*/
/// <amd-module name="@angular/localize/private" />
export { $localize as ɵ$localize, _global as ɵ_global, LocalizeFn as ɵLocalizeFn, TranslateFn as ɵTranslateFn } from './src/localize';
export { computeMsgId as ɵcomputeMsgId, findEndOfBlock as ɵfindEndOfBlock, isMissingTranslationError as ɵisMissingTranslationError, makeParsedTranslation as ɵmakeParsedTranslation, makeTemplateObject as ɵmakeTemplateObject, MissingTranslationError as ɵMissingTranslationError, ParsedMessage as ɵParsedMessage, ParsedTranslation as ɵParsedTranslation, ParsedTranslations as ɵParsedTranslations, parseMessage as ɵparseMessage, parseMetadata as ɵparseMetadata, parseTranslation as ɵparseTranslation, SourceLocation as ɵSourceLocation, SourceMessage as ɵSourceMessage, splitBlock as ɵsplitBlock, translate as ɵtranslate } from './src/utils';
+10
View File
@@ -0,0 +1,10 @@
{
"$schema": "../node_modules/@angular-devkit/schematics/collection-schema.json",
"schematics": {
"ng-add": {
"description": "Add @angular/localize polyfill to a project.",
"factory": "./ng-add",
"schema": "ng-add/schema.json"
}
}
}
+13
View File
@@ -0,0 +1,13 @@
/**
* @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
*
* @fileoverview Schematics for `ng add @angular/localize` schematic.
*/
/// <amd-module name="@angular/localize/schematics/ng-add" />
import { Rule } from '@angular-devkit/schematics';
import { Schema } from './schema';
export default function (options: Schema): Rule;
File diff suppressed because one or more lines are too long
+26
View File
@@ -0,0 +1,26 @@
/**
* @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
*/
export interface Schema {
/**
* The name of the project.
*/
project?: string;
/**
* The name of the project.
* @deprecated use the `project` option instead.
*/
name?: string;
/**
* Will this project use $localize at runtime?
*
* If true then the dependency is included in the `dependencies` section of package.json, rather
* than `devDependencies`.
*/
useAtRuntime?: boolean;
}
+26
View File
@@ -0,0 +1,26 @@
{
"$schema": "http://json-schema.org/draft-07/schema",
"$id": "SchematicsAngularLocalizeNgAdd",
"title": "Angular Localize Ng Add Schema",
"type": "object",
"properties": {
"project": {
"type": "string",
"description": "The name of the project.",
"$default": {
"$source": "projectName"
}
},
"name": {
"type": "string",
"description": "The name of the project.",
"x-deprecated": "Use the \"project\" option instead."
},
"useAtRuntime": {
"type": "boolean",
"description": "If set then `@angular/localize` is included in the `dependencies` section of `package.json`, rather than `devDependencies`, which is the default.",
"default": false
}
},
"required": []
}
+3
View File
@@ -0,0 +1,3 @@
{
"type": "commonjs"
}
+10
View File
@@ -0,0 +1,10 @@
/// <amd-module name="@angular/localize/src/localize" />
/**
* @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
*/
export { _global } from './src/global';
export { $localize, LocalizeFn, TranslateFn } from './src/localize';
+17
View File
@@ -0,0 +1,17 @@
/**
* @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
*/
/// <amd-module name="@angular/localize/src/localize/src/global" />
declare global {
interface WorkerGlobalScope extends EventTarget, WindowOrWorkerGlobalScope {
}
var WorkerGlobalScope: {
prototype: WorkerGlobalScope;
new (): WorkerGlobalScope;
};
}
export declare const _global: any;
+139
View File
@@ -0,0 +1,139 @@
/**
* @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
*/
/// <amd-module name="@angular/localize/src/localize/src/localize" />
/** @nodoc */
export interface LocalizeFn {
(messageParts: TemplateStringsArray, ...expressions: readonly any[]): string;
/**
* A function that converts an input "message with expressions" into a translated "message with
* expressions".
*
* The conversion may be done in place, modifying the array passed to the function, so
* don't assume that this has no side-effects.
*
* The expressions must be passed in since it might be they need to be reordered for
* different translations.
*/
translate?: TranslateFn;
/**
* The current locale of the translated messages.
*
* The compile-time translation inliner is able to replace the following code:
*
* ```
* typeof $localize !== "undefined" && $localize.locale
* ```
*
* with a string literal of the current locale. E.g.
*
* ```
* "fr"
* ```
*/
locale?: string;
}
/** @nodoc */
export interface TranslateFn {
(messageParts: TemplateStringsArray, expressions: readonly any[]): [TemplateStringsArray, readonly any[]];
}
/**
* Tag a template literal string for localization.
*
* For example:
*
* ```ts
* $localize `some string to localize`
* ```
*
* **Providing meaning, description and id**
*
* You can optionally specify one or more of `meaning`, `description` and `id` for a localized
* string by pre-pending it with a colon delimited block of the form:
*
* ```ts
* $localize`:meaning|description@@id:source message text`;
*
* $localize`:meaning|:source message text`;
* $localize`:description:source message text`;
* $localize`:@@id:source message text`;
* ```
*
* This format is the same as that used for `i18n` markers in Angular templates. See the
* [Angular i18n guide](guide/i18n-common-prepare#mark-text-in-component-template).
*
* **Naming placeholders**
*
* If the template literal string contains expressions, then the expressions will be automatically
* associated with placeholder names for you.
*
* For example:
*
* ```ts
* $localize `Hi ${name}! There are ${items.length} items.`;
* ```
*
* will generate a message-source of `Hi {$PH}! There are {$PH_1} items`.
*
* The recommended practice is to name the placeholder associated with each expression though.
*
* Do this by providing the placeholder name wrapped in `:` characters directly after the
* expression. These placeholder names are stripped out of the rendered localized string.
*
* For example, to name the `items.length` expression placeholder `itemCount` you write:
*
* ```ts
* $localize `There are ${items.length}:itemCount: items`;
* ```
*
* **Escaping colon markers**
*
* If you need to use a `:` character directly at the start of a tagged string that has no
* metadata block, or directly after a substitution expression that has no name you must escape
* the `:` by preceding it with a backslash:
*
* For example:
*
* ```ts
* // message has a metadata block so no need to escape colon
* $localize `:some description::this message starts with a colon (:)`;
* // no metadata block so the colon must be escaped
* $localize `\:this message starts with a colon (:)`;
* ```
*
* ```ts
* // named substitution so no need to escape colon
* $localize `${label}:label:: ${}`
* // anonymous substitution so colon must be escaped
* $localize `${label}\: ${}`
* ```
*
* **Processing localized strings:**
*
* There are three scenarios:
*
* * **compile-time inlining**: the `$localize` tag is transformed at compile time by a
* transpiler, removing the tag and replacing the template literal string with a translated
* literal string from a collection of translations provided to the transpilation tool.
*
* * **run-time evaluation**: the `$localize` tag is a run-time function that replaces and
* reorders the parts (static strings and expressions) of the template literal string with strings
* from a collection of translations loaded at run-time.
*
* * **pass-through evaluation**: the `$localize` tag is a run-time function that simply evaluates
* the original template literal string without applying any translations to the parts. This
* version is used during development or where there is no need to translate the localized
* template literals.
*
* @param messageParts a collection of the static parts of the template string.
* @param expressions a collection of the values of each placeholder in the template string.
* @returns the translated string, with the `messageParts` and `expressions` interleaved together.
*
* @globalApi
* @publicApi
*/
export declare const $localize: LocalizeFn;
+62
View File
@@ -0,0 +1,62 @@
/// <amd-module name="@angular/localize/src/translate" />
import { MessageId, TargetMessage } from './utils';
/**
* Load translations for use by `$localize`, if doing runtime translation.
*
* If the `$localize` tagged strings are not going to be replaced at compiled time, it is possible
* to load a set of translations that will be applied to the `$localize` tagged strings at runtime,
* in the browser.
*
* Loading a new translation will overwrite a previous translation if it has the same `MessageId`.
*
* Note that `$localize` messages are only processed once, when the tagged string is first
* encountered, and does not provide dynamic language changing without refreshing the browser.
* Loading new translations later in the application life-cycle will not change the translated text
* of messages that have already been translated.
*
* The message IDs and translations are in the same format as that rendered to "simple JSON"
* translation files when extracting messages. In particular, placeholders in messages are rendered
* using the `{$PLACEHOLDER_NAME}` syntax. For example the message from the following template:
*
* ```html
* <div i18n>pre<span>inner-pre<b>bold</b>inner-post</span>post</div>
* ```
*
* would have the following form in the `translations` map:
*
* ```ts
* {
* "2932901491976224757":
* "pre{$START_TAG_SPAN}inner-pre{$START_BOLD_TEXT}bold{$CLOSE_BOLD_TEXT}inner-post{$CLOSE_TAG_SPAN}post"
* }
* ```
*
* @param translations A map from message ID to translated message.
*
* These messages are processed and added to a lookup based on their `MessageId`.
*
* @see `clearTranslations()` for removing translations loaded using this function.
* @see `$localize` for tagging messages as needing to be translated.
* @publicApi
*/
export declare function loadTranslations(translations: Record<MessageId, TargetMessage>): void;
/**
* Remove all translations for `$localize`, if doing runtime translation.
*
* All translations that had been loading into memory using `loadTranslations()` will be removed.
*
* @see `loadTranslations()` for loading translations at runtime.
* @see `$localize` for tagging messages as needing to be translated.
*
* @publicApi
*/
export declare function clearTranslations(): void;
/**
* Translate the text of the given message, using the loaded translations.
*
* This function may reorder (or remove) substitutions as indicated in the matching translation.
*/
export declare function translate(messageParts: TemplateStringsArray, substitutions: readonly any[]): [
TemplateStringsArray,
readonly any[]
];
+11
View File
@@ -0,0 +1,11 @@
/// <amd-module name="@angular/localize/src/utils" />
/**
* @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
*/
export * from './src/constants';
export * from './src/messages';
export * from './src/translations';
+58
View File
@@ -0,0 +1,58 @@
/**
* @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
*/
/// <amd-module name="@angular/localize/src/utils/src/constants" />
/**
* The character used to mark the start and end of a "block" in a `$localize` tagged string.
* A block can indicate metadata about the message or specify a name of a placeholder for a
* substitution expressions.
*
* For example:
*
* ```ts
* $localize`Hello, ${title}:title:!`;
* $localize`:meaning|description@@id:source message text`;
* ```
*/
export declare const BLOCK_MARKER = ":";
/**
* The marker used to separate a message's "meaning" from its "description" in a metadata block.
*
* For example:
*
* ```ts
* $localize `:correct|Indicates that the user got the answer correct: Right!`;
* $localize `:movement|Button label for moving to the right: Right!`;
* ```
*/
export declare const MEANING_SEPARATOR = "|";
/**
* The marker used to separate a message's custom "id" from its "description" in a metadata block.
*
* For example:
*
* ```ts
* $localize `:A welcome message on the home page@@myApp-homepage-welcome: Welcome!`;
* ```
*/
export declare const ID_SEPARATOR = "@@";
/**
* The marker used to separate legacy message ids from the rest of a metadata block.
*
* For example:
*
* ```ts
* $localize `:@@custom-id␟2df64767cd895a8fabe3e18b94b5b6b6f9e2e3f0: Welcome!`;
* ```
*
* Note that this character is the "symbol for the unit separator" (␟) not the "unit separator
* character" itself, since that has no visual representation. See https://graphemica.com/%E2%90%9F.
*
* Here is some background for the original "unit separator character":
* https://stackoverflow.com/questions/8695118/whats-the-file-group-record-unit-separator-control-characters-and-its-usage
*/
export declare const LEGACY_ID_INDICATOR = "\u241F";
+240
View File
@@ -0,0 +1,240 @@
/// <amd-module name="@angular/localize/src/utils/src/messages" />
/**
* Re-export this helper function so that users of `@angular/localize` don't need to actively import
* from `@angular/compiler`.
*/
export { computeMsgId } from '@angular/compiler';
/**
* A string containing a translation source message.
*
* I.E. the message that indicates what will be translated from.
*
* Uses `{$placeholder-name}` to indicate a placeholder.
*/
export declare type SourceMessage = string;
/**
* A string containing a translation target message.
*
* I.E. the message that indicates what will be translated to.
*
* Uses `{$placeholder-name}` to indicate a placeholder.
*/
export declare type TargetMessage = string;
/**
* A string that uniquely identifies a message, to be used for matching translations.
*/
export declare type MessageId = string;
/**
* Declares a copy of the `AbsoluteFsPath` branded type in `@angular/compiler-cli` to avoid an
* import into `@angular/compiler-cli`. The compiler-cli's declaration files are not necessarily
* compatible with web environments that use `@angular/localize`, and would inadvertently include
* `typescript` declaration files in any compilation unit that uses `@angular/localize` (which
* increases parsing time and memory usage during builds) using a default import that only
* type-checks when `allowSyntheticDefaultImports` is enabled.
*
* @see https://github.com/angular/angular/issues/45179
*/
declare type AbsoluteFsPathLocalizeCopy = string & {
_brand: 'AbsoluteFsPath';
};
/**
* The location of the message in the source file.
*
* The `line` and `column` values for the `start` and `end` properties are zero-based.
*/
export interface SourceLocation {
start: {
line: number;
column: number;
};
end: {
line: number;
column: number;
};
file: AbsoluteFsPathLocalizeCopy;
text?: string;
}
/**
* Additional information that can be associated with a message.
*/
export interface MessageMetadata {
/**
* A human readable rendering of the message
*/
text: string;
/**
* Legacy message ids, if provided.
*
* In legacy message formats the message id can only be computed directly from the original
* template source.
*
* Since this information is not available in `$localize` calls, the legacy message ids may be
* attached by the compiler to the `$localize` metablock so it can be used if needed at the point
* of translation if the translations are encoded using the legacy message id.
*/
legacyIds?: string[];
/**
* The id of the `message` if a custom one was specified explicitly.
*
* This id overrides any computed or legacy ids.
*/
customId?: string;
/**
* The meaning of the `message`, used to distinguish identical `messageString`s.
*/
meaning?: string;
/**
* The description of the `message`, used to aid translation.
*/
description?: string;
/**
* The location of the message in the source.
*/
location?: SourceLocation;
}
/**
* Information parsed from a `$localize` tagged string that is used to translate it.
*
* For example:
*
* ```
* const name = 'Jo Bloggs';
* $localize`Hello ${name}:title@@ID:!`;
* ```
*
* May be parsed into:
*
* ```
* {
* id: '6998194507597730591',
* substitutions: { title: 'Jo Bloggs' },
* messageString: 'Hello {$title}!',
* placeholderNames: ['title'],
* associatedMessageIds: { title: 'ID' },
* }
* ```
*/
export interface ParsedMessage extends MessageMetadata {
/**
* The key used to look up the appropriate translation target.
*/
id: MessageId;
/**
* A mapping of placeholder names to substitution values.
*/
substitutions: Record<string, any>;
/**
* An optional mapping of placeholder names to associated MessageIds.
* This can be used to match ICU placeholders to the message that contains the ICU.
*/
associatedMessageIds?: Record<string, MessageId>;
/**
* An optional mapping of placeholder names to source locations
*/
substitutionLocations?: Record<string, SourceLocation | undefined>;
/**
* The static parts of the message.
*/
messageParts: string[];
/**
* An optional mapping of message parts to source locations
*/
messagePartLocations?: (SourceLocation | undefined)[];
/**
* The names of the placeholders that will be replaced with substitutions.
*/
placeholderNames: string[];
}
/**
* Parse a `$localize` tagged string into a structure that can be used for translation or
* extraction.
*
* See `ParsedMessage` for an example.
*/
export declare function parseMessage(messageParts: TemplateStringsArray, expressions?: readonly any[], location?: SourceLocation, messagePartLocations?: (SourceLocation | undefined)[], expressionLocations?: (SourceLocation | undefined)[]): ParsedMessage;
/**
* Parse the given message part (`cooked` + `raw`) to extract the message metadata from the text.
*
* If the message part has a metadata block this function will extract the `meaning`,
* `description`, `customId` and `legacyId` (if provided) from the block. These metadata properties
* are serialized in the string delimited by `|`, `@@` and `␟` respectively.
*
* (Note that `␟` is the `LEGACY_ID_INDICATOR` - see `constants.ts`.)
*
* For example:
*
* ```ts
* `:meaning|description@@custom-id:`
* `:meaning|@@custom-id:`
* `:meaning|description:`
* `:description@@custom-id:`
* `:meaning|:`
* `:description:`
* `:@@custom-id:`
* `:meaning|description@@custom-id␟legacy-id-1␟legacy-id-2:`
* ```
*
* @param cooked The cooked version of the message part to parse.
* @param raw The raw version of the message part to parse.
* @returns A object containing any metadata that was parsed from the message part.
*/
export declare function parseMetadata(cooked: string, raw: string): MessageMetadata;
/**
* Parse the given message part (`cooked` + `raw`) to extract any placeholder metadata from the
* text.
*
* If the message part has a metadata block this function will extract the `placeholderName` and
* `associatedMessageId` (if provided) from the block.
*
* These metadata properties are serialized in the string delimited by `@@`.
*
* For example:
*
* ```ts
* `:placeholder-name@@associated-id:`
* ```
*
* @param cooked The cooked version of the message part to parse.
* @param raw The raw version of the message part to parse.
* @returns A object containing the metadata (`placeholderName` and `associatedMessageId`) of the
* preceding placeholder, along with the static text that follows.
*/
export declare function parsePlaceholder(cooked: string, raw: string): {
messagePart: string;
placeholderName?: string;
associatedMessageId?: string;
};
/**
* Split a message part (`cooked` + `raw`) into an optional delimited "block" off the front and the
* rest of the text of the message part.
*
* Blocks appear at the start of message parts. They are delimited by a colon `:` character at the
* start and end of the block.
*
* If the block is in the first message part then it will be metadata about the whole message:
* meaning, description, id. Otherwise it will be metadata about the immediately preceding
* substitution: placeholder name.
*
* Since blocks are optional, it is possible that the content of a message block actually starts
* with a block marker. In this case the marker must be escaped `\:`.
*
* @param cooked The cooked version of the message part to parse.
* @param raw The raw version of the message part to parse.
* @returns An object containing the `text` of the message part and the text of the `block`, if it
* exists.
* @throws an error if the `block` is unterminated
*/
export declare function splitBlock(cooked: string, raw: string): {
text: string;
block?: string;
};
/**
* Find the end of a "marked block" indicated by the first non-escaped colon.
*
* @param cooked The cooked string (where escaped chars have been processed)
* @param raw The raw string (where escape sequences are still in place)
*
* @returns the index of the end of block marker
* @throws an error if the block is unterminated
*/
export declare function findEndOfBlock(cooked: string, raw: string): number;
+59
View File
@@ -0,0 +1,59 @@
/// <amd-module name="@angular/localize/src/utils/src/translations" />
import { MessageId, MessageMetadata, ParsedMessage, TargetMessage } from './messages';
/**
* A translation message that has been processed to extract the message parts and placeholders.
*/
export interface ParsedTranslation extends MessageMetadata {
messageParts: TemplateStringsArray;
placeholderNames: string[];
}
/**
* The internal structure used by the runtime localization to translate messages.
*/
export declare type ParsedTranslations = Record<MessageId, ParsedTranslation>;
export declare class MissingTranslationError extends Error {
readonly parsedMessage: ParsedMessage;
private readonly type;
constructor(parsedMessage: ParsedMessage);
}
export declare function isMissingTranslationError(e: any): e is MissingTranslationError;
/**
* Translate the text of the `$localize` tagged-string (i.e. `messageParts` and
* `substitutions`) using the given `translations`.
*
* The tagged-string is parsed to extract its `messageId` which is used to find an appropriate
* `ParsedTranslation`. If this doesn't match and there are legacy ids then try matching a
* translation using those.
*
* If one is found then it is used to translate the message into a new set of `messageParts` and
* `substitutions`.
* The translation may reorder (or remove) substitutions as appropriate.
*
* If there is no translation with a matching message id then an error is thrown.
* If a translation contains a placeholder that is not found in the message being translated then an
* error is thrown.
*/
export declare function translate(translations: Record<string, ParsedTranslation>, messageParts: TemplateStringsArray, substitutions: readonly any[]): [TemplateStringsArray, readonly any[]];
/**
* Parse the `messageParts` and `placeholderNames` out of a target `message`.
*
* Used by `loadTranslations()` to convert target message strings into a structure that is more
* appropriate for doing translation.
*
* @param message the message to be parsed.
*/
export declare function parseTranslation(messageString: TargetMessage): ParsedTranslation;
/**
* Create a `ParsedTranslation` from a set of `messageParts` and `placeholderNames`.
*
* @param messageParts The message parts to appear in the ParsedTranslation.
* @param placeholderNames The names of the placeholders to intersperse between the `messageParts`.
*/
export declare function makeParsedTranslation(messageParts: string[], placeholderNames?: string[]): ParsedTranslation;
/**
* Create the specialized array that is passed to tagged-string tag functions.
*
* @param cooked The message parts with their escape codes processed.
* @param raw The message parts with their escaped codes as-is.
*/
export declare function makeTemplateObject(cooked: string[], raw: string[]): TemplateStringsArray;
+4
View File
@@ -0,0 +1,4 @@
### Disclaimer
The localize tools are consumed via the Angular CLI. The programmatic APIs are not considered officially
supported though and are not subject to the breaking change guarantees of SemVer.
+678
View File
@@ -0,0 +1,678 @@
import {createRequire as __cjsCompatRequire} from 'module';
const require = __cjsCompatRequire(import.meta.url);
import {
Diagnostics,
buildCodeFrameError,
buildLocalizeReplacement,
isBabelParseError,
isLocalize,
translate,
types,
unwrapMessagePartsFromLocalizeCall,
unwrapMessagePartsFromTemplateLiteral,
unwrapSubstitutionsFromLocalizeCall
} from "./chunk-EE2T5UCZ.js";
// bazel-out/k8-fastbuild/bin/packages/localize/tools/src/translate/source_files/es2015_translate_plugin.mjs
import { getFileSystem } from "@angular/compiler-cli/private/localize";
function makeEs2015TranslatePlugin(diagnostics, translations, { missingTranslation = "error", localizeName = "$localize" } = {}, fs = getFileSystem()) {
return {
visitor: {
TaggedTemplateExpression(path) {
try {
const tag = path.get("tag");
if (isLocalize(tag, localizeName)) {
const [messageParts] = unwrapMessagePartsFromTemplateLiteral(path.get("quasi").get("quasis"), fs);
const translated = translate(diagnostics, translations, messageParts, path.node.quasi.expressions, missingTranslation);
path.replaceWith(buildLocalizeReplacement(translated[0], translated[1]));
}
} catch (e) {
if (isBabelParseError(e)) {
throw buildCodeFrameError(fs, path, e);
} else {
throw e;
}
}
}
}
};
}
// bazel-out/k8-fastbuild/bin/packages/localize/tools/src/translate/source_files/es5_translate_plugin.mjs
import { getFileSystem as getFileSystem2 } from "@angular/compiler-cli/private/localize";
function makeEs5TranslatePlugin(diagnostics, translations, { missingTranslation = "error", localizeName = "$localize" } = {}, fs = getFileSystem2()) {
return {
visitor: {
CallExpression(callPath) {
try {
const calleePath = callPath.get("callee");
if (isLocalize(calleePath, localizeName)) {
const [messageParts] = unwrapMessagePartsFromLocalizeCall(callPath, fs);
const [expressions] = unwrapSubstitutionsFromLocalizeCall(callPath, fs);
const translated = translate(diagnostics, translations, messageParts, expressions, missingTranslation);
callPath.replaceWith(buildLocalizeReplacement(translated[0], translated[1]));
}
} catch (e) {
if (isBabelParseError(e)) {
diagnostics.error(buildCodeFrameError(fs, callPath, e));
} else {
throw e;
}
}
}
}
};
}
// bazel-out/k8-fastbuild/bin/packages/localize/tools/src/translate/source_files/locale_plugin.mjs
function makeLocalePlugin(locale, { localizeName = "$localize" } = {}) {
return {
visitor: {
MemberExpression(expression) {
const obj = expression.get("object");
if (!isLocalize(obj, localizeName)) {
return;
}
const property = expression.get("property");
if (!property.isIdentifier({ name: "locale" })) {
return;
}
if (expression.parentPath.isAssignmentExpression() && expression.parentPath.get("left") === expression) {
return;
}
const parent = expression.parentPath;
if (parent.isLogicalExpression({ operator: "&&" }) && parent.get("right") === expression) {
const left = parent.get("left");
if (isLocalizeGuard(left, localizeName)) {
parent.replaceWith(expression);
} else if (left.isLogicalExpression({ operator: "&&" }) && isLocalizeGuard(left.get("right"), localizeName)) {
left.replaceWith(left.get("left"));
}
}
expression.replaceWith(types.stringLiteral(locale));
}
}
};
}
function isLocalizeGuard(expression, localizeName) {
if (!expression.isBinaryExpression() || !(expression.node.operator === "!==" || expression.node.operator === "!=")) {
return false;
}
const left = expression.get("left");
const right = expression.get("right");
return left.isUnaryExpression({ operator: "typeof" }) && isLocalize(left.get("argument"), localizeName) && right.isStringLiteral({ value: "undefined" }) || right.isUnaryExpression({ operator: "typeof" }) && isLocalize(right.get("argument"), localizeName) && left.isStringLiteral({ value: "undefined" });
}
// bazel-out/k8-fastbuild/bin/packages/localize/tools/src/translate/translation_files/translation_parsers/arb_translation_parser.mjs
import { \u0275parseTranslation } from "@angular/localize";
var ArbTranslationParser = class {
analyze(_filePath, contents) {
const diagnostics = new Diagnostics();
if (!contents.includes('"@@locale"')) {
return { canParse: false, diagnostics };
}
try {
return { canParse: true, diagnostics, hint: this.tryParseArbFormat(contents) };
} catch {
diagnostics.warn("File is not valid JSON.");
return { canParse: false, diagnostics };
}
}
parse(_filePath, contents, arb = this.tryParseArbFormat(contents)) {
const bundle = {
locale: arb["@@locale"],
translations: {},
diagnostics: new Diagnostics()
};
for (const messageId of Object.keys(arb)) {
if (messageId.startsWith("@")) {
continue;
}
const targetMessage = arb[messageId];
bundle.translations[messageId] = \u0275parseTranslation(targetMessage);
}
return bundle;
}
tryParseArbFormat(contents) {
const json = JSON.parse(contents);
if (typeof json["@@locale"] !== "string") {
throw new Error("Missing @@locale property.");
}
return json;
}
};
// bazel-out/k8-fastbuild/bin/packages/localize/tools/src/translate/translation_files/translation_parsers/simple_json_translation_parser.mjs
import { \u0275parseTranslation as \u0275parseTranslation2 } from "@angular/localize";
import { extname } from "path";
var SimpleJsonTranslationParser = class {
analyze(filePath, contents) {
const diagnostics = new Diagnostics();
if (extname(filePath) !== ".json" || !(contents.includes('"locale"') && contents.includes('"translations"'))) {
diagnostics.warn("File does not have .json extension.");
return { canParse: false, diagnostics };
}
try {
const json = JSON.parse(contents);
if (json.locale === void 0) {
diagnostics.warn('Required "locale" property missing.');
return { canParse: false, diagnostics };
}
if (typeof json.locale !== "string") {
diagnostics.warn('The "locale" property is not a string.');
return { canParse: false, diagnostics };
}
if (json.translations === void 0) {
diagnostics.warn('Required "translations" property missing.');
return { canParse: false, diagnostics };
}
if (typeof json.translations !== "object") {
diagnostics.warn('The "translations" is not an object.');
return { canParse: false, diagnostics };
}
return { canParse: true, diagnostics, hint: json };
} catch (e) {
diagnostics.warn("File is not valid JSON.");
return { canParse: false, diagnostics };
}
}
parse(_filePath, contents, json) {
const { locale: parsedLocale, translations } = json || JSON.parse(contents);
const parsedTranslations = {};
for (const messageId in translations) {
const targetMessage = translations[messageId];
parsedTranslations[messageId] = \u0275parseTranslation2(targetMessage);
}
return { locale: parsedLocale, translations: parsedTranslations, diagnostics: new Diagnostics() };
}
};
// bazel-out/k8-fastbuild/bin/packages/localize/tools/src/translate/translation_files/translation_parsers/xliff1_translation_parser.mjs
import { ParseErrorLevel as ParseErrorLevel3, visitAll as visitAll2 } from "@angular/compiler";
// bazel-out/k8-fastbuild/bin/packages/localize/tools/src/translate/translation_files/base_visitor.mjs
var BaseVisitor = class {
visitElement(_element, _context) {
}
visitAttribute(_attribute, _context) {
}
visitText(_text, _context) {
}
visitComment(_comment, _context) {
}
visitExpansion(_expansion, _context) {
}
visitExpansionCase(_expansionCase, _context) {
}
};
// bazel-out/k8-fastbuild/bin/packages/localize/tools/src/translate/translation_files/message_serialization/message_serializer.mjs
import { Element as Element2, visitAll } from "@angular/compiler";
// bazel-out/k8-fastbuild/bin/packages/localize/tools/src/translate/translation_files/translation_parsers/translation_parse_error.mjs
import { ParseErrorLevel } from "@angular/compiler";
var TranslationParseError = class extends Error {
constructor(span, msg, level = ParseErrorLevel.ERROR) {
super(contextualMessage(span, msg, level));
this.span = span;
this.msg = msg;
this.level = level;
}
};
function contextualMessage(span, msg, level) {
const ctx = span.start.getContext(100, 2);
msg += `
At ${span.start}${span.details ? `, ${span.details}` : ""}:
`;
if (ctx) {
msg += `...${ctx.before}[${ParseErrorLevel[level]} ->]${ctx.after}...
`;
}
return msg;
}
// bazel-out/k8-fastbuild/bin/packages/localize/tools/src/translate/translation_files/translation_parsers/translation_utils.mjs
import { Element, ParseError, ParseErrorLevel as ParseErrorLevel2, XmlParser } from "@angular/compiler";
function getAttrOrThrow(element, attrName) {
const attrValue = getAttribute(element, attrName);
if (attrValue === void 0) {
throw new TranslationParseError(element.sourceSpan, `Missing required "${attrName}" attribute:`);
}
return attrValue;
}
function getAttribute(element, attrName) {
const attr = element.attrs.find((a) => a.name === attrName);
return attr !== void 0 ? attr.value : void 0;
}
function parseInnerRange(element) {
const xmlParser = new XmlParser();
const xml = xmlParser.parse(element.sourceSpan.start.file.content, element.sourceSpan.start.file.url, { tokenizeExpansionForms: true, range: getInnerRange(element) });
return xml;
}
function getInnerRange(element) {
const start = element.startSourceSpan.end;
const end = element.endSourceSpan.start;
return {
startPos: start.offset,
startLine: start.line,
startCol: start.col,
endPos: end.offset
};
}
function canParseXml(filePath, contents, rootNodeName, attributes) {
const diagnostics = new Diagnostics();
const xmlParser = new XmlParser();
const xml = xmlParser.parse(contents, filePath);
if (xml.rootNodes.length === 0 || xml.errors.some((error) => error.level === ParseErrorLevel2.ERROR)) {
xml.errors.forEach((e) => addParseError(diagnostics, e));
return { canParse: false, diagnostics };
}
const rootElements = xml.rootNodes.filter(isNamedElement(rootNodeName));
const rootElement = rootElements[0];
if (rootElement === void 0) {
diagnostics.warn(`The XML file does not contain a <${rootNodeName}> root node.`);
return { canParse: false, diagnostics };
}
for (const attrKey of Object.keys(attributes)) {
const attr = rootElement.attrs.find((attr2) => attr2.name === attrKey);
if (attr === void 0 || attr.value !== attributes[attrKey]) {
addParseDiagnostic(diagnostics, rootElement.sourceSpan, `The <${rootNodeName}> node does not have the required attribute: ${attrKey}="${attributes[attrKey]}".`, ParseErrorLevel2.WARNING);
return { canParse: false, diagnostics };
}
}
if (rootElements.length > 1) {
xml.errors.push(new ParseError(xml.rootNodes[1].sourceSpan, "Unexpected root node. XLIFF 1.2 files should only have a single <xliff> root node.", ParseErrorLevel2.WARNING));
}
return { canParse: true, diagnostics, hint: { element: rootElement, errors: xml.errors } };
}
function isNamedElement(name) {
function predicate(node) {
return node instanceof Element && node.name === name;
}
return predicate;
}
function addParseDiagnostic(diagnostics, sourceSpan, message, level) {
addParseError(diagnostics, new ParseError(sourceSpan, message, level));
}
function addParseError(diagnostics, parseError) {
if (parseError.level === ParseErrorLevel2.ERROR) {
diagnostics.error(parseError.toString());
} else {
diagnostics.warn(parseError.toString());
}
}
function addErrorsToBundle(bundle, errors) {
for (const error of errors) {
addParseError(bundle.diagnostics, error);
}
}
// bazel-out/k8-fastbuild/bin/packages/localize/tools/src/translate/translation_files/message_serialization/message_serializer.mjs
var MessageSerializer = class extends BaseVisitor {
constructor(renderer, config) {
super();
this.renderer = renderer;
this.config = config;
}
serialize(nodes) {
this.renderer.startRender();
visitAll(this, nodes);
this.renderer.endRender();
return this.renderer.message;
}
visitElement(element) {
if (this.config.placeholder && element.name === this.config.placeholder.elementName) {
const name = getAttrOrThrow(element, this.config.placeholder.nameAttribute);
const body = this.config.placeholder.bodyAttribute && getAttribute(element, this.config.placeholder.bodyAttribute);
this.visitPlaceholder(name, body);
} else if (this.config.placeholderContainer && element.name === this.config.placeholderContainer.elementName) {
const start = getAttrOrThrow(element, this.config.placeholderContainer.startAttribute);
const end = getAttrOrThrow(element, this.config.placeholderContainer.endAttribute);
this.visitPlaceholderContainer(start, element.children, end);
} else if (this.config.inlineElements.indexOf(element.name) !== -1) {
visitAll(this, element.children);
} else {
throw new TranslationParseError(element.sourceSpan, `Invalid element found in message.`);
}
}
visitText(text) {
this.renderer.text(text.value);
}
visitExpansion(expansion) {
this.renderer.startIcu();
this.renderer.text(`${expansion.switchValue}, ${expansion.type},`);
visitAll(this, expansion.cases);
this.renderer.endIcu();
}
visitExpansionCase(expansionCase) {
this.renderer.text(` ${expansionCase.value} {`);
this.renderer.startContainer();
visitAll(this, expansionCase.expression);
this.renderer.closeContainer();
this.renderer.text(`}`);
}
visitContainedNodes(nodes) {
this.renderer.startContainer();
visitAll(this, nodes);
this.renderer.closeContainer();
}
visitPlaceholder(name, body) {
this.renderer.placeholder(name, body);
}
visitPlaceholderContainer(startName, children, closeName) {
this.renderer.startPlaceholder(startName);
this.visitContainedNodes(children);
this.renderer.closePlaceholder(closeName);
}
isPlaceholderContainer(node) {
return node instanceof Element2 && node.name === this.config.placeholderContainer.elementName;
}
};
// bazel-out/k8-fastbuild/bin/packages/localize/tools/src/translate/translation_files/message_serialization/target_message_renderer.mjs
import { \u0275makeParsedTranslation } from "@angular/localize";
var TargetMessageRenderer = class {
constructor() {
this.current = { messageParts: [], placeholderNames: [], text: "" };
this.icuDepth = 0;
}
get message() {
const { messageParts, placeholderNames } = this.current;
return \u0275makeParsedTranslation(messageParts, placeholderNames);
}
startRender() {
}
endRender() {
this.storeMessagePart();
}
text(text) {
this.current.text += text;
}
placeholder(name, body) {
this.renderPlaceholder(name);
}
startPlaceholder(name) {
this.renderPlaceholder(name);
}
closePlaceholder(name) {
this.renderPlaceholder(name);
}
startContainer() {
}
closeContainer() {
}
startIcu() {
this.icuDepth++;
this.text("{");
}
endIcu() {
this.icuDepth--;
this.text("}");
}
normalizePlaceholderName(name) {
return name.replace(/-/g, "_");
}
renderPlaceholder(name) {
name = this.normalizePlaceholderName(name);
if (this.icuDepth > 0) {
this.text(`{${name}}`);
} else {
this.storeMessagePart();
this.current.placeholderNames.push(name);
}
}
storeMessagePart() {
this.current.messageParts.push(this.current.text);
this.current.text = "";
}
};
// bazel-out/k8-fastbuild/bin/packages/localize/tools/src/translate/translation_files/translation_parsers/serialize_translation_message.mjs
function serializeTranslationMessage(element, config) {
const { rootNodes, errors: parseErrors } = parseInnerRange(element);
try {
const serializer = new MessageSerializer(new TargetMessageRenderer(), config);
const translation = serializer.serialize(rootNodes);
return { translation, parseErrors, serializeErrors: [] };
} catch (e) {
return { translation: null, parseErrors, serializeErrors: [e] };
}
}
// bazel-out/k8-fastbuild/bin/packages/localize/tools/src/translate/translation_files/translation_parsers/xliff1_translation_parser.mjs
var Xliff1TranslationParser = class {
analyze(filePath, contents) {
return canParseXml(filePath, contents, "xliff", { version: "1.2" });
}
parse(filePath, contents, hint) {
return this.extractBundle(hint);
}
extractBundle({ element, errors }) {
const diagnostics = new Diagnostics();
errors.forEach((e) => addParseError(diagnostics, e));
if (element.children.length === 0) {
addParseDiagnostic(diagnostics, element.sourceSpan, "Missing expected <file> element", ParseErrorLevel3.WARNING);
return { locale: void 0, translations: {}, diagnostics };
}
const files = element.children.filter(isNamedElement("file"));
if (files.length === 0) {
addParseDiagnostic(diagnostics, element.sourceSpan, "No <file> elements found in <xliff>", ParseErrorLevel3.WARNING);
} else if (files.length > 1) {
addParseDiagnostic(diagnostics, files[1].sourceSpan, "More than one <file> element found in <xliff>", ParseErrorLevel3.WARNING);
}
const bundle = { locale: void 0, translations: {}, diagnostics };
const translationVisitor = new XliffTranslationVisitor();
const localesFound = /* @__PURE__ */ new Set();
for (const file of files) {
const locale = getAttribute(file, "target-language");
if (locale !== void 0) {
localesFound.add(locale);
bundle.locale = locale;
}
visitAll2(translationVisitor, file.children, bundle);
}
if (localesFound.size > 1) {
addParseDiagnostic(diagnostics, element.sourceSpan, `More than one locale found in translation file: ${JSON.stringify(Array.from(localesFound))}. Using "${bundle.locale}"`, ParseErrorLevel3.WARNING);
}
return bundle;
}
};
var XliffTranslationVisitor = class extends BaseVisitor {
visitElement(element, bundle) {
if (element.name === "trans-unit") {
this.visitTransUnitElement(element, bundle);
} else {
visitAll2(this, element.children, bundle);
}
}
visitTransUnitElement(element, bundle) {
const id = getAttribute(element, "id");
if (id === void 0) {
addParseDiagnostic(bundle.diagnostics, element.sourceSpan, `Missing required "id" attribute on <trans-unit> element.`, ParseErrorLevel3.ERROR);
return;
}
if (bundle.translations[id] !== void 0) {
addParseDiagnostic(bundle.diagnostics, element.sourceSpan, `Duplicated translations for message "${id}"`, ParseErrorLevel3.ERROR);
return;
}
let targetMessage = element.children.find(isNamedElement("target"));
if (targetMessage === void 0) {
addParseDiagnostic(bundle.diagnostics, element.sourceSpan, "Missing <target> element", ParseErrorLevel3.WARNING);
targetMessage = element.children.find(isNamedElement("source"));
if (targetMessage === void 0) {
addParseDiagnostic(bundle.diagnostics, element.sourceSpan, "Missing required element: one of <target> or <source> is required", ParseErrorLevel3.ERROR);
return;
}
}
const { translation, parseErrors, serializeErrors } = serializeTranslationMessage(targetMessage, {
inlineElements: ["g", "bx", "ex", "bpt", "ept", "ph", "it", "mrk"],
placeholder: { elementName: "x", nameAttribute: "id" }
});
if (translation !== null) {
bundle.translations[id] = translation;
}
addErrorsToBundle(bundle, parseErrors);
addErrorsToBundle(bundle, serializeErrors);
}
};
// bazel-out/k8-fastbuild/bin/packages/localize/tools/src/translate/translation_files/translation_parsers/xliff2_translation_parser.mjs
import { Element as Element3, ParseErrorLevel as ParseErrorLevel4, visitAll as visitAll3 } from "@angular/compiler";
var Xliff2TranslationParser = class {
analyze(filePath, contents) {
return canParseXml(filePath, contents, "xliff", { version: "2.0" });
}
parse(filePath, contents, hint) {
return this.extractBundle(hint);
}
extractBundle({ element, errors }) {
const diagnostics = new Diagnostics();
errors.forEach((e) => addParseError(diagnostics, e));
const locale = getAttribute(element, "trgLang");
const files = element.children.filter(isFileElement);
if (files.length === 0) {
addParseDiagnostic(diagnostics, element.sourceSpan, "No <file> elements found in <xliff>", ParseErrorLevel4.WARNING);
} else if (files.length > 1) {
addParseDiagnostic(diagnostics, files[1].sourceSpan, "More than one <file> element found in <xliff>", ParseErrorLevel4.WARNING);
}
const bundle = { locale, translations: {}, diagnostics };
const translationVisitor = new Xliff2TranslationVisitor();
for (const file of files) {
visitAll3(translationVisitor, file.children, { bundle });
}
return bundle;
}
};
var Xliff2TranslationVisitor = class extends BaseVisitor {
visitElement(element, { bundle, unit }) {
if (element.name === "unit") {
this.visitUnitElement(element, bundle);
} else if (element.name === "segment") {
this.visitSegmentElement(element, bundle, unit);
} else {
visitAll3(this, element.children, { bundle, unit });
}
}
visitUnitElement(element, bundle) {
const externalId = getAttribute(element, "id");
if (externalId === void 0) {
addParseDiagnostic(bundle.diagnostics, element.sourceSpan, `Missing required "id" attribute on <trans-unit> element.`, ParseErrorLevel4.ERROR);
return;
}
if (bundle.translations[externalId] !== void 0) {
addParseDiagnostic(bundle.diagnostics, element.sourceSpan, `Duplicated translations for message "${externalId}"`, ParseErrorLevel4.ERROR);
return;
}
visitAll3(this, element.children, { bundle, unit: externalId });
}
visitSegmentElement(element, bundle, unit) {
if (unit === void 0) {
addParseDiagnostic(bundle.diagnostics, element.sourceSpan, "Invalid <segment> element: should be a child of a <unit> element.", ParseErrorLevel4.ERROR);
return;
}
let targetMessage = element.children.find(isNamedElement("target"));
if (targetMessage === void 0) {
addParseDiagnostic(bundle.diagnostics, element.sourceSpan, "Missing <target> element", ParseErrorLevel4.WARNING);
targetMessage = element.children.find(isNamedElement("source"));
if (targetMessage === void 0) {
addParseDiagnostic(bundle.diagnostics, element.sourceSpan, "Missing required element: one of <target> or <source> is required", ParseErrorLevel4.ERROR);
return;
}
}
const { translation, parseErrors, serializeErrors } = serializeTranslationMessage(targetMessage, {
inlineElements: ["cp", "sc", "ec", "mrk", "sm", "em"],
placeholder: { elementName: "ph", nameAttribute: "equiv", bodyAttribute: "disp" },
placeholderContainer: { elementName: "pc", startAttribute: "equivStart", endAttribute: "equivEnd" }
});
if (translation !== null) {
bundle.translations[unit] = translation;
}
addErrorsToBundle(bundle, parseErrors);
addErrorsToBundle(bundle, serializeErrors);
}
};
function isFileElement(node) {
return node instanceof Element3 && node.name === "file";
}
// bazel-out/k8-fastbuild/bin/packages/localize/tools/src/translate/translation_files/translation_parsers/xtb_translation_parser.mjs
import { ParseErrorLevel as ParseErrorLevel5, visitAll as visitAll4 } from "@angular/compiler";
import { extname as extname2 } from "path";
var XtbTranslationParser = class {
analyze(filePath, contents) {
const extension = extname2(filePath);
if (extension !== ".xtb" && extension !== ".xmb") {
const diagnostics = new Diagnostics();
diagnostics.warn("Must have xtb or xmb extension.");
return { canParse: false, diagnostics };
}
return canParseXml(filePath, contents, "translationbundle", {});
}
parse(filePath, contents, hint) {
return this.extractBundle(hint);
}
extractBundle({ element, errors }) {
const langAttr = element.attrs.find((attr) => attr.name === "lang");
const bundle = {
locale: langAttr && langAttr.value,
translations: {},
diagnostics: new Diagnostics()
};
errors.forEach((e) => addParseError(bundle.diagnostics, e));
const bundleVisitor = new XtbVisitor();
visitAll4(bundleVisitor, element.children, bundle);
return bundle;
}
};
var XtbVisitor = class extends BaseVisitor {
visitElement(element, bundle) {
switch (element.name) {
case "translation":
const id = getAttribute(element, "id");
if (id === void 0) {
addParseDiagnostic(bundle.diagnostics, element.sourceSpan, `Missing required "id" attribute on <translation> element.`, ParseErrorLevel5.ERROR);
return;
}
if (bundle.translations[id] !== void 0) {
addParseDiagnostic(bundle.diagnostics, element.sourceSpan, `Duplicated translations for message "${id}"`, ParseErrorLevel5.ERROR);
return;
}
const { translation, parseErrors, serializeErrors } = serializeTranslationMessage(element, { inlineElements: [], placeholder: { elementName: "ph", nameAttribute: "name" } });
if (parseErrors.length) {
bundle.diagnostics.warn(computeParseWarning(id, parseErrors));
} else if (translation !== null) {
bundle.translations[id] = translation;
}
addErrorsToBundle(bundle, serializeErrors);
break;
default:
addParseDiagnostic(bundle.diagnostics, element.sourceSpan, `Unexpected <${element.name}> tag.`, ParseErrorLevel5.ERROR);
}
}
};
function computeParseWarning(id, errors) {
const msg = errors.map((e) => e.toString()).join("\n");
return `Could not parse message with id "${id}" - perhaps it has an unrecognised ICU format?
` + msg;
}
export {
makeEs2015TranslatePlugin,
makeEs5TranslatePlugin,
makeLocalePlugin,
ArbTranslationParser,
SimpleJsonTranslationParser,
Xliff1TranslationParser,
Xliff2TranslationParser,
XtbTranslationParser
};
/**
* @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
*/
//# sourceMappingURL=chunk-52W4JLVC.js.map
File diff suppressed because one or more lines are too long
+344
View File
@@ -0,0 +1,344 @@
import {createRequire as __cjsCompatRequire} from 'module';
const require = __cjsCompatRequire(import.meta.url);
// bazel-out/k8-fastbuild/bin/packages/localize/tools/src/diagnostics.mjs
var Diagnostics = class {
constructor() {
this.messages = [];
}
get hasErrors() {
return this.messages.some((m) => m.type === "error");
}
add(type, message) {
if (type !== "ignore") {
this.messages.push({ type, message });
}
}
warn(message) {
this.messages.push({ type: "warning", message });
}
error(message) {
this.messages.push({ type: "error", message });
}
merge(other) {
this.messages.push(...other.messages);
}
formatDiagnostics(message) {
const errors = this.messages.filter((d) => d.type === "error").map((d) => " - " + d.message);
const warnings = this.messages.filter((d) => d.type === "warning").map((d) => " - " + d.message);
if (errors.length) {
message += "\nERRORS:\n" + errors.join("\n");
}
if (warnings.length) {
message += "\nWARNINGS:\n" + warnings.join("\n");
}
return message;
}
};
// bazel-out/k8-fastbuild/bin/packages/localize/tools/src/source_file_utils.mjs
import { getFileSystem } from "@angular/compiler-cli/private/localize";
import { \u0275isMissingTranslationError, \u0275makeTemplateObject, \u0275translate } from "@angular/localize";
// bazel-out/k8-fastbuild/bin/packages/localize/tools/src/babel_core.mjs
import * as _babelNamespace from "@babel/core";
import _babelDefault from "@babel/core";
var _a;
var babel = (_a = _babelDefault) != null ? _a : _babelNamespace;
var _typesNamespace = _babelNamespace.types;
if (_babelDefault !== void 0) {
_typesNamespace = _babelDefault.types;
}
var types2 = _typesNamespace;
var NodePath = babel.NodePath;
var transformSync = babel.transformSync;
var parseSync = babel.parseSync;
var transformFromAstSync = babel.transformFromAstSync;
// bazel-out/k8-fastbuild/bin/packages/localize/tools/src/source_file_utils.mjs
function isLocalize(expression, localizeName) {
return isNamedIdentifier(expression, localizeName) && isGlobalIdentifier(expression);
}
function isNamedIdentifier(expression, name) {
return expression.isIdentifier() && expression.node.name === name;
}
function isGlobalIdentifier(identifier) {
return !identifier.scope || !identifier.scope.hasBinding(identifier.node.name);
}
function buildLocalizeReplacement(messageParts, substitutions) {
let mappedString = types2.stringLiteral(messageParts[0]);
for (let i = 1; i < messageParts.length; i++) {
mappedString = types2.binaryExpression("+", mappedString, wrapInParensIfNecessary(substitutions[i - 1]));
mappedString = types2.binaryExpression("+", mappedString, types2.stringLiteral(messageParts[i]));
}
return mappedString;
}
function unwrapMessagePartsFromLocalizeCall(call, fs = getFileSystem()) {
let cooked = call.get("arguments")[0];
if (cooked === void 0) {
throw new BabelParseError(call.node, "`$localize` called without any arguments.");
}
if (!cooked.isExpression()) {
throw new BabelParseError(cooked.node, "Unexpected argument to `$localize` (expected an array).");
}
let raw = cooked;
if (cooked.isLogicalExpression() && cooked.node.operator === "||" && cooked.get("left").isIdentifier()) {
const right = cooked.get("right");
if (right.isAssignmentExpression()) {
cooked = right.get("right");
if (!cooked.isExpression()) {
throw new BabelParseError(cooked.node, 'Unexpected "makeTemplateObject()" function (expected an expression).');
}
} else if (right.isSequenceExpression()) {
const expressions = right.get("expressions");
if (expressions.length > 2) {
const [first, second] = expressions;
if (first.isAssignmentExpression()) {
cooked = first.get("right");
if (!cooked.isExpression()) {
throw new BabelParseError(first.node, "Unexpected cooked value, expected an expression.");
}
if (second.isAssignmentExpression()) {
raw = second.get("right");
if (!raw.isExpression()) {
throw new BabelParseError(second.node, "Unexpected raw value, expected an expression.");
}
} else {
raw = cooked;
}
}
}
}
}
if (cooked.isCallExpression()) {
let call2 = cooked;
if (call2.get("arguments").length === 0) {
call2 = unwrapLazyLoadHelperCall(call2);
}
cooked = call2.get("arguments")[0];
if (!cooked.isExpression()) {
throw new BabelParseError(cooked.node, 'Unexpected `cooked` argument to the "makeTemplateObject()" function (expected an expression).');
}
const arg2 = call2.get("arguments")[1];
if (arg2 && !arg2.isExpression()) {
throw new BabelParseError(arg2.node, 'Unexpected `raw` argument to the "makeTemplateObject()" function (expected an expression).');
}
raw = arg2 !== void 0 ? arg2 : cooked;
}
const [cookedStrings] = unwrapStringLiteralArray(cooked, fs);
const [rawStrings, rawLocations] = unwrapStringLiteralArray(raw, fs);
return [\u0275makeTemplateObject(cookedStrings, rawStrings), rawLocations];
}
function unwrapSubstitutionsFromLocalizeCall(call, fs = getFileSystem()) {
const expressions = call.get("arguments").splice(1);
if (!isArrayOfExpressions(expressions)) {
const badExpression = expressions.find((expression) => !expression.isExpression());
throw new BabelParseError(badExpression.node, "Invalid substitutions for `$localize` (expected all substitution arguments to be expressions).");
}
return [
expressions.map((path) => path.node),
expressions.map((expression) => getLocation(fs, expression))
];
}
function unwrapMessagePartsFromTemplateLiteral(elements, fs = getFileSystem()) {
const cooked = elements.map((q) => {
if (q.node.value.cooked === void 0) {
throw new BabelParseError(q.node, `Unexpected undefined message part in "${elements.map((q2) => q2.node.value.cooked)}"`);
}
return q.node.value.cooked;
});
const raw = elements.map((q) => q.node.value.raw);
const locations = elements.map((q) => getLocation(fs, q));
return [\u0275makeTemplateObject(cooked, raw), locations];
}
function unwrapExpressionsFromTemplateLiteral(quasi, fs = getFileSystem()) {
return [
quasi.node.expressions,
quasi.get("expressions").map((e) => getLocation(fs, e))
];
}
function wrapInParensIfNecessary(expression) {
if (types2.isBinaryExpression(expression)) {
return types2.parenthesizedExpression(expression);
} else {
return expression;
}
}
function unwrapStringLiteralArray(array, fs = getFileSystem()) {
if (!isStringLiteralArray(array.node)) {
throw new BabelParseError(array.node, "Unexpected messageParts for `$localize` (expected an array of strings).");
}
const elements = array.get("elements");
return [elements.map((str) => str.node.value), elements.map((str) => getLocation(fs, str))];
}
function unwrapLazyLoadHelperCall(call) {
const callee = call.get("callee");
if (!callee.isIdentifier()) {
throw new BabelParseError(callee.node, "Unexpected lazy-load helper call (expected a call of the form `_templateObject()`).");
}
const lazyLoadBinding = call.scope.getBinding(callee.node.name);
if (!lazyLoadBinding) {
throw new BabelParseError(callee.node, "Missing declaration for lazy-load helper function");
}
const lazyLoadFn = lazyLoadBinding.path;
if (!lazyLoadFn.isFunctionDeclaration()) {
throw new BabelParseError(lazyLoadFn.node, "Unexpected expression (expected a function declaration");
}
const returnedNode = getReturnedExpression(lazyLoadFn);
if (returnedNode.isCallExpression()) {
return returnedNode;
}
if (returnedNode.isIdentifier()) {
const identifierName = returnedNode.node.name;
const declaration = returnedNode.scope.getBinding(identifierName);
if (declaration === void 0) {
throw new BabelParseError(returnedNode.node, "Missing declaration for return value from helper.");
}
if (!declaration.path.isVariableDeclarator()) {
throw new BabelParseError(declaration.path.node, "Unexpected helper return value declaration (expected a variable declaration).");
}
const initializer = declaration.path.get("init");
if (!initializer.isCallExpression()) {
throw new BabelParseError(declaration.path.node, "Unexpected return value from helper (expected a call expression).");
}
if (lazyLoadBinding.references === 1) {
lazyLoadFn.remove();
}
return initializer;
}
return call;
}
function getReturnedExpression(fn) {
const bodyStatements = fn.get("body").get("body");
for (const statement of bodyStatements) {
if (statement.isReturnStatement()) {
const argument = statement.get("argument");
if (argument.isSequenceExpression()) {
const expressions = argument.get("expressions");
return Array.isArray(expressions) ? expressions[expressions.length - 1] : expressions;
} else if (argument.isExpression()) {
return argument;
} else {
throw new BabelParseError(statement.node, "Invalid return argument in helper function (expected an expression).");
}
}
}
throw new BabelParseError(fn.node, "Missing return statement in helper function.");
}
function isStringLiteralArray(node) {
return types2.isArrayExpression(node) && node.elements.every((element) => types2.isStringLiteral(element));
}
function isArrayOfExpressions(paths) {
return paths.every((element) => element.isExpression());
}
function translate(diagnostics, translations, messageParts, substitutions, missingTranslation) {
try {
return \u0275translate(translations, messageParts, substitutions);
} catch (e) {
if (\u0275isMissingTranslationError(e)) {
diagnostics.add(missingTranslation, e.message);
return [
\u0275makeTemplateObject(e.parsedMessage.messageParts, e.parsedMessage.messageParts),
substitutions
];
} else {
diagnostics.error(e.message);
return [messageParts, substitutions];
}
}
}
var BabelParseError = class extends Error {
constructor(node, message) {
super(message);
this.node = node;
this.type = "BabelParseError";
}
};
function isBabelParseError(e) {
return e.type === "BabelParseError";
}
function buildCodeFrameError(fs, path, e) {
let filename = path.hub.file.opts.filename;
if (filename) {
filename = fs.resolve(filename);
let cwd = path.hub.file.opts.cwd;
if (cwd) {
cwd = fs.resolve(cwd);
filename = fs.relative(cwd, filename);
}
} else {
filename = "(unknown file)";
}
const message = path.hub.file.buildCodeFrameError(e.node, e.message).message;
return `${filename}: ${message}`;
}
function getLocation(fs, startPath, endPath) {
const startLocation = startPath.node.loc;
const file = getFileFromPath(fs, startPath);
if (!startLocation || !file) {
return void 0;
}
const endLocation = endPath && getFileFromPath(fs, endPath) === file && endPath.node.loc || startLocation;
return {
start: getLineAndColumn(startLocation.start),
end: getLineAndColumn(endLocation.end),
file,
text: getText(startPath)
};
}
function serializeLocationPosition(location) {
const endLineString = location.end !== void 0 && location.end.line !== location.start.line ? `,${location.end.line + 1}` : "";
return `${location.start.line + 1}${endLineString}`;
}
function getFileFromPath(fs, path) {
var _a2, _b;
const opts = path == null ? void 0 : path.hub.file.opts;
const filename = opts == null ? void 0 : opts.filename;
if (!filename || !opts.cwd) {
return null;
}
const relativePath = fs.relative(opts.cwd, filename);
const root = (_b = (_a2 = opts.generatorOpts) == null ? void 0 : _a2.sourceRoot) != null ? _b : opts.cwd;
const absPath = fs.resolve(root, relativePath);
return absPath;
}
function getLineAndColumn(loc) {
return { line: loc.line - 1, column: loc.column };
}
function getText(path) {
if (path.node.start == null || path.node.end == null) {
return void 0;
}
return path.hub.file.code.substring(path.node.start, path.node.end);
}
export {
Diagnostics,
types2 as types,
transformSync,
parseSync,
transformFromAstSync,
isLocalize,
isNamedIdentifier,
isGlobalIdentifier,
buildLocalizeReplacement,
unwrapMessagePartsFromLocalizeCall,
unwrapSubstitutionsFromLocalizeCall,
unwrapMessagePartsFromTemplateLiteral,
unwrapExpressionsFromTemplateLiteral,
translate,
isBabelParseError,
buildCodeFrameError,
getLocation,
serializeLocationPosition
};
/**
* @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
*/
//# sourceMappingURL=chunk-EE2T5UCZ.js.map
File diff suppressed because one or more lines are too long
+902
View File
@@ -0,0 +1,902 @@
import {createRequire as __cjsCompatRequire} from 'module';
const require = __cjsCompatRequire(import.meta.url);
import {
Diagnostics,
buildCodeFrameError,
getLocation,
isBabelParseError,
isGlobalIdentifier,
isNamedIdentifier,
serializeLocationPosition,
transformSync,
unwrapExpressionsFromTemplateLiteral,
unwrapMessagePartsFromLocalizeCall,
unwrapMessagePartsFromTemplateLiteral,
unwrapSubstitutionsFromLocalizeCall
} from "./chunk-EE2T5UCZ.js";
// bazel-out/k8-fastbuild/bin/packages/localize/tools/src/extract/duplicates.mjs
function checkDuplicateMessages(fs, messages, duplicateMessageHandling, basePath) {
const diagnostics = new Diagnostics();
if (duplicateMessageHandling === "ignore")
return diagnostics;
const messageMap = /* @__PURE__ */ new Map();
for (const message of messages) {
if (messageMap.has(message.id)) {
messageMap.get(message.id).push(message);
} else {
messageMap.set(message.id, [message]);
}
}
for (const duplicates of messageMap.values()) {
if (duplicates.length <= 1)
continue;
if (duplicates.every((message) => message.text === duplicates[0].text))
continue;
const diagnosticMessage = `Duplicate messages with id "${duplicates[0].id}":
` + duplicates.map((message) => serializeMessage(fs, basePath, message)).join("\n");
diagnostics.add(duplicateMessageHandling, diagnosticMessage);
}
return diagnostics;
}
function serializeMessage(fs, basePath, message) {
if (message.location === void 0) {
return ` - "${message.text}"`;
} else {
const locationFile = fs.relative(basePath, message.location.file);
const locationPosition = serializeLocationPosition(message.location);
return ` - "${message.text}" : ${locationFile}:${locationPosition}`;
}
}
// bazel-out/k8-fastbuild/bin/packages/localize/tools/src/extract/extraction.mjs
import { SourceFileLoader } from "@angular/compiler-cli/private/localize";
// bazel-out/k8-fastbuild/bin/packages/localize/tools/src/extract/source_files/es2015_extract_plugin.mjs
import { \u0275parseMessage } from "@angular/localize";
function makeEs2015ExtractPlugin(fs, messages, localizeName = "$localize") {
return {
visitor: {
TaggedTemplateExpression(path) {
const tag = path.get("tag");
if (isNamedIdentifier(tag, localizeName) && isGlobalIdentifier(tag)) {
const quasiPath = path.get("quasi");
const [messageParts, messagePartLocations] = unwrapMessagePartsFromTemplateLiteral(quasiPath.get("quasis"), fs);
const [expressions, expressionLocations] = unwrapExpressionsFromTemplateLiteral(quasiPath, fs);
const location = getLocation(fs, quasiPath);
const message = \u0275parseMessage(messageParts, expressions, location, messagePartLocations, expressionLocations);
messages.push(message);
}
}
}
};
}
// bazel-out/k8-fastbuild/bin/packages/localize/tools/src/extract/source_files/es5_extract_plugin.mjs
import { \u0275parseMessage as \u0275parseMessage2 } from "@angular/localize";
function makeEs5ExtractPlugin(fs, messages, localizeName = "$localize") {
return {
visitor: {
CallExpression(callPath) {
try {
const calleePath = callPath.get("callee");
if (isNamedIdentifier(calleePath, localizeName) && isGlobalIdentifier(calleePath)) {
const [messageParts, messagePartLocations] = unwrapMessagePartsFromLocalizeCall(callPath, fs);
const [expressions, expressionLocations] = unwrapSubstitutionsFromLocalizeCall(callPath, fs);
const [messagePartsArg, expressionsArg] = callPath.get("arguments");
const location = getLocation(fs, messagePartsArg, expressionsArg);
const message = \u0275parseMessage2(messageParts, expressions, location, messagePartLocations, expressionLocations);
messages.push(message);
}
} catch (e) {
if (isBabelParseError(e)) {
throw buildCodeFrameError(fs, callPath, e);
} else {
throw e;
}
}
}
}
};
}
// bazel-out/k8-fastbuild/bin/packages/localize/tools/src/extract/extraction.mjs
var MessageExtractor = class {
constructor(fs, logger, { basePath, useSourceMaps = true, localizeName = "$localize" }) {
this.fs = fs;
this.logger = logger;
this.basePath = basePath;
this.useSourceMaps = useSourceMaps;
this.localizeName = localizeName;
this.loader = new SourceFileLoader(this.fs, this.logger, { webpack: basePath });
}
extractMessages(filename) {
const messages = [];
const sourceCode = this.fs.readFile(this.fs.resolve(this.basePath, filename));
if (sourceCode.includes(this.localizeName)) {
transformSync(sourceCode, {
sourceRoot: this.basePath,
filename,
plugins: [
makeEs2015ExtractPlugin(this.fs, messages, this.localizeName),
makeEs5ExtractPlugin(this.fs, messages, this.localizeName)
],
code: false,
ast: false
});
if (this.useSourceMaps && messages.length > 0) {
this.updateSourceLocations(filename, sourceCode, messages);
}
}
return messages;
}
updateSourceLocations(filename, contents, messages) {
const sourceFile = this.loader.loadSourceFile(this.fs.resolve(this.basePath, filename), contents);
if (sourceFile === null) {
return;
}
for (const message of messages) {
if (message.location !== void 0) {
message.location = this.getOriginalLocation(sourceFile, message.location);
if (message.messagePartLocations) {
message.messagePartLocations = message.messagePartLocations.map((location) => location && this.getOriginalLocation(sourceFile, location));
}
if (message.substitutionLocations) {
const placeholderNames = Object.keys(message.substitutionLocations);
for (const placeholderName of placeholderNames) {
const location = message.substitutionLocations[placeholderName];
message.substitutionLocations[placeholderName] = location && this.getOriginalLocation(sourceFile, location);
}
}
}
}
}
getOriginalLocation(sourceFile, location) {
const originalStart = sourceFile.getOriginalLocation(location.start.line, location.start.column);
if (originalStart === null) {
return location;
}
const originalEnd = sourceFile.getOriginalLocation(location.end.line, location.end.column);
const start = { line: originalStart.line, column: originalStart.column };
const end = originalEnd !== null && originalEnd.file === originalStart.file ? { line: originalEnd.line, column: originalEnd.column } : start;
const originalSourceFile = sourceFile.sources.find((sf) => (sf == null ? void 0 : sf.sourcePath) === originalStart.file);
const startPos = originalSourceFile.startOfLinePositions[start.line] + start.column;
const endPos = originalSourceFile.startOfLinePositions[end.line] + end.column;
const text = originalSourceFile.contents.substring(startPos, endPos).trim();
return { file: originalStart.file, start, end, text };
}
};
// bazel-out/k8-fastbuild/bin/packages/localize/tools/src/extract/translation_files/utils.mjs
function consolidateMessages(messages, getMessageId2) {
const messageGroups = /* @__PURE__ */ new Map();
for (const message of messages) {
const id = getMessageId2(message);
if (!messageGroups.has(id)) {
messageGroups.set(id, [message]);
} else {
messageGroups.get(id).push(message);
}
}
for (const messages2 of messageGroups.values()) {
messages2.sort(compareLocations);
}
return Array.from(messageGroups.values()).sort((a1, a2) => compareLocations(a1[0], a2[0]));
}
function hasLocation(message) {
return message.location !== void 0;
}
function compareLocations({ location: location1 }, { location: location2 }) {
if (location1 === location2) {
return 0;
}
if (location1 === void 0) {
return -1;
}
if (location2 === void 0) {
return 1;
}
if (location1.file !== location2.file) {
return location1.file < location2.file ? -1 : 1;
}
if (location1.start.line !== location2.start.line) {
return location1.start.line < location2.start.line ? -1 : 1;
}
if (location1.start.column !== location2.start.column) {
return location1.start.column < location2.start.column ? -1 : 1;
}
return 0;
}
// bazel-out/k8-fastbuild/bin/packages/localize/tools/src/extract/translation_files/arb_translation_serializer.mjs
var ArbTranslationSerializer = class {
constructor(sourceLocale, basePath, fs) {
this.sourceLocale = sourceLocale;
this.basePath = basePath;
this.fs = fs;
}
serialize(messages) {
const messageGroups = consolidateMessages(messages, (message) => getMessageId(message));
let output = `{
"@@locale": ${JSON.stringify(this.sourceLocale)}`;
for (const duplicateMessages of messageGroups) {
const message = duplicateMessages[0];
const id = getMessageId(message);
output += this.serializeMessage(id, message);
output += this.serializeMeta(id, message.description, message.meaning, duplicateMessages.filter(hasLocation).map((m) => m.location));
}
output += "\n}";
return output;
}
serializeMessage(id, message) {
return `,
${JSON.stringify(id)}: ${JSON.stringify(message.text)}`;
}
serializeMeta(id, description, meaning, locations) {
const meta = [];
if (description) {
meta.push(`
"description": ${JSON.stringify(description)}`);
}
if (meaning) {
meta.push(`
"x-meaning": ${JSON.stringify(meaning)}`);
}
if (locations.length > 0) {
let locationStr = `
"x-locations": [`;
for (let i = 0; i < locations.length; i++) {
locationStr += (i > 0 ? ",\n" : "\n") + this.serializeLocation(locations[i]);
}
locationStr += "\n ]";
meta.push(locationStr);
}
return meta.length > 0 ? `,
${JSON.stringify("@" + id)}: {${meta.join(",")}
}` : "";
}
serializeLocation({ file, start, end }) {
return [
` {`,
` "file": ${JSON.stringify(this.fs.relative(this.basePath, file))},`,
` "start": { "line": "${start.line}", "column": "${start.column}" },`,
` "end": { "line": "${end.line}", "column": "${end.column}" }`,
` }`
].join("\n");
}
};
function getMessageId(message) {
return message.customId || message.id;
}
// bazel-out/k8-fastbuild/bin/packages/localize/tools/src/extract/translation_files/json_translation_serializer.mjs
var SimpleJsonTranslationSerializer = class {
constructor(sourceLocale) {
this.sourceLocale = sourceLocale;
}
serialize(messages) {
const fileObj = { locale: this.sourceLocale, translations: {} };
for (const [message] of consolidateMessages(messages, (message2) => message2.id)) {
fileObj.translations[message.id] = message.text;
}
return JSON.stringify(fileObj, null, 2);
}
};
// bazel-out/k8-fastbuild/bin/packages/localize/tools/src/extract/translation_files/legacy_message_id_migration_serializer.mjs
var LegacyMessageIdMigrationSerializer = class {
constructor(_diagnostics) {
this._diagnostics = _diagnostics;
}
serialize(messages) {
let hasMessages = false;
const mapping = messages.reduce((output, message) => {
if (shouldMigrate(message)) {
for (const legacyId of message.legacyIds) {
if (output.hasOwnProperty(legacyId)) {
this._diagnostics.warn(`Detected duplicate legacy ID ${legacyId}.`);
}
output[legacyId] = message.id;
hasMessages = true;
}
}
return output;
}, {});
if (!hasMessages) {
this._diagnostics.warn("Could not find any legacy message IDs in source files while generating the legacy message migration file.");
}
return JSON.stringify(mapping, null, 2);
}
};
function shouldMigrate(message) {
return !message.customId && !!message.legacyIds && message.legacyIds.length > 0;
}
// bazel-out/k8-fastbuild/bin/packages/localize/tools/src/extract/translation_files/format_options.mjs
function validateOptions(name, validOptions, options) {
const validOptionsMap = new Map(validOptions);
for (const option in options) {
if (!validOptionsMap.has(option)) {
throw new Error(`Invalid format option for ${name}: "${option}".
Allowed options are ${JSON.stringify(Array.from(validOptionsMap.keys()))}.`);
}
const validOptionValues = validOptionsMap.get(option);
const optionValue = options[option];
if (!validOptionValues.includes(optionValue)) {
throw new Error(`Invalid format option value for ${name}: "${option}".
Allowed option values are ${JSON.stringify(validOptionValues)} but received "${optionValue}".`);
}
}
}
function parseFormatOptions(optionString = "{}") {
return JSON.parse(optionString);
}
// bazel-out/k8-fastbuild/bin/packages/localize/tools/src/extract/translation_files/xliff1_translation_serializer.mjs
import { getFileSystem } from "@angular/compiler-cli/private/localize";
// bazel-out/k8-fastbuild/bin/packages/localize/tools/src/extract/translation_files/icu_parsing.mjs
function extractIcuPlaceholders(text) {
const state = new StateStack();
const pieces = new IcuPieces();
const braces = /[{}]/g;
let lastPos = 0;
let match;
while (match = braces.exec(text)) {
if (match[0] == "{") {
state.enterBlock();
} else {
state.leaveBlock();
}
if (state.getCurrent() === "placeholder") {
const name = tryParsePlaceholder(text, braces.lastIndex);
if (name) {
pieces.addText(text.substring(lastPos, braces.lastIndex - 1));
pieces.addPlaceholder(name);
braces.lastIndex += name.length + 1;
state.leaveBlock();
} else {
pieces.addText(text.substring(lastPos, braces.lastIndex));
state.nestedIcu();
}
} else {
pieces.addText(text.substring(lastPos, braces.lastIndex));
}
lastPos = braces.lastIndex;
}
pieces.addText(text.substring(lastPos));
return pieces.toArray();
}
var IcuPieces = class {
constructor() {
this.pieces = [""];
}
addText(text) {
this.pieces[this.pieces.length - 1] += text;
}
addPlaceholder(name) {
this.pieces.push(name);
this.pieces.push("");
}
toArray() {
return this.pieces;
}
};
var StateStack = class {
constructor() {
this.stack = [];
}
enterBlock() {
const current = this.getCurrent();
switch (current) {
case "icu":
this.stack.push("case");
break;
case "case":
this.stack.push("placeholder");
break;
case "placeholder":
this.stack.push("case");
break;
default:
this.stack.push("icu");
break;
}
}
leaveBlock() {
return this.stack.pop();
}
nestedIcu() {
const current = this.stack.pop();
assert(current === "placeholder", "A nested ICU must replace a placeholder but got " + current);
this.stack.push("icu");
}
getCurrent() {
return this.stack[this.stack.length - 1];
}
};
function tryParsePlaceholder(text, start) {
for (let i = start; i < text.length; i++) {
if (text[i] === ",") {
break;
}
if (text[i] === "}") {
return text.substring(start, i);
}
}
return null;
}
function assert(test, message) {
if (!test) {
throw new Error("Assertion failure: " + message);
}
}
// bazel-out/k8-fastbuild/bin/packages/localize/tools/src/extract/translation_files/xml_file.mjs
var XmlFile = class {
constructor() {
this.output = '<?xml version="1.0" encoding="UTF-8" ?>\n';
this.indent = "";
this.elements = [];
this.preservingWhitespace = false;
}
toString() {
return this.output;
}
startTag(name, attributes = {}, { selfClosing = false, preserveWhitespace } = {}) {
if (!this.preservingWhitespace) {
this.output += this.indent;
}
this.output += `<${name}`;
for (const [attrName, attrValue] of Object.entries(attributes)) {
if (attrValue) {
this.output += ` ${attrName}="${escapeXml(attrValue)}"`;
}
}
if (selfClosing) {
this.output += "/>";
} else {
this.output += ">";
this.elements.push(name);
this.incIndent();
}
if (preserveWhitespace !== void 0) {
this.preservingWhitespace = preserveWhitespace;
}
if (!this.preservingWhitespace) {
this.output += `
`;
}
return this;
}
endTag(name, { preserveWhitespace } = {}) {
const expectedTag = this.elements.pop();
if (expectedTag !== name) {
throw new Error(`Unexpected closing tag: "${name}", expected: "${expectedTag}"`);
}
this.decIndent();
if (!this.preservingWhitespace) {
this.output += this.indent;
}
this.output += `</${name}>`;
if (preserveWhitespace !== void 0) {
this.preservingWhitespace = preserveWhitespace;
}
if (!this.preservingWhitespace) {
this.output += `
`;
}
return this;
}
text(str) {
this.output += escapeXml(str);
return this;
}
rawText(str) {
this.output += str;
return this;
}
incIndent() {
this.indent = this.indent + " ";
}
decIndent() {
this.indent = this.indent.slice(0, -2);
}
};
var _ESCAPED_CHARS = [
[/&/g, "&amp;"],
[/"/g, "&quot;"],
[/'/g, "&apos;"],
[/</g, "&lt;"],
[/>/g, "&gt;"]
];
function escapeXml(text) {
return _ESCAPED_CHARS.reduce((text2, entry) => text2.replace(entry[0], entry[1]), text);
}
// bazel-out/k8-fastbuild/bin/packages/localize/tools/src/extract/translation_files/xliff1_translation_serializer.mjs
var LEGACY_XLIFF_MESSAGE_LENGTH = 40;
var Xliff1TranslationSerializer = class {
constructor(sourceLocale, basePath, useLegacyIds, formatOptions = {}, fs = getFileSystem()) {
this.sourceLocale = sourceLocale;
this.basePath = basePath;
this.useLegacyIds = useLegacyIds;
this.formatOptions = formatOptions;
this.fs = fs;
validateOptions("Xliff1TranslationSerializer", [["xml:space", ["preserve"]]], formatOptions);
}
serialize(messages) {
const messageGroups = consolidateMessages(messages, (message) => this.getMessageId(message));
const xml = new XmlFile();
xml.startTag("xliff", { "version": "1.2", "xmlns": "urn:oasis:names:tc:xliff:document:1.2" });
xml.startTag("file", {
"source-language": this.sourceLocale,
"datatype": "plaintext",
"original": "ng2.template",
...this.formatOptions
});
xml.startTag("body");
for (const duplicateMessages of messageGroups) {
const message = duplicateMessages[0];
const id = this.getMessageId(message);
xml.startTag("trans-unit", { id, datatype: "html" });
xml.startTag("source", {}, { preserveWhitespace: true });
this.serializeMessage(xml, message);
xml.endTag("source", { preserveWhitespace: false });
for (const { location } of duplicateMessages.filter(hasLocation)) {
this.serializeLocation(xml, location);
}
if (message.description) {
this.serializeNote(xml, "description", message.description);
}
if (message.meaning) {
this.serializeNote(xml, "meaning", message.meaning);
}
xml.endTag("trans-unit");
}
xml.endTag("body");
xml.endTag("file");
xml.endTag("xliff");
return xml.toString();
}
serializeMessage(xml, message) {
var _a;
const length = message.messageParts.length - 1;
for (let i = 0; i < length; i++) {
this.serializeTextPart(xml, message.messageParts[i]);
const name = message.placeholderNames[i];
const location = (_a = message.substitutionLocations) == null ? void 0 : _a[name];
const associatedMessageId = message.associatedMessageIds && message.associatedMessageIds[name];
this.serializePlaceholder(xml, name, location == null ? void 0 : location.text, associatedMessageId);
}
this.serializeTextPart(xml, message.messageParts[length]);
}
serializeTextPart(xml, text) {
const pieces = extractIcuPlaceholders(text);
const length = pieces.length - 1;
for (let i = 0; i < length; i += 2) {
xml.text(pieces[i]);
this.serializePlaceholder(xml, pieces[i + 1], void 0, void 0);
}
xml.text(pieces[length]);
}
serializePlaceholder(xml, id, text, associatedId) {
const attrs = { id };
const ctype = getCtypeForPlaceholder(id);
if (ctype !== null) {
attrs.ctype = ctype;
}
if (text !== void 0) {
attrs["equiv-text"] = text;
}
if (associatedId !== void 0) {
attrs["xid"] = associatedId;
}
xml.startTag("x", attrs, { selfClosing: true });
}
serializeNote(xml, name, value) {
xml.startTag("note", { priority: "1", from: name }, { preserveWhitespace: true });
xml.text(value);
xml.endTag("note", { preserveWhitespace: false });
}
serializeLocation(xml, location) {
xml.startTag("context-group", { purpose: "location" });
this.renderContext(xml, "sourcefile", this.fs.relative(this.basePath, location.file));
const endLineString = location.end !== void 0 && location.end.line !== location.start.line ? `,${location.end.line + 1}` : "";
this.renderContext(xml, "linenumber", `${location.start.line + 1}${endLineString}`);
xml.endTag("context-group");
}
renderContext(xml, type, value) {
xml.startTag("context", { "context-type": type }, { preserveWhitespace: true });
xml.text(value);
xml.endTag("context", { preserveWhitespace: false });
}
getMessageId(message) {
return message.customId || this.useLegacyIds && message.legacyIds !== void 0 && message.legacyIds.find((id) => id.length === LEGACY_XLIFF_MESSAGE_LENGTH) || message.id;
}
};
function getCtypeForPlaceholder(placeholder) {
const tag = placeholder.replace(/^(START_|CLOSE_)/, "");
switch (tag) {
case "LINE_BREAK":
return "lb";
case "TAG_IMG":
return "image";
default:
const element = tag.startsWith("TAG_") ? tag.replace(/^TAG_(.+)/, (_, tagName) => tagName.toLowerCase()) : TAG_MAP[tag];
if (element === void 0) {
return null;
}
return `x-${element}`;
}
}
var TAG_MAP = {
"LINK": "a",
"BOLD_TEXT": "b",
"EMPHASISED_TEXT": "em",
"HEADING_LEVEL1": "h1",
"HEADING_LEVEL2": "h2",
"HEADING_LEVEL3": "h3",
"HEADING_LEVEL4": "h4",
"HEADING_LEVEL5": "h5",
"HEADING_LEVEL6": "h6",
"HORIZONTAL_RULE": "hr",
"ITALIC_TEXT": "i",
"LIST_ITEM": "li",
"MEDIA_LINK": "link",
"ORDERED_LIST": "ol",
"PARAGRAPH": "p",
"QUOTATION": "q",
"STRIKETHROUGH_TEXT": "s",
"SMALL_TEXT": "small",
"SUBSTRIPT": "sub",
"SUPERSCRIPT": "sup",
"TABLE_BODY": "tbody",
"TABLE_CELL": "td",
"TABLE_FOOTER": "tfoot",
"TABLE_HEADER_CELL": "th",
"TABLE_HEADER": "thead",
"TABLE_ROW": "tr",
"MONOSPACED_TEXT": "tt",
"UNDERLINED_TEXT": "u",
"UNORDERED_LIST": "ul"
};
// bazel-out/k8-fastbuild/bin/packages/localize/tools/src/extract/translation_files/xliff2_translation_serializer.mjs
import { getFileSystem as getFileSystem2 } from "@angular/compiler-cli/private/localize";
var MAX_LEGACY_XLIFF_2_MESSAGE_LENGTH = 20;
var Xliff2TranslationSerializer = class {
constructor(sourceLocale, basePath, useLegacyIds, formatOptions = {}, fs = getFileSystem2()) {
this.sourceLocale = sourceLocale;
this.basePath = basePath;
this.useLegacyIds = useLegacyIds;
this.formatOptions = formatOptions;
this.fs = fs;
this.currentPlaceholderId = 0;
validateOptions("Xliff1TranslationSerializer", [["xml:space", ["preserve"]]], formatOptions);
}
serialize(messages) {
const messageGroups = consolidateMessages(messages, (message) => this.getMessageId(message));
const xml = new XmlFile();
xml.startTag("xliff", {
"version": "2.0",
"xmlns": "urn:oasis:names:tc:xliff:document:2.0",
"srcLang": this.sourceLocale
});
xml.startTag("file", { "id": "ngi18n", "original": "ng.template", ...this.formatOptions });
for (const duplicateMessages of messageGroups) {
const message = duplicateMessages[0];
const id = this.getMessageId(message);
xml.startTag("unit", { id });
const messagesWithLocations = duplicateMessages.filter(hasLocation);
if (message.meaning || message.description || messagesWithLocations.length) {
xml.startTag("notes");
for (const { location: { file, start, end } } of messagesWithLocations) {
const endLineString = end !== void 0 && end.line !== start.line ? `,${end.line + 1}` : "";
this.serializeNote(xml, "location", `${this.fs.relative(this.basePath, file)}:${start.line + 1}${endLineString}`);
}
if (message.description) {
this.serializeNote(xml, "description", message.description);
}
if (message.meaning) {
this.serializeNote(xml, "meaning", message.meaning);
}
xml.endTag("notes");
}
xml.startTag("segment");
xml.startTag("source", {}, { preserveWhitespace: true });
this.serializeMessage(xml, message);
xml.endTag("source", { preserveWhitespace: false });
xml.endTag("segment");
xml.endTag("unit");
}
xml.endTag("file");
xml.endTag("xliff");
return xml.toString();
}
serializeMessage(xml, message) {
this.currentPlaceholderId = 0;
const length = message.messageParts.length - 1;
for (let i = 0; i < length; i++) {
this.serializeTextPart(xml, message.messageParts[i]);
const name = message.placeholderNames[i];
const associatedMessageId = message.associatedMessageIds && message.associatedMessageIds[name];
this.serializePlaceholder(xml, name, message.substitutionLocations, associatedMessageId);
}
this.serializeTextPart(xml, message.messageParts[length]);
}
serializeTextPart(xml, text) {
const pieces = extractIcuPlaceholders(text);
const length = pieces.length - 1;
for (let i = 0; i < length; i += 2) {
xml.text(pieces[i]);
this.serializePlaceholder(xml, pieces[i + 1], void 0, void 0);
}
xml.text(pieces[length]);
}
serializePlaceholder(xml, placeholderName, substitutionLocations, associatedMessageId) {
var _a, _b;
const text = (_a = substitutionLocations == null ? void 0 : substitutionLocations[placeholderName]) == null ? void 0 : _a.text;
if (placeholderName.startsWith("START_")) {
const closingPlaceholderName = placeholderName.replace(/^START/, "CLOSE").replace(/_\d+$/, "");
const closingText = (_b = substitutionLocations == null ? void 0 : substitutionLocations[closingPlaceholderName]) == null ? void 0 : _b.text;
const attrs = {
id: `${this.currentPlaceholderId++}`,
equivStart: placeholderName,
equivEnd: closingPlaceholderName
};
const type = getTypeForPlaceholder(placeholderName);
if (type !== null) {
attrs.type = type;
}
if (text !== void 0) {
attrs.dispStart = text;
}
if (closingText !== void 0) {
attrs.dispEnd = closingText;
}
xml.startTag("pc", attrs);
} else if (placeholderName.startsWith("CLOSE_")) {
xml.endTag("pc");
} else {
const attrs = {
id: `${this.currentPlaceholderId++}`,
equiv: placeholderName
};
const type = getTypeForPlaceholder(placeholderName);
if (type !== null) {
attrs.type = type;
}
if (text !== void 0) {
attrs.disp = text;
}
if (associatedMessageId !== void 0) {
attrs["subFlows"] = associatedMessageId;
}
xml.startTag("ph", attrs, { selfClosing: true });
}
}
serializeNote(xml, name, value) {
xml.startTag("note", { category: name }, { preserveWhitespace: true });
xml.text(value);
xml.endTag("note", { preserveWhitespace: false });
}
getMessageId(message) {
return message.customId || this.useLegacyIds && message.legacyIds !== void 0 && message.legacyIds.find((id) => id.length <= MAX_LEGACY_XLIFF_2_MESSAGE_LENGTH && !/[^0-9]/.test(id)) || message.id;
}
};
function getTypeForPlaceholder(placeholder) {
const tag = placeholder.replace(/^(START_|CLOSE_)/, "").replace(/_\d+$/, "");
switch (tag) {
case "BOLD_TEXT":
case "EMPHASISED_TEXT":
case "ITALIC_TEXT":
case "LINE_BREAK":
case "STRIKETHROUGH_TEXT":
case "UNDERLINED_TEXT":
return "fmt";
case "TAG_IMG":
return "image";
case "LINK":
return "link";
default:
return /^(START_|CLOSE_)/.test(placeholder) ? "other" : null;
}
}
// bazel-out/k8-fastbuild/bin/packages/localize/tools/src/extract/translation_files/xmb_translation_serializer.mjs
import { getFileSystem as getFileSystem3 } from "@angular/compiler-cli/private/localize";
var XmbTranslationSerializer = class {
constructor(basePath, useLegacyIds, fs = getFileSystem3()) {
this.basePath = basePath;
this.useLegacyIds = useLegacyIds;
this.fs = fs;
}
serialize(messages) {
const messageGroups = consolidateMessages(messages, (message) => this.getMessageId(message));
const xml = new XmlFile();
xml.rawText(`<!DOCTYPE messagebundle [
<!ELEMENT messagebundle (msg)*>
<!ATTLIST messagebundle class CDATA #IMPLIED>
<!ELEMENT msg (#PCDATA|ph|source)*>
<!ATTLIST msg id CDATA #IMPLIED>
<!ATTLIST msg seq CDATA #IMPLIED>
<!ATTLIST msg name CDATA #IMPLIED>
<!ATTLIST msg desc CDATA #IMPLIED>
<!ATTLIST msg meaning CDATA #IMPLIED>
<!ATTLIST msg obsolete (obsolete) #IMPLIED>
<!ATTLIST msg xml:space (default|preserve) "default">
<!ATTLIST msg is_hidden CDATA #IMPLIED>
<!ELEMENT source (#PCDATA)>
<!ELEMENT ph (#PCDATA|ex)*>
<!ATTLIST ph name CDATA #REQUIRED>
<!ELEMENT ex (#PCDATA)>
]>
`);
xml.startTag("messagebundle");
for (const duplicateMessages of messageGroups) {
const message = duplicateMessages[0];
const id = this.getMessageId(message);
xml.startTag("msg", { id, desc: message.description, meaning: message.meaning }, { preserveWhitespace: true });
if (message.location) {
this.serializeLocation(xml, message.location);
}
this.serializeMessage(xml, message);
xml.endTag("msg", { preserveWhitespace: false });
}
xml.endTag("messagebundle");
return xml.toString();
}
serializeLocation(xml, location) {
xml.startTag("source");
const endLineString = location.end !== void 0 && location.end.line !== location.start.line ? `,${location.end.line + 1}` : "";
xml.text(`${this.fs.relative(this.basePath, location.file)}:${location.start.line}${endLineString}`);
xml.endTag("source");
}
serializeMessage(xml, message) {
const length = message.messageParts.length - 1;
for (let i = 0; i < length; i++) {
this.serializeTextPart(xml, message.messageParts[i]);
xml.startTag("ph", { name: message.placeholderNames[i] }, { selfClosing: true });
}
this.serializeTextPart(xml, message.messageParts[length]);
}
serializeTextPart(xml, text) {
const pieces = extractIcuPlaceholders(text);
const length = pieces.length - 1;
for (let i = 0; i < length; i += 2) {
xml.text(pieces[i]);
xml.startTag("ph", { name: pieces[i + 1] }, { selfClosing: true });
}
xml.text(pieces[length]);
}
getMessageId(message) {
return message.customId || this.useLegacyIds && message.legacyIds !== void 0 && message.legacyIds.find((id) => id.length <= 20 && !/[^0-9]/.test(id)) || message.id;
}
};
export {
checkDuplicateMessages,
MessageExtractor,
ArbTranslationSerializer,
SimpleJsonTranslationSerializer,
LegacyMessageIdMigrationSerializer,
parseFormatOptions,
Xliff1TranslationSerializer,
Xliff2TranslationSerializer,
XmbTranslationSerializer
};
/**
* @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
*/
//# sourceMappingURL=chunk-ELQQ25UB.js.map
File diff suppressed because one or more lines are too long
+72
View File
@@ -0,0 +1,72 @@
import {createRequire as __cjsCompatRequire} from 'module';
const require = __cjsCompatRequire(import.meta.url);
import {
ArbTranslationSerializer,
LegacyMessageIdMigrationSerializer,
MessageExtractor,
SimpleJsonTranslationSerializer,
Xliff1TranslationSerializer,
Xliff2TranslationSerializer,
XmbTranslationSerializer,
checkDuplicateMessages
} from "./chunk-ELQQ25UB.js";
import {
ArbTranslationParser,
SimpleJsonTranslationParser,
Xliff1TranslationParser,
Xliff2TranslationParser,
XtbTranslationParser,
makeEs2015TranslatePlugin,
makeEs5TranslatePlugin,
makeLocalePlugin
} from "./chunk-52W4JLVC.js";
import {
Diagnostics,
buildLocalizeReplacement,
isGlobalIdentifier,
translate,
unwrapExpressionsFromTemplateLiteral,
unwrapMessagePartsFromLocalizeCall,
unwrapMessagePartsFromTemplateLiteral,
unwrapSubstitutionsFromLocalizeCall
} from "./chunk-EE2T5UCZ.js";
// bazel-out/k8-fastbuild/bin/packages/localize/tools/index.mjs
import { NodeJSFileSystem, setFileSystem } from "@angular/compiler-cli/private/localize";
setFileSystem(new NodeJSFileSystem());
export {
ArbTranslationParser,
ArbTranslationSerializer,
Diagnostics,
LegacyMessageIdMigrationSerializer,
MessageExtractor,
SimpleJsonTranslationParser,
SimpleJsonTranslationSerializer,
Xliff1TranslationParser,
Xliff1TranslationSerializer,
Xliff2TranslationParser,
Xliff2TranslationSerializer,
XmbTranslationSerializer,
XtbTranslationParser,
buildLocalizeReplacement,
checkDuplicateMessages,
isGlobalIdentifier,
makeEs2015TranslatePlugin,
makeEs5TranslatePlugin,
makeLocalePlugin,
translate,
unwrapExpressionsFromTemplateLiteral,
unwrapMessagePartsFromLocalizeCall,
unwrapMessagePartsFromTemplateLiteral,
unwrapSubstitutionsFromLocalizeCall
};
/**
* @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
*/
//# sourceMappingURL=index.js.map
+6
View File
@@ -0,0 +1,6 @@
{
"version": 3,
"sources": ["../../../../../../../packages/localize/tools/index.ts"],
"mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAWA,SAAQ,kBAAkB,qBAAoB;AAC9C,cAAc,IAAI,iBAAgB,CAAE;",
"names": []
}
+147
View File
@@ -0,0 +1,147 @@
#!/usr/bin/env node
import {createRequire as __cjsCompatRequire} from 'module';
const require = __cjsCompatRequire(import.meta.url);
import {
ArbTranslationSerializer,
LegacyMessageIdMigrationSerializer,
MessageExtractor,
SimpleJsonTranslationSerializer,
Xliff1TranslationSerializer,
Xliff2TranslationSerializer,
XmbTranslationSerializer,
checkDuplicateMessages,
parseFormatOptions
} from "../../chunk-ELQQ25UB.js";
import "../../chunk-EE2T5UCZ.js";
// bazel-out/k8-fastbuild/bin/packages/localize/tools/src/extract/cli.mjs
import { ConsoleLogger, LogLevel, NodeJSFileSystem, setFileSystem } from "@angular/compiler-cli/private/localize";
import glob from "glob";
import yargs from "yargs";
// bazel-out/k8-fastbuild/bin/packages/localize/tools/src/extract/index.mjs
function extractTranslations({ rootPath: rootPath2, sourceFilePaths: sourceFilePaths2, sourceLocale, format: format2, outputPath: output, logger: logger2, useSourceMaps, useLegacyIds, duplicateMessageHandling: duplicateMessageHandling2, formatOptions: formatOptions2 = {}, fileSystem: fs }) {
const basePath = fs.resolve(rootPath2);
const extractor = new MessageExtractor(fs, logger2, { basePath, useSourceMaps });
const messages = [];
for (const file of sourceFilePaths2) {
messages.push(...extractor.extractMessages(file));
}
const diagnostics = checkDuplicateMessages(fs, messages, duplicateMessageHandling2, basePath);
if (diagnostics.hasErrors) {
throw new Error(diagnostics.formatDiagnostics("Failed to extract messages"));
}
const outputPath = fs.resolve(rootPath2, output);
const serializer = getSerializer(format2, sourceLocale, fs.dirname(outputPath), useLegacyIds, formatOptions2, fs, diagnostics);
const translationFile = serializer.serialize(messages);
fs.ensureDir(fs.dirname(outputPath));
fs.writeFile(outputPath, translationFile);
if (diagnostics.messages.length) {
logger2.warn(diagnostics.formatDiagnostics("Messages extracted with warnings"));
}
}
function getSerializer(format2, sourceLocale, rootPath2, useLegacyIds, formatOptions2 = {}, fs, diagnostics) {
switch (format2) {
case "xlf":
case "xlif":
case "xliff":
return new Xliff1TranslationSerializer(sourceLocale, rootPath2, useLegacyIds, formatOptions2, fs);
case "xlf2":
case "xlif2":
case "xliff2":
return new Xliff2TranslationSerializer(sourceLocale, rootPath2, useLegacyIds, formatOptions2, fs);
case "xmb":
return new XmbTranslationSerializer(rootPath2, useLegacyIds, fs);
case "json":
return new SimpleJsonTranslationSerializer(sourceLocale);
case "arb":
return new ArbTranslationSerializer(sourceLocale, rootPath2, fs);
case "legacy-migrate":
return new LegacyMessageIdMigrationSerializer(diagnostics);
}
throw new Error(`No translation serializer can handle the provided format: ${format2}`);
}
// bazel-out/k8-fastbuild/bin/packages/localize/tools/src/extract/cli.mjs
process.title = "Angular Localization Message Extractor (localize-extract)";
var args = process.argv.slice(2);
var options = yargs(args).option("l", {
alias: "locale",
describe: "The locale of the source being processed",
default: "en",
type: "string"
}).option("r", {
alias: "root",
default: ".",
describe: "The root path for other paths provided in these options.\nThis should either be absolute or relative to the current working directory.",
type: "string"
}).option("s", {
alias: "source",
required: true,
describe: "A glob pattern indicating what files to search for translations, e.g. `./dist/**/*.js`.\nThis should be relative to the root path.",
type: "string"
}).option("f", {
alias: "format",
required: true,
choices: ["xmb", "xlf", "xlif", "xliff", "xlf2", "xlif2", "xliff2", "json", "legacy-migrate"],
describe: "The format of the translation file.",
type: "string"
}).option("formatOptions", {
describe: 'Additional options to pass to the translation file serializer, in the form of JSON formatted key-value string pairs:\nFor example: `--formatOptions {"xml:space":"preserve"}.\nThe meaning of the options is specific to the format being serialized.',
type: "string"
}).option("o", {
alias: "outputPath",
required: true,
describe: "A path to where the translation file will be written. This should be relative to the root path.",
type: "string"
}).option("loglevel", {
describe: "The lowest severity logging message that should be output.",
choices: ["debug", "info", "warn", "error"],
type: "string"
}).option("useSourceMaps", {
type: "boolean",
default: true,
describe: "Whether to generate source information in the output files by following source-map mappings found in the source files"
}).option("useLegacyIds", {
type: "boolean",
default: true,
describe: "Whether to use the legacy id format for messages that were extracted from Angular templates."
}).option("d", {
alias: "duplicateMessageHandling",
describe: "How to handle messages with the same id but different text.",
choices: ["error", "warning", "ignore"],
default: "warning",
type: "string"
}).strict().help().parseSync();
var fileSystem = new NodeJSFileSystem();
setFileSystem(fileSystem);
var rootPath = options.r;
var sourceFilePaths = glob.sync(options.s, { cwd: rootPath, nodir: true });
var logLevel = options.loglevel;
var logger = new ConsoleLogger(logLevel ? LogLevel[logLevel] : LogLevel.warn);
var duplicateMessageHandling = options.d;
var formatOptions = parseFormatOptions(options.formatOptions);
var format = options.f;
extractTranslations({
rootPath,
sourceFilePaths,
sourceLocale: options.l,
format,
outputPath: options.o,
logger,
useSourceMaps: options.useSourceMaps,
useLegacyIds: format === "legacy-migrate" || options.useLegacyIds,
duplicateMessageHandling,
formatOptions,
fileSystem
});
/**
* @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
*/
//# sourceMappingURL=cli.js.map
+6
View File
@@ -0,0 +1,6 @@
{
"version": 3,
"sources": ["../../../../../../../../../packages/localize/tools/src/extract/cli.ts", "../../../../../../../../../packages/localize/tools/src/extract/index.ts"],
"mappings": ";;;;;;;;;;;;;;;;;;;AASA,SAAQ,eAAe,UAAU,kBAAkB,qBAAoB;AACvE,OAAO,UAAU;AACjB,OAAO,WAAW;;;AC+DZ,SAAU,oBAAoB,EAClC,UAAAA,WACA,iBAAAC,kBACA,cACA,QAAAC,SACA,YAAY,QACZ,QAAAC,SACA,eACA,cACA,0BAAAC,2BACA,eAAAC,iBAAgB,CAAA,GAChB,YAAY,GAAE,GACa;AAC3B,QAAM,WAAW,GAAG,QAAQL,SAAQ;AACpC,QAAM,YAAY,IAAI,iBAAiB,IAAIG,SAAQ,EAAC,UAAU,cAAa,CAAC;AAE5E,QAAM,WAA6B,CAAA;AACnC,aAAW,QAAQF,kBAAiB;AAClC,aAAS,KAAK,GAAG,UAAU,gBAAgB,IAAI,CAAC;;AAGlD,QAAM,cAAc,uBAAuB,IAAI,UAAUG,2BAA0B,QAAQ;AAC3F,MAAI,YAAY,WAAW;AACzB,UAAM,IAAI,MAAM,YAAY,kBAAkB,4BAA4B,CAAC;;AAG7E,QAAM,aAAa,GAAG,QAAQJ,WAAU,MAAM;AAC9C,QAAM,aAAa,cACfE,SAAQ,cAAc,GAAG,QAAQ,UAAU,GAAG,cAAcG,gBAAe,IAAI,WAAW;AAC9F,QAAM,kBAAkB,WAAW,UAAU,QAAQ;AACrD,KAAG,UAAU,GAAG,QAAQ,UAAU,CAAC;AACnC,KAAG,UAAU,YAAY,eAAe;AAExC,MAAI,YAAY,SAAS,QAAQ;AAC/B,IAAAF,QAAO,KAAK,YAAY,kBAAkB,kCAAkC,CAAC;;AAEjF;AAEA,SAAS,cACLD,SAAgB,cAAsBF,WAA0B,cAChEK,iBAA+B,CAAA,GAAI,IACnC,aAAwB;AAC1B,UAAQH,SAAQ;IACd,KAAK;IACL,KAAK;IACL,KAAK;AACH,aAAO,IAAI,4BACP,cAAcF,WAAU,cAAcK,gBAAe,EAAE;IAC7D,KAAK;IACL,KAAK;IACL,KAAK;AACH,aAAO,IAAI,4BACP,cAAcL,WAAU,cAAcK,gBAAe,EAAE;IAC7D,KAAK;AACH,aAAO,IAAI,yBAAyBL,WAAU,cAAc,EAAE;IAChE,KAAK;AACH,aAAO,IAAI,gCAAgC,YAAY;IACzD,KAAK;AACH,aAAO,IAAI,yBAAyB,cAAcA,WAAU,EAAE;IAChE,KAAK;AACH,aAAO,IAAI,mCAAmC,WAAW;;AAE7D,QAAM,IAAI,MAAM,6DAA6DE,SAAQ;AACvF;;;ADxHA,QAAQ,QAAQ;AAChB,IAAM,OAAO,QAAQ,KAAK,MAAM,CAAC;AACjC,IAAM,UACF,MAAM,IAAI,EACL,OAAO,KAAK;EACX,OAAO;EACP,UAAU;EACV,SAAS;EACT,MAAM;CACP,EACA,OAAO,KAAK;EACX,OAAO;EACP,SAAS;EACT,UAAU;EAEV,MAAM;CACP,EACA,OAAO,KAAK;EACX,OAAO;EACP,UAAU;EACV,UACI;EAEJ,MAAM;CACP,EACA,OAAO,KAAK;EACX,OAAO;EACP,UAAU;EACV,SACI,CAAC,OAAO,OAAO,QAAQ,SAAS,QAAQ,SAAS,UAAU,QAAQ,gBAAgB;EACvF,UAAU;EACV,MAAM;CACP,EACA,OAAO,iBAAiB;EACvB,UACI;EAGJ,MAAM;CACP,EACA,OAAO,KAAK;EACX,OAAO;EACP,UAAU;EACV,UACI;EACJ,MAAM;CACP,EACA,OAAO,YAAY;EAClB,UAAU;EACV,SAAS,CAAC,SAAS,QAAQ,QAAQ,OAAO;EAC1C,MAAM;CACP,EACA,OAAO,iBAAiB;EACvB,MAAM;EACN,SAAS;EACT,UACI;CACL,EACA,OAAO,gBAAgB;EACtB,MAAM;EACN,SAAS;EACT,UACI;CACL,EACA,OAAO,KAAK;EACX,OAAO;EACP,UAAU;EACV,SAAS,CAAC,SAAS,WAAW,QAAQ;EACtC,SAAS;EACT,MAAM;CACP,EACA,OAAM,EACN,KAAI,EACJ,UAAS;AAElB,IAAM,aAAa,IAAI,iBAAgB;AACvC,cAAc,UAAU;AAExB,IAAM,WAAW,QAAQ;AACzB,IAAM,kBAAkB,KAAK,KAAK,QAAQ,GAAG,EAAC,KAAK,UAAU,OAAO,KAAI,CAAC;AACzE,IAAM,WAAW,QAAQ;AACzB,IAAM,SAAS,IAAI,cAAc,WAAW,SAAS,YAAY,SAAS,IAAI;AAC9E,IAAM,2BAA2B,QAAQ;AACzC,IAAM,gBAAgB,mBAAmB,QAAQ,aAAa;AAC9D,IAAM,SAAS,QAAQ;AAEvB,oBAAoB;EAClB;EACA;EACA,cAAc,QAAQ;EACtB;EACA,YAAY,QAAQ;EACpB;EACA,eAAe,QAAQ;EACvB,cAAc,WAAW,oBAAoB,QAAQ;EACrD;EACA;EACA;CACD;",
"names": ["rootPath", "sourceFilePaths", "format", "logger", "duplicateMessageHandling", "formatOptions"]
}
+77
View File
@@ -0,0 +1,77 @@
#!/usr/bin/env node
import {createRequire as __cjsCompatRequire} from 'module';
const require = __cjsCompatRequire(import.meta.url);
// bazel-out/k8-fastbuild/bin/packages/localize/tools/src/migrate/cli.mjs
import { ConsoleLogger, LogLevel, NodeJSFileSystem, setFileSystem } from "@angular/compiler-cli/private/localize";
import glob from "glob";
import yargs from "yargs";
// bazel-out/k8-fastbuild/bin/packages/localize/tools/src/migrate/index.mjs
import { getFileSystem } from "@angular/compiler-cli/private/localize";
// bazel-out/k8-fastbuild/bin/packages/localize/tools/src/migrate/migrate.mjs
function migrateFile(sourceCode, mapping) {
const legacyIds = Object.keys(mapping);
for (const legacyId of legacyIds) {
const canonicalId = mapping[legacyId];
const pattern = new RegExp(escapeRegExp(legacyId), "g");
sourceCode = sourceCode.replace(pattern, canonicalId);
}
return sourceCode;
}
function escapeRegExp(str) {
return str.replace(/([.*+?^=!:${}()|[\]\/\\])/g, "\\$1");
}
// bazel-out/k8-fastbuild/bin/packages/localize/tools/src/migrate/index.mjs
function migrateFiles({ rootPath: rootPath2, translationFilePaths: translationFilePaths2, mappingFilePath, logger: logger2 }) {
const fs2 = getFileSystem();
const absoluteMappingPath = fs2.resolve(rootPath2, mappingFilePath);
const mapping = JSON.parse(fs2.readFile(absoluteMappingPath));
if (Object.keys(mapping).length === 0) {
logger2.warn(`Mapping file at ${absoluteMappingPath} is empty. Either there are no messages that need to be migrated, or the extraction step failed to find them.`);
} else {
translationFilePaths2.forEach((path) => {
const absolutePath = fs2.resolve(rootPath2, path);
const sourceCode = fs2.readFile(absolutePath);
fs2.writeFile(absolutePath, migrateFile(sourceCode, mapping));
});
}
}
// bazel-out/k8-fastbuild/bin/packages/localize/tools/src/migrate/cli.mjs
var args = process.argv.slice(2);
var options = yargs(args).option("r", {
alias: "root",
default: ".",
describe: "The root path for other paths provided in these options.\nThis should either be absolute or relative to the current working directory.",
type: "string"
}).option("f", {
alias: "files",
required: true,
describe: "A glob pattern indicating what files to migrate. This should be relative to the root path",
type: "string"
}).option("m", {
alias: "mapFile",
required: true,
describe: "Path to the migration mapping file generated by `localize-extract`. This should be relative to the root path.",
type: "string"
}).strict().help().parseSync();
var fs = new NodeJSFileSystem();
setFileSystem(fs);
var rootPath = options.r;
var translationFilePaths = glob.sync(options.f, { cwd: rootPath, nodir: true });
var logger = new ConsoleLogger(LogLevel.warn);
migrateFiles({ rootPath, translationFilePaths, mappingFilePath: options.m, logger });
process.exit(0);
/**
* @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
*/
//# sourceMappingURL=cli.js.map
+6
View File
@@ -0,0 +1,6 @@
{
"version": 3,
"sources": ["../../../../../../../../../packages/localize/tools/src/migrate/cli.ts", "../../../../../../../../../packages/localize/tools/src/migrate/index.ts", "../../../../../../../../../packages/localize/tools/src/migrate/migrate.ts"],
"mappings": ";;;;;;;AASA,SAAQ,eAAe,UAAU,kBAAkB,qBAAoB;AACvE,OAAO,UAAU;AACjB,OAAO,WAAW;;;ACHlB,SAAQ,qBAA4B;;;ACM9B,SAAU,YAAY,YAAoB,SAAyB;AACvE,QAAM,YAAY,OAAO,KAAK,OAAO;AAErC,aAAW,YAAY,WAAW;AAChC,UAAM,cAAc,QAAQ;AAC5B,UAAM,UAAU,IAAI,OAAO,aAAa,QAAQ,GAAG,GAAG;AACtD,iBAAa,WAAW,QAAQ,SAAS,WAAW;;AAGtD,SAAO;AACT;AAGA,SAAS,aAAa,KAAW;AAC/B,SAAO,IAAI,QAAQ,8BAA8B,MAAM;AACzD;;;ADAM,SAAU,aAAa,EAC3B,UAAAA,WACA,sBAAAC,uBACA,iBACA,QAAAC,QAAM,GACc;AACpB,QAAMC,MAAK,cAAa;AACxB,QAAM,sBAAsBA,IAAG,QAAQH,WAAU,eAAe;AAChE,QAAM,UAAU,KAAK,MAAMG,IAAG,SAAS,mBAAmB,CAAC;AAE3D,MAAI,OAAO,KAAK,OAAO,EAAE,WAAW,GAAG;AACrC,IAAAD,QAAO,KACH,mBAAmB,kIACoD;SACtE;AACL,IAAAD,sBAAqB,QAAQ,UAAO;AAClC,YAAM,eAAeE,IAAG,QAAQH,WAAU,IAAI;AAC9C,YAAM,aAAaG,IAAG,SAAS,YAAY;AAC3C,MAAAA,IAAG,UAAU,cAAc,YAAY,YAAY,OAAO,CAAC;IAC7D,CAAC;;AAEL;;;ADpCA,IAAM,OAAO,QAAQ,KAAK,MAAM,CAAC;AACjC,IAAM,UACF,MAAM,IAAI,EACL,OAAO,KAAK;EACX,OAAO;EACP,SAAS;EACT,UAAU;EAEV,MAAM;CACP,EACA,OAAO,KAAK;EACX,OAAO;EACP,UAAU;EACV,UACI;EACJ,MAAM;CACP,EACA,OAAO,KAAK;EACX,OAAO;EACP,UAAU;EACV,UACI;EACJ,MAAM;CACP,EACA,OAAM,EACN,KAAI,EACJ,UAAS;AAElB,IAAM,KAAK,IAAI,iBAAgB;AAC/B,cAAc,EAAE;AAEhB,IAAM,WAAW,QAAQ;AACzB,IAAM,uBAAuB,KAAK,KAAK,QAAQ,GAAG,EAAC,KAAK,UAAU,OAAO,KAAI,CAAC;AAC9E,IAAM,SAAS,IAAI,cAAc,SAAS,IAAI;AAE9C,aAAa,EAAC,UAAU,sBAAsB,iBAAiB,QAAQ,GAAG,OAAM,CAAC;AACjF,QAAQ,KAAK,CAAC;",
"names": ["rootPath", "translationFilePaths", "logger", "fs"]
}
+322
View File
@@ -0,0 +1,322 @@
#!/usr/bin/env node
import {createRequire as __cjsCompatRequire} from 'module';
const require = __cjsCompatRequire(import.meta.url);
import {
ArbTranslationParser,
SimpleJsonTranslationParser,
Xliff1TranslationParser,
Xliff2TranslationParser,
XtbTranslationParser,
makeEs2015TranslatePlugin,
makeEs5TranslatePlugin,
makeLocalePlugin
} from "../../chunk-52W4JLVC.js";
import {
Diagnostics,
parseSync,
transformFromAstSync
} from "../../chunk-EE2T5UCZ.js";
// bazel-out/k8-fastbuild/bin/packages/localize/tools/src/translate/cli.mjs
import { NodeJSFileSystem, setFileSystem } from "@angular/compiler-cli/private/localize";
import glob from "glob";
import yargs from "yargs";
// bazel-out/k8-fastbuild/bin/packages/localize/tools/src/translate/output_path.mjs
function getOutputPathFn(fs2, outputFolder) {
const [pre, post] = outputFolder.split("{{LOCALE}}");
return post === void 0 ? (_locale, relativePath) => fs2.join(pre, relativePath) : (locale, relativePath) => fs2.join(pre + locale + post, relativePath);
}
// bazel-out/k8-fastbuild/bin/packages/localize/tools/src/translate/index.mjs
import { getFileSystem, relativeFrom } from "@angular/compiler-cli/private/localize";
// bazel-out/k8-fastbuild/bin/packages/localize/tools/src/translate/asset_files/asset_translation_handler.mjs
import { absoluteFrom } from "@angular/compiler-cli/private/localize";
var AssetTranslationHandler = class {
constructor(fs2) {
this.fs = fs2;
}
canTranslate(_relativeFilePath, _contents) {
return true;
}
translate(diagnostics2, _sourceRoot, relativeFilePath, contents, outputPathFn2, translations, sourceLocale2) {
for (const translation of translations) {
this.writeAssetFile(diagnostics2, outputPathFn2, translation.locale, relativeFilePath, contents);
}
if (sourceLocale2 !== void 0) {
this.writeAssetFile(diagnostics2, outputPathFn2, sourceLocale2, relativeFilePath, contents);
}
}
writeAssetFile(diagnostics2, outputPathFn2, locale, relativeFilePath, contents) {
try {
const outputPath = absoluteFrom(outputPathFn2(locale, relativeFilePath));
this.fs.ensureDir(this.fs.dirname(outputPath));
this.fs.writeFile(outputPath, contents);
} catch (e) {
diagnostics2.error(e.message);
}
}
};
// bazel-out/k8-fastbuild/bin/packages/localize/tools/src/translate/source_files/source_file_translation_handler.mjs
import { absoluteFrom as absoluteFrom2 } from "@angular/compiler-cli/private/localize";
var SourceFileTranslationHandler = class {
constructor(fs2, translationOptions = {}) {
this.fs = fs2;
this.translationOptions = translationOptions;
this.sourceLocaleOptions = { ...this.translationOptions, missingTranslation: "ignore" };
}
canTranslate(relativeFilePath, _contents) {
return this.fs.extname(relativeFilePath) === ".js";
}
translate(diagnostics2, sourceRoot, relativeFilePath, contents, outputPathFn2, translations, sourceLocale2) {
const sourceCode = Buffer.from(contents).toString("utf8");
if (!sourceCode.includes("$localize")) {
for (const translation of translations) {
this.writeSourceFile(diagnostics2, outputPathFn2, translation.locale, relativeFilePath, contents);
}
if (sourceLocale2 !== void 0) {
this.writeSourceFile(diagnostics2, outputPathFn2, sourceLocale2, relativeFilePath, contents);
}
} else {
const ast = parseSync(sourceCode, { sourceRoot, filename: relativeFilePath });
if (!ast) {
diagnostics2.error(`Unable to parse source file: ${this.fs.join(sourceRoot, relativeFilePath)}`);
return;
}
for (const translationBundle of translations) {
this.translateFile(diagnostics2, ast, translationBundle, sourceRoot, relativeFilePath, outputPathFn2, this.translationOptions);
}
if (sourceLocale2 !== void 0) {
this.translateFile(diagnostics2, ast, { locale: sourceLocale2, translations: {} }, sourceRoot, relativeFilePath, outputPathFn2, this.sourceLocaleOptions);
}
}
}
translateFile(diagnostics2, ast, translationBundle, sourceRoot, filename, outputPathFn2, options2) {
const translated = transformFromAstSync(ast, void 0, {
compact: true,
generatorOpts: { minified: true },
plugins: [
makeLocalePlugin(translationBundle.locale),
makeEs2015TranslatePlugin(diagnostics2, translationBundle.translations, options2, this.fs),
makeEs5TranslatePlugin(diagnostics2, translationBundle.translations, options2, this.fs)
],
cwd: sourceRoot,
filename
});
if (translated && translated.code) {
this.writeSourceFile(diagnostics2, outputPathFn2, translationBundle.locale, filename, translated.code);
const outputPath = absoluteFrom2(outputPathFn2(translationBundle.locale, filename));
this.fs.ensureDir(this.fs.dirname(outputPath));
this.fs.writeFile(outputPath, translated.code);
} else {
diagnostics2.error(`Unable to translate source file: ${this.fs.join(sourceRoot, filename)}`);
return;
}
}
writeSourceFile(diagnostics2, outputPathFn2, locale, relativeFilePath, contents) {
try {
const outputPath = absoluteFrom2(outputPathFn2(locale, relativeFilePath));
this.fs.ensureDir(this.fs.dirname(outputPath));
this.fs.writeFile(outputPath, contents);
} catch (e) {
diagnostics2.error(e.message);
}
}
};
// bazel-out/k8-fastbuild/bin/packages/localize/tools/src/translate/translation_files/translation_loader.mjs
var TranslationLoader = class {
constructor(fs2, translationParsers, duplicateTranslation2, diagnostics2) {
this.fs = fs2;
this.translationParsers = translationParsers;
this.duplicateTranslation = duplicateTranslation2;
this.diagnostics = diagnostics2;
}
loadBundles(translationFilePaths2, translationFileLocales2) {
return translationFilePaths2.map((filePaths, index) => {
const providedLocale = translationFileLocales2[index];
return this.mergeBundles(filePaths, providedLocale);
});
}
loadBundle(filePath, providedLocale) {
const fileContents = this.fs.readFile(filePath);
const unusedParsers = /* @__PURE__ */ new Map();
for (const translationParser of this.translationParsers) {
const result = translationParser.analyze(filePath, fileContents);
if (!result.canParse) {
unusedParsers.set(translationParser, result);
continue;
}
const { locale: parsedLocale, translations, diagnostics: diagnostics2 } = translationParser.parse(filePath, fileContents, result.hint);
if (diagnostics2.hasErrors) {
throw new Error(diagnostics2.formatDiagnostics(`The translation file "${filePath}" could not be parsed.`));
}
const locale = providedLocale || parsedLocale;
if (locale === void 0) {
throw new Error(`The translation file "${filePath}" does not contain a target locale and no explicit locale was provided for this file.`);
}
if (parsedLocale !== void 0 && providedLocale !== void 0 && parsedLocale !== providedLocale) {
diagnostics2.warn(`The provided locale "${providedLocale}" does not match the target locale "${parsedLocale}" found in the translation file "${filePath}".`);
}
if (this.diagnostics) {
this.diagnostics.merge(diagnostics2);
}
return { locale, translations, diagnostics: diagnostics2 };
}
const diagnosticsMessages = [];
for (const [parser, result] of unusedParsers.entries()) {
diagnosticsMessages.push(result.diagnostics.formatDiagnostics(`
${parser.constructor.name} cannot parse translation file.`));
}
throw new Error(`There is no "TranslationParser" that can parse this translation file: ${filePath}.` + diagnosticsMessages.join("\n"));
}
mergeBundles(filePaths, providedLocale) {
const bundles = filePaths.map((filePath) => this.loadBundle(filePath, providedLocale));
const bundle = bundles[0];
for (let i = 1; i < bundles.length; i++) {
const nextBundle = bundles[i];
if (nextBundle.locale !== bundle.locale) {
if (this.diagnostics) {
const previousFiles = filePaths.slice(0, i).map((f) => `"${f}"`).join(", ");
this.diagnostics.warn(`When merging multiple translation files, the target locale "${nextBundle.locale}" found in "${filePaths[i]}" does not match the target locale "${bundle.locale}" found in earlier files [${previousFiles}].`);
}
}
Object.keys(nextBundle.translations).forEach((messageId) => {
var _a;
if (bundle.translations[messageId] !== void 0) {
(_a = this.diagnostics) == null ? void 0 : _a.add(this.duplicateTranslation, `Duplicate translations for message "${messageId}" when merging "${filePaths[i]}".`);
} else {
bundle.translations[messageId] = nextBundle.translations[messageId];
}
});
}
return bundle;
}
};
// bazel-out/k8-fastbuild/bin/packages/localize/tools/src/translate/translator.mjs
var Translator = class {
constructor(fs2, resourceHandlers, diagnostics2) {
this.fs = fs2;
this.resourceHandlers = resourceHandlers;
this.diagnostics = diagnostics2;
}
translateFiles(inputPaths, rootPath, outputPathFn2, translations, sourceLocale2) {
inputPaths.forEach((inputPath) => {
const absInputPath = this.fs.resolve(rootPath, inputPath);
const contents = this.fs.readFileBuffer(absInputPath);
const relativePath = this.fs.relative(rootPath, absInputPath);
for (const resourceHandler of this.resourceHandlers) {
if (resourceHandler.canTranslate(relativePath, contents)) {
return resourceHandler.translate(this.diagnostics, rootPath, relativePath, contents, outputPathFn2, translations, sourceLocale2);
}
}
this.diagnostics.error(`Unable to handle resource file: ${inputPath}`);
});
}
};
// bazel-out/k8-fastbuild/bin/packages/localize/tools/src/translate/index.mjs
function translateFiles({ sourceRootPath: sourceRootPath2, sourceFilePaths: sourceFilePaths2, translationFilePaths: translationFilePaths2, translationFileLocales: translationFileLocales2, outputPathFn: outputPathFn2, diagnostics: diagnostics2, missingTranslation: missingTranslation2, duplicateTranslation: duplicateTranslation2, sourceLocale: sourceLocale2 }) {
const fs2 = getFileSystem();
const translationLoader = new TranslationLoader(fs2, [
new Xliff2TranslationParser(),
new Xliff1TranslationParser(),
new XtbTranslationParser(),
new SimpleJsonTranslationParser(),
new ArbTranslationParser()
], duplicateTranslation2, diagnostics2);
const resourceProcessor = new Translator(fs2, [
new SourceFileTranslationHandler(fs2, { missingTranslation: missingTranslation2 }),
new AssetTranslationHandler(fs2)
], diagnostics2);
const translationFilePathsArrays = translationFilePaths2.map((filePaths) => Array.isArray(filePaths) ? filePaths.map((p) => fs2.resolve(p)) : [fs2.resolve(filePaths)]);
const translations = translationLoader.loadBundles(translationFilePathsArrays, translationFileLocales2);
sourceRootPath2 = fs2.resolve(sourceRootPath2);
resourceProcessor.translateFiles(sourceFilePaths2.map(relativeFrom), fs2.resolve(sourceRootPath2), outputPathFn2, translations, sourceLocale2);
}
// bazel-out/k8-fastbuild/bin/packages/localize/tools/src/translate/cli.mjs
process.title = "Angular Localization Message Translator (localize-translate)";
var args = process.argv.slice(2);
var options = yargs(args).option("r", {
alias: "root",
required: true,
describe: "The root path of the files to translate, either absolute or relative to the current working directory. E.g. `dist/en`.",
type: "string"
}).option("s", {
alias: "source",
required: true,
describe: "A glob pattern indicating what files to translate, relative to the `root` path. E.g. `bundles/**/*`.",
type: "string"
}).option("l", {
alias: "source-locale",
describe: "The source locale of the application. If this is provided then a copy of the application will be created with no translation but just the `$localize` calls stripped out.",
type: "string"
}).option("t", {
alias: "translations",
required: true,
array: true,
describe: 'A list of paths to the translation files to load, either absolute or relative to the current working directory.\nE.g. `-t src/locale/messages.en.xlf src/locale/messages.fr.xlf src/locale/messages.de.xlf`.\nIf you want to merge multiple translation files for each locale, then provide the list of files in an array.\nNote that the arrays must be in double quotes if you include any whitespace within the array.\nE.g. `-t "[src/locale/messages.en.xlf, src/locale/messages-2.en.xlf]" [src/locale/messages.fr.xlf,src/locale/messages-2.fr.xlf]`',
type: "string"
}).option("target-locales", {
array: true,
describe: 'A list of target locales for the translation files, which will override any target locale parsed from the translation file.\nE.g. "-t en fr de".',
type: "string"
}).option("o", {
alias: "outputPath",
required: true,
describe: "A output path pattern to where the translated files will be written.\nThe path must be either absolute or relative to the current working directory.\nThe marker `{{LOCALE}}` will be replaced with the target locale. E.g. `dist/{{LOCALE}}`.",
type: "string"
}).option("m", {
alias: "missingTranslation",
describe: "How to handle missing translations.",
choices: ["error", "warning", "ignore"],
default: "warning",
type: "string"
}).option("d", {
alias: "duplicateTranslation",
describe: "How to handle duplicate translations.",
choices: ["error", "warning", "ignore"],
default: "warning",
type: "string"
}).strict().help().parseSync();
var fs = new NodeJSFileSystem();
setFileSystem(fs);
var sourceRootPath = options.r;
var sourceFilePaths = glob.sync(options.s, { cwd: sourceRootPath, nodir: true });
var translationFilePaths = convertArraysFromArgs(options.t);
var outputPathFn = getOutputPathFn(fs, fs.resolve(options.o));
var diagnostics = new Diagnostics();
var missingTranslation = options.m;
var duplicateTranslation = options.d;
var sourceLocale = options.l;
var translationFileLocales = options["target-locales"] || [];
translateFiles({
sourceRootPath,
sourceFilePaths,
translationFilePaths,
translationFileLocales,
outputPathFn,
diagnostics,
missingTranslation,
duplicateTranslation,
sourceLocale
});
diagnostics.messages.forEach((m) => console.warn(`${m.type}: ${m.message}`));
process.exit(diagnostics.hasErrors ? 1 : 0);
function convertArraysFromArgs(args2) {
return args2.map((arg) => arg.startsWith("[") && arg.endsWith("]") ? arg.slice(1, -1).split(",").map((arg2) => arg2.trim()) : arg);
}
/**
* @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
*/
//# sourceMappingURL=cli.js.map
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+26
View File
@@ -0,0 +1,26 @@
/**
* @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
*/
/// <amd-module name="@angular/localize/tools" />
export { DiagnosticHandlingStrategy, Diagnostics } from './src/diagnostics';
export { checkDuplicateMessages } from './src/extract/duplicates';
export { MessageExtractor } from './src/extract/extraction';
export { ArbTranslationSerializer } from './src/extract/translation_files/arb_translation_serializer';
export { SimpleJsonTranslationSerializer } from './src/extract/translation_files/json_translation_serializer';
export { LegacyMessageIdMigrationSerializer } from './src/extract/translation_files/legacy_message_id_migration_serializer';
export { Xliff1TranslationSerializer } from './src/extract/translation_files/xliff1_translation_serializer';
export { Xliff2TranslationSerializer } from './src/extract/translation_files/xliff2_translation_serializer';
export { XmbTranslationSerializer } from './src/extract/translation_files/xmb_translation_serializer';
export { buildLocalizeReplacement, isGlobalIdentifier, translate, unwrapExpressionsFromTemplateLiteral, unwrapMessagePartsFromLocalizeCall, unwrapMessagePartsFromTemplateLiteral, unwrapSubstitutionsFromLocalizeCall } from './src/source_file_utils';
export { makeEs2015TranslatePlugin } from './src/translate/source_files/es2015_translate_plugin';
export { makeEs5TranslatePlugin } from './src/translate/source_files/es5_translate_plugin';
export { makeLocalePlugin } from './src/translate/source_files/locale_plugin';
export { ArbTranslationParser } from './src/translate/translation_files/translation_parsers/arb_translation_parser';
export { SimpleJsonTranslationParser } from './src/translate/translation_files/translation_parsers/simple_json_translation_parser';
export { Xliff1TranslationParser } from './src/translate/translation_files/translation_parsers/xliff1_translation_parser';
export { Xliff2TranslationParser } from './src/translate/translation_files/translation_parsers/xliff2_translation_parser';
export { XtbTranslationParser } from './src/translate/translation_files/translation_parsers/xtb_translation_parser';
+38
View File
@@ -0,0 +1,38 @@
/**
* @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
*/
/// <amd-module name="@angular/localize/tools/src/babel_core" />
/**
* This is an interop file allowing for `@babel/core` to be imported in both CommonJS or
* ES module files. The `@babel/core` package needs some special treatment because:
*
* Using a default import does not with CommonJS because the `@babel/core` package does not
* expose a `default` export at runtime (because it sets the `_esModule` property that causes
* TS to not create the necessary interop `default` export). On the other side, when loaded
* as part of an ESM, NodeJS will make all of the exports available as default export.
*
* Using named import bindings (i.e. namespace import or actual named bindings) is not
* working well for ESM because as said before, NodeJS will make all of the exports available
* as the `default` export. Hence ESM that imports CJS, always should use the default import.
*
* There is no solution that would work for both CJS and ESM, so we need to use a custom interop
* that switches between the named exports or the default exports depending on what is available.
* This allows the code to run in both ESM (for production) and CJS (for development).
*
* TODO(devversion): remove this once devmode uses ESM as well.
*/
import * as _babelNamespace from '@babel/core';
import _typesNamespace = _babelNamespace.types;
export import types = _typesNamespace;
export declare type PluginObj = _babelNamespace.PluginObj;
export declare type ConfigAPI = _babelNamespace.ConfigAPI;
export declare type NodePath<T = _babelNamespace.Node> = _babelNamespace.NodePath<T>;
export declare type TransformOptions = _babelNamespace.TransformOptions;
export declare const NodePath: typeof _babelNamespace.NodePath;
export declare const transformSync: typeof _babelNamespace.transformSync;
export declare const parseSync: typeof _babelNamespace.parseSync;
export declare const transformFromAstSync: typeof _babelNamespace.transformFromAstSync;
+30
View File
@@ -0,0 +1,30 @@
/**
* @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
*/
/// <amd-module name="@angular/localize/tools/src/diagnostics" />
/**
* How to handle potential diagnostics.
*/
export declare type DiagnosticHandlingStrategy = 'error' | 'warning' | 'ignore';
/**
* This class is used to collect and then report warnings and errors that occur during the execution
* of the tools.
*
* @publicApi used by CLI
*/
export declare class Diagnostics {
readonly messages: {
type: 'warning' | 'error';
message: string;
}[];
get hasErrors(): boolean;
add(type: DiagnosticHandlingStrategy, message: string): void;
warn(message: string): void;
error(message: string): void;
merge(other: Diagnostics): void;
formatDiagnostics(message: string): string;
}
+10
View File
@@ -0,0 +1,10 @@
#!/usr/bin/env node
/**
* @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
*/
/// <amd-module name="@angular/localize/tools/src/extract/cli" />
export {};
+17
View File
@@ -0,0 +1,17 @@
/// <amd-module name="@angular/localize/tools/src/extract/duplicates" />
/**
* @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
*/
import { AbsoluteFsPath, PathManipulation } from '@angular/compiler-cli/private/localize';
import { ɵParsedMessage } from '@angular/localize';
import { DiagnosticHandlingStrategy, Diagnostics } from '../diagnostics';
/**
* Check each of the given `messages` to find those that have the same id but different message
* text. Add diagnostics messages for each of these duplicate messages to the given `diagnostics`
* object (as necessary).
*/
export declare function checkDuplicateMessages(fs: PathManipulation, messages: ɵParsedMessage[], duplicateMessageHandling: DiagnosticHandlingStrategy, basePath: AbsoluteFsPath): Diagnostics;
+46
View File
@@ -0,0 +1,46 @@
/// <amd-module name="@angular/localize/tools/src/extract/extraction" />
/**
* @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
*/
import { AbsoluteFsPath, Logger, ReadonlyFileSystem } from '@angular/compiler-cli/private/localize';
import { ɵParsedMessage } from '@angular/localize';
export interface ExtractionOptions {
basePath: AbsoluteFsPath;
useSourceMaps?: boolean;
localizeName?: string;
}
/**
* Extracts parsed messages from file contents, by parsing the contents as JavaScript
* and looking for occurrences of `$localize` in the source code.
*
* @publicApi used by CLI
*/
export declare class MessageExtractor {
private fs;
private logger;
private basePath;
private useSourceMaps;
private localizeName;
private loader;
constructor(fs: ReadonlyFileSystem, logger: Logger, { basePath, useSourceMaps, localizeName }: ExtractionOptions);
extractMessages(filename: string): ɵParsedMessage[];
/**
* Update the location of each message to point to the source-mapped original source location, if
* available.
*/
private updateSourceLocations;
/**
* Find the original location using source-maps if available.
*
* @param sourceFile The generated `sourceFile` that contains the `location`.
* @param location The location within the generated `sourceFile` that needs mapping.
*
* @returns A new location that refers to the original source location mapped from the given
* `location` in the generated `sourceFile`.
*/
private getOriginalLocation;
}
+61
View File
@@ -0,0 +1,61 @@
/// <amd-module name="@angular/localize/tools/src/extract/index" />
/**
* @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
*/
import { FileSystem, Logger } from '@angular/compiler-cli/private/localize';
import { DiagnosticHandlingStrategy } from '../diagnostics';
import { FormatOptions } from './translation_files/format_options';
export interface ExtractTranslationsOptions {
/**
* The locale of the source being processed.
*/
sourceLocale: string;
/**
* The base path for other paths provided in these options.
* This should either be absolute or relative to the current working directory.
*/
rootPath: string;
/**
* An array of paths to files to search for translations. These should be relative to the
* rootPath.
*/
sourceFilePaths: string[];
/**
* The format of the translation file.
*/
format: string;
/**
* A path to where the translation file will be written. This should be relative to the rootPath.
*/
outputPath: string;
/**
* The logger to use for diagnostic messages.
*/
logger: Logger;
/**
* Whether to generate source information in the output files by following source-map mappings
* found in the source file.
*/
useSourceMaps: boolean;
/**
* Whether to use the legacy id format for messages that were extracted from Angular templates
*/
useLegacyIds: boolean;
/**
* How to handle messages with the same id but not the same text.
*/
duplicateMessageHandling: DiagnosticHandlingStrategy;
/**
* A collection of formatting options to pass to the translation file serializer.
*/
formatOptions?: FormatOptions;
/**
* The file-system abstraction to use.
*/
fileSystem: FileSystem;
}
export declare function extractTranslations({ rootPath, sourceFilePaths, sourceLocale, format, outputPath: output, logger, useSourceMaps, useLegacyIds, duplicateMessageHandling, formatOptions, fileSystem: fs, }: ExtractTranslationsOptions): void;
@@ -0,0 +1,12 @@
/// <amd-module name="@angular/localize/tools/src/extract/source_files/es2015_extract_plugin" />
/**
* @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
*/
import { PathManipulation } from '@angular/compiler-cli/private/localize';
import { ɵParsedMessage } from '@angular/localize';
import { PluginObj } from '../../babel_core';
export declare function makeEs2015ExtractPlugin(fs: PathManipulation, messages: ɵParsedMessage[], localizeName?: string): PluginObj;
@@ -0,0 +1,12 @@
/// <amd-module name="@angular/localize/tools/src/extract/source_files/es5_extract_plugin" />
/**
* @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
*/
import { PathManipulation } from '@angular/compiler-cli/private/localize';
import { ɵParsedMessage } from '@angular/localize';
import { PluginObj } from '../../babel_core';
export declare function makeEs5ExtractPlugin(fs: PathManipulation, messages: ɵParsedMessage[], localizeName?: string): PluginObj;
@@ -0,0 +1,46 @@
/// <amd-module name="@angular/localize/tools/src/extract/translation_files/arb_translation_serializer" />
/**
* @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
*/
import { AbsoluteFsPath, PathManipulation } from '@angular/compiler-cli/private/localize';
import { ɵParsedMessage } from '@angular/localize';
import { TranslationSerializer } from './translation_serializer';
/**
* A translation serializer that can render JSON formatted as an Application Resource Bundle (ARB).
*
* See https://github.com/google/app-resource-bundle/wiki/ApplicationResourceBundleSpecification
*
* ```
* {
* "@@locale": "en-US",
* "message-id": "Target message string",
* "@message-id": {
* "type": "text",
* "description": "Some description text",
* "x-locations": [
* {
* "start": {"line": 23, "column": 145},
* "end": {"line": 24, "column": 53},
* "file": "some/file.ts"
* },
* ...
* ]
* },
* ...
* }
* ```
*/
export declare class ArbTranslationSerializer implements TranslationSerializer {
private sourceLocale;
private basePath;
private fs;
constructor(sourceLocale: string, basePath: AbsoluteFsPath, fs: PathManipulation);
serialize(messages: ɵParsedMessage[]): string;
private serializeMessage;
private serializeMeta;
private serializeLocation;
}
@@ -0,0 +1,23 @@
/**
* @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
*/
/// <amd-module name="@angular/localize/tools/src/extract/translation_files/format_options" />
export declare type FormatOptions = Record<string, string>;
export declare type ValidOption = [key: string, values: string[]];
export declare type ValidOptions = ValidOption[];
/**
* Check that the given `options` are allowed based on the given `validOptions`.
* @param name The name of the serializer that is receiving the options.
* @param validOptions An array of valid options and their allowed values.
* @param options The options to be validated.
*/
export declare function validateOptions(name: string, validOptions: ValidOptions, options: FormatOptions): void;
/**
* Parse the given `optionString` into a collection of `FormatOptions`.
* @param optionString The string to parse.
*/
export declare function parseFormatOptions(optionString?: string): FormatOptions;
@@ -0,0 +1,52 @@
/**
* @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
*/
/// <amd-module name="@angular/localize/tools/src/extract/translation_files/icu_parsing" />
/**
* Split the given `text` into an array of "static strings" and ICU "placeholder names".
*
* This is required because ICU expressions in `$localize` tagged messages may contain "dynamic"
* piece (e.g. interpolations or element markers). These markers need to be translated to
* placeholders in extracted translation files. So we must parse ICUs to identify them and separate
* them out so that the translation serializers can render them appropriately.
*
* An example of an ICU with interpolations:
*
* ```
* {VAR_PLURAL, plural, one {{INTERPOLATION}} other {{INTERPOLATION_1} post}}
* ```
*
* In this ICU, `INTERPOLATION` and `INTERPOLATION_1` are actually placeholders that will be
* replaced with dynamic content at runtime.
*
* Such placeholders are identifiable as text wrapped in curly braces, within an ICU case
* expression.
*
* To complicate matters, it is possible for ICUs to be nested indefinitely within each other. In
* such cases, the nested ICU expression appears enclosed in a set of curly braces in the same way
* as a placeholder. The nested ICU expressions can be differentiated from placeholders as they
* contain a comma `,`, which separates the ICU value from the ICU type.
*
* Furthermore, nested ICUs can have placeholders of their own, which need to be extracted.
*
* An example of a nested ICU containing its own placeholders:
*
* ```
* {VAR_SELECT_1, select,
* invoice {Invoice for {INTERPOLATION}}
* payment {{VAR_SELECT, select,
* processor {Payment gateway}
* other {{INTERPOLATION_1}}
* }}
* ```
*
* @param text Text to be broken.
* @returns an array of strings, where
* - even values are static strings (e.g. 0, 2, 4, etc)
* - odd values are placeholder names (e.g. 1, 3, 5, etc)
*/
export declare function extractIcuPlaceholders(text: string): string[];
@@ -0,0 +1,21 @@
/// <amd-module name="@angular/localize/tools/src/extract/translation_files/json_translation_serializer" />
/**
* @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
*/
import { ɵParsedMessage } from '@angular/localize';
import { TranslationSerializer } from './translation_serializer';
/**
* This is a semi-public bespoke serialization format that is used for testing and sometimes as a
* format for storing translations that will be inlined at runtime.
*
* @see SimpleJsonTranslationParser
*/
export declare class SimpleJsonTranslationSerializer implements TranslationSerializer {
private sourceLocale;
constructor(sourceLocale: string);
serialize(messages: ɵParsedMessage[]): string;
}
@@ -0,0 +1,21 @@
/// <amd-module name="@angular/localize/tools/src/extract/translation_files/legacy_message_id_migration_serializer" />
/**
* @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
*/
import { ɵParsedMessage as ParsedMessage } from '@angular/localize';
import { Diagnostics } from '../../diagnostics';
import { TranslationSerializer } from './translation_serializer';
/**
* A translation serializer that generates the mapping file for the legacy message ID migration.
* The file is used by the `localize-migrate` script to migrate existing translation files from
* the legacy message IDs to the canonical ones.
*/
export declare class LegacyMessageIdMigrationSerializer implements TranslationSerializer {
private _diagnostics;
constructor(_diagnostics: Diagnostics);
serialize(messages: ParsedMessage[]): string;
}
@@ -0,0 +1,21 @@
/// <amd-module name="@angular/localize/tools/src/extract/translation_files/translation_serializer" />
/**
* @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
*/
import { ɵParsedMessage } from '@angular/localize';
/**
* Implement this interface to provide a class that can render messages into a translation file.
*/
export interface TranslationSerializer {
/**
* Serialize the contents of a translation file containing the given `messages`.
*
* @param messages The messages to render to the file.
* @returns The contents of the serialized file.
*/
serialize(messages: ɵParsedMessage[]): string;
}
@@ -0,0 +1,32 @@
/// <amd-module name="@angular/localize/tools/src/extract/translation_files/utils" />
/**
* @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
*/
import { ɵParsedMessage, ɵSourceLocation } from '@angular/localize';
/**
* Consolidate messages into groups that have the same id.
*
* Messages with the same id are grouped together so that we can quickly deduplicate messages when
* rendering into translation files.
*
* To ensure that messages are rendered in a deterministic order:
* - the messages within a group are sorted by location (file path, then start position)
* - the groups are sorted by the location of the first message in the group
*
* @param messages the messages to consolidate.
* @param getMessageId a function that will compute the message id of a message.
* @returns an array of message groups, where each group is an array of messages that have the same
* id.
*/
export declare function consolidateMessages(messages: ɵParsedMessage[], getMessageId: (message: ɵParsedMessage) => string): ɵParsedMessage[][];
/**
* Does the given message have a location property?
*/
export declare function hasLocation(message: ɵParsedMessage): message is ɵParsedMessage & {
location: ɵSourceLocation;
};
export declare function compareLocations({ location: location1 }: ɵParsedMessage, { location: location2 }: ɵParsedMessage): number;
@@ -0,0 +1,50 @@
/// <amd-module name="@angular/localize/tools/src/extract/translation_files/xliff1_translation_serializer" />
/**
* @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
*/
import { AbsoluteFsPath, PathManipulation } from '@angular/compiler-cli/private/localize';
import { ɵParsedMessage } from '@angular/localize';
import { FormatOptions } from './format_options';
import { TranslationSerializer } from './translation_serializer';
/**
* A translation serializer that can write XLIFF 1.2 formatted files.
*
* https://docs.oasis-open.org/xliff/v1.2/os/xliff-core.html
* https://docs.oasis-open.org/xliff/v1.2/xliff-profile-html/xliff-profile-html-1.2.html
*
* @see Xliff1TranslationParser
* @publicApi used by CLI
*/
export declare class Xliff1TranslationSerializer implements TranslationSerializer {
private sourceLocale;
private basePath;
private useLegacyIds;
private formatOptions;
private fs;
constructor(sourceLocale: string, basePath: AbsoluteFsPath, useLegacyIds: boolean, formatOptions?: FormatOptions, fs?: PathManipulation);
serialize(messages: ɵParsedMessage[]): string;
private serializeMessage;
private serializeTextPart;
private serializePlaceholder;
private serializeNote;
private serializeLocation;
private renderContext;
/**
* Get the id for the given `message`.
*
* If there was a custom id provided, use that.
*
* If we have requested legacy message ids, then try to return the appropriate id
* from the list of legacy ids that were extracted.
*
* Otherwise return the canonical message id.
*
* An Xliff 1.2 legacy message id is a hex encoded SHA-1 string, which is 40 characters long. See
* https://csrc.nist.gov/csrc/media/publications/fips/180/4/final/documents/fips180-4-draft-aug2014.pdf
*/
private getMessageId;
}
@@ -0,0 +1,49 @@
/// <amd-module name="@angular/localize/tools/src/extract/translation_files/xliff2_translation_serializer" />
/**
* @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
*/
import { AbsoluteFsPath, PathManipulation } from '@angular/compiler-cli/private/localize';
import { ɵParsedMessage } from '@angular/localize';
import { FormatOptions } from './format_options';
import { TranslationSerializer } from './translation_serializer';
/**
* A translation serializer that can write translations in XLIFF 2 format.
*
* https://docs.oasis-open.org/xliff/xliff-core/v2.0/os/xliff-core-v2.0-os.html
*
* @see Xliff2TranslationParser
* @publicApi used by CLI
*/
export declare class Xliff2TranslationSerializer implements TranslationSerializer {
private sourceLocale;
private basePath;
private useLegacyIds;
private formatOptions;
private fs;
private currentPlaceholderId;
constructor(sourceLocale: string, basePath: AbsoluteFsPath, useLegacyIds: boolean, formatOptions?: FormatOptions, fs?: PathManipulation);
serialize(messages: ɵParsedMessage[]): string;
private serializeMessage;
private serializeTextPart;
private serializePlaceholder;
private serializeNote;
/**
* Get the id for the given `message`.
*
* If there was a custom id provided, use that.
*
* If we have requested legacy message ids, then try to return the appropriate id
* from the list of legacy ids that were extracted.
*
* Otherwise return the canonical message id.
*
* An Xliff 2.0 legacy message id is a 64 bit number encoded as a decimal string, which will have
* at most 20 digits, since 2^65-1 = 36,893,488,147,419,103,231. This digest is based on:
* https://github.com/google/closure-compiler/blob/master/src/com/google/javascript/jscomp/GoogleJsMessageIdGenerator.java
*/
private getMessageId;
}
@@ -0,0 +1,44 @@
/// <amd-module name="@angular/localize/tools/src/extract/translation_files/xmb_translation_serializer" />
/**
* @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
*/
import { AbsoluteFsPath, PathManipulation } from '@angular/compiler-cli/private/localize';
import { ɵParsedMessage } from '@angular/localize';
import { TranslationSerializer } from './translation_serializer';
/**
* A translation serializer that can write files in XMB format.
*
* http://cldr.unicode.org/development/development-process/design-proposals/xmb
*
* @see XmbTranslationParser
* @publicApi used by CLI
*/
export declare class XmbTranslationSerializer implements TranslationSerializer {
private basePath;
private useLegacyIds;
private fs;
constructor(basePath: AbsoluteFsPath, useLegacyIds: boolean, fs?: PathManipulation);
serialize(messages: ɵParsedMessage[]): string;
private serializeLocation;
private serializeMessage;
private serializeTextPart;
/**
* Get the id for the given `message`.
*
* If there was a custom id provided, use that.
*
* If we have requested legacy message ids, then try to return the appropriate id
* from the list of legacy ids that were extracted.
*
* Otherwise return the canonical message id.
*
* An XMB legacy message id is a 64 bit number encoded as a decimal string, which will have
* at most 20 digits, since 2^65-1 = 36,893,488,147,419,103,231. This digest is based on:
* https://github.com/google/closure-compiler/blob/master/src/com/google/javascript/jscomp/GoogleJsMessageIdGenerator.java
*/
private getMessageId;
}
@@ -0,0 +1,26 @@
/**
* @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
*/
/// <amd-module name="@angular/localize/tools/src/extract/translation_files/xml_file" />
interface Options {
selfClosing?: boolean;
preserveWhitespace?: boolean;
}
export declare class XmlFile {
private output;
private indent;
private elements;
private preservingWhitespace;
toString(): string;
startTag(name: string, attributes?: Record<string, string | undefined>, { selfClosing, preserveWhitespace }?: Options): this;
endTag(name: string, { preserveWhitespace }?: Options): this;
text(str: string): this;
rawText(str: string): this;
private incIndent;
private decIndent;
}
export {};
+10
View File
@@ -0,0 +1,10 @@
#!/usr/bin/env node
/**
* @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
*/
/// <amd-module name="@angular/localize/tools/src/migrate/cli" />
export {};
+24
View File
@@ -0,0 +1,24 @@
/**
* @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
*/
/// <amd-module name="@angular/localize/tools/src/migrate/index" />
import { Logger } from '@angular/compiler-cli/private/localize';
export interface MigrateFilesOptions {
/**
* The base path for other paths provided in these options.
* This should either be absolute or relative to the current working directory.
*/
rootPath: string;
/** Paths to the files that should be migrated. Should be relative to the `rootPath`. */
translationFilePaths: string[];
/** Path to the file containing the message ID mappings. Should be relative to the `rootPath`. */
mappingFilePath: string;
/** Logger to use for diagnostic messages. */
logger: Logger;
}
/** Migrates the legacy message IDs based on the passed in configuration. */
export declare function migrateFiles({ rootPath, translationFilePaths, mappingFilePath, logger, }: MigrateFilesOptions): void;
+14
View File
@@ -0,0 +1,14 @@
/**
* @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
*/
/// <amd-module name="@angular/localize/tools/src/migrate/migrate" />
/** Mapping between legacy message IDs and their canonical counterparts. */
export declare type MigrationMapping = {
[legacyId: string]: string;
};
/** Migrates the legacy message IDs within a single file. */
export declare function migrateFile(sourceCode: string, mapping: MigrationMapping): string;
+151
View File
@@ -0,0 +1,151 @@
/// <amd-module name="@angular/localize/tools/src/source_file_utils" />
/**
* @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
*/
import { PathManipulation } from '@angular/compiler-cli/private/localize';
import { ɵParsedTranslation, ɵSourceLocation } from '@angular/localize';
import { NodePath } from '@babel/traverse';
import { types as t } from './babel_core';
import { DiagnosticHandlingStrategy, Diagnostics } from './diagnostics';
/**
* Is the given `expression` the global `$localize` identifier?
*
* @param expression The expression to check.
* @param localizeName The configured name of `$localize`.
*/
export declare function isLocalize(expression: NodePath, localizeName: string): expression is NodePath<t.Identifier>;
/**
* Is the given `expression` an identifier with the correct `name`?
*
* @param expression The expression to check.
* @param name The name of the identifier we are looking for.
*/
export declare function isNamedIdentifier(expression: NodePath, name: string): expression is NodePath<t.Identifier>;
/**
* Is the given `identifier` declared globally.
*
* @param identifier The identifier to check.
* @publicApi used by CLI
*/
export declare function isGlobalIdentifier(identifier: NodePath<t.Identifier>): boolean;
/**
* Build a translated expression to replace the call to `$localize`.
* @param messageParts The static parts of the message.
* @param substitutions The expressions to substitute into the message.
* @publicApi used by CLI
*/
export declare function buildLocalizeReplacement(messageParts: TemplateStringsArray, substitutions: readonly t.Expression[]): t.Expression;
/**
* Extract the message parts from the given `call` (to `$localize`).
*
* The message parts will either by the first argument to the `call` or it will be wrapped in call
* to a helper function like `__makeTemplateObject`.
*
* @param call The AST node of the call to process.
* @param fs The file system to use when computing source-map paths. If not provided then it uses
* the "current" FileSystem.
* @publicApi used by CLI
*/
export declare function unwrapMessagePartsFromLocalizeCall(call: NodePath<t.CallExpression>, fs?: PathManipulation): [TemplateStringsArray, (ɵSourceLocation | undefined)[]];
/**
* Parse the localize call expression to extract the arguments that hold the substitution
* expressions.
*
* @param call The AST node of the call to process.
* @param fs The file system to use when computing source-map paths. If not provided then it uses
* the "current" FileSystem.
* @publicApi used by CLI
*/
export declare function unwrapSubstitutionsFromLocalizeCall(call: NodePath<t.CallExpression>, fs?: PathManipulation): [t.Expression[], (ɵSourceLocation | undefined)[]];
/**
* Parse the tagged template literal to extract the message parts.
*
* @param elements The elements of the template literal to process.
* @param fs The file system to use when computing source-map paths. If not provided then it uses
* the "current" FileSystem.
* @publicApi used by CLI
*/
export declare function unwrapMessagePartsFromTemplateLiteral(elements: NodePath<t.TemplateElement>[], fs?: PathManipulation): [
TemplateStringsArray,
(ɵSourceLocation | undefined)[]
];
/**
* Parse the tagged template literal to extract the interpolation expressions.
*
* @param quasi The AST node of the template literal to process.
* @param fs The file system to use when computing source-map paths. If not provided then it uses
* the "current" FileSystem.
* @publicApi used by CLI
*/
export declare function unwrapExpressionsFromTemplateLiteral(quasi: NodePath<t.TemplateLiteral>, fs?: PathManipulation): [t.Expression[], (ɵSourceLocation | undefined)[]];
/**
* Wrap the given `expression` in parentheses if it is a binary expression.
*
* This ensures that this expression is evaluated correctly if it is embedded in another expression.
*
* @param expression The expression to potentially wrap.
*/
export declare function wrapInParensIfNecessary(expression: t.Expression): t.Expression;
/**
* Extract the string values from an `array` of string literals.
*
* @param array The array to unwrap.
* @param fs The file system to use when computing source-map paths. If not provided then it uses
* the "current" FileSystem.
*/
export declare function unwrapStringLiteralArray(array: NodePath<t.Expression>, fs?: PathManipulation): [string[], (ɵSourceLocation | undefined)[]];
/**
* This expression is believed to be a call to a "lazy-load" template object helper function.
* This is expected to be of the form:
*
* ```ts
* function _templateObject() {
* var e = _taggedTemplateLiteral(['cooked string', 'raw string']);
* return _templateObject = function() { return e }, e
* }
* ```
*
* We unwrap this to return the call to `_taggedTemplateLiteral()`.
*
* @param call the call expression to unwrap
* @returns the call expression
*/
export declare function unwrapLazyLoadHelperCall(call: NodePath<t.CallExpression>): NodePath<t.CallExpression>;
/**
* Is the given `node` an array of literal strings?
*
* @param node The node to test.
*/
export declare function isStringLiteralArray(node: t.Node): node is t.Expression & {
elements: t.StringLiteral[];
};
/**
* Are all the given `nodes` expressions?
* @param nodes The nodes to test.
*/
export declare function isArrayOfExpressions(paths: NodePath<t.Node>[]): paths is NodePath<t.Expression>[];
/** Options that affect how the `makeEsXXXTranslatePlugin()` functions work. */
export interface TranslatePluginOptions {
missingTranslation?: DiagnosticHandlingStrategy;
localizeName?: string;
}
/**
* Translate the text of the given message, using the given translations.
*
* Logs as warning if the translation is not available
* @publicApi used by CLI
*/
export declare function translate(diagnostics: Diagnostics, translations: Record<string, ɵParsedTranslation>, messageParts: TemplateStringsArray, substitutions: readonly any[], missingTranslation: DiagnosticHandlingStrategy): [TemplateStringsArray, readonly any[]];
export declare class BabelParseError extends Error {
node: t.Node;
private readonly type;
constructor(node: t.Node, message: string);
}
export declare function isBabelParseError(e: any): e is BabelParseError;
export declare function buildCodeFrameError(fs: PathManipulation, path: NodePath, e: BabelParseError): string;
export declare function getLocation(fs: PathManipulation, startPath: NodePath, endPath?: NodePath): ɵSourceLocation | undefined;
export declare function serializeLocationPosition(location: ɵSourceLocation): string;
@@ -0,0 +1,22 @@
/// <amd-module name="@angular/localize/tools/src/translate/asset_files/asset_translation_handler" />
/**
* @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
*/
import { AbsoluteFsPath, FileSystem, PathSegment } from '@angular/compiler-cli/private/localize';
import { Diagnostics } from '../../diagnostics';
import { OutputPathFn } from '../output_path';
import { TranslationBundle, TranslationHandler } from '../translator';
/**
* Translate an asset file by simply copying it to the appropriate translation output paths.
*/
export declare class AssetTranslationHandler implements TranslationHandler {
private fs;
constructor(fs: FileSystem);
canTranslate(_relativeFilePath: PathSegment | AbsoluteFsPath, _contents: Uint8Array): boolean;
translate(diagnostics: Diagnostics, _sourceRoot: AbsoluteFsPath, relativeFilePath: PathSegment | AbsoluteFsPath, contents: Uint8Array, outputPathFn: OutputPathFn, translations: TranslationBundle[], sourceLocale?: string): void;
private writeAssetFile;
}
+3
View File
@@ -0,0 +1,3 @@
#!/usr/bin/env node
/// <amd-module name="@angular/localize/tools/src/translate/cli" />
export {};
+67
View File
@@ -0,0 +1,67 @@
/// <amd-module name="@angular/localize/tools/src/translate/index" />
import { DiagnosticHandlingStrategy, Diagnostics } from '../diagnostics';
import { OutputPathFn } from './output_path';
export interface TranslateFilesOptions {
/**
* The root path of the files to translate, either absolute or relative to the current working
* directory. E.g. `dist/en`
*/
sourceRootPath: string;
/**
* The files to translate, relative to the `root` path.
*/
sourceFilePaths: string[];
/**
* An array of paths to the translation files to load, either absolute or relative to the current
* working directory.
*
* For each locale to be translated, there should be an element in `translationFilePaths`.
* Each element is either an absolute path to the translation file, or an array of absolute paths
* to translation files, for that locale.
*
* If the element contains more than one translation file, then the translations are merged.
*
* If allowed by the `duplicateTranslation` property, when more than one translation has the same
* message id, the message from the earlier translation file in the array is used.
*
* For example, if the files are `[app.xlf, lib-1.xlf, lib-2.xlif]` then a message that appears in
* `app.xlf` will override the same message in `lib-1.xlf` or `lib-2.xlf`.
*/
translationFilePaths: (string | string[])[];
/**
* A collection of the target locales for the translation files.
*
* If there is a locale provided in `translationFileLocales` then this is used rather than a
* locale extracted from the file itself.
* If there is neither a provided locale nor a locale parsed from the file, then an error is
* thrown.
* If there are both a provided locale and a locale parsed from the file, and they are not the
* same, then a warning is reported.
*/
translationFileLocales: (string | undefined)[];
/**
* A function that computes the output path of where the translated files will be
* written. The marker `{{LOCALE}}` will be replaced with the target locale. E.g.
* `dist/{{LOCALE}}`.
*/
outputPathFn: OutputPathFn;
/**
* An object that will receive any diagnostics messages due to the processing.
*/
diagnostics: Diagnostics;
/**
* How to handle missing translations.
*/
missingTranslation: DiagnosticHandlingStrategy;
/**
* How to handle duplicate translations.
*/
duplicateTranslation: DiagnosticHandlingStrategy;
/**
* The locale of the source files.
* If this is provided then a copy of the application will be created with no translation but just
* the `$localize` calls stripped out.
*/
sourceLocale?: string;
}
export declare function translateFiles({ sourceRootPath, sourceFilePaths, translationFilePaths, translationFileLocales, outputPathFn, diagnostics, missingTranslation, duplicateTranslation, sourceLocale }: TranslateFilesOptions): void;
+24
View File
@@ -0,0 +1,24 @@
/// <amd-module name="@angular/localize/tools/src/translate/output_path" />
/**
* @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
*/
import { AbsoluteFsPath, PathManipulation } from '@angular/compiler-cli/private/localize';
/**
* A function that will return an absolute path to where a file is to be written, given a locale and
* a relative path.
*/
export interface OutputPathFn {
(locale: string, relativePath: string): string;
}
/**
* Create a function that will compute the absolute path to where a translated file should be
* written.
*
* The special `{{LOCALE}}` marker will be replaced with the locale code of the current translation.
* @param outputFolder An absolute path to the folder containing this set of translations.
*/
export declare function getOutputPathFn(fs: PathManipulation, outputFolder: AbsoluteFsPath): OutputPathFn;
@@ -0,0 +1,20 @@
/// <amd-module name="@angular/localize/tools/src/translate/source_files/es2015_translate_plugin" />
/**
* @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
*/
import { PathManipulation } from '@angular/compiler-cli/private/localize';
import { ɵParsedTranslation } from '@angular/localize';
import { PluginObj } from '../../babel_core';
import { Diagnostics } from '../../diagnostics';
import { TranslatePluginOptions } from '../../source_file_utils';
/**
* Create a Babel plugin that can be used to do compile-time translation of `$localize` tagged
* messages.
*
* @publicApi used by CLI
*/
export declare function makeEs2015TranslatePlugin(diagnostics: Diagnostics, translations: Record<string, ɵParsedTranslation>, { missingTranslation, localizeName }?: TranslatePluginOptions, fs?: PathManipulation): PluginObj;
@@ -0,0 +1,20 @@
/// <amd-module name="@angular/localize/tools/src/translate/source_files/es5_translate_plugin" />
/**
* @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
*/
import { PathManipulation } from '@angular/compiler-cli/private/localize';
import { ɵParsedTranslation } from '@angular/localize';
import { PluginObj } from '../../babel_core';
import { Diagnostics } from '../../diagnostics';
import { TranslatePluginOptions } from '../../source_file_utils';
/**
* Create a Babel plugin that can be used to do compile-time translation of `$localize` tagged
* messages.
*
* @publicApi used by CLI
*/
export declare function makeEs5TranslatePlugin(diagnostics: Diagnostics, translations: Record<string, ɵParsedTranslation>, { missingTranslation, localizeName }?: TranslatePluginOptions, fs?: PathManipulation): PluginObj;
@@ -0,0 +1,24 @@
/// <amd-module name="@angular/localize/tools/src/translate/source_files/locale_plugin" />
/**
* @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
*/
import { PluginObj } from '../../babel_core';
import { TranslatePluginOptions } from '../../source_file_utils';
/**
* This Babel plugin will replace the following code forms with a string literal containing the
* given `locale`.
*
* * `$localize.locale` -> `"locale"`
* * `typeof $localize !== "undefined" && $localize.locale` -> `"locale"`
* * `xxx && typeof $localize !== "undefined" && $localize.locale` -> `"xxx && locale"`
* * `$localize.locale || default` -> `"locale" || default`
*
* @param locale The name of the locale to inline into the code.
* @param options Additional options including the name of the `$localize` function.
* @publicApi used by CLI
*/
export declare function makeLocalePlugin(locale: string, { localizeName }?: TranslatePluginOptions): PluginObj;
@@ -0,0 +1,27 @@
/// <amd-module name="@angular/localize/tools/src/translate/source_files/source_file_translation_handler" />
/**
* @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
*/
import { AbsoluteFsPath, FileSystem, PathSegment } from '@angular/compiler-cli/private/localize';
import { Diagnostics } from '../../diagnostics';
import { TranslatePluginOptions } from '../../source_file_utils';
import { OutputPathFn } from '../output_path';
import { TranslationBundle, TranslationHandler } from '../translator';
/**
* Translate a file by inlining all messages tagged by `$localize` with the appropriate translated
* message.
*/
export declare class SourceFileTranslationHandler implements TranslationHandler {
private fs;
private translationOptions;
private sourceLocaleOptions;
constructor(fs: FileSystem, translationOptions?: TranslatePluginOptions);
canTranslate(relativeFilePath: PathSegment | AbsoluteFsPath, _contents: Uint8Array): boolean;
translate(diagnostics: Diagnostics, sourceRoot: AbsoluteFsPath, relativeFilePath: PathSegment, contents: Uint8Array, outputPathFn: OutputPathFn, translations: TranslationBundle[], sourceLocale?: string): void;
private translateFile;
private writeSourceFile;
}
@@ -0,0 +1,22 @@
/// <amd-module name="@angular/localize/tools/src/translate/translation_files/base_visitor" />
/**
* @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
*/
import { Attribute, Comment, Element, Expansion, ExpansionCase, Text, Visitor } from '@angular/compiler';
/**
* A simple base class for the `Visitor` interface, which is a noop for every method.
*
* Sub-classes only need to override the methods that they care about.
*/
export declare class BaseVisitor implements Visitor {
visitElement(_element: Element, _context: any): any;
visitAttribute(_attribute: Attribute, _context: any): any;
visitText(_text: Text, _context: any): any;
visitComment(_comment: Comment, _context: any): any;
visitExpansion(_expansion: Expansion, _context: any): any;
visitExpansionCase(_expansionCase: ExpansionCase, _context: any): any;
}
@@ -0,0 +1,21 @@
/**
* @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
*/
/// <amd-module name="@angular/localize/tools/src/translate/translation_files/message_serialization/message_renderer" />
export interface MessageRenderer<T> {
message: T;
startRender(): void;
endRender(): void;
text(text: string): void;
placeholder(name: string, body: string | undefined): void;
startPlaceholder(name: string): void;
closePlaceholder(name: string): void;
startContainer(): void;
closeContainer(): void;
startIcu(): void;
endIcu(): void;
}
@@ -0,0 +1,43 @@
/// <amd-module name="@angular/localize/tools/src/translate/translation_files/message_serialization/message_serializer" />
/**
* @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
*/
import { Element, Expansion, ExpansionCase, Node, Text } from '@angular/compiler';
import { BaseVisitor } from '../base_visitor';
import { MessageRenderer } from './message_renderer';
export interface MessageSerializerConfig {
inlineElements: string[];
placeholder?: {
elementName: string;
nameAttribute: string;
bodyAttribute?: string;
};
placeholderContainer?: {
elementName: string;
startAttribute: string;
endAttribute: string;
};
}
/**
* This visitor will walk over a set of XML nodes, which represent an i18n message, and serialize
* them into a message object of type `T`.
* The type of the serialized message is controlled by the
*/
export declare class MessageSerializer<T> extends BaseVisitor {
private renderer;
private config;
constructor(renderer: MessageRenderer<T>, config: MessageSerializerConfig);
serialize(nodes: Node[]): T;
visitElement(element: Element): void;
visitText(text: Text): void;
visitExpansion(expansion: Expansion): void;
visitExpansionCase(expansionCase: ExpansionCase): void;
visitContainedNodes(nodes: Node[]): void;
visitPlaceholder(name: string, body: string | undefined): void;
visitPlaceholderContainer(startName: string, children: Node[], closeName: string): void;
private isPlaceholderContainer;
}
@@ -0,0 +1,31 @@
/// <amd-module name="@angular/localize/tools/src/translate/translation_files/message_serialization/target_message_renderer" />
/**
* @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
*/
import { ɵParsedTranslation } from '@angular/localize';
import { MessageRenderer } from './message_renderer';
/**
* A message renderer that outputs `ɵParsedTranslation` objects.
*/
export declare class TargetMessageRenderer implements MessageRenderer<ɵParsedTranslation> {
private current;
private icuDepth;
get message(): ɵParsedTranslation;
startRender(): void;
endRender(): void;
text(text: string): void;
placeholder(name: string, body: string | undefined): void;
startPlaceholder(name: string): void;
closePlaceholder(name: string): void;
startContainer(): void;
closeContainer(): void;
startIcu(): void;
endIcu(): void;
private normalizePlaceholderName;
private renderPlaceholder;
private storeMessagePart;
}
@@ -0,0 +1,55 @@
/// <amd-module name="@angular/localize/tools/src/translate/translation_files/translation_loader" />
/**
* @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
*/
import { AbsoluteFsPath, ReadonlyFileSystem } from '@angular/compiler-cli/private/localize';
import { DiagnosticHandlingStrategy, Diagnostics } from '../../diagnostics';
import { TranslationBundle } from '../translator';
import { TranslationParser } from './translation_parsers/translation_parser';
/**
* Use this class to load a collection of translation files from disk.
*/
export declare class TranslationLoader {
private fs;
private translationParsers;
private duplicateTranslation;
/** @deprecated */ private diagnostics?;
constructor(fs: ReadonlyFileSystem, translationParsers: TranslationParser<any>[], duplicateTranslation: DiagnosticHandlingStrategy,
/** @deprecated */ diagnostics?: Diagnostics | undefined);
/**
* Load and parse the translation files into a collection of `TranslationBundles`.
*
* @param translationFilePaths An array, per locale, of absolute paths to translation files.
*
* For each locale to be translated, there is an element in `translationFilePaths`. Each element
* is an array of absolute paths to translation files for that locale.
* If the array contains more than one translation file, then the translations are merged.
* If allowed by the `duplicateTranslation` property, when more than one translation has the same
* message id, the message from the earlier translation file in the array is used.
* For example, if the files are `[app.xlf, lib-1.xlf, lib-2.xlif]` then a message that appears in
* `app.xlf` will override the same message in `lib-1.xlf` or `lib-2.xlf`.
*
* @param translationFileLocales An array of locales for each of the translation files.
*
* If there is a locale provided in `translationFileLocales` then this is used rather than a
* locale extracted from the file itself.
* If there is neither a provided locale nor a locale parsed from the file, then an error is
* thrown.
* If there are both a provided locale and a locale parsed from the file, and they are not the
* same, then a warning is reported.
*/
loadBundles(translationFilePaths: AbsoluteFsPath[][], translationFileLocales: (string | undefined)[]): TranslationBundle[];
/**
* Load all the translations from the file at the given `filePath`.
*/
private loadBundle;
/**
* There is more than one `filePath` for this locale, so load each as a bundle and then merge
* them all together.
*/
private mergeBundles;
}
@@ -0,0 +1,59 @@
/// <amd-module name="@angular/localize/tools/src/translate/translation_files/translation_parsers/arb_translation_parser" />
/**
* @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
*/
import { MessageId, ɵSourceMessage } from '@angular/localize';
import { ParseAnalysis, ParsedTranslationBundle, TranslationParser } from './translation_parser';
export interface ArbJsonObject extends Record<MessageId, ɵSourceMessage | ArbMetadata> {
'@@locale': string;
}
export interface ArbMetadata {
type?: 'text' | 'image' | 'css';
description?: string;
['x-locations']?: ArbLocation[];
}
export interface ArbLocation {
start: {
line: number;
column: number;
};
end: {
line: number;
column: number;
};
file: string;
}
/**
* A translation parser that can parse JSON formatted as an Application Resource Bundle (ARB).
*
* See https://github.com/google/app-resource-bundle/wiki/ApplicationResourceBundleSpecification
*
* ```
* {
* "@@locale": "en-US",
* "message-id": "Target message string",
* "@message-id": {
* "type": "text",
* "description": "Some description text",
* "x-locations": [
* {
* "start": {"line": 23, "column": 145},
* "end": {"line": 24, "column": 53},
* "file": "some/file.ts"
* },
* ...
* ]
* },
* ...
* }
* ```
*/
export declare class ArbTranslationParser implements TranslationParser<ArbJsonObject> {
analyze(_filePath: string, contents: string): ParseAnalysis<ArbJsonObject>;
parse(_filePath: string, contents: string, arb?: ArbJsonObject): ParsedTranslationBundle;
private tryParseArbFormat;
}
@@ -0,0 +1,19 @@
/// <amd-module name="@angular/localize/tools/src/translate/translation_files/translation_parsers/serialize_translation_message" />
/**
* @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
*/
import { Element, ParseError } from '@angular/compiler';
import { ɵParsedTranslation } from '@angular/localize';
import { MessageSerializerConfig } from '../message_serialization/message_serializer';
/**
* Serialize the given `element` into a parsed translation using the given `serializer`.
*/
export declare function serializeTranslationMessage(element: Element, config: MessageSerializerConfig): {
translation: ɵParsedTranslation | null;
parseErrors: ParseError[];
serializeErrors: ParseError[];
};
@@ -0,0 +1,29 @@
/// <amd-module name="@angular/localize/tools/src/translate/translation_files/translation_parsers/simple_json_translation_parser" />
import { ParseAnalysis, ParsedTranslationBundle, TranslationParser } from './translation_parser';
interface SimpleJsonFile {
locale: string;
translations: {
[messageId: string]: string;
};
}
/**
* A translation parser that can parse JSON that has the form:
*
* ```
* {
* "locale": "...",
* "translations": {
* "message-id": "Target message string",
* ...
* }
* }
* ```
*
* @see SimpleJsonTranslationSerializer
* @publicApi used by CLI
*/
export declare class SimpleJsonTranslationParser implements TranslationParser<SimpleJsonFile> {
analyze(filePath: string, contents: string): ParseAnalysis<SimpleJsonFile>;
parse(_filePath: string, contents: string, json?: SimpleJsonFile): ParsedTranslationBundle;
}
export {};
@@ -0,0 +1,18 @@
/// <amd-module name="@angular/localize/tools/src/translate/translation_files/translation_parsers/translation_parse_error" />
/**
* @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
*/
import { ParseErrorLevel, ParseSourceSpan } from '@angular/compiler';
/**
* This error is thrown when there is a problem parsing a translation file.
*/
export declare class TranslationParseError extends Error {
span: ParseSourceSpan;
msg: string;
level: ParseErrorLevel;
constructor(span: ParseSourceSpan, msg: string, level?: ParseErrorLevel);
}
@@ -0,0 +1,80 @@
/// <amd-module name="@angular/localize/tools/src/translate/translation_files/translation_parsers/translation_parser" />
/**
* @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
*/
import { MessageId, ɵParsedTranslation } from '@angular/localize';
import { Diagnostics } from '../../../diagnostics';
/**
* Indicates that a parser can parse a given file, with a hint that can be used to speed up actual
* parsing.
*/
export interface CanParseAnalysis<Hint> {
canParse: true;
diagnostics: Diagnostics;
hint: Hint;
}
/**
* Indicates that a parser cannot parse a given file with diagnostics as why this is.
* */
export interface CannotParseAnalysis {
canParse: false;
diagnostics: Diagnostics;
}
/**
* Information about whether a `TranslationParser` can parse a given file.
*/
export declare type ParseAnalysis<Hint> = CanParseAnalysis<Hint> | CannotParseAnalysis;
/**
* An object that holds translations that have been parsed from a translation file.
*/
export interface ParsedTranslationBundle {
locale: string | undefined;
translations: Record<MessageId, ɵParsedTranslation>;
diagnostics: Diagnostics;
}
/**
* Implement this interface to provide a class that can parse the contents of a translation file.
*
* The `analyze()` method can return a hint that can be used by the `parse()` method to speed
* up parsing. This allows the parser to do significant work to determine if the file can be parsed
* without duplicating the work when it comes to actually parsing the file.
*
* Example usage:
*
* ```
* const parser: TranslationParser = getParser();
* const analysis = parser.analyze(filePath, content);
* if (analysis.canParse) {
* return parser.parse(filePath, content, analysis.hint);
* }
* ```
*/
export interface TranslationParser<Hint = true> {
/**
* Analyze the file to see if this parser can parse the given file.
*
* @param filePath The absolute path to the translation file.
* @param contents The contents of the translation file.
* @returns Information indicating whether the file can be parsed by this parser.
*/
analyze(filePath: string, contents: string): ParseAnalysis<Hint>;
/**
* Parses the given file, extracting the target locale and translations.
*
* Note that this method should not throw an error. Check the `bundle.diagnostics` property for
* potential parsing errors and warnings.
*
* @param filePath The absolute path to the translation file.
* @param contents The contents of the translation file.
* @param hint A value that can be used by the parser to speed up parsing of the file. This will
* have been provided as the return result from calling `analyze()`.
* @returns The translation bundle parsed from the file.
* @throws No errors. If there was a problem with parsing the bundle will contain errors
* in the `diagnostics` property.
*/
parse(filePath: string, contents: string, hint: Hint): ParsedTranslationBundle;
}
@@ -0,0 +1,65 @@
/// <amd-module name="@angular/localize/tools/src/translate/translation_files/translation_parsers/translation_utils" />
/**
* @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
*/
import { Element, Node, ParseError, ParseErrorLevel, ParseSourceSpan, ParseTreeResult } from '@angular/compiler';
import { Diagnostics } from '../../../diagnostics';
import { ParseAnalysis, ParsedTranslationBundle } from './translation_parser';
export declare function getAttrOrThrow(element: Element, attrName: string): string;
export declare function getAttribute(element: Element, attrName: string): string | undefined;
/**
* Parse the "contents" of an XML element.
*
* This would be equivalent to parsing the `innerHTML` string of an HTML document.
*
* @param element The element whose inner range we want to parse.
* @returns a collection of XML `Node` objects and any errors that were parsed from the element's
* contents.
*/
export declare function parseInnerRange(element: Element): ParseTreeResult;
/**
* This "hint" object is used to pass information from `analyze()` to `parse()` for
* `TranslationParser`s that expect XML contents.
*
* This saves the `parse()` method from having to re-parse the XML.
*/
export interface XmlTranslationParserHint {
element: Element;
errors: ParseError[];
}
/**
* Can this XML be parsed for translations, given the expected `rootNodeName` and expected root node
* `attributes` that should appear in the file.
*
* @param filePath The path to the file being checked.
* @param contents The contents of the file being checked.
* @param rootNodeName The expected name of an XML root node that should exist.
* @param attributes The attributes (and their values) that should appear on the root node.
* @returns The `XmlTranslationParserHint` object for use by `TranslationParser.parse()` if the XML
* document has the expected format.
*/
export declare function canParseXml(filePath: string, contents: string, rootNodeName: string, attributes: Record<string, string>): ParseAnalysis<XmlTranslationParserHint>;
/**
* Create a predicate, which can be used by things like `Array.filter()`, that will match a named
* XML Element from a collection of XML Nodes.
*
* @param name The expected name of the element to match.
*/
export declare function isNamedElement(name: string): (node: Node) => node is Element;
/**
* Add an XML parser related message to the given `diagnostics` object.
*/
export declare function addParseDiagnostic(diagnostics: Diagnostics, sourceSpan: ParseSourceSpan, message: string, level: ParseErrorLevel): void;
/**
* Copy the formatted error message from the given `parseError` object into the given `diagnostics`
* object.
*/
export declare function addParseError(diagnostics: Diagnostics, parseError: ParseError): void;
/**
* Add the provided `errors` to the `bundle` diagnostics.
*/
export declare function addErrorsToBundle(bundle: ParsedTranslationBundle, errors: ParseError[]): void;
@@ -0,0 +1,17 @@
/// <amd-module name="@angular/localize/tools/src/translate/translation_files/translation_parsers/xliff1_translation_parser" />
import { ParseAnalysis, ParsedTranslationBundle, TranslationParser } from './translation_parser';
import { XmlTranslationParserHint } from './translation_utils';
/**
* A translation parser that can load XLIFF 1.2 files.
*
* https://docs.oasis-open.org/xliff/v1.2/os/xliff-core.html
* https://docs.oasis-open.org/xliff/v1.2/xliff-profile-html/xliff-profile-html-1.2.html
*
* @see Xliff1TranslationSerializer
* @publicApi used by CLI
*/
export declare class Xliff1TranslationParser implements TranslationParser<XmlTranslationParserHint> {
analyze(filePath: string, contents: string): ParseAnalysis<XmlTranslationParserHint>;
parse(filePath: string, contents: string, hint: XmlTranslationParserHint): ParsedTranslationBundle;
private extractBundle;
}

Some files were not shown because too many files have changed in this diff Show More