@rr0/cms 0.3.76 → 0.3.78

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -29,7 +29,12 @@ export declare class RR0ContextImpl extends SsgContextImpl {
29
29
  readonly images: Set<string>;
30
30
  protected readonly fileMap: Map<string, FileContents>;
31
31
  place: PlaceContext;
32
+ /**
33
+ * The language of a passage that differs from its page's (<blockquote lang="en"> in a French page).
34
+ */
35
+ protected localeOverride?: string;
32
36
  constructor(locale: string, time: TimeContext, config: FileWriteConfig, people?: any, currentFile?: FileContents | undefined, _messages?: RR0Messages, cms?: CMSContext);
37
+ get locale(): string;
33
38
  get messages(): RR0Messages;
34
39
  read(filePath: string): FileContents;
35
40
  clone(locale?: string): RR0ContextImpl;
@@ -13,6 +13,10 @@ export class RR0ContextImpl extends SsgContextImpl {
13
13
  this.fileMap = new Map();
14
14
  this.place = new PlaceContext(locale, this.messages.context.place);
15
15
  }
16
+ get locale() {
17
+ var _a;
18
+ return (_a = this.localeOverride) !== null && _a !== void 0 ? _a : super.locale;
19
+ }
16
20
  get messages() {
17
21
  let messages = this._messages;
18
22
  if (!messages) {
@@ -43,7 +47,10 @@ export class RR0ContextImpl extends SsgContextImpl {
43
47
  }
44
48
  clone(locale = this.locale) {
45
49
  var _a;
46
- return new RR0ContextImpl(locale, this.time.clone(), this.config, (_a = this.people) === null || _a === void 0 ? void 0 : _a.clone(), this._file, this.messages, this.cms);
50
+ const sameLocale = locale === this.locale;
51
+ const clone = new RR0ContextImpl(locale, this.time.clone(), this.config, (_a = this.people) === null || _a === void 0 ? void 0 : _a.clone(), this._file, sameLocale ? this._messages : undefined, this.cms);
52
+ clone.localeOverride = sameLocale ? this.localeOverride : locale;
53
+ return clone;
47
54
  }
48
55
  toString() {
49
56
  var _a;
@@ -30,7 +30,9 @@ export class LanguageReplaceCommand extends DomReplaceCommand {
30
30
  }
31
31
  }
32
32
  else {
33
- pageLang = "fr";
33
+ // A file without variant is French, unless it declares otherwise (an English document not translated yet)
34
+ const declared = inputFile.document.querySelector("meta[http-equiv='content-language' i]");
35
+ pageLang = (declared === null || declared === void 0 ? void 0 : declared.content.trim().substring(0, 2).toLowerCase()) || "fr";
34
36
  }
35
37
  inputFile.document.documentElement.lang = inputFile.lang.lang = pageLang;
36
38
  const langVariants = variants.length == 1 && variants[0] == "" ? [pageLang == "fr" ? "en" : "fr"] : variants;
@@ -8,6 +8,12 @@ describe("LanguageReplaceCommand", () => {
8
8
  await command.execute(context);
9
9
  expect(context.file.contents).toBe(`<html lang="fr"><head><meta name="generator" content="ssg-api"></head><body><span id="alternate"><a href="/${cmsTestUtil.filePath(cmsTestUtil.time.filePath("1/9/6/8/CondonReport/index.html"))}">English version</a></span></body></html>`);
10
10
  });
11
+ test("declared language of a file without variant", async () => {
12
+ const context = cmsTestUtil.time.newHtmlContext("1/9/9/0/08/index.html", `<meta http-equiv="content-language" content="en"><span id="alternate"/>`);
13
+ await new LanguageReplaceCommand().execute(context);
14
+ expect(context.file.lang.lang).toBe("en");
15
+ expect(context.file.document.documentElement.lang).toBe("en");
16
+ });
11
17
  test("add english translation", async () => {
12
18
  const context = cmsTestUtil.time.newHtmlContext("0/6/4/0/ChronicaMinor/index_fr.html", `<span id="alternate"/>`);
13
19
  const command = new LanguageReplaceCommand();
@@ -53,12 +53,13 @@ export class TimeElementFactory {
53
53
  return replacement;
54
54
  }
55
55
  createStarting(fromContext, previousContext, options) {
56
+ options = { ...options, relativeWords: false }; // Not "à partir de l'année suivante"
56
57
  const { result, replacement } = this.renderer.renderContent(fromContext, previousContext, options);
57
58
  let startingReplacement;
58
59
  startingReplacement = fromContext.file.document.createElement("span");
59
60
  startingReplacement.className = "time-interval";
60
61
  const approximate = !fromContext.time.getDayOfMonth();
61
- startingReplacement.innerHTML = fromContext.messages.context.time.starting(approximate) + " " + result.outerHTML;
62
+ startingReplacement.textContent = fromContext.messages.context.time.starting(approximate);
62
63
  result.append(startingReplacement, replacement);
63
64
  return result;
64
65
  }
@@ -20,7 +20,11 @@ export declare class TimeReplacer implements DomReplacement<HtmlRR0Context, HTML
20
20
  * @return The text that precedes an element in its sentence.
21
21
  */
22
22
  static precedingText(el: Element): string;
23
- replacement(context: HtmlRR0Context, origEl: HTMLTimeElement): Promise<HTMLElement>;
23
+ /**
24
+ * @return The language of the passage holding an element, if it differs from its page's.
25
+ */
26
+ static passageLang(context: HtmlRR0Context, el: Element): string | undefined;
27
+ replacement(pageContext: HtmlRR0Context, origEl: HTMLTimeElement): Promise<HTMLElement>;
24
28
  /**
25
29
  * Renders a range of durations ("P10M/12M") as "from 10 to 12 minutes".
26
30
  */
@@ -24,12 +24,23 @@ export class TimeReplacer {
24
24
  }
25
25
  return (_b = (_a = node.previousSibling) === null || _a === void 0 ? void 0 : _a.textContent) !== null && _b !== void 0 ? _b : "";
26
26
  }
27
- async replacement(context, origEl) {
27
+ /**
28
+ * @return The language of the passage holding an element, if it differs from its page's.
29
+ */
30
+ static passageLang(context, el) {
31
+ var _a, _b;
32
+ const lang = (_b = (_a = el.closest("[lang]")) === null || _a === void 0 ? void 0 : _a.getAttribute("lang")) === null || _b === void 0 ? void 0 : _b.trim().substring(0, 2).toLowerCase();
33
+ return lang && lang !== context.locale.substring(0, 2) ? lang : undefined;
34
+ }
35
+ async replacement(pageContext, origEl) {
28
36
  let replacement;
29
37
  if (origEl.dateTime || origEl.dataset.format === "none") { // Already done, or not to be interpreted
30
38
  replacement = origEl;
31
39
  }
32
40
  else {
41
+ // A time in a passage of another language ("<blockquote lang='en'>") is rendered in that language
42
+ const passageLang = TimeReplacer.passageLang(pageContext, origEl);
43
+ const context = passageLang ? pageContext.clone(passageLang) : pageContext;
33
44
  const previousContext = origEl.dataset.context === "none" ? undefined : context.clone();
34
45
  const timeStr = origEl.textContent;
35
46
  const { prefix, value, suffix } = this.completer.split(timeStr);
@@ -72,6 +83,9 @@ export class TimeReplacer {
72
83
  wrapper.append(prefix, replacement, suffix);
73
84
  replacement = wrapper;
74
85
  }
86
+ if (context !== pageContext) {
87
+ pageContext.time = context.time; // The next times of the page follow this one
88
+ }
75
89
  context.debug("\tReplacing time", origEl.outerHTML, "with", ObjectUtils.asSet(replacement).outerHTML);
76
90
  }
77
91
  return replacement;
@@ -236,6 +236,15 @@ describe("TimeReplacer", async () => {
236
236
  test("but not without one", async () => {
237
237
  expect(await renderAfter("fr", "<time>2005</time>. Puis, <time>2006</time>")).toBe("l'année suivante");
238
238
  });
239
+ test("in the language of its passage", async () => {
240
+ expect(await renderAfter("fr", "<time>2005</time>. <q lang=\"en\">in <time>2006</time></q>")).toBe("2006");
241
+ expect(await renderAfter("fr", "<time>2005</time>. <q lang=\"en\">Then <time>2006</time></q>")).toBe("the year after");
242
+ expect(await renderAfter("fr", "<q lang=\"en\"><time>2006</time></q>. <time>2007</time>")).toBe("l'année suivante");
243
+ });
244
+ test("including the one of an open interval", async () => {
245
+ expect(await renderAfter("fr", "<time>2005</time>. <time>2006/</time>")).toBe("à partir de 2006");
246
+ expect(await renderAfter("en", "<time>2005</time>. <time>2006/</time>")).toBe("starting 2006");
247
+ });
239
248
  });
240
249
  test("avoids linking to current file", async () => {
241
250
  const context = cmsTestUtil.time.newHtmlContext("1/9/9/0/08/index.html", "");
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "@rr0/cms",
3
3
  "type": "module",
4
4
  "author": "Jérôme Beau <rr0@rr0.org> (https://rr0.org)",
5
- "version": "0.3.76",
5
+ "version": "0.3.78",
6
6
  "description": "RR0 Content Management System (CMS)",
7
7
  "exports": "./dist/index.js",
8
8
  "types": "./dist/index.d.ts",