🎨 French Font Generator – Générateur de Polices Françaises
🔄 Translation / Traduction
🎭 Quick Effect Presets / Effets Rapides
🎛️ Basic Controls / Contrôles de Base
32px
1px
1.4
✨ Visual Effects / Effets Visuels
1x
🔄 3D Transform / Transformation 3D
0°
0°
0°
1x
600px
📤 Export Options / Options d’Export
${text}
`;
this.downloadText(htmlContent, 'french-fonts.html', 'text/html');
this.showNotification('🔗 HTML exported! / HTML exporté!');
}
exportAsCSS() {
const cssContent = this.generateInlineCSS();
this.downloadText(cssContent, 'french-fonts.css', 'text/css');
this.showNotification('🎨 CSS exported! / CSS exporté!');
}
exportAsSVG() {
const textInput = document.getElementById('frenchTextInput');
const text = textInput.value.trim() || 'Bonjour le monde!';
const svgContent = ``;
this.downloadText(svgContent, 'french-fonts.svg', 'image/svg+xml');
this.showNotification('📐 SVG exported! / SVG exporté!');
}
generateInlineCSS() {
const settings = this.currentSettings;
let css = `.french-text {
font-size: ${settings.fontSize}px;
font-weight: ${settings.fontWeight};
color: ${settings.textColor};
letter-spacing: ${settings.letterSpacing}px;
line-height: ${settings.lineHeight};
text-align: ${settings.textAlign};`;
if (settings.textTransform !== 'none') {
css += `\n text-transform: ${settings.textTransform};`;
}
if (settings.shadowIntensity > 0) {
css += `\n text-shadow: ${settings.shadowIntensity * 2}px ${settings.shadowIntensity * 2}px 4px ${settings.shadowColor};`;
}
css += '\n}';
return css;
}
downloadText(content, filename, mimeType) {
const blob = new Blob([content], { type: mimeType });
const url = URL.createObjectURL(blob);
const link = document.createElement('a');
link.href = url;
link.download = filename;
link.click();
URL.revokeObjectURL(url);
}
updateControlsFromSettings() {
const settings = this.currentSettings;
// Update all control elements with current settings
Object.entries(settings).forEach(([key, value]) => {
let elementId = '';
// Map setting keys to element IDs
switch (key) {
case 'fontSize': elementId = 'fontSizeSlider'; break;
case 'fontWeight': elementId = 'fontWeightSelect'; break;
case 'textColor': elementId = 'textColorPicker'; break;
case 'letterSpacing': elementId = 'letterSpacingSlider'; break;
case 'lineHeight': elementId = 'lineHeightSlider'; break;
case 'textTransform': elementId = 'textTransformSelect'; break;
case 'shadowIntensity': elementId = 'shadowIntensitySlider'; break;
case 'shadowColor': elementId = 'shadowColorPicker'; break;
case 'backgroundEffect': elementId = 'backgroundEffectSelect'; break;
case 'textEffect': elementId = 'textEffectSelect'; break;
case 'animation': elementId = 'animationSelect'; break;
case 'borderStyle': elementId = 'borderStyleSelect'; break;
case 'rotateX': elementId = 'rotateXSlider'; break;
case 'rotateY': elementId = 'rotateYSlider'; break;
case 'skewX': elementId = 'skewXSlider'; break;
case 'scale': elementId = 'scaleSlider'; break;
case 'perspective': elementId = 'perspectiveSlider'; break;
case 'textAlign': elementId = 'textAlignSelect'; break;
}
const element = document.getElementById(elementId);
if (element) {
element.value = value;
// Update display for sliders
const displayElement = document.getElementById(elementId.replace('Slider', 'Display'));
if (displayElement && element.type === 'range') {
let suffix = key.includes('rotate') || key.includes('skew') ? '°' :
key === 'fontSize' || key === 'perspective' ? 'px' :
key === 'shadowIntensity' || key === 'scale' ? 'x' : '';
displayElement.textContent = value + suffix;
}
}
});
}
resetToDefaults() {
// Reset all settings to defaults
this.currentSettings = {
fontSize: 32,
fontWeight: 400,
textColor: '#000000',
letterSpacing: 1,
lineHeight: 1.4,
textTransform: 'none',
shadowIntensity: 1,
shadowColor: '#cccccc',
backgroundEffect: 'none',
textEffect: 'none',
animation: 'none',
borderStyle: 'none',
rotateX: 0,
rotateY: 0,
skewX: 0,
scale: 1,
perspective: 600,
textAlign: 'center'
};
this.updateControlsFromSettings();
this.generateFrenchFonts();
this.showNotification('🔄 Reset to defaults! / Remis par défaut!');
}
applyRandomSettings() {
// Apply random settings for fun effects
const colors = ['#0d47a1', '#1976d2', '#42a5f5', '#dc2626', '#ffc107', '#4caf50', '#9c27b0', '#ff6f00'];
const backgrounds = ['none', 'blue-gradient', 'gold-gradient', 'french-flag', 'lavender-texture'];
const textEffects = ['none', 'glow', 'outline', 'gradient', '3d'];
const animations = ['none', 'parisianGlow', 'champagneFloat', 'versaillesElegance', 'lavenderSway'];
this.currentSettings = {
fontSize: Math.floor(Math.random() * 60) + 20,
fontWeight: [100, 300, 400, 500, 700, 900][Math.floor(Math.random() * 6)],
textColor: colors[Math.floor(Math.random() * colors.length)],
letterSpacing: Math.floor(Math.random() * 10) - 2,
lineHeight: (Math.random() * 1.5) + 1,
textTransform: ['none', 'uppercase', 'lowercase', 'capitalize'][Math.floor(Math.random() * 4)],
shadowIntensity: Math.random() * 3,
shadowColor: colors[Math.floor(Math.random() * colors.length)],
backgroundEffect: backgrounds[Math.floor(Math.random() * backgrounds.length)],
textEffect: textEffects[Math.floor(Math.random() * textEffects.length)],
animation: animations[Math.floor(Math.random() * animations.length)],
borderStyle: ['none', 'solid', 'dashed', 'dotted'][Math.floor(Math.random() * 4)],
rotateX: Math.floor(Math.random() * 60) - 30,
rotateY: Math.floor(Math.random() * 60) - 30,
skewX: Math.floor(Math.random() * 20) - 10,
scale: (Math.random() * 1) + 0.7,
perspective: Math.floor(Math.random() * 500) + 300,
textAlign: ['left', 'center', 'right'][Math.floor(Math.random() * 3)]
};
this.updateControlsFromSettings();
this.generateFrenchFonts();
this.showNotification('🎲 Random settings applied! / Paramètres aléatoires appliqués!');
}
generateFrenchFonts() {
const textInput = document.getElementById('frenchTextInput');
const resultsSection = document.getElementById('frenchResultsSection');
const fontResults = document.getElementById('frenchFontResults');
if (!textInput || !resultsSection || !fontResults) {
console.error('Required elements not found');
alert('Error: Required elements not found. Please refresh the page.');
return;
}
const inputText = textInput.value.trim();
if (!inputText) {
alert('Veuillez entrer du texte français pour générer les polices ! / Please enter French text to generate fonts!');
textInput.focus();
return;
}
console.log('Generating fonts for text:', inputText);
let resultsHTML = '';
Object.entries(frenchFontStyles).forEach(([fontName, styleObj]) => {
const safeText = inputText.replace(/'/g, "'").replace(/"/g, """);
const customStyle = this.applyCustomStyles(styleObj.style);
const safeCSSStyle = customStyle.replace(/'/g, "\\'").replace(/"/g, '\\"');
resultsHTML += `
🎨
${fontName}
${inputText}
Please enter some English text to translate. / Veuillez entrer du texte anglais à traduire.
'; englishInput.focus(); return; } // Show loading state translationResult.innerHTML = `
🔄 Translating / Traduction... Please wait / Veuillez patienter...
`;
try {
let frenchText = await translateText(englishText, 'en', 'fr');
if (frenchText && frenchText !== englishText) {
frenchInput.value = frenchText;
translationResult.innerHTML = `
✅ Translation / Traduction (API): ${frenchText}
`;
// Auto-generate fonts with the translated text
setTimeout(() => {
generateFrenchFonts();
}, 500);
} else {
// Fallback to dictionary translation
fallbackDictionaryTranslation(englishText, frenchInput, translationResult);
}
} catch (error) {
console.error('Translation error:', error);
// Fallback to dictionary translation
fallbackDictionaryTranslation(englishText, frenchInput, translationResult);
}
}
// API Translation function with multiple providers
async function translateText(text, from, to) {
// First try MyMemory API
try {
const myMemoryUrl = `https://api.mymemory.translated.net/get?q=${encodeURIComponent(text)}&langpair=${from}|${to}`;
const myMemoryResponse = await fetch(myMemoryUrl);
const myMemoryData = await myMemoryResponse.json();
if (myMemoryData.responseData && myMemoryData.responseData.translatedText) {
return myMemoryData.responseData.translatedText;
}
} catch (error) {
console.warn('MyMemory API failed:', error);
}
// Second try Lingva Translate API
try {
const lingvaUrl = `https://lingva.ml/api/v1/${from}/${to}/${encodeURIComponent(text)}`;
const lingvaResponse = await fetch(lingvaUrl);
const lingvaData = await lingvaResponse.json();
if (lingvaData.translation) {
return lingvaData.translation;
}
} catch (error) {
console.warn('Lingva API failed:', error);
}
// Third try alternative Lingva instance
try {
const lingvaAltUrl = `https://translate.jae.fi/api/v1/${from}/${to}/${encodeURIComponent(text)}`;
const lingvaAltResponse = await fetch(lingvaAltUrl);
const lingvaAltData = await lingvaAltResponse.json();
if (lingvaAltData.translation) {
return lingvaAltData.translation;
}
} catch (error) {
console.warn('Alternative Lingva API failed:', error);
}
// Fourth try another Lingva instance
try {
const lingvaAlt2Url = `https://lingva.garudalinux.org/api/v1/${from}/${to}/${encodeURIComponent(text)}`;
const lingvaAlt2Response = await fetch(lingvaAlt2Url);
const lingvaAlt2Data = await lingvaAlt2Response.json();
if (lingvaAlt2Data.translation) {
return lingvaAlt2Data.translation;
}
} catch (error) {
console.warn('Second alternative Lingva API failed:', error);
}
return null; // All APIs failed
}
// Fallback dictionary translation
function fallbackDictionaryTranslation(englishText, frenchInput, translationResult) {
const words = englishText.toLowerCase().split(' ');
let frenchText = '';
words.forEach((word, index) => {
const cleanWord = word.replace(/[^\w]/g, '');
const punctuation = word.replace(/\w/g, '');
const translation = englishToFrenchMap[cleanWord] || cleanWord;
frenchText += translation + punctuation;
if (index < words.length - 1) frenchText += ' ';
});
frenchInput.value = frenchText;
translationResult.innerHTML = `
⚠️ Translation / Traduction (Dictionary): ${frenchText}
API translation unavailable, using local dictionary. / Traduction API indisponible, utilisation du dictionnaire local.
`;
// Auto-generate fonts with the translated text
setTimeout(() => {
generateFrenchFonts();
}, 500);
}
// Generate French fonts function
function generateFrenchFonts() {
const textInput = document.getElementById('frenchTextInput');
const resultsSection = document.getElementById('frenchResultsSection');
const fontResults = document.getElementById('frenchFontResults');
if (!textInput || !resultsSection || !fontResults) {
console.error('Required elements not found');
alert('Error: Required elements not found. Please refresh the page.');
return;
}
const inputText = textInput.value.trim();
if (!inputText) {
alert('Veuillez entrer du texte français pour générer les polices ! / Please enter French text to generate fonts!');
textInput.focus();
return;
}
console.log('Generating fonts for text:', inputText);
let resultsHTML = '';
Object.entries(frenchFontStyles).forEach(([fontName, styleObj]) => {
const safeText = inputText.replace(/'/g, "'").replace(/"/g, """);
const customStyle = applyCustomStyles(styleObj.style);
const safeCSSStyle = customStyle.replace(/'/g, "\\'").replace(/"/g, '\\"');
resultsHTML += `
API translation unavailable, using local dictionary. / Traduction API indisponible, utilisation du dictionnaire local.
🎨
${fontName}
${inputText}