`;
@@ -550,7 +550,7 @@ export function renderInfoBox() {
html += `
•
- ${validEvents[i]}
+ ${validEvents[i]}
`;
}
@@ -560,7 +560,7 @@ export function renderInfoBox() {
html += `
+
- ${i18n.getTranslation('infobox.recentEvents.addEventPlaceholder')}
+ ${i18n.getTranslation('infobox.recentEvents.addEventPlaceholder') || 'Click to add event'}
`;
}
@@ -652,7 +652,7 @@ export function renderInfoBox() {
// Update icon
$lockIcon.text(newLockState ? '🔒' : '🔓');
- $lockIcon.attr('title', newLockState ? i18n.getTranslation('infoBox.locked') : i18n.getTranslation('infoBox.unlocked'));
+ $lockIcon.attr('title', newLockState ? (i18n.getTranslation('infoBox.locked') || 'Locked') : (i18n.getTranslation('infoBox.unlocked') || 'Unlocked'));
$lockIcon.toggleClass('locked', newLockState);
// Save settings to persist lock state
diff --git a/src/systems/rendering/inventory.js b/src/systems/rendering/inventory.js
index 0c914c3..aae5055 100644
--- a/src/systems/rendering/inventory.js
+++ b/src/systems/rendering/inventory.js
@@ -9,6 +9,7 @@ import { getInventoryRenderOptions, restoreFormStates } from '../interaction/inv
import { updateInventoryItem } from '../interaction/inventoryEdit.js';
import { parseItems } from '../../utils/itemParser.js';
import { isItemLocked, setItemLock } from '../generation/lockManager.js';
+import { i18n } from '../../core/i18n.js';
// Type imports
/** @typedef {import('../../types/inventory.js').InventoryV2} InventoryV2 */
@@ -25,7 +26,7 @@ function getLockIconHtml(tracker, path) {
const isLocked = isItemLocked(tracker, path);
const lockIcon = isLocked ? '🔒' : '🔓';
- const lockTitle = isLocked ? 'Locked' : 'Unlocked';
+ const lockTitle = isLocked ? i18n.getTranslation('global.locked') || 'Locked' : i18n.getTranslation('global.unlocked') || 'Unlocked';
const lockedClass = isLocked ? ' locked' : '';
return `
${lockIcon}`;
}
@@ -47,19 +48,24 @@ export function getLocationId(locationName) {
* @returns {string} HTML for sub-tab navigation
*/
export function renderInventorySubTabs(activeTab = 'onPerson') {
+ const onPersonText = i18n.getTranslation('inventory.section.onPerson') || 'On Person';
+ const clothingText = i18n.getTranslation('inventory.section.clothing') || 'Clothing';
+ const storedText = i18n.getTranslation('inventory.section.stored') || 'Stored';
+ const assetsText = i18n.getTranslation('inventory.section.assets') || 'Assets';
+
return `
`;
@@ -76,7 +82,7 @@ export function renderOnPersonView(onPersonItems, viewMode = 'list') {
let itemsHtml = '';
if (items.length === 0) {
- itemsHtml = '
No items carried
';
+ itemsHtml = '
' + (i18n.getTranslation('inventory.onPerson.empty') || 'No items carried') + '
';
} else {
if (viewMode === 'grid') {
// Grid view: card-style items
@@ -85,10 +91,10 @@ export function renderOnPersonView(onPersonItems, viewMode = 'list') {
return `
${lockIconHtml}
-
`}).join('');
} else {
@@ -98,8 +104,8 @@ export function renderOnPersonView(onPersonItems, viewMode = 'list') {
return `
${lockIconHtml}
- ${escapeHtml(item)}
-
+ ${escapeHtml(item)}
+
@@ -112,30 +118,30 @@ export function renderOnPersonView(onPersonItems, viewMode = 'list') {
return `
@@ -158,7 +164,7 @@ export function renderClothingView(clothingItems, viewMode = 'list') {
let itemsHtml = '';
if (items.length === 0) {
- itemsHtml = '
No clothing worn
';
+ itemsHtml = '
' + (i18n.getTranslation('inventory.clothing.empty') || 'No clothing worn') + '
';
} else {
if (viewMode === 'grid') {
// Grid view: card-style items
@@ -167,10 +173,10 @@ export function renderClothingView(clothingItems, viewMode = 'list') {
return `
${lockIconHtml}
-
+
- ${escapeHtml(item)}
+ ${escapeHtml(item)}
`}).join('');
} else {
@@ -180,8 +186,8 @@ export function renderClothingView(clothingItems, viewMode = 'list') {
return `
${lockIconHtml}
- ${escapeHtml(item)}
-
+ ${escapeHtml(item)}
+
@@ -194,30 +200,30 @@ export function renderClothingView(clothingItems, viewMode = 'list') {
return `
@@ -242,30 +248,30 @@ export function renderStoredView(stored, collapsedLocations = [], viewMode = 'li
let html = `
@@ -274,7 +280,7 @@ export function renderStoredView(stored, collapsedLocations = [], viewMode = 'li
if (locations.length === 0) {
html += `
- No storage locations yet. Click "Add Location" to create one.
+ ${i18n.getTranslation('inventory.stored.empty') || 'No storage locations yet. Click "Add Location" to create one.'}
`;
} else {
@@ -286,7 +292,7 @@ export function renderStoredView(stored, collapsedLocations = [], viewMode = 'li
let itemsHtml = '';
if (items.length === 0) {
- itemsHtml = '
No items stored here
';
+ itemsHtml = '
' + (i18n.getTranslation('inventory.stored.noItems') || 'No items stored here') + '
';
} else {
if (viewMode === 'grid') {
// Grid view: card-style items
@@ -295,10 +301,10 @@ export function renderStoredView(stored, collapsedLocations = [], viewMode = 'li
return `
${lockIconHtml}
-
+
- ${escapeHtml(item)}
+ ${escapeHtml(item)}
`}).join('');
} else {
@@ -308,8 +314,8 @@ export function renderStoredView(stored, collapsedLocations = [], viewMode = 'li
return `
${lockIconHtml}
- ${escapeHtml(item)}
-
+ ${escapeHtml(item)}
+
@@ -327,20 +333,20 @@ export function renderStoredView(stored, collapsedLocations = [], viewMode = 'li
${escapeHtml(location)}
-
+
@@ -348,19 +354,19 @@ export function renderStoredView(stored, collapsedLocations = [], viewMode = 'li
${itemsHtml}
-
- Add Item
+
+ ${i18n.getTranslation('inventory.stored.addItemButton') || 'Add Item'}
-
Remove "${escapeHtml(location)}"? This will delete all items stored there.
+
${(i18n.getTranslation('inventory.stored.removeLocationConfirm') || 'Remove "{location}"? This will delete all items stored there.').replace('{location}', escapeHtml(location))}
- Cancel
+ ${i18n.getTranslation('global.cancel') || 'Cancel'}
- Confirm
+ ${i18n.getTranslation('global.confirm') || 'Confirm'}
@@ -388,7 +394,7 @@ export function renderAssetsView(assets, viewMode = 'list') {
let itemsHtml = '';
if (items.length === 0) {
- itemsHtml = '
No assets owned
';
+ itemsHtml = '
' + (i18n.getTranslation('inventory.assets.empty') || 'No assets owned') + '
';
} else {
if (viewMode === 'grid') {
// Grid view: card-style items
@@ -397,10 +403,10 @@ export function renderAssetsView(assets, viewMode = 'list') {
return `
${lockIconHtml}
-
+
- ${escapeHtml(item)}
+ ${escapeHtml(item)}
`}).join('');
} else {
@@ -410,8 +416,8 @@ export function renderAssetsView(assets, viewMode = 'list') {
return `
${lockIconHtml}
- ${escapeHtml(item)}
-
+ ${escapeHtml(item)}
+
@@ -424,30 +430,30 @@ export function renderAssetsView(assets, viewMode = 'list') {
return `
@@ -456,8 +462,7 @@ export function renderAssetsView(assets, viewMode = 'list') {
- Assets include vehicles (cars, motorcycles), property (homes, apartments),
- and major equipment (workshop tools, special items).
+ ${i18n.getTranslation('inventory.assets.description') || 'Assets include vehicles (cars, motorcycles), property (homes, apartments), and major equipment (workshop tools, special items).'}
diff --git a/src/systems/rendering/quests.js b/src/systems/rendering/quests.js
index 5f481a5..4667fb0 100644
--- a/src/systems/rendering/quests.js
+++ b/src/systems/rendering/quests.js
@@ -6,6 +6,7 @@
import { extensionSettings, $questsContainer, committedTrackerData, lastGeneratedData } from '../../core/state.js';
import { saveSettings, saveChatData } from '../../core/persistence.js';
import { isItemLocked, setItemLock } from '../generation/lockManager.js';
+import { i18n } from '../../core/i18n.js';
/**
* Syncs the current extensionSettings.quests to committedTrackerData.userStats
@@ -44,7 +45,7 @@ function getLockIconHtml(tracker, path) {
const isLocked = isItemLocked(tracker, path);
const lockIcon = isLocked ? '🔒' : '🔓';
- const lockTitle = isLocked ? 'Locked' : 'Unlocked';
+ const lockTitle = isLocked ? i18n.getTranslation('global.locked') || 'Locked' : i18n.getTranslation('global.unlocked') || 'Unlocked';
const lockedClass = isLocked ? ' locked' : '';
return `
${lockIcon}`;
}
@@ -66,13 +67,16 @@ function escapeHtml(text) {
* @returns {string} HTML for sub-tab navigation
*/
export function renderQuestsSubTabs(activeTab = 'main') {
+ const mainText = i18n.getTranslation('quests.section.main') || 'Main Quest';
+ const optionalText = i18n.getTranslation('quests.section.optional') || 'Optional Quests';
+
return `
- Main Quest
+ ${mainText}
- Optional Quests
+ ${optionalText}
`;
@@ -86,13 +90,18 @@ export function renderQuestsSubTabs(activeTab = 'main') {
export function renderMainQuestView(mainQuest) {
const questDisplay = (mainQuest && mainQuest !== 'None') ? mainQuest : '';
const hasQuest = questDisplay.length > 0;
+ const mainTitle = i18n.getTranslation('quests.main.title') || 'Main Quests';
+ const mainHint = i18n.getTranslation('quests.main.hint') || 'The main quest represents your primary objective in the story.';
+ const mainEmptyText = i18n.getTranslation('quests.main.empty') || 'No active main quests';
+ const addQuestButtonText = i18n.getTranslation('quests.main.addQuestButton') || 'Add Quest';
+ const addQuestPlaceholderText = i18n.getTranslation('quests.main.addQuestPlaceholder') || 'Enter main quest title...';
return `
@@ -112,32 +121,32 @@ export function renderMainQuestView(mainQuest) {
${getLockIconHtml('userStats', 'quests.main')}
${escapeHtml(questDisplay)}
-
+
-
+
` : `
-
No active main quests
+
${mainEmptyText}
`}
- The main quests represent your primary objective in the story.
+ ${mainHint}
`;
@@ -150,18 +159,23 @@ export function renderMainQuestView(mainQuest) {
*/
export function renderOptionalQuestsView(optionalQuests) {
const quests = optionalQuests.filter(q => q && q !== 'None');
+ const optionalTitle = i18n.getTranslation('quests.optional.title') || 'Optional Quests';
+ const optionalHint = i18n.getTranslation('quests.optional.hint') || 'Optional quests are side objectives that complement your main story.';
+ const optionalEmptyText = i18n.getTranslation('quests.optional.empty') || 'No active optional quests';
+ const addQuestButtonText = i18n.getTranslation('quests.optional.addQuestButton') || 'Add Quest';
+ const addQuestPlaceholderText = i18n.getTranslation('quests.optional.addQuestPlaceholder') || 'Enter optional quest title...';
let questsHtml = '';
if (quests.length === 0) {
- questsHtml = '
No active optional quests
';
+ questsHtml = `
${optionalEmptyText}
`;
} else {
questsHtml = quests.map((quest, index) => {
return `
${getLockIconHtml('userStats', `quests.optional[${index}]`)}
-
${escapeHtml(quest)}
+
${escapeHtml(quest)}
-
+
@@ -172,20 +186,20 @@ export function renderOptionalQuestsView(optionalQuests) {
return `
@@ -194,7 +208,7 @@ export function renderOptionalQuestsView(optionalQuests) {
- Optional quests are side objectives that complement your main story.
+ ${optionalHint}
diff --git a/src/systems/rendering/thoughts.js b/src/systems/rendering/thoughts.js
index 695a108..fb66c63 100644
--- a/src/systems/rendering/thoughts.js
+++ b/src/systems/rendering/thoughts.js
@@ -36,7 +36,7 @@ function getLockIconHtml(tracker, path) {
const isLocked = isItemLocked(tracker, path);
const lockIcon = isLocked ? '🔒' : '🔓';
- const lockTitle = isLocked ? i18n.getTranslation('thoughts.locked') : i18n.getTranslation('thoughts.unlocked');
+ const lockTitle = isLocked ? i18n.getTranslation('thoughts.locked') || 'Locked' : i18n.getTranslation('thoughts.unlocked') || 'Unlocked';
const lockedClass = isLocked ? ' locked' : '';
return `
${lockIcon}`;
}
@@ -111,7 +111,7 @@ export function renderThoughts({ preserveScroll = false, useCommittedFallback =
// Don't render if no data exists (e.g., after cache clear)
const thoughtsData = getPresentCharactersTrackerData({ useCommittedFallback });
if (!thoughtsData) {
- $thoughtsContainer.html('
No character data generated yet
');
+ $thoughtsContainer.html('
' + (i18n.getTranslation('thoughts.empty') || 'No character data generated yet') + '
');
return;
}
@@ -381,14 +381,14 @@ export function renderThoughts({ preserveScroll = false, useCommittedFallback =
html += `