Add French translate
Add French translation and localize hardcoded strings :
Changes
1. Translation Files
Created
src/i18n/fr.json
: Contains all French translations for the extension.
Updated
src/i18n/en.json
: Added new keys for terms that were previously hardcoded (e.g., "Force", "Volonté", "Météo", "Locked", "Unlocked").
2. UI Updates
settings.html
: Added "Français" to the language selection dropdown.
3. Code Refactoring
src/systems/rendering/thoughts.js
: Replaced hardcoded strings ("Add Character", "Locked", "Click to edit") with i18n calls.
src/systems/rendering/userStats.js
: Replaced hardcoded tooltips and titles with i18n calls.
src/systems/rendering/infoBox.js
: Localized weather, location, and date widget texts.
src/systems/ui/trackerEditor.js
: Updated the "Reset to Defaults" logic to use localized names for stats (e.g., "Santé", "Force") based on the active language.
This commit is contained in:
@@ -12,6 +12,7 @@ import {
|
||||
$userStatsContainer,
|
||||
FALLBACK_AVATAR_DATA_URI
|
||||
} from '../../core/state.js';
|
||||
import { i18n } from '../../core/i18n.js';
|
||||
import {
|
||||
saveSettings,
|
||||
saveChatData,
|
||||
@@ -273,7 +274,7 @@ export function renderUserStats() {
|
||||
// Check if stats bars section is locked
|
||||
const isStatsLocked = isItemLocked('userStats', 'stats');
|
||||
const lockIcon = isStatsLocked ? '🔒' : '🔓';
|
||||
const lockTitle = isStatsLocked ? 'Locked - AI cannot change stats' : 'Unlocked - AI can change stats';
|
||||
const lockTitle = isStatsLocked ? i18n.getTranslation('userStats.statsLocked') : i18n.getTranslation('userStats.statsUnlocked');
|
||||
const lockedClass = isStatsLocked ? ' locked' : '';
|
||||
|
||||
let html = '<div class="rpg-stats-content">';
|
||||
@@ -286,8 +287,8 @@ export function renderUserStats() {
|
||||
<img src="${userPortrait}" alt="${userName}" class="rpg-user-portrait" onerror="this.style.opacity='0.5';this.onerror=null;" />
|
||||
<span class="rpg-user-name">${userName}</span>
|
||||
${showLevel ? `<span style="opacity: 0.5;">|</span>
|
||||
<span class="rpg-level-label">LVL</span>
|
||||
<span class="rpg-level-value rpg-editable" contenteditable="true" data-field="level" title="Click to edit level">${extensionSettings.level}</span>` : ''}
|
||||
<span class="rpg-level-label">${i18n.getTranslation('userStats.level')}</span>
|
||||
<span class="rpg-level-value rpg-editable" contenteditable="true" data-field="level" title="${i18n.getTranslation('userStats.clickToEditLevel')}">${extensionSettings.level}</span>` : ''}
|
||||
</div>
|
||||
`;
|
||||
|
||||
@@ -320,11 +321,11 @@ export function renderUserStats() {
|
||||
|
||||
html += `
|
||||
<div class="rpg-stat-row">
|
||||
<span class="rpg-stat-label rpg-editable-stat-name" contenteditable="true" data-field="${stat.id}" title="Click to edit stat name">${stat.name}:</span>
|
||||
<span class="rpg-stat-label rpg-editable-stat-name" contenteditable="true" data-field="${stat.id}" title="${i18n.getTranslation('userStats.clickToEditStatName')}">${stat.name}:</span>
|
||||
<div class="rpg-stat-bar" style="background: ${gradient}">
|
||||
<div class="rpg-stat-fill" style="width: ${100 - percentage}%"></div>
|
||||
</div>
|
||||
<span class="rpg-stat-value rpg-editable-stat" contenteditable="true" data-field="${stat.id}" data-max="${maxValue}" data-mode="${displayMode}" title="Click to edit">${displayValue}</span>
|
||||
<span class="rpg-stat-value rpg-editable-stat" contenteditable="true" data-field="${stat.id}" data-max="${maxValue}" data-mode="${displayMode}" title="${i18n.getTranslation('userStats.clickToEditStatValue')}">${displayValue}</span>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
@@ -334,7 +335,7 @@ export function renderUserStats() {
|
||||
if (config.statusSection.enabled) {
|
||||
const isMoodLocked = isItemLocked('userStats', 'status');
|
||||
const moodLockIcon = isMoodLocked ? '🔒' : '🔓';
|
||||
const moodLockTitle = isMoodLocked ? 'Locked - AI cannot change mood' : 'Unlocked - AI can change mood';
|
||||
const moodLockTitle = isMoodLocked ? i18n.getTranslation('userStats.moodLocked') : i18n.getTranslation('userStats.moodUnlocked');
|
||||
const moodLockedClass = isMoodLocked ? ' locked' : '';
|
||||
html += '<div class="rpg-mood">';
|
||||
if (showLockIcons) {
|
||||
@@ -342,7 +343,7 @@ export function renderUserStats() {
|
||||
}
|
||||
|
||||
if (config.statusSection.showMoodEmoji) {
|
||||
html += `<div class="rpg-mood-emoji rpg-editable" contenteditable="true" data-field="mood" title="Click to edit emoji">${stats.mood}</div>`;
|
||||
html += `<div class="rpg-mood-emoji rpg-editable" contenteditable="true" data-field="mood" title="${i18n.getTranslation('userStats.clickToEditEmoji')}">${stats.mood}</div>`;
|
||||
}
|
||||
|
||||
// Render custom status fields
|
||||
@@ -368,7 +369,7 @@ export function renderUserStats() {
|
||||
if (config.skillsSection.enabled) {
|
||||
const isSkillsLocked = isItemLocked('userStats', 'skills');
|
||||
const skillsLockIcon = isSkillsLocked ? '🔒' : '🔓';
|
||||
const skillsLockTitle = isSkillsLocked ? 'Locked - AI cannot change skills' : 'Unlocked - AI can change skills';
|
||||
const skillsLockTitle = isSkillsLocked ? i18n.getTranslation('userStats.skillsLocked') : i18n.getTranslation('userStats.skillsUnlocked');
|
||||
const skillsLockedClass = isSkillsLocked ? ' locked' : '';
|
||||
let skillsValue = 'None';
|
||||
// Handle JSON array format: [{name: "Art"}, {name: "Coding"}]
|
||||
@@ -385,7 +386,7 @@ export function renderUserStats() {
|
||||
}
|
||||
html += `
|
||||
<span class="rpg-skills-label">${config.skillsSection.label}:</span>
|
||||
<div class="rpg-skills-value rpg-editable" contenteditable="true" data-field="skills" title="Click to edit skills">${skillsValue}</div>
|
||||
<div class="rpg-skills-value rpg-editable" contenteditable="true" data-field="skills" title="${i18n.getTranslation('userStats.clickToEditSkills')}">${skillsValue}</div>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
@@ -409,15 +410,15 @@ export function renderUserStats() {
|
||||
const enabledAttributes = rpgAttributes.filter(attr => attr && attr.enabled && attr.name && attr.id);
|
||||
|
||||
if (enabledAttributes.length > 0) {
|
||||
html += `
|
||||
html += `
|
||||
<div class="rpg-stats-right">
|
||||
<div class="rpg-classic-stats">
|
||||
<div class="rpg-classic-stats-grid">
|
||||
`;
|
||||
|
||||
enabledAttributes.forEach(attr => {
|
||||
const value = extensionSettings.classicStats[attr.id] !== undefined ? extensionSettings.classicStats[attr.id] : 10;
|
||||
html += `
|
||||
enabledAttributes.forEach(attr => {
|
||||
const value = extensionSettings.classicStats[attr.id] !== undefined ? extensionSettings.classicStats[attr.id] : 10;
|
||||
html += `
|
||||
<div class="rpg-classic-stat" data-stat="${attr.id}">
|
||||
<span class="rpg-classic-stat-label">${attr.name}</span>
|
||||
<div class="rpg-classic-stat-buttons">
|
||||
@@ -427,9 +428,9 @@ export function renderUserStats() {
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
});
|
||||
});
|
||||
|
||||
html += `
|
||||
html += `
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -448,7 +449,7 @@ export function renderUserStats() {
|
||||
// console.log('[RPG UserStats Render] ✓ HTML rendered to #rpg-user-stats container');
|
||||
|
||||
// Add event listeners for editable stat values
|
||||
$('.rpg-editable-stat').on('blur', function() {
|
||||
$('.rpg-editable-stat').on('blur', function () {
|
||||
const field = $(this).data('field');
|
||||
const mode = $(this).data('mode');
|
||||
const maxValue = parseInt($(this).data('max')) || 100;
|
||||
@@ -492,7 +493,7 @@ export function renderUserStats() {
|
||||
});
|
||||
|
||||
// Add event listeners for mood/conditions editing
|
||||
$('.rpg-mood-emoji.rpg-editable').on('blur', function() {
|
||||
$('.rpg-mood-emoji.rpg-editable').on('blur', function () {
|
||||
const value = $(this).text().trim();
|
||||
extensionSettings.userStats.mood = value || '😐';
|
||||
|
||||
@@ -504,7 +505,7 @@ export function renderUserStats() {
|
||||
updateMessageSwipeData();
|
||||
});
|
||||
|
||||
$('.rpg-mood-conditions.rpg-editable').on('blur', function() {
|
||||
$('.rpg-mood-conditions.rpg-editable').on('blur', function () {
|
||||
const value = $(this).text().trim();
|
||||
const fieldKey = $(this).data('field');
|
||||
extensionSettings.userStats[fieldKey] = value || 'None';
|
||||
@@ -518,7 +519,7 @@ export function renderUserStats() {
|
||||
});
|
||||
|
||||
// Add event listener for skills editing
|
||||
$('.rpg-skills-value.rpg-editable').on('blur', function() {
|
||||
$('.rpg-skills-value.rpg-editable').on('blur', function () {
|
||||
const value = $(this).text().trim();
|
||||
extensionSettings.userStats.skills = value || 'None';
|
||||
|
||||
@@ -531,7 +532,7 @@ export function renderUserStats() {
|
||||
});
|
||||
|
||||
// Add event listeners for stat name editing
|
||||
$('.rpg-editable-stat-name').on('blur', function() {
|
||||
$('.rpg-editable-stat-name').on('blur', function () {
|
||||
const field = $(this).data('field');
|
||||
const value = $(this).text().trim().replace(':', '');
|
||||
|
||||
@@ -555,7 +556,7 @@ export function renderUserStats() {
|
||||
});
|
||||
|
||||
// Add event listener for level editing
|
||||
$('.rpg-level-value.rpg-editable').on('blur', function() {
|
||||
$('.rpg-level-value.rpg-editable').on('blur', function () {
|
||||
let value = parseInt($(this).text().trim());
|
||||
if (isNaN(value) || value < 1) {
|
||||
value = 1;
|
||||
@@ -573,15 +574,15 @@ export function renderUserStats() {
|
||||
});
|
||||
|
||||
// Prevent line breaks in level field
|
||||
$('.rpg-level-value.rpg-editable').on('keydown', function(e) {
|
||||
$('.rpg-level-value.rpg-editable').on('keydown', function (e) {
|
||||
if (e.key === 'Enter') {
|
||||
e.preventDefault();
|
||||
$(this).blur();
|
||||
}
|
||||
});
|
||||
|
||||
// Add event listener for section lock icon clicks (support both click and touch)
|
||||
$('.rpg-section-lock-icon').on('click touchend', function(e) {
|
||||
// Add event listener for section lock icon clicks (support both click and touch)
|
||||
$('.rpg-section-lock-icon').on('click touchend', function (e) {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
const $icon = $(this);
|
||||
@@ -594,7 +595,7 @@ export function renderUserStats() {
|
||||
|
||||
// Update icon
|
||||
const newIcon = !currentlyLocked ? '🔒' : '🔓';
|
||||
const newTitle = !currentlyLocked ? 'Locked - AI cannot change this section' : 'Unlocked - AI can change this section';
|
||||
const newTitle = !currentlyLocked ? i18n.getTranslation('infoBox.locked') : i18n.getTranslation('infoBox.unlocked');
|
||||
$icon.text(newIcon);
|
||||
$icon.attr('title', newTitle);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user