feat: add i18n support for Italian, Spanish, Portuguese and Russian

This commit is contained in:
2026-02-08 09:56:43 +01:00
parent a5995857e8
commit c66b77dbf8
10 changed files with 1556 additions and 10 deletions

View File

@@ -102,7 +102,11 @@ tests/
locales/ locales/
├── de.json # Deutsch (Fallback) ├── de.json # Deutsch (Fallback)
├── en.json ├── en.json
── fr.json ── fr.json
├── it.json # Italienisch
├── es.json # Spanisch
├── pt.json # Portugiesisch (BR)
└── ru.json # Russisch
``` ```
## Konventionen ## Konventionen
@@ -130,7 +134,8 @@ locales/
- Schlüssel: `section.key` (z.B. `home.title`) - Schlüssel: `section.key` (z.B. `home.title`)
- Im HTML: `data-i18n="key"` oder `${t('key')}` - Im HTML: `data-i18n="key"` oder `${t('key')}`
- Placeholder: `data-i18n-placeholder="key"` - Placeholder: `data-i18n-placeholder="key"`
- Neue Texte in **allen 3 Sprachen** hinzufügen - Neue Texte in **allen 7 Sprachen** hinzufügen (de, en, fr, it, es, pt, ru)
- Frontend nutzt Kurzcodes (`de`), Directus Langcodes (`de-DE`) — Mapping in `i18n.js` (`LOCALE_TO_DIRECTUS`)
## Aktuelle Probleme / Hinweise ## Aktuelle Probleme / Hinweise

View File

@@ -90,7 +90,7 @@ Kategorien mit hierarchischer Struktur.
|------|-----|--------------| |------|-----|--------------|
| `id` | integer | Primary Key | | `id` | integer | Primary Key |
| `categories_id` | UUID | FK → categories | | `categories_id` | UUID | FK → categories |
| `languages_code` | string | Sprachcode (`de`, `en`, `fr`) | | `languages_code` | string | Sprachcode (`de-DE`, `en-US`, `fr-FR`, `it-IT`, `es-ES`, `pt-BR`, `ru-RU`) |
| `name` | string | Übersetzter Name | | `name` | string | Übersetzter Name |
--- ---
@@ -117,8 +117,9 @@ Verfügbare Sprachen.
| Feld | Typ | Beschreibung | | Feld | Typ | Beschreibung |
|------|-----|--------------| |------|-----|--------------|
| `code` | string | Primary Key, z.B. `de`, `en`, `fr` | | `code` | string | Primary Key, z.B. `de-DE`, `en-US`, `fr-FR`, `it-IT`, `es-ES`, `pt-BR`, `ru-RU` |
| `name` | string | Sprachname | | `name` | string | Sprachname |
| `direction` | string | Textrichtung: `ltr` oder `rtl` |
--- ---
@@ -180,7 +181,7 @@ Zusätzliche Felder für User-Einstellungen.
| Feld | Typ | Beschreibung | | Feld | Typ | Beschreibung |
|------|-----|--------------| |------|-----|--------------|
| `preferred_currency` | string | Bevorzugte Währung: `USD`, `EUR`, `CHF` (Default: `USD`) | | `preferred_currency` | string | Bevorzugte Währung: `USD`, `EUR`, `CHF` (Default: `USD`) |
| `preferred_locale` | string | Bevorzugte Sprache: `de`, `en`, `fr` | | `preferred_locale` | string | Bevorzugte Sprache: `de-DE`, `en-US`, `fr-FR`, `it-IT`, `es-ES`, `pt-BR`, `ru-RU` |
**Hinweis:** Diese Felder müssen in Directus unter Settings → Data Model → directus_users angelegt werden. **Hinweis:** Diese Felder müssen in Directus unter Settings → Data Model → directus_users angelegt werden.

300
docs/add-category-translations.sh Executable file
View File

@@ -0,0 +1,300 @@
#!/bin/bash
# Add translations for new languages to existing categories
# Usage: DIRECTUS_TOKEN=your_admin_token bash docs/add-category-translations.sh
#
# This script adds it-IT, es-ES, pt-BR, ru-RU translations to all categories.
# It reads existing categories from the API and creates missing translations.
API="https://api.dgray.io"
TOKEN="${DIRECTUS_TOKEN:?Set DIRECTUS_TOKEN environment variable}"
add_translation() {
local category_id="$1" lang_code="$2" name="$3"
curl -s -X POST "$API/items/categories_translations" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d "{
\"categories_id\": \"$category_id\",
\"languages_code\": \"$lang_code\",
\"name\": \"$name\"
}" > /dev/null 2>&1
}
add_all_translations() {
local category_id="$1"
local name_it="$2" name_es="$3" name_pt="$4" name_ru="$5"
add_translation "$category_id" "it-IT" "$name_it"
add_translation "$category_id" "es-ES" "$name_es"
add_translation "$category_id" "pt-BR" "$name_pt"
add_translation "$category_id" "ru-RU" "$name_ru"
}
echo "=== Adding translations (it-IT, es-ES, pt-BR, ru-RU) ==="
echo ""
# Clean up orphaned translations (categories_id = null) from previous runs
echo "Cleaning up orphaned translations..."
ORPHANS=$(curl -s "$API/items/categories_translations?filter[categories_id][_null]=true&fields=id&limit=-1" \
-H "Authorization: Bearer $TOKEN")
ORPHAN_IDS=$(echo "$ORPHANS" | grep -o '"id":[0-9]*' | cut -d: -f2 | tr '\n' ',' | sed 's/,$//')
if [ -n "$ORPHAN_IDS" ]; then
curl -s -X DELETE "$API/items/categories_translations" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d "[$ORPHAN_IDS]" > /dev/null 2>&1
echo " ✓ removed orphaned entries"
fi
# Fetch all categories to get their IDs (no status filter for admin)
echo "Fetching categories..."
CATEGORIES=$(curl -s "$API/items/categories?fields=id,slug&limit=-1" \
-H "Authorization: Bearer $TOKEN")
get_id() {
local slug="$1"
echo "$CATEGORIES" | python3 -c "
import json, sys
data = json.load(sys.stdin).get('data', [])
for cat in data:
if cat.get('slug') == '$slug':
print(cat['id'])
break
"
}
# ── 1. Electronics ──
echo "1/12 Electronics..."
ID=$(get_id "electronics")
add_all_translations "$ID" "Elettronica" "Electrónica" "Eletrônicos" "Электроника"
ID=$(get_id "phones")
add_all_translations "$ID" "Telefoni e Tablet" "Teléfonos y Tablets" "Celulares e Tablets" "Телефоны и планшеты"
ID=$(get_id "computers")
add_all_translations "$ID" "Computer e Accessori" "Ordenadores y Accesorios" "Computadores e Acessórios" "Компьютеры и аксессуары"
ID=$(get_id "tv-audio")
add_all_translations "$ID" "TV, Audio e Video" "TV, Audio y Vídeo" "TV, Áudio e Vídeo" "ТВ, аудио и видео"
ID=$(get_id "gaming")
add_all_translations "$ID" "Gaming e Console" "Gaming y Consolas" "Games e Consoles" "Игры и консоли"
ID=$(get_id "appliances")
add_all_translations "$ID" "Elettrodomestici" "Electrodomésticos" "Eletrodomésticos" "Бытовая техника"
ID=$(get_id "cameras")
add_all_translations "$ID" "Fotocamere e Fotografia" "Cámaras y Fotografía" "Câmeras e Fotografia" "Камеры и фотография"
echo " ✓ done"
# ── 2. Vehicles ──
echo "2/12 Vehicles..."
ID=$(get_id "vehicles")
add_all_translations "$ID" "Veicoli" "Vehículos" "Veículos" "Транспорт"
ID=$(get_id "cars")
add_all_translations "$ID" "Auto" "Coches" "Carros" "Автомобили"
ID=$(get_id "motorcycles")
add_all_translations "$ID" "Moto" "Motos" "Motos" "Мотоциклы"
ID=$(get_id "bikes")
add_all_translations "$ID" "Biciclette ed E-Bike" "Bicicletas y E-Bikes" "Bicicletas e E-Bikes" "Велосипеды и электровелосипеды"
ID=$(get_id "vehicle-parts")
add_all_translations "$ID" "Ricambi e Accessori" "Recambios y Accesorios" "Peças e Acessórios" "Запчасти и аксессуары"
ID=$(get_id "boats")
add_all_translations "$ID" "Barche e Imbarcazioni" "Barcos y Embarcaciones" "Barcos e Embarcações" "Лодки и водный транспорт"
echo " ✓ done"
# ── 3. Home & Garden ──
echo "3/12 Home & Garden..."
ID=$(get_id "home-garden")
add_all_translations "$ID" "Casa e Giardino" "Hogar y Jardín" "Casa e Jardim" "Дом и сад"
ID=$(get_id "furniture")
add_all_translations "$ID" "Mobili" "Muebles" "Móveis" "Мебель"
ID=$(get_id "kitchen")
add_all_translations "$ID" "Cucina" "Cocina" "Cozinha" "Кухня"
ID=$(get_id "garden")
add_all_translations "$ID" "Giardino e Outdoor" "Jardín y Exterior" "Jardim e Exterior" "Сад и отдых"
ID=$(get_id "tools")
add_all_translations "$ID" "Utensili e Officina" "Herramientas y Taller" "Ferramentas e Oficina" "Инструменты"
ID=$(get_id "decoration")
add_all_translations "$ID" "Decorazioni e Arte" "Decoración y Arte" "Decoração e Arte" "Декор и искусство"
ID=$(get_id "bathroom")
add_all_translations "$ID" "Bagno e Sanitari" "Baño y Sanitarios" "Banheiro" "Ванная"
echo " ✓ done"
# ── 4. Fashion & Accessories ──
echo "4/12 Fashion..."
ID=$(get_id "fashion")
add_all_translations "$ID" "Moda e Accessori" "Moda y Accesorios" "Moda e Acessórios" "Мода и аксессуары"
ID=$(get_id "women")
add_all_translations "$ID" "Moda Donna" "Moda Mujer" "Moda Feminina" "Женская одежда"
ID=$(get_id "men")
add_all_translations "$ID" "Moda Uomo" "Moda Hombre" "Moda Masculina" "Мужская одежда"
ID=$(get_id "kids-fashion")
add_all_translations "$ID" "Moda Bambini" "Moda Infantil" "Moda Infantil" "Детская одежда"
ID=$(get_id "shoes")
add_all_translations "$ID" "Scarpe" "Zapatos" "Sapatos" "Обувь"
ID=$(get_id "watches-jewelry")
add_all_translations "$ID" "Orologi e Gioielli" "Relojes y Joyas" "Relógios e Joias" "Часы и украшения"
ID=$(get_id "bags")
add_all_translations "$ID" "Borse e Bagagli" "Bolsos y Equipaje" "Bolsas e Bagagem" "Сумки и багаж"
echo " ✓ done"
# ── 5. Sports & Leisure ──
echo "5/12 Sports..."
ID=$(get_id "sports")
add_all_translations "$ID" "Sport e Tempo Libero" "Deportes y Ocio" "Esportes e Lazer" "Спорт и отдых"
ID=$(get_id "fitness")
add_all_translations "$ID" "Fitness e Palestra" "Fitness y Gimnasio" "Fitness e Academia" "Фитнес"
ID=$(get_id "outdoor-sports")
add_all_translations "$ID" "Escursionismo e Outdoor" "Senderismo y Outdoor" "Trilhas e Outdoor" "Туризм и походы"
ID=$(get_id "winter-sports")
add_all_translations "$ID" "Sport Invernali" "Deportes de Invierno" "Esportes de Inverno" "Зимний спорт"
ID=$(get_id "water-sports")
add_all_translations "$ID" "Sport Acquatici" "Deportes Acuáticos" "Esportes Aquáticos" "Водный спорт"
ID=$(get_id "team-sports")
add_all_translations "$ID" "Sport di Squadra" "Deportes de Equipo" "Esportes Coletivos" "Командный спорт"
ID=$(get_id "cycling")
add_all_translations "$ID" "Accessori Ciclismo" "Equipamiento Ciclismo" "Equipamento Ciclismo" "Велоаксессуары"
echo " ✓ done"
# ── 6. Family & Kids ──
echo "6/12 Family & Kids..."
ID=$(get_id "family-kids")
add_all_translations "$ID" "Famiglia e Bambini" "Familia y Niños" "Família e Crianças" "Семья и дети"
ID=$(get_id "toys")
add_all_translations "$ID" "Giocattoli e Giochi" "Juguetes y Juegos" "Brinquedos e Jogos" "Игрушки и игры"
ID=$(get_id "baby")
add_all_translations "$ID" "Neonati e Prima Infanzia" "Bebé y Primera Infancia" "Bebê e Primeira Infância" "Для малышей"
ID=$(get_id "school")
add_all_translations "$ID" "Materiale Scolastico" "Material Escolar" "Material Escolar" "Школьные принадлежности"
echo " ✓ done"
# ── 7. Books & Media ──
echo "7/12 Books & Media..."
ID=$(get_id "books-media")
add_all_translations "$ID" "Libri e Media" "Libros y Medios" "Livros e Mídia" "Книги и медиа"
ID=$(get_id "fiction")
add_all_translations "$ID" "Narrativa" "Ficción" "Ficção" "Художественная литература"
ID=$(get_id "nonfiction")
add_all_translations "$ID" "Saggistica e Scienze" "No Ficción y Ciencia" "Não Ficção e Ciência" "Нон-фикшн и наука"
ID=$(get_id "textbooks")
add_all_translations "$ID" "Libri di Testo e Corsi" "Libros de Texto y Cursos" "Livros Didáticos e Cursos" "Учебники и курсы"
ID=$(get_id "music-movies")
add_all_translations "$ID" "Musica, Film e Giochi" "Música, Películas y Juegos" "Música, Filmes e Jogos" "Музыка, фильмы и игры"
echo " ✓ done"
# ── 8. Pets & Animals ──
echo "8/12 Pets..."
ID=$(get_id "pets")
add_all_translations "$ID" "Animali e Accessori" "Mascotas y Animales" "Animais e Acessórios" "Животные"
ID=$(get_id "pet-supplies")
add_all_translations "$ID" "Accessori per Animali" "Accesorios para Mascotas" "Acessórios para Animais" "Зоотовары"
ID=$(get_id "pet-adoption")
add_all_translations "$ID" "Adozione" "Adopción" "Adoção" "Усыновление"
echo " ✓ done"
# ── 9. Jobs & Services ──
echo "9/12 Jobs..."
ID=$(get_id "jobs")
add_all_translations "$ID" "Lavoro e Servizi" "Empleo y Servicios" "Empregos e Serviços" "Работа и услуги"
ID=$(get_id "full-time")
add_all_translations "$ID" "Tempo Pieno" "Tiempo Completo" "Tempo Integral" "Полная занятость"
ID=$(get_id "part-time")
add_all_translations "$ID" "Part-Time e Lavoretti" "Tiempo Parcial y Minijobs" "Meio Período" "Частичная занятость"
ID=$(get_id "freelance")
add_all_translations "$ID" "Freelance e Remoto" "Freelance y Remoto" "Freelance e Remoto" "Фриланс и удалёнка"
ID=$(get_id "services")
add_all_translations "$ID" "Servizi e Artigianato" "Servicios y Oficios" "Serviços e Artesanato" "Услуги и ремесло"
echo " ✓ done"
# ── 10. Real Estate ──
echo "10/12 Real Estate..."
ID=$(get_id "real-estate")
add_all_translations "$ID" "Immobili" "Inmuebles" "Imóveis" "Недвижимость"
ID=$(get_id "apartments")
add_all_translations "$ID" "Appartamenti" "Pisos" "Apartamentos" "Квартиры"
ID=$(get_id "houses")
add_all_translations "$ID" "Case" "Casas" "Casas" "Дома"
ID=$(get_id "rooms")
add_all_translations "$ID" "Stanze e Coinquilini" "Habitaciones y Pisos Compartidos" "Quartos e Repúblicas" "Комнаты и совместное проживание"
ID=$(get_id "commercial")
add_all_translations "$ID" "Commerciale" "Comercial" "Comercial" "Коммерческая недвижимость"
echo " ✓ done"
# ── 11. Collectibles & Hobbies ──
echo "11/12 Collectibles..."
ID=$(get_id "collectibles")
add_all_translations "$ID" "Collezionismo e Hobby" "Coleccionismo y Hobbies" "Colecionáveis e Hobbies" "Коллекционирование и хобби"
ID=$(get_id "antiques")
add_all_translations "$ID" "Antiquariato" "Antigüedades" "Antiguidades" "Антиквариат"
ID=$(get_id "coins-stamps")
add_all_translations "$ID" "Monete e Francobolli" "Monedas y Sellos" "Moedas e Selos" "Монеты и марки"
ID=$(get_id "models")
add_all_translations "$ID" "Modellismo e Figurine" "Modelismo y Figuras" "Modelismo e Figuras" "Моделизм и фигурки"
ID=$(get_id "art-crafts")
add_all_translations "$ID" "Arte e Fatto a Mano" "Arte y Hecho a Mano" "Arte e Artesanato" "Искусство и хендмейд"
echo " ✓ done"
# ── 12. Other ──
echo "12/12 Other..."
ID=$(get_id "other")
add_all_translations "$ID" "Altro" "Otros" "Outros" "Прочее"
ID=$(get_id "free-stuff")
add_all_translations "$ID" "Gratis" "Gratis" "Grátis" "Бесплатно"
ID=$(get_id "barter")
add_all_translations "$ID" "Baratto e Scambio" "Trueque e Intercambio" "Troca" "Обмен"
ID=$(get_id "lost-found")
add_all_translations "$ID" "Oggetti Smarriti" "Objetos Perdidos" "Achados e Perdidos" "Находки"
echo " ✓ done"
echo ""
echo "=== Translation import complete! ==="
echo "4 languages × 71 categories = 284 translations added."

View File

@@ -377,6 +377,21 @@ class PageHome extends HTMLElement {
}) })
} }
const priceBtn = this.querySelector('#toggle-price-filter span')
if (priceBtn) priceBtn.textContent = t('search.priceRange')
const clearBtn = this.querySelector('#clear-filters')
if (clearBtn) clearBtn.textContent = t('search.clearAll')
const applyBtn = this.querySelector('#apply-price')
if (applyBtn) applyBtn.textContent = t('search.apply')
const minInput = this.querySelector('#min-price')
if (minInput) minInput.placeholder = t('search.min')
const maxInput = this.querySelector('#max-price')
if (maxInput) maxInput.placeholder = t('search.max')
const searchBox = this.querySelector('search-box') const searchBox = this.querySelector('search-box')
if (searchBox) searchBox.loadAndRender() if (searchBox) searchBox.loadAndRender()
} }

View File

@@ -5,9 +5,28 @@
*/ */
/** /**
* @typedef {'de' | 'en' | 'fr'} Locale * @typedef {'de' | 'en' | 'fr' | 'it' | 'es' | 'pt' | 'ru'} Locale
*/ */
/**
* Mapping from short locale codes (used in frontend) to
* Directus long locale codes (used in categories_translations etc.)
* @type {Object<Locale, string>}
*/
const LOCALE_TO_DIRECTUS = {
de: 'de-DE',
en: 'en-US',
fr: 'fr-FR',
it: 'it-IT',
es: 'es-ES',
pt: 'pt-BR',
ru: 'ru-RU'
}
const DIRECTUS_TO_LOCALE = Object.fromEntries(
Object.entries(LOCALE_TO_DIRECTUS).map(([k, v]) => [v, k])
)
/** /**
* I18n Service class * I18n Service class
* @class * @class
@@ -21,7 +40,7 @@ class I18n {
/** @type {Locale} */ /** @type {Locale} */
this.fallbackLocale = 'de' this.fallbackLocale = 'de'
/** @type {Locale[]} */ /** @type {Locale[]} */
this.supportedLocales = ['de', 'en', 'fr'] this.supportedLocales = ['de', 'en', 'fr', 'it', 'es', 'pt', 'ru']
/** @type {Set<Function>} */ /** @type {Set<Function>} */
this.subscribers = new Set() this.subscribers = new Set()
/** @type {boolean} */ /** @type {boolean} */
@@ -198,12 +217,35 @@ class I18n {
const names = { const names = {
de: 'Deutsch', de: 'Deutsch',
en: 'English', en: 'English',
fr: 'Français' fr: 'Français',
it: 'Italiano',
es: 'Español',
pt: 'Português',
ru: 'Русский'
} }
return names[locale] || locale return names[locale] || locale
} }
/**
* Get the Directus language code for a frontend locale
* @param {Locale} [locale] - Frontend locale (defaults to current)
* @returns {string} Directus language code (e.g. 'de-DE')
*/
getDirectusLocale(locale) {
return LOCALE_TO_DIRECTUS[locale || this.currentLocale] || LOCALE_TO_DIRECTUS[this.fallbackLocale]
}
/**
* Get the frontend locale for a Directus language code
* @param {string} directusCode - Directus code (e.g. 'it-IT')
* @returns {Locale}
*/
fromDirectusLocale(directusCode) {
return DIRECTUS_TO_LOCALE[directusCode] || directusCode?.split('-')[0] || this.fallbackLocale
}
} }
export const i18n = new I18n() export const i18n = new I18n()
export const t = (key, params) => i18n.t(key, params) export const t = (key, params) => i18n.t(key, params)
export const getCurrentLanguage = () => i18n.getLocale() export const getCurrentLanguage = () => i18n.getLocale()
export { LOCALE_TO_DIRECTUS, DIRECTUS_TO_LOCALE }

View File

@@ -3,7 +3,7 @@
*/ */
import { directus } from './directus.js' import { directus } from './directus.js'
import { getCurrentLanguage } from '../i18n.js' import { getCurrentLanguage, LOCALE_TO_DIRECTUS } from '../i18n.js'
class CategoriesService { class CategoriesService {
constructor() { constructor() {
@@ -126,10 +126,13 @@ class CategoriesService {
getTranslatedName(category, lang = null) { getTranslatedName(category, lang = null) {
const currentLang = lang || getCurrentLanguage() const currentLang = lang || getCurrentLanguage()
const directusCode = LOCALE_TO_DIRECTUS[currentLang] || currentLang
if (category.translations && Array.isArray(category.translations)) { if (category.translations && Array.isArray(category.translations)) {
const translation = category.translations.find( const translation = category.translations.find(
t => t.languages_code === currentLang || t.languages_code?.startsWith(currentLang) t => t.languages_code === directusCode
|| t.languages_code === currentLang
|| t.languages_code?.startsWith(currentLang)
) )
if (translation?.name) { if (translation?.name) {
return translation.name return translation.name

295
locales/es.json Normal file
View File

@@ -0,0 +1,295 @@
{
"header": {
"searchPlaceholder": "¿Qué estás buscando?",
"createListing": "Crear anuncio",
"toggleTheme": "Cambiar tema",
"selectLanguage": "Seleccionar idioma",
"profile": "Perfil"
},
"footer": {
"rights": "Todos los derechos reservados.",
"about": "Acerca de",
"privacy": "Privacidad",
"terms": "Condiciones",
"contact": "Contacto"
},
"home": {
"title": "Bienvenido a dgray.io",
"subtitle": "Encuentra grandes ofertas cerca de ti o vende lo que ya no necesitas.",
"browseListings": "Explorar anuncios",
"createListing": "Crear anuncio",
"categories": "Categorías",
"recentListings": "Anuncios recientes",
"placeholderTitle": "Anuncio de ejemplo",
"placeholderLocation": "Ubicación",
"addFavorite": "Añadir a favoritos",
"removeFavorite": "Eliminar de favoritos",
"noListings": "No se encontraron anuncios",
"loadMore": "Cargar más",
"pullToRefresh": "Desliza para actualizar"
},
"common": {
"loading": "Cargando...",
"error": "Error al cargar",
"close": "Cerrar",
"remove": "Eliminar",
"home": "Inicio"
},
"error": {
"title": "Algo salió mal",
"retry": "Intentar de nuevo",
"offline": "Sin conexión a internet"
},
"search": {
"title": "Buscar",
"placeholder": "Introduce un término de búsqueda...",
"allCategories": "Todas las categorías",
"allSubcategories": "Todas las subcategorías",
"currentLocation": "Ubicación actual",
"locating": "Localizando...",
"searchButton": "Buscar",
"loading": "Buscando...",
"enterQuery": "Introduce un término de búsqueda para encontrar anuncios.",
"noResults": "No se encontraron resultados. Prueba con otro término de búsqueda.",
"resultsCount": "{{count}} resultados encontrados",
"allIn": "Todo en",
"clearAll": "Borrar todo",
"radiusAround": "{{radius}} km de radio",
"priceRange": "Precio",
"min": "Mín",
"max": "Máx",
"apply": "Aplicar",
"sortBy": "Ordenar por",
"sortNewest": "Más recientes",
"sortOldest": "Más antiguos",
"sortPriceAsc": "Precio: de menor a mayor",
"sortPriceDesc": "Precio: de mayor a menor",
"sortDistance": "Cercanos"
},
"countries": {
"ch": "Suiza",
"de": "Alemania",
"at": "Austria",
"fr": "Francia",
"it": "Italia",
"li": "Liechtenstein"
},
"listing": {
"notFound": "Este anuncio no fue encontrado.",
"backHome": "Volver al inicio",
"description": "Descripción",
"location": "Ubicación",
"seller": "Vendedor",
"anonymousSeller": "Vendedor anónimo",
"memberSince": "Miembro desde",
"postedOn": "Publicado el",
"contactSeller": "Contactar al vendedor",
"paymentInfo": "El pago se realiza directamente a través de Monero (XMR).",
"moneroAddress": "Dirección Monero del vendedor",
"noMoneroAddress": "No se proporcionó dirección Monero",
"copyAddress": "Copiar dirección",
"contactHint": "Copia la dirección y envía el importe con tu monedero Monero.",
"priceOnRequest": "Precio a consultar",
"shippingAvailable": "Envío disponible",
"viewSingular": "visita",
"viewPlural": "visitas",
"share": "Compartir",
"report": "Reportar",
"moreFromSeller": "Más de este vendedor",
"edit": "Editar",
"expired": "Caducado",
"expiresIn1Day": "Queda 1 día",
"expiresInDays": "Quedan {{days}} días"
},
"chat": {
"title": "Enviar mensaje",
"placeholder": "Escribe un mensaje...",
"encrypted": "Cifrado de extremo a extremo",
"startConversation": "Inicia una conversación con el vendedor.",
"send": "Enviar",
"unavailable": "Chat no disponible"
},
"create": {
"title": "Crear anuncio",
"editTitle": "Editar anuncio",
"listingTitle": "Título",
"titlePlaceholder": "¿Qué quieres vender?",
"category": "Categoría",
"selectCategory": "Seleccionar categoría",
"condition": "Estado",
"conditionNew": "Nuevo",
"conditionLikeNew": "Como nuevo",
"conditionGood": "Bueno",
"conditionFair": "Aceptable",
"conditionPoor": "Deficiente",
"price": "Precio",
"currency": "Moneda",
"priceMode": "Modo de precio",
"priceModeFiat": "Precio fiat fijo",
"priceModeXmr": "Precio XMR fijo",
"priceModeHint": "Fiat fijo: El importe en fiat se mantiene igual. XMR fijo: El importe en XMR se mantiene igual.",
"shippingAvailable": "Envío disponible",
"shippingCost": "Coste de envío",
"shippingCostPlaceholder": "p. ej. 5,00",
"location": "Ubicación",
"locationPlaceholder": "Ciudad, código postal o dirección",
"locationHint": "Elige la ubicación de tu anuncio",
"description": "Descripción",
"descriptionPlaceholder": "Describe tu artículo en detalle...",
"images": "Imágenes",
"uploadImages": "Subir imágenes (máx. 5)",
"moneroAddress": "Tu dirección Monero",
"moneroPlaceholder": "4... o 8...",
"moneroHint": "Los compradores enviarán el pago directamente a esta dirección.",
"cancel": "Cancelar",
"publish": "Publicar",
"publishing": "Publicando...",
"saveChanges": "Guardar cambios",
"saving": "Guardando...",
"publishFailed": "Error al publicar. Inténtalo de nuevo.",
"invalidMoneroAddress": "Dirección Monero no válida. Comprueba el formato.",
"draftRestored": "Borrador restaurado",
"clearDraft": "Descartar"
},
"notFound": {
"title": "Página no encontrada",
"message": "La página que buscas no existe.",
"backHome": "Volver al inicio"
},
"cropper": {
"title": "Recortar imagen",
"preview": "Vista previa:",
"cancel": "Cancelar",
"confirm": "Aplicar",
"aspectRatio": "Proporción:",
"free": "Libre"
},
"captcha": {
"verify": "No soy un robot",
"verified": "Verificado",
"solving": "Verificando...",
"attempts": "intentos",
"error": "Error - inténtalo de nuevo"
},
"profile": {
"myListings": "Mis anuncios",
"messages": "Mensajes",
"favorites": "Favoritos",
"settings": "Ajustes"
},
"auth": {
"login": "Iniciar sesión",
"logout": "Cerrar sesión",
"loggingIn": "Iniciando sesión...",
"yourUuid": "Tu UUID",
"enterUuid": "Introduce tu UUID",
"invalidUuid": "UUID no válido o cuenta no encontrada",
"noAccount": "¿Aún no tienes cuenta?",
"hasAccount": "¿Ya tienes cuenta?",
"createAccount": "Crear cuenta",
"registerInfo": "Se generará un UUID único para ti. Este UUID es tu único acceso. ¡Guárdalo de forma segura!",
"generateUuid": "Generar UUID",
"creating": "Creando...",
"accountCreated": "¡Cuenta creada!",
"important": "¡Importante!",
"saveUuidWarning": "Guarda este UUID de forma segura. Es tu único acceso a tu cuenta. ¡No hay forma de recuperarlo!",
"copy": "Copiar",
"downloadBackup": "Descargar copia de seguridad",
"confirmSaved": "He guardado mi UUID",
"registrationFailed": "Error en el registro",
"loginRequired": "Inicia sesión para continuar"
},
"favorites": {
"title": "Favoritos",
"subtitle": "Tus anuncios guardados",
"empty": "Sin favoritos",
"emptyHint": "Pulsa el icono de corazón en un anuncio para guardarlo.",
"browse": "Explorar anuncios"
},
"myListings": {
"title": "Mis anuncios",
"subtitle": "Gestiona tus anuncios",
"empty": "Sin anuncios",
"emptyHint": "Aún no has creado ningún anuncio.",
"create": "Crear anuncio",
"loginRequired": "Inicio de sesión requerido",
"loginHint": "Inicia sesión para ver tus anuncios.",
"login": "Iniciar sesión",
"status": {
"draft": "Borrador",
"archived": "Archivado",
"processing": "Pendiente",
"published": "Publicado",
"expired": "Caducado"
}
},
"messages": {
"title": "Mensajes",
"subtitle": "Tus conversaciones",
"empty": "Sin mensajes",
"emptyHint": "Contacta a un vendedor para iniciar una conversación.",
"browse": "Explorar anuncios",
"loginRequired": "Inicio de sesión requerido",
"loginHint": "Inicia sesión para ver tus mensajes.",
"login": "Iniciar sesión",
"unknownListing": "Anuncio desconocido",
"today": "Hoy",
"yesterday": "Ayer",
"daysAgo": "Hace {{days}} días"
},
"settings": {
"title": "Ajustes",
"appearance": "Apariencia",
"theme": "Tema",
"themeLight": "Claro",
"themeDark": "Oscuro",
"themeSystem": "Sistema",
"language": "Idioma",
"account": "Cuenta",
"userId": "ID de usuario",
"logout": "Cerrar sesión",
"login": "Iniciar sesión",
"notLoggedIn": "No has iniciado sesión.",
"loggedOut": "Sesión cerrada correctamente",
"data": "Datos",
"favorites": "Favoritos",
"favoritesHint": "Eliminar favoritos guardados localmente",
"searchHistory": "Historial de búsqueda",
"searchHistoryHint": "Eliminar filtros de búsqueda guardados",
"clear": "Borrar",
"confirmClearFavorites": "¿Eliminar todos los favoritos?",
"confirmClearSearch": "¿Eliminar el historial de búsqueda?",
"favoritesCleared": "Favoritos eliminados",
"searchCleared": "Historial de búsqueda eliminado",
"about": "Acerca de",
"currency": "Moneda",
"currencyChanged": "Moneda cambiada"
},
"notifications": {
"title": "Notificaciones",
"empty": "Sin notificaciones",
"markAllRead": "Marcar todo como leído",
"listing_created": "Tu anuncio ha sido creado",
"listing_published": "Tu anuncio ha sido publicado",
"listing_expired": "Tu anuncio ha caducado",
"new_message": "Tienes un mensaje nuevo",
"favorite_added": "Alguien ha guardado tu anuncio"
},
"payment": {
"title": "Pago",
"listingFee": "Tarifa del anuncio",
"feeInfo": "1 anuncio = 1 mes = {{amount}} {{currency}}",
"payNow": "Pagar ahora",
"paying": "Procesando pago...",
"processing": "Pago recibido, esperando confirmación...",
"success": "¡Pago completado! Tu anuncio ya está publicado.",
"expired": "El pago ha caducado. Inténtalo de nuevo.",
"failed": "El pago ha fallado. Inténtalo de nuevo.",
"resume": "Reanudar pago",
"pending": "Pago pendiente",
"required": "Se requiere una tarifa de {{amount}} {{currency}} para publicar.",
"paidViaXmr": "Pagado con Monero (XMR)",
"awaitingConfirmation": "Esperando confirmación en la cadena de bloques",
"awaitingHint": "Tu pago ha sido recibido. El anuncio se publicará automáticamente tras 1 confirmación."
}
}

295
locales/it.json Normal file
View File

@@ -0,0 +1,295 @@
{
"header": {
"searchPlaceholder": "Cosa stai cercando?",
"createListing": "Crea annuncio",
"toggleTheme": "Cambia tema",
"selectLanguage": "Seleziona lingua",
"profile": "Profilo"
},
"footer": {
"rights": "Tutti i diritti riservati.",
"about": "Chi siamo",
"privacy": "Privacy",
"terms": "Condizioni",
"contact": "Contatto"
},
"home": {
"title": "Benvenuto su dgray.io",
"subtitle": "Trova ottime offerte vicino a te o vendi ciò che non ti serve più.",
"browseListings": "Sfoglia annunci",
"createListing": "Crea annuncio",
"categories": "Categorie",
"recentListings": "Annunci recenti",
"placeholderTitle": "Annuncio di esempio",
"placeholderLocation": "Località",
"addFavorite": "Aggiungi ai preferiti",
"removeFavorite": "Rimuovi dai preferiti",
"noListings": "Nessun annuncio trovato",
"loadMore": "Carica altri",
"pullToRefresh": "Trascina per aggiornare"
},
"common": {
"loading": "Caricamento...",
"error": "Errore di caricamento",
"close": "Chiudi",
"remove": "Rimuovi",
"home": "Home"
},
"error": {
"title": "Qualcosa è andato storto",
"retry": "Riprova",
"offline": "Nessuna connessione internet"
},
"search": {
"title": "Ricerca",
"placeholder": "Inserisci un termine di ricerca...",
"allCategories": "Tutte le categorie",
"allSubcategories": "Tutte le sottocategorie",
"currentLocation": "Posizione attuale",
"locating": "Localizzazione...",
"searchButton": "Cerca",
"loading": "Ricerca in corso...",
"enterQuery": "Inserisci un termine per trovare annunci.",
"noResults": "Nessun risultato trovato. Prova con un altro termine.",
"resultsCount": "{{count}} risultati trovati",
"allIn": "Tutti in",
"clearAll": "Cancella tutto",
"radiusAround": "Raggio di {{radius}} km",
"priceRange": "Prezzo",
"min": "Min",
"max": "Max",
"apply": "Applica",
"sortBy": "Ordina per",
"sortNewest": "Più recenti",
"sortOldest": "Meno recenti",
"sortPriceAsc": "Prezzo: dal più basso",
"sortPriceDesc": "Prezzo: dal più alto",
"sortDistance": "Nelle vicinanze"
},
"countries": {
"ch": "Svizzera",
"de": "Germania",
"at": "Austria",
"fr": "Francia",
"it": "Italia",
"li": "Liechtenstein"
},
"listing": {
"notFound": "Questo annuncio non è stato trovato.",
"backHome": "Torna alla home",
"description": "Descrizione",
"location": "Località",
"seller": "Venditore",
"anonymousSeller": "Venditore anonimo",
"memberSince": "Membro dal",
"postedOn": "Pubblicato il",
"contactSeller": "Contatta il venditore",
"paymentInfo": "Il pagamento avviene direttamente tramite Monero (XMR).",
"moneroAddress": "Indirizzo Monero del venditore",
"noMoneroAddress": "Nessun indirizzo Monero fornito",
"copyAddress": "Copia indirizzo",
"contactHint": "Copia l'indirizzo e invia l'importo con il tuo portafoglio Monero.",
"priceOnRequest": "Prezzo su richiesta",
"shippingAvailable": "Spedizione disponibile",
"viewSingular": "visualizzazione",
"viewPlural": "visualizzazioni",
"share": "Condividi",
"report": "Segnala",
"moreFromSeller": "Altri annunci di questo venditore",
"edit": "Modifica",
"expired": "Scaduto",
"expiresIn1Day": "1 giorno rimanente",
"expiresInDays": "{{days}} giorni rimanenti"
},
"chat": {
"title": "Invia messaggio",
"placeholder": "Scrivi un messaggio...",
"encrypted": "Crittografia end-to-end",
"startConversation": "Inizia una conversazione con il venditore.",
"send": "Invia",
"unavailable": "Chat non disponibile"
},
"create": {
"title": "Crea annuncio",
"editTitle": "Modifica annuncio",
"listingTitle": "Titolo",
"titlePlaceholder": "Cosa vuoi vendere?",
"category": "Categoria",
"selectCategory": "Seleziona categoria",
"condition": "Condizione",
"conditionNew": "Nuovo",
"conditionLikeNew": "Come nuovo",
"conditionGood": "Buono",
"conditionFair": "Discreto",
"conditionPoor": "Scarso",
"price": "Prezzo",
"currency": "Valuta",
"priceMode": "Modalità prezzo",
"priceModeFiat": "Prezzo fiat fisso",
"priceModeXmr": "Prezzo XMR fisso",
"priceModeHint": "Fiat fisso: l'importo in fiat resta invariato. XMR fisso: l'importo in XMR resta invariato.",
"shippingAvailable": "Spedizione disponibile",
"shippingCost": "Costo di spedizione",
"shippingCostPlaceholder": "es. 5.00",
"location": "Località",
"locationPlaceholder": "Città, CAP o indirizzo",
"locationHint": "Scegli la località per il tuo annuncio",
"description": "Descrizione",
"descriptionPlaceholder": "Descrivi il tuo articolo in dettaglio...",
"images": "Immagini",
"uploadImages": "Carica immagini (max. 5)",
"moneroAddress": "Il tuo indirizzo Monero",
"moneroPlaceholder": "4... o 8...",
"moneroHint": "Gli acquirenti invieranno il pagamento direttamente a questo indirizzo.",
"cancel": "Annulla",
"publish": "Pubblica",
"publishing": "Pubblicazione in corso...",
"saveChanges": "Salva modifiche",
"saving": "Salvataggio...",
"publishFailed": "Pubblicazione fallita. Riprova.",
"invalidMoneroAddress": "Indirizzo Monero non valido. Controlla il formato.",
"draftRestored": "Bozza ripristinata",
"clearDraft": "Elimina"
},
"notFound": {
"title": "Pagina non trovata",
"message": "La pagina che stai cercando non esiste.",
"backHome": "Torna alla home"
},
"cropper": {
"title": "Ritaglia immagine",
"preview": "Anteprima:",
"cancel": "Annulla",
"confirm": "Applica",
"aspectRatio": "Rapporto:",
"free": "Libero"
},
"captcha": {
"verify": "Non sono un robot",
"verified": "Verificato",
"solving": "Verifica in corso...",
"attempts": "tentativi",
"error": "Errore - riprova"
},
"profile": {
"myListings": "I miei annunci",
"messages": "Messaggi",
"favorites": "Preferiti",
"settings": "Impostazioni"
},
"auth": {
"login": "Accedi",
"logout": "Esci",
"loggingIn": "Accesso in corso...",
"yourUuid": "Il tuo UUID",
"enterUuid": "Inserisci il tuo UUID",
"invalidUuid": "UUID non valido o account non trovato",
"noAccount": "Non hai ancora un account?",
"hasAccount": "Hai già un account?",
"createAccount": "Crea account",
"registerInfo": "Verrà generato un UUID unico per te. Questo UUID è il tuo unico accesso - conservalo in modo sicuro!",
"generateUuid": "Genera UUID",
"creating": "Creazione in corso...",
"accountCreated": "Account creato!",
"important": "Importante!",
"saveUuidWarning": "Conserva questo UUID in modo sicuro. È il tuo unico accesso al tuo account. Non è possibile recuperarlo!",
"copy": "Copia",
"downloadBackup": "Scarica backup",
"confirmSaved": "Ho salvato il mio UUID",
"registrationFailed": "Registrazione fallita",
"loginRequired": "Accedi per continuare"
},
"favorites": {
"title": "Preferiti",
"subtitle": "I tuoi annunci salvati",
"empty": "Nessun preferito",
"emptyHint": "Clicca l'icona del cuore su un annuncio per salvarlo.",
"browse": "Sfoglia annunci"
},
"myListings": {
"title": "I miei annunci",
"subtitle": "Gestisci i tuoi annunci",
"empty": "Nessun annuncio",
"emptyHint": "Non hai ancora creato nessun annuncio.",
"create": "Crea annuncio",
"loginRequired": "Accesso richiesto",
"loginHint": "Accedi per vedere i tuoi annunci.",
"login": "Accedi",
"status": {
"draft": "Bozza",
"archived": "Archiviato",
"processing": "In attesa",
"published": "Pubblicato",
"expired": "Scaduto"
}
},
"messages": {
"title": "Messaggi",
"subtitle": "Le tue conversazioni",
"empty": "Nessun messaggio",
"emptyHint": "Contatta un venditore per iniziare una conversazione.",
"browse": "Sfoglia annunci",
"loginRequired": "Accesso richiesto",
"loginHint": "Accedi per vedere i tuoi messaggi.",
"login": "Accedi",
"unknownListing": "Annuncio sconosciuto",
"today": "Oggi",
"yesterday": "Ieri",
"daysAgo": "{{days}} giorni fa"
},
"settings": {
"title": "Impostazioni",
"appearance": "Aspetto",
"theme": "Tema",
"themeLight": "Chiaro",
"themeDark": "Scuro",
"themeSystem": "Sistema",
"language": "Lingua",
"account": "Account",
"userId": "ID utente",
"logout": "Esci",
"login": "Accedi",
"notLoggedIn": "Non hai effettuato l'accesso.",
"loggedOut": "Disconnesso con successo",
"data": "Dati",
"favorites": "Preferiti",
"favoritesHint": "Elimina i preferiti salvati localmente",
"searchHistory": "Cronologia ricerche",
"searchHistoryHint": "Elimina i filtri di ricerca salvati",
"clear": "Cancella",
"confirmClearFavorites": "Eliminare tutti i preferiti?",
"confirmClearSearch": "Eliminare la cronologia delle ricerche?",
"favoritesCleared": "Preferiti eliminati",
"searchCleared": "Cronologia ricerche eliminata",
"about": "Informazioni",
"currency": "Valuta",
"currencyChanged": "Valuta cambiata"
},
"notifications": {
"title": "Notifiche",
"empty": "Nessuna notifica",
"markAllRead": "Segna tutto come letto",
"listing_created": "Il tuo annuncio è stato creato",
"listing_published": "Il tuo annuncio è stato pubblicato",
"listing_expired": "Il tuo annuncio è scaduto",
"new_message": "Hai un nuovo messaggio",
"favorite_added": "Qualcuno ha salvato il tuo annuncio"
},
"payment": {
"title": "Pagamento",
"listingFee": "Tariffa annuncio",
"feeInfo": "1 annuncio = 1 mese = {{amount}} {{currency}}",
"payNow": "Paga ora",
"paying": "Pagamento in corso...",
"processing": "Pagamento ricevuto, in attesa di conferma...",
"success": "Pagamento riuscito! Il tuo annuncio è ora online.",
"expired": "Pagamento scaduto. Riprova.",
"failed": "Pagamento fallito. Riprova.",
"resume": "Riprendi pagamento",
"pending": "Pagamento in sospeso",
"required": "Per la pubblicazione è richiesta una tariffa di {{amount}} {{currency}}.",
"paidViaXmr": "Pagato tramite Monero (XMR)",
"awaitingConfirmation": "In attesa di conferma sulla blockchain",
"awaitingHint": "Il tuo pagamento è stato ricevuto. L'annuncio verrà pubblicato automaticamente dopo 1 conferma."
}
}

295
locales/pt.json Normal file
View File

@@ -0,0 +1,295 @@
{
"header": {
"searchPlaceholder": "O que você está procurando?",
"createListing": "Criar Anúncio",
"toggleTheme": "Alternar tema",
"selectLanguage": "Selecionar idioma",
"profile": "Perfil"
},
"footer": {
"rights": "Todos os direitos reservados.",
"about": "Sobre",
"privacy": "Privacidade",
"terms": "Termos",
"contact": "Contato"
},
"home": {
"title": "Bem-vindo ao dgray.io",
"subtitle": "Encontre boas ofertas perto de você ou venda o que não precisa mais.",
"browseListings": "Ver Anúncios",
"createListing": "Criar Anúncio",
"categories": "Categorias",
"recentListings": "Anúncios Recentes",
"placeholderTitle": "Anúncio de Exemplo",
"placeholderLocation": "Localização",
"addFavorite": "Adicionar aos favoritos",
"removeFavorite": "Remover dos favoritos",
"noListings": "Nenhum anúncio encontrado",
"loadMore": "Carregar mais",
"pullToRefresh": "Puxe para atualizar"
},
"common": {
"loading": "Carregando...",
"error": "Erro ao carregar",
"close": "Fechar",
"remove": "Remover",
"home": "Início"
},
"error": {
"title": "Algo deu errado",
"retry": "Tentar novamente",
"offline": "Sem conexão com a internet"
},
"search": {
"title": "Busca",
"placeholder": "Digite o termo de busca...",
"allCategories": "Todas as Categorias",
"allSubcategories": "Todas as Subcategorias",
"currentLocation": "Localização Atual",
"locating": "Localizando...",
"searchButton": "Buscar",
"loading": "Buscando...",
"enterQuery": "Digite um termo de busca para encontrar anúncios.",
"noResults": "Nenhum resultado encontrado. Tente outro termo de busca.",
"resultsCount": "{{count}} resultados encontrados",
"allIn": "Todos em",
"clearAll": "Limpar tudo",
"radiusAround": "Raio de {{radius}} km",
"priceRange": "Preço",
"min": "Mín",
"max": "Máx",
"apply": "Aplicar",
"sortBy": "Ordenar por",
"sortNewest": "Mais recentes",
"sortOldest": "Mais antigos",
"sortPriceAsc": "Preço: menor para maior",
"sortPriceDesc": "Preço: maior para menor",
"sortDistance": "Próximos"
},
"countries": {
"ch": "Suíça",
"de": "Alemanha",
"at": "Áustria",
"fr": "França",
"it": "Itália",
"li": "Liechtenstein"
},
"listing": {
"notFound": "Este anúncio não foi encontrado.",
"backHome": "Voltar ao Início",
"description": "Descrição",
"location": "Localização",
"seller": "Vendedor",
"anonymousSeller": "Vendedor Anônimo",
"memberSince": "Membro desde",
"postedOn": "Publicado em",
"contactSeller": "Contatar Vendedor",
"paymentInfo": "O pagamento é feito diretamente via Monero (XMR).",
"moneroAddress": "Endereço Monero do Vendedor",
"noMoneroAddress": "Nenhum endereço Monero fornecido",
"copyAddress": "Copiar endereço",
"contactHint": "Copie o endereço e envie o valor usando sua carteira Monero.",
"priceOnRequest": "Preço sob consulta",
"shippingAvailable": "Envio disponível",
"viewSingular": "visualização",
"viewPlural": "visualizações",
"share": "Compartilhar",
"report": "Denunciar",
"moreFromSeller": "Mais deste vendedor",
"edit": "Editar",
"expired": "Expirado",
"expiresIn1Day": "1 dia restante",
"expiresInDays": "{{days}} dias restantes"
},
"chat": {
"title": "Enviar Mensagem",
"placeholder": "Escreva uma mensagem...",
"encrypted": "Criptografia de ponta a ponta",
"startConversation": "Inicie uma conversa com o vendedor.",
"send": "Enviar",
"unavailable": "Chat indisponível"
},
"create": {
"title": "Criar Anúncio",
"editTitle": "Editar Anúncio",
"listingTitle": "Título",
"titlePlaceholder": "O que você quer vender?",
"category": "Categoria",
"selectCategory": "Selecionar categoria",
"condition": "Condição",
"conditionNew": "Novo",
"conditionLikeNew": "Seminovo",
"conditionGood": "Bom",
"conditionFair": "Regular",
"conditionPoor": "Ruim",
"price": "Preço",
"currency": "Moeda",
"priceMode": "Modo de preço",
"priceModeFiat": "Preço fixo em fiat",
"priceModeXmr": "Preço fixo em XMR",
"priceModeHint": "Fiat fixo: O valor em fiat permanece o mesmo. XMR fixo: O valor em XMR permanece o mesmo.",
"shippingAvailable": "Envio disponível",
"shippingCost": "Custo de envio",
"shippingCostPlaceholder": "ex: 5,00",
"location": "Localização",
"locationPlaceholder": "Cidade, CEP ou endereço",
"locationHint": "Escolha a localização do seu anúncio",
"description": "Descrição",
"descriptionPlaceholder": "Descreva seu item em detalhes...",
"images": "Imagens",
"uploadImages": "Enviar imagens (máx. 5)",
"moneroAddress": "Seu Endereço Monero",
"moneroPlaceholder": "4... ou 8...",
"moneroHint": "Os compradores enviarão o pagamento diretamente para este endereço.",
"cancel": "Cancelar",
"publish": "Publicar",
"publishing": "Publicando...",
"saveChanges": "Salvar Alterações",
"saving": "Salvando...",
"publishFailed": "Falha ao publicar. Por favor, tente novamente.",
"invalidMoneroAddress": "Endereço Monero inválido. Verifique o formato.",
"draftRestored": "Rascunho restaurado",
"clearDraft": "Descartar"
},
"notFound": {
"title": "Página Não Encontrada",
"message": "A página que você procura não existe.",
"backHome": "Voltar ao Início"
},
"cropper": {
"title": "Cortar imagem",
"preview": "Pré-visualização:",
"cancel": "Cancelar",
"confirm": "Aplicar",
"aspectRatio": "Proporção:",
"free": "Livre"
},
"captcha": {
"verify": "Não sou um robô",
"verified": "Verificado",
"solving": "Verificando...",
"attempts": "tentativas",
"error": "Erro - tente novamente"
},
"profile": {
"myListings": "Meus Anúncios",
"messages": "Mensagens",
"favorites": "Favoritos",
"settings": "Configurações"
},
"auth": {
"login": "Entrar",
"logout": "Sair",
"loggingIn": "Entrando...",
"yourUuid": "Seu UUID",
"enterUuid": "Por favor, insira seu UUID",
"invalidUuid": "UUID inválido ou conta não encontrada",
"noAccount": "Ainda não tem conta?",
"hasAccount": "Já tem uma conta?",
"createAccount": "Criar Conta",
"registerInfo": "Um UUID único será gerado para você. Este UUID é seu único acesso - guarde-o com segurança!",
"generateUuid": "Gerar UUID",
"creating": "Criando...",
"accountCreated": "Conta Criada!",
"important": "Importante!",
"saveUuidWarning": "Guarde este UUID com segurança. Ele é seu único acesso à sua conta. Não há como recuperá-lo!",
"copy": "Copiar",
"downloadBackup": "Baixar Backup",
"confirmSaved": "Eu salvei meu UUID",
"registrationFailed": "Falha no cadastro",
"loginRequired": "Por favor, faça login para continuar"
},
"favorites": {
"title": "Favoritos",
"subtitle": "Seus anúncios salvos",
"empty": "Sem favoritos",
"emptyHint": "Clique no ícone de coração em um anúncio para salvá-lo.",
"browse": "Ver anúncios"
},
"myListings": {
"title": "Meus Anúncios",
"subtitle": "Gerencie seus anúncios",
"empty": "Sem anúncios",
"emptyHint": "Você ainda não criou nenhum anúncio.",
"create": "Criar anúncio",
"loginRequired": "Login necessário",
"loginHint": "Faça login para ver seus anúncios.",
"login": "Entrar",
"status": {
"draft": "Rascunho",
"archived": "Arquivado",
"processing": "Pendente",
"published": "Publicado",
"expired": "Expirado"
}
},
"messages": {
"title": "Mensagens",
"subtitle": "Suas conversas",
"empty": "Sem mensagens",
"emptyHint": "Entre em contato com um vendedor para iniciar uma conversa.",
"browse": "Ver anúncios",
"loginRequired": "Login necessário",
"loginHint": "Faça login para ver suas mensagens.",
"login": "Entrar",
"unknownListing": "Anúncio desconhecido",
"today": "Hoje",
"yesterday": "Ontem",
"daysAgo": "{{days}} dias atrás"
},
"settings": {
"title": "Configurações",
"appearance": "Aparência",
"theme": "Tema",
"themeLight": "Claro",
"themeDark": "Escuro",
"themeSystem": "Sistema",
"language": "Idioma",
"account": "Conta",
"userId": "ID do Usuário",
"logout": "Sair",
"login": "Entrar",
"notLoggedIn": "Você não está logado.",
"loggedOut": "Desconectado com sucesso",
"data": "Dados",
"favorites": "Favoritos",
"favoritesHint": "Excluir favoritos salvos localmente",
"searchHistory": "Histórico de busca",
"searchHistoryHint": "Excluir filtros de busca salvos",
"clear": "Limpar",
"confirmClearFavorites": "Excluir todos os favoritos?",
"confirmClearSearch": "Excluir histórico de busca?",
"favoritesCleared": "Favoritos excluídos",
"searchCleared": "Histórico de busca excluído",
"about": "Sobre",
"currency": "Moeda",
"currencyChanged": "Moeda alterada"
},
"notifications": {
"title": "Notificações",
"empty": "Sem notificações",
"markAllRead": "Marcar todas como lidas",
"listing_created": "Seu anúncio foi criado",
"listing_published": "Seu anúncio foi publicado",
"listing_expired": "Seu anúncio expirou",
"new_message": "Você tem uma nova mensagem",
"favorite_added": "Alguém salvou seu anúncio"
},
"payment": {
"title": "Pagamento",
"listingFee": "Taxa do Anúncio",
"feeInfo": "1 anúncio = 1 mês = {{amount}} {{currency}}",
"payNow": "Pagar Agora",
"paying": "Processando pagamento...",
"processing": "Pagamento recebido, aguardando confirmação...",
"success": "Pagamento realizado! Seu anúncio está no ar.",
"expired": "Pagamento expirado. Por favor, tente novamente.",
"failed": "Pagamento falhou. Por favor, tente novamente.",
"resume": "Retomar pagamento",
"pending": "Pagamento pendente",
"required": "Uma taxa de {{amount}} {{currency}} é necessária para publicar.",
"paidViaXmr": "Pago via Monero (XMR)",
"awaitingConfirmation": "Aguardando confirmação na blockchain",
"awaitingHint": "Seu pagamento foi recebido. O anúncio será publicado automaticamente após 1 confirmação."
}
}

295
locales/ru.json Normal file
View File

@@ -0,0 +1,295 @@
{
"header": {
"searchPlaceholder": "Что вы ищете?",
"createListing": "Создать объявление",
"toggleTheme": "Переключить тему",
"selectLanguage": "Выбрать язык",
"profile": "Профиль"
},
"footer": {
"rights": "Все права защищены.",
"about": "О нас",
"privacy": "Конфиденциальность",
"terms": "Условия",
"contact": "Контакты"
},
"home": {
"title": "Добро пожаловать на dgray.io",
"subtitle": "Находите выгодные предложения рядом или продавайте ненужное.",
"browseListings": "Смотреть объявления",
"createListing": "Создать объявление",
"categories": "Категории",
"recentListings": "Новые объявления",
"placeholderTitle": "Пример объявления",
"placeholderLocation": "Местоположение",
"addFavorite": "Добавить в избранное",
"removeFavorite": "Удалить из избранного",
"noListings": "Объявления не найдены",
"loadMore": "Загрузить ещё",
"pullToRefresh": "Потяните для обновления"
},
"common": {
"loading": "Загрузка...",
"error": "Ошибка загрузки",
"close": "Закрыть",
"remove": "Удалить",
"home": "Главная"
},
"error": {
"title": "Что-то пошло не так",
"retry": "Попробовать снова",
"offline": "Нет подключения к интернету"
},
"search": {
"title": "Поиск",
"placeholder": "Введите поисковый запрос...",
"allCategories": "Все категории",
"allSubcategories": "Все подкатегории",
"currentLocation": "Текущее местоположение",
"locating": "Определение...",
"searchButton": "Найти",
"loading": "Поиск...",
"enterQuery": "Введите запрос для поиска объявлений.",
"noResults": "Ничего не найдено. Попробуйте другой запрос.",
"resultsCount": "Найдено результатов: {{count}}",
"allIn": "Все в",
"clearAll": "Очистить всё",
"radiusAround": "Радиус {{radius}} км",
"priceRange": "Цена",
"min": "Мин",
"max": "Макс",
"apply": "Применить",
"sortBy": "Сортировка",
"sortNewest": "Сначала новые",
"sortOldest": "Сначала старые",
"sortPriceAsc": "Цена: по возрастанию",
"sortPriceDesc": "Цена: по убыванию",
"sortDistance": "Рядом"
},
"countries": {
"ch": "Швейцария",
"de": "Германия",
"at": "Австрия",
"fr": "Франция",
"it": "Италия",
"li": "Лихтенштейн"
},
"listing": {
"notFound": "Объявление не найдено.",
"backHome": "На главную",
"description": "Описание",
"location": "Местоположение",
"seller": "Продавец",
"anonymousSeller": "Анонимный продавец",
"memberSince": "Участник с",
"postedOn": "Опубликовано",
"contactSeller": "Связаться с продавцом",
"paymentInfo": "Оплата производится напрямую через Monero (XMR).",
"moneroAddress": "Monero-адрес продавца",
"noMoneroAddress": "Monero-адрес не указан",
"copyAddress": "Копировать адрес",
"contactHint": "Скопируйте адрес и отправьте сумму через ваш Monero-кошелёк.",
"priceOnRequest": "Цена по запросу",
"shippingAvailable": "Доставка возможна",
"viewSingular": "просмотр",
"viewPlural": "просмотров",
"share": "Поделиться",
"report": "Пожаловаться",
"moreFromSeller": "Другие объявления продавца",
"edit": "Редактировать",
"expired": "Истекло",
"expiresIn1Day": "Остался 1 день",
"expiresInDays": "Осталось {{days}} дн."
},
"chat": {
"title": "Отправить сообщение",
"placeholder": "Написать сообщение...",
"encrypted": "Сквозное шифрование",
"startConversation": "Начните разговор с продавцом.",
"send": "Отправить",
"unavailable": "Чат недоступен"
},
"create": {
"title": "Создать объявление",
"editTitle": "Редактировать объявление",
"listingTitle": "Название",
"titlePlaceholder": "Что вы хотите продать?",
"category": "Категория",
"selectCategory": "Выберите категорию",
"condition": "Состояние",
"conditionNew": "Новое",
"conditionLikeNew": "Как новое",
"conditionGood": "Хорошее",
"conditionFair": "Удовлетворительное",
"conditionPoor": "Плохое",
"price": "Цена",
"currency": "Валюта",
"priceMode": "Режим цены",
"priceModeFiat": "Фиксированная цена в фиате",
"priceModeXmr": "Фиксированная цена в XMR",
"priceModeHint": "Фиат: сумма в фиате остаётся неизменной. XMR: сумма в XMR остаётся неизменной.",
"shippingAvailable": "Доставка возможна",
"shippingCost": "Стоимость доставки",
"shippingCostPlaceholder": "напр. 5.00",
"location": "Местоположение",
"locationPlaceholder": "Город, индекс или адрес",
"locationHint": "Укажите местоположение для вашего объявления",
"description": "Описание",
"descriptionPlaceholder": "Подробно опишите ваш товар...",
"images": "Изображения",
"uploadImages": "Загрузить изображения (макс. 5)",
"moneroAddress": "Ваш Monero-адрес",
"moneroPlaceholder": "4... или 8...",
"moneroHint": "Покупатели отправят оплату напрямую на этот адрес.",
"cancel": "Отмена",
"publish": "Опубликовать",
"publishing": "Публикация...",
"saveChanges": "Сохранить изменения",
"saving": "Сохранение...",
"publishFailed": "Публикация не удалась. Попробуйте снова.",
"invalidMoneroAddress": "Неверный Monero-адрес. Проверьте формат.",
"draftRestored": "Черновик восстановлен",
"clearDraft": "Удалить черновик"
},
"notFound": {
"title": "Страница не найдена",
"message": "Запрашиваемая страница не существует.",
"backHome": "На главную"
},
"cropper": {
"title": "Обрезать изображение",
"preview": "Предпросмотр:",
"cancel": "Отмена",
"confirm": "Применить",
"aspectRatio": "Соотношение:",
"free": "Свободное"
},
"captcha": {
"verify": "Я не робот",
"verified": "Подтверждено",
"solving": "Проверка...",
"attempts": "попыток",
"error": "Ошибка — попробуйте снова"
},
"profile": {
"myListings": "Мои объявления",
"messages": "Сообщения",
"favorites": "Избранное",
"settings": "Настройки"
},
"auth": {
"login": "Войти",
"logout": "Выйти",
"loggingIn": "Вход...",
"yourUuid": "Ваш UUID",
"enterUuid": "Введите ваш UUID",
"invalidUuid": "Неверный UUID или аккаунт не найден",
"noAccount": "Нет аккаунта?",
"hasAccount": "Уже есть аккаунт?",
"createAccount": "Создать аккаунт",
"registerInfo": "Для вас будет сгенерирован уникальный UUID. Этот UUID — ваш единственный доступ, сохраните его надёжно!",
"generateUuid": "Сгенерировать UUID",
"creating": "Создание...",
"accountCreated": "Аккаунт создан!",
"important": "Важно!",
"saveUuidWarning": "Сохраните этот UUID надёжно. Это ваш единственный доступ к аккаунту. Восстановить его невозможно!",
"copy": "Копировать",
"downloadBackup": "Скачать резервную копию",
"confirmSaved": "Я сохранил свой UUID",
"registrationFailed": "Регистрация не удалась",
"loginRequired": "Войдите, чтобы продолжить"
},
"favorites": {
"title": "Избранное",
"subtitle": "Сохранённые объявления",
"empty": "Нет избранного",
"emptyHint": "Нажмите на сердечко, чтобы сохранить объявление.",
"browse": "Смотреть объявления"
},
"myListings": {
"title": "Мои объявления",
"subtitle": "Управление объявлениями",
"empty": "Нет объявлений",
"emptyHint": "Вы ещё не создали ни одного объявления.",
"create": "Создать объявление",
"loginRequired": "Необходимо войти",
"loginHint": "Войдите, чтобы увидеть свои объявления.",
"login": "Войти",
"status": {
"draft": "Черновик",
"archived": "В архиве",
"processing": "На рассмотрении",
"published": "Опубликовано",
"expired": "Истекло"
}
},
"messages": {
"title": "Сообщения",
"subtitle": "Ваши переписки",
"empty": "Нет сообщений",
"emptyHint": "Свяжитесь с продавцом, чтобы начать переписку.",
"browse": "Смотреть объявления",
"loginRequired": "Необходимо войти",
"loginHint": "Войдите, чтобы увидеть свои сообщения.",
"login": "Войти",
"unknownListing": "Неизвестное объявление",
"today": "Сегодня",
"yesterday": "Вчера",
"daysAgo": "{{days}} дн. назад"
},
"settings": {
"title": "Настройки",
"appearance": "Внешний вид",
"theme": "Тема",
"themeLight": "Светлая",
"themeDark": "Тёмная",
"themeSystem": "Системная",
"language": "Язык",
"account": "Аккаунт",
"userId": "ID пользователя",
"logout": "Выйти",
"login": "Войти",
"notLoggedIn": "Вы не вошли в аккаунт.",
"loggedOut": "Вы вышли из аккаунта",
"data": "Данные",
"favorites": "Избранное",
"favoritesHint": "Удалить локально сохранённое избранное",
"searchHistory": "История поиска",
"searchHistoryHint": "Удалить сохранённые фильтры поиска",
"clear": "Очистить",
"confirmClearFavorites": "Удалить всё избранное?",
"confirmClearSearch": "Удалить историю поиска?",
"favoritesCleared": "Избранное удалено",
"searchCleared": "История поиска удалена",
"about": "О приложении",
"currency": "Валюта",
"currencyChanged": "Валюта изменена"
},
"notifications": {
"title": "Уведомления",
"empty": "Нет уведомлений",
"markAllRead": "Отметить все как прочитанные",
"listing_created": "Ваше объявление создано",
"listing_published": "Ваше объявление опубликовано",
"listing_expired": "Срок вашего объявления истёк",
"new_message": "У вас новое сообщение",
"favorite_added": "Кто-то сохранил ваше объявление"
},
"payment": {
"title": "Оплата",
"listingFee": "Стоимость размещения",
"feeInfo": "1 объявление = 1 месяц = {{amount}} {{currency}}",
"payNow": "Оплатить",
"paying": "Обработка платежа...",
"processing": "Платёж получен, ожидание подтверждения...",
"success": "Оплата прошла успешно! Ваше объявление опубликовано.",
"expired": "Время оплаты истекло. Попробуйте снова.",
"failed": "Оплата не удалась. Попробуйте снова.",
"resume": "Продолжить оплату",
"pending": "Ожидание оплаты",
"required": "Для публикации требуется оплата {{amount}} {{currency}}.",
"paidViaXmr": "Оплачено через Monero (XMR)",
"awaitingConfirmation": "Ожидание подтверждения в блокчейне",
"awaitingHint": "Ваш платёж получен. Объявление будет опубликовано автоматически после 1 подтверждения."
}
}