Repository: gohugoio/hugo (language: go)

Issue:
tpl/tplimpl: Embedded render hooks fail to get page resource when destination has leading ./
The issue is comparable to #12163 but with languages in sub-dirs. Images with a relative URL in markdown of non-default languages are not copied to the destination subdir.

### What version of Hugo are you using (`hugo version`)?

<pre>
$ hugo version
hugo v0.126.1-3d40aba512931031921463dafc172c0d124437b8+extended linux/amd64 BuildDate=2024-05-15T10:42:34Z VendorInfo=gohugoio
</pre>

### Does this issue reproduce with the latest release?

Yes.  The issue is reproducible with Hugo >= v0.123.0 up until the current v0.126.1 release. It works with Hugo v0.122.0.


### How to reproduce

#### 1. Fresh test site

Created as follows:

```
$ hugo new site issue
$ cd issue
$ git init
$ git submodule add https://github.com/theNewDynamic/gohugo-theme-ananke.git themes/ananke
```

Create a `hugo.toml` file with the following content:

```
baseURL = 'https://example.org/'
languageCode = 'de-de'
title = 'My New Hugo Site'
theme = 'ananke'
defaultContentLanguage = 'de'
defaultContentLanguageInSubdir = true

[languages]
  [languages.de]
    disabled = false
    languageCode = 'de'
    languageDirection = 'ltr'
    languageName = 'Deutsch'
    title = 'Problem'
    weight = 1

  [languages.en]
    disabled = false
    languageCode = 'en'
    languageDirection = 'ltr'
    languageName = 'English'
    title = 'Issue'
    weight = 2
```


#### 2. Add a content page with a translation and a `![pic](./image.png)`

```
$ pwd
/home/user/dev/issue-hugo/issue
$ tree ./content
./content
└── test
    ├── image.png
    ├── index.de.md
    └── index.en.md
```

with `index.de.md` content: 

```
---
title: 'Test DE (Hauptsprache / main language)'
date: 2024-05-17T19:07:13+02:00
---

## Hauptsprache / main language (German, de)

Dies ist ein Test (This is a Test):

![pic](./image.png)
```

and `index.en.md` content:

```
---
title: 'Test EN (secondary language)'
date: 2024-05-17T19:07:13+02:00
---

## Secondary language (English, en)

This is a Test:

![pic](./image.png)
```


#### 3. Expected result (=Hugo v0.122.0)

`public/en/test/image.png` exists when running `hugo server --disableFastRender --cleanDestinationDir --renderToDisk`:

```
$ tree ./public/
./public/
[...]
├── de
[...]
│   └── test
│       ├── image.png
│       └── index.html
├── en
[...]
│   └── test
│       ├── image.png
│       └── index.html
[...]
```




#### 4. Actual result (=Hugo >= v0.123.0 up until current release v0.126.1)

`public/en/test/image.png` does not exists when running `hugo server --disableFastRender --cleanDestinationDir`:

```
$ tree ./public/
./public/
[...]
├── de
[...]
│   └── test
│       ├── image.png
│       └── index.html
├── en
[...]
│   └── test
│       └── index.html
[...]
```
Notice the missing `image.png` below `en/test/`


#### Misc notes / real world example

I ran into this while working on https://foundata.com/en/blog/ (where "de" (German) is the default language and "en" (English) is an additional translation). I added two blog postings and noticed that some images on the English homepage at `/en/` as well as in the blog postings are missing.

It worked well with Hugo 0.122.0:

```
                  | DE | EN  
-------------------+----+-----
  Pages            | 86 | 84  
  Paginator pages  |  0 |  0  
  Non-page files   | 60 | 57  
  Static files     | 40 | 40  
  Processed images | 48 | 48  
  Aliases          | 19 | 17  
  Sitemaps         |  2 |  1  
  Cleaned          | 48 | 48 
  ```

but failed with the latest Hugo version 0.126.1 (Please notice the difference in the "EN" column (especially the `Processed images [...] 0` instead of `48`):

```
                   | DE | EN  
-------------------+----+-----
  Pages            | 88 | 85  
  Paginator pages  |  0 |  0  
  Non-page files   | 60 | 57  
  Static files     | 40 | 40  
  Processed images | 48 |  0  
  Aliases          | 19 | 17  
  Cleaned          | 48 | 48 
  ```


Discussion / hints:
With v0.123.0 and later, by default, we don't duplicate resources. See:
<https://gohugo.io/content-management/page-resources/#multilingual>.

This is the expected result:

```text
public/
├── de/
│   ├── test/
│   │   ├── image.png  <-- this is a page resource for both languages
│   │   └── index.html
│   └── index.html
├── en/
│   ├── test/
│   │   └── index.html
│   └── index.html
└── index.html
```

If you change your markdown destination from `./image.png` to `image.png`, the embedded image render hook will resolve the destination as expected.

The issue here is the leading `./`. 

---

Example site:

```text
git clone --single-branch -b hugo-github-issue-12514 https://github.com/jmooring/hugo-testing hugo-github-issue-12514
cd hugo-github-issue-12514
hugo server
```

Then visit the English version of the test page.


@bep I'll submit a PR to address this in the render hooks. That seems less invasive than altering the behavior of `.Resources.Get` and friends. 

Fix patch:
diff --git a/tpl/tplimpl/embedded/templates/_default/_markup/render-image.html b/tpl/tplimpl/embedded/templates/_default/_markup/render-image.html
index 31437cdd430..89514cb83a0 100644
--- a/tpl/tplimpl/embedded/templates/_default/_markup/render-image.html
+++ b/tpl/tplimpl/embedded/templates/_default/_markup/render-image.html
@@ -1,7 +1,8 @@
 {{- $u := urls.Parse .Destination -}}
 {{- $src := $u.String -}}
 {{- if not $u.IsAbs -}}
-  {{- with or (.PageInner.Resources.Get $u.Path) (resources.Get $u.Path) -}}
+  {{- $path := strings.TrimPrefix "./" $u.Path }}
+  {{- with or (.PageInner.Resources.Get $path) (resources.Get $path) -}}
     {{- $src = .RelPermalink -}}
     {{- with $u.RawQuery -}}
       {{- $src = printf "%s?%s" $src . -}}
diff --git a/tpl/tplimpl/embedded/templates/_default/_markup/render-link.html b/tpl/tplimpl/embedded/templates/_default/_markup/render-link.html
index 30e4d2660c6..daf3f11e1a7 100644
--- a/tpl/tplimpl/embedded/templates/_default/_markup/render-link.html
+++ b/tpl/tplimpl/embedded/templates/_default/_markup/render-link.html
@@ -3,10 +3,11 @@
 {{- if strings.HasPrefix $u.String "#" }}
   {{- $href = printf "%s#%s" .PageInner.RelPermalink $u.Fragment }}
 {{- else if not $u.IsAbs -}}
+  {{- $path := strings.TrimPrefix "./" $u.Path }}
   {{- with or
-    ($.PageInner.GetPage $u.Path)
-    ($.PageInner.Resources.Get $u.Path)
-    (resources.Get $u.Path)
+    ($.PageInner.GetPage $path)
+    ($.PageInner.Resources.Get $path)
+    (resources.Get $path)
   -}}
     {{- $href = .RelPermalink -}}
     {{- with $u.RawQuery -}}


Test patch:
diff --git a/tpl/tplimpl/render_hook_integration_test.go b/tpl/tplimpl/render_hook_integration_test.go
index f6cb5bf6b2f..b91358227da 100644
--- a/tpl/tplimpl/render_hook_integration_test.go
+++ b/tpl/tplimpl/render_hook_integration_test.go
@@ -51,7 +51,8 @@ title: s1/p1
 title: s1/p2
 ---
 [500](a.txt) // global resource
-[600](b.txt) // page resource
+[510](b.txt) // page resource
+[520](./b.txt) // page resource
 -- content/s1/p2/b.txt --
 irrelevant
 -- content/s1/p3.md --
@@ -125,12 +126,14 @@ title: s1/p3
 
 	b.AssertFileContent("public/s1/p2/index.html",
 		`<a href="/a.txt">500</a>`,
-		`<a href="/s1/p2/b.txt">600</a>`,
+		`<a href="/s1/p2/b.txt">510</a>`,
+		`<a href="/s1/p2/b.txt">520</a>`,
 	)
 }
 
 // Issue 12203
 // Issue 12468
+// Issue 12514
 func TestEmbeddedImageRenderHook(t *testing.T) {
 	t.Parallel()
 
@@ -145,7 +148,9 @@ block = false
 [markup.goldmark.renderHooks.image]
 enableDefault = true
 -- content/p1/index.md --
-![alt](pixel.png?a=b&c=d#fragment)
+![alt1](./pixel.png)
+
+![alt2](pixel.png?a=b&c=d#fragment)
 {.foo #bar}
 -- content/p1/pixel.png --
 iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNkYPhfDwAChwGA60e6kgAAAABJRU5ErkJggg==
@@ -154,10 +159,16 @@ iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNkYPhfDwAChwGA60e6kgAA
 `
 
 	b := hugolib.Test(t, files)
-	b.AssertFileContent("public/p1/index.html", `<img alt="alt" src="/dir/p1/pixel.png?a=b&c=d#fragment">`)
+	b.AssertFileContent("public/p1/index.html",
+		`<img alt="alt1" src="/dir/p1/pixel.png">`,
+		`<img alt="alt2" src="/dir/p1/pixel.png?a=b&c=d#fragment">`,
+	)
 
 	files = strings.Replace(files, "block = false", "block = true", -1)
 
 	b = hugolib.Test(t, files)
-	b.AssertFileContent("public/p1/index.html", `<img alt="alt" class="foo" id="bar" src="/dir/p1/pixel.png?a=b&c=d#fragment">`)
+	b.AssertFileContent("public/p1/index.html",
+		`<img alt="alt1" src="/dir/p1/pixel.png">`,
+		`<img alt="alt2" class="foo" id="bar" src="/dir/p1/pixel.png?a=b&c=d#fragment">`,
+	)
 }