A sample config:
```toml
defaultContentLanguage = "en"
defaultContentLanguageInSubdir = true
[Languages]
[Languages.en]
weight = 10
title = "In English"
languageName = "English"
contentDir = "content/english"
[Languages.nn]
weight = 20
title = "På Norsk"
languageName = "Norsk"
contentDir = "content/norwegian"
```
The value of `contentDir` can be any valid path, even absolute path references. The only restriction is that the content dirs cannot overlap.
The content files will be assigned a language by
1. The placement: `content/norwegian/post/my-post.md` will be read as Norwegian content.
2. The filename: `content/english/post/my-post.nn.md` will be read as Norwegian even if it lives in the English content folder.
The content directories will be merged into a big virtual filesystem with one simple rule: The most specific language file will win.
This means that if both `content/norwegian/post/my-post.md` and `content/english/post/my-post.nn.md` exists, they will be considered duplicates and the version inside `content/norwegian` will win.
Note that translations will be automatically assigned by Hugo by the content file's relative placement, so `content/norwegian/post/my-post.md` will be a translation of `content/english/post/my-post.md`.
If this does not work for you, you can connect the translations together by setting a `translationKey` in the content files' front matter.
Fixes#4523Fixes#4552Fixes#4553
As an example:
```html
{{ $pages := .Site.RegularPages | lang.Merge $frSite.RegularPages | lang.Merge $enSite.RegularPages }}
```
Will "fill in the gaps" in the current site with, from left to right, content from the French site, and lastly the English.
Fixes#4463
This means that you can do something ala:
```html
{{ if ge .Hugo.Version "0.36" }}Reasonable new Hugo version!{{ end }}
```
The intented use is feature toggling, but please note that it will take some time and Hugo versions until this can be trusted. It does not work in older Hugo versions.
Fixes#4443
Also:
- Remove unnecessary space from `figure` tag if no class is specified.
- Update related tests.
- Add test cases for the changes made to the figure shortcode.
- Document the newly added target and rel parameters
- Add more detail to the documentation of all figure shortcode parameters.
The tplimpl package was misusing the TemplateLookupDescriptor.WorkingDir
field from the output package. By incorrectly setting it to the theme
directory instead of the site root, the user is unable to override theme
templates in some situations.
Fixes#3505
The new lookup order:
1) Page.Params.images if set
2) Image resources: images with name "feature" (priority), "cover", "thumbnail"
3) Site.Params.images if set
Fixes#4349
This is in heavy use in rendering, so this makes a difference:
```bash
benchmark old ns/op new ns/op delta
BenchmarkSiteBuilding/TOML,num_langs=1,num_pages=500,tags_per_page=5,shortcodes,render-4 124551144 107743429 -13.49%
benchmark old allocs new allocs delta
BenchmarkSiteBuilding/TOML,num_langs=1,num_pages=500,tags_per_page=5,shortcodes,render-4 528684 435118 -17.70%
benchmark old bytes new bytes delta
BenchmarkSiteBuilding/TOML,num_langs=1,num_pages=500,tags_per_page=5,shortcodes,render-4 53306848 45147832 -15.31%
```
This commit adds support for multiple statDirs both on the global and language level.
A simple `config.toml` example:
```bash
staticDir = ["static1", "static2"]
[languages]
[languages.no]
staticDir = ["staticDir_override", "static_no"]
baseURL = "https://example.no"
languageName = "Norsk"
weight = 1
title = "På norsk"
[languages.en]
staticDir2 = "static_en"
baseURL = "https://example.com"
languageName = "English"
weight = 2
title = "In English"
```
In the above, with no theme used:
the English site will get its static files as a union of "static1", "static2" and "static_en". On file duplicates, the right-most version will win.
the Norwegian site will get its static files as a union of "staticDir_override" and "static_no".
This commit also concludes the Multihost support in #4027.
Fixes#36Closes#4027
This commit adds a "cache potential" column when running `hugo --templateMetrics --templateMetricsHints`.
This is only calculated when `--templateMetricsHints` is set, as these calculations has an negative effect on the other timings.
This gives a value for partials only, and is a number between 0-100 that indicates if `partial` can be replaced with `partialCached`.
100 means that all execution of the same partial resulted in the same output.
You should do some manual research before going "all cache".
Add template function that will build a string from the given format
string and arguments, then log it to ERROR. This has an intended
side-effect of causing the build to fail, when executed.
Resolves#3817
Changes fall into one of the following:
- gofmt -s
- receiver name is inconsistent
- omit unused 2nd value from range
- godoc comment formed incorrectly
- err assigned and not used
- if block ends with a return statement followed by else
Add a template function that allows conversion to float. This is
useful, for example, when passing aspect ratios into templates,
which tend to not be integers.
Fixes#3307
Ceil and Floor are frontends for the stdlib math functions. The Round
implementation is essentially the same thing except that the Go stdlib
doesn't include a Round implementation in a stable release yet. I've
included the Round function slated for Go 1.10.
Fixes#3883
This closes#98, even if this commit does not do full content text search.
We may revisit that problem in the future, but that deserves its own issue.
Fixes#98
These funcs were added during the move to namespaces but were
undocumented. This commit fixes the order of the arguments and adds the
funcs to the method mapping.
And use it in `eq` and `ne` so `Page` values can be compared directly in the templates without thinking about it being a `Page` or a `PageOutput` wrapper.
Fixes#3807
As pointed out by the linter, some exported functions and types are
missing doc comments.
The linter warnings have been reduced from 194 to 116.
Not all missing comments have been added in this commit though.
This works for the `title` func and the other places where Hugo makes title case.
* AP style (new default)
* Chicago style
* Go style (what we have today)
Fixes#989
This enables `AND` (`intersect`) and `OR` (`union`) filters when combined with `where`.
Example:
```go
{{ $pages := where .Site.RegularPages "Type" "not in" (slice "page" "about") }}
{{ $pages := $pages | union (where .Site.RegularPages "Params.pinned" true) }}
{{ $pages := $pages | intersect (where .Site.RegularPages "Params.images" "!=" nil) }}
```
The above fetches regular pages not of `page` or `about` type unless they are pinned. And finally, we exclude all pages with no `images` set in Page params.
Fixes#3174
* Improve the built-in Disqus template
Set `disqus_identifier`, `disqus_title`, and `disqus_url`
only if the user has explicitly provided them.
Do not load Disqus when the website is previewed locally,
otherwise it is very confusing.
* Use disqus_config instead of three global variables
https://help.disqus.com/customer/portal/articles/472098-javascript-configuration-variables
Unsupported types are currently silently ignored by IsSet. An earlier
attempt was made to solve the issue by returning an error. That attempt
was reverted since it broke some existing themes.
So instead, we'll log an error. Hopefully, people will stop using IsSet
in this way, and we can eventually return an error outright.
Updates #3092
This commit allows shortcode per output format, a typical use case would be the special AMP media tags.
Note that this will only re-render the "overridden" shortcodes and only in pages where these are used, so performance in the normal case should not suffer.
Closes#3220
- Move the main GetCSV and GetJSON into data.go.
- Add error returns to GetCSV and GetJSON.
- Add http client to Namespace for test mocking.
- Send accept headers on remote requests. Fixes#3395
- Return an error on non-2XX HTTP response codes and don't retry.
- Move cache tests to cache_test.go.
As a first step to remove the hard ties between `tplimpl` and the different namespace packages.
The `lang` package is used as the first example use case.
See #3042
This commit moves almost all of the template functions into separate
packages under tpl/ and adds a namespace framework. All changes should
be backward compatible for end users, as all existing function names in
the template funcMap are left intact.
Seq and DoArithmatic have been moved out of the helpers package and into
template namespaces.
Most of the tests involved have been refactored, and many new tests have
been written. There's still work to do, but this is a big improvement.
I got a little overzealous and added some new functions along the way:
- strings.Contains
- strings.ContainsAny
- strings.HasSuffix
- strings.TrimPrefix
- strings.TrimSuffix
Documentation is forthcoming.
Fixes#3042
For pages with translations, add links with hreflang attributes to the
default sitemap template. This helps Google to show the correct
language page in its search results. The syntax used is based on
Google's example at [1].
Also update the sitemap template docs to reflect the changes in the
default template.
[1]
https://support.google.com/webmasters/answer/2620865?hl=en&topic=2370587&ctx=topicFixes#2569
Most obvius benefit of this is to include CSS partials with css file suffix into HTML templates.
A valid workaround would be to rename the file `mystyles.html`, but that doesn't work too good for external editors etc.
The css partial is a method used in some themes before Hugo 0.20, but then it stopped working.
This commit reintroduces that behaviour.
Note that the regular layout lookups for text templates, i.e. "single.json" will be
prefixed with "_text/" on lookup and will only match in the text collection.
Fixes#3273
Before this commit, Hugo used `html/template` for all Go templates.
While this is a fine choice for HTML and maybe also RSS feeds, it is painful for plain text formats such as CSV, JSON etc.
This commit fixes that by using the `IsPlainText` attribute on the output format to decide what to use.
A couple of notes:
* The above requires a nonambiguous template name to type mapping. I.e. `/layouts/_default/list.json` will only work if there is only one JSON output format, `/layouts/_default/list.mytype.json` will always work.
* Ambiguous types will fall back to HTML.
* Partials inherits the text vs HTML identificator of the container template. This also means that plain text templates can only include plain text partials.
* Shortcode templates are, by definition, currently HTML templates only.
Fixes#3221
Before this commit, Hugo used `html/template` for all Go templates.
While this is a fine choice for HTML and maybe also RSS feeds, it is painful for plain text formats such as CSV, JSON etc.
This commit fixes that by using the `IsPlainText` attribute on the output format to decide what to use.
A couple of notes:
* The above requires a nonambiguous template name to type mapping. I.e. `/layouts/_default/list.json` will only work if there is only one JSON output format, `/layouts/_default/list.mytype.json` will always work.
* Ambiguous types will fall back to HTML.
* Partials inherits the text vs HTML identificator of the container template. This also means that plain text templates can only include plain text partials.
* Shortcode templates are, by definition, currently HTML templates only.
Fixes#3221
Add a new rssLimit site configuration option with default of 15. Prior
to this fix, you could create your own RSS feed to override the default
limit of 15, but we still had a hardcoded limit of 50 items set in
`hugolib.renderRSS()`.
With this option in place, the `range first 15 .Data.Pages` logic is no
longer hardcoded into the embedded RSS template.
Because the size of the slice passed to the template is now limited to
rssLimit instead of 50, this commit is a breaking change for sites
with a custom RSS template that expects more than 15 items.
Fixes#3035
Allow all nodes/pages to use date-related OpenGraph meta tags, not
only sites which are using the as-of-yet unfinished .Site.Authors
functionality.
Improve compliance of tags with Facebook's OpenGraph docs for the
"website" and "article" types[0][1]. Also, use the proper tag for
modification date (og:update_time vs article:modified_time).
Generate date published using either .PublishDate or .Date, and use
.Lastmod for modification date, which can use the new enableGitInfo
functionality from Hugo 0.18, but seamlessly falls back to .Date if
the site does not have this enabled/supported.
[0] https://developers.facebook.com/docs/reference/opengraph/object-type/website/
[1] https://developers.facebook.com/docs/reference/opengraph/object-type/article/
Note that this looks like overkill for just the logger, and that is correct,
but this will make sense once we start with the template handling etc.
Updates #2701
This commit adds a truncate template function for safely truncating text without
breaking words. The truncate function is HTML aware, so if the input text is a
template.HTML it will be truncated without leaving broken or unclosed HTML tags.
{{ "this is a very long text" | truncate 10 " ..." }}
{{ "With [Markdown](/markdown) inside." | markdownify | truncate 10 }}
This commit fixes the base template lookup order to match the behaviour of regular templates.
```
1. <current-path>/<template-name>-baseof.<suffix>, e.g. list-baseof.<suffix>.
2. <current-path>/baseof.<suffix>
3. _default/<template-name>-baseof.<suffix>, e.g. list-baseof.<suffix>.
4. _default/baseof.<suffix>
For each of the steps above, it will first look in the project, then, if theme is set,
in the theme's layouts folder.
```
Fixes#2783
There are currently several Params and case related issues floating around in Hugo.
This is very confusing for users and one of the most common support questions on the forum.
And while there have been done some great leg work in Viper etc., this is of limited value since this and similar doesn't work:
`Params.myCamelCasedParam`
Hugo has control over all the template method invocations, and can take care of all the lower-casing of the map lookup keys.
But that doesn't help with direct template lookups of type `Site.Params.TWITTER_CONFIG.USER_ID`.
This commit solves that by doing some carefully crafted modifications of the templates' AST -- lowercasing the params keys.
This is low-level work, but it's not like the template API wil change -- and this is important enough to defend such "bit fiddling".
Tests are added for all the template engines: Go templates, Ace and Amber.
Fixes#2615Fixes#1129Fixes#2590
There are currently several Params and case related issues floating around in Hugo.
This is very confusing for users and one of the most common support questions on the forum.
And while there have been done some great leg work in Viper etc., this is of limited value since this and similar doesn't work:
`Params.myCamelCasedParam`
Hugo has control over all the template method invocations, and can take care of all the lower-casing of the map lookup keys.
But that doesn't help with direct template lookups of type `Site.Params.TWITTER_CONFIG.USER_ID`.
This commit solves that by doing some carefully crafted modifications of the templates' AST -- lowercasing the params keys.
This is low-level work, but it's not like the template API wil change -- and this is important enough to defend such "bit fiddling".
Tests are added for all the template engines: Go templates, Ace and Amber.
Fixes#2615Fixes#1129Fixes#2590
Add imageConfig function which calls image.DecodeConfig and returns the height, width and color mode of the image. (#2677)
This allows for more advanced image shortcodes and templates such as those required by AMP.
layouts/shortcodes/amp-img.html
```
{{ $src := .Get "src" }}
{{ $config := imageConfig (printf "/static/%s" $src) }}
<amp-img src="{{$src}}"
height="{{$config.Height}}"
width="{{$config.Width}}"
layout="responsive">
</amp-img>
```
tpl/template_funcs.go:1019:3: the surrounding loop is unconditionally terminated
source/lazy_file_reader.go:66:5: err != nil is always true for all possible
values ([nil:error] != [nil:error])
All config variables starts with low-case and uses camelCase.
If there is abbreviation at the beginning of the name, the whole
abbreviation will be written in low-case.
If there is abbreviation at the end of the name, the
whole abbreviation will be written in upper-case.
For example, rssURI.
The gain, given the "real sites benchmark" below, is obvious:
```
benchmark old ns/op new ns/op delta
BenchmarkHugo-4 14497594101 13084156335 -9.75%
benchmark old allocs new allocs delta
BenchmarkHugo-4 57404335 48282002 -15.89%
benchmark old bytes new bytes delta
BenchmarkHugo-4 9933505624 9721984424 -2.13%
```
Fixes#2495
* Make the type/var names more specific. They live in the test namespace, but there are other tests there.
* Camel case variable
* Small change suggested by Golint
There were some breaking changes etc. that is too late to fix for 0.17.
Let us think this through and add proper author support for Hugo 0.18.
Fixes#2464
Revert "docs: Add documentation for author profiles"
This reverts commit b6673e5309.
Revert "Add First Class Author Support"
This reverts commit cf978c0649.
* Fall back to default language on missing translation file
* Add a i18n-warnings build flag
* If that flag is set, print a parseable and greppable string on missing translation strings
See #2303
The current "rendering language" is needed outside of Site. This commit moves the Language type to the helpers package, and then used to get correct correct language configuration in the markdownify template func.
This commit also adds two new template funcs: relLangURL and absLangURL.
See #2309
Work In Progress!
This commit makes a rework of the build and rebuild process to better suit a multi-site setup.
This also includes a complete overhaul of the site tests. Previous these were a messy mix that
were testing just small parts of the build chain, some of it testing code-paths not even used in
"real life". Now all tests that depends on a built site follows the same and real production code path.
See #2309Closes#2211Closes#477Closes#1744
This commit also consolidates URLs on Node vs Page, so now .Permalink should be interoperable.
Note that this implementations should be fairly short-livded, waiting for #2297, but the API should be stable.
Setting the language to use when loading the language bundles just doesn't work.
The template system is unfortanetely a global, and the last languate processed won ...
Implements:
* support to render:
* content/post/whatever.en.md to /en/2015/12/22/whatever/index.html
* content/post/whatever.fr.md to /fr/2015/12/22/whatever/index.html
* gets enabled when `Multilingual:` is specified in config.
* support having language switchers in templates, that know
where the translated page is (with .Page.Translations)
(when you're on /en/about/, you can have a "Francais" link pointing to
/fr/a-propos/)
* all translations are in the `.Page.Translations` map, including the current one.
* easily tweak themes to support Multilingual mode
* renders in a single swift, no need for two config files.
Adds a couple of variables useful for multilingual sites
Adds documentation (content/multilingual.md)
Added language prefixing for all URL generation/permalinking see in the
code base.
Implements i18n. Leverages the great github.com/nicksnyder/go-i18n lib.. thanks Nick.
* Adds "i18n" and "T" template functions..
These functions allow trivial escaping and unescaping of HTML entities,
and make it far easier to compose other functions for the creation of
parameterised URLs.
Add logic to tpl.humanize such that it understands input of int literals
or strings which represent an integer. When tpl.humanize sees this type
of input, it will use inflect.Ordinalize as opposed to the standard
inflect.Humanize.
Fixes#1886
The query function will take a set of parameters specified like a dict and return a url.Values object which can be .Encode'd into a query string.
Example:
<a href="http://www.google.com?{{ (querify "q" "test" "page" 3).Encode | safeHTML }}">Search</a>
Returns:
<a href="http://www.google.com?page=3&q=test">Search</a>
Closes#2257
Returns true if a given field value that is a slice / array of strings, integers or floats contains elements in common with the matching value. It follows the same rules as the intersect function.
Closes#1945