123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274 |
- package i18n
- import (
- "notabug.org/apiote/amuse/config"
- "bytes"
- "fmt"
- "golang.org/x/text/language"
- "html/template"
- "os"
- "path/filepath"
- "reflect"
- "regexp"
- "strings"
- "time"
- "github.com/BurntSushi/toml"
- "github.com/bytesparadise/libasciidoc"
- "github.com/bytesparadise/libasciidoc/pkg/configuration"
- "notabug.org/apiote/gott"
- )
- type Translation struct {
- Global map[string]string
- Index map[string]string
- Search map[string]string
- Film map[string]string
- Serie map[string]string
- Person map[string]string
- Book map[string]string
- BookSerie map[string]string
- About map[string]string
- Signup map[string]string
- Signedup map[string]string
- Login map[string]string
- Loggedout map[string]string
- Watchlist map[string]string
- Readlist map[string]string
- Tvqueue map[string]string
- Experiences map[string]string
- Error map[string]string
- Account map[string]string
- PremiereType map[int]string
- }
- var serverLangs []language.Tag
- func LoadServerLangs() error {
- var tags []string
- var defaultLocale string
- defaultLocaleIndex := -1
- err := filepath.Walk(config.DataHome+"/i18n", func(path string, info os.FileInfo, err error) error {
- if !info.IsDir() {
- if filepath.Ext(path) == ".toml" {
- tag := strings.Replace(filepath.Base(path), ".toml", "", 1)
- if tag == "default" {
- p, err := os.Readlink(path)
- if err != nil {
- return err
- }
- defaultLocale = strings.Replace(filepath.Base(p), ".toml", "", 1)
- } else {
- tags = append(tags, tag)
- }
- }
- }
- return nil
- })
- if err != nil {
- return err
- }
- for i, tag := range tags {
- if tag == defaultLocale {
- defaultLocaleIndex = i
- }
- }
- tags[0], tags[defaultLocaleIndex] = tags[defaultLocaleIndex], tags[0]
- for _, tag := range tags {
- serverLangs = append(serverLangs, language.Make(tag))
- }
- return nil
- }
- func Match(acceptLanguages []language.Tag) (language.Tag, error) {
- var matcher = language.NewMatcher(serverLangs)
- tag, _, _ := matcher.Match(acceptLanguages...)
- b, s, r := tag.Raw()
- t, err := language.Compose(b, s, r)
- return t, err
- }
- func loadStringsFile(args ...interface{}) (interface{}, error) {
- var (
- strings Translation
- err error
- )
- if langTag, ok := args[0].(language.Tag); ok {
- language := langTag.String()
- _, err = toml.DecodeFile(filepath.Join(config.DataHome+"/i18n", language+".toml"), &strings)
- }
- args[1] = strings
- return gott.Tuple(args), err
- }
- func loadDefaultStringsFile(args ...interface{}) (interface{}, error) {
- var strings Translation
- _, err := toml.DecodeFile(filepath.Join(config.DataHome+"/i18n", "default.toml"), &strings)
- args[2] = strings
- return gott.Tuple(args), err
- }
- func loadStrings(args ...interface{}) interface{} {
- strings := args[1].(Translation)
- defaultTranslation := args[2].(Translation)
- stringsValue := reflect.ValueOf(&strings).Elem()
- stringsType := stringsValue.Type()
- for i := 0; i < stringsValue.NumField(); i++ {
- stringsField := stringsValue.Field(i)
- if i == stringsValue.NumField()-1 {
- continue
- }
- if stringsField.IsNil() {
- stringsField.Set(reflect.MakeMap(reflect.TypeOf(map[string]string{})))
- }
- defaultValue := reflect.ValueOf(&defaultTranslation).Elem()
- for key, entry := range defaultValue.FieldByName(stringsType.Field(i).Name).Interface().(map[string]string) {
- if stringsField.Interface().(map[string]string)[key] == "" {
- stringsField.Interface().(map[string]string)[key] = entry
- }
- }
- }
- args[1] = strings
- return gott.Tuple(args)
- }
- func loadPremiereTypes(args ...interface{}) interface{} {
- strings := args[1].(Translation)
- strings.PremiereType = map[int]string{
- 1: "premiere_type_premiere",
- 2: "premiere_type_cinema_limited",
- 3: "premiere_type_cinema",
- 4: "premiere_type_digital",
- 5: "premiere_type_physical",
- 6: "premiere_type_tv",
- }
- args[1] = strings
- return gott.Tuple(args)
- }
- func LoadStrings(language language.Tag) (Translation, error) {
- r, err := gott.
- NewResult(gott.Tuple{language, Translation{}, Translation{}}).
- Bind(loadStringsFile).
- Bind(loadDefaultStringsFile).
- Map(loadStrings).
- Map(loadPremiereTypes).
- Finish()
- if err == nil {
- return r.(gott.Tuple)[1].(Translation), nil
- } else {
- return Translation{}, err
- }
- }
- func GetPremiereType(index int, translation Translation) string {
- return translation.Film[translation.PremiereType[index]]
- }
- func FormatDate(date time.Time, format string, translation map[string]string) string {
- format = strings.ReplaceAll(format, "%a", translation[date.Weekday().String()+"_short"])
- format = strings.ReplaceAll(format, "%A", translation[date.Weekday().String()])
- format = strings.ReplaceAll(format, "%b", translation[date.Month().String()+"_short"])
- format = strings.ReplaceAll(format, "%B", translation[date.Month().String()])
- // %c intentionally ommitted
- format = strings.ReplaceAll(format, "%C", fmt.Sprintf("%d", date.Year()/100))
- format = strings.ReplaceAll(format, "%d", fmt.Sprintf("%02d", date.Day()))
- format = strings.ReplaceAll(format, "%D", fmt.Sprintf("%02d/%02d/%02d", date.Month(), date.Day(), date.Year()%100))
- format = strings.ReplaceAll(format, "%e", fmt.Sprintf("%2d", date.Day()))
- format = strings.ReplaceAll(format, "%h", translation[date.Month().String()+"_short"])
- format = strings.ReplaceAll(format, "%H", fmt.Sprintf("%02d", date.Hour()))
- hour := date.Hour() % 12
- if hour == 0 {
- hour = 12
- }
- format = strings.ReplaceAll(format, "%I", fmt.Sprintf("%02d", hour))
- format = strings.ReplaceAll(format, "%j", fmt.Sprintf("%03d", date.YearDay()))
- format = strings.ReplaceAll(format, "%m", fmt.Sprintf("%02d", date.Month()))
- format = strings.ReplaceAll(format, "%M", fmt.Sprintf("%02d", date.Minute()))
- format = strings.ReplaceAll(format, "%n", "\n")
- // todo %p
- // %r intentionally ommitted
- format = strings.ReplaceAll(format, "%S", fmt.Sprintf("%02d", date.Second()))
- format = strings.ReplaceAll(format, "%t", "\t")
- format = strings.ReplaceAll(format, "%T", fmt.Sprintf("%02d:%02d:%02d", date.Hour(), date.Minute(), date.Second()%100))
- weekday := date.Weekday()
- if weekday == 0 {
- weekday = 7
- }
- format = strings.ReplaceAll(format, "%u", fmt.Sprintf("%d", weekday))
- // todo %U
- // todo %V
- format = strings.ReplaceAll(format, "%w", fmt.Sprintf("%d", date.Weekday()))
- // todo %W
- // %x intentionally ommitted
- // %X intentionally ommitted
- format = strings.ReplaceAll(format, "%y", fmt.Sprintf("%d", date.Year()%100))
- format = strings.ReplaceAll(format, "%Y", fmt.Sprintf("%d", date.Year()))
- zone, _ := date.Zone()
- format = strings.ReplaceAll(format, "%Z", zone)
- format = strings.ReplaceAll(format, "%%", "%")
- return format
- }
- func FormatDateNice(datetime time.Time, strings Translation, timezone string) string {
- t := time.Now()
- location, err := time.LoadLocation(timezone)
- if err != nil {
- return strings.Global["unknown"]
- }
- midnightToday := time.Date(t.Year(), t.Month(), t.Day(), 0, 0, 0, 0, location)
- midnightYester := midnightToday.Add(-24 * time.Hour)
- midnightEreyester := midnightYester.Add(-24 * time.Hour)
- midnightWeek := midnightToday.Add(-24 * 7 * time.Hour)
- midnightYear := time.Date(t.Year(), 1, 1, 0, 0, 0, 0, location)
- var dateFormat string
- if datetime.After(midnightToday) {
- dateFormat = strings.Global["experience_format_today"]
- } else if datetime.After(midnightYester) {
- dateFormat = strings.Global["experience_format_yesterday"]
- } else if datetime.After(midnightEreyester) {
- dateFormat = strings.Global["experience_format_ereyester"]
- } else if datetime.After(midnightWeek) {
- dateFormat = strings.Global["experience_format_week"]
- } else if datetime.After(midnightYear) {
- dateFormat = strings.Global["experience_format_year"]
- } else {
- dateFormat = strings.Global["experience_format_earlier"]
- }
- date := FormatDate(datetime, dateFormat, strings.Global)
- return date
- }
- func RenderAsciiDoc(asciidoc string) template.HTML {
- r := strings.NewReader(asciidoc)
- w := bytes.NewBuffer([]byte{})
- config := configuration.NewConfiguration()
- libasciidoc.Convert(r, w, config)
- output := bytes.ReplaceAll(w.Bytes(), []byte("\n"), []byte(""))
- divRegex, err := regexp.Compile("<\\/?div[^>]*>")
- if err != nil {
- return template.HTML("<span style=\"color: red;\">error rendering asciidoc (div regex)</span>")
- }
- pRegex, err := regexp.Compile("<\\/?p>")
- if err != nil {
- return template.HTML("<span style=\"color: red;\">error rendering asciidoc (p regex)</span>")
- }
- output = divRegex.ReplaceAll(output, []byte(""))
- output = pRegex.ReplaceAll(output, []byte(""))
- return template.HTML(output)
- }
- func GetErrorData(code int, translation Translation, part string) string {
- key := fmt.Sprintf("%d_%s", code, part)
- return translation.Error[key]
- }
|