Skip to content

Commit de2a5fb

Browse files
committed
markup/asciidocext: Fix the outdir document attribute
Changes: - Unescape the outdir attribute to handle multibyte content paths - Retain the language prefix with multilingual sites Closes #9202 Closes #10473
1 parent b95f7d2 commit de2a5fb

File tree

2 files changed

+139
-1
lines changed

2 files changed

+139
-1
lines changed
Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,134 @@
1+
// Copyright 2025 The Hugo Authors. All rights reserved.
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
// http://www.apache.org/licenses/LICENSE-2.0
7+
//
8+
// Unless required by applicable law or agreed to in writing, software
9+
// distributed under the License is distributed on an "AS IS" BASIS,
10+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11+
// See the License for the specific language governing permissions and
12+
// limitations under the License.
13+
14+
// Package asciidocext converts AsciiDoc to HTML using Asciidoctor
15+
// external binary. The `asciidoc` module is reserved for a future golang
16+
// implementation.
17+
18+
package asciidocext_test
19+
20+
import (
21+
"fmt"
22+
"strings"
23+
"testing"
24+
25+
"github.com/gohugoio/hugo/hugolib"
26+
"github.com/gohugoio/hugo/markup/asciidocext"
27+
)
28+
29+
// Issue 9202
30+
func TestAsciidoctorMultibyteOutdir(t *testing.T) {
31+
if !asciidocext.Supports() {
32+
t.Skip("skip asciidoc")
33+
}
34+
35+
files := `
36+
-- hugo.toml --
37+
disableKinds = ['home','rss','section','sitemap','taxonomy','term']
38+
39+
[markup.asciidocext]
40+
workingFolderCurrent = true
41+
42+
[security.exec]
43+
allow = ['^asciidoctor$']
44+
-- content/p1.adoc --
45+
---
46+
title: p1
47+
---
48+
H~2~O
49+
-- content/hügo.adoc --
50+
---
51+
title: hügo
52+
---
53+
H~2~O
54+
-- layouts/all.html --
55+
{{ .Content }}
56+
`
57+
58+
b, err := hugolib.TestE(t, files, hugolib.TestOptInfo())
59+
if err != nil {
60+
fmt.Println(err.Error())
61+
}
62+
63+
wantContent := "<p>H<sub>2</sub>O</p>"
64+
65+
b.AssertFileContent("public/p1/index.html", wantContent)
66+
b.AssertFileContent("public/hügo/index.html", wantContent)
67+
b.AssertLogContains("/public/p1")
68+
b.AssertLogContains("/public/hügo")
69+
}
70+
71+
// Issue 10473
72+
func TestAsciidoctorMultilingualOutdir(t *testing.T) {
73+
if !asciidocext.Supports() {
74+
t.Skip("skip asciidoc")
75+
}
76+
77+
files := `
78+
-- hugo.toml --
79+
disableKinds = ['home','rss','section','sitemap','taxonomy','term']
80+
81+
defaultContentLanguage = 'en'
82+
defaultContentLanguageInSubdir = true
83+
84+
[languages.en]
85+
weight = 1
86+
BASEURL_EN
87+
88+
[languages.de]
89+
weight = 2
90+
BASEURL_DE
91+
92+
[markup.asciidocExt]
93+
workingFolderCurrent = true
94+
95+
[security.exec]
96+
allow = ['^asciidoctor$']
97+
-- content/p1.en.adoc --
98+
---
99+
title: p1 (en)
100+
---
101+
H~2~O
102+
-- content/p1.de.adoc --
103+
---
104+
title: p1 (de)
105+
---
106+
H~2~O
107+
-- layouts/all.html --
108+
{{ .Content }}
109+
`
110+
111+
wantContent := "<p>H<sub>2</sub>O</p>"
112+
113+
// multilingual single-host
114+
f := strings.ReplaceAll(files, "BASEURL_EN", "")
115+
f = strings.ReplaceAll(f, "BASEURL_DE", "")
116+
117+
b := hugolib.Test(t, f, hugolib.TestOptInfo())
118+
119+
b.AssertFileContent("public/en/p1/index.html", wantContent)
120+
b.AssertFileContent("public/de/p1/index.html", wantContent)
121+
b.AssertLogContains("/public/en/p1")
122+
b.AssertLogContains("/public/de/p1")
123+
124+
// multilingual multi-host
125+
f = strings.ReplaceAll(files, "BASEURL_EN", "baseURL = 'https://en.example.org/'")
126+
f = strings.ReplaceAll(f, "BASEURL_DE", "baseURL = 'https://de.example.org/'")
127+
128+
b = hugolib.Test(t, f, hugolib.TestOptInfo())
129+
130+
b.AssertFileContent("public/en/p1/index.html", wantContent)
131+
b.AssertFileContent("public/de/p1/index.html", wantContent)
132+
// b.AssertLogContains("/public/en/p1") // JMM fail: outdir contains /public/p1 (missing language prefix)
133+
// b.AssertLogContains("/public/de/p1") // JMM fail: outdir contains /public/p1 (missing language prefix)
134+
}

‎markup/asciidocext/internal/converter.go‎

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package internal
22

33
import (
44
"bytes"
5+
"net/url"
56
"path/filepath"
67
"strings"
78

@@ -110,7 +111,10 @@ func (a *AsciidocConverter) ParseArgs(ctx converter.DocumentContext) []string {
110111
postDir := ""
111112
page, ok := ctx.Document.(pageSubset)
112113
if ok {
113-
postDir = filepath.Base(page.RelPermalink())
114+
postDir, err = url.PathUnescape(page.RelPermalink())
115+
if err != nil {
116+
a.Cfg.Logger.Errorln("unable to unescape the relative permalink")
117+
}
114118
} else {
115119
a.Cfg.Logger.Errorln("unable to cast interface to pageSubset")
116120
}

0 commit comments

Comments
 (0)