Skip to content

Commit

Permalink
Add a way to disable one or more languages
Browse files Browse the repository at this point in the history
This commit adds a new config setting:

```toml
disableLanguages = ["fr"]
```

If this is a multilingual site:

* No site for the French language will be created
* French content pages will be ignored/not read
* The French language configuration (menus etc.) will also be ignored

This makes it possible to start translating new languages and turn it on when you're happy etc.

Fixes gohugoio#4297
Fixed gohugoio#4329
  • Loading branch information
bep committed Jan 26, 2018
1 parent 322c567 commit 66195bd
Show file tree
Hide file tree
Showing 10 changed files with 160 additions and 42 deletions.
23 changes: 13 additions & 10 deletions commands/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -173,20 +173,23 @@ func server(cmd *cobra.Command, args []string) error {
c.Set("liveReloadPort", serverPorts[0])
}

if c.languages.IsMultihost() {
for i, language := range c.languages {
baseURL, err := fixURL(language, baseURL, serverPorts[i])
if err != nil {
return err
}
language.Set("baseURL", baseURL)
isMultiHost := c.languages.IsMultihost()
for i, language := range c.languages {
var serverPort int
if isMultiHost {
serverPort = serverPorts[i]
} else {
serverPort = serverPorts[0]
}
} else {
baseURL, err := fixURL(c.Cfg, baseURL, serverPorts[0])

baseURL, err := fixURL(language, baseURL, serverPort)
if err != nil {
return err
}
c.Set("baseURL", baseURL)
language.Set("baseURL", baseURL)
if i == 0 {
c.Set("baseURL", baseURL)
}
}

return nil
Expand Down
1 change: 1 addition & 0 deletions config/configProvider.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ type Provider interface {
GetBool(key string) bool
GetStringMap(key string) map[string]interface{}
GetStringMapString(key string) map[string]string
GetStringSlice(key string) []string
Get(key string) interface{}
Set(key string, value interface{})
IsSet(key string) bool
Expand Down
5 changes: 5 additions & 0 deletions helpers/language.go
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,11 @@ func (l *Language) GetStringMapString(key string) map[string]string {
return cast.ToStringMapString(l.Get(key))
}

// returns the value associated with the key as a slice of strings.
func (l *Language) GetStringSlice(key string) []string {
return cast.ToStringSlice(l.Get(key))
}

// Get returns a value associated with the key relying on specified language.
// Get is case-insensitive for a key.
//
Expand Down
38 changes: 33 additions & 5 deletions hugolib/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -72,16 +72,46 @@ func LoadConfig(fs afero.Fs, relativeSourcePath, configFilename string) (*viper.
}

func loadLanguageSettings(cfg config.Provider, oldLangs helpers.Languages) error {
multilingual := cfg.GetStringMap("languages")

defaultLang := cfg.GetString("defaultContentLanguage")

var languages map[string]interface{}

languagesFromConfig := cfg.GetStringMap("languages")
disableLanguages := cfg.GetStringSlice("disableLanguages")

if len(disableLanguages) == 0 {
languages = languagesFromConfig
} else {
languages = make(map[string]interface{})
for k, v := range languagesFromConfig {
isDisabled := false
for _, disabled := range disableLanguages {
if disabled == defaultLang {
return fmt.Errorf("cannot disable default language %q", defaultLang)
}

if strings.EqualFold(k, disabled) {
isDisabled = true
break
}
}
if !isDisabled {
languages[k] = v
}

}
}

var (
langs helpers.Languages
err error
)

if len(multilingual) == 0 {
if len(languages) == 0 {
langs = append(langs, helpers.NewDefaultLanguage(cfg))
} else {
langs, err = toSortedLanguages(cfg, multilingual)
langs, err = toSortedLanguages(cfg, languages)
if err != nil {
return fmt.Errorf("Failed to parse multilingual config: %s", err)
}
Expand Down Expand Up @@ -114,8 +144,6 @@ func loadLanguageSettings(cfg config.Provider, oldLangs helpers.Languages) error
}
}

defaultLang := cfg.GetString("defaultContentLanguage")

// The defaultContentLanguage is something the user has to decide, but it needs
// to match a language in the language definition list.
langExists := false
Expand Down
6 changes: 6 additions & 0 deletions hugolib/fileInfo.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,9 @@ type fileInfo struct {
bundleTp bundleDirType
source.ReadableFile
overriddenLang string

// Set if the content language for this file is disabled.
disabled bool
}

func (fi *fileInfo) Lang() string {
Expand Down Expand Up @@ -60,6 +63,9 @@ func newFileInfo(sp *source.SourceSpec, baseDir, filename string, fi os.FileInfo
ReadableFile: baseFi,
}

lang := f.Lang()
f.disabled = lang != "" && sp.DisabledLanguages[lang]

return f

}
Expand Down
36 changes: 26 additions & 10 deletions hugolib/page_bundler_capture.go
Original file line number Diff line number Diff line change
Expand Up @@ -149,8 +149,10 @@ func (c *capturer) capturePartial(filenames ...string) error {
// create the proper mapping for it.
c.getRealFileInfo(dir)

f := c.newFileInfo(resolvedFilename, fi, tp)
c.copyOrHandleSingle(f)
f, active := c.newFileInfo(resolvedFilename, fi, tp)
if active {
c.copyOrHandleSingle(f)
}
}
}

Expand Down Expand Up @@ -228,7 +230,10 @@ func (c *capturer) handleBranchDir(dirname string) error {

tp, isContent := classifyBundledFile(fi.Name())

f := c.newFileInfo(fi.filename, fi.FileInfo, tp)
f, active := c.newFileInfo(fi.filename, fi.FileInfo, tp)
if !active {
continue
}
if f.isOwner() {
dirs.addBundleHeader(f)
} else if !isContent {
Expand Down Expand Up @@ -309,7 +314,7 @@ func (c *capturer) handleDir(dirname string) error {
return c.handleNonBundle(dirname, files, state == dirStateSinglesOnly)
}

var fileInfos = make([]*fileInfo, len(files))
var fileInfos = make([]*fileInfo, 0, len(files))

for i, fi := range files {
currentType := bundleNot
Expand All @@ -324,8 +329,12 @@ func (c *capturer) handleDir(dirname string) error {
if bundleType == bundleNot && currentType != bundleNot {
bundleType = currentType
}
f, active := c.newFileInfo(fi.filename, fi.FileInfo, currentType)
if !active {
continue
}

fileInfos[i] = c.newFileInfo(fi.filename, fi.FileInfo, currentType)
fileInfos = append(fileInfos, f)
}

var todo []*fileInfo
Expand Down Expand Up @@ -377,8 +386,11 @@ func (c *capturer) handleNonBundle(
}
} else {
if singlesOnly {
file := c.newFileInfo(fi.filename, fi, bundleNot)
c.handler.handleSingles(file)
f, active := c.newFileInfo(fi.filename, fi, bundleNot)
if !active {
continue
}
c.handler.handleSingles(f)
} else {
c.handler.handleCopyFiles(fi.filename)
}
Expand Down Expand Up @@ -462,7 +474,10 @@ func (c *capturer) collectFiles(dirname string, handleFiles func(fis ...*fileInf
return err
}
} else {
handleFiles(c.newFileInfo(fi.filename, fi.FileInfo, bundleNot))
f, active := c.newFileInfo(fi.filename, fi.FileInfo, bundleNot)
if active {
handleFiles(f)
}
}
}

Expand Down Expand Up @@ -506,8 +521,9 @@ func (c *capturer) readDir(dirname string) ([]fileInfoName, error) {
return fis, nil
}

func (c *capturer) newFileInfo(filename string, fi os.FileInfo, tp bundleDirType) *fileInfo {
return newFileInfo(c.sourceSpec, c.baseDir, filename, fi, tp)
func (c *capturer) newFileInfo(filename string, fi os.FileInfo, tp bundleDirType) (*fileInfo, bool) {
f := newFileInfo(c.sourceSpec, c.baseDir, filename, fi, tp)
return f, !f.disabled
}

type fileInfoName struct {
Expand Down
1 change: 1 addition & 0 deletions hugolib/page_bundler_capture_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,7 @@ func TestPageBundlerCaptureMultilingual(t *testing.T) {
expected := `
F:
/work/base/1s/mypage.md
/work/base/1s/mypage.nn.md
/work/base/bb/_1.md
/work/base/bb/_1.nn.md
/work/base/bb/en.md
Expand Down
49 changes: 49 additions & 0 deletions hugolib/page_bundler_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,10 @@ func TestPageBundlerSiteMultilingual(t *testing.T) {

s := sites.Sites[0]

assert.Equal(8, len(s.RegularPages))
assert.Equal(18, len(s.Pages))
assert.Equal(35, len(s.AllPages))

bundleWithSubPath := s.getPage(KindPage, "lb/index")
assert.NotNil(bundleWithSubPath)

Expand All @@ -214,6 +218,8 @@ func TestPageBundlerSiteMultilingual(t *testing.T) {
assert.Equal(bfBundle, s.getPage(KindPage, "my-bf-bundle"))

nnSite := sites.Sites[1]
assert.Equal(7, len(nnSite.RegularPages))

bfBundleNN := nnSite.getPage(KindPage, "bf/my-bf-bundle/index")
assert.NotNil(bfBundleNN)
assert.Equal("nn", bfBundleNN.Lang())
Expand All @@ -233,6 +239,48 @@ func TestPageBundlerSiteMultilingual(t *testing.T) {
}
}

func TestMultilingualDisableDefaultLanguage(t *testing.T) {
t.Parallel()

assert := require.New(t)
cfg, _ := newTestBundleSourcesMultilingual(t)

cfg.Set("disableLanguages", []string{"en"})

err := loadDefaultSettingsFor(cfg)
assert.Error(err)
assert.Contains(err.Error(), "cannot disable default language")
}

func TestMultilingualDisableLanguage(t *testing.T) {
t.Parallel()

assert := require.New(t)
cfg, fs := newTestBundleSourcesMultilingual(t)
cfg.Set("disableLanguages", []string{"nn"})

assert.NoError(loadDefaultSettingsFor(cfg))
sites, err := NewHugoSites(deps.DepsCfg{Fs: fs, Cfg: cfg})
assert.NoError(err)
assert.Equal(1, len(sites.Sites))

assert.NoError(sites.Build(BuildCfg{}))

s := sites.Sites[0]

assert.Equal(8, len(s.RegularPages))
assert.Equal(18, len(s.Pages))
// No nn pages
assert.Equal(18, len(s.AllPages))
for _, p := range s.rawAllPages {
assert.True(p.Lang() != "nn")
}
for _, p := range s.AllPages {
assert.True(p.Lang() != "nn")
}

}

func TestPageBundlerSiteWitSymbolicLinksInContent(t *testing.T) {
assert := require.New(t)
cfg, fs, workDir := newTestBundleSymbolicSources(t)
Expand Down Expand Up @@ -509,6 +557,7 @@ TheContent.
writeSource(t, fs, filepath.Join(workDir, "layouts", "_default", "list.html"), layout)

writeSource(t, fs, filepath.Join(workDir, "base", "1s", "mypage.md"), pageContent)
writeSource(t, fs, filepath.Join(workDir, "base", "1s", "mypage.nn.md"), pageContent)
writeSource(t, fs, filepath.Join(workDir, "base", "1s", "mylogo.png"), "content")

writeSource(t, fs, filepath.Join(workDir, "base", "bb", "_index.md"), pageContent)
Expand Down
34 changes: 18 additions & 16 deletions hugolib/site.go
Original file line number Diff line number Diff line change
Expand Up @@ -1207,30 +1207,28 @@ func (s *Site) checkDirectories() (err error) {
}

type contentCaptureResultHandler struct {
contentProcessors map[string]*siteContentProcessor
defaultContentProcessor *siteContentProcessor
contentProcessors map[string]*siteContentProcessor
}

func (c *contentCaptureResultHandler) getContentProcessor(lang string) *siteContentProcessor {
proc, found := c.contentProcessors[lang]
if found {
return proc
}
return c.defaultContentProcessor
}

func (c *contentCaptureResultHandler) handleSingles(fis ...*fileInfo) {
for _, fi := range fis {
// May be connected to a language (content files)
proc, found := c.contentProcessors[fi.Lang()]
if !found {
panic("proc not found")
}
proc := c.getContentProcessor(fi.Lang())
proc.fileSinglesChan <- fi

}
}
func (c *contentCaptureResultHandler) handleBundles(d *bundleDirs) {
for _, b := range d.bundles {
lang := b.fi.Lang()

proc, found := c.contentProcessors[lang]
if !found {
panic("proc not found")
}
proc := c.getContentProcessor(b.fi.Lang())
proc.fileBundlesChan <- b

}
}

Expand All @@ -1247,13 +1245,17 @@ func (s *Site) readAndProcessContent(filenames ...string) error {

sourceSpec := source.NewSourceSpec(s.owner.Cfg, s.Fs)
baseDir := s.absContentDir()
defaultContentLanguage := s.SourceSpec.DefaultContentLanguage

contentProcessors := make(map[string]*siteContentProcessor)
var defaultContentProcessor *siteContentProcessor
sites := s.owner.langSite()
for k, v := range sites {
proc := newSiteContentProcessor(baseDir, len(filenames) > 0, v)
contentProcessors[k] = proc

if k == defaultContentLanguage {
defaultContentProcessor = proc
}
g.Go(func() error {
return proc.process(ctx)
})
Expand All @@ -1264,7 +1266,7 @@ func (s *Site) readAndProcessContent(filenames ...string) error {
bundleMap *contentChangeMap
)

mainHandler := &contentCaptureResultHandler{contentProcessors: contentProcessors}
mainHandler := &contentCaptureResultHandler{contentProcessors: contentProcessors, defaultContentProcessor: defaultContentProcessor}

if s.running() {
// Need to track changes.
Expand Down
Loading

0 comments on commit 66195bd

Please sign in to comment.