Add comprehensive i18n localization support
- Add go-i18n package for internationalization - Create i18n middleware to extract Accept-Language header - Add translation files for en, es, fr, de, pt languages - Localize all handler error messages and responses - Add language context to all API handlers Supported languages: English, Spanish, French, German, Portuguese 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
86
internal/i18n/i18n.go
Normal file
86
internal/i18n/i18n.go
Normal file
@@ -0,0 +1,86 @@
|
||||
package i18n
|
||||
|
||||
import (
|
||||
"embed"
|
||||
"encoding/json"
|
||||
|
||||
"github.com/nicksnyder/go-i18n/v2/i18n"
|
||||
"github.com/rs/zerolog/log"
|
||||
"golang.org/x/text/language"
|
||||
)
|
||||
|
||||
//go:embed translations/*.json
|
||||
var translationFS embed.FS
|
||||
|
||||
// Bundle is the global i18n bundle
|
||||
var Bundle *i18n.Bundle
|
||||
|
||||
// SupportedLanguages lists all supported language codes
|
||||
var SupportedLanguages = []string{"en", "es", "fr", "de", "pt"}
|
||||
|
||||
// DefaultLanguage is the fallback language
|
||||
const DefaultLanguage = "en"
|
||||
|
||||
// Init initializes the i18n bundle with embedded translation files
|
||||
func Init() error {
|
||||
Bundle = i18n.NewBundle(language.English)
|
||||
Bundle.RegisterUnmarshalFunc("json", json.Unmarshal)
|
||||
|
||||
// Load all translation files
|
||||
for _, lang := range SupportedLanguages {
|
||||
path := "translations/" + lang + ".json"
|
||||
data, err := translationFS.ReadFile(path)
|
||||
if err != nil {
|
||||
log.Warn().Str("language", lang).Err(err).Msg("Failed to load translation file")
|
||||
continue
|
||||
}
|
||||
Bundle.MustParseMessageFileBytes(data, path)
|
||||
log.Info().Str("language", lang).Msg("Loaded translation file")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// NewLocalizer creates a new localizer for the given language tags
|
||||
func NewLocalizer(langs ...string) *i18n.Localizer {
|
||||
return i18n.NewLocalizer(Bundle, langs...)
|
||||
}
|
||||
|
||||
// T translates a message ID with optional template data
|
||||
func T(localizer *i18n.Localizer, messageID string, templateData map[string]interface{}) string {
|
||||
if localizer == nil {
|
||||
localizer = NewLocalizer(DefaultLanguage)
|
||||
}
|
||||
|
||||
msg, err := localizer.Localize(&i18n.LocalizeConfig{
|
||||
MessageID: messageID,
|
||||
TemplateData: templateData,
|
||||
})
|
||||
if err != nil {
|
||||
// Fallback to message ID if translation not found
|
||||
log.Debug().Str("message_id", messageID).Err(err).Msg("Translation not found")
|
||||
return messageID
|
||||
}
|
||||
return msg
|
||||
}
|
||||
|
||||
// TSimple translates a message ID without template data
|
||||
func TSimple(localizer *i18n.Localizer, messageID string) string {
|
||||
return T(localizer, messageID, nil)
|
||||
}
|
||||
|
||||
// MustT translates a message ID or panics
|
||||
func MustT(localizer *i18n.Localizer, messageID string, templateData map[string]interface{}) string {
|
||||
if localizer == nil {
|
||||
localizer = NewLocalizer(DefaultLanguage)
|
||||
}
|
||||
|
||||
msg, err := localizer.Localize(&i18n.LocalizeConfig{
|
||||
MessageID: messageID,
|
||||
TemplateData: templateData,
|
||||
})
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return msg
|
||||
}
|
||||
122
internal/i18n/middleware.go
Normal file
122
internal/i18n/middleware.go
Normal file
@@ -0,0 +1,122 @@
|
||||
package i18n
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/nicksnyder/go-i18n/v2/i18n"
|
||||
"golang.org/x/text/language"
|
||||
)
|
||||
|
||||
const (
|
||||
// LocalizerKey is the key used to store the localizer in Gin context
|
||||
LocalizerKey = "i18n_localizer"
|
||||
// LocaleKey is the key used to store the detected locale in Gin context
|
||||
LocaleKey = "i18n_locale"
|
||||
)
|
||||
|
||||
// Middleware returns a Gin middleware that detects the user's preferred language
|
||||
// from the Accept-Language header and stores a localizer in the context
|
||||
func Middleware() gin.HandlerFunc {
|
||||
return func(c *gin.Context) {
|
||||
// Get Accept-Language header
|
||||
acceptLang := c.GetHeader("Accept-Language")
|
||||
|
||||
// Parse the preferred languages
|
||||
langs := parseAcceptLanguage(acceptLang)
|
||||
|
||||
// Create localizer with the preferred languages
|
||||
localizer := NewLocalizer(langs...)
|
||||
|
||||
// Determine the best matched locale for storage
|
||||
locale := matchLocale(langs)
|
||||
|
||||
// Store in context
|
||||
c.Set(LocalizerKey, localizer)
|
||||
c.Set(LocaleKey, locale)
|
||||
|
||||
c.Next()
|
||||
}
|
||||
}
|
||||
|
||||
// parseAcceptLanguage parses the Accept-Language header and returns a slice of language tags
|
||||
func parseAcceptLanguage(header string) []string {
|
||||
if header == "" {
|
||||
return []string{DefaultLanguage}
|
||||
}
|
||||
|
||||
// Parse using golang.org/x/text/language
|
||||
tags, _, err := language.ParseAcceptLanguage(header)
|
||||
if err != nil || len(tags) == 0 {
|
||||
return []string{DefaultLanguage}
|
||||
}
|
||||
|
||||
// Convert to string slice and normalize
|
||||
langs := make([]string, 0, len(tags))
|
||||
for _, tag := range tags {
|
||||
base, _ := tag.Base()
|
||||
lang := strings.ToLower(base.String())
|
||||
|
||||
// Only add supported languages
|
||||
for _, supported := range SupportedLanguages {
|
||||
if lang == supported {
|
||||
langs = append(langs, lang)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If no supported languages found, use default
|
||||
if len(langs) == 0 {
|
||||
return []string{DefaultLanguage}
|
||||
}
|
||||
|
||||
return langs
|
||||
}
|
||||
|
||||
// matchLocale returns the best matching locale from the provided languages
|
||||
func matchLocale(langs []string) string {
|
||||
for _, lang := range langs {
|
||||
for _, supported := range SupportedLanguages {
|
||||
if lang == supported {
|
||||
return supported
|
||||
}
|
||||
}
|
||||
}
|
||||
return DefaultLanguage
|
||||
}
|
||||
|
||||
// GetLocalizer retrieves the localizer from the Gin context
|
||||
func GetLocalizer(c *gin.Context) *i18n.Localizer {
|
||||
if localizer, exists := c.Get(LocalizerKey); exists {
|
||||
if l, ok := localizer.(*i18n.Localizer); ok {
|
||||
return l
|
||||
}
|
||||
}
|
||||
return NewLocalizer(DefaultLanguage)
|
||||
}
|
||||
|
||||
// GetLocale retrieves the detected locale from the Gin context
|
||||
func GetLocale(c *gin.Context) string {
|
||||
if locale, exists := c.Get(LocaleKey); exists {
|
||||
if l, ok := locale.(string); ok {
|
||||
return l
|
||||
}
|
||||
}
|
||||
return DefaultLanguage
|
||||
}
|
||||
|
||||
// LocalizedError returns a localized error message
|
||||
func LocalizedError(c *gin.Context, messageID string, templateData map[string]interface{}) string {
|
||||
return T(GetLocalizer(c), messageID, templateData)
|
||||
}
|
||||
|
||||
// LocalizedMessage returns a localized message
|
||||
func LocalizedMessage(c *gin.Context, messageID string) string {
|
||||
return TSimple(GetLocalizer(c), messageID)
|
||||
}
|
||||
|
||||
// LocalizedMessageWithData returns a localized message with template data
|
||||
func LocalizedMessageWithData(c *gin.Context, messageID string, templateData map[string]interface{}) string {
|
||||
return T(GetLocalizer(c), messageID, templateData)
|
||||
}
|
||||
187
internal/i18n/translations/de.json
Normal file
187
internal/i18n/translations/de.json
Normal file
@@ -0,0 +1,187 @@
|
||||
{
|
||||
"error.invalid_request_body": "Ungultiger Anforderungstext",
|
||||
"error.invalid_credentials": "Ungultige Anmeldedaten",
|
||||
"error.account_inactive": "Das Konto ist inaktiv",
|
||||
"error.username_taken": "Benutzername bereits vergeben",
|
||||
"error.email_taken": "E-Mail bereits registriert",
|
||||
"error.email_already_taken": "E-Mail bereits vergeben",
|
||||
"error.registration_failed": "Registrierung fehlgeschlagen",
|
||||
"error.not_authenticated": "Nicht authentifiziert",
|
||||
"error.failed_to_get_user": "Benutzer konnte nicht abgerufen werden",
|
||||
"error.failed_to_update_profile": "Profil konnte nicht aktualisiert werden",
|
||||
"error.invalid_verification_code": "Ungultiger Verifizierungscode",
|
||||
"error.verification_code_expired": "Der Verifizierungscode ist abgelaufen",
|
||||
"error.email_already_verified": "E-Mail bereits verifiziert",
|
||||
"error.verification_failed": "Verifizierung fehlgeschlagen",
|
||||
"error.failed_to_resend_verification": "Verifizierung konnte nicht erneut gesendet werden",
|
||||
"error.rate_limit_exceeded": "Zu viele Anfragen zur Passwortzurucksetzung. Bitte versuchen Sie es spater erneut.",
|
||||
"error.too_many_attempts": "Zu viele Versuche. Bitte fordern Sie einen neuen Code an.",
|
||||
"error.invalid_reset_token": "Ungultiger oder abgelaufener Zurucksetzungs-Token",
|
||||
"error.password_reset_failed": "Passwortzurucksetzung fehlgeschlagen",
|
||||
"error.apple_signin_not_configured": "Apple-Anmeldung ist nicht konfiguriert",
|
||||
"error.apple_signin_failed": "Apple-Anmeldung fehlgeschlagen",
|
||||
"error.invalid_apple_token": "Ungultiger Apple-Identitats-Token",
|
||||
|
||||
"error.invalid_task_id": "Ungultige Aufgaben-ID",
|
||||
"error.invalid_residence_id": "Ungultige Immobilien-ID",
|
||||
"error.invalid_contractor_id": "Ungultige Dienstleister-ID",
|
||||
"error.invalid_document_id": "Ungultige Dokument-ID",
|
||||
"error.invalid_completion_id": "Ungultige Abschluss-ID",
|
||||
"error.invalid_user_id": "Ungultige Benutzer-ID",
|
||||
"error.invalid_notification_id": "Ungultige Benachrichtigungs-ID",
|
||||
"error.invalid_device_id": "Ungultige Gerate-ID",
|
||||
|
||||
"error.task_not_found": "Aufgabe nicht gefunden",
|
||||
"error.residence_not_found": "Immobilie nicht gefunden",
|
||||
"error.contractor_not_found": "Dienstleister nicht gefunden",
|
||||
"error.document_not_found": "Dokument nicht gefunden",
|
||||
"error.completion_not_found": "Aufgabenabschluss nicht gefunden",
|
||||
"error.user_not_found": "Benutzer nicht gefunden",
|
||||
"error.share_code_invalid": "Ungultiger Freigabecode",
|
||||
"error.share_code_expired": "Der Freigabecode ist abgelaufen",
|
||||
|
||||
"error.task_access_denied": "Sie haben keinen Zugriff auf diese Aufgabe",
|
||||
"error.residence_access_denied": "Sie haben keinen Zugriff auf diese Immobilie",
|
||||
"error.contractor_access_denied": "Sie haben keinen Zugriff auf diesen Dienstleister",
|
||||
"error.document_access_denied": "Sie haben keinen Zugriff auf dieses Dokument",
|
||||
"error.not_residence_owner": "Nur der Eigentumer kann diese Aktion durchfuhren",
|
||||
"error.cannot_remove_owner": "Der Eigentumer kann nicht entfernt werden",
|
||||
"error.user_already_member": "Der Benutzer ist bereits Mitglied dieser Immobilie",
|
||||
"error.properties_limit_reached": "Sie haben die maximale Anzahl an Immobilien fur Ihr Abonnement erreicht",
|
||||
|
||||
"error.task_already_cancelled": "Die Aufgabe ist bereits storniert",
|
||||
"error.task_already_archived": "Die Aufgabe ist bereits archiviert",
|
||||
|
||||
"error.failed_to_parse_form": "Formular konnte nicht analysiert werden",
|
||||
"error.task_id_required": "task_id ist erforderlich",
|
||||
"error.invalid_task_id_value": "Ungultige task_id",
|
||||
"error.failed_to_upload_image": "Bild konnte nicht hochgeladen werden",
|
||||
"error.residence_id_required": "residence_id ist erforderlich",
|
||||
"error.invalid_residence_id_value": "Ungultige residence_id",
|
||||
"error.title_required": "Titel ist erforderlich",
|
||||
"error.failed_to_upload_file": "Datei konnte nicht hochgeladen werden",
|
||||
|
||||
"message.logged_out": "Erfolgreich abgemeldet",
|
||||
"message.email_verified": "E-Mail erfolgreich verifiziert",
|
||||
"message.verification_email_sent": "Verifizierungs-E-Mail gesendet",
|
||||
"message.password_reset_email_sent": "Wenn ein Konto mit dieser E-Mail existiert, wurde ein Zurucksetzungscode gesendet.",
|
||||
"message.reset_code_verified": "Code erfolgreich verifiziert",
|
||||
"message.password_reset_success": "Passwort erfolgreich zuruckgesetzt. Bitte melden Sie sich mit Ihrem neuen Passwort an.",
|
||||
|
||||
"message.task_deleted": "Aufgabe erfolgreich geloscht",
|
||||
"message.task_in_progress": "Aufgabe als in Bearbeitung markiert",
|
||||
"message.task_cancelled": "Aufgabe storniert",
|
||||
"message.task_uncancelled": "Aufgabe reaktiviert",
|
||||
"message.task_archived": "Aufgabe archiviert",
|
||||
"message.task_unarchived": "Aufgabe dearchiviert",
|
||||
"message.completion_deleted": "Abschluss erfolgreich geloscht",
|
||||
|
||||
"message.residence_deleted": "Immobilie erfolgreich geloscht",
|
||||
"message.user_removed": "Benutzer von der Immobilie entfernt",
|
||||
"message.tasks_report_generated": "Aufgabenbericht erfolgreich erstellt",
|
||||
"message.tasks_report_sent": "Aufgabenbericht erstellt und an {{.Email}} gesendet",
|
||||
"message.tasks_report_email_failed": "Aufgabenbericht erstellt, aber E-Mail konnte nicht gesendet werden",
|
||||
|
||||
"message.contractor_deleted": "Dienstleister erfolgreich geloscht",
|
||||
|
||||
"message.document_deleted": "Dokument erfolgreich geloscht",
|
||||
"message.document_activated": "Dokument aktiviert",
|
||||
"message.document_deactivated": "Dokument deaktiviert",
|
||||
|
||||
"message.notification_marked_read": "Benachrichtigung als gelesen markiert",
|
||||
"message.all_notifications_marked_read": "Alle Benachrichtigungen als gelesen markiert",
|
||||
"message.device_removed": "Gerät entfernt",
|
||||
|
||||
"message.subscription_upgraded": "Abonnement erfolgreich aktualisiert",
|
||||
"message.subscription_cancelled": "Abonnement gekündigt. Sie behalten die Pro-Vorteile bis zum Ende Ihres Abrechnungszeitraums.",
|
||||
"message.subscription_restored": "Abonnement erfolgreich wiederhergestellt",
|
||||
|
||||
"message.file_deleted": "Datei erfolgreich gelöscht",
|
||||
"message.static_data_refreshed": "Statische Daten aktualisiert",
|
||||
|
||||
"error.notification_not_found": "Benachrichtigung nicht gefunden",
|
||||
"error.invalid_platform": "Ungültige Plattform",
|
||||
|
||||
"error.upgrade_trigger_not_found": "Upgrade-Trigger nicht gefunden",
|
||||
"error.receipt_data_required": "receipt_data ist für iOS erforderlich",
|
||||
"error.purchase_token_required": "purchase_token ist für Android erforderlich",
|
||||
|
||||
"error.no_file_provided": "Keine Datei bereitgestellt",
|
||||
|
||||
"error.failed_to_fetch_residence_types": "Fehler beim Abrufen der Immobilientypen",
|
||||
"error.failed_to_fetch_task_categories": "Fehler beim Abrufen der Aufgabenkategorien",
|
||||
"error.failed_to_fetch_task_priorities": "Fehler beim Abrufen der Aufgabenprioritäten",
|
||||
"error.failed_to_fetch_task_frequencies": "Fehler beim Abrufen der Aufgabenfrequenzen",
|
||||
"error.failed_to_fetch_task_statuses": "Fehler beim Abrufen der Aufgabenstatus",
|
||||
"error.failed_to_fetch_contractor_specialties": "Fehler beim Abrufen der Dienstleister-Spezialitäten",
|
||||
|
||||
"push.task_due_soon.title": "Aufgabe Bald Fallig",
|
||||
"push.task_due_soon.body": "{{.TaskTitle}} ist fallig am {{.DueDate}}",
|
||||
"push.task_overdue.title": "Uberfällige Aufgabe",
|
||||
"push.task_overdue.body": "{{.TaskTitle}} ist uberfallig",
|
||||
"push.task_completed.title": "Aufgabe Abgeschlossen",
|
||||
"push.task_completed.body": "{{.UserName}} hat {{.TaskTitle}} abgeschlossen",
|
||||
"push.task_assigned.title": "Neue Aufgabe Zugewiesen",
|
||||
"push.task_assigned.body": "Ihnen wurde {{.TaskTitle}} zugewiesen",
|
||||
"push.residence_shared.title": "Immobilie Geteilt",
|
||||
"push.residence_shared.body": "{{.UserName}} hat {{.ResidenceName}} mit Ihnen geteilt",
|
||||
|
||||
"email.welcome.subject": "Willkommen bei Casera!",
|
||||
"email.verification.subject": "Bestatigen Sie Ihre E-Mail",
|
||||
"email.password_reset.subject": "Passwort-Zurucksetzungscode",
|
||||
"email.tasks_report.subject": "Aufgabenbericht fur {{.ResidenceName}}",
|
||||
|
||||
"lookup.residence_type.house": "Haus",
|
||||
"lookup.residence_type.apartment": "Wohnung",
|
||||
"lookup.residence_type.condo": "Eigentumswohnung",
|
||||
"lookup.residence_type.townhouse": "Reihenhaus",
|
||||
"lookup.residence_type.mobile_home": "Mobilheim",
|
||||
"lookup.residence_type.other": "Sonstiges",
|
||||
|
||||
"lookup.task_category.plumbing": "Sanitär",
|
||||
"lookup.task_category.electrical": "Elektrik",
|
||||
"lookup.task_category.hvac": "Heizung/Klimaanlage",
|
||||
"lookup.task_category.appliances": "Gerate",
|
||||
"lookup.task_category.exterior": "Aussenbereich",
|
||||
"lookup.task_category.interior": "Innenbereich",
|
||||
"lookup.task_category.landscaping": "Gartenpflege",
|
||||
"lookup.task_category.safety": "Sicherheit",
|
||||
"lookup.task_category.cleaning": "Reinigung",
|
||||
"lookup.task_category.pest_control": "Schadlingsbekampfung",
|
||||
"lookup.task_category.seasonal": "Saisonal",
|
||||
"lookup.task_category.other": "Sonstiges",
|
||||
|
||||
"lookup.task_priority.low": "Niedrig",
|
||||
"lookup.task_priority.medium": "Mittel",
|
||||
"lookup.task_priority.high": "Hoch",
|
||||
"lookup.task_priority.urgent": "Dringend",
|
||||
|
||||
"lookup.task_status.pending": "Ausstehend",
|
||||
"lookup.task_status.in_progress": "In Bearbeitung",
|
||||
"lookup.task_status.completed": "Abgeschlossen",
|
||||
"lookup.task_status.cancelled": "Storniert",
|
||||
"lookup.task_status.archived": "Archiviert",
|
||||
|
||||
"lookup.task_frequency.once": "Einmalig",
|
||||
"lookup.task_frequency.daily": "Taglich",
|
||||
"lookup.task_frequency.weekly": "Wochentlich",
|
||||
"lookup.task_frequency.biweekly": "Alle 2 Wochen",
|
||||
"lookup.task_frequency.monthly": "Monatlich",
|
||||
"lookup.task_frequency.quarterly": "Vierteljahrlich",
|
||||
"lookup.task_frequency.semiannually": "Halbjahrlich",
|
||||
"lookup.task_frequency.annually": "Jahrlich",
|
||||
|
||||
"lookup.contractor_specialty.plumber": "Klempner",
|
||||
"lookup.contractor_specialty.electrician": "Elektriker",
|
||||
"lookup.contractor_specialty.hvac_technician": "HLK-Techniker",
|
||||
"lookup.contractor_specialty.handyman": "Handwerker",
|
||||
"lookup.contractor_specialty.landscaper": "Landschaftsgartner",
|
||||
"lookup.contractor_specialty.roofer": "Dachdecker",
|
||||
"lookup.contractor_specialty.painter": "Maler",
|
||||
"lookup.contractor_specialty.carpenter": "Schreiner",
|
||||
"lookup.contractor_specialty.pest_control": "Schadlingsbekampfung",
|
||||
"lookup.contractor_specialty.cleaning": "Reinigung",
|
||||
"lookup.contractor_specialty.pool_service": "Pool-Service",
|
||||
"lookup.contractor_specialty.general_contractor": "Generalunternehmer",
|
||||
"lookup.contractor_specialty.other": "Sonstiges"
|
||||
}
|
||||
187
internal/i18n/translations/en.json
Normal file
187
internal/i18n/translations/en.json
Normal file
@@ -0,0 +1,187 @@
|
||||
{
|
||||
"error.invalid_request_body": "Invalid request body",
|
||||
"error.invalid_credentials": "Invalid credentials",
|
||||
"error.account_inactive": "Account is inactive",
|
||||
"error.username_taken": "Username already taken",
|
||||
"error.email_taken": "Email already registered",
|
||||
"error.email_already_taken": "Email already taken",
|
||||
"error.registration_failed": "Registration failed",
|
||||
"error.not_authenticated": "Not authenticated",
|
||||
"error.failed_to_get_user": "Failed to get user",
|
||||
"error.failed_to_update_profile": "Failed to update profile",
|
||||
"error.invalid_verification_code": "Invalid verification code",
|
||||
"error.verification_code_expired": "Verification code has expired",
|
||||
"error.email_already_verified": "Email already verified",
|
||||
"error.verification_failed": "Verification failed",
|
||||
"error.failed_to_resend_verification": "Failed to resend verification",
|
||||
"error.rate_limit_exceeded": "Too many password reset requests. Please try again later.",
|
||||
"error.too_many_attempts": "Too many attempts. Please request a new code.",
|
||||
"error.invalid_reset_token": "Invalid or expired reset token",
|
||||
"error.password_reset_failed": "Password reset failed",
|
||||
"error.apple_signin_not_configured": "Apple Sign In is not configured",
|
||||
"error.apple_signin_failed": "Apple Sign In failed",
|
||||
"error.invalid_apple_token": "Invalid Apple identity token",
|
||||
|
||||
"error.invalid_task_id": "Invalid task ID",
|
||||
"error.invalid_residence_id": "Invalid residence ID",
|
||||
"error.invalid_contractor_id": "Invalid contractor ID",
|
||||
"error.invalid_document_id": "Invalid document ID",
|
||||
"error.invalid_completion_id": "Invalid completion ID",
|
||||
"error.invalid_user_id": "Invalid user ID",
|
||||
"error.invalid_notification_id": "Invalid notification ID",
|
||||
"error.invalid_device_id": "Invalid device ID",
|
||||
|
||||
"error.task_not_found": "Task not found",
|
||||
"error.residence_not_found": "Residence not found",
|
||||
"error.contractor_not_found": "Contractor not found",
|
||||
"error.document_not_found": "Document not found",
|
||||
"error.completion_not_found": "Task completion not found",
|
||||
"error.user_not_found": "User not found",
|
||||
"error.share_code_invalid": "Invalid share code",
|
||||
"error.share_code_expired": "Share code has expired",
|
||||
|
||||
"error.task_access_denied": "You don't have access to this task",
|
||||
"error.residence_access_denied": "You don't have access to this property",
|
||||
"error.contractor_access_denied": "You don't have access to this contractor",
|
||||
"error.document_access_denied": "You don't have access to this document",
|
||||
"error.not_residence_owner": "Only the property owner can perform this action",
|
||||
"error.cannot_remove_owner": "Cannot remove the property owner",
|
||||
"error.user_already_member": "User is already a member of this property",
|
||||
"error.properties_limit_reached": "You have reached the maximum number of properties for your subscription",
|
||||
|
||||
"error.task_already_cancelled": "Task is already cancelled",
|
||||
"error.task_already_archived": "Task is already archived",
|
||||
|
||||
"error.failed_to_parse_form": "Failed to parse multipart form",
|
||||
"error.task_id_required": "task_id is required",
|
||||
"error.invalid_task_id_value": "Invalid task_id",
|
||||
"error.failed_to_upload_image": "Failed to upload image",
|
||||
"error.residence_id_required": "residence_id is required",
|
||||
"error.invalid_residence_id_value": "Invalid residence_id",
|
||||
"error.title_required": "title is required",
|
||||
"error.failed_to_upload_file": "Failed to upload file",
|
||||
|
||||
"message.logged_out": "Logged out successfully",
|
||||
"message.email_verified": "Email verified successfully",
|
||||
"message.verification_email_sent": "Verification email sent",
|
||||
"message.password_reset_email_sent": "If an account with that email exists, a password reset code has been sent.",
|
||||
"message.reset_code_verified": "Code verified successfully",
|
||||
"message.password_reset_success": "Password reset successfully. Please log in with your new password.",
|
||||
|
||||
"message.task_deleted": "Task deleted successfully",
|
||||
"message.task_in_progress": "Task marked as in progress",
|
||||
"message.task_cancelled": "Task cancelled",
|
||||
"message.task_uncancelled": "Task uncancelled",
|
||||
"message.task_archived": "Task archived",
|
||||
"message.task_unarchived": "Task unarchived",
|
||||
"message.completion_deleted": "Completion deleted successfully",
|
||||
|
||||
"message.residence_deleted": "Residence deleted successfully",
|
||||
"message.user_removed": "User removed from residence",
|
||||
"message.tasks_report_generated": "Tasks report generated successfully",
|
||||
"message.tasks_report_sent": "Tasks report generated and sent to {{.Email}}",
|
||||
"message.tasks_report_email_failed": "Tasks report generated but email could not be sent",
|
||||
|
||||
"message.contractor_deleted": "Contractor deleted successfully",
|
||||
|
||||
"message.document_deleted": "Document deleted successfully",
|
||||
"message.document_activated": "Document activated",
|
||||
"message.document_deactivated": "Document deactivated",
|
||||
|
||||
"message.notification_marked_read": "Notification marked as read",
|
||||
"message.all_notifications_marked_read": "All notifications marked as read",
|
||||
"message.device_removed": "Device removed",
|
||||
|
||||
"message.subscription_upgraded": "Subscription upgraded successfully",
|
||||
"message.subscription_cancelled": "Subscription cancelled. You will retain Pro benefits until the end of your billing period.",
|
||||
"message.subscription_restored": "Subscription restored successfully",
|
||||
|
||||
"message.file_deleted": "File deleted successfully",
|
||||
"message.static_data_refreshed": "Static data refreshed",
|
||||
|
||||
"error.notification_not_found": "Notification not found",
|
||||
"error.invalid_platform": "Invalid platform",
|
||||
|
||||
"error.upgrade_trigger_not_found": "Upgrade trigger not found",
|
||||
"error.receipt_data_required": "receipt_data is required for iOS",
|
||||
"error.purchase_token_required": "purchase_token is required for Android",
|
||||
|
||||
"error.no_file_provided": "No file provided",
|
||||
|
||||
"error.failed_to_fetch_residence_types": "Failed to fetch residence types",
|
||||
"error.failed_to_fetch_task_categories": "Failed to fetch task categories",
|
||||
"error.failed_to_fetch_task_priorities": "Failed to fetch task priorities",
|
||||
"error.failed_to_fetch_task_frequencies": "Failed to fetch task frequencies",
|
||||
"error.failed_to_fetch_task_statuses": "Failed to fetch task statuses",
|
||||
"error.failed_to_fetch_contractor_specialties": "Failed to fetch contractor specialties",
|
||||
|
||||
"push.task_due_soon.title": "Task Due Soon",
|
||||
"push.task_due_soon.body": "{{.TaskTitle}} is due {{.DueDate}}",
|
||||
"push.task_overdue.title": "Overdue Task",
|
||||
"push.task_overdue.body": "{{.TaskTitle}} is overdue",
|
||||
"push.task_completed.title": "Task Completed",
|
||||
"push.task_completed.body": "{{.UserName}} completed {{.TaskTitle}}",
|
||||
"push.task_assigned.title": "New Task Assigned",
|
||||
"push.task_assigned.body": "You have been assigned to {{.TaskTitle}}",
|
||||
"push.residence_shared.title": "Property Shared",
|
||||
"push.residence_shared.body": "{{.UserName}} shared {{.ResidenceName}} with you",
|
||||
|
||||
"email.welcome.subject": "Welcome to Casera!",
|
||||
"email.verification.subject": "Verify Your Email",
|
||||
"email.password_reset.subject": "Password Reset Code",
|
||||
"email.tasks_report.subject": "Tasks Report for {{.ResidenceName}}",
|
||||
|
||||
"lookup.residence_type.house": "House",
|
||||
"lookup.residence_type.apartment": "Apartment",
|
||||
"lookup.residence_type.condo": "Condo",
|
||||
"lookup.residence_type.townhouse": "Townhouse",
|
||||
"lookup.residence_type.mobile_home": "Mobile Home",
|
||||
"lookup.residence_type.other": "Other",
|
||||
|
||||
"lookup.task_category.plumbing": "Plumbing",
|
||||
"lookup.task_category.electrical": "Electrical",
|
||||
"lookup.task_category.hvac": "HVAC",
|
||||
"lookup.task_category.appliances": "Appliances",
|
||||
"lookup.task_category.exterior": "Exterior",
|
||||
"lookup.task_category.interior": "Interior",
|
||||
"lookup.task_category.landscaping": "Landscaping",
|
||||
"lookup.task_category.safety": "Safety",
|
||||
"lookup.task_category.cleaning": "Cleaning",
|
||||
"lookup.task_category.pest_control": "Pest Control",
|
||||
"lookup.task_category.seasonal": "Seasonal",
|
||||
"lookup.task_category.other": "Other",
|
||||
|
||||
"lookup.task_priority.low": "Low",
|
||||
"lookup.task_priority.medium": "Medium",
|
||||
"lookup.task_priority.high": "High",
|
||||
"lookup.task_priority.urgent": "Urgent",
|
||||
|
||||
"lookup.task_status.pending": "Pending",
|
||||
"lookup.task_status.in_progress": "In Progress",
|
||||
"lookup.task_status.completed": "Completed",
|
||||
"lookup.task_status.cancelled": "Cancelled",
|
||||
"lookup.task_status.archived": "Archived",
|
||||
|
||||
"lookup.task_frequency.once": "Once",
|
||||
"lookup.task_frequency.daily": "Daily",
|
||||
"lookup.task_frequency.weekly": "Weekly",
|
||||
"lookup.task_frequency.biweekly": "Every 2 Weeks",
|
||||
"lookup.task_frequency.monthly": "Monthly",
|
||||
"lookup.task_frequency.quarterly": "Quarterly",
|
||||
"lookup.task_frequency.semiannually": "Every 6 Months",
|
||||
"lookup.task_frequency.annually": "Annually",
|
||||
|
||||
"lookup.contractor_specialty.plumber": "Plumber",
|
||||
"lookup.contractor_specialty.electrician": "Electrician",
|
||||
"lookup.contractor_specialty.hvac_technician": "HVAC Technician",
|
||||
"lookup.contractor_specialty.handyman": "Handyman",
|
||||
"lookup.contractor_specialty.landscaper": "Landscaper",
|
||||
"lookup.contractor_specialty.roofer": "Roofer",
|
||||
"lookup.contractor_specialty.painter": "Painter",
|
||||
"lookup.contractor_specialty.carpenter": "Carpenter",
|
||||
"lookup.contractor_specialty.pest_control": "Pest Control",
|
||||
"lookup.contractor_specialty.cleaning": "Cleaning",
|
||||
"lookup.contractor_specialty.pool_service": "Pool Service",
|
||||
"lookup.contractor_specialty.general_contractor": "General Contractor",
|
||||
"lookup.contractor_specialty.other": "Other"
|
||||
}
|
||||
187
internal/i18n/translations/es.json
Normal file
187
internal/i18n/translations/es.json
Normal file
@@ -0,0 +1,187 @@
|
||||
{
|
||||
"error.invalid_request_body": "Cuerpo de solicitud no valido",
|
||||
"error.invalid_credentials": "Credenciales no validas",
|
||||
"error.account_inactive": "La cuenta esta inactiva",
|
||||
"error.username_taken": "El nombre de usuario ya esta en uso",
|
||||
"error.email_taken": "El correo electronico ya esta registrado",
|
||||
"error.email_already_taken": "El correo electronico ya esta en uso",
|
||||
"error.registration_failed": "Error en el registro",
|
||||
"error.not_authenticated": "No autenticado",
|
||||
"error.failed_to_get_user": "Error al obtener el usuario",
|
||||
"error.failed_to_update_profile": "Error al actualizar el perfil",
|
||||
"error.invalid_verification_code": "Codigo de verificacion no valido",
|
||||
"error.verification_code_expired": "El codigo de verificacion ha expirado",
|
||||
"error.email_already_verified": "El correo electronico ya esta verificado",
|
||||
"error.verification_failed": "Error en la verificacion",
|
||||
"error.failed_to_resend_verification": "Error al reenviar la verificacion",
|
||||
"error.rate_limit_exceeded": "Demasiadas solicitudes de restablecimiento de contrasena. Por favor, intentelo mas tarde.",
|
||||
"error.too_many_attempts": "Demasiados intentos. Por favor, solicite un nuevo codigo.",
|
||||
"error.invalid_reset_token": "Token de restablecimiento no valido o expirado",
|
||||
"error.password_reset_failed": "Error al restablecer la contrasena",
|
||||
"error.apple_signin_not_configured": "El inicio de sesion con Apple no esta configurado",
|
||||
"error.apple_signin_failed": "Error en el inicio de sesion con Apple",
|
||||
"error.invalid_apple_token": "Token de identidad de Apple no valido",
|
||||
|
||||
"error.invalid_task_id": "ID de tarea no valido",
|
||||
"error.invalid_residence_id": "ID de propiedad no valido",
|
||||
"error.invalid_contractor_id": "ID de contratista no valido",
|
||||
"error.invalid_document_id": "ID de documento no valido",
|
||||
"error.invalid_completion_id": "ID de finalizacion no valido",
|
||||
"error.invalid_user_id": "ID de usuario no valido",
|
||||
"error.invalid_notification_id": "ID de notificacion no valido",
|
||||
"error.invalid_device_id": "ID de dispositivo no valido",
|
||||
|
||||
"error.task_not_found": "Tarea no encontrada",
|
||||
"error.residence_not_found": "Propiedad no encontrada",
|
||||
"error.contractor_not_found": "Contratista no encontrado",
|
||||
"error.document_not_found": "Documento no encontrado",
|
||||
"error.completion_not_found": "Finalizacion de tarea no encontrada",
|
||||
"error.user_not_found": "Usuario no encontrado",
|
||||
"error.share_code_invalid": "Codigo de compartir no valido",
|
||||
"error.share_code_expired": "El codigo de compartir ha expirado",
|
||||
|
||||
"error.task_access_denied": "No tienes acceso a esta tarea",
|
||||
"error.residence_access_denied": "No tienes acceso a esta propiedad",
|
||||
"error.contractor_access_denied": "No tienes acceso a este contratista",
|
||||
"error.document_access_denied": "No tienes acceso a este documento",
|
||||
"error.not_residence_owner": "Solo el propietario de la propiedad puede realizar esta accion",
|
||||
"error.cannot_remove_owner": "No se puede eliminar al propietario de la propiedad",
|
||||
"error.user_already_member": "El usuario ya es miembro de esta propiedad",
|
||||
"error.properties_limit_reached": "Has alcanzado el numero maximo de propiedades para tu suscripcion",
|
||||
|
||||
"error.task_already_cancelled": "La tarea ya esta cancelada",
|
||||
"error.task_already_archived": "La tarea ya esta archivada",
|
||||
|
||||
"error.failed_to_parse_form": "Error al analizar el formulario",
|
||||
"error.task_id_required": "Se requiere task_id",
|
||||
"error.invalid_task_id_value": "task_id no valido",
|
||||
"error.failed_to_upload_image": "Error al subir la imagen",
|
||||
"error.residence_id_required": "Se requiere residence_id",
|
||||
"error.invalid_residence_id_value": "residence_id no valido",
|
||||
"error.title_required": "Se requiere el titulo",
|
||||
"error.failed_to_upload_file": "Error al subir el archivo",
|
||||
|
||||
"message.logged_out": "Sesion cerrada correctamente",
|
||||
"message.email_verified": "Correo electronico verificado correctamente",
|
||||
"message.verification_email_sent": "Correo de verificacion enviado",
|
||||
"message.password_reset_email_sent": "Si existe una cuenta con ese correo electronico, se ha enviado un codigo de restablecimiento de contrasena.",
|
||||
"message.reset_code_verified": "Codigo verificado correctamente",
|
||||
"message.password_reset_success": "Contrasena restablecida correctamente. Por favor, inicia sesion con tu nueva contrasena.",
|
||||
|
||||
"message.task_deleted": "Tarea eliminada correctamente",
|
||||
"message.task_in_progress": "Tarea marcada como en progreso",
|
||||
"message.task_cancelled": "Tarea cancelada",
|
||||
"message.task_uncancelled": "Tarea reactivada",
|
||||
"message.task_archived": "Tarea archivada",
|
||||
"message.task_unarchived": "Tarea desarchivada",
|
||||
"message.completion_deleted": "Finalizacion eliminada correctamente",
|
||||
|
||||
"message.residence_deleted": "Propiedad eliminada correctamente",
|
||||
"message.user_removed": "Usuario eliminado de la propiedad",
|
||||
"message.tasks_report_generated": "Informe de tareas generado correctamente",
|
||||
"message.tasks_report_sent": "Informe de tareas generado y enviado a {{.Email}}",
|
||||
"message.tasks_report_email_failed": "Informe de tareas generado pero no se pudo enviar el correo",
|
||||
|
||||
"message.contractor_deleted": "Contratista eliminado correctamente",
|
||||
|
||||
"message.document_deleted": "Documento eliminado correctamente",
|
||||
"message.document_activated": "Documento activado",
|
||||
"message.document_deactivated": "Documento desactivado",
|
||||
|
||||
"message.notification_marked_read": "Notificación marcada como leída",
|
||||
"message.all_notifications_marked_read": "Todas las notificaciones marcadas como leídas",
|
||||
"message.device_removed": "Dispositivo eliminado",
|
||||
|
||||
"message.subscription_upgraded": "Suscripción actualizada correctamente",
|
||||
"message.subscription_cancelled": "Suscripción cancelada. Mantendrás los beneficios Pro hasta el final de tu período de facturación.",
|
||||
"message.subscription_restored": "Suscripción restaurada correctamente",
|
||||
|
||||
"message.file_deleted": "Archivo eliminado correctamente",
|
||||
"message.static_data_refreshed": "Datos estáticos actualizados",
|
||||
|
||||
"error.notification_not_found": "Notificación no encontrada",
|
||||
"error.invalid_platform": "Plataforma no válida",
|
||||
|
||||
"error.upgrade_trigger_not_found": "Trigger de actualización no encontrado",
|
||||
"error.receipt_data_required": "Se requiere receipt_data para iOS",
|
||||
"error.purchase_token_required": "Se requiere purchase_token para Android",
|
||||
|
||||
"error.no_file_provided": "No se proporcionó ningún archivo",
|
||||
|
||||
"error.failed_to_fetch_residence_types": "Error al obtener los tipos de propiedad",
|
||||
"error.failed_to_fetch_task_categories": "Error al obtener las categorías de tareas",
|
||||
"error.failed_to_fetch_task_priorities": "Error al obtener las prioridades de tareas",
|
||||
"error.failed_to_fetch_task_frequencies": "Error al obtener las frecuencias de tareas",
|
||||
"error.failed_to_fetch_task_statuses": "Error al obtener los estados de tareas",
|
||||
"error.failed_to_fetch_contractor_specialties": "Error al obtener las especialidades de contratistas",
|
||||
|
||||
"push.task_due_soon.title": "Tarea Proxima a Vencer",
|
||||
"push.task_due_soon.body": "{{.TaskTitle}} vence {{.DueDate}}",
|
||||
"push.task_overdue.title": "Tarea Vencida",
|
||||
"push.task_overdue.body": "{{.TaskTitle}} esta vencida",
|
||||
"push.task_completed.title": "Tarea Completada",
|
||||
"push.task_completed.body": "{{.UserName}} completo {{.TaskTitle}}",
|
||||
"push.task_assigned.title": "Nueva Tarea Asignada",
|
||||
"push.task_assigned.body": "Se te ha asignado {{.TaskTitle}}",
|
||||
"push.residence_shared.title": "Propiedad Compartida",
|
||||
"push.residence_shared.body": "{{.UserName}} compartio {{.ResidenceName}} contigo",
|
||||
|
||||
"email.welcome.subject": "Bienvenido a Casera!",
|
||||
"email.verification.subject": "Verifica Tu Correo Electronico",
|
||||
"email.password_reset.subject": "Codigo de Restablecimiento de Contrasena",
|
||||
"email.tasks_report.subject": "Informe de Tareas para {{.ResidenceName}}",
|
||||
|
||||
"lookup.residence_type.house": "Casa",
|
||||
"lookup.residence_type.apartment": "Apartamento",
|
||||
"lookup.residence_type.condo": "Condominio",
|
||||
"lookup.residence_type.townhouse": "Casa Adosada",
|
||||
"lookup.residence_type.mobile_home": "Casa Movil",
|
||||
"lookup.residence_type.other": "Otro",
|
||||
|
||||
"lookup.task_category.plumbing": "Plomeria",
|
||||
"lookup.task_category.electrical": "Electricidad",
|
||||
"lookup.task_category.hvac": "Climatizacion",
|
||||
"lookup.task_category.appliances": "Electrodomesticos",
|
||||
"lookup.task_category.exterior": "Exterior",
|
||||
"lookup.task_category.interior": "Interior",
|
||||
"lookup.task_category.landscaping": "Jardineria",
|
||||
"lookup.task_category.safety": "Seguridad",
|
||||
"lookup.task_category.cleaning": "Limpieza",
|
||||
"lookup.task_category.pest_control": "Control de Plagas",
|
||||
"lookup.task_category.seasonal": "Estacional",
|
||||
"lookup.task_category.other": "Otro",
|
||||
|
||||
"lookup.task_priority.low": "Baja",
|
||||
"lookup.task_priority.medium": "Media",
|
||||
"lookup.task_priority.high": "Alta",
|
||||
"lookup.task_priority.urgent": "Urgente",
|
||||
|
||||
"lookup.task_status.pending": "Pendiente",
|
||||
"lookup.task_status.in_progress": "En Progreso",
|
||||
"lookup.task_status.completed": "Completada",
|
||||
"lookup.task_status.cancelled": "Cancelada",
|
||||
"lookup.task_status.archived": "Archivada",
|
||||
|
||||
"lookup.task_frequency.once": "Una Vez",
|
||||
"lookup.task_frequency.daily": "Diario",
|
||||
"lookup.task_frequency.weekly": "Semanal",
|
||||
"lookup.task_frequency.biweekly": "Cada 2 Semanas",
|
||||
"lookup.task_frequency.monthly": "Mensual",
|
||||
"lookup.task_frequency.quarterly": "Trimestral",
|
||||
"lookup.task_frequency.semiannually": "Cada 6 Meses",
|
||||
"lookup.task_frequency.annually": "Anual",
|
||||
|
||||
"lookup.contractor_specialty.plumber": "Plomero",
|
||||
"lookup.contractor_specialty.electrician": "Electricista",
|
||||
"lookup.contractor_specialty.hvac_technician": "Tecnico de Climatizacion",
|
||||
"lookup.contractor_specialty.handyman": "Manitas",
|
||||
"lookup.contractor_specialty.landscaper": "Jardinero",
|
||||
"lookup.contractor_specialty.roofer": "Techador",
|
||||
"lookup.contractor_specialty.painter": "Pintor",
|
||||
"lookup.contractor_specialty.carpenter": "Carpintero",
|
||||
"lookup.contractor_specialty.pest_control": "Control de Plagas",
|
||||
"lookup.contractor_specialty.cleaning": "Limpieza",
|
||||
"lookup.contractor_specialty.pool_service": "Servicio de Piscina",
|
||||
"lookup.contractor_specialty.general_contractor": "Contratista General",
|
||||
"lookup.contractor_specialty.other": "Otro"
|
||||
}
|
||||
187
internal/i18n/translations/fr.json
Normal file
187
internal/i18n/translations/fr.json
Normal file
@@ -0,0 +1,187 @@
|
||||
{
|
||||
"error.invalid_request_body": "Corps de requete non valide",
|
||||
"error.invalid_credentials": "Identifiants non valides",
|
||||
"error.account_inactive": "Le compte est inactif",
|
||||
"error.username_taken": "Nom d'utilisateur deja pris",
|
||||
"error.email_taken": "Email deja enregistre",
|
||||
"error.email_already_taken": "Email deja utilise",
|
||||
"error.registration_failed": "Echec de l'inscription",
|
||||
"error.not_authenticated": "Non authentifie",
|
||||
"error.failed_to_get_user": "Echec de la recuperation de l'utilisateur",
|
||||
"error.failed_to_update_profile": "Echec de la mise a jour du profil",
|
||||
"error.invalid_verification_code": "Code de verification non valide",
|
||||
"error.verification_code_expired": "Le code de verification a expire",
|
||||
"error.email_already_verified": "Email deja verifie",
|
||||
"error.verification_failed": "Echec de la verification",
|
||||
"error.failed_to_resend_verification": "Echec du renvoi de la verification",
|
||||
"error.rate_limit_exceeded": "Trop de demandes de reinitialisation de mot de passe. Veuillez reessayer plus tard.",
|
||||
"error.too_many_attempts": "Trop de tentatives. Veuillez demander un nouveau code.",
|
||||
"error.invalid_reset_token": "Jeton de reinitialisation non valide ou expire",
|
||||
"error.password_reset_failed": "Echec de la reinitialisation du mot de passe",
|
||||
"error.apple_signin_not_configured": "La connexion Apple n'est pas configuree",
|
||||
"error.apple_signin_failed": "Echec de la connexion Apple",
|
||||
"error.invalid_apple_token": "Jeton d'identite Apple non valide",
|
||||
|
||||
"error.invalid_task_id": "ID de tache non valide",
|
||||
"error.invalid_residence_id": "ID de propriete non valide",
|
||||
"error.invalid_contractor_id": "ID de prestataire non valide",
|
||||
"error.invalid_document_id": "ID de document non valide",
|
||||
"error.invalid_completion_id": "ID de completion non valide",
|
||||
"error.invalid_user_id": "ID d'utilisateur non valide",
|
||||
"error.invalid_notification_id": "ID de notification non valide",
|
||||
"error.invalid_device_id": "ID d'appareil non valide",
|
||||
|
||||
"error.task_not_found": "Tache non trouvee",
|
||||
"error.residence_not_found": "Propriete non trouvee",
|
||||
"error.contractor_not_found": "Prestataire non trouve",
|
||||
"error.document_not_found": "Document non trouve",
|
||||
"error.completion_not_found": "Completion de tache non trouvee",
|
||||
"error.user_not_found": "Utilisateur non trouve",
|
||||
"error.share_code_invalid": "Code de partage non valide",
|
||||
"error.share_code_expired": "Le code de partage a expire",
|
||||
|
||||
"error.task_access_denied": "Vous n'avez pas acces a cette tache",
|
||||
"error.residence_access_denied": "Vous n'avez pas acces a cette propriete",
|
||||
"error.contractor_access_denied": "Vous n'avez pas acces a ce prestataire",
|
||||
"error.document_access_denied": "Vous n'avez pas acces a ce document",
|
||||
"error.not_residence_owner": "Seul le proprietaire peut effectuer cette action",
|
||||
"error.cannot_remove_owner": "Impossible de retirer le proprietaire",
|
||||
"error.user_already_member": "L'utilisateur est deja membre de cette propriete",
|
||||
"error.properties_limit_reached": "Vous avez atteint le nombre maximum de proprietes pour votre abonnement",
|
||||
|
||||
"error.task_already_cancelled": "La tache est deja annulee",
|
||||
"error.task_already_archived": "La tache est deja archivee",
|
||||
|
||||
"error.failed_to_parse_form": "Echec de l'analyse du formulaire",
|
||||
"error.task_id_required": "task_id est requis",
|
||||
"error.invalid_task_id_value": "task_id non valide",
|
||||
"error.failed_to_upload_image": "Echec du telechargement de l'image",
|
||||
"error.residence_id_required": "residence_id est requis",
|
||||
"error.invalid_residence_id_value": "residence_id non valide",
|
||||
"error.title_required": "Le titre est requis",
|
||||
"error.failed_to_upload_file": "Echec du telechargement du fichier",
|
||||
|
||||
"message.logged_out": "Deconnexion reussie",
|
||||
"message.email_verified": "Email verifie avec succes",
|
||||
"message.verification_email_sent": "Email de verification envoye",
|
||||
"message.password_reset_email_sent": "Si un compte existe avec cet email, un code de reinitialisation a ete envoye.",
|
||||
"message.reset_code_verified": "Code verifie avec succes",
|
||||
"message.password_reset_success": "Mot de passe reinitialise avec succes. Veuillez vous connecter avec votre nouveau mot de passe.",
|
||||
|
||||
"message.task_deleted": "Tache supprimee avec succes",
|
||||
"message.task_in_progress": "Tache marquee comme en cours",
|
||||
"message.task_cancelled": "Tache annulee",
|
||||
"message.task_uncancelled": "Tache reactived",
|
||||
"message.task_archived": "Tache archivee",
|
||||
"message.task_unarchived": "Tache desarchivee",
|
||||
"message.completion_deleted": "Completion supprimee avec succes",
|
||||
|
||||
"message.residence_deleted": "Propriete supprimee avec succes",
|
||||
"message.user_removed": "Utilisateur retire de la propriete",
|
||||
"message.tasks_report_generated": "Rapport de taches genere avec succes",
|
||||
"message.tasks_report_sent": "Rapport de taches genere et envoye a {{.Email}}",
|
||||
"message.tasks_report_email_failed": "Rapport de taches genere mais l'email n'a pas pu etre envoye",
|
||||
|
||||
"message.contractor_deleted": "Prestataire supprime avec succes",
|
||||
|
||||
"message.document_deleted": "Document supprime avec succes",
|
||||
"message.document_activated": "Document active",
|
||||
"message.document_deactivated": "Document desactive",
|
||||
|
||||
"message.notification_marked_read": "Notification marquée comme lue",
|
||||
"message.all_notifications_marked_read": "Toutes les notifications marquées comme lues",
|
||||
"message.device_removed": "Appareil supprimé",
|
||||
|
||||
"message.subscription_upgraded": "Abonnement mis à niveau avec succès",
|
||||
"message.subscription_cancelled": "Abonnement annulé. Vous conserverez les avantages Pro jusqu'à la fin de votre période de facturation.",
|
||||
"message.subscription_restored": "Abonnement restauré avec succès",
|
||||
|
||||
"message.file_deleted": "Fichier supprimé avec succès",
|
||||
"message.static_data_refreshed": "Données statiques actualisées",
|
||||
|
||||
"error.notification_not_found": "Notification non trouvée",
|
||||
"error.invalid_platform": "Plateforme non valide",
|
||||
|
||||
"error.upgrade_trigger_not_found": "Déclencheur de mise à niveau non trouvé",
|
||||
"error.receipt_data_required": "receipt_data est requis pour iOS",
|
||||
"error.purchase_token_required": "purchase_token est requis pour Android",
|
||||
|
||||
"error.no_file_provided": "Aucun fichier fourni",
|
||||
|
||||
"error.failed_to_fetch_residence_types": "Échec de la récupération des types de propriété",
|
||||
"error.failed_to_fetch_task_categories": "Échec de la récupération des catégories de tâches",
|
||||
"error.failed_to_fetch_task_priorities": "Échec de la récupération des priorités de tâches",
|
||||
"error.failed_to_fetch_task_frequencies": "Échec de la récupération des fréquences de tâches",
|
||||
"error.failed_to_fetch_task_statuses": "Échec de la récupération des statuts de tâches",
|
||||
"error.failed_to_fetch_contractor_specialties": "Échec de la récupération des spécialités des prestataires",
|
||||
|
||||
"push.task_due_soon.title": "Tache Bientot Due",
|
||||
"push.task_due_soon.body": "{{.TaskTitle}} est due le {{.DueDate}}",
|
||||
"push.task_overdue.title": "Tache en Retard",
|
||||
"push.task_overdue.body": "{{.TaskTitle}} est en retard",
|
||||
"push.task_completed.title": "Tache Terminee",
|
||||
"push.task_completed.body": "{{.UserName}} a termine {{.TaskTitle}}",
|
||||
"push.task_assigned.title": "Nouvelle Tache Assignee",
|
||||
"push.task_assigned.body": "{{.TaskTitle}} vous a ete assignee",
|
||||
"push.residence_shared.title": "Propriete Partagee",
|
||||
"push.residence_shared.body": "{{.UserName}} a partage {{.ResidenceName}} avec vous",
|
||||
|
||||
"email.welcome.subject": "Bienvenue sur Casera !",
|
||||
"email.verification.subject": "Verifiez Votre Email",
|
||||
"email.password_reset.subject": "Code de Reinitialisation de Mot de Passe",
|
||||
"email.tasks_report.subject": "Rapport de Taches pour {{.ResidenceName}}",
|
||||
|
||||
"lookup.residence_type.house": "Maison",
|
||||
"lookup.residence_type.apartment": "Appartement",
|
||||
"lookup.residence_type.condo": "Copropriete",
|
||||
"lookup.residence_type.townhouse": "Maison de Ville",
|
||||
"lookup.residence_type.mobile_home": "Mobil-home",
|
||||
"lookup.residence_type.other": "Autre",
|
||||
|
||||
"lookup.task_category.plumbing": "Plomberie",
|
||||
"lookup.task_category.electrical": "Electricite",
|
||||
"lookup.task_category.hvac": "Climatisation",
|
||||
"lookup.task_category.appliances": "Electromenager",
|
||||
"lookup.task_category.exterior": "Exterieur",
|
||||
"lookup.task_category.interior": "Interieur",
|
||||
"lookup.task_category.landscaping": "Jardinage",
|
||||
"lookup.task_category.safety": "Securite",
|
||||
"lookup.task_category.cleaning": "Nettoyage",
|
||||
"lookup.task_category.pest_control": "Lutte Antiparasitaire",
|
||||
"lookup.task_category.seasonal": "Saisonnier",
|
||||
"lookup.task_category.other": "Autre",
|
||||
|
||||
"lookup.task_priority.low": "Basse",
|
||||
"lookup.task_priority.medium": "Moyenne",
|
||||
"lookup.task_priority.high": "Haute",
|
||||
"lookup.task_priority.urgent": "Urgente",
|
||||
|
||||
"lookup.task_status.pending": "En Attente",
|
||||
"lookup.task_status.in_progress": "En Cours",
|
||||
"lookup.task_status.completed": "Terminee",
|
||||
"lookup.task_status.cancelled": "Annulee",
|
||||
"lookup.task_status.archived": "Archivee",
|
||||
|
||||
"lookup.task_frequency.once": "Une Fois",
|
||||
"lookup.task_frequency.daily": "Quotidien",
|
||||
"lookup.task_frequency.weekly": "Hebdomadaire",
|
||||
"lookup.task_frequency.biweekly": "Toutes les 2 Semaines",
|
||||
"lookup.task_frequency.monthly": "Mensuel",
|
||||
"lookup.task_frequency.quarterly": "Trimestriel",
|
||||
"lookup.task_frequency.semiannually": "Tous les 6 Mois",
|
||||
"lookup.task_frequency.annually": "Annuel",
|
||||
|
||||
"lookup.contractor_specialty.plumber": "Plombier",
|
||||
"lookup.contractor_specialty.electrician": "Electricien",
|
||||
"lookup.contractor_specialty.hvac_technician": "Technicien CVC",
|
||||
"lookup.contractor_specialty.handyman": "Bricoleur",
|
||||
"lookup.contractor_specialty.landscaper": "Paysagiste",
|
||||
"lookup.contractor_specialty.roofer": "Couvreur",
|
||||
"lookup.contractor_specialty.painter": "Peintre",
|
||||
"lookup.contractor_specialty.carpenter": "Menuisier",
|
||||
"lookup.contractor_specialty.pest_control": "Desinsectisation",
|
||||
"lookup.contractor_specialty.cleaning": "Nettoyage",
|
||||
"lookup.contractor_specialty.pool_service": "Service Piscine",
|
||||
"lookup.contractor_specialty.general_contractor": "Entrepreneur General",
|
||||
"lookup.contractor_specialty.other": "Autre"
|
||||
}
|
||||
187
internal/i18n/translations/pt.json
Normal file
187
internal/i18n/translations/pt.json
Normal file
@@ -0,0 +1,187 @@
|
||||
{
|
||||
"error.invalid_request_body": "Corpo da solicitacao invalido",
|
||||
"error.invalid_credentials": "Credenciais invalidas",
|
||||
"error.account_inactive": "A conta esta inativa",
|
||||
"error.username_taken": "Nome de usuario ja em uso",
|
||||
"error.email_taken": "Email ja registrado",
|
||||
"error.email_already_taken": "Email ja em uso",
|
||||
"error.registration_failed": "Falha no registro",
|
||||
"error.not_authenticated": "Nao autenticado",
|
||||
"error.failed_to_get_user": "Falha ao obter usuario",
|
||||
"error.failed_to_update_profile": "Falha ao atualizar perfil",
|
||||
"error.invalid_verification_code": "Codigo de verificacao invalido",
|
||||
"error.verification_code_expired": "O codigo de verificacao expirou",
|
||||
"error.email_already_verified": "Email ja verificado",
|
||||
"error.verification_failed": "Falha na verificacao",
|
||||
"error.failed_to_resend_verification": "Falha ao reenviar verificacao",
|
||||
"error.rate_limit_exceeded": "Muitas solicitacoes de redefinicao de senha. Por favor, tente novamente mais tarde.",
|
||||
"error.too_many_attempts": "Muitas tentativas. Por favor, solicite um novo codigo.",
|
||||
"error.invalid_reset_token": "Token de redefinicao invalido ou expirado",
|
||||
"error.password_reset_failed": "Falha na redefinicao de senha",
|
||||
"error.apple_signin_not_configured": "O login com Apple nao esta configurado",
|
||||
"error.apple_signin_failed": "Falha no login com Apple",
|
||||
"error.invalid_apple_token": "Token de identidade Apple invalido",
|
||||
|
||||
"error.invalid_task_id": "ID da tarefa invalido",
|
||||
"error.invalid_residence_id": "ID da propriedade invalido",
|
||||
"error.invalid_contractor_id": "ID do prestador invalido",
|
||||
"error.invalid_document_id": "ID do documento invalido",
|
||||
"error.invalid_completion_id": "ID de conclusao invalido",
|
||||
"error.invalid_user_id": "ID do usuario invalido",
|
||||
"error.invalid_notification_id": "ID da notificacao invalido",
|
||||
"error.invalid_device_id": "ID do dispositivo invalido",
|
||||
|
||||
"error.task_not_found": "Tarefa nao encontrada",
|
||||
"error.residence_not_found": "Propriedade nao encontrada",
|
||||
"error.contractor_not_found": "Prestador nao encontrado",
|
||||
"error.document_not_found": "Documento nao encontrado",
|
||||
"error.completion_not_found": "Conclusao da tarefa nao encontrada",
|
||||
"error.user_not_found": "Usuario nao encontrado",
|
||||
"error.share_code_invalid": "Codigo de compartilhamento invalido",
|
||||
"error.share_code_expired": "O codigo de compartilhamento expirou",
|
||||
|
||||
"error.task_access_denied": "Voce nao tem acesso a esta tarefa",
|
||||
"error.residence_access_denied": "Voce nao tem acesso a esta propriedade",
|
||||
"error.contractor_access_denied": "Voce nao tem acesso a este prestador",
|
||||
"error.document_access_denied": "Voce nao tem acesso a este documento",
|
||||
"error.not_residence_owner": "Apenas o proprietario pode realizar esta acao",
|
||||
"error.cannot_remove_owner": "Nao e possivel remover o proprietario",
|
||||
"error.user_already_member": "O usuario ja e membro desta propriedade",
|
||||
"error.properties_limit_reached": "Voce atingiu o numero maximo de propriedades para sua assinatura",
|
||||
|
||||
"error.task_already_cancelled": "A tarefa ja esta cancelada",
|
||||
"error.task_already_archived": "A tarefa ja esta arquivada",
|
||||
|
||||
"error.failed_to_parse_form": "Falha ao analisar o formulario",
|
||||
"error.task_id_required": "task_id e obrigatorio",
|
||||
"error.invalid_task_id_value": "task_id invalido",
|
||||
"error.failed_to_upload_image": "Falha ao enviar imagem",
|
||||
"error.residence_id_required": "residence_id e obrigatorio",
|
||||
"error.invalid_residence_id_value": "residence_id invalido",
|
||||
"error.title_required": "Titulo e obrigatorio",
|
||||
"error.failed_to_upload_file": "Falha ao enviar arquivo",
|
||||
|
||||
"message.logged_out": "Logout realizado com sucesso",
|
||||
"message.email_verified": "Email verificado com sucesso",
|
||||
"message.verification_email_sent": "Email de verificacao enviado",
|
||||
"message.password_reset_email_sent": "Se existir uma conta com este email, um codigo de redefinicao foi enviado.",
|
||||
"message.reset_code_verified": "Codigo verificado com sucesso",
|
||||
"message.password_reset_success": "Senha redefinida com sucesso. Por favor, faca login com sua nova senha.",
|
||||
|
||||
"message.task_deleted": "Tarefa excluida com sucesso",
|
||||
"message.task_in_progress": "Tarefa marcada como em andamento",
|
||||
"message.task_cancelled": "Tarefa cancelada",
|
||||
"message.task_uncancelled": "Tarefa reativada",
|
||||
"message.task_archived": "Tarefa arquivada",
|
||||
"message.task_unarchived": "Tarefa desarquivada",
|
||||
"message.completion_deleted": "Conclusao excluida com sucesso",
|
||||
|
||||
"message.residence_deleted": "Propriedade excluida com sucesso",
|
||||
"message.user_removed": "Usuario removido da propriedade",
|
||||
"message.tasks_report_generated": "Relatorio de tarefas gerado com sucesso",
|
||||
"message.tasks_report_sent": "Relatorio de tarefas gerado e enviado para {{.Email}}",
|
||||
"message.tasks_report_email_failed": "Relatorio de tarefas gerado mas o email nao pode ser enviado",
|
||||
|
||||
"message.contractor_deleted": "Prestador excluido com sucesso",
|
||||
|
||||
"message.document_deleted": "Documento excluido com sucesso",
|
||||
"message.document_activated": "Documento ativado",
|
||||
"message.document_deactivated": "Documento desativado",
|
||||
|
||||
"message.notification_marked_read": "Notificação marcada como lida",
|
||||
"message.all_notifications_marked_read": "Todas as notificações marcadas como lidas",
|
||||
"message.device_removed": "Dispositivo removido",
|
||||
|
||||
"message.subscription_upgraded": "Assinatura atualizada com sucesso",
|
||||
"message.subscription_cancelled": "Assinatura cancelada. Você manterá os benefícios Pro até o final do seu período de faturamento.",
|
||||
"message.subscription_restored": "Assinatura restaurada com sucesso",
|
||||
|
||||
"message.file_deleted": "Arquivo excluído com sucesso",
|
||||
"message.static_data_refreshed": "Dados estáticos atualizados",
|
||||
|
||||
"error.notification_not_found": "Notificação não encontrada",
|
||||
"error.invalid_platform": "Plataforma inválida",
|
||||
|
||||
"error.upgrade_trigger_not_found": "Gatilho de atualização não encontrado",
|
||||
"error.receipt_data_required": "receipt_data é obrigatório para iOS",
|
||||
"error.purchase_token_required": "purchase_token é obrigatório para Android",
|
||||
|
||||
"error.no_file_provided": "Nenhum arquivo fornecido",
|
||||
|
||||
"error.failed_to_fetch_residence_types": "Falha ao buscar tipos de propriedade",
|
||||
"error.failed_to_fetch_task_categories": "Falha ao buscar categorias de tarefas",
|
||||
"error.failed_to_fetch_task_priorities": "Falha ao buscar prioridades de tarefas",
|
||||
"error.failed_to_fetch_task_frequencies": "Falha ao buscar frequências de tarefas",
|
||||
"error.failed_to_fetch_task_statuses": "Falha ao buscar status de tarefas",
|
||||
"error.failed_to_fetch_contractor_specialties": "Falha ao buscar especialidades de prestadores",
|
||||
|
||||
"push.task_due_soon.title": "Tarefa Proxima do Vencimento",
|
||||
"push.task_due_soon.body": "{{.TaskTitle}} vence em {{.DueDate}}",
|
||||
"push.task_overdue.title": "Tarefa Atrasada",
|
||||
"push.task_overdue.body": "{{.TaskTitle}} esta atrasada",
|
||||
"push.task_completed.title": "Tarefa Concluida",
|
||||
"push.task_completed.body": "{{.UserName}} concluiu {{.TaskTitle}}",
|
||||
"push.task_assigned.title": "Nova Tarefa Atribuida",
|
||||
"push.task_assigned.body": "{{.TaskTitle}} foi atribuida a voce",
|
||||
"push.residence_shared.title": "Propriedade Compartilhada",
|
||||
"push.residence_shared.body": "{{.UserName}} compartilhou {{.ResidenceName}} com voce",
|
||||
|
||||
"email.welcome.subject": "Bem-vindo ao Casera!",
|
||||
"email.verification.subject": "Verifique Seu Email",
|
||||
"email.password_reset.subject": "Codigo de Redefinicao de Senha",
|
||||
"email.tasks_report.subject": "Relatorio de Tarefas para {{.ResidenceName}}",
|
||||
|
||||
"lookup.residence_type.house": "Casa",
|
||||
"lookup.residence_type.apartment": "Apartamento",
|
||||
"lookup.residence_type.condo": "Condominio",
|
||||
"lookup.residence_type.townhouse": "Sobrado",
|
||||
"lookup.residence_type.mobile_home": "Casa Movel",
|
||||
"lookup.residence_type.other": "Outro",
|
||||
|
||||
"lookup.task_category.plumbing": "Encanamento",
|
||||
"lookup.task_category.electrical": "Eletrica",
|
||||
"lookup.task_category.hvac": "Climatizacao",
|
||||
"lookup.task_category.appliances": "Eletrodomesticos",
|
||||
"lookup.task_category.exterior": "Exterior",
|
||||
"lookup.task_category.interior": "Interior",
|
||||
"lookup.task_category.landscaping": "Paisagismo",
|
||||
"lookup.task_category.safety": "Seguranca",
|
||||
"lookup.task_category.cleaning": "Limpeza",
|
||||
"lookup.task_category.pest_control": "Controle de Pragas",
|
||||
"lookup.task_category.seasonal": "Sazonal",
|
||||
"lookup.task_category.other": "Outro",
|
||||
|
||||
"lookup.task_priority.low": "Baixa",
|
||||
"lookup.task_priority.medium": "Media",
|
||||
"lookup.task_priority.high": "Alta",
|
||||
"lookup.task_priority.urgent": "Urgente",
|
||||
|
||||
"lookup.task_status.pending": "Pendente",
|
||||
"lookup.task_status.in_progress": "Em Andamento",
|
||||
"lookup.task_status.completed": "Concluida",
|
||||
"lookup.task_status.cancelled": "Cancelada",
|
||||
"lookup.task_status.archived": "Arquivada",
|
||||
|
||||
"lookup.task_frequency.once": "Uma Vez",
|
||||
"lookup.task_frequency.daily": "Diario",
|
||||
"lookup.task_frequency.weekly": "Semanal",
|
||||
"lookup.task_frequency.biweekly": "Quinzenal",
|
||||
"lookup.task_frequency.monthly": "Mensal",
|
||||
"lookup.task_frequency.quarterly": "Trimestral",
|
||||
"lookup.task_frequency.semiannually": "Semestral",
|
||||
"lookup.task_frequency.annually": "Anual",
|
||||
|
||||
"lookup.contractor_specialty.plumber": "Encanador",
|
||||
"lookup.contractor_specialty.electrician": "Eletricista",
|
||||
"lookup.contractor_specialty.hvac_technician": "Tecnico de Climatizacao",
|
||||
"lookup.contractor_specialty.handyman": "Faz-tudo",
|
||||
"lookup.contractor_specialty.landscaper": "Paisagista",
|
||||
"lookup.contractor_specialty.roofer": "Telhadista",
|
||||
"lookup.contractor_specialty.painter": "Pintor",
|
||||
"lookup.contractor_specialty.carpenter": "Carpinteiro",
|
||||
"lookup.contractor_specialty.pest_control": "Controle de Pragas",
|
||||
"lookup.contractor_specialty.cleaning": "Limpeza",
|
||||
"lookup.contractor_specialty.pool_service": "Servico de Piscina",
|
||||
"lookup.contractor_specialty.general_contractor": "Empreiteiro Geral",
|
||||
"lookup.contractor_specialty.other": "Outro"
|
||||
}
|
||||
Reference in New Issue
Block a user