179 lines
4.2 KiB
Go
179 lines
4.2 KiB
Go
package parser
|
|
|
|
import (
|
|
"fmt"
|
|
"os"
|
|
"path/filepath"
|
|
"sort"
|
|
"strings"
|
|
)
|
|
|
|
// Translation for a text to translate
|
|
type Translation struct {
|
|
MsgId string
|
|
MsgIdPlural string
|
|
Context string
|
|
SourceLocations []string
|
|
}
|
|
|
|
// AddLocations to translation
|
|
func (t *Translation) AddLocations(locations []string) {
|
|
if t.SourceLocations == nil {
|
|
t.SourceLocations = locations
|
|
} else {
|
|
t.SourceLocations = append(t.SourceLocations, locations...)
|
|
}
|
|
}
|
|
|
|
// Dump translation as string
|
|
func (t *Translation) Dump() string {
|
|
data := make([]string, 0, len(t.SourceLocations)+5)
|
|
|
|
for _, location := range t.SourceLocations {
|
|
data = append(data, "#: "+location)
|
|
}
|
|
|
|
if t.Context != "" {
|
|
data = append(data, "msgctxt "+t.Context)
|
|
}
|
|
|
|
data = append(data, "msgid "+t.MsgId)
|
|
|
|
if t.MsgIdPlural == "" {
|
|
data = append(data, "msgstr \"\"")
|
|
} else {
|
|
data = append(data,
|
|
"msgid_plural "+t.MsgIdPlural,
|
|
"msgstr[0] \"\"",
|
|
"msgstr[1] \"\"")
|
|
}
|
|
|
|
return strings.Join(data, "\n")
|
|
}
|
|
|
|
// TranslationMap contains a map of translations with the ID as key
|
|
type TranslationMap map[string]*Translation
|
|
|
|
// Dump the translation map as string
|
|
func (m TranslationMap) Dump() string {
|
|
// sort by translation id for consistence output
|
|
keys := make([]string, 0, len(m))
|
|
for k := range m {
|
|
keys = append(keys, k)
|
|
}
|
|
sort.Strings(keys)
|
|
|
|
data := make([]string, 0, len(m))
|
|
for _, key := range keys {
|
|
data = append(data, (m)[key].Dump())
|
|
}
|
|
return strings.Join(data, "\n\n")
|
|
}
|
|
|
|
// Domain holds all translations of one domain
|
|
type Domain struct {
|
|
Translations TranslationMap
|
|
ContextTranslations map[string]TranslationMap
|
|
}
|
|
|
|
// AddTranslation to the domain
|
|
func (d *Domain) AddTranslation(translation *Translation) {
|
|
if d.Translations == nil {
|
|
d.Translations = make(TranslationMap)
|
|
d.ContextTranslations = make(map[string]TranslationMap)
|
|
}
|
|
|
|
if translation.Context == "" {
|
|
if t, ok := d.Translations[translation.MsgId]; ok {
|
|
t.AddLocations(translation.SourceLocations)
|
|
} else {
|
|
d.Translations[translation.MsgId] = translation
|
|
}
|
|
} else {
|
|
if _, ok := d.ContextTranslations[translation.Context]; !ok {
|
|
d.ContextTranslations[translation.Context] = make(TranslationMap)
|
|
}
|
|
|
|
if t, ok := d.ContextTranslations[translation.Context][translation.MsgId]; ok {
|
|
t.AddLocations(translation.SourceLocations)
|
|
} else {
|
|
d.ContextTranslations[translation.Context][translation.MsgId] = translation
|
|
}
|
|
}
|
|
}
|
|
|
|
// Dump the domain as string
|
|
func (d *Domain) Dump() string {
|
|
data := make([]string, 0, len(d.ContextTranslations)+1)
|
|
data = append(data, d.Translations.Dump())
|
|
|
|
// sort context translations by context for consistence output
|
|
keys := make([]string, 0, len(d.ContextTranslations))
|
|
for k := range d.ContextTranslations {
|
|
keys = append(keys, k)
|
|
}
|
|
sort.Strings(keys)
|
|
|
|
for _, key := range keys {
|
|
data = append(data, d.ContextTranslations[key].Dump())
|
|
}
|
|
return strings.Join(data, "\n\n")
|
|
}
|
|
|
|
// Save domain to file
|
|
func (d *Domain) Save(path string) error {
|
|
file, err := os.Create(path)
|
|
if err != nil {
|
|
return fmt.Errorf("failed to domain: %w", err)
|
|
}
|
|
defer file.Close()
|
|
|
|
// write header
|
|
_, err = file.WriteString(`msgid ""
|
|
msgstr ""
|
|
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
|
"MIME-Version: 1.0\n"
|
|
"Content-Type: text/plain; charset=UTF-8\n"
|
|
"Content-Transfer-Encoding: 8bit\n"
|
|
"Language: \n"
|
|
"X-Generator: xgotext\n"
|
|
|
|
`)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
// write domain content
|
|
_, err = file.WriteString(d.Dump())
|
|
return err
|
|
}
|
|
|
|
// DomainMap contains multiple domains as map with name as key
|
|
type DomainMap map[string]*Domain
|
|
|
|
// AddTranslation to domain map
|
|
func (m *DomainMap) AddTranslation(domain string, translation *Translation) {
|
|
if _, ok := (*m)[domain]; !ok {
|
|
(*m)[domain] = new(Domain)
|
|
}
|
|
(*m)[domain].AddTranslation(translation)
|
|
}
|
|
|
|
// Save domains to directory
|
|
func (m *DomainMap) Save(directory string) error {
|
|
// ensure output directory exist
|
|
err := os.MkdirAll(directory, os.ModePerm)
|
|
if err != nil {
|
|
return fmt.Errorf("failed to create output dir: %w", err)
|
|
}
|
|
|
|
// save each domain in a separate po file
|
|
for name, domain := range *m {
|
|
err := domain.Save(filepath.Join(directory, name+".po"))
|
|
if err != nil {
|
|
return fmt.Errorf("failed to save domain %s: %w", name, err)
|
|
}
|
|
}
|
|
return nil
|
|
}
|