【问题标题】:Yaml file to struct parsing (translation) in GolangYaml 文件在 Golang 中进行结构解析(翻译)
【发布时间】:2020-04-30 01:28:21
【问题描述】:

我正在尝试为我的 web 应用程序构建翻译功能。我的应用程序中有多个包。每个包(目录)都包含一个翻译文件夹和里面的 yaml 文件。但是我在解析并将其分配给消息时遇到问题。

en.yaml

msgLogin : "You've login successfully"

msgProducts:
  0: "You don't have any product."
  1: "You have %d product."
  2: "You have %d products."

errLogin: "Wrong password or username"

我的代码:

type TranslationEntry struct {
    Key struct {
        Value interface{}
    }
}

func parseTranslations(dir string) {
    files, _ := ioutil.ReadDir(dir)

    for _, f := range files {
        yamlFile, _ := ioutil.ReadFile(dir + "/" + f.Name())
        var data translation
        if err := yaml.Unmarshal(yamlFile, &data); err != nil {
            return nil, err
        }

        lang := strings.Split(f.Name(), ".")[0]
        switch msg := data.Key.Value.(type) {
        case string:
            message.SetString(language.Make(lang), cast.ToString(data.Key), cast.ToString(data.Key.Value))
        case map[int]string:
            message.Set(language.Make(lang), cast.ToString(data.Key),
                plural.Selectf(1, "%d",
                    "=0", cast.ToString(data.Key.Value["0"]),
                    "=1", cast.ToString(data.Key.Value["1"]),
                    "=2", cast.ToString(data.Key.Value["2"]),
                ))
        }

        translations[lang] = &dictionary{Data: data}
    }
}

我完全不知道如何设计我的结构或解析 yaml 文件。

谢谢你

【问题讨论】:

    标签: go yaml


    【解决方案1】:

    如果您正在使用我认为您正在使用的 YAML 库 (https://godoc.org/gopkg.in/yaml.v2),则可以创建一个 Golang 结构,该结构可以使用 Unmarshal 从您帖子中的 YAML 文件进行映射,您可以这样做:

    type TranslationEntry struct {
        MsgLogin string `yaml:"msgLogin"`
        MsgProducts map[int]string `yaml:"msgProducts"`
        ErrLogin string `yaml:"errLogin"`
    }
    

    在字段声明之后的``里面的东西叫做标签。它们是在某些数据类型和 Golang 结构之间映射时通常指定字段名称的方式(在我的情况下,通常我将结构映射到 JSON,但我也做过 YAML)。如果您使用的是我上面提到的相同 YAML 解析器,那么它就是这样工作的。

    基本上,双引号内的文本是您的结构字段将映射到的 YAML 键。在上面的代码中,YAML 键名和结构字段名之间的唯一区别是大写,但这里有一个使用完全不同名称的示例:

    type ExampleStruct struct {
        MyAbcField string `yaml:"abc"`
    }
    
    

    当使用 Unmarshal 和 ExampleStruct 和以下 YAML 时,这会将 MyAbcField 的值设置为 "my data"

    abc: "my data"
    

    这允许您设计一个匹配的 Golang 结构,但您决定构建您的 YAML。

    这是我在 Go Playground 中的上述代码:https://play.golang.org/p/Q9FvNsw-BOx

    现在,如果您无法修复 YAML 文件的结构,您还可以解析为嵌套映射。您可以通过将 interface{}(空接口)类型的变量而不是结构传递给 Unmarshal 来做到这一点。但是,这需要大量样板文件,因为您需要执行类型断言才能访问您的数据。因此,除非您绝对无法避免,否则我建议使用固定结构。

    这是一个示例,我解析您发布的 YAML,然后获取 msgLogin 字段:

    var data interface{}
    if err := yaml.Unmarshal([]byte(yamlFile), &data); err != nil {
        // handle error
    }
    
    // a type assertion that data is a map is needed in order to get keys or iterate
    topLevel, ok := data.(map[interface{}]interface{}) 
    if !ok {
        // handle error
    }
    
    fmt.Println(topLevel["msgLogin"])
    

    这是我的结构示例的 Go Playground,改为使用解析为嵌套地图:https://play.golang.org/p/ERBjClSazkz

    【讨论】:

    • 感谢您的回答。但有一个问题。您在结构中使用了 MsgLogin MsgProducts 等。这些是关键,并且在每个文件中都会有所不同。我该怎么做?
    • 啊我的错。当您在帖子中说“翻译”时,我以为您的意思是本地化。对于本地化,您将在每个文件中都有相同的键(我必须在英语和日语之间本地化很多)。听起来在您的情况下您需要解析为嵌套地图。给我一点时间检查一下。
    • 我在回复的底部添加了有关如何解析为嵌套地图的信息。如果可以的话,我建议您尝试使用固定格式的结构(以避免样板),但嵌套映射应该可以满足您的要求。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-04-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-01-23
    • 2019-01-20
    • 2019-01-17
    相关资源
    最近更新 更多