github.com/cozy/cozy-stack@v0.0.0-20240603063001-31110fa4cae1/pkg/i18n/i18n.go (about)

     1  package i18n
     2  
     3  import (
     4  	"fmt"
     5  	"html/template"
     6  	"regexp"
     7  	"strings"
     8  	"time"
     9  
    10  	"github.com/cozy/cozy-stack/pkg/consts"
    11  	"github.com/cozy/cozy-stack/pkg/logger"
    12  	"github.com/goodsign/monday"
    13  	"github.com/leonelquinteros/gotext"
    14  )
    15  
    16  var translations = make(map[string]*gotext.Po)
    17  
    18  // LoadLocale creates the translation object for a locale from the content of a .po file
    19  func LoadLocale(locale, contextName string, rawPO []byte) {
    20  	po := gotext.NewPo()
    21  	po.Parse(rawPO)
    22  	identifier := locale
    23  	if contextName != "" {
    24  		identifier = contextName + "/" + locale
    25  	}
    26  	translations[identifier] = po
    27  }
    28  
    29  // Translator returns a translation function of the locale specified
    30  func Translator(locale, contextName string) func(key string, vars ...interface{}) string {
    31  	return func(key string, vars ...interface{}) string {
    32  		return Translate(key, locale, contextName, vars...)
    33  	}
    34  }
    35  
    36  var boldRegexp = regexp.MustCompile(`\*\*(.*?)\*\*`)
    37  var newlineRegexp = regexp.MustCompile(`(\n)`)
    38  
    39  // TranslatorHTML returns a translation function of the locale specified, which
    40  // allow simple markup like **bold**.
    41  func TranslatorHTML(locale, contextName string) func(key string, vars ...interface{}) template.HTML {
    42  	return func(key string, vars ...interface{}) template.HTML {
    43  		translated := Translate(key, locale, contextName, vars...)
    44  		escaped := template.HTMLEscapeString(translated)
    45  		replaced := boldRegexp.ReplaceAllString(escaped, "<strong>$1</strong>")
    46  		replaced = newlineRegexp.ReplaceAllString(replaced, "<br />")
    47  		return template.HTML(replaced)
    48  	}
    49  }
    50  
    51  // Translate translates the given key on the specified locale.
    52  func Translate(key, locale, contextName string, vars ...interface{}) string {
    53  	if po, ok := translations[contextName+"/"+locale]; ok {
    54  		translated := po.Get(key)
    55  		if translated != key && translated != "" {
    56  			if len(vars) > 0 {
    57  				return fmt.Sprintf(translated, vars...)
    58  			}
    59  			return translated
    60  		}
    61  	}
    62  	if po, ok := translations[locale]; ok {
    63  		translated := po.Get(key)
    64  		if translated != key && translated != "" {
    65  			if len(vars) > 0 {
    66  				return fmt.Sprintf(translated, vars...)
    67  			}
    68  			return translated
    69  		}
    70  	}
    71  	if po, ok := translations[consts.DefaultLocale]; ok {
    72  		translated := po.Get(key, vars...)
    73  		if translated != key && translated != "" {
    74  			return translated
    75  		}
    76  	}
    77  	logger.WithNamespace("i18n").
    78  		Infof("Translation not found for key %q on locale %q", key, locale)
    79  	if strings.HasPrefix(key, " Permissions ") {
    80  		key = strings.Replace(key, "Permissions ", "", 1)
    81  	}
    82  	return fmt.Sprintf(key, vars...)
    83  }
    84  
    85  // LocalizeTime transforms a date+time in a string for the given locale.
    86  // The layout is in the same format as the one given to time.Format.
    87  func LocalizeTime(t time.Time, locale, layout string) string {
    88  	return monday.Format(t, layout, mondayLocale(locale))
    89  }
    90  
    91  func mondayLocale(locale string) monday.Locale {
    92  	switch locale {
    93  	case "de", "de_DE":
    94  		return monday.LocaleDeDE
    95  	case "es", "es_ES":
    96  		return monday.LocaleEsES
    97  	case "fr", "fr_FR":
    98  		return monday.LocaleFrFR
    99  	case "it", "it_IT":
   100  		return monday.LocaleItIT
   101  	case "ja", "ja_JP":
   102  		return monday.LocaleJaJP
   103  	case "nl", "nl_NL":
   104  		return monday.LocaleNlNL
   105  	case "pt", "pt_PT":
   106  		return monday.LocalePtPT
   107  	case "ru", "ru_RU":
   108  		return monday.LocaleRuRU
   109  	default:
   110  		return monday.LocaleEnUS
   111  	}
   112  }