From 7ac81ed5fe629d2e212b04e7bd5ea17668e277a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A9ry=20Debongnie?= Date: Mon, 6 Mar 2023 12:00:25 +0100 Subject: [PATCH] [FIX] compiler: call translate function with correct string Before this commit, the parser would remove all consecutive white spaces for text nodes. After that, the code generator would call the translate function with the resulting string, which then is different than what we would expect. With this commit, we make sure we apply the translation before removing the additional whitespace. To do that, we have to move the code processing the string from the parser into the code generator, which actually makes sense, as the parser should only collect all useful information without applying too much logic. closes #1351 --- src/compiler/code_generator.ts | 6 ++++++ src/compiler/parser.ts | 8 ++------ .../compiler/__snapshots__/translation.test.ts.snap | 13 +++++++++++++ tests/compiler/parser.test.ts | 4 ++-- tests/compiler/translation.test.ts | 12 ++++++++++++ 5 files changed, 35 insertions(+), 8 deletions(-) diff --git a/src/compiler/code_generator.ts b/src/compiler/code_generator.ts index 76c37fca..a40b3a02 100644 --- a/src/compiler/code_generator.ts +++ b/src/compiler/code_generator.ts @@ -32,6 +32,7 @@ import { import { OwlError } from "../runtime/error_handling"; type BlockType = "block" | "text" | "multi" | "list" | "html" | "comment"; +const whitespaceRE = /\s+/g; export interface Config { translateFn?: (s: string) => string; @@ -166,6 +167,7 @@ interface Context { nameSpace?: string; tModelSelectedExpr?: string; ctxVar?: string; + inPreTag?: boolean; } function createContext(parentCtx: Context, params?: Partial): Context { @@ -534,6 +536,9 @@ export class CodeGenerator { const match = translationRE.exec(value) as any; value = match[1] + this.translateFn(match[2]) + match[3]; } + if (!ctx.inPreTag) { + value = value.replace(whitespaceRE, " "); + } if (!block || forceNewBlock) { block = this.createBlock(block, "text", ctx); @@ -746,6 +751,7 @@ export class CodeGenerator { tKeyExpr: ctx.tKeyExpr, nameSpace, tModelSelectedExpr, + inPreTag: ctx.inPreTag || ast.tag === "pre", }); this.compileAST(child, subCtx); } diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index 0bf572d9..42a89f13 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -261,16 +261,12 @@ function parseTNode(node: Element, ctx: ParsingContext): AST | null { // Text and Comment Nodes // ----------------------------------------------------------------------------- const lineBreakRE = /[\r\n]/; -const whitespaceRE = /\s+/g; function parseTextCommentNode(node: Node, ctx: ParsingContext): AST | null { if (node.nodeType === Node.TEXT_NODE) { let value = node.textContent || ""; - if (!ctx.inPreTag) { - if (lineBreakRE.test(value) && !value.trim()) { - return null; - } - value = value.replace(whitespaceRE, " "); + if (!ctx.inPreTag && lineBreakRE.test(value) && !value.trim()) { + return null; } return { type: ASTType.Text, value }; diff --git a/tests/compiler/__snapshots__/translation.test.ts.snap b/tests/compiler/__snapshots__/translation.test.ts.snap index 877a307b..f40bedda 100644 --- a/tests/compiler/__snapshots__/translation.test.ts.snap +++ b/tests/compiler/__snapshots__/translation.test.ts.snap @@ -64,3 +64,16 @@ exports[`translation support translation is done on the trimmed text, with extra } }" `; + +exports[`translation support translation works, even if initial string has inner consecutive white space 1`] = ` +"function anonymous(app, bdom, helpers +) { + let { text, createBlock, list, multi, html, toggler, comment } = bdom; + + let block1 = createBlock(\`
un mot
\`); + + return function template(ctx, node, key = \\"\\") { + return block1(); + } +}" +`; diff --git a/tests/compiler/parser.test.ts b/tests/compiler/parser.test.ts index 52178251..cdbbcace 100644 --- a/tests/compiler/parser.test.ts +++ b/tests/compiler/parser.test.ts @@ -26,10 +26,10 @@ describe("qweb parser", () => { }); }); - test("white spaces are condensed into a single space", async () => { + test("white spaces are maintained", async () => { expect(parse(" ")).toEqual({ type: ASTType.Text, - value: " ", + value: " ", }); }); diff --git a/tests/compiler/translation.test.ts b/tests/compiler/translation.test.ts index 676a8d23..71dc6ba6 100644 --- a/tests/compiler/translation.test.ts +++ b/tests/compiler/translation.test.ts @@ -88,4 +88,16 @@ describe("translation support", () => { expect(fixture.innerHTML).toBe("
mot
"); expect(translateFn).toHaveBeenCalledWith("word"); }); + + test("translation works, even if initial string has inner consecutive white space", async () => { + class SomeComponent extends Component { + static template = xml`
some word
`; + } + + const translateFn = jest.fn((expr: string) => (expr === "some word" ? "un mot" : expr)); + + await mount(SomeComponent, fixture, { translateFn }); + expect(translateFn).toHaveBeenCalledWith("some word"); + expect(fixture.innerHTML).toBe("
un mot
"); + }); });