641 lines
24 KiB
JavaScript
Executable File
641 lines
24 KiB
JavaScript
Executable File
/**
|
|
* @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
|