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
"); + }); });