Ctrl K
ComunidadGuías…

internal/app/langpack/parser.go

Rama main · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
package langpack

import (
	"fmt"
	"math"
	"os"
	"path/filepath"
	"regexp"
	"strconv"
	"strings"

	"telesrv/internal/domain"
)

var tdesktopStringRE = regexp.MustCompile(`(?s)"((?:\\.|[^"\\])*)"\s*=\s*"((?:\\.|[^"\\])*)";`)
var langPackNameRE = regexp.MustCompile(`^[a-z0-9][a-z0-9_-]{0,31}$`)
var langCodeRE = regexp.MustCompile(`^[a-z0-9]{1,16}(?:-[a-z0-9]{1,16})*$`)

// ParseTDesktopFile parses a client .strings file into a domain langpack.
func ParseTDesktopFile(path string) (domain.LangPack, error) {
	pack, err := packFromFilename(path)
	if err != nil {
		return domain.LangPack{}, err
	}
	data, err := os.ReadFile(path)
	if err != nil {
		return domain.LangPack{}, fmt.Errorf("read langpack %q: %w", path, err)
	}

	plain := make([]domain.LangPackString, 0)
	plurals := make(map[string]*domain.LangPackString)
	pluralOrder := make([]string, 0)
	for _, match := range tdesktopStringRE.FindAllStringSubmatch(string(data), -1) {
		key := unquoteTDesktop(match[1])
		value := unquoteTDesktop(match[2])
		base, plural := splitPluralKey(key)
		if plural == "" {
			plain = append(plain, domain.LangPackString{Key: key, Value: value})
			continue
		}
		item, ok := plurals[base]
		if !ok {
			plurals[base] = &domain.LangPackString{Key: base, Pluralized: true}
			item = plurals[base]
			pluralOrder = append(pluralOrder, base)
		}
		setPluralValue(item, plural, value)
	}

	pack.Strings = make([]domain.LangPackString, 0, len(plain)+len(pluralOrder))
	pack.Strings = append(pack.Strings, plain...)
	for _, key := range pluralOrder {
		pack.Strings = append(pack.Strings, *plurals[key])
	}
	return pack, nil
}

func packFromFilename(path string) (domain.LangPack, error) {
	name := strings.TrimSuffix(filepath.Base(path), filepath.Ext(path))
	idx := strings.LastIndex(name, "_v")
	if idx <= 0 || idx+2 >= len(name) {
		return domain.LangPack{}, fmt.Errorf("invalid langpack filename %q", filepath.Base(path))
	}
	version, err := strconv.Atoi(name[idx+2:])
	if err != nil {
		return domain.LangPack{}, fmt.Errorf("parse langpack version %q: %w", name[idx+2:], err)
	}

	head := name[:idx]
	dirPack := filepath.Base(filepath.Dir(path))
	prefix := dirPack + "_"
	langPack := ""
	langCode := ""
	if dirPack != "." && dirPack != "" && strings.HasPrefix(head, prefix) {
		langPack = dirPack
		langCode = strings.TrimPrefix(head, prefix)
	} else {
		sep := strings.Index(head, "_")
		if sep <= 0 || sep+1 >= len(head) {
			return domain.LangPack{}, fmt.Errorf("invalid langpack filename %q", filepath.Base(path))
		}
		langPack = head[:sep]
		langCode = head[sep+1:]
	}
	if langPack == "" || langCode == "" {
		return domain.LangPack{}, fmt.Errorf("invalid langpack filename %q", filepath.Base(path))
	}
	langPack = normalizePack(langPack)
	langCode = normalizeCode(langCode)
	if !langPackNameRE.MatchString(langPack) {
		return domain.LangPack{}, fmt.Errorf("invalid langpack name %q in %q", langPack, filepath.Base(path))
	}
	if len(langCode) > 64 || !langCodeRE.MatchString(langCode) {
		return domain.LangPack{}, fmt.Errorf("invalid language code %q in %q", langCode, filepath.Base(path))
	}
	if version <= 0 || version > math.MaxInt32 {
		return domain.LangPack{}, fmt.Errorf("invalid langpack version %d in %q", version, filepath.Base(path))
	}
	return domain.LangPack{
		LangPack: langPack,
		LangCode: langCode,
		Version:  version,
	}, nil
}

func splitPluralKey(key string) (base, plural string) {
	for _, suffix := range []string{"#zero", "#one", "#two", "#few", "#many", "#other"} {
		if strings.HasSuffix(key, suffix) {
			return strings.TrimSuffix(key, suffix), strings.TrimPrefix(suffix, "#")
		}
	}
	return key, ""
}

func setPluralValue(item *domain.LangPackString, plural, value string) {
	switch plural {
	case "zero":
		item.ZeroValue = value
	case "one":
		item.OneValue = value
	case "two":
		item.TwoValue = value
	case "few":
		item.FewValue = value
	case "many":
		item.ManyValue = value
	case "other":
		item.OtherValue = value
	}
}

func unquoteTDesktop(s string) string {
	v, err := strconv.Unquote(`"` + s + `"`)
	if err != nil {
		return s
	}
	return v
}