深入理解Hugo - 组件设计之配置和语言的关系

174 阅读3分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第3天,点击查看活动详情 ,祝福祖国,生日快乐 :)

Hugo的组件设计

架构图可以帮助我们从全局视角理解Hugo的架构设计。 现在让我们更近一步,从模块的角度来观察Hugo架构的细节

配置和语言的关系

Hugo提供了强大的配置功能,如配置文件、配置目录、配置主题等等。 构建站点过程中,只要是你能想到的定制化需求,基本都能通过配置实现。

为了满足不同的定制化需求,Hugo的思路是首先要处理好多配置文件之间的关系,所以需要合并一些配置项,这样就需要大小写不敏感。 定制化只是一小部分,其它的通用信息,就用默认配置来进行说明。

支持多语言是常见需求,现在好多软件遵循的策略就是国际化优先。 那Hugo是怎么理解语言和配置的关系呢?

个人站点实例中,我们在config.toml中和语言相关的配置如下:

defaultContentLanguage = 'zh'
[languages]
[languages.zh]
  languageName = '中文'
  contentDir = 'content'
  weight = 1

[languages.en]
  languageName = 'English'
  contentDir = 'content.en'
  weight = 2

可以配置默认语言,支持的多语言有中文和英语。

那这样看来,配置应该包含语言。 也就是说语言应该是配置结构体中的一个字段。 而事实是这样的吗? 让我们还是从Hugo游乐场源码出发,来一探究竟。

在此之前,我们先从架构图中寻找线索: 3.1-hugo-arch-config-language.svg

可以看到,最终创建Language的地方是在DepsCfg,并不是Config。 这和我们的直觉是相反的,让我们来看看关键的config.Provider,DepsCfg和Language相关代码片断。

config.Provider

// Provider provides the configuration settings for Hugo.
type Provider interface {
   ...
   Get(key string) any
   Set(key string, value any)
   ...
}

可以看出,Provider接口提供了GetSet方法,就像一个key/value仓库。 那语言相关的配置同样也存储在了Provider里面。

DepsCfg

// DepsCfg contains configuration options that can be used to configure Hugo
// on a global level, i.e. logging etc.
// Nil values will be given default values.
type DepsCfg struct {
   // The language to use.
   Language *langs.Language
   
   // The configuration to use.
   Cfg config.Provider

   ...
}

DepsCfg中包含了config.Provider以及Language。

创建站点的时候,直接传入的就是DepsCfg:

// newSite creates a new site with the given configuration.
func newSite(cfg deps.DepsCfg) (*Site, error) {
   ...
}

在调用创建站点前,DepsCfg就已经把Language准备好了:

func createSitesFromConfig(cfg deps.DepsCfg) ([]*Site, error) {
   ...
   languages := getLanguages(cfg.Cfg)
   for _, lang := range languages {
      ... 
      cfg.Language = lang
      s, err = newSite(cfg)

      ...
   }
   return sites, nil
}

而从Language结构体可以看出:

// Language manages specific-language configuration.
type Language struct {
   Lang   string
   Weight int // for sort

   // Global config.
   // For internal use.
   Cfg config.Provider
   
   ...
}

Language是包含了Cfg config.Provider的。 也就是说Language和Config的关系实际上是包含关系,并不像我们上面感受到的那样。 仔细一想,合情合理。 Config专注提供配置key/value仓库管理服务,而Language和Site是一一对应的,需要其它配置信息补充说明。