Files
descrybe/apps/web/scripts/expand-phrase-map.mjs
greeneclipse 8580c996c3 Initial commit of Descrybe v2 without local scratch artifacts.
Drop one-shot tmp/axe scripts and agent i18n scratch so the Gitea tree is deployable.
2026-08-09 22:47:43 +02:00

200 lines
35 KiB
JavaScript

import fs from "node:fs";
import { EXTRA as EXTRA_ES } from "./locale-extra-es.mjs";
function parse(s) {
const d = {};
const re = /"([^"\\]+)"\s*:\s*((?:"(?:\\.|[^"\\])*")|(?:`(?:\\.|[^`\\])*`))/gs;
let m;
while ((m = re.exec(s))) {
const raw = m[2];
d[m[1]] = raw.startsWith("`")
? raw.slice(1, -1).replace(/\\`/g, "`").replace(/\\\$/g, "$").replace(/\\n/g, "\n")
: JSON.parse(raw);
}
return d;
}
const en = parse(fs.readFileSync("../src/lib/i18n/messages/en.ts", "utf8"));
const seed = JSON.parse(fs.readFileSync("_phrase-seed.json", "utf8"));
/** @type {Record<string, {fr:string,de:string,it:string,pt:string,nl:string,pl:string,ja:string}>} */
const MORE = {
Descrybe: { fr: "Descrybe", de: "Descrybe", it: "Descrybe", pt: "Descrybe", nl: "Descrybe", pl: "Descrybe", ja: "Descrybe" },
"—": { fr: "—", de: "—", it: "—", pt: "—", nl: "—", pl: "—", ja: "—" },
Marketing: { fr: "Marketing", de: "Marketing", it: "Marketing", pt: "Marketing", nl: "Marketing", pl: "Marketing", ja: "マーケティング" },
Exports: { fr: "Exports", de: "Exporte", it: "Esportazioni", pt: "Exportações", nl: "Exports", pl: "Eksporty", ja: "エクスポート" },
SEO: { fr: "SEO", de: "SEO", it: "SEO", pt: "SEO", nl: "SEO", pl: "SEO", ja: "SEO" },
Admin: { fr: "Admin", de: "Admin", it: "Admin", pt: "Admin", nl: "Admin", pl: "Admin", ja: "管理" },
EPREL: { fr: "EPREL", de: "EPREL", it: "EPREL", pt: "EPREL", nl: "EPREL", pl: "EPREL", ja: "EPREL" },
"Re: {subject}": { fr: "Re: {subject}", de: "Re: {subject}", it: "Re: {subject}", pt: "Re: {subject}", nl: "Re: {subject}", pl: "Re: {subject}", ja: "Re: {subject}" },
"Sign in": { fr: "Se connecter", de: "Anmelden", it: "Accedi", pt: "Iniciar sessão", nl: "Inloggen", pl: "Zaloguj się", ja: "ログイン" },
"Use your Descrybe email and password.": { fr: "Utilisez votre e-mail et mot de passe Descrybe.", de: "Verwenden Sie Ihre Descrybe-E-Mail und Ihr Passwort.", it: "Usa la tua email e password Descrybe.", pt: "Utilize o seu e-mail e palavra-passe Descrybe.", nl: "Gebruik uw Descrybe e-mailadres en wachtwoord.", pl: "Użyj adresu e-mail i hasła Descrybe.", ja: "Descrybeのメールアドレスとパスワードを使用してください。" },
"Signing in…": { fr: "Connexion…", de: "Anmeldung…", it: "Accesso in corso…", pt: "A iniciar sessão…", nl: "Bezig met inloggen…", pl: "Logowanie…", ja: "ログイン中…" },
"Login failed": { fr: "Échec de la connexion", de: "Anmeldung fehlgeschlagen", it: "Accesso non riuscito", pt: "Falha no início de sessão", nl: "Inloggen mislukt", pl: "Logowanie nie powiodło się", ja: "ログインに失敗しました" },
"Create company": { fr: "Créer une entreprise", de: "Unternehmen erstellen", it: "Crea azienda", pt: "Criar empresa", nl: "Bedrijf aanmaken", pl: "Utwórz firmę", ja: "会社を作成" },
"Accept invite": { fr: "Accepter l'invitation", de: "Einladung annehmen", it: "Accetta invito", pt: "Aceitar convite", nl: "Uitnodiging accepteren", pl: "Zaakceptuj zaproszenie", ja: "招待を承認" },
"Set password": { fr: "Définir le mot de passe", de: "Passwort festlegen", it: "Imposta password", pt: "Definir palavra-passe", nl: "Wachtwoord instellen", pl: "Ustaw hasło", ja: "パスワードを設定" },
"Company name": { fr: "Nom de l'entreprise", de: "Unternehmensname", it: "Nome azienda", pt: "Nome da empresa", nl: "Bedrijfsnaam", pl: "Nazwa firmy", ja: "会社名" },
"Create account": { fr: "Créer un compte", de: "Konto erstellen", it: "Crea account", pt: "Criar conta", nl: "Account aanmaken", pl: "Utwórz konto", ja: "アカウントを作成" },
"Creating…": { fr: "Création…", de: "Wird erstellt…", it: "Creazione…", pt: "A criar…", nl: "Bezig met aanmaken…", pl: "Tworzenie…", ja: "作成中…" },
"Registration failed": { fr: "Échec de l'inscription", de: "Registrierung fehlgeschlagen", it: "Registrazione non riuscita", pt: "Falha no registo", nl: "Registratie mislukt", pl: "Rejestracja nie powiodła się", ja: "登録に失敗しました" },
"Already have an account?": { fr: "Vous avez déjà un compte ?", de: "Haben Sie bereits ein Konto?", it: "Hai già un account?", pt: "Já tem uma conta?", nl: "Heeft u al een account?", pl: "Masz już konto?", ja: "すでにアカウントをお持ちですか?" },
"No account?": { fr: "Pas de compte ?", de: "Kein Konto?", it: "Nessun account?", pt: "Sem conta?", nl: "Geen account?", pl: "Brak konta?", ja: "アカウントがありませんか?" },
"Admin → Users": { fr: "Admin → Utilisateurs", de: "Admin → Benutzer", it: "Admin → Utenti", pt: "Admin → Utilizadores", nl: "Admin → Gebruikers", pl: "Admin → Użytkownicy", ja: "管理 → ユーザー" },
"your email": { fr: "votre e-mail", de: "Ihre E-Mail", it: "la tua email", pt: "o seu e-mail", nl: "uw e-mail", pl: "twój e-mail", ja: "あなたのメール" },
Profile: { fr: "Profil", de: "Profil", it: "Profilo", pt: "Perfil", nl: "Profiel", pl: "Profil", ja: "プロフィール" },
Email: { fr: "E-mail", de: "E-Mail", it: "Email", pt: "E-mail", nl: "E-mail", pl: "E-mail", ja: "メール" },
Member: { fr: "Membre", de: "Mitglied", it: "Membro", pt: "Membro", nl: "Lid", pl: "Członek", ja: "メンバー" },
Remove: { fr: "Retirer", de: "Entfernen", it: "Rimuovi", pt: "Remover", nl: "Verwijderen", pl: "Usuń", ja: "削除" },
Promote: { fr: "Promouvoir", de: "Befördern", it: "Promuovi", pt: "Promover", nl: "Promoveren", pl: "Awansuj", ja: "昇格" },
Demote: { fr: "Rétrograder", de: "Herabstufen", it: "Degrada", pt: "Despromover", nl: "Degraderen", pl: "Degraduj", ja: "降格" },
Role: { fr: "Rôle", de: "Rolle", it: "Ruolo", pt: "Papel", nl: "Rol", pl: "Rola", ja: "ロール" },
Status: { fr: "Statut", de: "Status", it: "Stato", pt: "Estado", nl: "Status", pl: "Status", ja: "ステータス" },
Actions: { fr: "Actions", de: "Aktionen", it: "Azioni", pt: "Ações", nl: "Acties", pl: "Akcje", ja: "操作" },
Name: { fr: "Nom", de: "Name", it: "Nome", pt: "Nome", nl: "Naam", pl: "Nazwa", ja: "名前" },
Key: { fr: "Clé", de: "Schlüssel", it: "Chiave", pt: "Chave", nl: "Sleutel", pl: "Klucz", ja: "キー" },
Plan: { fr: "Offre", de: "Plan", it: "Piano", pt: "Plano", nl: "Plan", pl: "Plan", ja: "プラン" },
Used: { fr: "Utilisé", de: "Verbraucht", it: "Usato", pt: "Usado", nl: "Gebruikt", pl: "Użyte", ja: "使用済み" },
Trial: { fr: "Essai", de: "Testphase", it: "Prova", pt: "Teste", nl: "Proef", pl: "Okres próbny", ja: "トライアル" },
Export: { fr: "Exporter", de: "Exportieren", it: "Esporta", pt: "Exportar", nl: "Exporteren", pl: "Eksportuj", ja: "エクスポート" },
"API Keys": { fr: "Clés API", de: "API-Schlüssel", it: "Chiavi API", pt: "Chaves API", nl: "API-sleutels", pl: "Klucze API", ja: "APIキー" },
"Copy link": { fr: "Copier le lien", de: "Link kopieren", it: "Copia link", pt: "Copiar link", nl: "Link kopiëren", pl: "Kopiuj link", ja: "リンクをコピー" },
"Send invite": { fr: "Envoyer l'invitation", de: "Einladung senden", it: "Invia invito", pt: "Enviar convite", nl: "Uitnodiging verzenden", pl: "Wyślij zaproszenie", ja: "招待を送信" },
"Invite user": { fr: "Inviter un utilisateur", de: "Benutzer einladen", it: "Invita utente", pt: "Convidar utilizador", nl: "Gebruiker uitnodigen", pl: "Zaproś użytkownika", ja: "ユーザーを招待" },
"First Name": { fr: "Prénom", de: "Vorname", it: "Nome", pt: "Nome próprio", nl: "Voornaam", pl: "Imię", ja: "名" },
"Last Name": { fr: "Nom", de: "Nachname", it: "Cognome", pt: "Apelido", nl: "Achternaam", pl: "Nazwisko", ja: "姓" },
"Team Members": { fr: "Membres de l'équipe", de: "Teammitglieder", it: "Membri del team", pt: "Membros da equipa", nl: "Teamleden", pl: "Członkowie zespołu", ja: "チームメンバー" },
"Personal Information": { fr: "Informations personnelles", de: "Persönliche Daten", it: "Informazioni personali", pt: "Informação pessoal", nl: "Persoonlijke gegevens", pl: "Dane osobowe", ja: "個人情報" },
"Update your personal details": { fr: "Mettez à jour vos informations personnelles", de: "Aktualisieren Sie Ihre persönlichen Daten", it: "Aggiorna i tuoi dati personali", pt: "Atualize os seus dados pessoais", nl: "Werk uw persoonlijke gegevens bij", pl: "Zaktualizuj swoje dane osobowe", ja: "個人情報を更新" },
"Your first name": { fr: "Votre prénom", de: "Ihr Vorname", it: "Il tuo nome", pt: "O seu nome próprio", nl: "Uw voornaam", pl: "Twoje imię", ja: "名" },
"Your last name": { fr: "Votre nom", de: "Ihr Nachname", it: "Il tuo cognome", pt: "O seu apelido", nl: "Uw achternaam", pl: "Twoje nazwisko", ja: "姓" },
"Profile updated.": { fr: "Profil mis à jour.", de: "Profil aktualisiert.", it: "Profilo aggiornato.", pt: "Perfil atualizado.", nl: "Profiel bijgewerkt.", pl: "Profil zaktualizowany.", ja: "プロフィールを更新しました。" },
"Could not update profile": { fr: "Impossible de mettre à jour le profil", de: "Profil konnte nicht aktualisiert werden", it: "Impossibile aggiornare il profilo", pt: "Não foi possível atualizar o perfil", nl: "Profiel kon niet worden bijgewerkt", pl: "Nie można zaktualizować profilu", ja: "プロフィールを更新できませんでした" },
"Saving…": { fr: "Enregistrement…", de: "Speichern…", it: "Salvataggio…", pt: "A guardar…", nl: "Bezig met opslaan…", pl: "Zapisywanie…", ja: "保存中…" },
"Accepting…": { fr: "Acceptation…", de: "Wird angenommen…", it: "Accettazione…", pt: "A aceitar…", nl: "Bezig met accepteren…", pl: "Akceptowanie…", ja: "承認中…" },
"Open dashboard": { fr: "Ouvrir le tableau de bord", de: "Dashboard öffnen", it: "Apri dashboard", pt: "Abrir painel", nl: "Dashboard openen", pl: "Otwórz panel", ja: "ダッシュボードを開く" },
"Company settings": { fr: "Paramètres de l'entreprise", de: "Unternehmenseinstellungen", it: "Impostazioni azienda", pt: "Definições da empresa", nl: "Bedrijfsinstellingen", pl: "Ustawienia firmy", ja: "会社の設定" },
"Go to sign in": { fr: "Aller à la connexion", de: "Zur Anmeldung", it: "Vai all'accesso", pt: "Ir para início de sessão", nl: "Naar inloggen", pl: "Przejdź do logowania", ja: "ログインへ" },
"Password saved": { fr: "Mot de passe enregistré", de: "Passwort gespeichert", it: "Password salvata", pt: "Palavra-passe guardada", nl: "Wachtwoord opgeslagen", pl: "Hasło zapisane", ja: "パスワードを保存しました" },
"You're on the team": { fr: "Vous faites partie de l'équipe", de: "Sie sind im Team", it: "Fai parte del team", pt: "Já faz parte da equipa", nl: "U bent in het team", pl: "Jesteś w zespole", ja: "チームに参加しました" },
"Enable fields": { fr: "Activer les champs", de: "Felder aktivieren", it: "Abilita campi", pt: "Ativar campos", nl: "Velden inschakelen", pl: "Włącz pola", ja: "フィールドを有効化" },
"Process products": { fr: "Traiter les produits", de: "Produkte verarbeiten", it: "Elabora prodotti", pt: "Processar produtos", nl: "Producten verwerken", pl: "Przetwarzaj produkty", ja: "商品を処理" },
"Connect feed": { fr: "Connecter un flux", de: "Feed verbinden", it: "Collega feed", pt: "Ligar feed", nl: "Feed koppelen", pl: "Podłącz feed", ja: "フィードを接続" },
"Upload CSV": { fr: "Téléverser un CSV", de: "CSV hochladen", it: "Carica CSV", pt: "Carregar CSV", nl: "CSV uploaden", pl: "Prześlij CSV", ja: "CSVをアップロード" },
"View plans": { fr: "Voir les offres", de: "Pläne ansehen", it: "Vedi i piani", pt: "Ver planos", nl: "Plannen bekijken", pl: "Zobacz plany", ja: "プランを見る" },
"Compare plans": { fr: "Comparer les offres", de: "Pläne vergleichen", it: "Confronta i piani", pt: "Comparar planos", nl: "Plannen vergelijken", pl: "Porównaj plany", ja: "プランを比較" },
"Start a job": { fr: "Démarrer une tâche", de: "Job starten", it: "Avvia un processo", pt: "Iniciar uma tarefa", nl: "Een job starten", pl: "Uruchom zadanie", ja: "ジョブを開始" },
"Resume tutorial": { fr: "Reprendre le tutoriel", de: "Tutorial fortsetzen", it: "Riprendi tutorial", pt: "Retomar tutorial", nl: "Tutorial hervatten", pl: "Wznów samouczek", ja: "チュートリアルを再開" },
"Restart tutorial": { fr: "Relancer le tutoriel", de: "Tutorial neu starten", it: "Riavvia tutorial", pt: "Reiniciar tutorial", nl: "Tutorial opnieuw starten", pl: "Uruchom ponownie samouczek", ja: "チュートリアルを再開する" },
"Open products": { fr: "Ouvrir les produits", de: "Produkte öffnen", it: "Apri prodotti", pt: "Abrir produtos", nl: "Producten openen", pl: "Otwórz produkty", ja: "商品を開く" },
"Welcome to {name}": { fr: "Bienvenue sur {name}", de: "Willkommen bei {name}", it: "Benvenuto in {name}", pt: "Bem-vindo a {name}", nl: "Welkom bij {name}", pl: "Witamy w {name}", ja: "{name} へようこそ" },
"Company Settings": { fr: "Paramètres de l'entreprise", de: "Unternehmenseinstellungen", it: "Impostazioni azienda", pt: "Definições da empresa", nl: "Bedrijfsinstellingen", pl: "Ustawienia firmy", ja: "会社の設定" },
"Active company": { fr: "Entreprise active", de: "Aktives Unternehmen", it: "Azienda attiva", pt: "Empresa ativa", nl: "Actief bedrijf", pl: "Aktywna firma", ja: "アクティブな会社" },
"Credits overview": { fr: "Aperçu des crédits", de: "Credit-Übersicht", it: "Panoramica crediti", pt: "Resumo de créditos", nl: "Credits-overzicht", pl: "Przegląd kredytów", ja: "クレジット概要" },
"Company Information": { fr: "Informations sur l'entreprise", de: "Unternehmensinformationen", it: "Informazioni azienda", pt: "Informação da empresa", nl: "Bedrijfsgegevens", pl: "Informacje o firmie", ja: "会社情報" },
"Update your company details": { fr: "Mettez à jour les détails de votre entreprise", de: "Aktualisieren Sie Ihre Unternehmensdaten", it: "Aggiorna i dettagli dell'azienda", pt: "Atualize os detalhes da empresa", nl: "Werk uw bedrijfsgegevens bij", pl: "Zaktualizuj dane firmy", ja: "会社の詳細を更新" },
"Company Name": { fr: "Nom de l'entreprise", de: "Unternehmensname", it: "Nome azienda", pt: "Nome da empresa", nl: "Bedrijfsnaam", pl: "Nazwa firmy", ja: "会社名" },
"Your company name": { fr: "Le nom de votre entreprise", de: "Ihr Unternehmensname", it: "Il nome della tua azienda", pt: "O nome da sua empresa", nl: "Uw bedrijfsnaam", pl: "Nazwa Twojej firmy", ja: "会社名" },
"Content Settings": { fr: "Paramètres de contenu", de: "Inhaltseinstellungen", it: "Impostazioni contenuti", pt: "Definições de conteúdo", nl: "Contentinstellingen", pl: "Ustawienia treści", ja: "コンテンツ設定" },
"Merge products with the same GTIN": { fr: "Fusionner les produits avec le même GTIN", de: "Produkte mit derselben GTIN zusammenführen", it: "Unisci prodotti con lo stesso GTIN", pt: "Unir produtos com o mesmo GTIN", nl: "Producten met dezelfde GTIN samenvoegen", pl: "Scal produkty z tym samym GTIN", ja: "同じGTINの商品をマージ" },
"Email integration": { fr: "Intégration e-mail", de: "E-Mail-Integration", it: "Integrazione email", pt: "Integração de e-mail", nl: "E-mailintegratie", pl: "Integracja e-mail", ja: "メール連携" },
"AI integrations": { fr: "Intégrations IA", de: "KI-Integrationen", it: "Integrazioni IA", pt: "Integrações de IA", nl: "AI-integraties", pl: "Integracje AI", ja: "AI連携" },
"Operator alerts": { fr: "Alertes opérateur", de: "Operator-Benachrichtigungen", it: "Avvisi operatore", pt: "Alertas do operador", nl: "Operator-meldingen", pl: "Alerty operatora", ja: "オペレーターアラート" },
"In-app toasts": { fr: "Toasts dans l'application", de: "In-App-Toasts", it: "Toast in-app", pt: "Toasts na aplicação", nl: "In-app toasts", pl: "Powiadomienia w aplikacji", ja: "アプリ内トースト" },
"Email alerts": { fr: "Alertes e-mail", de: "E-Mail-Benachrichtigungen", it: "Avvisi email", pt: "Alertas por e-mail", nl: "E-mailmeldingen", pl: "Alerty e-mail", ja: "メールアラート" },
"Create API Key": { fr: "Créer une clé API", de: "API-Schlüssel erstellen", it: "Crea chiave API", pt: "Criar chave API", nl: "API-sleutel maken", pl: "Utwórz klucz API", ja: "APIキーを作成" },
"Create API key": { fr: "Créer une clé API", de: "API-Schlüssel erstellen", it: "Crea chiave API", pt: "Criar chave API", nl: "API-sleutel maken", pl: "Utwórz klucz API", ja: "APIキーを作成" },
"API key": { fr: "Clé API", de: "API-Schlüssel", it: "Chiave API", pt: "Chave API", nl: "API-sleutel", pl: "Klucz API", ja: "APIキー" },
"Key name": { fr: "Nom de la clé", de: "Schlüsselname", it: "Nome chiave", pt: "Nome da chave", nl: "Sleutelnaam", pl: "Nazwa klucza", ja: "キー名" },
"Store it somewhere safe.": { fr: "Conservez-la en lieu sûr.", de: "Bewahren Sie ihn sicher auf.", it: "Conservala in un posto sicuro.", pt: "Guarde-a num local seguro.", nl: "Bewaar hem op een veilige plek.", pl: "Przechowuj go w bezpiecznym miejscu.", ja: "安全な場所に保管してください。" },
"Last Used": { fr: "Dernière utilisation", de: "Zuletzt verwendet", it: "Ultimo utilizzo", pt: "Última utilização", nl: "Laatst gebruikt", pl: "Ostatnio użyty", ja: "最終使用" },
"Expires {date}": { fr: "Expire le {date}", de: "Läuft ab am {date}", it: "Scade il {date}", pt: "Expira a {date}", nl: "Verloopt op {date}", pl: "Wygasa {date}", ja: "{date} に期限切れ" },
"Invite for {email}.": { fr: "Invitation pour {email}.", de: "Einladung für {email}.", it: "Invito per {email}.", pt: "Convite para {email}.", nl: "Uitnodiging voor {email}.", pl: "Zaproszenie dla {email}.", ja: "{email} 宛の招待です。" },
"Joined / expires": { fr: "Inscription / expiration", de: "Beigetreten / läuft ab", it: "Iscrizione / scadenza", pt: "Adesão / expira", nl: "Toegetreden / verloopt", pl: "Dołączył / wygasa", ja: "参加 / 期限" },
"Make admin": { fr: "Rendre admin", de: "Zum Admin machen", it: "Rendi admin", pt: "Tornar admin", nl: "Admin maken", pl: "Uczyń adminem", ja: "管理者にする" },
"Make member": { fr: "Rendre membre", de: "Zum Mitglied machen", it: "Rendi membro", pt: "Tornar membro", nl: "Lid maken", pl: "Uczyń członkiem", ja: "メンバーにする" },
"Revoke invite": { fr: "Révoquer l'invitation", de: "Einladung widerrufen", it: "Revoca invito", pt: "Revogar convite", nl: "Uitnodiging intrekken", pl: "Unieważnij zaproszenie", ja: "招待を取り消す" },
"Member actions": { fr: "Actions du membre", de: "Mitgliederaktionen", it: "Azioni del membro", pt: "Ações do membro", nl: "Acties voor lid", pl: "Akcje członka", ja: "メンバーの操作" },
"No teammates yet": { fr: "Pas encore de coéquipiers", de: "Noch keine Teammitglieder", it: "Ancora nessun compagno di team", pt: "Ainda sem colegas", nl: "Nog geen teamleden", pl: "Brak jeszcze członków zespołu", ja: "まだチームメンバーがいません" },
"Share accept link": { fr: "Partager le lien d'acceptation", de: "Annahmelink teilen", it: "Condividi link di accettazione", pt: "Partilhar link de aceitação", nl: "Acceptatielink delen", pl: "Udostępnij link akceptacji", ja: "承認リンクを共有" },
"Accept link copied.": { fr: "Lien d'acceptation copié.", de: "Annahmelink kopiert.", it: "Link di accettazione copiato.", pt: "Link de aceitação copiado.", nl: "Acceptatielink gekopieerd.", pl: "Skopiowano link akceptacji.", ja: "承認リンクをコピーしました。" },
"Invite teammate": { fr: "Inviter un coéquipier", de: "Teammitglied einladen", it: "Invita un collega", pt: "Convidar colega", nl: "Teamlid uitnodigen", pl: "Zaproś członka zespołu", ja: "チームメイトを招待" },
"colleague@example.com": { fr: "collegue@exemple.com", de: "kollege@beispiel.com", it: "collega@esempio.com", pt: "colega@exemplo.com", nl: "collega@voorbeeld.com", pl: "kolega@przyklad.com", ja: "colleague@example.com" },
"Go to Billing": { fr: "Aller à la facturation", de: "Zur Abrechnung", it: "Vai alla fatturazione", pt: "Ir para Faturação", nl: "Naar facturering", pl: "Przejdź do rozliczeń", ja: "請求へ" },
"Dashboard actions": { fr: "Actions du tableau de bord", de: "Dashboard-Aktionen", it: "Azioni dashboard", pt: "Ações do painel", nl: "Dashboardacties", pl: "Akcje panelu", ja: "ダッシュボードの操作" },
"No catalog data yet": { fr: "Pas encore de données catalogue", de: "Noch keine Katalogdaten", it: "Ancora nessun dato di catalogo", pt: "Ainda sem dados de catálogo", nl: "Nog geen catalogusgegevens", pl: "Brak jeszcze danych katalogu", ja: "まだカタログデータがありません" },
"Connect feed anyway": { fr: "Connecter un flux quand même", de: "Feed trotzdem verbinden", it: "Collega comunque un feed", pt: "Ligar feed mesmo assim", nl: "Feed toch koppelen", pl: "Podłącz feed mimo to", ja: "それでもフィードを接続" },
"Import and map": { fr: "Importer et mapper", de: "Importieren und zuordnen", it: "Importa e mappa", pt: "Importar e mapear", nl: "Importeren en mappen", pl: "Importuj i mapuj", ja: "インポートとマップ" },
"Browse and process": { fr: "Parcourir et traiter", de: "Durchsuchen und verarbeiten", it: "Sfoglia ed elabora", pt: "Explorar e processar", nl: "Bladeren en verwerken", pl: "Przeglądaj i przetwarzaj", ja: "閲覧と処理" },
"Monitor tasks": { fr: "Surveiller les tâches", de: "Aufgaben überwachen", it: "Monitora le attività", pt: "Monitorizar tarefas", nl: "Taken monitoren", pl: "Monitoruj zadania", ja: "タスクを監視" },
"Templates & download": { fr: "Modèles et téléchargement", de: "Vorlagen & Download", it: "Modelli e download", pt: "Modelos e transferência", nl: "Sjablonen & download", pl: "Szablony i pobieranie", ja: "テンプレートとダウンロード" },
"Sync a sample": { fr: "Synchroniser un échantillon", de: "Stichprobe synchronisieren", it: "Sincronizza un campione", pt: "Sincronizar uma amostra", nl: "Een steekproef synchroniseren", pl: "Synchronizuj próbkę", ja: "サンプルを同期" },
"Map source fields": { fr: "Mapper les champs source", de: "Quellfelder zuordnen", it: "Mappa campi origine", pt: "Mapear campos de origem", nl: "Bronvelden mappen", pl: "Mapuj pola źródła", ja: "ソースフィールドをマップ" },
"Add or connect a source": { fr: "Ajouter ou connecter une source", de: "Quelle hinzufügen oder verbinden", it: "Aggiungi o collega un'origine", pt: "Adicionar ou ligar uma origem", nl: "Bron toevoegen of koppelen", pl: "Dodaj lub podłącz źródło", ja: "ソースを追加または接続" },
"Latest processing jobs": { fr: "Dernières tâches de traitement", de: "Neueste Verarbeitungsjobs", it: "Ultimi processi di elaborazione", pt: "Últimas tarefas de processamento", nl: "Laatste verwerkingsjobs", pl: "Najnowsze zadania przetwarzania", ja: "最新の処理ジョブ" },
"Credits running low": { fr: "Crédits bientôt épuisés", de: "Credits werden knapp", it: "Crediti in esaurimento", pt: "Créditos a esgotar-se", nl: "Credits raken op", pl: "Kończą się kredyty", ja: "クレジットが少なくなっています" },
"Product limit reached": { fr: "Limite de produits atteinte", de: "Produktlimit erreicht", it: "Limite prodotti raggiunto", pt: "Limite de produtos atingido", nl: "Productlimiet bereikt", pl: "Osiągnięto limit produktów", ja: "商品上限に達しました" },
"You're out of AI credits": { fr: "Vous n'avez plus de crédits IA", de: "Ihre KI-Credits sind aufgebraucht", it: "Hai esaurito i crediti IA", pt: "Ficou sem créditos de IA", nl: "Uw AI-credits zijn op", pl: "Skończyły Ci się kredyty AI", ja: "AIクレジットがなくなりました" },
"You're on the Free plan": { fr: "Vous êtes sur l'offre Free", de: "Sie nutzen den Free-Plan", it: "Sei sul piano Free", pt: "Está no plano Free", nl: "U zit op het Free-plan", pl: "Korzystasz z planu Free", ja: "Freeプランをご利用中です" },
"Trial · {plan}": { fr: "Essai · {plan}", de: "Testphase · {plan}", it: "Prova · {plan}", pt: "Teste · {plan}", nl: "Proef · {plan}", pl: "Okres próbny · {plan}", ja: "トライアル · {plan}" },
"Revoke this invitation?": { fr: "Révoquer cette invitation ?", de: "Diese Einladung widerrufen?", it: "Revocare questo invito?", pt: "Revogar este convite?", nl: "Deze uitnodiging intrekken?", pl: "Unieważnić to zaproszenie?", ja: "この招待を取り消しますか?" },
"Invitation revoked.": { fr: "Invitation révoquée.", de: "Einladung widerrufen.", it: "Invito revocato.", pt: "Convite revogado.", nl: "Uitnodiging ingetrokken.", pl: "Zaproszenie unieważnione.", ja: "招待を取り消しました。" },
"Could not send invite": { fr: "Impossible d'envoyer l'invitation", de: "Einladung konnte nicht gesendet werden", it: "Impossibile inviare l'invito", pt: "Não foi possível enviar o convite", nl: "Uitnodiging kon niet worden verzonden", pl: "Nie można wysłać zaproszenia", ja: "招待を送信できませんでした" },
"Could not revoke invite": { fr: "Impossible de révoquer l'invitation", de: "Einladung konnte nicht widerrufen werden", it: "Impossibile revocare l'invito", pt: "Não foi possível revogar o convite", nl: "Uitnodiging kon niet worden ingetrokken", pl: "Nie można unieważnić zaproszenia", ja: "招待を取り消せませんでした" },
"Could not remove user": { fr: "Impossible de retirer l'utilisateur", de: "Benutzer konnte nicht entfernt werden", it: "Impossibile rimuovere l'utente", pt: "Não foi possível remover o utilizador", nl: "Gebruiker kon niet worden verwijderd", pl: "Nie można usunąć użytkownika", ja: "ユーザーを削除できませんでした" },
"Could not update role": { fr: "Impossible de mettre à jour le rôle", de: "Rolle konnte nicht aktualisiert werden", it: "Impossibile aggiornare il ruolo", pt: "Não foi possível atualizar o papel", nl: "Rol kon niet worden bijgewerkt", pl: "Nie można zaktualizować roli", ja: "ロールを更新できませんでした" },
"Could not verify invite": { fr: "Impossible de vérifier l'invitation", de: "Einladung konnte nicht verifiziert werden", it: "Impossibile verificare l'invito", pt: "Não foi possível verificar o convite", nl: "Uitnodiging kon niet worden geverifieerd", pl: "Nie można zweryfikować zaproszenia", ja: "招待を確認できませんでした" },
"Could not accept invite": { fr: "Impossible d'accepter l'invitation", de: "Einladung konnte nicht angenommen werden", it: "Impossibile accettare l'invito", pt: "Não foi possível aceitar o convite", nl: "Uitnodiging kon niet worden geaccepteerd", pl: "Nie można zaakceptować zaproszenia", ja: "招待を承認できませんでした" },
"Could not set password": { fr: "Impossible de définir le mot de passe", de: "Passwort konnte nicht festgelegt werden", it: "Impossibile impostare la password", pt: "Não foi possível definir a palavra-passe", nl: "Wachtwoord kon niet worden ingesteld", pl: "Nie można ustawić hasła", ja: "パスワードを設定できませんでした" },
"Enter a valid email address.": { fr: "Saisissez une adresse e-mail valide.", de: "Geben Sie eine gültige E-Mail-Adresse ein.", it: "Inserisci un indirizzo email valido.", pt: "Introduza um endereço de e-mail válido.", nl: "Voer een geldig e-mailadres in.", pl: "Wprowadź prawidłowy adres e-mail.", ja: "有効なメールアドレスを入力してください。" },
"Companies need at least one admin": { fr: "Les entreprises ont besoin d'au moins un administrateur", de: "Unternehmen benötigen mindestens einen Admin", it: "Le aziende necessitano di almeno un amministratore", pt: "As empresas precisam de pelo menos um administrador", nl: "Bedrijven hebben minstens één beheerder nodig", pl: "Firmy potrzebują co najmniej jednego administratora", ja: "会社には少なくとも1人の管理者が必要です" },
"Set password first:": { fr: "Définissez d'abord le mot de passe :", de: "Zuerst Passwort festlegen:", it: "Imposta prima la password:", pt: "Defina primeiro a palavra-passe:", nl: "Stel eerst een wachtwoord in:", pl: "Najpierw ustaw hasło:", ja: "先にパスワードを設定:" },
"Platform admins can re-issue from": { fr: "Les administrateurs de la plateforme peuvent réémettre depuis", de: "Plattform-Admins können erneut ausstellen unter", it: "Gli amministratori della piattaforma possono riemettere da", pt: "Os administradores da plataforma podem reemitir a partir de", nl: "Platformbeheerders kunnen opnieuw uitgeven via", pl: "Administratorzy platformy mogą ponownie wystawić z", ja: "プラットフォーム管理者は次から再発行できます:" },
"Have a token? Open accept invite": { fr: "Vous avez un jeton ? Ouvrir accepter l'invitation", de: "Haben Sie ein Token? Einladung annehmen öffnen", it: "Hai un token? Apri accetta invito", pt: "Tem um token? Abrir aceitar convite", nl: "Heeft u een token? Open uitnodiging accepteren", pl: "Masz token? Otwórz akceptację zaproszenia", ja: "トークンがありますか?招待の承認を開く" },
"Have an invite or set-password link?": { fr: "Vous avez une invitation ou un lien de définition de mot de passe ?", de: "Haben Sie eine Einladung oder einen Passwort-Link?", it: "Hai un invito o un link per impostare la password?", pt: "Tem um convite ou um link para definir a palavra-passe?", nl: "Heeft u een uitnodiging of set-wachtwoordlink?", pl: "Masz zaproszenie lub link do ustawienia hasła?", ja: "招待またはパスワード設定リンクがありますか?" },
"Registers a company and its admin user.": { fr: "Enregistre une entreprise et son utilisateur administrateur.", de: "Registriert ein Unternehmen und dessen Admin-Benutzer.", it: "Registra un'azienda e il relativo utente amministratore.", pt: "Regista uma empresa e o respetivo utilizador administrador.", nl: "Registreert een bedrijf en de bijbehorende beheerdersgebruiker.", pl: "Rejestruje firmę i jej użytkownika administratora.", ja: "会社とその管理者ユーザーを登録します。" },
"Checking invite…": { fr: "Vérification de l'invitation…", de: "Einladung wird geprüft…", it: "Verifica invito…", pt: "A verificar convite…", nl: "Uitnodiging controleren…", pl: "Sprawdzanie zaproszenia…", ja: "招待を確認中…" },
"Invite token": { fr: "Jeton d'invitation", de: "Einladungs-Token", it: "Token di invito", pt: "Token de convite", nl: "Uitnodigingstoken", pl: "Token zaproszenia", ja: "招待トークン" },
"Reset token": { fr: "Jeton de réinitialisation", de: "Reset-Token", it: "Token di reimpostazione", pt: "Token de redefinição", nl: "Resettoken", pl: "Token resetowania", ja: "リセットトークン" },
"At least 8 characters. No other complexity rules.": { fr: "Au moins 8 caractères. Aucune autre règle de complexité.", de: "Mindestens 8 Zeichen. Keine weiteren Komplexitätsregeln.", it: "Almeno 8 caratteri. Nessun'altra regola di complessità.", pt: "Pelo menos 8 caracteres. Sem outras regras de complexidade.", nl: "Minimaal 8 tekens. Geen andere complexiteitsregels.", pl: "Co najmniej 8 znaków. Brak innych reguł złożoności.", ja: "8文字以上。その他の複雑さの規則はありません。" },
"Switch account:": { fr: "Changer de compte :", de: "Konto wechseln:", it: "Cambia account:", pt: "Mudar de conta:", nl: "Account wisselen:", pl: "Zmień konto:", ja: "アカウント切替:" },
"Re-issue path:": { fr: "Chemin de réémission :", de: "Neuausstellungs-Pfad:", it: "Percorso di riemissione:", pt: "Caminho de reemissão:", nl: "Pad voor opnieuw uitgeven:", pl: "Ścieżka ponownego wystawienia:", ja: "再発行の手順:" },
"Wrong account for this invite": { fr: "Mauvais compte pour cette invitation", de: "Falsches Konto für diese Einladung", it: "Account errato per questo invito", pt: "Conta errada para este convite", nl: "Verkeerd account voor deze uitnodiging", pl: "Złe konto dla tego zaproszenia", ja: "この招待には別のアカウントが必要です" },
"{email} removed.": { fr: "{email} retiré.", de: "{email} entfernt.", it: "{email} rimosso.", pt: "{email} removido.", nl: "{email} verwijderd.", pl: "Usunięto {email}.", ja: "{email} を削除しました。" },
"{email} is now {role}.": { fr: "{email} est maintenant {role}.", de: "{email} ist jetzt {role}.", it: "{email} ora è {role}.", pt: "{email} é agora {role}.", nl: "{email} is nu {role}.", pl: "{email} jest teraz {role}.", ja: "{email} は現在 {role} です。" },
"{action} {email} to {role}?": { fr: "{action} {email} en {role} ?", de: "{email} zu {role} {action}?", it: "{action} {email} a {role}?", pt: "{action} {email} para {role}?", nl: "{email} naar {role} {action}?", pl: "{action} {email} do {role}?", ja: "{email} を {role} に{action}しますか?" },
"Remove {email} from this company?": { fr: "Retirer {email} de cette entreprise ?", de: "{email} aus diesem Unternehmen entfernen?", it: "Rimuovere {email} da questa azienda?", pt: "Remover {email} desta empresa?", nl: "{email} uit dit bedrijf verwijderen?", pl: "Usunąć {email} z tej firmy?", ja: "{email} をこの会社から削除しますか?" },
"Live totals for {name}": { fr: "Totaux en direct pour {name}", de: "Live-Summen für {name}", it: "Totali in tempo reale per {name}", pt: "Totais em direto para {name}", nl: "Live totalen voor {name}", pl: "Bieżące sumy dla {name}", ja: "{name} のリアルタイム合計" },
"Trial ends {date}. {credits} credits remaining.": { fr: "L'essai se termine le {date}. {credits} crédits restants.", de: "Testphase endet am {date}. {credits} Credits übrig.", it: "La prova termina il {date}. {credits} crediti rimanenti.", pt: "O teste termina a {date}. {credits} créditos restantes.", nl: "Proef eindigt op {date}. {credits} credits resterend.", pl: "Okres próbny kończy się {date}. Pozostało {credits} kredytów.", ja: "トライアルは {date} に終了します。残りクレジット {credits}。" },
"{credits} credits remaining on your trial.": { fr: "{credits} crédits restants sur votre essai.", de: "{credits} Credits verbleiben in Ihrer Testphase.", it: "{credits} crediti rimanenti nella prova.", pt: "{credits} créditos restantes no seu teste.", nl: "{credits} credits resterend op uw proef.", pl: "Pozostało {credits} kredytów w okresie próbnym.", ja: "トライアルの残りクレジットは {credits} です。" },
"Feeds, products, jobs, and export.": { fr: "Flux, produits, tâches et export.", de: "Feeds, Produkte, Jobs und Export.", it: "Feed, prodotti, processi ed esportazione.", pt: "Feeds, produtos, tarefas e exportação.", nl: "Feeds, producten, jobs en export.", pl: "Feedy, produkty, zadania i eksport.", ja: "フィード、商品、ジョブ、エクスポート。" }
};
// Merge seed.es + MORE into full phrase-map
const map = { ...seed };
for (const [enText, langs] of Object.entries(MORE)) {
map[enText] = { ...(map[enText] || {}), ...langs };
}
// Also attach es from EXTRA_ES for any en phrases covered by keys
for (const [k, es] of Object.entries(EXTRA_ES.es)) {
const e = en[k];
if (!e) continue;
map[e] = { ...(map[e] || {}), es };
}
fs.writeFileSync("phrase-map.json", JSON.stringify(map, null, 2));
console.log("phrase-map entries", Object.keys(map).length);
// Count coverage vs needed phrases
const needed = JSON.parse(fs.readFileSync("_phrases-needed.json", "utf8"));
let covered = 0;
const gaps = [];
for (const p of needed) {
const m = map[p];
if (m && m.fr && m.de && m.it && m.pt && m.nl && m.pl && m.ja) covered++;
else gaps.push(p);
}
console.log("needed", needed.length, "fully covered", covered, "gaps", gaps.length);
fs.writeFileSync("_phrase-gaps.json", JSON.stringify(gaps, null, 2));