All files / src/astro Trans.astro

100% Statements 18/18
100% Branches 10/10
100% Functions 2/2
100% Lines 16/16

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45                                    5x 5x 5x   5x 5x   5x 5x 5x 5x 5x 3x   2x       5x   5x 1x       15x  
---
interface Props {
  /**
   * Translation template. Placeholders use `{{name}}` and are filled by Astro slots with the same name.
   * When there is only one placeholder, the default slot can be used instead.
   *
   * @example
   * ```astro
   * <Trans message="a{{b}}c">
   *   <strong>B</strong>
   * </Trans>
   * ```
   */
  message: string;
}
 
type HtmlPart = { h: string };
 
const { message = "" } = Astro.props;
const slices: Array<string | HtmlPart> = [];
const matchArgs = /{{(\S+?)}}/gi;
let slice: RegExpExecArray | null;
let pointer = 0;
let defaultSlotIndex = 0;
 
while ((slice = matchArgs.exec(message))) {
  const key = slice[1];
  slices.push(message.slice(pointer, slice.index));
  pointer = matchArgs.lastIndex;
  if (Astro.slots.has(key)) {
    slices.push({ h: await Astro.slots.render(key) });
  } else {
    defaultSlotIndex = slices.push(`{{${key}}}`) - 1;
  }
}
 
slices.push(message.slice(pointer));
 
if (slices.length === 3 && defaultSlotIndex && Astro.slots.has("default")) {
  slices[defaultSlotIndex] = { h: await Astro.slots.render("default") };
}
---
 
{slices.map((part) => (typeof part === "string" ? part : <Fragment set:html={part.h} />))}