Merge pull request #52 from lilminzyu/i18n/zh-tw
Add Chinese (Traditional) i18n support
This commit is contained in:
@@ -5,6 +5,7 @@ import { power_user } from '../../../power-user.js';
|
||||
|
||||
// Core modules
|
||||
import { extensionName, extensionFolderPath } from './src/core/config.js';
|
||||
import { i18n } from './src/core/i18n.js';
|
||||
import {
|
||||
extensionSettings,
|
||||
lastGeneratedData,
|
||||
@@ -104,7 +105,8 @@ import {
|
||||
setupMobileTabs,
|
||||
removeMobileTabs,
|
||||
setupMobileKeyboardHandling,
|
||||
setupContentEditableScrolling
|
||||
setupContentEditableScrolling,
|
||||
updateMobileTabLabels
|
||||
} from './src/systems/ui/mobile.js';
|
||||
import {
|
||||
setupDesktopTabs,
|
||||
@@ -152,35 +154,30 @@ import {
|
||||
// (setupMobileToggle, constrainFabToViewport, setupMobileTabs, removeMobileTabs,
|
||||
// setupMobileKeyboardHandling, setupContentEditableScrolling)
|
||||
|
||||
/**
|
||||
* Updates UI elements that are dynamically generated and not covered by data-i18n-key.
|
||||
*/
|
||||
function updateDynamicLabels() {
|
||||
// Update "Refresh RPG Info" button, but only if it's not disabled
|
||||
const refreshBtn = document.getElementById('rpg-manual-update');
|
||||
if (refreshBtn && !refreshBtn.disabled) {
|
||||
const refreshText = i18n.getTranslation('template.mainPanel.refreshRpgInfo') || 'Refresh RPG Info';
|
||||
refreshBtn.innerHTML = `<i class="fa-solid fa-sync"></i> ${refreshText}`;
|
||||
}
|
||||
|
||||
// Update "Last Roll" label
|
||||
updateDiceDisplay();
|
||||
|
||||
// Update mobile tab labels
|
||||
updateMobileTabLabels();
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the extension settings to the Extensions tab.
|
||||
*/
|
||||
function addExtensionSettings() {
|
||||
const settingsHtml = `
|
||||
<div class="inline-drawer">
|
||||
<div class="inline-drawer-toggle inline-drawer-header">
|
||||
<b><i class="fa-solid fa-dice-d20"></i> RPG Companion</b>
|
||||
<div class="inline-drawer-icon fa-solid fa-circle-chevron-down down"></div>
|
||||
</div>
|
||||
<div class="inline-drawer-content">
|
||||
<label class="checkbox_label" for="rpg-extension-enabled">
|
||||
<input type="checkbox" id="rpg-extension-enabled" />
|
||||
<span>Enable RPG Companion</span>
|
||||
</label>
|
||||
<small class="notes">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;">
|
||||
<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
|
||||
</a>
|
||||
<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 Creator
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
async function addExtensionSettings() {
|
||||
// Load the HTML template for the settings
|
||||
const settingsHtml = await renderExtensionTemplateAsync(extensionName, 'settings');
|
||||
$('#extensions_settings2').append(settingsHtml);
|
||||
|
||||
// Set up the enable/disable toggle
|
||||
@@ -210,12 +207,27 @@ function addExtensionSettings() {
|
||||
// Update Memory Recollection button visibility
|
||||
updateMemoryRecollectionButton();
|
||||
});
|
||||
|
||||
// Set up language selector
|
||||
const langSelect = $('#rpg-companion-language-select');
|
||||
if (langSelect.length) {
|
||||
langSelect.val(i18n.currentLanguage);
|
||||
langSelect.on('change', async function() {
|
||||
const selectedLanguage = $(this).val();
|
||||
await i18n.setLanguage(selectedLanguage);
|
||||
// We need to re-apply translations to the settings panel specifically
|
||||
i18n.applyTranslations(document.getElementById('extensions_settings2'));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the UI for the extension.
|
||||
*/
|
||||
async function initUI() {
|
||||
// Initialize i18n
|
||||
await i18n.init();
|
||||
|
||||
// Only initialize UI if extension is enabled
|
||||
if (!extensionSettings.enabled) {
|
||||
console.log('[RPG Companion] Extension disabled - skipping UI initialization');
|
||||
@@ -249,6 +261,9 @@ async function initUI() {
|
||||
setInventoryContainer($('#rpg-inventory'));
|
||||
setQuestsContainer($('#rpg-quests'));
|
||||
|
||||
// Re-apply translations to the entire body to catch all new elements from the template
|
||||
i18n.applyTranslations(document.body);
|
||||
|
||||
// Set up event listeners (enable/disable is handled in Extensions tab)
|
||||
$('#rpg-toggle-auto-update').on('change', function() {
|
||||
extensionSettings.autoUpdate = $(this).prop('checked');
|
||||
@@ -597,9 +612,15 @@ jQuery(async () => {
|
||||
console.error('[RPG Companion] Settings load failed, continuing with defaults:', error);
|
||||
}
|
||||
|
||||
// Initialize i18n early for the settings panel
|
||||
await i18n.init();
|
||||
|
||||
// Set up a central listener for language changes to update dynamic UI parts
|
||||
i18n.addEventListener('languageChanged', updateDynamicLabels);
|
||||
|
||||
// Add extension settings to Extensions tab
|
||||
try {
|
||||
addExtensionSettings();
|
||||
await addExtensionSettings();
|
||||
} catch (error) {
|
||||
console.error('[RPG Companion] Failed to add extension settings tab:', error);
|
||||
// Don't throw - extension can still work without settings tab
|
||||
|
||||
+11
-2
@@ -7,9 +7,18 @@
|
||||
<div class="inline-drawer-content">
|
||||
<label class="checkbox_label" for="rpg-extension-enabled">
|
||||
<input type="checkbox" id="rpg-extension-enabled" />
|
||||
<span>Enable RPG Companion</span>
|
||||
<span data-i18n-key="settings.extensionEnabled">Enable RPG Companion</span>
|
||||
</label>
|
||||
<small class="notes">Toggle to enable/disable the RPG Companion extension. Configure additional settings within the panel itself.</small>
|
||||
|
||||
<div class="form-group" style="margin-top: 10px;">
|
||||
<label for="rpg-companion-language-select" data-i18n-key="settings.language.label">Language</label>
|
||||
<select id="rpg-companion-language-select" class="text_pole">
|
||||
<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>
|
||||
</select>
|
||||
</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>
|
||||
|
||||
<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;">
|
||||
|
||||
@@ -0,0 +1,103 @@
|
||||
//- No-op in case this is running outside of SillyTavern
|
||||
const { extension_settings } = typeof self.SillyTavern !== 'undefined' ? self.SillyTavern.getContext() : { extension_settings: {} };
|
||||
|
||||
class Internationalization {
|
||||
constructor() {
|
||||
this.currentLanguage = 'en';
|
||||
this.translations = {};
|
||||
this._listeners = {};
|
||||
}
|
||||
|
||||
addEventListener(event, callback) {
|
||||
if (!this._listeners[event]) {
|
||||
this._listeners[event] = [];
|
||||
}
|
||||
this._listeners[event].push(callback);
|
||||
}
|
||||
|
||||
dispatchEvent(event, data) {
|
||||
if (this._listeners[event]) {
|
||||
this._listeners[event].forEach(callback => callback(data));
|
||||
}
|
||||
}
|
||||
|
||||
async init() {
|
||||
const savedLanguage = localStorage.getItem('rpgCompanionLanguage') || 'en';
|
||||
this.currentLanguage = savedLanguage;
|
||||
|
||||
await this.loadTranslations(this.currentLanguage);
|
||||
this.applyTranslations(document.body);
|
||||
|
||||
const langSelect = document.getElementById('rpg-companion-language-select');
|
||||
if (langSelect) {
|
||||
langSelect.value = this.currentLanguage;
|
||||
}
|
||||
}
|
||||
|
||||
async loadTranslations(lang) {
|
||||
const fetchUrl = `/scripts/extensions/third-party/rpg-companion-sillytavern/src/i18n/${lang}.json`;
|
||||
try {
|
||||
const response = await fetch(fetchUrl);
|
||||
if (!response.ok) {
|
||||
console.error(`[RPG-Companion-i18n] Failed to load translation file for ${lang}. Status: ${response.status}`);
|
||||
if (lang !== 'en') {
|
||||
return this.loadTranslations('en');
|
||||
}
|
||||
return;
|
||||
}
|
||||
this.translations = await response.json();
|
||||
} catch (error) {
|
||||
console.error('[RPG-Companion-i18n] CRITICAL error loading translation file:', error);
|
||||
}
|
||||
}
|
||||
|
||||
applyTranslations(rootElement) {
|
||||
if (!rootElement) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 1. Translate textContent
|
||||
const textElements = rootElement.querySelectorAll('[data-i18n-key]');
|
||||
textElements.forEach(element => {
|
||||
const key = element.dataset.i18nKey;
|
||||
const translation = this.getTranslation(key);
|
||||
if (translation) {
|
||||
element.textContent = translation;
|
||||
}
|
||||
});
|
||||
|
||||
// 2. Translate title attribute
|
||||
const titleElements = rootElement.querySelectorAll('[data-i18n-title]');
|
||||
titleElements.forEach(element => {
|
||||
const key = element.dataset.i18nTitle;
|
||||
const translation = this.getTranslation(key);
|
||||
if (translation) {
|
||||
element.setAttribute('title', translation);
|
||||
}
|
||||
});
|
||||
|
||||
// 3. Translate aria-label attribute
|
||||
const ariaLabelElements = rootElement.querySelectorAll('[data-i18n-aria-label]');
|
||||
ariaLabelElements.forEach(element => {
|
||||
const key = element.dataset.i18nAriaLabel;
|
||||
const translation = this.getTranslation(key);
|
||||
if (translation) {
|
||||
element.setAttribute('aria-label', translation);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
getTranslation(key) {
|
||||
return this.translations[key] || null;
|
||||
}
|
||||
|
||||
async setLanguage(lang) {
|
||||
this.currentLanguage = lang;
|
||||
localStorage.setItem('rpgCompanionLanguage', lang);
|
||||
await this.loadTranslations(lang);
|
||||
this.applyTranslations(document.body);
|
||||
this.dispatchEvent('languageChanged');
|
||||
}
|
||||
}
|
||||
|
||||
export const i18n = new Internationalization();
|
||||
@@ -0,0 +1,165 @@
|
||||
{
|
||||
"settings.language.label": "Language",
|
||||
"settings.language.option.en": "English",
|
||||
"settings.language.option.zh-tw": "繁體中文",
|
||||
"settings.extensionEnabled": "Enable RPG Companion",
|
||||
"settings.note": "Toggle to enable/disable the RPG Companion extension. Configure additional settings within the panel itself.",
|
||||
"template.settingsTitle": "RPG Companion Settings",
|
||||
"template.settingsModal.themeTitle": "Theme",
|
||||
"template.settingsModal.themeLabel": "Visual Theme:",
|
||||
"template.settingsModal.themeOptions.default": "Default",
|
||||
"template.settingsModal.themeOptions.sciFi": "Sci-Fi (Synthwave)",
|
||||
"template.settingsModal.themeOptions.fantasy": "Fantasy (Rustic Parchment)",
|
||||
"template.settingsModal.themeOptions.cyberpunk": "Cyberpunk (Neon Grid)",
|
||||
"template.settingsModal.themeOptions.custom": "Custom",
|
||||
"template.settingsModal.themeOptions.custom.background": "Background:",
|
||||
"template.settingsModal.themeOptions.custom.accent": "Accent:",
|
||||
"template.settingsModal.themeOptions.custom.text": "Text:",
|
||||
"template.settingsModal.themeOptions.custom.highlight": "Highlight:",
|
||||
"template.settingsModal.theme.statBarLow": "Stat Bar Color (Low):",
|
||||
"template.settingsModal.theme.statBarLowNote": "Color when stats are at 0%",
|
||||
"template.settingsModal.theme.statBarHigh": "Stat Bar Color (High):",
|
||||
"template.settingsModal.theme.statBarHighNote": "Color when stats are at 100%",
|
||||
"template.settingsModal.displayTitle": "Display Options",
|
||||
"template.settingsModal.displayNote": "Use the Extensions tab to enable/disable the RPG Companion extension.",
|
||||
"template.settingsModal.display.panelPosition": "Panel Position:",
|
||||
"template.settingsModal.display.panelPositionOptions.right": "Right Sidebar",
|
||||
"template.settingsModal.display.panelPositionOptions.left": "Left Sidebar",
|
||||
"template.settingsModal.display.toggleAutoUpdate": "Auto-update after messages",
|
||||
"template.settingsModal.display.showUserStats": "Show User Stats",
|
||||
"template.settingsModal.display.showInfoBox": "Show Info Box",
|
||||
"template.settingsModal.display.showPresentCharacters": "Show Present Characters",
|
||||
"template.settingsModal.display.showInventory": "Show Inventory",
|
||||
"template.settingsModal.display.showThoughtsInChat": "Show Thoughts in Chat",
|
||||
"template.settingsModal.display.showThoughtsInChatNote": "Display character thoughts as overlay bubbles next to their messages",
|
||||
"template.settingsModal.display.alwaysShowThoughtBubble": "Always Show Thought Bubble",
|
||||
"template.settingsModal.display.alwaysShowThoughtBubbleNote": "Auto-expand thought bubble without clicking the icon first",
|
||||
"template.settingsModal.display.enableAnimations": "Enable Animations",
|
||||
"template.settingsModal.display.enableAnimationsNote": "Smooth transitions for stats, content updates, and dice rolls",
|
||||
"template.settingsModal.display.showPlotProgressionButtons": "Show Plot Progression Buttons",
|
||||
"template.settingsModal.display.showPlotProgressionButtonsNote": "Display buttons above chat input for plot progression prompts",
|
||||
"template.settingsModal.display.enableDebugMode": "Enable Debug Mode",
|
||||
"template.settingsModal.display.enableDebugModeNote": "Shows parser logs in a mobile-friendly UI panel. Useful for troubleshooting. Look for the red bug button.",
|
||||
"template.settingsModal.advancedTitle": "Advanced",
|
||||
"template.settingsModal.advanced.generationMode": "Generation Mode:",
|
||||
"template.settingsModal.advanced.generationModeOptions.together": "Together with Main Generation",
|
||||
"template.settingsModal.advanced.generationModeOptions.separate": "Separate Generation",
|
||||
"template.settingsModal.advanced.generationModeNote": "Together: Adds RPG tracking to main roleplay. Separate: Generates RPG data separately (manual or auto).",
|
||||
"template.settingsModal.advanced.contextMessages": "Context Messages:",
|
||||
"template.settingsModal.advanced.contextMessagesNote": "Number of recent messages to include (Separate mode only)",
|
||||
"template.settingsModal.advanced.memoryBatchSize": "Memory Batch Size:",
|
||||
"template.settingsModal.advanced.memoryBatchSizeNote": "Number of messages to process per batch in Memory Recollection",
|
||||
"template.settingsModal.advanced.useSeparatePreset": "Use model connected to RPG Companion Trackers preset",
|
||||
"template.settingsModal.advanced.useSeparatePresetNote": "Separate mode only. When enabled, tracker generation will use the model from the \"RPG Companion Trackers\" preset instead of your main API model. The preset will be switched automatically during generation and restored afterward. Select the desired model in that preset and make sure the \"Bind presets to API connections\" toggle is on (next to the import/export preset buttons).",
|
||||
"template.settingsModal.advanced.skipInjections": "Skip Injections during Guided Generations:",
|
||||
"template.settingsModal.advanced.skipInjectionsOptions.none": "Never skip",
|
||||
"template.settingsModal.advanced.skipInjectionsOptions.impersonation": "Only on impersonation requests",
|
||||
"template.settingsModal.advanced.skipInjectionsOptions.guided": "Always for guided or quiet prompts",
|
||||
"template.settingsModal.advanced.skipInjectionsNote": "When set, the extension will not inject tracker prompts, examples, or HTML instructions according to the selected mode when a guided generation (via `instruct` or `quiet_prompt`) is detected. Useful when using GuidedGenerations or similar extensions.",
|
||||
"template.settingsModal.advanced.customHtmlPromptTitle": "Custom HTML Prompt:",
|
||||
"template.settingsModal.advanced.restoreDefaultHtmlPrompt": "Restore Default",
|
||||
"template.settingsModal.advanced.customHtmlPromptNote": "Customize the HTML prompt injected when \"Enable Immersive HTML\" is enabled. The default prompt is shown above - you can edit it directly or replace it entirely. Click \"Restore Default\" to reset. This affects all generation modes (together, separate, and plot progression).",
|
||||
"template.settingsModal.advanced.clearCache": "Clear Extension Cache",
|
||||
"template.settingsModal.advanced.resetFabPositions": "Reset Button Positions",
|
||||
"template.settingsModal.advanced.resetFabPositionsNote": "Resets all floating action buttons (toggle, refresh, debug) to default top-left positions. Useful if buttons are off-screen.",
|
||||
"template.trackerEditorModal.title": "Edit Trackers",
|
||||
"template.trackerEditorModal.tabs.userStats": "User Stats",
|
||||
"template.trackerEditorModal.tabs.infoBox": "Info Box",
|
||||
"template.trackerEditorModal.tabs.presentCharacters": "Present Characters",
|
||||
"template.trackerEditorModal.buttons.reset": "Reset to Defaults",
|
||||
"template.trackerEditorModal.buttons.cancel": "Cancel",
|
||||
"template.trackerEditorModal.buttons.save": "Save & Apply",
|
||||
"template.trackerEditorModal.userStatsTab.customStatsTitle": "Custom Stats",
|
||||
"template.trackerEditorModal.userStatsTab.addCustomStatButton": "Add Custom Stat",
|
||||
"template.trackerEditorModal.userStatsTab.rpgAttributesTitle": "RPG Attributes",
|
||||
"template.trackerEditorModal.userStatsTab.enableRpgAttributes": "Enable RPG Attributes Section",
|
||||
"template.trackerEditorModal.userStatsTab.alwaysIncludeAttributes": "Always Include Attributes in Prompt",
|
||||
"template.trackerEditorModal.userStatsTab.alwaysIncludeAttributesNote": "If disabled, attributes are only sent when a dice roll is active.",
|
||||
"template.trackerEditorModal.userStatsTab.addAttributeButton": "Add Attribute",
|
||||
"template.trackerEditorModal.userStatsTab.statusSectionTitle": "Status Section",
|
||||
"template.trackerEditorModal.userStatsTab.enableStatusSection": "Enable Status Section",
|
||||
"template.trackerEditorModal.userStatsTab.showMoodEmoji": "Show Mood Emoji",
|
||||
"template.trackerEditorModal.userStatsTab.statusFieldsLabel": "Status Fields (comma-separated):",
|
||||
"template.trackerEditorModal.userStatsTab.skillsSectionTitle": "Skills Section",
|
||||
"template.trackerEditorModal.userStatsTab.enableSkillsSection": "Enable Skills Section",
|
||||
"template.trackerEditorModal.userStatsTab.skillsLabelLabel": "Skills Label:",
|
||||
"template.trackerEditorModal.userStatsTab.skillsListLabel": "Skills List (comma-separated):",
|
||||
"template.trackerEditorModal.infoBoxTab.widgetsTitle": "Widgets",
|
||||
"template.trackerEditorModal.infoBoxTab.dateWidget": "Date",
|
||||
"template.trackerEditorModal.infoBoxTab.weatherWidget": "Weather",
|
||||
"template.trackerEditorModal.infoBoxTab.temperatureWidget": "Temperature",
|
||||
"template.trackerEditorModal.infoBoxTab.timeWidget": "Time",
|
||||
"template.trackerEditorModal.infoBoxTab.locationWidget": "Location",
|
||||
"template.trackerEditorModal.infoBoxTab.recentEventsWidget": "Recent Events",
|
||||
"template.trackerEditorModal.presentCharactersTab.relationshipStatusTitle": "Relationship Status Fields",
|
||||
"template.trackerEditorModal.presentCharactersTab.relationshipStatusHint": "Define relationship types with corresponding emojis shown on character portraits",
|
||||
"template.trackerEditorModal.presentCharactersTab.newRelationshipButton": "New Relationship",
|
||||
"template.trackerEditorModal.presentCharactersTab.appearanceDemeanorTitle": "Appearance/Demeanor Fields",
|
||||
"template.trackerEditorModal.presentCharactersTab.appearanceDemeanorHint": "Fields shown below character name, separated by |",
|
||||
"template.trackerEditorModal.presentCharactersTab.addCustomFieldButton": "Add Custom Field",
|
||||
"template.trackerEditorModal.presentCharactersTab.thoughtsConfigTitle": "Thoughts Configuration",
|
||||
"template.trackerEditorModal.presentCharactersTab.enableCharacterThoughts": "Enable Character Thoughts",
|
||||
"template.trackerEditorModal.presentCharactersTab.thoughtsLabelLabel": "Thoughts Label:",
|
||||
"template.trackerEditorModal.presentCharactersTab.aiInstructionLabel": "AI Instruction:",
|
||||
"template.trackerEditorModal.presentCharactersTab.characterStatsTitle": "Character Stats",
|
||||
"template.trackerEditorModal.presentCharactersTab.trackCharacterStats": "Track Character Stats",
|
||||
"template.trackerEditorModal.presentCharactersTab.characterStatsHint": "Create stats to track for each character (displayed as colored bars)",
|
||||
"template.trackerEditorModal.presentCharactersTab.addCharacterStatButton": "Add Character Stat",
|
||||
"template.mainPanel.title": "RPG Companion",
|
||||
"template.mainPanel.lastRoll": "Last Roll:",
|
||||
"template.mainPanel.clearLastRoll": "Clear last roll",
|
||||
"template.mainPanel.enableImmersiveHtml": "Enable Immersive HTML",
|
||||
"template.mainPanel.refreshRpgInfo": "Refresh RPG Info",
|
||||
"template.mainPanel.updating": "Updating...",
|
||||
"template.mainPanel.editTrackersButton": "Edit Trackers",
|
||||
"template.mainPanel.settingsButton": "Settings",
|
||||
"global.none": "None",
|
||||
"global.add": "Add",
|
||||
"global.cancel": "Cancel",
|
||||
"global.listView": "List view",
|
||||
"global.gridView": "Grid view",
|
||||
"global.save": "Save",
|
||||
"global.status":"Status",
|
||||
"global.inventory":"Inventory",
|
||||
"global.quests":"Quests",
|
||||
"global.info":"Info",
|
||||
"infobox.noData.title": "No data yet",
|
||||
"infobox.noData.instruction": "Generate a new response in the roleplay or switch to \"Separate Generation\" in Settings to access and click the \"Refresh RPG Info\" button",
|
||||
"infobox.recentEvents.title": "Recent Events",
|
||||
"infobox.recentEvents.addEventPlaceholder": "Add event...",
|
||||
"inventory.section.onPerson": "On Person",
|
||||
"inventory.section.stored": "Stored",
|
||||
"inventory.section.assets": "Assets",
|
||||
"inventory.onPerson.empty": "No items carried",
|
||||
"inventory.onPerson.title": "Items Currently Carried",
|
||||
"inventory.onPerson.addItemButton": "Add Item",
|
||||
"inventory.onPerson.addItemPlaceholder": "Enter item name...",
|
||||
"inventory.stored.title": "Storage Locations",
|
||||
"inventory.stored.addLocationButton": "Add Location",
|
||||
"inventory.stored.addLocationPlaceholder": "Enter location name...",
|
||||
"inventory.stored.saveButton": "Save",
|
||||
"inventory.stored.empty": "No storage locations yet. Click \"Add Location\" to create one.",
|
||||
"inventory.stored.noItems": "No items stored here",
|
||||
"inventory.stored.addItemToLocationPlaceholder": "Enter item name...",
|
||||
"inventory.stored.addItemButton": "Add Item",
|
||||
"inventory.stored.confirmRemoveLocationMessage": "Remove \"${location}\"? This will delete all items stored there.",
|
||||
"inventory.stored.confirmRemoveLocationConfirmButton": "Confirm",
|
||||
"inventory.assets.empty": "No assets owned",
|
||||
"inventory.assets.title": "Vehicles, Property & Major Possessions",
|
||||
"inventory.assets.addAssetModalTitle": "Add Asset",
|
||||
"inventory.assets.addAssetButton": "Add Asset",
|
||||
"inventory.assets.addAssetPlaceholder": "Enter asset name...",
|
||||
"inventory.assets.description": "Assets include vehicles (cars, motorcycles), property (homes, apartments), and major equipment (workshop tools, special items).",
|
||||
"quests.section.main": "Main Quest",
|
||||
"quests.section.optional": "Optional Quests",
|
||||
"quests.main.title": "Main Quests",
|
||||
"quests.main.addQuestButton": "Add Quest",
|
||||
"quests.main.addQuestPlaceholder": "Enter main quest title...",
|
||||
"quests.main.empty": "No active main quests",
|
||||
"quests.main.hint": "The main quest represents your primary objective in the story.",
|
||||
"quests.optional.title": "Optional Quests",
|
||||
"quests.optional.addQuestButton": "Add Quest",
|
||||
"quests.optional.addQuestPlaceholder": "Enter optional quest title...",
|
||||
"quests.optional.empty": "No active optional quests",
|
||||
"quests.optional.hint": "Optional quests are side objectives that complement your main story."
|
||||
}
|
||||
@@ -0,0 +1,165 @@
|
||||
{
|
||||
"settings.language.label": "語言",
|
||||
"settings.language.option.en": "English",
|
||||
"settings.language.option.zh-tw": "繁體中文",
|
||||
"settings.extensionEnabled": "啟用 RPG Companion",
|
||||
"settings.note": "切換開關以啟用/停用 RPG Companion。其他設定可在面板內配置。",
|
||||
"template.settingsTitle": "RPG Companion 設定",
|
||||
"template.settingsModal.themeTitle": "主題",
|
||||
"template.settingsModal.themeLabel": "可選主題:",
|
||||
"template.settingsModal.themeOptions.default": "預設",
|
||||
"template.settingsModal.themeOptions.sciFi": "科幻 (合成波)",
|
||||
"template.settingsModal.themeOptions.fantasy": "奇幻 (古樸羊皮紙)",
|
||||
"template.settingsModal.themeOptions.cyberpunk": "賽博朋克 (霓虹網格)",
|
||||
"template.settingsModal.themeOptions.custom": "自訂",
|
||||
"template.settingsModal.themeOptions.custom.background": "背景:",
|
||||
"template.settingsModal.themeOptions.custom.accent": "強調色:",
|
||||
"template.settingsModal.themeOptions.custom.text": "文字:",
|
||||
"template.settingsModal.themeOptions.custom.highlight": "高亮:",
|
||||
"template.settingsModal.theme.statBarLow": "屬性條顏色 (低):",
|
||||
"template.settingsModal.theme.statBarLowNote": "屬性在 0% 時的顏色",
|
||||
"template.settingsModal.theme.statBarHigh": "屬性條顏色 (高):",
|
||||
"template.settingsModal.theme.statBarHighNote": "屬性在 100% 時的顏色",
|
||||
"template.settingsModal.displayTitle": "顯示設定",
|
||||
"template.settingsModal.displayNote": "使用擴充功能標籤來啟用/停用 RPG Companion 擴充功能。",
|
||||
"template.settingsModal.display.panelPosition": "面板位置:",
|
||||
"template.settingsModal.display.panelPositionOptions.right": "右側邊欄",
|
||||
"template.settingsModal.display.panelPositionOptions.left": "左側邊欄",
|
||||
"template.settingsModal.display.toggleAutoUpdate": "訊息後自動更新",
|
||||
"template.settingsModal.display.showUserStats": "顯示 user 屬性",
|
||||
"template.settingsModal.display.showInfoBox": "顯示資訊框",
|
||||
"template.settingsModal.display.showPresentCharacters": "顯示在場角色",
|
||||
"template.settingsModal.display.showInventory": "顯示物品欄",
|
||||
"template.settingsModal.display.showThoughtsInChat": "在聊天中顯示想法",
|
||||
"template.settingsModal.display.showThoughtsInChatNote": "將角色想法顯示為其訊息旁的泡泡",
|
||||
"template.settingsModal.display.alwaysShowThoughtBubble": "始終顯示想法泡泡",
|
||||
"template.settingsModal.display.alwaysShowThoughtBubbleNote": "自動展開想法泡泡",
|
||||
"template.settingsModal.display.enableAnimations": "啟用動畫",
|
||||
"template.settingsModal.display.enableAnimationsNote": "屬性、內容更新和擲骰的動畫效果",
|
||||
"template.settingsModal.display.showPlotProgressionButtons": "顯示劇情推進按鈕(QR)",
|
||||
"template.settingsModal.display.showPlotProgressionButtonsNote": "在聊天輸入框上方顯示劇情推進提示按鈕(QR)",
|
||||
"template.settingsModal.display.enableDebugMode": "Debug Mode",
|
||||
"template.settingsModal.display.enableDebugModeNote": "UI 面板中顯示日誌,對於故障排除很有用。",
|
||||
"template.settingsModal.advancedTitle": "進階",
|
||||
"template.settingsModal.advanced.generationMode": "生成模式:",
|
||||
"template.settingsModal.advanced.generationModeOptions.together": "同時生成",
|
||||
"template.settingsModal.advanced.generationModeOptions.separate": "單獨生成",
|
||||
"template.settingsModal.advanced.generationModeNote": "同時生成:將 RPG 追蹤添加到主要提示詞中一同生成。單獨生成:分開生成 RPG 數據。(就是手動或自動的差別)。",
|
||||
"template.settingsModal.advanced.contextMessages": "上下文訊息:",
|
||||
"template.settingsModal.advanced.contextMessagesNote": "包含的最近訊息數量(僅限單獨生成模式)",
|
||||
"template.settingsModal.advanced.memoryBatchSize": "記憶批次大小:",
|
||||
"template.settingsModal.advanced.memoryBatchSizeNote": "在記憶回憶中每批處理的訊息數量",
|
||||
"template.settingsModal.advanced.useSeparatePreset": "使用 RPG Companion 追蹤預設模型(設置次要模型)",
|
||||
"template.settingsModal.advanced.useSeparatePresetNote": "僅限單獨生成模式。啟用後將使用“RPG Companion Trackers”預設中綁定的模型,而不是您的主要 API 模型。生成期間會自動切換預設,之後會恢復原使用預設。請在“RPG Companion Trackers”預設中選擇次要模型,並確保“將預設綁定到 API 連接”切換已開啟(在導入/導出預設按鈕旁邊)。",
|
||||
"template.settingsModal.advanced.skipInjections": "在引導生成期間跳過注入:",
|
||||
"template.settingsModal.advanced.skipInjectionsOptions.none": "從不跳過",
|
||||
"template.settingsModal.advanced.skipInjectionsOptions.impersonation": "僅在模擬請求時跳過",
|
||||
"template.settingsModal.advanced.skipInjectionsOptions.guided": "始終跳過引導",
|
||||
"template.settingsModal.advanced.skipInjectionsNote": "當設置後,擴充功能在檢測到引導生成(通過 `instruct` 或 `quiet_prompt`)時,將根據所選模式不注入追蹤提示詞、範例或 HTML 指令。當與 GuidedGenerations 或類似擴充功能一起使用時非常有用。",
|
||||
"template.settingsModal.advanced.customHtmlPromptTitle": "自訂 HTML 提示詞:",
|
||||
"template.settingsModal.advanced.restoreDefaultHtmlPrompt": "恢復預設",
|
||||
"template.settingsModal.advanced.customHtmlPromptNote": "自訂啟用“啟用沉浸式 HTML”時注入的 HTML 提示詞。上方顯示預設提示詞 - 您可以直接編輯或完全替換它。點擊“恢復預設”以重置。這會影響所有生成模式(同時、單獨和劇情推進)。",
|
||||
"template.settingsModal.advanced.clearCache": "清除擴充功能快取",
|
||||
"template.settingsModal.advanced.resetFabPositions": "重置按鈕位置",
|
||||
"template.settingsModal.advanced.resetFabPositionsNote": "將所有浮動操作按鈕(切換、刷新、調試)重置為預設的左上位置。如果按鈕在螢幕外,這會很有用。",
|
||||
"template.trackerEditorModal.title": "追蹤器編輯",
|
||||
"template.trackerEditorModal.tabs.userStats": "User 屬性",
|
||||
"template.trackerEditorModal.tabs.infoBox": "資訊框",
|
||||
"template.trackerEditorModal.tabs.presentCharacters": "在場角色",
|
||||
"template.trackerEditorModal.buttons.reset": "重置為預設值",
|
||||
"template.trackerEditorModal.buttons.cancel": "取消",
|
||||
"template.trackerEditorModal.buttons.save": "保存並應用",
|
||||
"template.trackerEditorModal.userStatsTab.customStatsTitle": "自訂屬性",
|
||||
"template.trackerEditorModal.userStatsTab.addCustomStatButton": "添加自訂屬性",
|
||||
"template.trackerEditorModal.userStatsTab.rpgAttributesTitle": "RPG 屬性",
|
||||
"template.trackerEditorModal.userStatsTab.enableRpgAttributes": "啟用 RPG 屬性",
|
||||
"template.trackerEditorModal.userStatsTab.alwaysIncludeAttributes": "始終發送屬性(prompt)",
|
||||
"template.trackerEditorModal.userStatsTab.alwaysIncludeAttributesNote": "將 RPG 屬性始終包含在提示詞中,即使它們未顯示在面板上也一樣。",
|
||||
"template.trackerEditorModal.userStatsTab.addAttributeButton": "添加屬性",
|
||||
"template.trackerEditorModal.userStatsTab.statusSectionTitle": "狀態欄",
|
||||
"template.trackerEditorModal.userStatsTab.enableStatusSection": "啟用狀態欄",
|
||||
"template.trackerEditorModal.userStatsTab.showMoodEmoji": "顯示心情emoji",
|
||||
"template.trackerEditorModal.userStatsTab.statusFieldsLabel": "狀態欄欄位(以逗號分隔):",
|
||||
"template.trackerEditorModal.userStatsTab.skillsSectionTitle": "技能欄",
|
||||
"template.trackerEditorModal.userStatsTab.enableSkillsSection": "啟用技能欄",
|
||||
"template.trackerEditorModal.userStatsTab.skillsLabelLabel": "技能欄標籤:",
|
||||
"template.trackerEditorModal.userStatsTab.skillsListLabel": " 技能列表(以逗號分隔):",
|
||||
"template.trackerEditorModal.infoBoxTab.widgetsTitle": "小工具",
|
||||
"template.trackerEditorModal.infoBoxTab.dateWidget": "日期",
|
||||
"template.trackerEditorModal.infoBoxTab.weatherWidget": "天氣",
|
||||
"template.trackerEditorModal.infoBoxTab.temperatureWidget": "溫度",
|
||||
"template.trackerEditorModal.infoBoxTab.timeWidget": "時間",
|
||||
"template.trackerEditorModal.infoBoxTab.locationWidget": "位置",
|
||||
"template.trackerEditorModal.infoBoxTab.recentEventsWidget": "近期事件",
|
||||
"template.trackerEditorModal.presentCharactersTab.relationshipStatusTitle": "關係狀態",
|
||||
"template.trackerEditorModal.presentCharactersTab.relationshipStatusHint": "定義關係類型,並在角色頭像上顯示對應的表情符號",
|
||||
"template.trackerEditorModal.presentCharactersTab.newRelationshipButton": "新增關係類型",
|
||||
"template.trackerEditorModal.presentCharactersTab.appearanceDemeanorTitle": "外觀與當前行為舉止",
|
||||
"template.trackerEditorModal.presentCharactersTab.appearanceDemeanorHint": "角色名稱下方顯示的字段,以 | 分隔。",
|
||||
"template.trackerEditorModal.presentCharactersTab.addCustomFieldButton": "添加自訂字段",
|
||||
"template.trackerEditorModal.presentCharactersTab.thoughtsConfigTitle": "內心話配置",
|
||||
"template.trackerEditorModal.presentCharactersTab.enableCharacterThoughts": "啟用角色內心話",
|
||||
"template.trackerEditorModal.presentCharactersTab.thoughtsLabelLabel": "內心話標籤:",
|
||||
"template.trackerEditorModal.presentCharactersTab.aiInstructionLabel": "內心話提示詞:",
|
||||
"template.trackerEditorModal.presentCharactersTab.characterStatsTitle": "角色屬性",
|
||||
"template.trackerEditorModal.presentCharactersTab.trackCharacterStats": "啟用角色屬性",
|
||||
"template.trackerEditorModal.presentCharactersTab.characterStatsHint": "建立統計資料以追蹤每個角色(以彩色長條圖顯示)",
|
||||
"template.trackerEditorModal.presentCharactersTab.addCharacterStatButton": "添加角色屬性",
|
||||
"template.mainPanel.title": "RPG Companion",
|
||||
"template.mainPanel.lastRoll": "上次擲骰:",
|
||||
"template.mainPanel.clearLastRoll": "清除上次擲骰",
|
||||
"template.mainPanel.enableImmersiveHtml": "啟用沉浸式 HTML",
|
||||
"template.mainPanel.refreshRpgInfo": "刷新資訊",
|
||||
"template.mainPanel.updating": "更新中...",
|
||||
"template.mainPanel.editTrackersButton": "追蹤器編輯",
|
||||
"template.mainPanel.settingsButton": "設定",
|
||||
"global.none": "None",
|
||||
"global.add": "添加",
|
||||
"global.cancel": "取消",
|
||||
"global.save": "保存",
|
||||
"global.listView": "清單檢視",
|
||||
"global.gridView": "格子檢視",
|
||||
"global.status": "狀態欄",
|
||||
"global.inventory": "物品欄",
|
||||
"global.quests": "任務",
|
||||
"global.info":"資訊",
|
||||
"infobox.noData.title": "無資訊可顯示",
|
||||
"infobox.noData.instruction": "在RP中產生新的回复,或在設定中切換到“單獨生成”,然後點擊“刷新資訊”按鈕。",
|
||||
"infobox.recentEvents.title": "近期事件",
|
||||
"infobox.recentEvents.addEventPlaceholder": "添加事件...",
|
||||
"inventory.section.onPerson": "隨身物品",
|
||||
"inventory.section.stored": "倉庫物品",
|
||||
"inventory.section.assets": "資產",
|
||||
"inventory.onPerson.empty": "這裡什麼都沒有 (⚲□⚲)",
|
||||
"inventory.onPerson.title": "攜帶的物品",
|
||||
"inventory.onPerson.addItemButton": "添加物品",
|
||||
"inventory.onPerson.addItemPlaceholder": "輸入物品名稱...",
|
||||
"inventory.stored.title": "倉庫位置",
|
||||
"inventory.stored.addLocationButton": "添加倉庫",
|
||||
"inventory.stored.addLocationPlaceholder": "輸入倉庫名稱...",
|
||||
"inventory.stored.saveButton": "保存",
|
||||
"inventory.stored.empty": "沒有倉庫 (⚲□⚲), 點擊\"添加倉庫\"來新增一個倉庫",
|
||||
"inventory.stored.noItems": "這個倉庫是空的 (⚲□⚲)",
|
||||
"inventory.stored.addItemToLocationPlaceholder": "輸入物品名稱...",
|
||||
"inventory.stored.addItemButton": "添加物品",
|
||||
"inventory.stored.confirmRemoveLocationMessage": "確定要刪除這個倉庫嗎?這將移除所有其中的物品。",
|
||||
"inventory.stored.confirmRemoveLocationConfirmButton": "刪除",
|
||||
"inventory.assets.empty": "沒有資產 (⚲□⚲) 好窮",
|
||||
"inventory.assets.title": "車輛、房產及主要財產",
|
||||
"inventory.assets.addAssetModalTitle": "添加資產",
|
||||
"inventory.assets.addAssetButton": "添加資產",
|
||||
"inventory.assets.addAssetPlaceholder": "輸入資產名稱...",
|
||||
"inventory.assets.description": "資產包括車輛(汽車、摩托車)、房產(房屋、公寓)和主要設備(車間工具、特殊物品)。",
|
||||
"quests.section.main": "主線任務",
|
||||
"quests.section.optional": "支線任務",
|
||||
"quests.main.title": "主線任務",
|
||||
"quests.main.addQuestButton": "添加主要任務",
|
||||
"quests.main.addQuestPlaceholder": "輸入主線任務名稱...",
|
||||
"quests.main.empty": "當前無主要任務 (ฅ˙Ⱉ˙ฅ)",
|
||||
"quests.main.hint": "主線任務代表你在故事中的主要目標。",
|
||||
"quests.optional.title": "支線任務",
|
||||
"quests.optional.addQuestButton": "添加支線任務",
|
||||
"quests.optional.addQuestPlaceholder": "輸入支線任務名稱...",
|
||||
"quests.optional.empty": "當前無支線任務 (ʘ̆ʚʘ̆)",
|
||||
"quests.optional.hint": "支線任務是補充主線劇情的支線目標。"
|
||||
}
|
||||
@@ -9,6 +9,7 @@ import {
|
||||
setPendingDiceRoll
|
||||
} from '../../core/state.js';
|
||||
import { saveSettings } from '../../core/persistence.js';
|
||||
import { i18n } from '../../core/i18n.js';
|
||||
|
||||
/**
|
||||
* Rolls the dice and displays result.
|
||||
@@ -85,10 +86,13 @@ export async function executeRollCommand(command) {
|
||||
*/
|
||||
export function updateDiceDisplay() {
|
||||
const lastRoll = extensionSettings.lastDiceRoll;
|
||||
const label = i18n.getTranslation('template.mainPanel.lastRoll') || 'Last Roll: ';
|
||||
const noneValue = i18n.getTranslation('global.none') || 'None';
|
||||
|
||||
if (lastRoll) {
|
||||
$('#rpg-last-roll-text').text(`Last Roll (${lastRoll.formula}): ${lastRoll.total}`);
|
||||
$('#rpg-last-roll-text').text(`${label}(${lastRoll.formula}): ${lastRoll.total}`);
|
||||
} else {
|
||||
$('#rpg-last-roll-text').text('Last Roll: None');
|
||||
$('#rpg-last-roll-text').text(label + noneValue);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -22,6 +22,7 @@ import { renderInfoBox } from '../rendering/infoBox.js';
|
||||
import { renderThoughts } from '../rendering/thoughts.js';
|
||||
import { renderInventory } from '../rendering/inventory.js';
|
||||
import { renderQuests } from '../rendering/quests.js';
|
||||
import { i18n } from '../../core/i18n.js';
|
||||
|
||||
// Store the original preset name to restore after tracker generation
|
||||
let originalPresetName = null;
|
||||
@@ -104,8 +105,8 @@ export async function updateRPGData(renderUserStats, renderInfoBox, renderThough
|
||||
|
||||
// Update button to show "Updating..." state
|
||||
const $updateBtn = $('#rpg-manual-update');
|
||||
const originalHtml = $updateBtn.html();
|
||||
$updateBtn.html('<i class="fa-solid fa-spinner fa-spin"></i> Updating...').prop('disabled', true);
|
||||
const updatingText = i18n.getTranslation('template.mainPanel.updating') || 'Updating...';
|
||||
$updateBtn.html(`<i class="fa-solid fa-spinner fa-spin"></i> ${updatingText}`).prop('disabled', true);
|
||||
|
||||
// Save current preset name before switching (if we're going to switch)
|
||||
if (extensionSettings.useSeparatePreset) {
|
||||
@@ -229,7 +230,8 @@ export async function updateRPGData(renderUserStats, renderInfoBox, renderThough
|
||||
|
||||
// Restore button to original state
|
||||
const $updateBtn = $('#rpg-manual-update');
|
||||
$updateBtn.html('<i class="fa-solid fa-sync"></i> Refresh RPG Info').prop('disabled', false);
|
||||
const refreshText = i18n.getTranslation('template.mainPanel.refreshRpgInfo') || 'Refresh RPG Info';
|
||||
$updateBtn.html(`<i class="fa-solid fa-sync"></i> ${refreshText}`).prop('disabled', false);
|
||||
|
||||
// Reset the flag after tracker generation completes
|
||||
// This ensures the flag persists through both main generation AND tracker generation
|
||||
|
||||
@@ -11,6 +11,7 @@ import {
|
||||
$infoBoxContainer
|
||||
} from '../../core/state.js';
|
||||
import { saveChatData } from '../../core/persistence.js';
|
||||
import { i18n } from '../../core/i18n.js';
|
||||
|
||||
/**
|
||||
* Helper to separate emoji from text in a string
|
||||
@@ -72,8 +73,8 @@ export function renderInfoBox() {
|
||||
const placeholderHtml = `
|
||||
<div class="rpg-dashboard rpg-dashboard-row-1">
|
||||
<div class="rpg-dashboard-widget rpg-placeholder-widget">
|
||||
<div class="rpg-placeholder-text">No data yet</div>
|
||||
<div class="rpg-placeholder-hint">Generate a new response in the roleplay or switch to "Separate Generation" in Settings to access and click the "Refresh RPG Info" button</div>
|
||||
<div class="rpg-placeholder-text" data-i18n-key="infobox.noData.title">${i18n.getTranslation('infobox.noData.title')}</div>
|
||||
<div class="rpg-placeholder-hint" data-i18n-key="infobox.noData.instruction">${i18n.getTranslation('infobox.noData.instruction')}</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
@@ -447,7 +448,7 @@ export function renderInfoBox() {
|
||||
<div class="rpg-notebook-ring"></div>
|
||||
<div class="rpg-notebook-ring"></div>
|
||||
</div>
|
||||
<div class="rpg-notebook-title">Recent Events</div>
|
||||
<div class="rpg-notebook-title" data-i18n-key="infobox.recentEvents.title">${i18n.getTranslation('infobox.recentEvents.title')}</div>
|
||||
<div class="rpg-notebook-lines">
|
||||
`;
|
||||
|
||||
@@ -466,7 +467,7 @@ export function renderInfoBox() {
|
||||
html += `
|
||||
<div class="rpg-notebook-line rpg-event-add">
|
||||
<span class="rpg-bullet">+</span>
|
||||
<span class="rpg-event-text rpg-editable rpg-event-placeholder" contenteditable="true" data-field="event${i + 1}" title="Click to add event">Add event...</span>
|
||||
<span class="rpg-event-text rpg-editable rpg-event-placeholder" contenteditable="true" data-field="event${i + 1}" title="Click to add event" data-i18n-key="infobox.recentEvents.addEventPlaceholder">${i18n.getTranslation('infobox.recentEvents.addEventPlaceholder')}</span>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ import { extensionSettings, $inventoryContainer } from '../../core/state.js';
|
||||
import { getInventoryRenderOptions, restoreFormStates } from '../interaction/inventoryActions.js';
|
||||
import { updateInventoryItem } from '../interaction/inventoryEdit.js';
|
||||
import { parseItems } from '../../utils/itemParser.js';
|
||||
import { i18n } from '../../core/i18n.js';
|
||||
|
||||
// Type imports
|
||||
/** @typedef {import('../../types/inventory.js').InventoryV2} InventoryV2 */
|
||||
@@ -30,14 +31,14 @@ export function getLocationId(locationName) {
|
||||
export function renderInventorySubTabs(activeTab = 'onPerson') {
|
||||
return `
|
||||
<div class="rpg-inventory-subtabs">
|
||||
<button class="rpg-inventory-subtab ${activeTab === 'onPerson' ? 'active' : ''}" data-tab="onPerson">
|
||||
On Person
|
||||
<button class="rpg-inventory-subtab ${activeTab === 'onPerson' ? 'active' : ''}" data-tab="onPerson" data-i18n-key="inventory.section.onPerson">
|
||||
${i18n.getTranslation('inventory.section.onPerson')}
|
||||
</button>
|
||||
<button class="rpg-inventory-subtab ${activeTab === 'stored' ? 'active' : ''}" data-tab="stored">
|
||||
Stored
|
||||
<button class="rpg-inventory-subtab ${activeTab === 'stored' ? 'active' : ''}" data-tab="stored" data-i18n-key="inventory.section.stored">
|
||||
${i18n.getTranslation('inventory.section.stored')}
|
||||
</button>
|
||||
<button class="rpg-inventory-subtab ${activeTab === 'assets' ? 'active' : ''}" data-tab="assets">
|
||||
Assets
|
||||
<button class="rpg-inventory-subtab ${activeTab === 'assets' ? 'active' : ''}" data-tab="assets" data-i18n-key="inventory.section.assets">
|
||||
${i18n.getTranslation('inventory.section.assets')}
|
||||
</button>
|
||||
</div>
|
||||
`;
|
||||
@@ -54,7 +55,7 @@ export function renderOnPersonView(onPersonItems, viewMode = 'list') {
|
||||
|
||||
let itemsHtml = '';
|
||||
if (items.length === 0) {
|
||||
itemsHtml = '<div class="rpg-inventory-empty">No items carried</div>';
|
||||
itemsHtml = `<div class="rpg-inventory-empty" data-i18n-key="inventory.onPerson.empty">${i18n.getTranslation('inventory.onPerson.empty')}</div>`;
|
||||
} else {
|
||||
if (viewMode === 'grid') {
|
||||
// Grid view: card-style items
|
||||
@@ -84,30 +85,30 @@ export function renderOnPersonView(onPersonItems, viewMode = 'list') {
|
||||
return `
|
||||
<div class="rpg-inventory-section" data-section="onPerson">
|
||||
<div class="rpg-inventory-header">
|
||||
<h4>Items Currently Carried</h4>
|
||||
<h4 data-i18n-key="inventory.onPerson.title">${i18n.getTranslation('inventory.onPerson.title')}</h4>
|
||||
<div class="rpg-inventory-header-actions">
|
||||
<div class="rpg-view-toggle">
|
||||
<button class="rpg-view-btn ${viewMode === 'list' ? 'active' : ''}" data-action="switch-view" data-field="onPerson" data-view="list" title="List view">
|
||||
<button class="rpg-view-btn ${viewMode === 'list' ? 'active' : ''}" data-action="switch-view" data-field="onPerson" data-view="list" title="${i18n.getTranslation('global.listView')}">
|
||||
<i class="fa-solid fa-list"></i>
|
||||
</button>
|
||||
<button class="rpg-view-btn ${viewMode === 'grid' ? 'active' : ''}" data-action="switch-view" data-field="onPerson" data-view="grid" title="Grid view">
|
||||
<button class="rpg-view-btn ${viewMode === 'grid' ? 'active' : ''}" data-action="switch-view" data-field="onPerson" data-view="grid" title="${i18n.getTranslation('global.gridView')}">
|
||||
<i class="fa-solid fa-th"></i>
|
||||
</button>
|
||||
</div>
|
||||
<button class="rpg-inventory-add-btn" data-action="add-item" data-field="onPerson" title="Add new item">
|
||||
<i class="fa-solid fa-plus"></i> Add Item
|
||||
<i class="fa-solid fa-plus"></i> <span data-i18n-key="inventory.onPerson.addItemButton">${i18n.getTranslation('inventory.onPerson.addItemButton')}</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="rpg-inventory-content">
|
||||
<div class="rpg-inline-form" id="rpg-add-item-form-onPerson" style="display: none;">
|
||||
<input type="text" class="rpg-inline-input" id="rpg-new-item-onPerson" placeholder="Enter item name..." />
|
||||
<input type="text" class="rpg-inline-input" id="rpg-new-item-onPerson" placeholder="${i18n.getTranslation('inventory.onPerson.addItemPlaceholder')}" data-i18n-placeholder-key="inventory.onPerson.addItemPlaceholder" />
|
||||
<div class="rpg-inline-buttons">
|
||||
<button class="rpg-inline-btn rpg-inline-cancel" data-action="cancel-add-item" data-field="onPerson">
|
||||
<i class="fa-solid fa-times"></i> Cancel
|
||||
<i class="fa-solid fa-times"></i> <span data-i18n-key="global.cancel">${i18n.getTranslation('global.cancel')}</span>
|
||||
</button>
|
||||
<button class="rpg-inline-btn rpg-inline-save" data-action="save-add-item" data-field="onPerson">
|
||||
<i class="fa-solid fa-check"></i> Add
|
||||
<i class="fa-solid fa-check"></i> <span data-i18n-key="global.add">${i18n.getTranslation('global.add')}</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
@@ -132,30 +133,30 @@ export function renderStoredView(stored, collapsedLocations = [], viewMode = 'li
|
||||
let html = `
|
||||
<div class="rpg-inventory-section" data-section="stored">
|
||||
<div class="rpg-inventory-header">
|
||||
<h4>Storage Locations</h4>
|
||||
<h4 data-i18n-key="inventory.stored.title">${i18n.getTranslation('inventory.stored.title')}</h4>
|
||||
<div class="rpg-inventory-header-actions">
|
||||
<div class="rpg-view-toggle">
|
||||
<button class="rpg-view-btn ${viewMode === 'list' ? 'active' : ''}" data-action="switch-view" data-field="stored" data-view="list" title="List view">
|
||||
<button class="rpg-view-btn ${viewMode === 'list' ? 'active' : ''}" data-action="switch-view" data-field="stored" data-view="list" title="${i18n.getTranslation('global.listView')}">
|
||||
<i class="fa-solid fa-list"></i>
|
||||
</button>
|
||||
<button class="rpg-view-btn ${viewMode === 'grid' ? 'active' : ''}" data-action="switch-view" data-field="stored" data-view="grid" title="Grid view">
|
||||
<button class="rpg-view-btn ${viewMode === 'grid' ? 'active' : ''}" data-action="switch-view" data-field="stored" data-view="grid" title="${i18n.getTranslation('global.gridView')}">
|
||||
<i class="fa-solid fa-th"></i>
|
||||
</button>
|
||||
</div>
|
||||
<button class="rpg-inventory-add-btn" data-action="add-location" title="Add new storage location">
|
||||
<i class="fa-solid fa-plus"></i> Add Location
|
||||
<i class="fa-solid fa-plus"></i> <span data-i18n-key="inventory.stored.addLocationButton">${i18n.getTranslation('inventory.stored.addLocationButton')}</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="rpg-inventory-content">
|
||||
<div class="rpg-inline-form" id="rpg-add-location-form" style="display: none;">
|
||||
<input type="text" class="rpg-inline-input" id="rpg-new-location-name" placeholder="Enter location name..." />
|
||||
<input type="text" class="rpg-inline-input" id="rpg-new-location-name" placeholder="${i18n.getTranslation('inventory.stored.addLocationPlaceholder')}" data-i18n-placeholder-key="inventory.stored.addLocationPlaceholder" />
|
||||
<div class="rpg-inline-buttons">
|
||||
<button class="rpg-inline-btn rpg-inline-cancel" data-action="cancel-add-location">
|
||||
<i class="fa-solid fa-times"></i> Cancel
|
||||
<i class="fa-solid fa-times"></i> <span data-i18n-key="global.cancel">${i18n.getTranslation('global.cancel')}</span>
|
||||
</button>
|
||||
<button class="rpg-inline-btn rpg-inline-save" data-action="save-add-location">
|
||||
<i class="fa-solid fa-check"></i> Save
|
||||
<i class="fa-solid fa-check"></i> <span data-i18n-key="inventory.stored.saveButton">${i18n.getTranslation('inventory.stored.saveButton')}</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
@@ -163,8 +164,8 @@ export function renderStoredView(stored, collapsedLocations = [], viewMode = 'li
|
||||
|
||||
if (locations.length === 0) {
|
||||
html += `
|
||||
<div class="rpg-inventory-empty">
|
||||
No storage locations yet. Click "Add Location" to create one.
|
||||
<div class="rpg-inventory-empty" data-i18n-key="inventory.stored.empty">
|
||||
${i18n.getTranslation('inventory.stored.empty')}
|
||||
</div>
|
||||
`;
|
||||
} else {
|
||||
@@ -176,7 +177,7 @@ export function renderStoredView(stored, collapsedLocations = [], viewMode = 'li
|
||||
|
||||
let itemsHtml = '';
|
||||
if (items.length === 0) {
|
||||
itemsHtml = '<div class="rpg-inventory-empty">No items stored here</div>';
|
||||
itemsHtml = `<div class="rpg-inventory-empty" data-i18n-key="inventory.stored.noItems">${i18n.getTranslation('inventory.stored.noItems')}</div>`;
|
||||
} else {
|
||||
if (viewMode === 'grid') {
|
||||
// Grid view: card-style items
|
||||
@@ -218,13 +219,13 @@ export function renderStoredView(stored, collapsedLocations = [], viewMode = 'li
|
||||
</div>
|
||||
<div class="rpg-storage-content" ${isCollapsed ? 'style="display:none;"' : ''}>
|
||||
<div class="rpg-inline-form" id="rpg-add-item-form-stored-${locationId}" style="display: none;">
|
||||
<input type="text" class="rpg-inline-input rpg-location-item-input" data-location="${escapeHtml(location)}" placeholder="Enter item name..." />
|
||||
<input type="text" class="rpg-inline-input rpg-location-item-input" data-location="${escapeHtml(location)}" placeholder="${i18n.getTranslation('inventory.stored.addItemToLocationPlaceholder')}" data-i18n-placeholder-key="inventory.stored.addItemToLocationPlaceholder" />
|
||||
<div class="rpg-inline-buttons">
|
||||
<button class="rpg-inline-btn rpg-inline-cancel" data-action="cancel-add-item" data-field="stored" data-location="${escapeHtml(location)}">
|
||||
<i class="fa-solid fa-times"></i> Cancel
|
||||
<i class="fa-solid fa-times"></i> <span data-i18n-key="global.cancel">${i18n.getTranslation('global.cancel')}</span>
|
||||
</button>
|
||||
<button class="rpg-inline-btn rpg-inline-save" data-action="save-add-item" data-field="stored" data-location="${escapeHtml(location)}">
|
||||
<i class="fa-solid fa-check"></i> Add
|
||||
<i class="fa-solid fa-check"></i> <span data-i18n-key="global.add">${i18n.getTranslation('global.add')}</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
@@ -233,18 +234,18 @@ export function renderStoredView(stored, collapsedLocations = [], viewMode = 'li
|
||||
</div>
|
||||
<div class="rpg-storage-add-item-container">
|
||||
<button class="rpg-inventory-add-btn" data-action="add-item" data-field="stored" data-location="${escapeHtml(location)}" title="Add item to this location">
|
||||
<i class="fa-solid fa-plus"></i> Add Item
|
||||
<i class="fa-solid fa-plus"></i> <span data-i18n-key="inventory.stored.addItemButton">${i18n.getTranslation('inventory.stored.addItemButton')}</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="rpg-inline-confirmation" id="rpg-remove-confirm-${locationId}" style="display: none;">
|
||||
<p>Remove "${escapeHtml(location)}"? This will delete all items stored there.</p>
|
||||
<p>${i18n.getTranslation('inventory.stored.confirmRemoveLocationMessage', { location: escapeHtml(location) })}</p>
|
||||
<div class="rpg-inline-buttons">
|
||||
<button class="rpg-inline-btn rpg-inline-cancel" data-action="cancel-remove-location" data-location="${escapeHtml(location)}">
|
||||
<i class="fa-solid fa-times"></i> Cancel
|
||||
<i class="fa-solid fa-times"></i> <span data-i18n-key="global.cancel">${i18n.getTranslation('global.cancel')}</span>
|
||||
</button>
|
||||
<button class="rpg-inline-btn rpg-inline-confirm" data-action="confirm-remove-location" data-location="${escapeHtml(location)}">
|
||||
<i class="fa-solid fa-check"></i> Confirm
|
||||
<i class="fa-solid fa-check"></i> <span data-i18n-key="inventory.stored.confirmRemoveLocationConfirmButton">${i18n.getTranslation('inventory.stored.confirmRemoveLocationConfirmButton')}</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
@@ -272,7 +273,7 @@ export function renderAssetsView(assets, viewMode = 'list') {
|
||||
|
||||
let itemsHtml = '';
|
||||
if (items.length === 0) {
|
||||
itemsHtml = '<div class="rpg-inventory-empty">No assets owned</div>';
|
||||
itemsHtml = `<div class="rpg-inventory-empty" data-i18n-key="inventory.assets.empty">${i18n.getTranslation('inventory.assets.empty')}</div>`;
|
||||
} else {
|
||||
if (viewMode === 'grid') {
|
||||
// Grid view: card-style items
|
||||
@@ -289,7 +290,7 @@ export function renderAssetsView(assets, viewMode = 'list') {
|
||||
itemsHtml = items.map((item, index) => `
|
||||
<div class="rpg-item-row" data-field="assets" data-index="${index}">
|
||||
<span class="rpg-item-name rpg-editable" contenteditable="true" data-field="assets" data-index="${index}" title="Click to edit">${escapeHtml(item)}</span>
|
||||
<button class="rpg-item-remove" data-action="remove-item" data-field="assets" data-index="${index}" title="Remove asset">
|
||||
<button class="rpg-item-remove" data-action="remove-item" data-field="assets" data-index="${index}" title="${i18n.getTranslation('inventory.assets.removeAssetTitle')}">
|
||||
<i class="fa-solid fa-times"></i>
|
||||
</button>
|
||||
</div>
|
||||
@@ -302,30 +303,30 @@ export function renderAssetsView(assets, viewMode = 'list') {
|
||||
return `
|
||||
<div class="rpg-inventory-section" data-section="assets">
|
||||
<div class="rpg-inventory-header">
|
||||
<h4>Vehicles, Property & Major Possessions</h4>
|
||||
<h4 data-i18n-key="inventory.assets.title">${i18n.getTranslation('inventory.assets.title')}</h4>
|
||||
<div class="rpg-inventory-header-actions">
|
||||
<div class="rpg-view-toggle">
|
||||
<button class="rpg-view-btn ${viewMode === 'list' ? 'active' : ''}" data-action="switch-view" data-field="assets" data-view="list" title="List view">
|
||||
<button class="rpg-view-btn ${viewMode === 'list' ? 'active' : ''}" data-action="switch-view" data-field="assets" data-view="list" title="${i18n.getTranslation('global.listView')}">
|
||||
<i class="fa-solid fa-list"></i>
|
||||
</button>
|
||||
<button class="rpg-view-btn ${viewMode === 'grid' ? 'active' : ''}" data-action="switch-view" data-field="assets" data-view="grid" title="Grid view">
|
||||
<button class="rpg-view-btn ${viewMode === 'grid' ? 'active' : ''}" data-action="switch-view" data-field="assets" data-view="grid" title="${i18n.getTranslation('global.gridView')}">
|
||||
<i class="fa-solid fa-th"></i>
|
||||
</button>
|
||||
</div>
|
||||
<button class="rpg-inventory-add-btn" data-action="add-item" data-field="assets" title="Add new asset">
|
||||
<i class="fa-solid fa-plus"></i> Add Asset
|
||||
<i class="fa-solid fa-plus"></i> <span data-i18n-key="inventory.assets.addAssetButton">${i18n.getTranslation('inventory.assets.addAssetButton')}</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="rpg-inventory-content">
|
||||
<div class="rpg-inline-form" id="rpg-add-item-form-assets" style="display: none;">
|
||||
<input type="text" class="rpg-inline-input" id="rpg-new-item-assets" placeholder="Enter asset name..." />
|
||||
<input type="text" class="rpg-inline-input" id="rpg-new-item-assets" placeholder="${i18n.getTranslation('inventory.assets.addAssetPlaceholder')}" data-i18n-placeholder-key="inventory.assets.addAssetPlaceholder" />
|
||||
<div class="rpg-inline-buttons">
|
||||
<button class="rpg-inline-btn rpg-inline-cancel" data-action="cancel-add-item" data-field="assets">
|
||||
<i class="fa-solid fa-times"></i> Cancel
|
||||
<i class="fa-solid fa-times"></i> <span data-i18n-key="global.cancel">${i18n.getTranslation('global.cancel')}</span>
|
||||
</button>
|
||||
<button class="rpg-inline-btn rpg-inline-save" data-action="save-add-item" data-field="assets">
|
||||
<i class="fa-solid fa-check"></i> Add
|
||||
<i class="fa-solid fa-check"></i> <span data-i18n-key="global.add">${i18n.getTranslation('global.add')}</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
@@ -334,8 +335,7 @@ export function renderAssetsView(assets, viewMode = 'list') {
|
||||
</div>
|
||||
<div class="rpg-inventory-hint">
|
||||
<i class="fa-solid fa-info-circle"></i>
|
||||
Assets include vehicles (cars, motorcycles), property (homes, apartments),
|
||||
and major equipment (workshop tools, special items).
|
||||
<span data-i18n-key="inventory.assets.description">${i18n.getTranslation('inventory.assets.description')}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
|
||||
import { extensionSettings, $questsContainer } from '../../core/state.js';
|
||||
import { saveSettings } from '../../core/persistence.js';
|
||||
import { i18n } from '../../core/i18n.js';
|
||||
|
||||
/**
|
||||
* HTML escape helper
|
||||
@@ -25,11 +26,11 @@ function escapeHtml(text) {
|
||||
export function renderQuestsSubTabs(activeTab = 'main') {
|
||||
return `
|
||||
<div class="rpg-quests-subtabs">
|
||||
<button class="rpg-quests-subtab ${activeTab === 'main' ? 'active' : ''}" data-tab="main">
|
||||
Main Quest
|
||||
<button class="rpg-quests-subtab ${activeTab === 'main' ? 'active' : ''}" data-tab="main" data-i18n-key="quests.section.main">
|
||||
${i18n.getTranslation('quests.section.main')}
|
||||
</button>
|
||||
<button class="rpg-quests-subtab ${activeTab === 'optional' ? 'active' : ''}" data-tab="optional">
|
||||
Optional Quests
|
||||
<button class="rpg-quests-subtab ${activeTab === 'optional' ? 'active' : ''}" data-tab="optional" data-i18n-key="quests.section.optional">
|
||||
${i18n.getTranslation('quests.section.optional')}
|
||||
</button>
|
||||
</div>
|
||||
`;
|
||||
@@ -47,9 +48,9 @@ export function renderMainQuestView(mainQuest) {
|
||||
return `
|
||||
<div class="rpg-quest-section">
|
||||
<div class="rpg-quest-header">
|
||||
<h3 class="rpg-quest-section-title">Main Quests</h3>
|
||||
${!hasQuest ? `<button class="rpg-add-quest-btn" data-action="add-quest" data-field="main" title="Add main quests">
|
||||
<i class="fa-solid fa-plus"></i> Add Quest
|
||||
<h3 class="rpg-quest-section-title" data-i18n-key="quests.main.title">${i18n.getTranslation('quests.main.title')}</h3>
|
||||
${!hasQuest ? `<button class="rpg-add-quest-btn" data-action="add-quest" data-field="main" title="${i18n.getTranslation('quests.main.addQuestTitle')}">
|
||||
<i class="fa-solid fa-plus"></i> <span data-i18n-key="global.add">${i18n.getTranslation('global.add')}</span>
|
||||
</button>` : ''}
|
||||
</div>
|
||||
<div class="rpg-quest-content">
|
||||
@@ -58,10 +59,10 @@ export function renderMainQuestView(mainQuest) {
|
||||
<input type="text" class="rpg-inline-input" id="rpg-edit-quest-main" value="${escapeHtml(questDisplay)}" />
|
||||
<div class="rpg-inline-buttons">
|
||||
<button class="rpg-inline-btn rpg-inline-cancel" data-action="cancel-edit-quest" data-field="main">
|
||||
<i class="fa-solid fa-times"></i> Cancel
|
||||
<i class="fa-solid fa-times"></i> <span data-i18n-key="global.cancel">${i18n.getTranslation('global.cancel')}</span>
|
||||
</button>
|
||||
<button class="rpg-inline-btn rpg-inline-save" data-action="save-edit-quest" data-field="main">
|
||||
<i class="fa-solid fa-check"></i> Save
|
||||
<i class="fa-solid fa-check"></i> <span data-i18n-key="global.save">${i18n.getTranslation('global.save')}</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
@@ -78,22 +79,22 @@ export function renderMainQuestView(mainQuest) {
|
||||
</div>
|
||||
` : `
|
||||
<div class="rpg-inline-form" id="rpg-add-quest-form-main" style="display: none;">
|
||||
<input type="text" class="rpg-inline-input" id="rpg-new-quest-main" placeholder="Enter main quests title..." />
|
||||
<input type="text" class="rpg-inline-input" id="rpg-new-quest-main" placeholder="${i18n.getTranslation('quests.main.addQuestPlaceholder')}" data-i18n-placeholder-key="quests.main.addQuestPlaceholder" />
|
||||
<div class="rpg-inline-actions">
|
||||
<button class="rpg-inline-btn rpg-inline-cancel" data-action="cancel-add-quest" data-field="main">
|
||||
<i class="fa-solid fa-times"></i> Cancel
|
||||
<i class="fa-solid fa-times"></i> <span data-i18n-key="global.cancel">${i18n.getTranslation('global.cancel')}</span>
|
||||
</button>
|
||||
<button class="rpg-inline-btn rpg-inline-save" data-action="save-add-quest" data-field="main">
|
||||
<i class="fa-solid fa-check"></i> Add
|
||||
<i class="fa-solid fa-check"></i> <span data-i18n-key="global.add">${i18n.getTranslation('global.add')}</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="rpg-quest-empty">No active main quests</div>
|
||||
<div class="rpg-quest-empty" data-i18n-key="quests.main.empty">${i18n.getTranslation('quests.main.empty')}</div>
|
||||
`}
|
||||
</div>
|
||||
<div class="rpg-quest-hint">
|
||||
<i class="fa-solid fa-lightbulb"></i>
|
||||
The main quests represent your primary objective in the story.
|
||||
<span data-i18n-key="quests.main.hint">${i18n.getTranslation('quests.main.hint')}</span>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
@@ -109,7 +110,7 @@ export function renderOptionalQuestsView(optionalQuests) {
|
||||
|
||||
let questsHtml = '';
|
||||
if (quests.length === 0) {
|
||||
questsHtml = '<div class="rpg-quest-empty">No active optional quests</div>';
|
||||
questsHtml = `<div class="rpg-quest-empty" data-i18n-key="quests.optional.empty">${i18n.getTranslation('quests.optional.empty')}</div>`;
|
||||
} else {
|
||||
questsHtml = quests.map((quest, index) => `
|
||||
<div class="rpg-quest-item" data-field="optional" data-index="${index}">
|
||||
@@ -126,20 +127,20 @@ export function renderOptionalQuestsView(optionalQuests) {
|
||||
return `
|
||||
<div class="rpg-quest-section">
|
||||
<div class="rpg-quest-header">
|
||||
<h3 class="rpg-quest-section-title">Optional Quests</h3>
|
||||
<button class="rpg-add-quest-btn" data-action="add-quest" data-field="optional" title="Add optional quest">
|
||||
<i class="fa-solid fa-plus"></i> Add Quest
|
||||
<h3 class="rpg-quest-section-title" data-i18n-key="quests.optional.title">${i18n.getTranslation('quests.optional.title')}</h3>
|
||||
<button class="rpg-add-quest-btn" data-action="add-quest" data-field="optional" title="${i18n.getTranslation('quests.optional.addQuestTitle')}">
|
||||
<i class="fa-solid fa-plus"></i> <span data-i18n-key="global.add">${i18n.getTranslation('global.add')}</span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="rpg-quest-content">
|
||||
<div class="rpg-inline-form" id="rpg-add-quest-form-optional" style="display: none;">
|
||||
<input type="text" class="rpg-inline-input" id="rpg-new-quest-optional" placeholder="Enter optional quest title..." />
|
||||
<input type="text" class="rpg-inline-input" id="rpg-new-quest-optional" placeholder="${i18n.getTranslation('quests.optional.addQuestPlaceholder')}" data-i18n-placeholder-key="quests.optional.addQuestPlaceholder" />
|
||||
<div class="rpg-inline-buttons">
|
||||
<button class="rpg-inline-btn rpg-inline-cancel" data-action="cancel-add-quest" data-field="optional">
|
||||
<i class="fa-solid fa-times"></i> Cancel
|
||||
<i class="fa-solid fa-times"></i> <span data-i18n-key="global.cancel">${i18n.getTranslation('global.cancel')}</span>
|
||||
</button>
|
||||
<button class="rpg-inline-btn rpg-inline-save" data-action="save-add-quest" data-field="optional">
|
||||
<i class="fa-solid fa-check"></i> Add
|
||||
<i class="fa-solid fa-check"></i> <span data-i18n-key="global.add">${i18n.getTranslation('global.add')}</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
@@ -148,7 +149,7 @@ export function renderOptionalQuestsView(optionalQuests) {
|
||||
</div>
|
||||
<div class="rpg-quest-hint">
|
||||
<i class="fa-solid fa-info-circle"></i>
|
||||
Optional quests are side objectives that complement your main story.
|
||||
<span data-i18n-key="quests.optional.hint">${i18n.getTranslation('quests.optional.hint')}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -3,6 +3,8 @@
|
||||
* Handles desktop-specific UI functionality: tab navigation
|
||||
*/
|
||||
|
||||
import { i18n } from '../../core/i18n.js';
|
||||
|
||||
/**
|
||||
* Sets up desktop tab navigation for organizing content.
|
||||
* Only runs on desktop viewports (>1000px).
|
||||
@@ -34,15 +36,15 @@ export function setupDesktopTabs() {
|
||||
<div class="rpg-tabs-nav">
|
||||
<button class="rpg-tab-btn active" data-tab="status">
|
||||
<i class="fa-solid fa-chart-simple"></i>
|
||||
<span>Status</span>
|
||||
<span data-i18n-key="global.status">Status</span>
|
||||
</button>
|
||||
<button class="rpg-tab-btn" data-tab="inventory">
|
||||
<i class="fa-solid fa-box"></i>
|
||||
<span>Inventory</span>
|
||||
<span data-i18n-key="global.inventory">Inventory</span>
|
||||
</button>
|
||||
<button class="rpg-tab-btn" data-tab="quests">
|
||||
<i class="fa-solid fa-scroll"></i>
|
||||
<span>Quests</span>
|
||||
<span data-i18n-key="global.quests">Quests</span>
|
||||
</button>
|
||||
</div>
|
||||
`);
|
||||
@@ -86,6 +88,7 @@ export function setupDesktopTabs() {
|
||||
|
||||
// Replace content box with tabs container
|
||||
$contentBox.html('').append($tabsContainer);
|
||||
i18n.applyTranslations($tabsContainer[0]);
|
||||
|
||||
// Handle tab switching
|
||||
$tabNav.find('.rpg-tab-btn').on('click', function() {
|
||||
|
||||
@@ -11,6 +11,7 @@ import {
|
||||
$thoughtsContainer,
|
||||
$inventoryContainer
|
||||
} from '../../core/state.js';
|
||||
import { i18n } from '../../core/i18n.js';
|
||||
|
||||
/**
|
||||
* Toggles the visibility of plot buttons based on settings.
|
||||
@@ -92,6 +93,7 @@ export function updateCollapseToggleIcon() {
|
||||
*/
|
||||
export function setupCollapseToggle() {
|
||||
const $collapseToggle = $('#rpg-collapse-toggle');
|
||||
$collapseToggle.attr('title', i18n.getTranslation('template.mainPanel.collapseExpand'));
|
||||
const $panel = $('#rpg-companion-panel');
|
||||
const $icon = $collapseToggle.find('i');
|
||||
|
||||
|
||||
@@ -7,6 +7,43 @@ import { extensionSettings } from '../../core/state.js';
|
||||
import { saveSettings } from '../../core/persistence.js';
|
||||
import { closeMobilePanelWithAnimation, updateCollapseToggleIcon } from './layout.js';
|
||||
import { setupDesktopTabs, removeDesktopTabs } from './desktop.js';
|
||||
import { i18n } from '../../core/i18n.js';
|
||||
|
||||
/**
|
||||
* Updates the text labels of the mobile navigation tabs based on the current language.
|
||||
*/
|
||||
export function updateMobileTabLabels() {
|
||||
const $tabs = $('.rpg-mobile-tabs .rpg-mobile-tab');
|
||||
if ($tabs.length === 0) return;
|
||||
|
||||
$tabs.each(function() {
|
||||
const $tab = $(this);
|
||||
const tabName = $tab.data('tab');
|
||||
let translationKey = '';
|
||||
|
||||
switch (tabName) {
|
||||
case 'stats':
|
||||
translationKey = 'global.status';
|
||||
break;
|
||||
case 'info':
|
||||
translationKey = 'global.info';
|
||||
break;
|
||||
case 'inventory':
|
||||
translationKey = 'global.inventory';
|
||||
break;
|
||||
case 'quests':
|
||||
translationKey = 'global.quests';
|
||||
break;
|
||||
}
|
||||
|
||||
if (translationKey) {
|
||||
const translation = i18n.getTranslation(translationKey);
|
||||
if (translation) {
|
||||
$tab.find('span').text(translation);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets up the mobile toggle button (FAB) with drag functionality.
|
||||
@@ -547,19 +584,19 @@ export function setupMobileTabs() {
|
||||
|
||||
// Tab 1: Stats (User Stats only)
|
||||
if (hasStats) {
|
||||
tabs.push('<button class="rpg-mobile-tab active" data-tab="stats"><i class="fa-solid fa-chart-bar"></i><span>Stats</span></button>');
|
||||
tabs.push('<button class="rpg-mobile-tab active" data-tab="stats"><i class="fa-solid fa-chart-bar"></i><span>' + i18n.getTranslation('global.status') + '</span></button>');
|
||||
}
|
||||
// Tab 2: Info (Info Box + Character Thoughts)
|
||||
if (hasInfo) {
|
||||
tabs.push('<button class="rpg-mobile-tab ' + (tabs.length === 0 ? 'active' : '') + '" data-tab="info"><i class="fa-solid fa-book"></i><span>Info</span></button>');
|
||||
tabs.push('<button class="rpg-mobile-tab ' + (tabs.length === 0 ? 'active' : '') + '" data-tab="info"><i class="fa-solid fa-book"></i><span>' + i18n.getTranslation('global.info') + '</span></button>');
|
||||
}
|
||||
// Tab 3: Inventory
|
||||
if (hasInventory) {
|
||||
tabs.push('<button class="rpg-mobile-tab ' + (tabs.length === 0 ? 'active' : '') + '" data-tab="inventory"><i class="fa-solid fa-box"></i><span>Inventory</span></button>');
|
||||
tabs.push('<button class="rpg-mobile-tab ' + (tabs.length === 0 ? 'active' : '') + '" data-tab="inventory"><i class="fa-solid fa-box"></i><span>' + i18n.getTranslation('global.inventory') + '</span></button>');
|
||||
}
|
||||
// Tab 4: Quests
|
||||
if (hasQuests) {
|
||||
tabs.push('<button class="rpg-mobile-tab ' + (tabs.length === 0 ? 'active' : '') + '" data-tab="quests"><i class="fa-solid fa-scroll"></i><span>Quests</span></button>');
|
||||
tabs.push('<button class="rpg-mobile-tab ' + (tabs.length === 0 ? 'active' : '') + '" data-tab="quests"><i class="fa-solid fa-scroll"></i><span>' + i18n.getTranslation('global.quests') + '</span></button>');
|
||||
}
|
||||
|
||||
const $tabNav = $('<div class="rpg-mobile-tabs">' + tabs.join('') + '</div>');
|
||||
|
||||
@@ -23,6 +23,7 @@ import {
|
||||
updateDiceDisplay as updateDiceDisplayCore,
|
||||
addDiceQuickReply as addDiceQuickReplyCore
|
||||
} from '../features/dice.js';
|
||||
import { i18n } from '../../core/i18n.js';
|
||||
|
||||
/**
|
||||
* Modern DiceModal ES6 Class
|
||||
@@ -318,6 +319,7 @@ export function setupDiceRoller() {
|
||||
e.stopPropagation(); // Prevent opening the dice popup
|
||||
clearDiceRollCore();
|
||||
});
|
||||
$('#rpg-clear-dice').attr('title', i18n.getTranslation('template.mainPanel.clearLastRoll'));
|
||||
|
||||
return diceModal;
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* Tracker Editor Module
|
||||
* Provides UI for customizing tracker configurations
|
||||
*/
|
||||
|
||||
import { i18n } from '../../core/i18n.js';
|
||||
import { extensionSettings } from '../../core/state.js';
|
||||
import { saveSettings } from '../../core/persistence.js';
|
||||
import { renderUserStats } from '../rendering/userStats.js';
|
||||
@@ -205,7 +205,7 @@ function renderUserStatsTab() {
|
||||
let html = '<div class="rpg-editor-section">';
|
||||
|
||||
// Custom Stats section
|
||||
html += '<h4><i class="fa-solid fa-heart-pulse"></i> Custom Stats</h4>';
|
||||
html += `<h4><i class="fa-solid fa-heart-pulse"></i> ${i18n.getTranslation('template.trackerEditorModal.userStatsTab.customStatsTitle')}</h4>`;
|
||||
html += '<div class="rpg-editor-stats-list" id="rpg-editor-stats-list">';
|
||||
|
||||
config.customStats.forEach((stat, index) => {
|
||||
@@ -219,25 +219,25 @@ function renderUserStatsTab() {
|
||||
});
|
||||
|
||||
html += '</div>';
|
||||
html += '<button class="rpg-btn-secondary" id="rpg-add-stat"><i class="fa-solid fa-plus"></i> Add Custom Stat</button>';
|
||||
html += `<button class="rpg-btn-secondary" id="rpg-add-stat"><i class="fa-solid fa-plus"></i> ${i18n.getTranslation('template.trackerEditorModal.userStatsTab.addCustomStatButton')}</button>`;
|
||||
|
||||
// RPG Attributes section
|
||||
html += '<h4><i class="fa-solid fa-dice-d20"></i> RPG Attributes</h4>';
|
||||
html += `<h4><i class="fa-solid fa-dice-d20"></i> ${i18n.getTranslation('template.trackerEditorModal.userStatsTab.rpgAttributesTitle')}</h4>`;
|
||||
|
||||
// Enable/disable toggle for entire RPG Attributes section
|
||||
const showRPGAttributes = config.showRPGAttributes !== undefined ? config.showRPGAttributes : true;
|
||||
html += '<div class="rpg-editor-toggle-row">';
|
||||
html += `<input type="checkbox" id="rpg-show-rpg-attrs" ${showRPGAttributes ? 'checked' : ''}>`;
|
||||
html += '<label for="rpg-show-rpg-attrs">Enable RPG Attributes Section</label>';
|
||||
html += `<label for="rpg-show-rpg-attrs">${i18n.getTranslation('template.trackerEditorModal.userStatsTab.enableRpgAttributes')}</label>`;
|
||||
html += '</div>';
|
||||
|
||||
// Always send attributes toggle
|
||||
const alwaysSendAttributes = config.alwaysSendAttributes !== undefined ? config.alwaysSendAttributes : false;
|
||||
html += '<div class="rpg-editor-toggle-row">';
|
||||
html += `<input type="checkbox" id="rpg-always-send-attrs" ${alwaysSendAttributes ? 'checked' : ''}>`;
|
||||
html += '<label for="rpg-always-send-attrs">Always Include Attributes in Prompt</label>';
|
||||
html += `<label for="rpg-always-send-attrs">${i18n.getTranslation('template.trackerEditorModal.userStatsTab.alwaysIncludeAttributes')}</label>`;
|
||||
html += '</div>';
|
||||
html += '<small class="rpg-editor-note">If disabled, attributes are only sent when a dice roll is active.</small>';
|
||||
html += `<small class="rpg-editor-note">${i18n.getTranslation('template.trackerEditorModal.userStatsTab.alwaysIncludeAttributesNote')}</small>`;
|
||||
|
||||
html += '<div class="rpg-editor-stats-list" id="rpg-editor-attrs-list">';
|
||||
|
||||
@@ -268,34 +268,34 @@ function renderUserStatsTab() {
|
||||
});
|
||||
|
||||
html += '</div>';
|
||||
html += '<button class="rpg-btn-secondary" id="rpg-add-attr"><i class="fa-solid fa-plus"></i> Add Attribute</button>';
|
||||
html += `<button class="rpg-btn-secondary" id="rpg-add-attr"><i class="fa-solid fa-plus"></i> ${i18n.getTranslation('template.trackerEditorModal.userStatsTab.addAttributeButton')}</button>`;
|
||||
|
||||
// Status Section
|
||||
html += '<h4><i class="fa-solid fa-face-smile"></i> Status Section</h4>';
|
||||
html += `<h4><i class="fa-solid fa-face-smile"></i> ${i18n.getTranslation('template.trackerEditorModal.userStatsTab.statusSectionTitle')}</h4>`;
|
||||
html += '<div class="rpg-editor-toggle-row">';
|
||||
html += `<input type="checkbox" id="rpg-status-enabled" ${config.statusSection.enabled ? 'checked' : ''}>`;
|
||||
html += '<label for="rpg-status-enabled">Enable Status Section</label>';
|
||||
html += `<label for="rpg-status-enabled">${i18n.getTranslation('template.trackerEditorModal.userStatsTab.enableStatusSection')}</label>`;
|
||||
html += '</div>';
|
||||
|
||||
html += '<div class="rpg-editor-toggle-row">';
|
||||
html += `<input type="checkbox" id="rpg-mood-emoji" ${config.statusSection.showMoodEmoji ? 'checked' : ''}>`;
|
||||
html += '<label for="rpg-mood-emoji">Show Mood Emoji</label>';
|
||||
html += `<label for="rpg-mood-emoji">${i18n.getTranslation('template.trackerEditorModal.userStatsTab.showMoodEmoji')}</label>`;
|
||||
html += '</div>';
|
||||
|
||||
html += '<label>Status Fields (comma-separated):</label>';
|
||||
html += `<label>${i18n.getTranslation('template.trackerEditorModal.userStatsTab.statusFieldsLabel')}</label>`;
|
||||
html += `<input type="text" id="rpg-status-fields" value="${config.statusSection.customFields.join(', ')}" class="rpg-text-input" placeholder="e.g., Conditions, Appearance">`;
|
||||
|
||||
// Skills Section
|
||||
html += '<h4><i class="fa-solid fa-star"></i> Skills Section</h4>';
|
||||
html += `<h4><i class="fa-solid fa-star"></i> ${i18n.getTranslation('template.trackerEditorModal.userStatsTab.skillsSectionTitle')}</h4>`;
|
||||
html += '<div class="rpg-editor-toggle-row">';
|
||||
html += `<input type="checkbox" id="rpg-skills-enabled" ${config.skillsSection.enabled ? 'checked' : ''}>`;
|
||||
html += '<label for="rpg-skills-enabled">Enable Skills Section</label>';
|
||||
html += `<label for="rpg-skills-enabled">${i18n.getTranslation('template.trackerEditorModal.userStatsTab.enableSkillsSection')}</label>`;
|
||||
html += '</div>';
|
||||
|
||||
html += '<label>Skills Label:</label>';
|
||||
html += `<label>${i18n.getTranslation('template.trackerEditorModal.userStatsTab.skillsLabelLabel')}</label>`;
|
||||
html += `<input type="text" id="rpg-skills-label" value="${config.skillsSection.label}" class="rpg-text-input" placeholder="Skills">`;
|
||||
|
||||
html += '<label>Skills List (comma-separated):</label>';
|
||||
html += `<label>${i18n.getTranslation('template.trackerEditorModal.userStatsTab.skillsListLabel')}</label>`;
|
||||
const skillFields = config.skillsSection.customFields || [];
|
||||
html += `<input type="text" id="rpg-skills-fields" value="${skillFields.join(', ')}" class="rpg-text-input" placeholder="e.g., Stealth, Persuasion, Combat">`;
|
||||
|
||||
@@ -436,12 +436,12 @@ function renderInfoBoxTab() {
|
||||
const config = extensionSettings.trackerConfig.infoBox;
|
||||
let html = '<div class="rpg-editor-section">';
|
||||
|
||||
html += '<h4><i class="fa-solid fa-info-circle"></i> Widgets</h4>';
|
||||
html += `<h4><i class="fa-solid fa-info-circle"></i> ${i18n.getTranslation('template.trackerEditorModal.infoBoxTab.widgetsTitle')}</h4>`;
|
||||
|
||||
// Date widget
|
||||
html += '<div class="rpg-editor-widget-row">';
|
||||
html += `<input type="checkbox" id="rpg-widget-date" ${config.widgets.date.enabled ? 'checked' : ''}>`;
|
||||
html += '<label for="rpg-widget-date">Date</label>';
|
||||
html += `<label for="rpg-widget-date">${i18n.getTranslation('template.trackerEditorModal.infoBoxTab.dateWidget')}</label>`;
|
||||
html += '<select id="rpg-date-format" class="rpg-select-mini">';
|
||||
html += `<option value="Weekday, Month, Year" ${config.widgets.date.format === 'Weekday, Month, Year' ? 'selected' : ''}>Weekday, Month, Year</option>`;
|
||||
html += `<option value="dd/mm/yyyy" ${config.widgets.date.format === 'dd/mm/yyyy' ? 'selected' : ''}>dd/mm/yyyy</option>`;
|
||||
@@ -453,13 +453,13 @@ function renderInfoBoxTab() {
|
||||
// Weather widget
|
||||
html += '<div class="rpg-editor-widget-row">';
|
||||
html += `<input type="checkbox" id="rpg-widget-weather" ${config.widgets.weather.enabled ? 'checked' : ''}>`;
|
||||
html += '<label for="rpg-widget-weather">Weather</label>';
|
||||
html += `<label for="rpg-widget-weather">${i18n.getTranslation('template.trackerEditorModal.infoBoxTab.weatherWidget')}</label>`;
|
||||
html += '</div>';
|
||||
|
||||
// Temperature widget
|
||||
html += '<div class="rpg-editor-widget-row">';
|
||||
html += `<input type="checkbox" id="rpg-widget-temperature" ${config.widgets.temperature.enabled ? 'checked' : ''}>`;
|
||||
html += '<label for="rpg-widget-temperature">Temperature</label>';
|
||||
html += `<label for="rpg-widget-temperature">${i18n.getTranslation('template.trackerEditorModal.infoBoxTab.temperatureWidget')}</label>`;
|
||||
html += '<div class="rpg-radio-group">';
|
||||
html += `<label><input type="radio" name="temp-unit" value="C" ${config.widgets.temperature.unit === 'C' ? 'checked' : ''}> °C</label>`;
|
||||
html += `<label><input type="radio" name="temp-unit" value="F" ${config.widgets.temperature.unit === 'F' ? 'checked' : ''}> °F</label>`;
|
||||
@@ -469,19 +469,19 @@ function renderInfoBoxTab() {
|
||||
// Time widget
|
||||
html += '<div class="rpg-editor-widget-row">';
|
||||
html += `<input type="checkbox" id="rpg-widget-time" ${config.widgets.time.enabled ? 'checked' : ''}>`;
|
||||
html += '<label for="rpg-widget-time">Time</label>';
|
||||
html += `<label for="rpg-widget-time">${i18n.getTranslation('template.trackerEditorModal.infoBoxTab.timeWidget')}</label>`;
|
||||
html += '</div>';
|
||||
|
||||
// Location widget
|
||||
html += '<div class="rpg-editor-widget-row">';
|
||||
html += `<input type="checkbox" id="rpg-widget-location" ${config.widgets.location.enabled ? 'checked' : ''}>`;
|
||||
html += '<label for="rpg-widget-location">Location</label>';
|
||||
html += `<label for="rpg-widget-location">${i18n.getTranslation('template.trackerEditorModal.infoBoxTab.locationWidget')}</label>`;
|
||||
html += '</div>';
|
||||
|
||||
// Recent Events widget
|
||||
html += '<div class="rpg-editor-widget-row">';
|
||||
html += `<input type="checkbox" id="rpg-widget-events" ${config.widgets.recentEvents.enabled ? 'checked' : ''}>`;
|
||||
html += '<label for="rpg-widget-events">Recent Events</label>';
|
||||
html += `<label for="rpg-widget-events">${i18n.getTranslation('template.trackerEditorModal.infoBoxTab.recentEventsWidget')}</label>`;
|
||||
html += '</div>';
|
||||
|
||||
html += '</div>';
|
||||
@@ -537,8 +537,8 @@ function renderPresentCharactersTab() {
|
||||
let html = '<div class="rpg-editor-section">';
|
||||
|
||||
// Relationship Fields Section
|
||||
html += '<h4><i class="fa-solid fa-heart"></i> Relationship Status Fields</h4>';
|
||||
html += '<p class="rpg-editor-hint">Define relationship types with corresponding emojis shown on character portraits</p>';
|
||||
html += `<h4><i class="fa-solid fa-heart"></i> ${i18n.getTranslation('template.trackerEditorModal.presentCharactersTab.relationshipStatusTitle')}</h4>`;
|
||||
html += `<p class="rpg-editor-hint">${i18n.getTranslation('template.trackerEditorModal.presentCharactersTab.relationshipStatusHint')}</p>`;
|
||||
|
||||
html += '<div class="rpg-relationship-mapping-list" id="rpg-relationship-mapping-list">';
|
||||
// Show existing relationships as field → emoji pairs
|
||||
@@ -561,11 +561,11 @@ function renderPresentCharactersTab() {
|
||||
`;
|
||||
}
|
||||
html += '</div>';
|
||||
html += '<button class="rpg-btn-secondary" id="rpg-add-relationship"><i class="fa-solid fa-plus"></i> New Relationship</button>';
|
||||
html += `<button class="rpg-btn-secondary" id="rpg-add-relationship"><i class="fa-solid fa-plus"></i> ${i18n.getTranslation('template.trackerEditorModal.presentCharactersTab.newRelationshipButton')}</button>`;
|
||||
|
||||
// Custom Fields Section
|
||||
html += '<h4><i class="fa-solid fa-list"></i> Appearance/Demeanor Fields</h4>';
|
||||
html += '<p class="rpg-editor-hint">Fields shown below character name, separated by |</p>';
|
||||
html += `<h4><i class="fa-solid fa-list"></i> ${i18n.getTranslation('template.trackerEditorModal.presentCharactersTab.appearanceDemeanorTitle')}</h4>`;
|
||||
html += `<p class="rpg-editor-hint">${i18n.getTranslation('template.trackerEditorModal.presentCharactersTab.appearanceDemeanorHint')}</p>`;
|
||||
|
||||
html += '<div class="rpg-editor-fields-list" id="rpg-editor-fields-list">';
|
||||
|
||||
@@ -585,34 +585,34 @@ function renderPresentCharactersTab() {
|
||||
});
|
||||
|
||||
html += '</div>';
|
||||
html += '<button class="rpg-btn-secondary" id="rpg-add-field"><i class="fa-solid fa-plus"></i> Add Custom Field</button>';
|
||||
html += `<button class="rpg-btn-secondary" id="rpg-add-field"><i class="fa-solid fa-plus"></i> ${i18n.getTranslation('template.trackerEditorModal.presentCharactersTab.addCustomFieldButton')}</button>`;
|
||||
|
||||
// Thoughts Section
|
||||
html += '<h4><i class="fa-solid fa-comment-dots"></i> Thoughts Configuration</h4>';
|
||||
html += `<h4><i class="fa-solid fa-comment-dots"></i> ${i18n.getTranslation('template.trackerEditorModal.presentCharactersTab.thoughtsConfigTitle')}</h4>`;
|
||||
html += '<div class="rpg-editor-toggle-row">';
|
||||
html += `<input type="checkbox" id="rpg-thoughts-enabled" ${config.thoughts?.enabled ? 'checked' : ''}>`;
|
||||
html += '<label for="rpg-thoughts-enabled">Enable Character Thoughts</label>';
|
||||
html += `<label for="rpg-thoughts-enabled">${i18n.getTranslation('template.trackerEditorModal.presentCharactersTab.enableCharacterThoughts')}</label>`;
|
||||
html += '</div>';
|
||||
|
||||
html += '<div class="rpg-thoughts-config">';
|
||||
html += '<div class="rpg-editor-input-group">';
|
||||
html += '<label>Thoughts Label:</label>';
|
||||
html += `<label>${i18n.getTranslation('template.trackerEditorModal.presentCharactersTab.thoughtsLabelLabel')}</label>`;
|
||||
html += `<input type="text" id="rpg-thoughts-name" value="${config.thoughts?.name || 'Thoughts'}" placeholder="e.g., Thoughts, Inner Voice, Feelings">`;
|
||||
html += '</div>';
|
||||
html += '<div class="rpg-editor-input-group">';
|
||||
html += '<label>AI Instruction:</label>';
|
||||
html += `<label>${i18n.getTranslation('template.trackerEditorModal.presentCharactersTab.aiInstructionLabel')}</label>`;
|
||||
html += `<input type="text" id="rpg-thoughts-description" value="${config.thoughts?.description || 'Internal monologue (in first person POV, up to three sentences long)'}" placeholder="Description of what to generate">`;
|
||||
html += '</div>';
|
||||
html += '</div>';
|
||||
|
||||
// Character Stats
|
||||
html += '<h4><i class="fa-solid fa-chart-bar"></i> Character Stats</h4>';
|
||||
html += `<h4><i class="fa-solid fa-chart-bar"></i> ${i18n.getTranslation('template.trackerEditorModal.presentCharactersTab.characterStatsTitle')}</h4>`;
|
||||
html += '<div class="rpg-editor-toggle-row">';
|
||||
html += `<input type="checkbox" id="rpg-char-stats-enabled" ${config.characterStats?.enabled ? 'checked' : ''}>`;
|
||||
html += '<label for="rpg-char-stats-enabled">Track Character Stats</label>';
|
||||
html += `<label for="rpg-char-stats-enabled">${i18n.getTranslation('template.trackerEditorModal.presentCharactersTab.trackCharacterStats')}</label>`;
|
||||
html += '</div>';
|
||||
|
||||
html += '<p class="rpg-editor-hint">Create stats to track for each character (displayed as colored bars)</p>';
|
||||
html += `<p class="rpg-editor-hint">${i18n.getTranslation('template.trackerEditorModal.presentCharactersTab.characterStatsHint')}</p>`;
|
||||
html += '<div class="rpg-editor-fields-list" id="rpg-char-stats-list">';
|
||||
|
||||
const charStats = config.characterStats?.customStats || [];
|
||||
@@ -627,7 +627,7 @@ function renderPresentCharactersTab() {
|
||||
});
|
||||
|
||||
html += '</div>';
|
||||
html += '<button class="rpg-btn-secondary" id="rpg-add-char-stat"><i class="fa-solid fa-plus"></i> Add Character Stat</button>';
|
||||
html += `<button class="rpg-btn-secondary" id="rpg-add-char-stat"><i class="fa-solid fa-plus"></i> ${i18n.getTranslation('template.trackerEditorModal.presentCharactersTab.addCharacterStatButton')}</button>`;
|
||||
|
||||
html += '</div>';
|
||||
|
||||
|
||||
+72
-72
@@ -10,7 +10,7 @@
|
||||
<div class="rpg-panel-header">
|
||||
<h3>
|
||||
<i class="fa-solid fa-dice-d20"></i>
|
||||
RPG Companion
|
||||
<span data-i18n-key="template.mainPanel.title">RPG Companion</span>
|
||||
</h3>
|
||||
</div>
|
||||
|
||||
@@ -18,8 +18,8 @@
|
||||
<!-- Dice Roll Display -->
|
||||
<div id="rpg-dice-display" class="rpg-dice-display">
|
||||
<i class="fa-solid fa-dice"></i>
|
||||
<span id="rpg-last-roll-text">Last Roll: None</span>
|
||||
<button id="rpg-clear-dice" class="rpg-clear-dice-btn" title="Clear last roll">×</button>
|
||||
<span id="rpg-last-roll-text"></span>
|
||||
<button id="rpg-clear-dice" class="rpg-clear-dice-btn">×</button>
|
||||
</div>
|
||||
|
||||
<!-- Unified Game Content Box -->
|
||||
@@ -64,22 +64,22 @@
|
||||
<label class="rpg-toggle-label">
|
||||
<input type="checkbox" id="rpg-toggle-html-prompt">
|
||||
<i class="fa-solid fa-code"></i>
|
||||
<span>Enable Immersive HTML</span>
|
||||
<span data-i18n-key="template.mainPanel.enableImmersiveHtml">Enable Immersive HTML</span>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<!-- Manual Update Button -->
|
||||
<button id="rpg-manual-update" class="rpg-btn-primary rpg-manual-update-btn">
|
||||
<i class="fa-solid fa-sync"></i> Refresh RPG Info
|
||||
<i class="fa-solid fa-sync"></i> <span data-i18n-key="template.mainPanel.refreshRpgInfo">Refresh RPG Info</span>
|
||||
</button>
|
||||
|
||||
<!-- Settings and Edit Trackers Buttons Row -->
|
||||
<div class="rpg-settings-buttons-row">
|
||||
<button id="rpg-open-tracker-editor" class="rpg-btn-settings rpg-btn-half">
|
||||
<i class="fa-solid fa-sliders"></i> Edit Trackers
|
||||
<i class="fa-solid fa-sliders"></i> <span data-i18n-key="template.mainPanel.editTrackersButton">Edit Trackers</span>
|
||||
</button>
|
||||
<button id="rpg-open-settings" class="rpg-btn-settings rpg-btn-half">
|
||||
<i class="fa-solid fa-gear"></i> Settings
|
||||
<i class="fa-solid fa-gear"></i> <span data-i18n-key="template.mainPanel.settingsButton">Settings</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
@@ -92,184 +92,184 @@
|
||||
<header class="rpg-settings-popup-header">
|
||||
<h3 id="rpg-settings-title">
|
||||
<i class="fa-solid fa-gear" aria-hidden="true"></i>
|
||||
<span>RPG Companion Settings</span>
|
||||
<span data-i18n-key="template.settingsTitle">RPG Companion Settings</span>
|
||||
</h3>
|
||||
<button id="rpg-close-settings" class="rpg-popup-close" type="button" aria-label="Close settings">×</button>
|
||||
</header>
|
||||
<div class="rpg-settings-popup-body">
|
||||
<div class="rpg-settings-group">
|
||||
<h4><i class="fa-solid fa-palette" aria-hidden="true"></i> Theme</h4>
|
||||
<h4 data-i18n-key="template.settingsModal.themeTitle"><i class="fa-solid fa-palette" aria-hidden="true"></i> Theme</h4>
|
||||
<div class="rpg-setting-row">
|
||||
<label for="rpg-theme-select">Visual Theme:</label>
|
||||
<label for="rpg-theme-select" data-i18n-key="template.settingsModal.themeLabel">Visual Theme:</label>
|
||||
<select id="rpg-theme-select" class="rpg-select">
|
||||
<option value="default">Default</option>
|
||||
<option value="sci-fi">Sci-Fi (Synthwave)</option>
|
||||
<option value="fantasy">Fantasy (Rustic Parchment)</option>
|
||||
<option value="cyberpunk">Cyberpunk (Neon Grid)</option>
|
||||
<option value="custom">Custom</option>
|
||||
<option value="default" data-i18n-key="template.settingsModal.themeOptions.default">Default</option>
|
||||
<option value="sci-fi" data-i18n-key="template.settingsModal.themeOptions.sciFi">Sci-Fi (Synthwave)</option>
|
||||
<option value="fantasy" data-i18n-key="template.settingsModal.themeOptions.fantasy">Fantasy (Rustic Parchment)</option>
|
||||
<option value="cyberpunk" data-i18n-key="template.settingsModal.themeOptions.cyberpunk">Cyberpunk (Neon Grid)</option>
|
||||
<option value="custom" data-i18n-key="template.settingsModal.themeOptions.custom">Custom</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<!-- Custom Theme Colors (Hidden by default) -->
|
||||
<div id="rpg-custom-colors" class="rpg-custom-colors" style="display: none;">
|
||||
<div class="rpg-setting-row">
|
||||
<label for="rpg-custom-bg">Background:</label>
|
||||
<label for="rpg-custom-bg" data-i18n-key="template.settingsModal.themeOptions.custom.background">Background:</label>
|
||||
<input type="color" id="rpg-custom-bg" value="#1a1a2e" />
|
||||
</div>
|
||||
<div class="rpg-setting-row">
|
||||
<label for="rpg-custom-accent">Accent:</label>
|
||||
<label for="rpg-custom-accent" data-i18n-key="template.settingsModal.themeOptions.custom.accent">Accent:</label>
|
||||
<input type="color" id="rpg-custom-accent" value="#16213e" />
|
||||
</div>
|
||||
<div class="rpg-setting-row">
|
||||
<label for="rpg-custom-text">Text:</label>
|
||||
<label for="rpg-custom-text" data-i18n-key="template.settingsModal.themeOptions.custom.text">Text:</label>
|
||||
<input type="color" id="rpg-custom-text" value="#eaeaea" />
|
||||
</div>
|
||||
<div class="rpg-setting-row">
|
||||
<label for="rpg-custom-highlight">Highlight:</label>
|
||||
<label for="rpg-custom-highlight" data-i18n-key="template.settingsModal.themeOptions.custom.highlight">Highlight:</label>
|
||||
<input type="color" id="rpg-custom-highlight" value="#e94560" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="rpg-setting-row">
|
||||
<label for="rpg-stat-bar-color-low">Stat Bar Color (Low):</label>
|
||||
<label for="rpg-stat-bar-color-low" data-i18n-key="template.settingsModal.theme.statBarLow">Stat Bar Color (Low):</label>
|
||||
<input type="color" id="rpg-stat-bar-color-low" value="#cc3333" />
|
||||
<small>Color when stats are at 0%</small>
|
||||
<small data-i18n-key="template.settingsModal.theme.statBarLowNote">Color when stats are at 0%</small>
|
||||
</div>
|
||||
|
||||
<div class="rpg-setting-row">
|
||||
<label for="rpg-stat-bar-color-high">Stat Bar Color (High):</label>
|
||||
<label for="rpg-stat-bar-color-high" data-i18n-key="template.settingsModal.theme.statBarHigh">Stat Bar Color (High):</label>
|
||||
<input type="color" id="rpg-stat-bar-color-high" value="#33cc66" />
|
||||
<small>Color when stats are at 100%</small>
|
||||
<small data-i18n-key="template.settingsModal.theme.statBarHighNote">Color when stats are at 100%</small>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="rpg-settings-group">
|
||||
<h4><i class="fa-solid fa-toggle-on" aria-hidden="true"></i> Display Options</h4>
|
||||
<small class="notes" style="display: block; margin-bottom: 10px;">
|
||||
<h4 data-i18n-key="template.settingsModal.displayTitle"><i class="fa-solid fa-toggle-on" aria-hidden="true"></i> Display Options</h4>
|
||||
<small class="notes" style="display: block; margin-bottom: 10px;" data-i18n-key="template.settingsModal.displayNote">
|
||||
<i class="fa-solid fa-info-circle" aria-hidden="true"></i> Use the Extensions tab to enable/disable the RPG Companion extension.
|
||||
</small>
|
||||
|
||||
<div class="rpg-setting-row">
|
||||
<label for="rpg-position-select">Panel Position:</label>
|
||||
<label for="rpg-position-select" data-i18n-key="template.settingsModal.display.panelPosition">Panel Position:</label>
|
||||
<select id="rpg-position-select" class="rpg-select">
|
||||
<option value="right">Right Sidebar</option>
|
||||
<option value="left">Left Sidebar</option>
|
||||
<option value="right" data-i18n-key="template.settingsModal.display.panelPositionOptions.right">Right Sidebar</option>
|
||||
<option value="left" data-i18n-key="template.settingsModal.display.panelPositionOptions.left">Left Sidebar</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<label class="checkbox_label">
|
||||
<input type="checkbox" id="rpg-toggle-auto-update" />
|
||||
<span>Auto-update after messages</span>
|
||||
<span data-i18n-key="template.settingsModal.display.toggleAutoUpdate">Auto-update after messages</span>
|
||||
</label>
|
||||
|
||||
<label class="checkbox_label">
|
||||
<input type="checkbox" id="rpg-toggle-user-stats" />
|
||||
<span>Show User Stats</span>
|
||||
<span data-i18n-key="template.settingsModal.display.showUserStats">Show User Stats</span>
|
||||
</label>
|
||||
|
||||
<label class="checkbox_label">
|
||||
<input type="checkbox" id="rpg-toggle-info-box" />
|
||||
<span>Show Info Box</span>
|
||||
<span data-i18n-key="template.settingsModal.display.showInfoBox">Show Info Box</span>
|
||||
</label>
|
||||
|
||||
<label class="checkbox_label">
|
||||
<input type="checkbox" id="rpg-toggle-thoughts" />
|
||||
<span>Show Present Characters</span>
|
||||
<span data-i18n-key="template.settingsModal.display.showPresentCharacters">Show Present Characters</span>
|
||||
</label>
|
||||
|
||||
<label class="checkbox_label">
|
||||
<input type="checkbox" id="rpg-toggle-inventory" />
|
||||
<span>Show Inventory</span>
|
||||
<span data-i18n-key="template.settingsModal.display.showInventory">Show Inventory</span>
|
||||
</label>
|
||||
|
||||
<label class="checkbox_label">
|
||||
<input type="checkbox" id="rpg-toggle-thoughts-in-chat" />
|
||||
<span>Show Thoughts in Chat</span>
|
||||
<span data-i18n-key="template.settingsModal.display.showThoughtsInChat">Show Thoughts in Chat</span>
|
||||
</label>
|
||||
<small style="display: block; margin-left: 24px; margin-top: -8px; color: #888; font-size: 11px;">
|
||||
<small style="display: block; margin-left: 24px; margin-top: -8px; color: #888; font-size: 11px;" data-i18n-key="template.settingsModal.display.showThoughtsInChatNote">
|
||||
Display character thoughts as overlay bubbles next to their messages
|
||||
</small>
|
||||
|
||||
<label class="checkbox_label">
|
||||
<input type="checkbox" id="rpg-toggle-always-show-bubble" />
|
||||
<span>Always Show Thought Bubble</span>
|
||||
<span data-i18n-key="template.settingsModal.display.alwaysShowThoughtBubble">Always Show Thought Bubble</span>
|
||||
</label>
|
||||
<small style="display: block; margin-left: 24px; margin-top: -8px; color: #888; font-size: 11px;">
|
||||
<small style="display: block; margin-left: 24px; margin-top: -8px; color: #888; font-size: 11px;" data-i18n-key="template.settingsModal.display.alwaysShowThoughtBubbleNote">
|
||||
Auto-expand thought bubble without clicking the icon first
|
||||
</small>
|
||||
|
||||
<label class="checkbox_label">
|
||||
<input type="checkbox" id="rpg-toggle-animations" />
|
||||
<span>Enable Animations</span>
|
||||
<span data-i18n-key="template.settingsModal.display.enableAnimations">Enable Animations</span>
|
||||
</label>
|
||||
<small style="display: block; margin-left: 24px; margin-top: -8px; color: #888; font-size: 11px;">
|
||||
<small style="display: block; margin-left: 24px; margin-top: -8px; color: #888; font-size: 11px;" data-i18n-key="template.settingsModal.display.enableAnimationsNote">
|
||||
Smooth transitions for stats, content updates, and dice rolls
|
||||
</small>
|
||||
|
||||
<label class="checkbox_label">
|
||||
<input type="checkbox" id="rpg-toggle-plot-buttons" />
|
||||
<span>Show Plot Progression Buttons</span>
|
||||
<span data-i18n-key="template.settingsModal.display.showPlotProgressionButtons">Show Plot Progression Buttons</span>
|
||||
</label>
|
||||
<small style="display: block; margin-left: 24px; margin-top: -8px; color: #888; font-size: 11px;">
|
||||
<small style="display: block; margin-left: 24px; margin-top: -8px; color: #888; font-size: 11px;" data-i18n-key="template.settingsModal.display.showPlotProgressionButtonsNote">
|
||||
Display buttons above chat input for plot progression prompts
|
||||
</small>
|
||||
|
||||
<label class="checkbox_label">
|
||||
<input type="checkbox" id="rpg-toggle-debug-mode" />
|
||||
<span>Enable Debug Mode</span>
|
||||
<span data-i18n-key="template.settingsModal.display.enableDebugMode">Enable Debug Mode</span>
|
||||
</label>
|
||||
<small style="display: block; margin-left: 24px; margin-top: -8px; color: #888; font-size: 11px;">
|
||||
<small style="display: block; margin-left: 24px; margin-top: -8px; color: #888; font-size: 11px;" data-i18n-key="template.settingsModal.display.enableDebugModeNote">
|
||||
Shows parser logs in a mobile-friendly UI panel. Useful for troubleshooting. Look for the red bug button.
|
||||
</small>
|
||||
</div>
|
||||
|
||||
<div class="rpg-settings-group">
|
||||
<h4><i class="fa-solid fa-sliders" aria-hidden="true"></i> Advanced</h4>
|
||||
<h4 data-i18n-key="template.settingsModal.advancedTitle"><i class="fa-solid fa-sliders" aria-hidden="true"></i> Advanced</h4>
|
||||
|
||||
<div class="rpg-setting-row">
|
||||
<label for="rpg-generation-mode">Generation Mode:</label>
|
||||
<label for="rpg-generation-mode" data-i18n-key="template.settingsModal.advanced.generationMode">Generation Mode:</label>
|
||||
<select id="rpg-generation-mode" class="rpg-select">
|
||||
<option value="together">Together with Main Generation</option>
|
||||
<option value="separate">Separate Generation</option>
|
||||
<option value="together" data-i18n-key="template.settingsModal.advanced.generationModeOptions.together">Together with Main Generation</option>
|
||||
<option value="separate" data-i18n-key="template.settingsModal.advanced.generationModeOptions.separate">Separate Generation</option>
|
||||
</select>
|
||||
<small>Together: Adds RPG tracking to main roleplay. Separate: Generates RPG data separately (manual or auto).</small>
|
||||
<small data-i18n-key="template.settingsModal.advanced.generationModeNote">Together: Adds RPG tracking to main roleplay. Separate: Generates RPG data separately (manual or auto).</small>
|
||||
</div>
|
||||
|
||||
<div class="rpg-setting-row">
|
||||
<label for="rpg-update-depth">Context Messages:</label>
|
||||
<label for="rpg-update-depth" data-i18n-key="template.settingsModal.advanced.contextMessages">Context Messages:</label>
|
||||
<input type="number" id="rpg-update-depth" min="1" max="20" value="4" class="rpg-input" />
|
||||
<small>Number of recent messages to include (Separate mode only)</small>
|
||||
<small data-i18n-key="template.settingsModal.advanced.contextMessagesNote">Number of recent messages to include (Separate mode only)</small>
|
||||
</div>
|
||||
|
||||
<div class="rpg-setting-row">
|
||||
<label for="rpg-memory-messages">Memory Batch Size:</label>
|
||||
<label for="rpg-memory-messages" data-i18n-key="template.settingsModal.advanced.memoryBatchSize">Memory Batch Size:</label>
|
||||
<input type="number" id="rpg-memory-messages" min="4" max="50" value="16" class="rpg-input" />
|
||||
<small>Number of messages to process per batch in Memory Recollection</small>
|
||||
<small data-i18n-key="template.settingsModal.advanced.memoryBatchSizeNote">Number of messages to process per batch in Memory Recollection</small>
|
||||
</div>
|
||||
|
||||
<label class="checkbox_label">
|
||||
<input type="checkbox" id="rpg-use-separate-preset" />
|
||||
<span>Use model connected to RPG Companion Trackers preset</span>
|
||||
<span data-i18n-key="template.settingsModal.advanced.useSeparatePreset">Use model connected to RPG Companion Trackers preset</span>
|
||||
</label>
|
||||
<small style="display: block; margin-left: 24px; margin-top: -8px; color: #888; font-size: 11px;">
|
||||
<small style="display: block; margin-left: 24px; margin-top: -8px; color: #888; font-size: 11px;" data-i18n-key="template.settingsModal.advanced.useSeparatePresetNote">
|
||||
Separate mode only. When enabled, tracker generation will use the model from the "RPG Companion Trackers" preset instead of your main API model. The preset will be switched automatically during generation and restored afterward. Select the desired model in that preset and make sure the "Bind presets to API connections" toggle is on (next to the import/export preset buttons).
|
||||
</small>
|
||||
|
||||
<div class="rpg-setting-row">
|
||||
<label for="rpg-skip-guided-mode">Skip Injections during Guided Generations:</label>
|
||||
<label for="rpg-skip-guided-mode" data-i18n-key="template.settingsModal.advanced.skipInjections">Skip Injections during Guided Generations:</label>
|
||||
<select id="rpg-skip-guided-mode" class="rpg-select">
|
||||
<option value="none">Never skip</option>
|
||||
<option value="impersonation">Only on impersonation requests</option>
|
||||
<option value="guided">Always for guided or quiet prompts</option>
|
||||
<option value="none" data-i18n-key="template.settingsModal.advanced.skipInjectionsOptions.none">Never skip</option>
|
||||
<option value="impersonation" data-i18n-key="template.settingsModal.advanced.skipInjectionsOptions.impersonation">Only on impersonation requests</option>
|
||||
<option value="guided" data-i18n-key="template.settingsModal.advanced.skipInjectionsOptions.guided">Always for guided or quiet prompts</option>
|
||||
</select>
|
||||
</div>
|
||||
<small style="display: block; margin-left: 24px; margin-top: -8px; color: #888; font-size: 11px;">
|
||||
<small style="display: block; margin-left: 24px; margin-top: -8px; color: #888; font-size: 11px;" data-i18n-key="template.settingsModal.advanced.skipInjectionsNote">
|
||||
When set, the extension will not inject tracker prompts, examples, or HTML instructions according to the selected mode when a guided generation (via `instruct` or `quiet_prompt`) is detected. Useful when using GuidedGenerations or similar extensions.
|
||||
</small>
|
||||
|
||||
<!-- Custom HTML Prompt Editor -->
|
||||
<div class="rpg-setting-row" style="margin-top: 20px; padding-top: 20px; border-top: 1px solid var(--rpg-border);">
|
||||
<label for="rpg-custom-html-prompt" style="display: block; margin-bottom: 8px; font-weight: 600;">
|
||||
<label for="rpg-custom-html-prompt" style="display: block; margin-bottom: 8px; font-weight: 600;" data-i18n-key="template.settingsModal.advanced.customHtmlPromptTitle">
|
||||
<i class="fa-solid fa-code" aria-hidden="true"></i> Custom HTML Prompt:
|
||||
</label>
|
||||
|
||||
@@ -281,10 +281,10 @@
|
||||
placeholder=""></textarea>
|
||||
<div style="margin-top: 8px; display: flex; gap: 8px;">
|
||||
<button id="rpg-restore-default-html-prompt" class="menu_button" style="flex: 1;">
|
||||
<i class="fa-solid fa-rotate-left" aria-hidden="true"></i> Restore Default
|
||||
<i class="fa-solid fa-rotate-left" aria-hidden="true"></i> <span data-i18n-key="template.settingsModal.advanced.restoreDefaultHtmlPrompt">Restore Default</span>
|
||||
</button>
|
||||
</div>
|
||||
<small style="display: block; margin-top: 8px; color: #888; font-size: 11px;">
|
||||
<small style="display: block; margin-top: 8px; color: #888; font-size: 11px;" data-i18n-key="template.settingsModal.advanced.customHtmlPromptNote">
|
||||
Customize the HTML prompt injected when "Enable Immersive HTML" is enabled. The default prompt is shown above - you can edit it directly or replace it entirely. Click "Restore Default" to reset. This affects all generation modes (together, separate, and plot progression).
|
||||
</small>
|
||||
</div>
|
||||
@@ -292,16 +292,16 @@
|
||||
<!-- Clear Cache Button -->
|
||||
<div style="margin-top: 16px; padding-top: 16px; border-top: 1px solid var(--rpg-border);">
|
||||
<button id="rpg-clear-cache" class="rpg-btn-clear-cache">
|
||||
<i class="fa-solid fa-trash" aria-hidden="true"></i> Clear Extension Cache
|
||||
<i class="fa-solid fa-trash" aria-hidden="true"></i> <span data-i18n-key="template.settingsModal.advanced.clearCache">Clear Extension Cache</span>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- Reset FAB Positions Button -->
|
||||
<div style="margin-top: 16px; padding-top: 16px; border-top: 1px solid var(--rpg-border);">
|
||||
<button id="rpg-reset-fab-positions" class="rpg-btn-reset-fab">
|
||||
<i class="fa-solid fa-arrows-rotate" aria-hidden="true"></i> Reset Button Positions
|
||||
<i class="fa-solid fa-arrows-rotate" aria-hidden="true"></i> <span data-i18n-key="template.settingsModal.advanced.resetFabPositions">Reset Button Positions</span>
|
||||
</button>
|
||||
<small style="display: block; margin-top: 8px; color: #888; font-size: 11px;">
|
||||
<small style="display: block; margin-top: 8px; color: #888; font-size: 11px;" data-i18n-key="template.settingsModal.advanced.resetFabPositionsNote">
|
||||
Resets all floating action buttons (toggle, refresh, debug) to default top-left positions. Useful if buttons are off-screen.
|
||||
</small>
|
||||
</div>
|
||||
@@ -375,7 +375,7 @@
|
||||
<header class="rpg-settings-popup-header">
|
||||
<h3 id="rpg-editor-title">
|
||||
<i class="fa-solid fa-sliders" aria-hidden="true"></i>
|
||||
<span>Edit Trackers</span>
|
||||
<span data-i18n-key="template.trackerEditorModal.title">Edit Trackers</span>
|
||||
</h3>
|
||||
<button id="rpg-close-tracker-editor" class="rpg-popup-close" type="button" aria-label="Close tracker editor">×</button>
|
||||
</header>
|
||||
@@ -383,13 +383,13 @@
|
||||
<!-- Tabs -->
|
||||
<div class="rpg-editor-tabs">
|
||||
<button class="rpg-editor-tab active" data-tab="userStats">
|
||||
<i class="fa-solid fa-heart-pulse"></i> User Stats
|
||||
<i class="fa-solid fa-heart-pulse"></i> <span data-i18n-key="template.trackerEditorModal.tabs.userStats">User Stats</span>
|
||||
</button>
|
||||
<button class="rpg-editor-tab" data-tab="infoBox">
|
||||
<i class="fa-solid fa-info-circle"></i> Info Box
|
||||
<i class="fa-solid fa-info-circle"></i> <span data-i18n-key="template.trackerEditorModal.tabs.infoBox">Info Box</span>
|
||||
</button>
|
||||
<button class="rpg-editor-tab" data-tab="presentCharacters">
|
||||
<i class="fa-solid fa-users"></i> Present Characters
|
||||
<i class="fa-solid fa-users"></i> <span data-i18n-key="template.trackerEditorModal.tabs.presentCharacters">Present Characters</span>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
@@ -402,12 +402,12 @@
|
||||
|
||||
<footer class="rpg-settings-popup-footer">
|
||||
<button id="rpg-editor-reset" class="rpg-btn-secondary" type="button">
|
||||
<i class="fa-solid fa-rotate-left"></i> Reset to Defaults
|
||||
<i class="fa-solid fa-rotate-left"></i> <span data-i18n-key="template.trackerEditorModal.buttons.reset">Reset to Defaults</span>
|
||||
</button>
|
||||
<div class="rpg-footer-right">
|
||||
<button id="rpg-editor-cancel" class="rpg-btn-secondary" type="button">Cancel</button>
|
||||
<button id="rpg-editor-cancel" class="rpg-btn-secondary" type="button" data-i18n-key="template.trackerEditorModal.buttons.cancel">Cancel</button>
|
||||
<button id="rpg-editor-save" class="rpg-btn-primary" type="button">
|
||||
<i class="fa-solid fa-save"></i> Save & Apply
|
||||
<i class="fa-solid fa-save"></i> <span data-i18n-key="template.trackerEditorModal.buttons.save">Save & Apply</span>
|
||||
</button>
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
Reference in New Issue
Block a user