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:
+14
-6
@@ -16,26 +16,33 @@
|
|||||||
<option value="en" data-i18n-key="settings.language.option.en">English</option>
|
<option value="en" data-i18n-key="settings.language.option.en">English</option>
|
||||||
<option value="zh-tw" data-i18n-key="settings.language.option.zh-tw">繁體中文</option>
|
<option value="zh-tw" data-i18n-key="settings.language.option.zh-tw">繁體中文</option>
|
||||||
<option value="ru" data-i18n-key="settings.language.option.ru">Русский</option>
|
<option value="ru" data-i18n-key="settings.language.option.ru">Русский</option>
|
||||||
|
<option value="fr" data-i18n-key="settings.language.option.fr">Français</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<small class="notes" data-i18n-key="settings.note">Toggle to enable/disable the RPG Companion extension. Configure additional settings within the panel itself.</small>
|
<small class="notes" data-i18n-key="settings.note">Toggle to enable/disable the RPG Companion extension.
|
||||||
|
Configure additional settings within the panel itself.</small>
|
||||||
|
|
||||||
<div style="margin-top: 10px; display: flex; gap: 10px;">
|
<div style="margin-top: 10px; display: flex; gap: 10px;">
|
||||||
<a href="https://discord.com/invite/KdAkTg94ME" target="_blank" class="menu_button" style="flex: 1; text-align: center; text-decoration: none;">
|
<a href="https://discord.com/invite/KdAkTg94ME" target="_blank" class="menu_button"
|
||||||
|
style="flex: 1; text-align: center; text-decoration: none;">
|
||||||
<i class="fa-brands fa-discord"></i> Discord
|
<i class="fa-brands fa-discord"></i> Discord
|
||||||
</a>
|
</a>
|
||||||
<a href="https://ko-fi.com/marinara_spaghetti" target="_blank" class="menu_button" style="flex: 1; text-align: center; text-decoration: none;">
|
<a href="https://ko-fi.com/marinara_spaghetti" target="_blank" class="menu_button"
|
||||||
|
style="flex: 1; text-align: center; text-decoration: none;">
|
||||||
<i class="fa-solid fa-heart"></i> Support
|
<i class="fa-solid fa-heart"></i> Support
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div style="margin-top: 15px; text-align: center; opacity: 0.7; font-size: 0.8em; line-height: 1.5;">
|
<div style="margin-top: 15px; text-align: center; opacity: 0.7; font-size: 0.8em; line-height: 1.5;">
|
||||||
<div style="margin-bottom: 5px;">
|
<div style="margin-bottom: 5px;">
|
||||||
<i class="fa-solid fa-microchip"></i> <strong data-i18n="settings.recommendedModels.title">Recommended Models:</strong>
|
<i class="fa-solid fa-microchip"></i> <strong
|
||||||
|
data-i18n="settings.recommendedModels.title">Recommended Models:</strong>
|
||||||
</div>
|
</div>
|
||||||
<div style="opacity: 0.8; font-size: 0.9em;" data-i18n="settings.recommendedModels.description">
|
<div style="opacity: 0.8; font-size: 0.9em;" data-i18n="settings.recommendedModels.description">
|
||||||
For the extension to work properly, <strong>it is not recommended to use any models below 20B, especially if they're old.</strong> It works best with the SOTA models such as Deepseek, Claude, GPT, or Gemini.
|
For the extension to work properly, <strong>it is not recommended to use any models below 20B,
|
||||||
|
especially if they're old.</strong> It works best with the SOTA models such as Deepseek, Claude,
|
||||||
|
GPT, or Gemini.
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -44,7 +51,8 @@
|
|||||||
<i class="fa-solid fa-users"></i> <strong>Contributors:</strong>
|
<i class="fa-solid fa-users"></i> <strong>Contributors:</strong>
|
||||||
</div>
|
</div>
|
||||||
<div style="opacity: 0.8; font-size: 0.9em;">
|
<div style="opacity: 0.8; font-size: 0.9em;">
|
||||||
SpicyMarinara, Paperboygold, Munimunigamer, Subarashimo, Lilminzyu, Claude, IDeathByte, Chungchandev, Joenunezb, Amauragis, Tomt610, and Jakstein.
|
SpicyMarinara, Paperboygold, Munimunigamer, Subarashimo, Lilminzyu, Claude, IDeathByte,
|
||||||
|
Chungchandev, Joenunezb, Amauragis, Tomt610, and Jakstein.
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
+35
-1
@@ -238,5 +238,39 @@
|
|||||||
"musicPlayer.noMusic": "AI will suggest music when appropriate for the scene",
|
"musicPlayer.noMusic": "AI will suggest music when appropriate for the scene",
|
||||||
"errors.parsingError": "RPG Companion Trackers' parsing error! The model returned an incorrect format. If the issue persists, consider changing the model for generations.",
|
"errors.parsingError": "RPG Companion Trackers' parsing error! The model returned an incorrect format. If the issue persists, consider changing the model for generations.",
|
||||||
"settings.recommendedModels.title": "Recommended Models",
|
"settings.recommendedModels.title": "Recommended Models",
|
||||||
"settings.recommendedModels.description": "For the extension to work properly, **it is not recommended to use any models below 20B, especially if they're old.** It works best with the SOTA models such as Deepseek, Claude, GPT, or Gemini."
|
"settings.recommendedModels.description": "For the extension to work properly, **it is not recommended to use any models below 20B, especially if they're old.** It works best with the SOTA models such as Deepseek, Claude, GPT, or Gemini.",
|
||||||
|
"thoughts.addCharacter": "Add Character",
|
||||||
|
"thoughts.locked": "Locked",
|
||||||
|
"thoughts.unlocked": "Unlocked",
|
||||||
|
"thoughts.clickToEdit": "Click to edit",
|
||||||
|
"thoughts.clickToUpload": "Click to upload avatar",
|
||||||
|
"thoughts.removeCharacter": "Remove character",
|
||||||
|
"userStats.level": "LVL",
|
||||||
|
"userStats.clickToEditLevel": "Click to edit level",
|
||||||
|
"userStats.statsLocked": "Locked - AI cannot change stats",
|
||||||
|
"userStats.statsUnlocked": "Unlocked - AI can change stats",
|
||||||
|
"userStats.clickToEditStatName": "Click to edit stat name",
|
||||||
|
"userStats.clickToEditStatValue": "Click to edit",
|
||||||
|
"userStats.moodLocked": "Locked - AI cannot change mood",
|
||||||
|
"userStats.moodUnlocked": "Unlocked - AI can change mood",
|
||||||
|
"userStats.clickToEditEmoji": "Click to edit emoji",
|
||||||
|
"userStats.skillsLocked": "Locked - AI cannot change skills",
|
||||||
|
"userStats.skillsUnlocked": "Unlocked - AI can change skills",
|
||||||
|
"userStats.clickToEditSkills": "Click to edit skills",
|
||||||
|
"infoBox.clickToEdit": "Click to edit",
|
||||||
|
"infoBox.locked": "Locked - AI cannot change this",
|
||||||
|
"infoBox.unlocked": "Unlocked - AI can change this",
|
||||||
|
"infoBox.weatherFallback": "Weather",
|
||||||
|
"infoBox.locationFallback": "Location",
|
||||||
|
"stats.health": "Health",
|
||||||
|
"stats.satiety": "Satiety",
|
||||||
|
"stats.energy": "Energy",
|
||||||
|
"stats.hygiene": "Hygiene",
|
||||||
|
"stats.arousal": "Arousal",
|
||||||
|
"stats.str": "STR",
|
||||||
|
"stats.dex": "DEX",
|
||||||
|
"stats.con": "CON",
|
||||||
|
"stats.int": "INT",
|
||||||
|
"stats.wis": "WIS",
|
||||||
|
"stats.cha": "CHA"
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,277 @@
|
|||||||
|
{
|
||||||
|
"settings.language.label": "Langue",
|
||||||
|
"settings.language.option.en": "English",
|
||||||
|
"settings.language.option.zh-tw": "繁體中文",
|
||||||
|
"settings.language.option.ru": "Русский",
|
||||||
|
"settings.language.option.fr": "Français",
|
||||||
|
"settings.extensionEnabled": "Activer RPG Companion",
|
||||||
|
"settings.note": "Basculez pour activer/désactiver l'extension RPG Companion. Configurez des paramètres supplémentaires dans le panneau lui-même.",
|
||||||
|
"template.settingsTitle": "Paramètres RPG Companion",
|
||||||
|
"template.settingsModal.themeTitle": "Thème",
|
||||||
|
"template.settingsModal.themeLabel": "Thème Visuel :",
|
||||||
|
"template.settingsModal.themeOptions.default": "Défaut",
|
||||||
|
"template.settingsModal.themeOptions.sciFi": "Sci-Fi (Synthwave)",
|
||||||
|
"template.settingsModal.themeOptions.fantasy": "Fantasy (Parchemin Rustique)",
|
||||||
|
"template.settingsModal.themeOptions.cyberpunk": "Cyberpunk (Grille Néon)",
|
||||||
|
"template.settingsModal.themeOptions.custom": "Personnalisé",
|
||||||
|
"template.settingsModal.themeOptions.custom.background": "Arrière-plan :",
|
||||||
|
"template.settingsModal.themeOptions.custom.accent": "Accent :",
|
||||||
|
"template.settingsModal.themeOptions.custom.text": "Texte :",
|
||||||
|
"template.settingsModal.themeOptions.custom.highlight": "Surlignage :",
|
||||||
|
"template.settingsModal.theme.statBarLow": "Couleur Barre Stat (Bas) :",
|
||||||
|
"template.settingsModal.theme.statBarLowNote": "Couleur lorsque les stats sont à 0%.",
|
||||||
|
"template.settingsModal.theme.statBarHigh": "Couleur Barre Stat (Haut) :",
|
||||||
|
"template.settingsModal.theme.statBarHighNote": "Couleur lorsque les stats sont à 100%.",
|
||||||
|
"template.settingsModal.displayTitle": "Options d'Affichage",
|
||||||
|
"template.settingsModal.displayNote": "Vous pouvez activer/désactiver l'extension complète RPG Companion dans l'onglet Extensions de SillyTavern.",
|
||||||
|
"template.settingsModal.display.panelPosition": "Position du Panneau :",
|
||||||
|
"template.settingsModal.display.panelPositionOptions.right": "Barre Latérale Droite",
|
||||||
|
"template.settingsModal.display.panelPositionOptions.left": "Barre Latérale Gauche",
|
||||||
|
"template.settingsModal.display.toggleAutoUpdate": "Mise à jour auto après messages",
|
||||||
|
"template.settingsModal.display.toggleAutoUpdateNote": "Rafraîchir automatiquement les infos RPG après chaque message.",
|
||||||
|
"template.settingsModal.display.showUserStats": "Afficher Stats Utilisateur",
|
||||||
|
"template.settingsModal.display.showUserStatsNote": "Activer les Stats Utilisateur pour suivre les statistiques, l'humeur, les attributs, les compétences, etc. de votre persona.",
|
||||||
|
"template.settingsModal.display.showInfoBox": "Afficher Boîte Info",
|
||||||
|
"template.settingsModal.display.showInfoBoxNote": "Afficher le lieu, l'heure, la météo et les événements récents.",
|
||||||
|
"template.settingsModal.display.showPresentCharacters": "Afficher Personnages Présents",
|
||||||
|
"template.settingsModal.display.showPresentCharactersNote": "Afficher les portraits des personnages avec leurs pensées actuelles et leur statut.",
|
||||||
|
"template.settingsModal.display.narratorMode": "Mode Narrateur",
|
||||||
|
"template.settingsModal.display.narratorModeNote": "Utiliser la carte de personnage comme narrateur. Déduire les personnages du contexte au lieu d'utiliser des références de personnages fixes.",
|
||||||
|
"template.settingsModal.display.showInventory": "Afficher Inventaire",
|
||||||
|
"template.settingsModal.display.showInventoryNote": "Suivre les objets transportés, les vêtements portés, les objets stockés et les biens.",
|
||||||
|
"template.settingsModal.display.showQuests": "Afficher Quêtes",
|
||||||
|
"template.settingsModal.display.showQuestsNote": "Gérer les quêtes principales et optionnelles avec des objectifs.",
|
||||||
|
"template.settingsModal.display.showLockIcons": "Afficher Icônes Verrouillage",
|
||||||
|
"template.settingsModal.display.showLockIconsNote": "Afficher les icônes de verrouillage/déverrouillage sur les éléments de suivi pour empêcher l'IA de les modifier.",
|
||||||
|
"template.settingsModal.display.showThoughtsInChat": "Afficher Pensées",
|
||||||
|
"template.settingsModal.display.showThoughtsInChatNote": "Afficher les pensées des personnages sous forme de bulles superposées à côté de leurs messages.",
|
||||||
|
"template.settingsModal.display.alwaysShowThoughtBubble": "Toujours Afficher Bulle Pensée",
|
||||||
|
"template.settingsModal.display.alwaysShowThoughtBubbleNote": "Développer automatiquement la bulle de pensée sans cliquer sur l'icône d'abord",
|
||||||
|
"template.settingsModal.display.enableAnimations": "Activer Animations",
|
||||||
|
"template.settingsModal.display.enableAnimationsNote": "Transitions fluides pour les stats, les mises à jour de contenu et les lancers de dés.",
|
||||||
|
"template.settingsModal.display.showImmersiveHtmlToggle": "Afficher HTML Immersif",
|
||||||
|
"template.settingsModal.display.showImmersiveHtmlToggleNote": "Afficher un bouton pour activer/désactiver le formatage HTML dans les messages.",
|
||||||
|
"template.settingsModal.display.showDialogueColoringToggle": "Afficher Dialogues Colorés",
|
||||||
|
"template.settingsModal.display.showDialogueColoringToggleNote": "Afficher un bouton pour activer/désactiver le formatage des dialogues colorés.",
|
||||||
|
"template.settingsModal.display.showDeceptionToggle": "Afficher Système Déception",
|
||||||
|
"template.settingsModal.display.showDeceptionToggleNote": "Afficher un bouton pour activer/désactiver le Système de Déception pour marquer les mensonges.",
|
||||||
|
"template.settingsModal.display.showOmniscienceToggle": "Afficher Filtre Omniscience",
|
||||||
|
"template.settingsModal.display.showOmniscienceToggleNote": "Afficher un bouton pour activer/désactiver le Filtre d'Omniscience pour filtrer les événements cachés.",
|
||||||
|
"template.settingsModal.display.showSpotifyMusicToggle": "Afficher Musique Spotify",
|
||||||
|
"template.settingsModal.display.showSpotifyMusicToggleNote": "Afficher le lecteur Spotify avec des pistes suggérées par l'IA appropriées à la scène.",
|
||||||
|
"template.settingsModal.display.showSnowflakesToggle": "Afficher Effet Flocons",
|
||||||
|
"template.settingsModal.display.showDynamicWeatherToggle": "Afficher Effets Météo Dynamiques",
|
||||||
|
"template.settingsModal.display.showDynamicWeatherToggleNote": "Afficher un bouton pour activer/désactiver les effets météo animés.",
|
||||||
|
"template.settingsModal.display.showNarratorMode": "Afficher Mode Narrateur",
|
||||||
|
"template.settingsModal.display.showNarratorModeNote": "Afficher un bouton pour activer/désactiver le mode narrateur (déduire les personnages du contexte).",
|
||||||
|
"template.settingsModal.display.showAutoAvatars": "Afficher Génération Auto Avatars",
|
||||||
|
"template.settingsModal.display.showAutoAvatarsNote": "Afficher un bouton pour générer automatiquement des avatars pour les personnages sans image.",
|
||||||
|
"template.settingsModal.display.showRandomizedPlot": "Afficher Progression Intrigue Aléatoire",
|
||||||
|
"template.settingsModal.display.showRandomizedPlotNote": "Afficher un bouton pour des invites de progression d'intrigue générées aléatoirement par l'IA.",
|
||||||
|
"template.settingsModal.display.showNaturalPlot": "Afficher Progression Intrigue Naturelle",
|
||||||
|
"template.settingsModal.display.showNaturalPlotNote": "Afficher un bouton pour des invites de continuation narrative conscientes du contexte.",
|
||||||
|
"template.settingsModal.display.showStartEncounter": "Afficher Démarrer Rencontre",
|
||||||
|
"template.settingsModal.display.showStartEncounterNote": "Afficher un bouton pour initier des rencontres de combat interactives.",
|
||||||
|
"template.settingsModal.display.showDiceDisplay": "Afficher Lancer de Dés",
|
||||||
|
"template.settingsModal.display.showDiceDisplayNote": "Afficher l'indicateur \"Dernier Lancer\" dans le panneau.",
|
||||||
|
"template.mainPanel.autoAvatars": "Avatars Auto",
|
||||||
|
"template.settingsModal.advancedTitle": "Avancé",
|
||||||
|
"template.settingsModal.advanced.encounterHistoryDepth": "Profondeur Historique Rencontre :",
|
||||||
|
"template.settingsModal.advanced.encounterHistoryDepthNote": "Nombre de messages récents à inclure dans l'initialisation du combat.",
|
||||||
|
"template.settingsModal.advanced.autoSaveCombatLogs": "Sauvegarde Auto Journaux Combat",
|
||||||
|
"template.settingsModal.advanced.autoSaveCombatLogsNote": "Sauvegarder les journaux de combat détaillés dans un fichier pour référence future et analyse.",
|
||||||
|
"template.settingsModal.advanced.clearCacheNote": "Efface les données de suivi validées et affichées pour votre chat actuellement actif.",
|
||||||
|
"template.settingsModal.advanced.generationMode": "Mode de Génération :",
|
||||||
|
"template.settingsModal.advanced.generationModeOptions.together": "Ensemble avec Génération Principale",
|
||||||
|
"template.settingsModal.advanced.generationModeOptions.separate": "Génération Séparée",
|
||||||
|
"template.settingsModal.advanced.generationModeNote": "Ensemble : Ajoute le suivi RPG au jeu de rôle principal. Séparé : Génère les données RPG séparément (manuel ou auto). Externe : Se connecte directement à un point de terminaison compatible OpenAI.",
|
||||||
|
"template.settingsModal.advanced.generationModeOptions.external": "API Externe",
|
||||||
|
"template.settingsModal.advanced.externalApi.title": "Paramètres API Externe",
|
||||||
|
"template.settingsModal.advanced.externalApi.baseUrl": "URL de base API",
|
||||||
|
"template.settingsModal.advanced.externalApi.baseUrlNote": "Point de terminaison compatible OpenAI (ex: OpenAI, OpenRouter, serveur LLM local).",
|
||||||
|
"template.settingsModal.advanced.externalApi.apiKey": "Clé API",
|
||||||
|
"template.settingsModal.advanced.externalApi.apiKeyNote": "Votre clé API pour le service externe.",
|
||||||
|
"template.settingsModal.advanced.externalApi.model": "Modèle",
|
||||||
|
"template.settingsModal.advanced.externalApi.modelNote": "Identifiant du modèle (ex: gpt-4o-mini, claude-3-haiku, mistral-7b).",
|
||||||
|
"template.settingsModal.advanced.externalApi.maxTokens": "Max Tokens",
|
||||||
|
"template.settingsModal.advanced.externalApi.temperature": "Température",
|
||||||
|
"template.settingsModal.advanced.externalApi.testConnection": "Tester Connexion",
|
||||||
|
"template.settingsModal.advanced.contextMessages": "Messages de Contexte :",
|
||||||
|
"template.settingsModal.advanced.contextMessagesNote": "Nombre de messages récents à inclure.",
|
||||||
|
"template.settingsModal.advanced.useSeparatePreset": "Utiliser modèle connecté au preset RPG Companion Trackers",
|
||||||
|
"template.settingsModal.advanced.useSeparatePresetNote": "Si activé, la génération de suivi utilisera le modèle du preset \"RPG Companion Trackers\" au lieu de votre modèle API principal. Le preset sera commuté automatiquement pendant la génération et restauré après. Sélectionnez le modèle souhaité dans ce preset et assurez-vous que l'option \"Lier les presets aux connexions API\" est activée (à côté des boutons import/export preset).",
|
||||||
|
"template.settingsModal.advanced.skipInjections": "Sauter Injections Pendant Générations Guidées :",
|
||||||
|
"template.settingsModal.advanced.skipInjectionsOptions.none": "Ne jamais sauter",
|
||||||
|
"template.settingsModal.advanced.skipInjectionsOptions.impersonation": "Seulement sur demandes d'imitation",
|
||||||
|
"template.settingsModal.advanced.skipInjectionsOptions.guided": "Toujours pour invites guidées ou silencieuses",
|
||||||
|
"template.settingsModal.advanced.skipInjectionsNote": "Si défini, l'extension n'injectera pas les invites de suivi, exemples ou instructions HTML selon le mode sélectionné lorsqu'une génération guidée (via `instruct` ou `quiet_prompt`) est détectée. Utile lors de l'utilisation de GuidedGenerations ou extensions similaires.",
|
||||||
|
"template.settingsModal.advanced.customHtmlPromptTitle": "Invite HTML Personnalisée :",
|
||||||
|
"template.settingsModal.advanced.restoreDefaultHtmlPrompt": "Restaurer Défaut",
|
||||||
|
"template.settingsModal.advanced.customHtmlPromptNote": "Personnalisez l'invite HTML injectée lorsque \"Activer HTML Immersif\" est activé. L'invite par défaut est affichée ci-dessus - vous pouvez l'éditer directement ou la remplacer entièrement. Cliquez sur \"Restaurer Défaut\" pour réinitialiser. Cela affecte tous les modes de génération (ensemble, séparé et progression d'intrigue).",
|
||||||
|
"template.settingsModal.advanced.clearCache": "Effacer Cache Extension",
|
||||||
|
"template.settingsModal.advanced.resetFabPositions": "Réinitialiser Positions Boutons",
|
||||||
|
"template.settingsModal.advanced.resetFabPositionsNote": "Réinitialise tous les boutons d'action flottants (bascule, rafraîchir, debug) à leurs positions par défaut en haut à gauche. Utile si les boutons sont hors écran.",
|
||||||
|
"template.trackerEditorModal.title": "Éditer Suivis",
|
||||||
|
"template.trackerEditorModal.tabs.userStats": "Stats Utilisateur",
|
||||||
|
"template.trackerEditorModal.tabs.infoBox": "Boîte Info",
|
||||||
|
"template.trackerEditorModal.tabs.presentCharacters": "Personnages Présents",
|
||||||
|
"template.trackerEditorModal.buttons.reset": "Réinitialiser",
|
||||||
|
"template.trackerEditorModal.buttons.cancel": "Annuler",
|
||||||
|
"template.trackerEditorModal.buttons.save": "Sauvegarder & Appliquer",
|
||||||
|
"template.trackerEditorModal.buttons.export": "Exporter",
|
||||||
|
"template.trackerEditorModal.buttons.import": "Importer",
|
||||||
|
"template.trackerEditorModal.messages.exportSuccess": "Preset de suivi exporté avec succès !",
|
||||||
|
"template.trackerEditorModal.messages.exportError": "Échec de l'exportation du preset. Vérifiez la console pour les détails.",
|
||||||
|
"template.trackerEditorModal.messages.importSuccess": "Preset de suivi importé avec succès !",
|
||||||
|
"template.trackerEditorModal.messages.importError": "Échec de l'importation du preset",
|
||||||
|
"template.trackerEditorModal.messages.importConfirm": "Ceci remplacera votre configuration actuelle de suivi. Continuer ?",
|
||||||
|
"template.trackerEditorModal.userStatsTab.customStatsTitle": "Stats Personnalisées",
|
||||||
|
"template.trackerEditorModal.userStatsTab.addCustomStatButton": "Ajouter Stat Perso",
|
||||||
|
"template.trackerEditorModal.userStatsTab.rpgAttributesTitle": "Attributs RPG",
|
||||||
|
"template.trackerEditorModal.userStatsTab.enableRpgAttributes": "Activer Section Attributs RPG",
|
||||||
|
"template.trackerEditorModal.userStatsTab.alwaysIncludeAttributes": "Toujours Inclure Attributs dans Invite",
|
||||||
|
"template.trackerEditorModal.userStatsTab.alwaysIncludeAttributesNote": "Si désactivé, les attributs ne sont envoyés que lorsqu'un lancer de dé est actif.",
|
||||||
|
"template.trackerEditorModal.userStatsTab.addAttributeButton": "Ajouter Attribut",
|
||||||
|
"template.trackerEditorModal.userStatsTab.statusSectionTitle": "Section Statut",
|
||||||
|
"template.trackerEditorModal.userStatsTab.enableStatusSection": "Activer Section Statut",
|
||||||
|
"template.trackerEditorModal.userStatsTab.showMoodEmoji": "Afficher Emoji Humeur",
|
||||||
|
"template.trackerEditorModal.userStatsTab.statusFieldsLabel": "Champs Statut (séparés par virgule) :",
|
||||||
|
"template.trackerEditorModal.userStatsTab.skillsSectionTitle": "Section Compétences",
|
||||||
|
"template.trackerEditorModal.userStatsTab.enableSkillsSection": "Activer Section Compétences",
|
||||||
|
"template.trackerEditorModal.userStatsTab.skillsLabelLabel": "Libellé Compétences :",
|
||||||
|
"template.trackerEditorModal.userStatsTab.skillsListLabel": "Liste Compétences (séparées par virgule) :",
|
||||||
|
"template.trackerEditorModal.infoBoxTab.widgetsTitle": "Widgets",
|
||||||
|
"template.trackerEditorModal.infoBoxTab.dateWidget": "Date",
|
||||||
|
"template.trackerEditorModal.infoBoxTab.weatherWidget": "Météo",
|
||||||
|
"template.trackerEditorModal.infoBoxTab.temperatureWidget": "Température",
|
||||||
|
"template.trackerEditorModal.infoBoxTab.timeWidget": "Heure",
|
||||||
|
"template.trackerEditorModal.infoBoxTab.locationWidget": "Lieu",
|
||||||
|
"template.trackerEditorModal.infoBoxTab.recentEventsWidget": "Événements Récents",
|
||||||
|
"template.trackerEditorModal.presentCharactersTab.relationshipStatusTitle": "Champs Statut Relation",
|
||||||
|
"template.trackerEditorModal.presentCharactersTab.enableRelationshipStatus": "Activer Champs Statut Relation",
|
||||||
|
"template.trackerEditorModal.presentCharactersTab.relationshipStatusHint": "Définir les types de relation avec les emojis correspondants affichés sur les portraits des personnages.",
|
||||||
|
"template.trackerEditorModal.presentCharactersTab.newRelationshipButton": "Nouvelle Relation",
|
||||||
|
"template.trackerEditorModal.presentCharactersTab.appearanceDemeanorTitle": "Champs Apparence/Comportement",
|
||||||
|
"template.trackerEditorModal.presentCharactersTab.appearanceDemeanorHint": "Champs affichés sous le nom du personnage.",
|
||||||
|
"template.trackerEditorModal.presentCharactersTab.addCustomFieldButton": "Ajouter Champ Perso",
|
||||||
|
"template.trackerEditorModal.presentCharactersTab.thoughtsConfigTitle": "Configuration Pensées",
|
||||||
|
"template.trackerEditorModal.presentCharactersTab.enableCharacterThoughts": "Activer Pensées Personnage",
|
||||||
|
"template.trackerEditorModal.presentCharactersTab.thoughtsLabelLabel": "Libellé Pensées :",
|
||||||
|
"template.trackerEditorModal.presentCharactersTab.aiInstructionLabel": "Instruction IA :",
|
||||||
|
"template.trackerEditorModal.presentCharactersTab.characterStatsTitle": "Stats Personnage",
|
||||||
|
"template.trackerEditorModal.presentCharactersTab.trackCharacterStats": "Suivre Stats Personnage",
|
||||||
|
"template.trackerEditorModal.presentCharactersTab.characterStatsHint": "Créer des stats à suivre pour chaque personnage (affichées comme nombres colorés).",
|
||||||
|
"template.trackerEditorModal.presentCharactersTab.addCharacterStatButton": "Ajouter Stat Personnage",
|
||||||
|
"template.mainPanel.title": "RPG Companion",
|
||||||
|
"template.mainPanel.lastRoll": "Dernier Lancer :",
|
||||||
|
"template.mainPanel.clearLastRoll": "Effacer dernier lancer",
|
||||||
|
"template.mainPanel.immersiveHtml": "HTML Immersif",
|
||||||
|
"template.mainPanel.coloredDialogues": "Dialogues Colorés",
|
||||||
|
"template.mainPanel.deceptionSystem": "Système Déception",
|
||||||
|
"template.mainPanel.omniscienceFilter": "Filtre Omniscience",
|
||||||
|
"template.mainPanel.spotifyMusic": "Musique Spotify",
|
||||||
|
"template.mainPanel.snowflakesEffect": "Effet Flocons",
|
||||||
|
"template.mainPanel.dynamicWeatherEffects": "Météo Dynamique",
|
||||||
|
"template.mainPanel.narratorMode": "Mode Narrateur",
|
||||||
|
"template.mainPanel.refreshRpgInfo": "Rafraîchir Infos RPG",
|
||||||
|
"template.mainPanel.updating": "Mise à jour...",
|
||||||
|
"template.mainPanel.editTrackersButton": "Éditer Suivis",
|
||||||
|
"template.mainPanel.settingsButton": "Paramètres",
|
||||||
|
"global.none": "Aucun",
|
||||||
|
"global.add": "Ajouter",
|
||||||
|
"global.cancel": "Annuler",
|
||||||
|
"global.listView": "Vue liste",
|
||||||
|
"global.gridView": "Vue grille",
|
||||||
|
"global.save": "Sauvegarder",
|
||||||
|
"global.status": "Statut",
|
||||||
|
"global.inventory": "Inventaire",
|
||||||
|
"global.quests": "Quêtes",
|
||||||
|
"global.info": "Info",
|
||||||
|
"infobox.noData.title": "Pas de données",
|
||||||
|
"infobox.noData.instruction": "Générez une nouvelle réponse dans le jeu de rôle ou basculez vers \"Génération Séparée\" dans les Paramètres pour accéder et cliquer sur le bouton \"Rafraîchir Infos RPG\"",
|
||||||
|
"infobox.recentEvents.title": "Événements Récents",
|
||||||
|
"infobox.recentEvents.addEventPlaceholder": "Ajouter événement...",
|
||||||
|
"inventory.section.onPerson": "Sur Soi",
|
||||||
|
"inventory.section.clothing": "Vêtements",
|
||||||
|
"inventory.section.stored": "Stocké",
|
||||||
|
"inventory.section.assets": "Biens",
|
||||||
|
"inventory.onPerson.empty": "Aucun objet porté",
|
||||||
|
"inventory.onPerson.title": "Objets Actuellement Portés",
|
||||||
|
"inventory.onPerson.addItemButton": "Ajouter Objet",
|
||||||
|
"inventory.onPerson.addItemPlaceholder": "Entrer nom objet...",
|
||||||
|
"inventory.clothing.empty": "Ne porte rien",
|
||||||
|
"inventory.clothing.title": "Vêtements & Armure",
|
||||||
|
"inventory.clothing.addItemButton": "Ajouter Vêtement",
|
||||||
|
"inventory.clothing.addItemPlaceholder": "Entrer vêtement...",
|
||||||
|
"inventory.stored.title": "Lieux de Stockage",
|
||||||
|
"inventory.stored.addLocationButton": "Ajouter Lieu",
|
||||||
|
"inventory.stored.addLocationPlaceholder": "Entrer nom lieu...",
|
||||||
|
"inventory.stored.saveButton": "Sauvegarder",
|
||||||
|
"inventory.stored.empty": "Aucun lieu de stockage. Cliquez sur \"Ajouter Lieu\" pour en créer un.",
|
||||||
|
"inventory.stored.noItems": "Aucun objet stocké ici",
|
||||||
|
"inventory.stored.addItemToLocationPlaceholder": "Entrer nom objet...",
|
||||||
|
"inventory.stored.addItemButton": "Ajouter Objet",
|
||||||
|
"inventory.stored.confirmRemoveLocationMessage": "Supprimer \"${location}\" ? Cela supprimera tous les objets stockés ici.",
|
||||||
|
"inventory.stored.confirmRemoveLocationConfirmButton": "Confirmer",
|
||||||
|
"inventory.assets.empty": "Aucun bien possédé",
|
||||||
|
"inventory.assets.title": "Véhicules, Propriétés & Possessions Majeures",
|
||||||
|
"inventory.assets.addAssetModalTitle": "Ajouter Bien",
|
||||||
|
"inventory.assets.addAssetButton": "Ajouter Bien",
|
||||||
|
"inventory.assets.addAssetPlaceholder": "Entrer nom bien...",
|
||||||
|
"inventory.assets.description": "Les biens incluent les véhicules (voitures, motos), les propriétés (maisons, appartements) et les équipements majeurs (outils d'atelier, objets spéciaux).",
|
||||||
|
"quests.section.main": "Quête Principale",
|
||||||
|
"quests.section.optional": "Quêtes Optionnelles",
|
||||||
|
"quests.main.title": "Quêtes Principales",
|
||||||
|
"quests.main.addQuestButton": "Ajouter Quête",
|
||||||
|
"quests.main.addQuestPlaceholder": "Entrer titre quête principale...",
|
||||||
|
"quests.main.empty": "Aucune quête principale active",
|
||||||
|
"quests.main.hint": "La quête principale représente votre objectif principal dans l'histoire.",
|
||||||
|
"quests.optional.title": "Quêtes Optionnelles",
|
||||||
|
"quests.optional.addQuestButton": "Ajouter Quête",
|
||||||
|
"quests.optional.addQuestPlaceholder": "Entrer titre quête optionnelle...",
|
||||||
|
"quests.optional.empty": "Aucune quête optionnelle active",
|
||||||
|
"quests.optional.hint": "Les quêtes optionnelles sont des objectifs secondaires qui complètent votre histoire principale.",
|
||||||
|
"checkpoint.setChapterStart": "Définir Début Chapitre",
|
||||||
|
"checkpoint.clearChapterStart": "Effacer Début Chapitre",
|
||||||
|
"checkpoint.indicator": "Début Chapitre",
|
||||||
|
"checkpoint.tooltip": "Les messages avant ce point sont exclus du contexte",
|
||||||
|
"musicPlayer.title": "Musique de Scène",
|
||||||
|
"musicPlayer.noMusic": "L'IA suggérera de la musique quand approprié pour la scène",
|
||||||
|
"errors.parsingError": "Erreur de parsing RPG Companion Trackers ! Le modèle a renvoyé un format incorrect. Si le problème persiste, envisagez de changer le modèle pour les générations.",
|
||||||
|
"settings.recommendedModels.title": "Modèles Recommandés",
|
||||||
|
"settings.recommendedModels.description": "Pour que l'extension fonctionne correctement, **il n'est pas recommandé d'utiliser des modèles de moins de 20B, surtout s'ils sont anciens.** Elle fonctionne mieux avec les modèles SOTA tels que Deepseek, Claude, GPT ou Gemini.",
|
||||||
|
"thoughts.addCharacter": "Ajouter un personnage",
|
||||||
|
"thoughts.locked": "Verrouillé",
|
||||||
|
"thoughts.unlocked": "Déverrouillé",
|
||||||
|
"thoughts.clickToEdit": "Cliquer pour modifier",
|
||||||
|
"thoughts.clickToUpload": "Cliquer pour télécharger un avatar",
|
||||||
|
"thoughts.removeCharacter": "Supprimer le personnage",
|
||||||
|
"userStats.level": "NIV",
|
||||||
|
"userStats.clickToEditLevel": "Cliquer pour modifier le niveau",
|
||||||
|
"userStats.statsLocked": "Verrouillé - L'IA ne peut pas modifier les stats",
|
||||||
|
"userStats.statsUnlocked": "Déverrouillé - L'IA peut modifier les stats",
|
||||||
|
"userStats.clickToEditStatName": "Cliquer pour modifier le nom",
|
||||||
|
"userStats.clickToEditStatValue": "Cliquer pour modifier",
|
||||||
|
"userStats.moodLocked": "Verrouillé - L'IA ne peut pas modifier l'humeur",
|
||||||
|
"userStats.moodUnlocked": "Déverrouillé - L'IA peut modifier l'humeur",
|
||||||
|
"userStats.clickToEditEmoji": "Cliquer pour modifier l'émoji",
|
||||||
|
"userStats.skillsLocked": "Verrouillé - L'IA ne peut pas modifier les compétences",
|
||||||
|
"userStats.skillsUnlocked": "Déverrouillé - L'IA peut modifier les compétences",
|
||||||
|
"userStats.clickToEditSkills": "Cliquer pour modifier les compétences",
|
||||||
|
"infoBox.clickToEdit": "Cliquer pour modifier",
|
||||||
|
"infoBox.locked": "Verrouillé - L'IA ne peut pas modifier à ceci",
|
||||||
|
"infoBox.unlocked": "Déverrouillé - L'IA peut modifier à ceci",
|
||||||
|
"infoBox.weatherFallback": "Météo",
|
||||||
|
"infoBox.locationFallback": "Lieu",
|
||||||
|
"stats.health": "Santé",
|
||||||
|
"stats.satiety": "Satiété",
|
||||||
|
"stats.energy": "Énergie",
|
||||||
|
"stats.hygiene": "Hygiène",
|
||||||
|
"stats.arousal": "Excitation",
|
||||||
|
"stats.str": "FOR",
|
||||||
|
"stats.dex": "DEX",
|
||||||
|
"stats.con": "CON",
|
||||||
|
"stats.int": "INT",
|
||||||
|
"stats.wis": "VOL",
|
||||||
|
"stats.cha": "CHA"
|
||||||
|
}
|
||||||
@@ -363,9 +363,9 @@ export function renderInfoBox() {
|
|||||||
row1Widgets.push(`
|
row1Widgets.push(`
|
||||||
<div class="rpg-dashboard-widget rpg-calendar-widget">
|
<div class="rpg-dashboard-widget rpg-calendar-widget">
|
||||||
${dateLockIconHtml}
|
${dateLockIconHtml}
|
||||||
<div class="rpg-calendar-top rpg-editable" contenteditable="true" data-field="month" data-full-value="${data.month || ''}" title="Click to edit">${monthDisplay}</div>
|
<div class="rpg-calendar-top rpg-editable" contenteditable="true" data-field="month" data-full-value="${data.month || ''}" title="${i18n.getTranslation('infoBox.clickToEdit')}">${monthDisplay}</div>
|
||||||
<div class="rpg-calendar-day" title="Click to edit"><span class="rpg-calendar-day-text rpg-editable" contenteditable="true" data-field="weekday" data-full-value="${data.weekday || ''}">${weekdayDisplay}</span></div>
|
<div class="rpg-calendar-day" title="${i18n.getTranslation('infoBox.clickToEdit')}"><span class="rpg-calendar-day-text rpg-editable" contenteditable="true" data-field="weekday" data-full-value="${data.weekday || ''}">${weekdayDisplay}</span></div>
|
||||||
<div class="rpg-calendar-year rpg-editable" contenteditable="true" data-field="year" data-full-value="${data.year || ''}" title="Click to edit">${yearDisplay}</div>
|
<div class="rpg-calendar-year rpg-editable" contenteditable="true" data-field="year" data-full-value="${data.year || ''}" title="${i18n.getTranslation('infoBox.clickToEdit')}">${yearDisplay}</div>
|
||||||
</div>
|
</div>
|
||||||
`);
|
`);
|
||||||
}
|
}
|
||||||
@@ -373,14 +373,14 @@ export function renderInfoBox() {
|
|||||||
// Weather widget - show if enabled
|
// Weather widget - show if enabled
|
||||||
if (config?.widgets?.weather?.enabled) {
|
if (config?.widgets?.weather?.enabled) {
|
||||||
const weatherEmoji = data.weatherEmoji || '🌤️';
|
const weatherEmoji = data.weatherEmoji || '🌤️';
|
||||||
const weatherForecast = data.weatherForecast || 'Weather';
|
const weatherForecast = data.weatherForecast || i18n.getTranslation('infoBox.weatherFallback');
|
||||||
const weatherLockIconHtml = getLockIconHtml('infoBox', 'weather');
|
const weatherLockIconHtml = getLockIconHtml('infoBox', 'weather');
|
||||||
|
|
||||||
row1Widgets.push(`
|
row1Widgets.push(`
|
||||||
<div class="rpg-dashboard-widget rpg-weather-widget">
|
<div class="rpg-dashboard-widget rpg-weather-widget">
|
||||||
${weatherLockIconHtml}
|
${weatherLockIconHtml}
|
||||||
<div class="rpg-weather-icon rpg-editable" contenteditable="true" data-field="weatherEmoji" title="Click to edit emoji">${weatherEmoji}</div>
|
<div class="rpg-weather-icon rpg-editable" contenteditable="true" data-field="weatherEmoji" title="${i18n.getTranslation('userStats.clickToEditEmoji')}">${weatherEmoji}</div>
|
||||||
<div class="rpg-weather-forecast rpg-editable" contenteditable="true" data-field="weatherForecast" title="Click to edit">${weatherForecast}</div>
|
<div class="rpg-weather-forecast rpg-editable" contenteditable="true" data-field="weatherForecast" title="${i18n.getTranslation('infoBox.clickToEdit')}">${weatherForecast}</div>
|
||||||
</div>
|
</div>
|
||||||
`);
|
`);
|
||||||
}
|
}
|
||||||
@@ -429,7 +429,7 @@ export function renderInfoBox() {
|
|||||||
<div class="rpg-thermometer-fill" style="height: ${tempPercent}%; background: ${tempColor}"></div>
|
<div class="rpg-thermometer-fill" style="height: ${tempPercent}%; background: ${tempColor}"></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="rpg-temp-value rpg-editable" contenteditable="true" data-field="temperature" title="Click to edit">${tempDisplay}</div>
|
<div class="rpg-temp-value rpg-editable" contenteditable="true" data-field="temperature" title="${i18n.getTranslation('infoBox.clickToEdit')}">${tempDisplay}</div>
|
||||||
</div>
|
</div>
|
||||||
`);
|
`);
|
||||||
}
|
}
|
||||||
@@ -464,9 +464,9 @@ export function renderInfoBox() {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="rpg-time-range">
|
<div class="rpg-time-range">
|
||||||
<div class="rpg-time-value rpg-editable" contenteditable="true" data-field="timeStart" title="Click to edit start time">${timeStartDisplay}</div>
|
<div class="rpg-time-value rpg-editable" contenteditable="true" data-field="timeStart" title="${i18n.getTranslation('infoBox.clickToEdit')}">${timeStartDisplay}</div>
|
||||||
<span class="rpg-time-separator">→</span>
|
<span class="rpg-time-separator">→</span>
|
||||||
<div class="rpg-time-value rpg-editable" contenteditable="true" data-field="timeEnd" title="Click to edit end time">${timeEndDisplay}</div>
|
<div class="rpg-time-value rpg-editable" contenteditable="true" data-field="timeEnd" title="${i18n.getTranslation('infoBox.clickToEdit')}">${timeEndDisplay}</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
`);
|
`);
|
||||||
@@ -481,7 +481,7 @@ export function renderInfoBox() {
|
|||||||
|
|
||||||
// Row 2: Location widget (full width) - show if enabled
|
// Row 2: Location widget (full width) - show if enabled
|
||||||
if (config?.widgets?.location?.enabled) {
|
if (config?.widgets?.location?.enabled) {
|
||||||
const locationDisplay = data.location || 'Location';
|
const locationDisplay = data.location || i18n.getTranslation('infoBox.locationFallback');
|
||||||
const locationLockIconHtml = getLockIconHtml('infoBox', 'location');
|
const locationLockIconHtml = getLockIconHtml('infoBox', 'location');
|
||||||
|
|
||||||
html += `
|
html += `
|
||||||
@@ -491,7 +491,7 @@ export function renderInfoBox() {
|
|||||||
<div class="rpg-map-bg">
|
<div class="rpg-map-bg">
|
||||||
<div class="rpg-map-marker">📍</div>
|
<div class="rpg-map-marker">📍</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="rpg-location-text rpg-editable" contenteditable="true" data-field="location" title="Click to edit">${locationDisplay}</div>
|
<div class="rpg-location-text rpg-editable" contenteditable="true" data-field="location" title="${i18n.getTranslation('infoBox.clickToEdit')}">${locationDisplay}</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
@@ -550,7 +550,7 @@ export function renderInfoBox() {
|
|||||||
html += `
|
html += `
|
||||||
<div class="rpg-notebook-line">
|
<div class="rpg-notebook-line">
|
||||||
<span class="rpg-bullet">•</span>
|
<span class="rpg-bullet">•</span>
|
||||||
<span class="rpg-event-text rpg-editable" contenteditable="true" data-field="event${i + 1}" title="Click to edit">${validEvents[i]}</span>
|
<span class="rpg-event-text rpg-editable" contenteditable="true" data-field="event${i + 1}" title="${i18n.getTranslation('infoBox.clickToEdit')}">${validEvents[i]}</span>
|
||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
@@ -652,7 +652,7 @@ export function renderInfoBox() {
|
|||||||
|
|
||||||
// Update icon
|
// Update icon
|
||||||
$lockIcon.text(newLockState ? '🔒' : '🔓');
|
$lockIcon.text(newLockState ? '🔒' : '🔓');
|
||||||
$lockIcon.attr('title', newLockState ? 'Locked - AI cannot change this' : 'Unlocked - AI can change this');
|
$lockIcon.attr('title', newLockState ? i18n.getTranslation('infoBox.locked') : i18n.getTranslation('infoBox.unlocked'));
|
||||||
$lockIcon.toggleClass('locked', newLockState);
|
$lockIcon.toggleClass('locked', newLockState);
|
||||||
|
|
||||||
// Save settings to persist lock state
|
// Save settings to persist lock state
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ import {
|
|||||||
FALLBACK_AVATAR_DATA_URI,
|
FALLBACK_AVATAR_DATA_URI,
|
||||||
addDebugLog
|
addDebugLog
|
||||||
} from '../../core/state.js';
|
} from '../../core/state.js';
|
||||||
|
import { i18n } from '../../core/i18n.js';
|
||||||
import { saveChatData, saveSettings } from '../../core/persistence.js';
|
import { saveChatData, saveSettings } from '../../core/persistence.js';
|
||||||
import { getSafeThumbnailUrl } from '../../utils/avatars.js';
|
import { getSafeThumbnailUrl } from '../../utils/avatars.js';
|
||||||
import { isItemLocked, setItemLock } from '../generation/lockManager.js';
|
import { isItemLocked, setItemLock } from '../generation/lockManager.js';
|
||||||
@@ -30,7 +31,7 @@ function getLockIconHtml(tracker, path) {
|
|||||||
|
|
||||||
const isLocked = isItemLocked(tracker, path);
|
const isLocked = isItemLocked(tracker, path);
|
||||||
const lockIcon = isLocked ? '🔒' : '🔓';
|
const lockIcon = isLocked ? '🔒' : '🔓';
|
||||||
const lockTitle = isLocked ? 'Locked' : 'Unlocked';
|
const lockTitle = isLocked ? i18n.getTranslation('thoughts.locked') : i18n.getTranslation('thoughts.unlocked');
|
||||||
const lockedClass = isLocked ? ' locked' : '';
|
const lockedClass = isLocked ? ' locked' : '';
|
||||||
return `<span class="rpg-section-lock-icon${lockedClass}" data-tracker="${tracker}" data-path="${path}" title="${lockTitle}">${lockIcon}</span>`;
|
return `<span class="rpg-section-lock-icon${lockedClass}" data-tracker="${tracker}" data-path="${path}" title="${lockTitle}">${lockIcon}</span>`;
|
||||||
}
|
}
|
||||||
@@ -502,14 +503,14 @@ export function renderThoughts({ preserveScroll = false } = {}) {
|
|||||||
html += `
|
html += `
|
||||||
<div class="rpg-character-card" data-character-name="${char.name}">
|
<div class="rpg-character-card" data-character-name="${char.name}">
|
||||||
<div class="rpg-character-header-row">
|
<div class="rpg-character-header-row">
|
||||||
<div class="rpg-character-avatar rpg-avatar-upload" data-character="${char.name}" title="Click to upload avatar">
|
<div class="rpg-character-avatar rpg-avatar-upload" data-character="${char.name}" title="${i18n.getTranslation('thoughts.clickToUpload')}">
|
||||||
<img src="${characterPortrait}" alt="${char.name}" onerror="this.style.opacity='0.5';this.onerror=null;" />
|
<img src="${characterPortrait}" alt="${char.name}" onerror="this.style.opacity='0.5';this.onerror=null;" />
|
||||||
${hasRelationshipEnabled ? `<div class="rpg-relationship-badge rpg-editable" contenteditable="true" data-character="${char.name}" data-field="${relationshipFieldName}" title="Click to edit (use emoji: ⚔️ ⚖️ ⭐ ❤️)">${relationshipBadge}</div>` : ''}
|
${hasRelationshipEnabled ? `<div class="rpg-relationship-badge rpg-editable" contenteditable="true" data-character="${char.name}" data-field="${relationshipFieldName}" title="${i18n.getTranslation('thoughts.clickToEdit')} (emoji: ⚔️ ⚖️ ⭐ ❤️)">${relationshipBadge}</div>` : ''}
|
||||||
</div>
|
</div>
|
||||||
<div class="rpg-character-header">
|
<div class="rpg-character-header">
|
||||||
<span class="rpg-character-emoji rpg-editable" contenteditable="true" data-character="${char.name}" data-field="emoji" title="Click to edit emoji">${char.emoji}</span>
|
<span class="rpg-character-emoji rpg-editable" contenteditable="true" data-character="${char.name}" data-field="emoji" title="${i18n.getTranslation('thoughts.clickToEdit')}">${char.emoji}</span>
|
||||||
<span class="rpg-character-name rpg-editable" contenteditable="true" data-character="${char.name}" data-field="name" title="Click to edit name">${char.name}</span>
|
<span class="rpg-character-name rpg-editable" contenteditable="true" data-character="${char.name}" data-field="name" title="${i18n.getTranslation('thoughts.clickToEdit')}">${char.name}</span>
|
||||||
<button class="rpg-character-remove" data-character="${char.name}" title="Remove character">×</button>
|
<button class="rpg-character-remove" data-character="${char.name}" title="${i18n.getTranslation('thoughts.removeCharacter')}">×</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="rpg-character-content">
|
<div class="rpg-character-content">
|
||||||
@@ -532,12 +533,12 @@ export function renderThoughts({ preserveScroll = false } = {}) {
|
|||||||
html += `
|
html += `
|
||||||
<div class="rpg-character-field rpg-character-${fieldId}" style="position: relative;">
|
<div class="rpg-character-field rpg-character-${fieldId}" style="position: relative;">
|
||||||
${lockIconHtml}
|
${lockIconHtml}
|
||||||
<span class="rpg-editable${emptyClass}" contenteditable="true" data-character="${char.name}" data-field="${field.name}" title="Click to edit ${field.name}" ${placeholder}>${fieldValue}</span>
|
<span class="rpg-editable${emptyClass}" contenteditable="true" data-character="${char.name}" data-field="${field.name}" title="${i18n.getTranslation('thoughts.clickToEdit')}" ${placeholder}>${fieldValue}</span>
|
||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
} else {
|
} else {
|
||||||
html += `
|
html += `
|
||||||
<div class="rpg-character-field rpg-character-${fieldId} rpg-editable${emptyClass}" contenteditable="true" data-character="${char.name}" data-field="${field.name}" title="Click to edit ${field.name}" ${placeholder}>${fieldValue}</div>
|
<div class="rpg-character-field rpg-character-${fieldId} rpg-editable${emptyClass}" contenteditable="true" data-character="${char.name}" data-field="${field.name}" title="${i18n.getTranslation('thoughts.clickToEdit')}" ${placeholder}>${fieldValue}</div>
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -563,7 +564,7 @@ export function renderThoughts({ preserveScroll = false } = {}) {
|
|||||||
);
|
);
|
||||||
html += `
|
html += `
|
||||||
<div class="rpg-character-stat">
|
<div class="rpg-character-stat">
|
||||||
<span class="rpg-stat-name">${stat.name}: </span><span class="rpg-editable" contenteditable="true" data-character="${char.name}" data-field="${stat.name}" style="color: ${statColor}" title="Click to edit ${stat.name}">${statValue}%</span>
|
<span class="rpg-stat-name">${stat.name}: </span><span class="rpg-editable" contenteditable="true" data-character="${char.name}" data-field="${stat.name}" style="color: ${statColor}" title="${i18n.getTranslation('thoughts.clickToEdit')}">${statValue}%</span>
|
||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
@@ -589,8 +590,8 @@ export function renderThoughts({ preserveScroll = false } = {}) {
|
|||||||
// Add "Add Character" button if data exists (inside rpg-thoughts-content)
|
// Add "Add Character" button if data exists (inside rpg-thoughts-content)
|
||||||
if (presentCharacters.length > 0) {
|
if (presentCharacters.length > 0) {
|
||||||
html += `
|
html += `
|
||||||
<button class="rpg-add-character-btn" title="Add a new character">
|
<button class="rpg-add-character-btn" title="${i18n.getTranslation('thoughts.addCharacter')}">
|
||||||
<i class="fa-solid fa-plus"></i> Add Character
|
<i class="fa-solid fa-plus"></i> ${i18n.getTranslation('thoughts.addCharacter')}
|
||||||
</button>
|
</button>
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ import {
|
|||||||
$userStatsContainer,
|
$userStatsContainer,
|
||||||
FALLBACK_AVATAR_DATA_URI
|
FALLBACK_AVATAR_DATA_URI
|
||||||
} from '../../core/state.js';
|
} from '../../core/state.js';
|
||||||
|
import { i18n } from '../../core/i18n.js';
|
||||||
import {
|
import {
|
||||||
saveSettings,
|
saveSettings,
|
||||||
saveChatData,
|
saveChatData,
|
||||||
@@ -273,7 +274,7 @@ export function renderUserStats() {
|
|||||||
// Check if stats bars section is locked
|
// Check if stats bars section is locked
|
||||||
const isStatsLocked = isItemLocked('userStats', 'stats');
|
const isStatsLocked = isItemLocked('userStats', 'stats');
|
||||||
const lockIcon = isStatsLocked ? '🔒' : '🔓';
|
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' : '';
|
const lockedClass = isStatsLocked ? ' locked' : '';
|
||||||
|
|
||||||
let html = '<div class="rpg-stats-content">';
|
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;" />
|
<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>
|
<span class="rpg-user-name">${userName}</span>
|
||||||
${showLevel ? `<span style="opacity: 0.5;">|</span>
|
${showLevel ? `<span style="opacity: 0.5;">|</span>
|
||||||
<span class="rpg-level-label">LVL</span>
|
<span class="rpg-level-label">${i18n.getTranslation('userStats.level')}</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-value rpg-editable" contenteditable="true" data-field="level" title="${i18n.getTranslation('userStats.clickToEditLevel')}">${extensionSettings.level}</span>` : ''}
|
||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
|
|
||||||
@@ -320,11 +321,11 @@ export function renderUserStats() {
|
|||||||
|
|
||||||
html += `
|
html += `
|
||||||
<div class="rpg-stat-row">
|
<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-bar" style="background: ${gradient}">
|
||||||
<div class="rpg-stat-fill" style="width: ${100 - percentage}%"></div>
|
<div class="rpg-stat-fill" style="width: ${100 - percentage}%"></div>
|
||||||
</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>
|
</div>
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
@@ -334,7 +335,7 @@ export function renderUserStats() {
|
|||||||
if (config.statusSection.enabled) {
|
if (config.statusSection.enabled) {
|
||||||
const isMoodLocked = isItemLocked('userStats', 'status');
|
const isMoodLocked = isItemLocked('userStats', 'status');
|
||||||
const moodLockIcon = isMoodLocked ? '🔒' : '🔓';
|
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' : '';
|
const moodLockedClass = isMoodLocked ? ' locked' : '';
|
||||||
html += '<div class="rpg-mood">';
|
html += '<div class="rpg-mood">';
|
||||||
if (showLockIcons) {
|
if (showLockIcons) {
|
||||||
@@ -342,7 +343,7 @@ export function renderUserStats() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (config.statusSection.showMoodEmoji) {
|
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
|
// Render custom status fields
|
||||||
@@ -368,7 +369,7 @@ export function renderUserStats() {
|
|||||||
if (config.skillsSection.enabled) {
|
if (config.skillsSection.enabled) {
|
||||||
const isSkillsLocked = isItemLocked('userStats', 'skills');
|
const isSkillsLocked = isItemLocked('userStats', 'skills');
|
||||||
const skillsLockIcon = isSkillsLocked ? '🔒' : '🔓';
|
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' : '';
|
const skillsLockedClass = isSkillsLocked ? ' locked' : '';
|
||||||
let skillsValue = 'None';
|
let skillsValue = 'None';
|
||||||
// Handle JSON array format: [{name: "Art"}, {name: "Coding"}]
|
// Handle JSON array format: [{name: "Art"}, {name: "Coding"}]
|
||||||
@@ -385,7 +386,7 @@ export function renderUserStats() {
|
|||||||
}
|
}
|
||||||
html += `
|
html += `
|
||||||
<span class="rpg-skills-label">${config.skillsSection.label}:</span>
|
<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>
|
</div>
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
@@ -594,7 +595,7 @@ export function renderUserStats() {
|
|||||||
|
|
||||||
// Update icon
|
// Update icon
|
||||||
const newIcon = !currentlyLocked ? '🔒' : '🔓';
|
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.text(newIcon);
|
||||||
$icon.attr('title', newTitle);
|
$icon.attr('title', newTitle);
|
||||||
|
|
||||||
|
|||||||
@@ -334,20 +334,20 @@ function resetToDefaults() {
|
|||||||
extensionSettings.trackerConfig = {
|
extensionSettings.trackerConfig = {
|
||||||
userStats: {
|
userStats: {
|
||||||
customStats: [
|
customStats: [
|
||||||
{ id: 'health', name: 'Health', enabled: true, persistInHistory: false },
|
{ id: 'health', name: i18n.getTranslation('stats.health'), enabled: true, persistInHistory: false },
|
||||||
{ id: 'satiety', name: 'Satiety', enabled: true, persistInHistory: false },
|
{ id: 'satiety', name: i18n.getTranslation('stats.satiety'), enabled: true, persistInHistory: false },
|
||||||
{ id: 'energy', name: 'Energy', enabled: true, persistInHistory: false },
|
{ id: 'energy', name: i18n.getTranslation('stats.energy'), enabled: true, persistInHistory: false },
|
||||||
{ id: 'hygiene', name: 'Hygiene', enabled: true, persistInHistory: false },
|
{ id: 'hygiene', name: i18n.getTranslation('stats.hygiene'), enabled: true, persistInHistory: false },
|
||||||
{ id: 'arousal', name: 'Arousal', enabled: true, persistInHistory: false }
|
{ id: 'arousal', name: i18n.getTranslation('stats.arousal'), enabled: true, persistInHistory: false }
|
||||||
],
|
],
|
||||||
showRPGAttributes: true,
|
showRPGAttributes: true,
|
||||||
rpgAttributes: [
|
rpgAttributes: [
|
||||||
{ id: 'str', name: 'STR', enabled: true, persistInHistory: false },
|
{ id: 'str', name: i18n.getTranslation('stats.str'), enabled: true, persistInHistory: false },
|
||||||
{ id: 'dex', name: 'DEX', enabled: true, persistInHistory: false },
|
{ id: 'dex', name: i18n.getTranslation('stats.dex'), enabled: true, persistInHistory: false },
|
||||||
{ id: 'con', name: 'CON', enabled: true, persistInHistory: false },
|
{ id: 'con', name: i18n.getTranslation('stats.con'), enabled: true, persistInHistory: false },
|
||||||
{ id: 'int', name: 'INT', enabled: true, persistInHistory: false },
|
{ id: 'int', name: i18n.getTranslation('stats.int'), enabled: true, persistInHistory: false },
|
||||||
{ id: 'wis', name: 'WIS', enabled: true, persistInHistory: false },
|
{ id: 'wis', name: i18n.getTranslation('stats.wis'), enabled: true, persistInHistory: false },
|
||||||
{ id: 'cha', name: 'CHA', enabled: true, persistInHistory: false }
|
{ id: 'cha', name: i18n.getTranslation('stats.cha'), enabled: true, persistInHistory: false }
|
||||||
],
|
],
|
||||||
statusSection: {
|
statusSection: {
|
||||||
enabled: true,
|
enabled: true,
|
||||||
@@ -408,8 +408,8 @@ function resetToDefaults() {
|
|||||||
characterStats: {
|
characterStats: {
|
||||||
enabled: false,
|
enabled: false,
|
||||||
customStats: [
|
customStats: [
|
||||||
{ id: 'health', name: 'Health', enabled: true, colorLow: '#ff4444', colorHigh: '#44ff44' },
|
{ id: 'health', name: i18n.getTranslation('stats.health'), enabled: true, colorLow: '#ff4444', colorHigh: '#44ff44' },
|
||||||
{ id: 'energy', name: 'Energy', enabled: true, colorLow: '#ffaa00', colorHigh: '#44ffff' }
|
{ id: 'energy', name: i18n.getTranslation('stats.energy'), enabled: true, colorLow: '#ffaa00', colorHigh: '#44ffff' }
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user