All checks were successful
Deploy to Production / Build and Deploy (push) Successful in 12s
- Sidebar: dynamic brand-accent colors, brainstorm section restyled - AI chat general: popup panel with expand/collapse, hides when contextual AI open - AI chat contextual: tabs reordered (Actions first), X close button, height fix - Settings: all tabs restyled, 6 new color presets (sage, terracotta, iron, etc.) - Global color cleanup: emerald/orange hardcoded → brand-accent dynamic - Brainstorm page: orange → brand-accent throughout - PageEntry animation component added to key pages - Floating AI button: bg-brand-accent instead of hardcoded black - i18n: all 15 locales updated with new AI/billing keys - Billing: freemium quota tracking, BYOK, stripe subscription scaffolding - Admin: integrated into new design - AGENTS.md + CLAUDE.md project rules added
594 lines
16 KiB
JavaScript
594 lines
16 KiB
JavaScript
/**
|
|
* Met à jour agents.form.slideThemes + richTextEditor (aiReformulateFailed, translateTargets)
|
|
* dans memento-note/locales/*.json (seul en.json est laissé hors de ce script).
|
|
*/
|
|
import fs from 'fs'
|
|
import path from 'path'
|
|
import { fileURLToPath } from 'url'
|
|
|
|
const __dirname = path.dirname(fileURLToPath(import.meta.url))
|
|
const localesDir = path.join(__dirname, '..', 'locales')
|
|
|
|
const slideKeys = [
|
|
'modern_wellness',
|
|
'business_authority',
|
|
'nature_outdoors',
|
|
'vintage_academic',
|
|
'soft_creative',
|
|
'bohemian',
|
|
'vibrant_tech',
|
|
'craft_artisan',
|
|
'tech_night',
|
|
'education_charts',
|
|
'forest_eco',
|
|
'elegant_fashion',
|
|
'art_food',
|
|
'luxury_mystery',
|
|
'pure_tech_blue',
|
|
'coastal_coral',
|
|
'vibrant_orange_mint',
|
|
'platinum_white_gold',
|
|
]
|
|
|
|
const TT_KEYS = [
|
|
'Francais',
|
|
'English',
|
|
'Espanol',
|
|
'Deutsch',
|
|
'Persan',
|
|
'Portugais',
|
|
'Italiano',
|
|
'Chinois',
|
|
'Japonais',
|
|
]
|
|
|
|
/** @returns {Record<string,string>} slideThemes avec toutes les clés présentes */
|
|
function st(...values) {
|
|
const out = {}
|
|
slideKeys.forEach((k, i) => {
|
|
out[k] = values[i]
|
|
})
|
|
return out
|
|
}
|
|
|
|
/** @returns {Record<string,string>} translateTargets avec clés fixes */
|
|
function tt(vf, ven, ves, vd, vp, vp2, vit, vch, vja) {
|
|
return {
|
|
Francais: vf,
|
|
English: ven,
|
|
Espanol: ves,
|
|
Deutsch: vd,
|
|
Persan: vp,
|
|
Portugais: vp2,
|
|
Italiano: vit,
|
|
Chinois: vch,
|
|
Japonais: vja,
|
|
}
|
|
}
|
|
|
|
/** @type {Record<string, { slideThemes: Record<string,string>, translateTargets: Record<string,string>, aiReformulateFailed: string }>} */
|
|
const LOCALE = {
|
|
de: {
|
|
slideThemes: st(
|
|
'Modern & Wohlbefinden',
|
|
'Business & Autorität',
|
|
'Natur & Outdoor',
|
|
'Vintage & Akademisch',
|
|
'Sanft & Kreativ',
|
|
'Bohemian',
|
|
'Lebhaft & Tech',
|
|
'Handwerk & Artisan',
|
|
'Tech & Nacht (dunkel)',
|
|
'Bildung & Diagramme',
|
|
'Wald & Öko',
|
|
'Elegant & Mode',
|
|
'Kunst & Kulinarik',
|
|
'Luxus & Mystik',
|
|
'Reines Tech-Blau',
|
|
'Küsten-Koralle',
|
|
'Lebhaft Orange & Minze',
|
|
'Platin Weißgold',
|
|
),
|
|
translateTargets: tt(
|
|
'Französisch',
|
|
'Englisch',
|
|
'Spanisch',
|
|
'Deutsch',
|
|
'Persisch',
|
|
'Portugiesisch',
|
|
'Italienisch',
|
|
'Chinesisch',
|
|
'Japanisch',
|
|
),
|
|
aiReformulateFailed:
|
|
'Der KI-Assistent konnte diesen Text nicht verarbeiten. Bitte erneut versuchen.',
|
|
},
|
|
es: {
|
|
slideThemes: st(
|
|
'Moderno y bienestar',
|
|
'Negocios y autoridad',
|
|
'Naturaleza y aire libre',
|
|
'Vintage y académico',
|
|
'Suave y creativo',
|
|
'Bohemio',
|
|
'Vibrante y tech',
|
|
'Artesanía',
|
|
'Tech y noche (oscuro)',
|
|
'Educación y gráficos',
|
|
'Bosque y eco',
|
|
'Elegancia y moda',
|
|
'Arte y gastronomía',
|
|
'Lujo y misterio',
|
|
'Tech azul puro',
|
|
'Coral costero',
|
|
'Naranja vibrante y menta',
|
|
'Platino blanco y oro',
|
|
),
|
|
translateTargets: tt(
|
|
'Francés',
|
|
'Inglés',
|
|
'Español',
|
|
'Alemán',
|
|
'Persa',
|
|
'Portugués',
|
|
'Italiano',
|
|
'Chino',
|
|
'Japonés',
|
|
),
|
|
aiReformulateFailed:
|
|
'La IA no pudo procesar este texto. Inténtalo de nuevo.',
|
|
},
|
|
fr: {
|
|
slideThemes: st(
|
|
'Moderne & bien-être',
|
|
'Affaires & autorité',
|
|
'Nature & plein air',
|
|
'Vintage & académique',
|
|
'Doux & créatif',
|
|
'Bohème',
|
|
'Éclat & tech',
|
|
'Artisan & fait main',
|
|
'Tech & nuit (sombre)',
|
|
'Éducation & graphiques',
|
|
'Forêt & éco',
|
|
'Élégance & mode',
|
|
'Art & gastronomie',
|
|
'Luxe & mystère',
|
|
'Bleu tech pur',
|
|
'Corail côtier',
|
|
'Orange vif & menthe',
|
|
'Platine blanc & or',
|
|
),
|
|
translateTargets: tt(
|
|
'Français',
|
|
'Anglais',
|
|
'Espagnol',
|
|
'Allemand',
|
|
'Persan',
|
|
'Portugais',
|
|
'Italien',
|
|
'Chinois',
|
|
'Japonais',
|
|
),
|
|
aiReformulateFailed:
|
|
"L'assistant IA n'a pas pu traiter ce texte. Réessayez.",
|
|
},
|
|
it: {
|
|
slideThemes: st(
|
|
'Moderno e benessere',
|
|
'Business e autorevolezza',
|
|
'Natura e outdoor',
|
|
'Vintage e accademico',
|
|
'Morbido e creativo',
|
|
'Bohemien',
|
|
'Vivace e tech',
|
|
'Artigianato',
|
|
'Tech e notte (scuro)',
|
|
'Formazione e grafici',
|
|
'Foresta ed eco',
|
|
'Eleganza e moda',
|
|
'Arte e cucina',
|
|
'Lusso e mistero',
|
|
'Tech blu puro',
|
|
'Corallo costiero',
|
|
'Arancio vivace e menta',
|
|
'Platino bianco e oro',
|
|
),
|
|
translateTargets: tt(
|
|
'Francese',
|
|
'Inglese',
|
|
'Spagnolo',
|
|
'Tedesco',
|
|
'Persiano',
|
|
'Portoghese',
|
|
'Italiano',
|
|
'Cinese',
|
|
'Giapponese',
|
|
),
|
|
aiReformulateFailed:
|
|
"L'assistente IA non ha potuto elaborare questo testo. Riprova.",
|
|
},
|
|
pt: {
|
|
slideThemes: st(
|
|
'Moderno e bem-estar',
|
|
'Negócios e autoridade',
|
|
'Natureza e ar livre',
|
|
'Vintage e académico',
|
|
'Suave e criativo',
|
|
'Boémio',
|
|
'Vibrante e tech',
|
|
'Artesanato',
|
|
'Tech e noite (escuro)',
|
|
'Educação e gráficos',
|
|
'Floresta e eco',
|
|
'Elegância e moda',
|
|
'Arte e gastronomia',
|
|
'Luxo e mistério',
|
|
'Tech azul puro',
|
|
'Coral costeiro',
|
|
'Laranja vibrante e hortelã',
|
|
'Platina branca e ouro',
|
|
),
|
|
translateTargets: tt(
|
|
'Francês',
|
|
'Inglês',
|
|
'Espanhol',
|
|
'Alemão',
|
|
'Persa',
|
|
'Português',
|
|
'Italiano',
|
|
'Chinês',
|
|
'Japonês',
|
|
),
|
|
aiReformulateFailed:
|
|
'A IA não conseguiu processar este texto. Tenta novamente.',
|
|
},
|
|
nl: {
|
|
slideThemes: st(
|
|
'Modern & welzijn',
|
|
'Zaken & autoriteit',
|
|
'Natuur & buiten',
|
|
'Vintage & academisch',
|
|
'Zacht & creatief',
|
|
'Bohemian',
|
|
'Levendig & tech',
|
|
'Ambacht',
|
|
'Tech & nacht (donker)',
|
|
'Onderwijs & grafieken',
|
|
'Bos & eco',
|
|
'Elegant & mode',
|
|
'Kunst & gastronomie',
|
|
'Luxe & mysterie',
|
|
'Strak techblauw',
|
|
'Kustkoraal',
|
|
'Levend oranje & munt',
|
|
'Platina witgoud',
|
|
),
|
|
translateTargets: tt(
|
|
'Frans',
|
|
'Engels',
|
|
'Spaans',
|
|
'Duits',
|
|
'Perzisch',
|
|
'Portugees',
|
|
'Italiaans',
|
|
'Chinees',
|
|
'Japans',
|
|
),
|
|
aiReformulateFailed:
|
|
'De AI-assistent kon deze tekst niet verwerken. Probeer het opnieuw.',
|
|
},
|
|
pl: {
|
|
slideThemes: st(
|
|
'Nowoczesny wellness',
|
|
'Biznes i autorytet',
|
|
'Natura i outdoor',
|
|
'Vintage i akademicki',
|
|
'Miękki i kreatywny',
|
|
'Boho',
|
|
'Żywy tech',
|
|
'Rzemiosło',
|
|
'Tech i noc (ciemny)',
|
|
'Edukacja i wykresy',
|
|
'Las i eco',
|
|
'Elegancja i moda',
|
|
'Sztuka i kuchnia',
|
|
'Luksus i tajemnica',
|
|
'Czysty tech niebieski',
|
|
'Koral przybrzeżny',
|
|
'Żywa pomarańcz i mięta',
|
|
'Platyna i białe złoto',
|
|
),
|
|
translateTargets: tt(
|
|
'Francuski',
|
|
'Angielski',
|
|
'Hiszpański',
|
|
'Niemiecki',
|
|
'Perski',
|
|
'Portugalski',
|
|
'Włoski',
|
|
'Chiński',
|
|
'Japoński',
|
|
),
|
|
aiReformulateFailed:
|
|
'Asystent IA nie mógł przetworzyć tego tekstu. Spróbuj ponownie.',
|
|
},
|
|
ru: {
|
|
slideThemes: st(
|
|
'Современность и велнес',
|
|
'Бизнес и авторитет',
|
|
'Природа и активный отдых',
|
|
'Винтаж и академизм',
|
|
'Мягкость и креатив',
|
|
'Богемный',
|
|
'Яркость и техно',
|
|
'Ремесло',
|
|
'Техно и ночь (тёмный)',
|
|
'Образование и графики',
|
|
'Лес и эко',
|
|
'Элегантность и мода',
|
|
'Искусство и гастрономия',
|
|
'Роскошь и тайна',
|
|
'Чистый техно-синий',
|
|
'Прибрежный коралл',
|
|
'Яркий оранжевый и мята',
|
|
'Платина и белое золото',
|
|
),
|
|
translateTargets: tt(
|
|
'Французский',
|
|
'Английский',
|
|
'Испанский',
|
|
'Немецкий',
|
|
'Персидский',
|
|
'Португальский',
|
|
'Итальянский',
|
|
'Китайский',
|
|
'Японский',
|
|
),
|
|
aiReformulateFailed:
|
|
'ИИ-помощник не смог обработать этот текст. Попробуйте снова.',
|
|
},
|
|
zh: {
|
|
slideThemes: st(
|
|
'现代与活力',
|
|
'商务权威',
|
|
'自然户外',
|
|
'复古学院',
|
|
'柔和创意',
|
|
'波希米亚',
|
|
'活力科技',
|
|
'手工艺匠心',
|
|
'科技暗夜(深色)',
|
|
'教育与图表',
|
|
'森林生态',
|
|
'优雅时尚',
|
|
'艺术与美食',
|
|
'奢华神秘',
|
|
'纯正科技蓝',
|
|
'海岸珊瑚',
|
|
'活力橙与薄荷',
|
|
'铂金与白金色',
|
|
),
|
|
translateTargets: tt(
|
|
'法语',
|
|
'英语',
|
|
'西班牙语',
|
|
'德语',
|
|
'波斯语',
|
|
'葡萄牙语',
|
|
'意大利语',
|
|
'中文',
|
|
'日语',
|
|
),
|
|
aiReformulateFailed: 'AI 助手无法处理此文本,请重试。',
|
|
},
|
|
ja: {
|
|
slideThemes: st(
|
|
'モダン&ウェルネス',
|
|
'ビジネス&オーソリティ',
|
|
'ネイチャー&アウトドア',
|
|
'ヴィンテージ&アカデミック',
|
|
'ソフト&クリエイティブ',
|
|
'ボヘミアン',
|
|
'ビブラント&テック',
|
|
'クラフト&職人',
|
|
'テック&ナイト(ダーク)',
|
|
'教育&チャート',
|
|
'フォレスト&エコ',
|
|
'エレガント&ファッション',
|
|
'アート&フード',
|
|
'ラグジュアリー&ミステリー',
|
|
'ピュアテックブルー',
|
|
'コースタルコーラル',
|
|
'ビビッドオレンジ&ミント',
|
|
'プラチナホワイトゴールド',
|
|
),
|
|
translateTargets: tt(
|
|
'フランス語',
|
|
'英語',
|
|
'スペイン語',
|
|
'ドイツ語',
|
|
'ペルシア語',
|
|
'ポルトガル語',
|
|
'イタリア語',
|
|
'中国語',
|
|
'日本語',
|
|
),
|
|
aiReformulateFailed:
|
|
'AI アシスタントがこのテキストを処理できませんでした。もう一度お試しください。',
|
|
},
|
|
ko: {
|
|
slideThemes: st(
|
|
'모던 앤 웰니스',
|
|
'비즈니스 앤 오서리티',
|
|
'네이처 앤 아웃도어',
|
|
'빈티지 앤 아카데믹',
|
|
'소프트 앤 크리에이티브',
|
|
'보헤미안',
|
|
'비브런트 앤 테크',
|
|
'크래프트 앤 아티즌',
|
|
'테크 앤 나イト(다크)',
|
|
'교육 앤 차트',
|
|
'포레스트 앤 에코',
|
|
'엘리건트 앤 패션',
|
|
'아트 앤 푸드',
|
|
'럭셔리 앤 미스터리',
|
|
'퓨어 테크 블루',
|
|
'코스트럴 코럴',
|
|
'비브런트 오렌지 앤 민트',
|
|
'플래티넘 화이트 골드',
|
|
),
|
|
translateTargets: tt(
|
|
'프랑스어',
|
|
'영어',
|
|
'스페인어',
|
|
'독일어',
|
|
'페르시아어',
|
|
'포르투갈어',
|
|
'이탈리아어',
|
|
'중국어',
|
|
'일본어',
|
|
),
|
|
aiReformulateFailed:
|
|
'AI 어시스턴트가 이 텍스트를 처리하지 못했습니다. 다시 시도해 주세요.',
|
|
},
|
|
ar: {
|
|
slideThemes: st(
|
|
'عصري وصحة وعافية',
|
|
'عمل وسلطة مهنية',
|
|
'طبيعة وهواء طلق',
|
|
'عتيق وأكاديمي',
|
|
'ناعم وإبداعي',
|
|
'بوهيمي',
|
|
'زاهٍ وتقني',
|
|
'حرفة وصناعة يدوية',
|
|
'تقني وليلة (داكن)',
|
|
'تعليم ورسوم بيانية',
|
|
'غابة وبيئة',
|
|
'أنيق وأزياء',
|
|
'فن وطعام',
|
|
'فخامة وغموض',
|
|
'أزرق تقني نقي',
|
|
'مرجان ساحلي',
|
|
'برتقالي زاهٍ ونعناع',
|
|
'بلاتيني ذهب أبيض',
|
|
),
|
|
translateTargets: tt(
|
|
'الفرنسية',
|
|
'الإنجليزية',
|
|
'الإسبانية',
|
|
'الألمانية',
|
|
'الفارسية',
|
|
'البرتغالية',
|
|
'الإيطالية',
|
|
'الصينية',
|
|
'اليابانية',
|
|
),
|
|
aiReformulateFailed:
|
|
'تعذّر على المساعد الذكي معالجة هذا النص. حاول مجدداً.',
|
|
},
|
|
fa: {
|
|
slideThemes: st(
|
|
'مدرن و تندرستی',
|
|
'کسبوکار و اعتبار',
|
|
'طبیعت و فضای باز',
|
|
'کلاسیک دانشگاهی',
|
|
'نرم و خلاقانه',
|
|
'بوهمیایی',
|
|
'پرجنبوجوش و تکنولوژی',
|
|
'صنعت دستی و هنرمند',
|
|
'فناوری و شب (تیره)',
|
|
'آموزش و نمودار',
|
|
'جنگل و اکولوژی',
|
|
'شیک و مد',
|
|
'هنر و غذا',
|
|
'لوکس و مرموز',
|
|
'آبی تکنولوژی خالص',
|
|
'مرجان ساحلی',
|
|
'نارنجی شاد و نعناع',
|
|
'پلاتین و سفید طلایی',
|
|
),
|
|
translateTargets: tt(
|
|
'فرانسوی',
|
|
'انگلیسی',
|
|
'اسپانیایی',
|
|
'آلمانی',
|
|
'فارسی',
|
|
'پرتغالی',
|
|
'ایتالیایی',
|
|
'چینی',
|
|
'ژاپنی',
|
|
),
|
|
aiReformulateFailed:
|
|
'دستیار هوش مصنوعی نتوانست این متن را پردازش کند. دوباره تلاش کنید.',
|
|
},
|
|
hi: {
|
|
slideThemes: st(
|
|
'आधुनिक और वेलनेस',
|
|
'व्यवसाय और प्राधिकरण',
|
|
'प्रकृति और बाहर',
|
|
'विंटेज और शैक्षणिक',
|
|
'मुलायम और रचनात्मक',
|
|
'बोहो',
|
|
'जीवंत और टेक',
|
|
'शिल्प और कारीगर',
|
|
'टेक और रात (डार्क)',
|
|
'शिक्षा और चार्ट',
|
|
'वन और इको',
|
|
'सुरुचिपूर्ण और फैशन',
|
|
'कला और भोजन',
|
|
'लक्ज़री और रहस्य',
|
|
'शुद्ध टेक नीला',
|
|
'तटीय कोरल',
|
|
'जीवंत संतरा और पुदीना',
|
|
'प्लैटिनम सफ़ेद सोना',
|
|
),
|
|
translateTargets: tt(
|
|
'फ़्रेंच',
|
|
'अंग्रेज़ी',
|
|
'स्पेनिश',
|
|
'जर्मन',
|
|
'फ़ारसी',
|
|
'पुर्तगाली',
|
|
'इतालवी',
|
|
'चीनी',
|
|
'जापानी',
|
|
),
|
|
aiReformulateFailed:
|
|
'AI सहायक इस पाठ को प्रोसेस नहीं कर सका। दोबारा कोशिश करें।',
|
|
},
|
|
}
|
|
|
|
function applyLocale(code, bundle) {
|
|
const file = path.join(localesDir, `${code}.json`)
|
|
if (!fs.existsSync(file)) {
|
|
console.warn('Fichier manquant:', file)
|
|
return
|
|
}
|
|
const raw = fs.readFileSync(file, 'utf8')
|
|
const j = JSON.parse(raw)
|
|
if (!j.agents?.form) {
|
|
console.warn(`${code}: agents.form absent, ignoré`)
|
|
return
|
|
}
|
|
if (!j.agents.form.slideThemes) j.agents.form.slideThemes = {}
|
|
slideKeys.forEach((k) => {
|
|
j.agents.form.slideThemes[k] = bundle.slideThemes[k]
|
|
})
|
|
|
|
if (!j.richTextEditor) j.richTextEditor = {}
|
|
TT_KEYS.forEach((k) => {
|
|
j.richTextEditor.translateTargets =
|
|
j.richTextEditor.translateTargets ?? {}
|
|
j.richTextEditor.translateTargets[k] = bundle.translateTargets[k]
|
|
})
|
|
j.richTextEditor.aiReformulateFailed = bundle.aiReformulateFailed
|
|
|
|
fs.writeFileSync(file, JSON.stringify(j, null, 2) + '\n', 'utf8')
|
|
console.log('OK', code)
|
|
}
|
|
|
|
for (const code of Object.keys(LOCALE)) {
|
|
applyLocale(code, LOCALE[code])
|
|
}
|