Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 18 additions & 2 deletions config/_default/hugo.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -177,11 +177,16 @@ cascade:
target:
path: /dev/**

mediaTypes:
text/nginx:
suffixes: nginx

outputs:
home:
- html
- cms_config
- rss
- redirects
section:
- html
taxonomy:
Expand All @@ -193,9 +198,16 @@ outputFormats:
cms_config:
baseName: cms-config
mediaType: application/yaml
isHTML: false
isPlainText: true
notAlternative: true
redirects:
baseName: .nginx/301
mediaType: text/nginx
rel: nginx
isPlainText: true
notAlternative: true
root: true
ugly: true

# Keep for local dev. Production build uses --minify.
minify:
Expand Down Expand Up @@ -273,4 +285,8 @@ caches:
images:
dir: :cacheDir/images

disableHugoGeneratorInject: true
disableHugoGeneratorInject: true
# Aliases are served as nginx 301 redirects from the generated .nginx/301.nginx
# map (themes/trigo/layouts/home.redirects.nginx), not as HTML redirect pages.
# Hosts without that nginx config, e.g. GitHub Pages, have no alias redirects.
disableAliases: true
4 changes: 3 additions & 1 deletion content/en/about/conduct/_index.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
---
title: FreeCAD Code of Conduct
linkTitle: Conduct
draft: true
build:
render: never
aliases: ["/codeofconduct"]
redirect: https://github.com/FreeCAD/FreeCAD/blob/main/CODE_OF_CONDUCT.md
---
4 changes: 3 additions & 1 deletion content/en/about/privacy/_index.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
---
title: FreeCAD Privacy Policy
linkTitle: Privacy
draft: true
build:
render: never
aliases: ["/privacy"]
redirect: https://github.com/FreeCAD/FreeCAD/blob/main/PRIVACY_POLICY.md
---
1 change: 1 addition & 0 deletions content/en/community/_index.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
---
title: Community
description: Get in touch with the community around the world.
aliases: ["/professional-network"]
icon: people
icon_cms: groups
---
1 change: 1 addition & 0 deletions content/en/community/calendar/_index.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
---
title: Calendar
description: Browse all scheduled happenings.
aliases: ["/events"]
weight: 1
icon: date
---
1 change: 1 addition & 0 deletions content/en/dev/_index.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
---
title: Development Handbook
description: Start contributing, extending, and shaping the future of the FreeCAD ecosystem.
aliases: ["/contributing"]
icon: dev
icon_cms: logo_dev
---
1 change: 1 addition & 0 deletions content/en/donate/_index.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
title: Support the FreeCAD project
linkTitle: Donate
description: Donate once or sponsor monthly to make FreeCAD even more awesome!
aliases: ["/sponsor"]
icon: heart
icon_cms: favorite
---
Expand Down
1 change: 1 addition & 0 deletions content/en/download/_index.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
title: Launch into design!
linkTitle: Download
description: Get FreeCAD and start with freedom right away.
aliases: ["/downloads"]
icon: download
icon_cms: download
---
Expand Down
1 change: 1 addition & 0 deletions content/en/download/addons/_index.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
---
title: Addons
description: Explore FreeCAD ecosystem and take advantage of specialized tools.
aliases: ["/addons"]
weight: 3
icon: puzzle
---
1 change: 1 addition & 0 deletions content/en/features/_index.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
title: Innovate without limits
linkTitle: Features
description: Powerful and open parametric design for everyone.
aliases: ["/features"]

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This one doesn't work: the section is already called "features", so this results in a circular self-redirecting loop.

icon: stars
icon_cms: bolt
---
Expand Down
1 change: 1 addition & 0 deletions content/en/news/_index.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
---
title: News
description: Browse the latest news
aliases: ["/blog"]
icon: news
icon_cms: brand_awareness
---
6 changes: 3 additions & 3 deletions themes/trigo/layouts/_partials/utils/link_redirect.html
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,12 @@
{{- $link = .RelPermalink -}}
{{- end -}}
{{- else -}}
{{- $target := site.GetPage . -}}
{{- $target := $page.Site.GetPage . -}}
{{- with $target -}}
{{- $link = .RelPermalink -}}
{{- else -}}
{{- if and (hasPrefix . $wiki_url) (not site.Language.IsDefault) -}}
{{- $link = printf "%s/%s" . site.Language.Name -}}
{{- if and (hasPrefix . $wiki_url) (not $page.Site.Language.IsDefault) -}}
{{- $link = printf "%s/%s" . $page.Site.Language.Name -}}
{{- else -}}
{{- $link = . -}}
{{- end -}}
Expand Down
146 changes: 146 additions & 0 deletions themes/trigo/layouts/home.redirects.nginx
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
{{- /*
SPDX-License-Identifier: MIT
SPDX-FileCopyrightText: 2026 FreeCAD
SPDX-FileNotice: Part of the Trigo theme for Hugo.
*/ -}}

{{- /* Nginx redirects:

- Get all pages with aliases or redirect param.
- Homepage also gets the old /index.php.
- Resolve targets like site links do, so pages with a `redirect` param point to their target.
- Match languages by normalized lang name without locale, e.g. es_CO -> es, zh_TW -> zh.
- Do not include equal old and new paths to avoid circular self-redirecting loop.
- Output is parsed as nginx config, so every line is checked against a safe character set.
- Generate nginx redirects map for each alias or redirect-only page.

@example /old, /old/, and /old.php -> /new/
@example /old.php?lang=<lang> -> translated /<lang>/new/ or default /new/ page if translation missing
@example /?lang=<lang> -> translated homepage
@example /<lang>/internal and /<lang>/internal/ -> https://external.org/
@example /<lang>/releases/0-17 and /<lang>/releases/0-17/ -> https://wiki.freecad.org/Release_notes_0.17/<lang>

*/ -}}

{{- if site.IsDefault -}}

{{- $redirects := dict -}}
{{- $safe_source := `^/[A-Za-z0-9._~/%-]*(\?lang=[A-Za-z_]+)?$` -}}
{{- $safe_target := `^(/|https://)[A-Za-z0-9._~/%:?&=+()-]*$` -}}
{{- $old_locales := slice
"be"
"ca"
"cs"
"de"
"el"
"en"
"es"
"es_CO"
"eu"
"fa"
"fi"
"fr"
"ga"
"hr"
"hu"
"it"
"ja"
"ka"
"ko"
"lo"
"nl"
"pl"
"pt_BR"
"ru"
"sl"
"sr"
"sv"
"ta"
"tr"
"uk"
"zh_CN"
"zh_TW"
-}}

{{- range $page := hugo.Sites.Default.Pages -}}
{{- $aliases := $page.Aliases -}}

{{- if $page.IsHome -}}
{{- $aliases = $aliases | append "/index" -}}
{{- end -}}

{{- if $aliases -}}
{{- $key := partial "utils/cache_key.html" $page -}}
{{- $new_redirect := partialCached "utils/link_redirect.html" $page $key -}}
{{- $new_langs := dict -}}

{{- range $translation := $page.Translations -}}
{{- $normalized := replace (lower $translation.Language.Name) "_" "-" -}}
{{- $lang_name := index (split $normalized "-") 0 -}}
{{- if not (isset $new_langs $lang_name) -}}
{{- $key := partial "utils/cache_key.html" $translation -}}
{{- $lang_target := partialCached "utils/link_redirect.html" $translation $key .Language.Name -}}
{{- $new_langs = merge $new_langs (dict $lang_name $lang_target) -}}
{{- end -}}
{{- end -}}

{{- range $alias := $aliases -}}
{{- $alias = trim $alias "/" -}}
{{- $php_alias := printf "/%s.php" $alias -}}

{{- range $old_source := slice (printf "/%s" $alias) (printf "/%s/" $alias) $php_alias -}}
{{- $redirects = merge $redirects (dict $old_source $new_redirect) -}}
{{- end -}}

{{- $lang_sources := slice $php_alias -}}
{{- if $page.IsHome -}}
{{- $lang_sources = $lang_sources | append "/" -}}
{{- end -}}

{{- range $old_locale := $old_locales -}}
{{- $normalized := replace (lower $old_locale) "_" "-" -}}
{{- $lang_name := index (split $normalized "-") 0 -}}
{{- $new_target := default $new_redirect (index $new_langs $lang_name) -}}

{{- range $lang_source := $lang_sources -}}
{{- $redirects = merge $redirects (dict (printf "%s?lang=%s" $lang_source $old_locale) $new_target) -}}
{{- end -}}
{{- end -}}
{{- end -}}

{{- else if and $page.Params.redirect (ne $page.Params.redirect "auto") -}}
{{- $key := partial "utils/cache_key.html" $page -}}
{{- $new_redirect := partialCached "utils/link_redirect.html" $page $key -}}
{{- $page_source := trim $page.RelPermalink "/" -}}

{{- /* Include the canonical trailing-slash path, which would otherwise serve the placeholder page. */ -}}
{{- range $old_source := slice (printf "/%s" $page_source) (printf "/%s/" $page_source) -}}
{{- $redirects = merge $redirects (dict $old_source $new_redirect) -}}
{{- end -}}

{{- range $translation := $page.Translations -}}
{{- $key := partial "utils/cache_key.html" $translation -}}
{{- $redirect_target := partialCached "utils/link_redirect.html" $translation $key .Language.Name -}}
{{- $translated_source := trim $translation.RelPermalink "/" -}}
{{- range $old_source := slice (printf "/%s" $translated_source) (printf "/%s/" $translated_source) -}}
{{- $redirects = merge $redirects (dict $old_source $redirect_target) -}}
{{- end -}}
{{- end -}}
{{- end -}}
{{- end -}}

{{- range $old, $new := $redirects -}}
{{- if not (findRE $safe_source $old) -}}
{{- errorf "Redirect source %q contains characters not allowed in the nginx map" $old -}}
{{- end -}}

{{- if not (findRE $safe_target $new) -}}
{{- errorf "Redirect target %q for %q contains characters not allowed in the nginx map" $new $old -}}
{{- end -}}

{{- /* Skip equal old and new paths, which would redirect to themselves. */ -}}
{{- if ne (trim $old "/") (trim $new "/") -}}
{{- printf "%s %s;\n" $old $new -}}
{{- end -}}
{{- end -}}
{{- end -}}
Loading