2017-05-27 19:08:47 +02:00
package publicSettings
2017-05-07 02:32:32 +02:00
import (
2017-05-14 21:45:50 +02:00
"errors"
2017-05-09 01:44:41 +02:00
"fmt"
2017-05-13 22:52:10 +02:00
"html/template"
"net/http"
"path"
"path/filepath"
2017-05-17 07:58:40 +02:00
"github.com/NyaaPantsu/nyaa/config"
"github.com/NyaaPantsu/nyaa/model"
2017-05-11 15:12:19 +02:00
"github.com/nicksnyder/go-i18n/i18n"
2017-05-13 00:17:34 +02:00
"github.com/nicksnyder/go-i18n/i18n/language"
2017-05-07 23:05:41 +02:00
)
2017-05-07 02:32:32 +02:00
2017-05-26 12:12:52 +02:00
// UserRetriever : this interface is required to prevent a cyclic import between the languages and userService package.
2017-05-14 21:45:50 +02:00
type UserRetriever interface {
RetrieveCurrentUser ( r * http . Request ) ( model . User , error )
}
2017-05-26 12:12:52 +02:00
// TemplateTfunc : T func used in template
2017-05-21 00:38:28 +02:00
type TemplateTfunc func ( string , ... interface { } ) template . HTML
2017-05-14 21:45:50 +02:00
var (
2017-05-31 04:21:57 +02:00
defaultLanguage = config . Conf . I18n . DefaultLanguage
2017-05-26 12:12:52 +02:00
userRetriever UserRetriever
2017-05-14 21:45:50 +02:00
)
2017-05-26 12:12:52 +02:00
// InitI18n : Initialize the languages translation
2017-05-14 21:45:50 +02:00
func InitI18n ( conf config . I18nConfig , retriever UserRetriever ) error {
defaultLanguage = conf . DefaultLanguage
userRetriever = retriever
2017-05-31 04:21:57 +02:00
defaultFilepath := path . Join ( conf . Directory , defaultLanguage + ".all.json" )
2017-05-13 22:52:10 +02:00
err := i18n . LoadTranslationFile ( defaultFilepath )
if err != nil {
panic ( fmt . Sprintf ( "failed to load default translation file '%s': %v" , defaultFilepath , err ) )
}
2017-05-31 04:21:57 +02:00
paths , err := filepath . Glob ( path . Join ( conf . Directory , "*.json" ) )
2017-05-13 22:52:10 +02:00
if err != nil {
return fmt . Errorf ( "failed to get translation files: %v" , err )
}
2017-05-14 21:45:50 +02:00
for _ , file := range paths {
err := i18n . LoadTranslationFile ( file )
2017-05-13 22:52:10 +02:00
if err != nil {
2017-05-14 21:45:50 +02:00
return fmt . Errorf ( "failed to load translation file '%s': %v" , file , err )
2017-05-13 22:52:10 +02:00
}
}
return nil
}
2017-05-26 12:12:52 +02:00
// GetDefaultLanguage : returns the default language from config
2017-05-14 21:45:50 +02:00
func GetDefaultLanguage ( ) string {
return defaultLanguage
}
2017-05-26 12:12:52 +02:00
// TfuncAndLanguageWithFallback : When go-i18n finds a language with >0 translations, it uses it as the Tfunc
2017-05-09 20:24:37 +02:00
// However, if said language has a missing translation, it won't fallback to the "main" language
2017-05-13 00:17:34 +02:00
func TfuncAndLanguageWithFallback ( language string , languages ... string ) ( i18n . TranslateFunc , * language . Language , error ) {
2017-05-19 04:55:59 +02:00
fallbackLanguage := GetDefaultLanguage ( )
2017-05-09 20:24:37 +02:00
2017-05-19 04:55:59 +02:00
tFunc , tLang , err1 := i18n . TfuncAndLanguage ( language , languages ... )
// If fallbackLanguage fails, it will give the "id" field so we don't
// care about the error
fallbackT , fallbackTlang , _ := i18n . TfuncAndLanguage ( fallbackLanguage )
2017-05-09 20:24:37 +02:00
2017-05-19 04:55:59 +02:00
translateFunction := func ( translationID string , args ... interface { } ) string {
if translated := tFunc ( translationID , args ... ) ; translated != translationID {
2017-05-09 20:24:37 +02:00
return translated
}
return fallbackT ( translationID , args ... )
2017-05-19 04:55:59 +02:00
}
if err1 != nil {
tLang = fallbackTlang
}
return translateFunction , tLang , err1
2017-05-09 20:24:37 +02:00
}
2017-05-26 12:12:52 +02:00
// GetAvailableLanguages : Get languages available on the website
2017-05-10 21:45:39 +02:00
func GetAvailableLanguages ( ) ( languages map [ string ] string ) {
languages = make ( map [ string ] string )
var T i18n . TranslateFunc
for _ , languageTag := range i18n . LanguageTags ( ) {
T , _ = i18n . Tfunc ( languageTag )
/ * Translation files should have an ID with the translated language name .
If they don ' t , just use the languageTag * /
if languageName := T ( "language_name" ) ; languageName != "language_name" {
2017-05-11 15:12:19 +02:00
languages [ languageTag ] = languageName
2017-05-10 21:45:39 +02:00
} else {
languages [ languageTag ] = languageTag
}
}
return
}
2017-05-26 12:12:52 +02:00
// GetDefaultTfunc : Gets T func from default language
2017-05-14 21:45:50 +02:00
func GetDefaultTfunc ( ) ( i18n . TranslateFunc , error ) {
return i18n . Tfunc ( defaultLanguage )
}
2017-05-26 12:12:52 +02:00
// GetTfuncAndLanguageFromRequest : Gets the T func and chosen language from the request
2017-05-14 21:45:50 +02:00
func GetTfuncAndLanguageFromRequest ( r * http . Request ) ( T i18n . TranslateFunc , Tlang * language . Language ) {
2017-05-10 21:45:39 +02:00
userLanguage := ""
2017-05-21 02:12:29 +02:00
user , _ := getCurrentUser ( r )
if user . ID > 0 {
2017-05-11 15:12:19 +02:00
userLanguage = user . Language
2017-05-10 21:45:39 +02:00
}
2017-05-07 23:05:41 +02:00
cookie , err := r . Cookie ( "lang" )
cookieLanguage := ""
if err == nil {
cookieLanguage = cookie . Value
}
2017-05-10 21:45:39 +02:00
2017-05-19 04:55:59 +02:00
// go-i18n supports the format of the Accept-Language header
2017-05-07 23:05:41 +02:00
headerLanguage := r . Header . Get ( "Accept-Language" )
2017-05-19 04:55:59 +02:00
T , Tlang , _ = TfuncAndLanguageWithFallback ( userLanguage , cookieLanguage , headerLanguage )
2017-05-13 00:17:34 +02:00
return
}
2017-05-26 12:12:52 +02:00
// GetTfuncFromRequest : Gets the T func from the request
2017-05-21 00:38:28 +02:00
func GetTfuncFromRequest ( r * http . Request ) TemplateTfunc {
2017-05-14 21:45:50 +02:00
T , _ := GetTfuncAndLanguageFromRequest ( r )
2017-05-21 00:38:28 +02:00
return func ( id string , args ... interface { } ) template . HTML {
return template . HTML ( fmt . Sprintf ( T ( id ) , args ... ) )
}
2017-05-07 23:05:41 +02:00
}
2017-05-14 21:45:50 +02:00
2017-05-27 19:08:47 +02:00
// GetThemeFromRequest: Gets the user selected theme from the request
func GetThemeFromRequest ( r * http . Request ) string {
user , _ := getCurrentUser ( r )
if user . ID > 0 {
return user . Theme
}
cookie , err := r . Cookie ( "theme" )
if err == nil {
return cookie . Value
}
return ""
}
2017-05-31 04:21:35 +02:00
// GetThemeFromRequest: Gets the user selected theme from the request
func GetMascotFromRequest ( r * http . Request ) string {
user , _ := getCurrentUser ( r )
if user . ID > 0 {
return user . Mascot
}
cookie , err := r . Cookie ( "mascot" )
if err == nil {
return cookie . Value
}
return "show"
}
2017-05-14 21:45:50 +02:00
func getCurrentUser ( r * http . Request ) ( model . User , error ) {
if userRetriever == nil {
return model . User { } , errors . New ( "failed to get current user: no user retriever set" )
}
return userRetriever . RetrieveCurrentUser ( r )
}