mirror of
https://github.com/miniflux/v2.git
synced 2025-07-27 17:28:38 +00:00
First commit
This commit is contained in:
commit
8ffb773f43
2121 changed files with 1118910 additions and 0 deletions
47
locale/language.go
Normal file
47
locale/language.go
Normal file
|
@ -0,0 +1,47 @@
|
|||
// Copyright 2017 Frédéric Guillot. All rights reserved.
|
||||
// Use of this source code is governed by the Apache 2.0
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package locale
|
||||
|
||||
import "fmt"
|
||||
|
||||
type Language struct {
|
||||
language string
|
||||
translations Translation
|
||||
}
|
||||
|
||||
func (l *Language) Get(key string, args ...interface{}) string {
|
||||
var translation string
|
||||
|
||||
str, found := l.translations[key]
|
||||
if !found {
|
||||
translation = key
|
||||
} else {
|
||||
translation = str.(string)
|
||||
}
|
||||
|
||||
return fmt.Sprintf(translation, args...)
|
||||
}
|
||||
|
||||
func (l *Language) Plural(key string, n int, args ...interface{}) string {
|
||||
translation := key
|
||||
slices, found := l.translations[key]
|
||||
if found {
|
||||
|
||||
pluralForm, found := pluralForms[l.language]
|
||||
if !found {
|
||||
pluralForm = pluralForms["default"]
|
||||
}
|
||||
|
||||
index := pluralForm(n)
|
||||
translations := slices.([]interface{})
|
||||
translation = key
|
||||
|
||||
if len(translations) > index {
|
||||
translation = translations[index].(string)
|
||||
}
|
||||
}
|
||||
|
||||
return fmt.Sprintf(translation, args...)
|
||||
}
|
30
locale/locale.go
Normal file
30
locale/locale.go
Normal file
|
@ -0,0 +1,30 @@
|
|||
// Copyright 2017 Frédéric Guillot. All rights reserved.
|
||||
// Use of this source code is governed by the Apache 2.0
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package locale
|
||||
|
||||
import "log"
|
||||
|
||||
type Translation map[string]interface{}
|
||||
|
||||
type Locales map[string]Translation
|
||||
|
||||
func Load() *Translator {
|
||||
translator := NewTranslator()
|
||||
|
||||
for language, translations := range Translations {
|
||||
log.Println("Loading translation:", language)
|
||||
translator.AddLanguage(language, translations)
|
||||
}
|
||||
|
||||
return translator
|
||||
}
|
||||
|
||||
// GetAvailableLanguages returns the list of available languages.
|
||||
func GetAvailableLanguages() map[string]string {
|
||||
return map[string]string{
|
||||
"en_US": "English",
|
||||
"fr_FR": "Français",
|
||||
}
|
||||
}
|
103
locale/locale_test.go
Normal file
103
locale/locale_test.go
Normal file
|
@ -0,0 +1,103 @@
|
|||
// Copyright 2017 Frédéric Guillot. All rights reserved.
|
||||
// Use of this source code is governed by the Apache 2.0
|
||||
// license that can be found in the LICENSE file.
|
||||
package locale
|
||||
|
||||
import "testing"
|
||||
|
||||
func TestTranslateWithMissingLanguage(t *testing.T) {
|
||||
translator := NewTranslator()
|
||||
translation := translator.GetLanguage("en_US").Get("auth.username")
|
||||
|
||||
if translation != "auth.username" {
|
||||
t.Errorf("Wrong translation, got %s", translation)
|
||||
}
|
||||
}
|
||||
|
||||
func TestTranslateWithExistingKey(t *testing.T) {
|
||||
data := `{"auth.username": "Username"}`
|
||||
translator := NewTranslator()
|
||||
translator.AddLanguage("en_US", data)
|
||||
translation := translator.GetLanguage("en_US").Get("auth.username")
|
||||
|
||||
if translation != "Username" {
|
||||
t.Errorf("Wrong translation, got %s", translation)
|
||||
}
|
||||
}
|
||||
|
||||
func TestTranslateWithMissingKey(t *testing.T) {
|
||||
data := `{"auth.username": "Username"}`
|
||||
translator := NewTranslator()
|
||||
translator.AddLanguage("en_US", data)
|
||||
translation := translator.GetLanguage("en_US").Get("auth.password")
|
||||
|
||||
if translation != "auth.password" {
|
||||
t.Errorf("Wrong translation, got %s", translation)
|
||||
}
|
||||
}
|
||||
|
||||
func TestTranslateWithMissingKeyAndPlaceholder(t *testing.T) {
|
||||
translator := NewTranslator()
|
||||
translator.AddLanguage("fr_FR", "")
|
||||
translation := translator.GetLanguage("fr_FR").Get("Status: %s", "ok")
|
||||
|
||||
if translation != "Status: ok" {
|
||||
t.Errorf("Wrong translation, got %s", translation)
|
||||
}
|
||||
}
|
||||
|
||||
func TestTranslatePluralWithDefaultRule(t *testing.T) {
|
||||
data := `{"number_of_users": ["Il y a %d utilisateur (%s)", "Il y a %d utilisateurs (%s)"]}`
|
||||
translator := NewTranslator()
|
||||
translator.AddLanguage("fr_FR", data)
|
||||
language := translator.GetLanguage("fr_FR")
|
||||
|
||||
translation := language.Plural("number_of_users", 1, 1, "some text")
|
||||
expected := "Il y a 1 utilisateur (some text)"
|
||||
if translation != expected {
|
||||
t.Errorf(`Wrong translation, got "%s" instead of "%s"`, translation, expected)
|
||||
}
|
||||
|
||||
translation = language.Plural("number_of_users", 2, 2, "some text")
|
||||
expected = "Il y a 2 utilisateurs (some text)"
|
||||
if translation != expected {
|
||||
t.Errorf(`Wrong translation, got "%s" instead of "%s"`, translation, expected)
|
||||
}
|
||||
}
|
||||
|
||||
func TestTranslatePluralWithRussianRule(t *testing.T) {
|
||||
data := `{"key": ["из %d книги за %d день", "из %d книг за %d дня", "из %d книг за %d дней"]}`
|
||||
translator := NewTranslator()
|
||||
translator.AddLanguage("ru_RU", data)
|
||||
language := translator.GetLanguage("ru_RU")
|
||||
|
||||
translation := language.Plural("key", 1, 1, 1)
|
||||
expected := "из 1 книги за 1 день"
|
||||
if translation != expected {
|
||||
t.Errorf(`Wrong translation, got "%s" instead of "%s"`, translation, expected)
|
||||
}
|
||||
|
||||
translation = language.Plural("key", 2, 2, 2)
|
||||
expected = "из 2 книг за 2 дня"
|
||||
if translation != expected {
|
||||
t.Errorf(`Wrong translation, got "%s" instead of "%s"`, translation, expected)
|
||||
}
|
||||
|
||||
translation = language.Plural("key", 5, 5, 5)
|
||||
expected = "из 5 книг за 5 дней"
|
||||
if translation != expected {
|
||||
t.Errorf(`Wrong translation, got "%s" instead of "%s"`, translation, expected)
|
||||
}
|
||||
}
|
||||
|
||||
func TestTranslatePluralWithMissingTranslation(t *testing.T) {
|
||||
translator := NewTranslator()
|
||||
translator.AddLanguage("fr_FR", "")
|
||||
language := translator.GetLanguage("fr_FR")
|
||||
|
||||
translation := language.Plural("number_of_users", 2)
|
||||
expected := "number_of_users"
|
||||
if translation != expected {
|
||||
t.Errorf(`Wrong translation, got "%s" instead of "%s"`, translation, expected)
|
||||
}
|
||||
}
|
101
locale/plurals.go
Normal file
101
locale/plurals.go
Normal file
|
@ -0,0 +1,101 @@
|
|||
// Copyright 2017 Frédéric Guillot. All rights reserved.
|
||||
// Use of this source code is governed by the Apache 2.0
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package locale
|
||||
|
||||
// See https://localization-guide.readthedocs.io/en/latest/l10n/pluralforms.html
|
||||
// And http://www.unicode.org/cldr/charts/29/supplemental/language_plural_rules.html
|
||||
var pluralForms = map[string]func(n int) int{
|
||||
// nplurals=2; plural=(n != 1);
|
||||
"default": func(n int) int {
|
||||
if n != 1 {
|
||||
return 1
|
||||
}
|
||||
|
||||
return 0
|
||||
},
|
||||
// nplurals=6; plural=(n==0 ? 0 : n==1 ? 1 : n==2 ? 2 : n%100>=3 && n%100<=10 ? 3 : n%100>=11 ? 4 : 5);
|
||||
"ar_AR": func(n int) int {
|
||||
if n == 0 {
|
||||
return 0
|
||||
}
|
||||
|
||||
if n == 1 {
|
||||
return 1
|
||||
}
|
||||
|
||||
if n == 2 {
|
||||
return 2
|
||||
}
|
||||
|
||||
if n%100 >= 3 && n%100 <= 10 {
|
||||
return 3
|
||||
}
|
||||
|
||||
if n%100 >= 11 {
|
||||
return 4
|
||||
}
|
||||
|
||||
return 5
|
||||
},
|
||||
// nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2;
|
||||
"cs_CZ": func(n int) int {
|
||||
if n == 1 {
|
||||
return 0
|
||||
}
|
||||
|
||||
if n >= 2 && n <= 4 {
|
||||
return 1
|
||||
}
|
||||
|
||||
return 2
|
||||
},
|
||||
// nplurals=3; plural=(n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);
|
||||
"pl_PL": func(n int) int {
|
||||
if n == 1 {
|
||||
return 0
|
||||
}
|
||||
|
||||
if n%10 >= 2 && n%10 <= 4 && (n%100 < 10 || n%100 >= 20) {
|
||||
return 1
|
||||
}
|
||||
|
||||
return 2
|
||||
},
|
||||
// nplurals=2; plural=(n > 1);
|
||||
"pt_BR": func(n int) int {
|
||||
if n > 1 {
|
||||
return 1
|
||||
}
|
||||
return 0
|
||||
},
|
||||
// nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);
|
||||
"ru_RU": func(n int) int {
|
||||
if n%10 == 1 && n%100 != 11 {
|
||||
return 0
|
||||
}
|
||||
|
||||
if n%10 >= 2 && n%10 <= 4 && (n%100 < 10 || n%100 >= 20) {
|
||||
return 1
|
||||
}
|
||||
|
||||
return 2
|
||||
},
|
||||
// nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);
|
||||
"sr_RS": func(n int) int {
|
||||
if n%10 == 1 && n%100 != 11 {
|
||||
return 0
|
||||
}
|
||||
|
||||
if n%10 >= 2 && n%10 <= 4 && (n%100 < 10 || n%100 >= 20) {
|
||||
return 1
|
||||
}
|
||||
|
||||
return 2
|
||||
},
|
||||
// nplurals=1; plural=0;
|
||||
"zh_CN": func(n int) int {
|
||||
return 0
|
||||
},
|
||||
}
|
136
locale/translations.go
Normal file
136
locale/translations.go
Normal file
|
@ -0,0 +1,136 @@
|
|||
// Code generated by go generate; DO NOT EDIT.
|
||||
// 2017-11-19 22:01:21.925268372 -0800 PST m=+0.006101515
|
||||
|
||||
package locale
|
||||
|
||||
var Translations = map[string]string{
|
||||
"en_US": `{
|
||||
"plural.feed.error_count": [
|
||||
"%d error",
|
||||
"%d errors"
|
||||
],
|
||||
"plural.categories.feed_count": [
|
||||
"There is %d feed.",
|
||||
"There are %d feeds."
|
||||
]
|
||||
}`,
|
||||
"fr_FR": `{
|
||||
"plural.feed.error_count": [
|
||||
"%d erreur",
|
||||
"%d erreurs"
|
||||
],
|
||||
"plural.categories.feed_count": [
|
||||
"Il y %d abonnement.",
|
||||
"Il y %d abonnements."
|
||||
],
|
||||
"Username": "Nom d'utilisateur",
|
||||
"Password": "Mot de passe",
|
||||
"Unread": "Non lus",
|
||||
"History": "Historique",
|
||||
"Feeds": "Abonnements",
|
||||
"Categories": "Catégories",
|
||||
"Settings": "Réglages",
|
||||
"Logout": "Se déconnecter",
|
||||
"Next": "Suivant",
|
||||
"Previous": "Précédent",
|
||||
"New Subscription": "Nouvel Abonnment",
|
||||
"Import": "Importation",
|
||||
"Export": "Exportation",
|
||||
"There is no category. You must have at least one category.": "Il n'y a aucune catégorie. Vous devez avoir au moins une catégorie.",
|
||||
"URL": "URL",
|
||||
"Category": "Catégorie",
|
||||
"Find a subscription": "Trouver un abonnement",
|
||||
"Loading...": "Chargement...",
|
||||
"Create a category": "Créer une catégorie",
|
||||
"There is no category.": "Il n'y a aucune catégorie.",
|
||||
"Edit": "Modifier",
|
||||
"Remove": "Supprimer",
|
||||
"No feed.": "Aucun abonnement.",
|
||||
"There is no article in this category.": "Il n'y a aucun article dans cette catégorie.",
|
||||
"Original": "Original",
|
||||
"Mark this page as read": "Marquer cette page comme lu",
|
||||
"not yet": "pas encore",
|
||||
"just now": "à l'instant",
|
||||
"1 minute ago": "il y a une minute",
|
||||
"%d minutes ago": "il y a %d minutes",
|
||||
"1 hour ago": "il y a une heure",
|
||||
"%d hours ago": "il y a %d heures",
|
||||
"yesterday": "hier",
|
||||
"%d days ago": "il y a %d jours",
|
||||
"%d weeks ago": "il y a %d semaines",
|
||||
"%d months ago": "il y a %d mois",
|
||||
"%d years ago": "il y a %d années",
|
||||
"Date": "Date",
|
||||
"IP Address": "Adresse IP",
|
||||
"User Agent": "Navigateur Web",
|
||||
"Actions": "Actions",
|
||||
"Current session": "Session actuelle",
|
||||
"Sessions": "Sessions",
|
||||
"Users": "Utilisateurs",
|
||||
"Add user": "Ajouter un utilisateur",
|
||||
"Choose a Subscription": "Choisissez un abonnement",
|
||||
"Subscribe": "S'abonner",
|
||||
"New Category": "Nouvelle Catégorie",
|
||||
"Title": "Titre",
|
||||
"Save": "Sauvegarder",
|
||||
"or": "ou",
|
||||
"cancel": "annuler",
|
||||
"New User": "Nouvel Utilisateur",
|
||||
"Confirmation": "Confirmation",
|
||||
"Administrator": "Administrateur",
|
||||
"Edit Category: %s": "Modification de la catégorie : %s",
|
||||
"Update": "Mettre à jour",
|
||||
"Edit Feed: %s": "Modification de l'abonnement : %s",
|
||||
"There is no category!": "Il n'y a aucune catégorie !",
|
||||
"Edit user: %s": "Modification de l'utilisateur : %s",
|
||||
"There is no article for this feed.": "Il n'y a aucun article pour cet abonnement.",
|
||||
"Add subscription": "Ajouter un abonnement",
|
||||
"You don't have any subscription.": "Vous n'avez aucun abonnement",
|
||||
"Last check:": "Dernière vérification :",
|
||||
"Refresh": "Actualiser",
|
||||
"There is no history at the moment.": "Il n'y a aucun historique pour le moment.",
|
||||
"OPML file": "Fichier OPML",
|
||||
"Sign In": "Connexion",
|
||||
"Sign in": "Connexion",
|
||||
"Theme": "Thème",
|
||||
"Timezone": "Fuseau horaire",
|
||||
"Language": "Langue",
|
||||
"There is no unread article.": "Il n'y a rien de nouveau à lire.",
|
||||
"You are the only user.": "Vous êtes le seul utilisateur.",
|
||||
"Last Login": "Dernière connexion",
|
||||
"Yes": "Oui",
|
||||
"No": "Non",
|
||||
"This feed already exists (%s).": "Cet abonnement existe déjà (%s).",
|
||||
"Unable to fetch feed (statusCode=%d).": "Impossible de récupérer cet abonnement (code=%d).",
|
||||
"Unable to open this link: %v": "Impossible d'ouvrir ce lien : %v",
|
||||
"Unable to analyze this page: %v": "Impossible d'analyzer cette page : %v",
|
||||
"Unable to find any subscription.": "Impossible de trouver un abonnement.",
|
||||
"The URL and the category are mandatory.": "L'URL et la catégorie sont obligatoire.",
|
||||
"All fields are mandatory.": "Tous les champs sont obligatoire.",
|
||||
"Passwords are not the same.": "Les mots de passe ne sont pas les mêmes.",
|
||||
"You must use at least 6 characters.": "Vous devez utiliser au moins 6 caractères.",
|
||||
"The username is mandatory.": "Le nom d'utilisateur est obligatoire.",
|
||||
"The username, theme, language and timezone fields are mandatory.": "Le nom d'utilisateur, le thème, la langue et le fuseau horaire sont obligatoire.",
|
||||
"The title is mandatory.": "Le titre est obligatoire.",
|
||||
"About": "A propos",
|
||||
"version": "Version",
|
||||
"Version:": "Version :",
|
||||
"Build Date:": "Date de la compilation :",
|
||||
"Author:": "Auteur :",
|
||||
"Authors": "Auteurs",
|
||||
"License:": "Licence :",
|
||||
"Attachments": "Pièces jointes",
|
||||
"Download": "Télécharger",
|
||||
"Invalid username or password.": "Mauvais identifiant ou mot de passe.",
|
||||
"Never": "Jamais",
|
||||
"Unable to execute request: %v": "Impossible d'exécuter cette requête: %v",
|
||||
"Last Parsing Error": "Dernière erreur d'analyse",
|
||||
"There is a problem with this feed": "Il y a un problème avec cet abonnement"
|
||||
}
|
||||
`,
|
||||
}
|
||||
|
||||
var TranslationsChecksums = map[string]string{
|
||||
"en_US": "6fe95384260941e8a5a3c695a655a932e0a8a6a572c1e45cb2b1ae8baa01b897",
|
||||
"fr_FR": "1f75e5a4b581755f7f84687126bc5b96aaf0109a2f83a72a8770c2ad3ddb7ba3",
|
||||
}
|
10
locale/translations/en_US.json
Normal file
10
locale/translations/en_US.json
Normal file
|
@ -0,0 +1,10 @@
|
|||
{
|
||||
"plural.feed.error_count": [
|
||||
"%d error",
|
||||
"%d errors"
|
||||
],
|
||||
"plural.categories.feed_count": [
|
||||
"There is %d feed.",
|
||||
"There are %d feeds."
|
||||
]
|
||||
}
|
113
locale/translations/fr_FR.json
Normal file
113
locale/translations/fr_FR.json
Normal file
|
@ -0,0 +1,113 @@
|
|||
{
|
||||
"plural.feed.error_count": [
|
||||
"%d erreur",
|
||||
"%d erreurs"
|
||||
],
|
||||
"plural.categories.feed_count": [
|
||||
"Il y %d abonnement.",
|
||||
"Il y %d abonnements."
|
||||
],
|
||||
"Username": "Nom d'utilisateur",
|
||||
"Password": "Mot de passe",
|
||||
"Unread": "Non lus",
|
||||
"History": "Historique",
|
||||
"Feeds": "Abonnements",
|
||||
"Categories": "Catégories",
|
||||
"Settings": "Réglages",
|
||||
"Logout": "Se déconnecter",
|
||||
"Next": "Suivant",
|
||||
"Previous": "Précédent",
|
||||
"New Subscription": "Nouvel Abonnment",
|
||||
"Import": "Importation",
|
||||
"Export": "Exportation",
|
||||
"There is no category. You must have at least one category.": "Il n'y a aucune catégorie. Vous devez avoir au moins une catégorie.",
|
||||
"URL": "URL",
|
||||
"Category": "Catégorie",
|
||||
"Find a subscription": "Trouver un abonnement",
|
||||
"Loading...": "Chargement...",
|
||||
"Create a category": "Créer une catégorie",
|
||||
"There is no category.": "Il n'y a aucune catégorie.",
|
||||
"Edit": "Modifier",
|
||||
"Remove": "Supprimer",
|
||||
"No feed.": "Aucun abonnement.",
|
||||
"There is no article in this category.": "Il n'y a aucun article dans cette catégorie.",
|
||||
"Original": "Original",
|
||||
"Mark this page as read": "Marquer cette page comme lu",
|
||||
"not yet": "pas encore",
|
||||
"just now": "à l'instant",
|
||||
"1 minute ago": "il y a une minute",
|
||||
"%d minutes ago": "il y a %d minutes",
|
||||
"1 hour ago": "il y a une heure",
|
||||
"%d hours ago": "il y a %d heures",
|
||||
"yesterday": "hier",
|
||||
"%d days ago": "il y a %d jours",
|
||||
"%d weeks ago": "il y a %d semaines",
|
||||
"%d months ago": "il y a %d mois",
|
||||
"%d years ago": "il y a %d années",
|
||||
"Date": "Date",
|
||||
"IP Address": "Adresse IP",
|
||||
"User Agent": "Navigateur Web",
|
||||
"Actions": "Actions",
|
||||
"Current session": "Session actuelle",
|
||||
"Sessions": "Sessions",
|
||||
"Users": "Utilisateurs",
|
||||
"Add user": "Ajouter un utilisateur",
|
||||
"Choose a Subscription": "Choisissez un abonnement",
|
||||
"Subscribe": "S'abonner",
|
||||
"New Category": "Nouvelle Catégorie",
|
||||
"Title": "Titre",
|
||||
"Save": "Sauvegarder",
|
||||
"or": "ou",
|
||||
"cancel": "annuler",
|
||||
"New User": "Nouvel Utilisateur",
|
||||
"Confirmation": "Confirmation",
|
||||
"Administrator": "Administrateur",
|
||||
"Edit Category: %s": "Modification de la catégorie : %s",
|
||||
"Update": "Mettre à jour",
|
||||
"Edit Feed: %s": "Modification de l'abonnement : %s",
|
||||
"There is no category!": "Il n'y a aucune catégorie !",
|
||||
"Edit user: %s": "Modification de l'utilisateur : %s",
|
||||
"There is no article for this feed.": "Il n'y a aucun article pour cet abonnement.",
|
||||
"Add subscription": "Ajouter un abonnement",
|
||||
"You don't have any subscription.": "Vous n'avez aucun abonnement",
|
||||
"Last check:": "Dernière vérification :",
|
||||
"Refresh": "Actualiser",
|
||||
"There is no history at the moment.": "Il n'y a aucun historique pour le moment.",
|
||||
"OPML file": "Fichier OPML",
|
||||
"Sign In": "Connexion",
|
||||
"Sign in": "Connexion",
|
||||
"Theme": "Thème",
|
||||
"Timezone": "Fuseau horaire",
|
||||
"Language": "Langue",
|
||||
"There is no unread article.": "Il n'y a rien de nouveau à lire.",
|
||||
"You are the only user.": "Vous êtes le seul utilisateur.",
|
||||
"Last Login": "Dernière connexion",
|
||||
"Yes": "Oui",
|
||||
"No": "Non",
|
||||
"This feed already exists (%s).": "Cet abonnement existe déjà (%s).",
|
||||
"Unable to fetch feed (statusCode=%d).": "Impossible de récupérer cet abonnement (code=%d).",
|
||||
"Unable to open this link: %v": "Impossible d'ouvrir ce lien : %v",
|
||||
"Unable to analyze this page: %v": "Impossible d'analyzer cette page : %v",
|
||||
"Unable to find any subscription.": "Impossible de trouver un abonnement.",
|
||||
"The URL and the category are mandatory.": "L'URL et la catégorie sont obligatoire.",
|
||||
"All fields are mandatory.": "Tous les champs sont obligatoire.",
|
||||
"Passwords are not the same.": "Les mots de passe ne sont pas les mêmes.",
|
||||
"You must use at least 6 characters.": "Vous devez utiliser au moins 6 caractères.",
|
||||
"The username is mandatory.": "Le nom d'utilisateur est obligatoire.",
|
||||
"The username, theme, language and timezone fields are mandatory.": "Le nom d'utilisateur, le thème, la langue et le fuseau horaire sont obligatoire.",
|
||||
"The title is mandatory.": "Le titre est obligatoire.",
|
||||
"About": "A propos",
|
||||
"version": "Version",
|
||||
"Version:": "Version :",
|
||||
"Build Date:": "Date de la compilation :",
|
||||
"Author:": "Auteur :",
|
||||
"Authors": "Auteurs",
|
||||
"License:": "Licence :",
|
||||
"Attachments": "Pièces jointes",
|
||||
"Download": "Télécharger",
|
||||
"Invalid username or password.": "Mauvais identifiant ou mot de passe.",
|
||||
"Never": "Jamais",
|
||||
"Unable to execute request: %v": "Impossible d'exécuter cette requête: %v",
|
||||
"Last Parsing Error": "Dernière erreur d'analyse",
|
||||
"There is a problem with this feed": "Il y a un problème avec cet abonnement"
|
||||
}
|
40
locale/translator.go
Normal file
40
locale/translator.go
Normal file
|
@ -0,0 +1,40 @@
|
|||
// Copyright 2017 Frédéric Guillot. All rights reserved.
|
||||
// Use of this source code is governed by the Apache 2.0
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package locale
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type Translator struct {
|
||||
Locales Locales
|
||||
}
|
||||
|
||||
func (t *Translator) AddLanguage(language, translations string) error {
|
||||
var decodedTranslations Translation
|
||||
|
||||
decoder := json.NewDecoder(strings.NewReader(translations))
|
||||
if err := decoder.Decode(&decodedTranslations); err != nil {
|
||||
return fmt.Errorf("Invalid JSON file: %v", err)
|
||||
}
|
||||
|
||||
t.Locales[language] = decodedTranslations
|
||||
return nil
|
||||
}
|
||||
|
||||
func (t *Translator) GetLanguage(language string) *Language {
|
||||
translations, found := t.Locales[language]
|
||||
if !found {
|
||||
return &Language{language: language}
|
||||
}
|
||||
|
||||
return &Language{language: language, translations: translations}
|
||||
}
|
||||
|
||||
func NewTranslator() *Translator {
|
||||
return &Translator{Locales: make(Locales)}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue