From 2dbcbe6c5abe6ac9d7ae15fb75e8edd158466a69 Mon Sep 17 00:00:00 2001 From: sunwei Date: Mon, 30 Dec 2024 21:04:27 +0800 Subject: [PATCH] support multiple languages --- internal/domain/content/type.go | 4 + internal/domain/content/valueobject/site.go | 82 ++++++++++++++-- .../interfaces/api/handler/handlecontent.go | 8 +- pkg/language/language.go | 98 +++++++++++++++++++ 4 files changed, 183 insertions(+), 9 deletions(-) create mode 100644 pkg/language/language.go diff --git a/internal/domain/content/type.go b/internal/domain/content/type.go index f9fbdc4..c152ff2 100644 --- a/internal/domain/content/type.go +++ b/internal/domain/content/type.go @@ -53,6 +53,10 @@ const ( Pending Status = "pending" ) +type Unmarshalable interface { + UnmarshalJSON([]byte) error +} + // Hideable lets a user keep items hidden type Hideable interface { Hide(http.ResponseWriter, *http.Request) error diff --git a/internal/domain/content/valueobject/site.go b/internal/domain/content/valueobject/site.go index 99c4052..ce506b0 100644 --- a/internal/domain/content/valueobject/site.go +++ b/internal/domain/content/valueobject/site.go @@ -2,8 +2,10 @@ package valueobject import ( "bytes" + "encoding/json" "fmt" "github.com/gohugonet/hugoverse/pkg/editor" + "github.com/gohugonet/hugoverse/pkg/language" "net/http" "text/template" ) @@ -11,13 +13,14 @@ import ( type Site struct { Item - Title string `json:"title"` - Description string `json:"description"` - BaseURL string `json:"base_url"` - Theme string `json:"theme"` - Params string `json:"params"` - Owner string `json:"owner"` - WorkingDir string `json:"working_dir"` + Title string `json:"title"` + Description string `json:"description"` + BaseURL string `json:"base_url"` + Theme string `json:"theme"` + Params string `json:"params"` + Owner string `json:"owner"` + WorkingDir string `json:"working_dir"` + Languages []string `json:"languages"` } // MarshalEditor writes a buffer of html to edit a Song within the CMS @@ -73,6 +76,13 @@ func (s *Site) MarshalEditor() ([]byte, error) { "placeholder": "Enter the project file system dir here", }), }, + editor.Field{ + View: editor.Input("Languages", s, map[string]string{ + "label": "Languages", + "type": "text", + "placeholder": "Enter the Languages here", + }), + }, ) if err != nil { @@ -186,11 +196,28 @@ owner = "{{.Owner}}" [[module.imports]] path = "{{.Theme}}" +{{- if .IsMultiLanguages}} +[languages] +{{- range $index, $lang := .Languages }} + [languages.{{ $lang }}] + languageName = '{{ getLanguageName $lang }}' + contentDir = 'content.{{ $lang }}' + weight = {{ add $index 1 }} +{{- end }} +{{- end }} + [params] {{.Params}} ` - tmpl, err := template.New("toml").Parse(tomlTemplate) + funcMap := template.FuncMap{ + "add": func(a, b int) int { + return a + b + }, + "getLanguageName": language.GetLanguageName, + } + + tmpl, err := template.New("toml").Funcs(funcMap).Parse(tomlTemplate) if err != nil { return nil, fmt.Errorf("parse toml template error : %v", err) } @@ -202,3 +229,42 @@ owner = "{{.Owner}}" return result.Bytes(), nil } + +func (s *Site) IsMultiLanguages() bool { + return len(s.Languages) > 1 +} + +func (s *Site) UnmarshalJSON(data []byte) error { + // Create a temporary struct with the same fields + type Alias Site + temp := &struct { + Languages interface{} `json:"languages"` + *Alias + }{ + Alias: (*Alias)(s), + } + + // Unmarshal the JSON into the temp struct + if err := json.Unmarshal(data, &temp); err != nil { + return err + } + + // Handle the "languages" field + switch v := temp.Languages.(type) { + case nil: + // If it's nil or an empty string, set Languages as an empty array + s.Languages = []string{} + case string: + // If it's a single string, wrap it in an array + s.Languages = []string{v} + case []interface{}: + // If it's an array, convert it into a slice of strings + for _, item := range v { + if str, ok := item.(string); ok { + s.Languages = append(s.Languages, str) + } + } + } + + return nil +} diff --git a/internal/interfaces/api/handler/handlecontent.go b/internal/interfaces/api/handler/handlecontent.go index 05ca929..a006a28 100644 --- a/internal/interfaces/api/handler/handlecontent.go +++ b/internal/interfaces/api/handler/handlecontent.go @@ -142,7 +142,13 @@ func (s *Handler) getContent(res http.ResponseWriter, req *http.Request) { } p := pt() - err = json.Unmarshal(post, p) + + unmarshal, ok := p.(content.Unmarshalable) + if ok { + err = unmarshal.UnmarshalJSON(post) + } else { + err = json.Unmarshal(post, p) + } if err != nil { s.log.Errorf("Error unmarshalling content: %v", err) res.WriteHeader(http.StatusInternalServerError) diff --git a/pkg/language/language.go b/pkg/language/language.go new file mode 100644 index 0000000..9962541 --- /dev/null +++ b/pkg/language/language.go @@ -0,0 +1,98 @@ +package language + +import ( + "golang.org/x/text/language" +) + +const Unknown = "Unknown" + +func GetLanguageName(code string) string { + tag, err := language.Parse(code) + if err != nil { + return Unknown + } + + return tagToName[tag] +} + +var tagToName = map[language.Tag]string{ + language.Afrikaans: "Afrikaans", + language.Amharic: "Amharic", + language.Arabic: "Arabic", + language.ModernStandardArabic: "Modern Standard Arabic", + language.Azerbaijani: "Azerbaijani", + language.Bulgarian: "Bulgarian", + language.Bengali: "Bengali", + language.Catalan: "Catalan", + language.Czech: "Czech", + language.Danish: "Danish", + language.German: "German", + language.Greek: "Greek", + language.English: "English", + language.AmericanEnglish: "American English", + language.BritishEnglish: "British English", + language.Spanish: "Spanish", + language.EuropeanSpanish: "European Spanish", + language.LatinAmericanSpanish: "Latin American Spanish", + language.Estonian: "Estonian", + language.Persian: "Persian", + language.Finnish: "Finnish", + language.Filipino: "Filipino", + language.French: "French", + language.CanadianFrench: "Canadian French", + language.Gujarati: "Gujarati", + language.Hebrew: "Hebrew", + language.Hindi: "Hindi", + language.Croatian: "Croatian", + language.Hungarian: "Hungarian", + language.Armenian: "Armenian", + language.Indonesian: "Indonesian", + language.Icelandic: "Icelandic", + language.Italian: "Italian", + language.Japanese: "Japanese", + language.Georgian: "Georgian", + language.Kazakh: "Kazakh", + language.Khmer: "Khmer", + language.Kannada: "Kannada", + language.Korean: "Korean", + language.Kirghiz: "Kirghiz", + language.Lao: "Lao", + language.Lithuanian: "Lithuanian", + language.Latvian: "Latvian", + language.Macedonian: "Macedonian", + language.Malayalam: "Malayalam", + language.Mongolian: "Mongolian", + language.Marathi: "Marathi", + language.Malay: "Malay", + language.Burmese: "Burmese", + language.Nepali: "Nepali", + language.Dutch: "Dutch", + language.Norwegian: "Norwegian", + language.Punjabi: "Punjabi", + language.Polish: "Polish", + language.Portuguese: "Portuguese", + language.BrazilianPortuguese: "Brazilian Portuguese", + language.EuropeanPortuguese: "European Portuguese", + language.Romanian: "Romanian", + language.Russian: "Russian", + language.Sinhala: "Sinhala", + language.Slovak: "Slovak", + language.Slovenian: "Slovenian", + language.Albanian: "Albanian", + language.Serbian: "Serbian", + language.SerbianLatin: "Serbian (Latin)", + language.Swedish: "Swedish", + language.Swahili: "Swahili", + language.Tamil: "Tamil", + language.Telugu: "Telugu", + language.Thai: "Thai", + language.Turkish: "Turkish", + language.Ukrainian: "Ukrainian", + language.Urdu: "Urdu", + language.Uzbek: "Uzbek", + language.Vietnamese: "Vietnamese", + language.Chinese: "Chinese", + language.SimplifiedChinese: "Simplified Chinese", + language.TraditionalChinese: "Traditional Chinese", + language.Zulu: "Zulu", +}