@jjlmoya/utils-books 1.8.0 → 1.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/src/category/index.ts +2 -1
- package/src/entries.ts +4 -1
- package/src/index.ts +1 -0
- package/src/tests/locale_completeness.test.ts +1 -1
- package/src/tests/tool_validation.test.ts +1 -1
- package/src/tool/book-index-page-budget-calculator/bibliography.astro +6 -0
- package/src/tool/book-index-page-budget-calculator/bibliography.ts +17 -0
- package/src/tool/book-index-page-budget-calculator/book-index-page-budget-calculator.css +478 -0
- package/src/tool/book-index-page-budget-calculator/component.astro +134 -0
- package/src/tool/book-index-page-budget-calculator/controller.ts +114 -0
- package/src/tool/book-index-page-budget-calculator/dom-views.ts +89 -0
- package/src/tool/book-index-page-budget-calculator/entry.ts +39 -0
- package/src/tool/book-index-page-budget-calculator/evaluator.ts +26 -0
- package/src/tool/book-index-page-budget-calculator/i18n/de.ts +35 -0
- package/src/tool/book-index-page-budget-calculator/i18n/en.ts +113 -0
- package/src/tool/book-index-page-budget-calculator/i18n/es.ts +35 -0
- package/src/tool/book-index-page-budget-calculator/i18n/fr.ts +8 -0
- package/src/tool/book-index-page-budget-calculator/i18n/id.ts +35 -0
- package/src/tool/book-index-page-budget-calculator/i18n/it.ts +8 -0
- package/src/tool/book-index-page-budget-calculator/i18n/ja.ts +8 -0
- package/src/tool/book-index-page-budget-calculator/i18n/ko.ts +8 -0
- package/src/tool/book-index-page-budget-calculator/i18n/nl.ts +8 -0
- package/src/tool/book-index-page-budget-calculator/i18n/pl.ts +8 -0
- package/src/tool/book-index-page-budget-calculator/i18n/pt.ts +8 -0
- package/src/tool/book-index-page-budget-calculator/i18n/ru.ts +8 -0
- package/src/tool/book-index-page-budget-calculator/i18n/sv.ts +8 -0
- package/src/tool/book-index-page-budget-calculator/i18n/tr.ts +8 -0
- package/src/tool/book-index-page-budget-calculator/i18n/zh.ts +8 -0
- package/src/tool/book-index-page-budget-calculator/index.ts +11 -0
- package/src/tool/book-index-page-budget-calculator/logic.test.ts +52 -0
- package/src/tool/book-index-page-budget-calculator/logic.ts +86 -0
- package/src/tool/book-index-page-budget-calculator/seo.astro +15 -0
- package/src/tool/book-index-page-budget-calculator/storage.ts +17 -0
- package/src/tool/book-index-page-budget-calculator/ui.ts +41 -0
- package/src/tools.ts +2 -1
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
import {
|
|
2
|
+
calculateIndexBudget,
|
|
3
|
+
clampNumber,
|
|
4
|
+
centimetersToInches,
|
|
5
|
+
DEFAULT_INDEX_INPUTS,
|
|
6
|
+
inchesToCentimeters,
|
|
7
|
+
type BookIndexInputs,
|
|
8
|
+
type Density,
|
|
9
|
+
} from './logic';
|
|
10
|
+
import { renderBudget } from './dom-views';
|
|
11
|
+
import { loadUnitSystem, saveUnitSystem, type UnitSystem } from './storage';
|
|
12
|
+
import type { BookIndexUI } from './ui';
|
|
13
|
+
|
|
14
|
+
const DISPLAY_LIMITS = {
|
|
15
|
+
manuscriptWords: [100, 500000],
|
|
16
|
+
indexEntries: [10, 10000],
|
|
17
|
+
targetIndexPages: [1, 200],
|
|
18
|
+
} as const;
|
|
19
|
+
|
|
20
|
+
function input(root: HTMLElement, name: string): HTMLInputElement | null {
|
|
21
|
+
return root.querySelector<HTMLInputElement>(`[data-input="${name}"]`);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
function parseInput(root: HTMLElement, name: string, fallback: number): number {
|
|
25
|
+
const field = input(root, name);
|
|
26
|
+
return field ? Number(field.value) || fallback : fallback;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function displayedDimension(inputs: BookIndexInputs, unitSystem: UnitSystem, dimension: 'width' | 'height'): number {
|
|
30
|
+
const value = dimension === 'width' ? inputs.trimWidthInches : inputs.trimHeightInches;
|
|
31
|
+
return unitSystem === 'metric' ? inchesToCentimeters(value) : value;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function readInputs(root: HTMLElement, previous: BookIndexInputs, unitSystem: UnitSystem): BookIndexInputs {
|
|
35
|
+
const width = parseInput(root, 'trim-width', displayedDimension(previous, unitSystem, 'width'));
|
|
36
|
+
const height = parseInput(root, 'trim-height', displayedDimension(previous, unitSystem, 'height'));
|
|
37
|
+
const toInches = (value: number): number => unitSystem === 'metric' ? centimetersToInches(value) : value;
|
|
38
|
+
|
|
39
|
+
return {
|
|
40
|
+
manuscriptWords: clampNumber(parseInput(root, 'manuscript-words', previous.manuscriptWords), ...DISPLAY_LIMITS.manuscriptWords, previous.manuscriptWords),
|
|
41
|
+
trimWidthInches: clampNumber(toInches(width), 3, 15, previous.trimWidthInches),
|
|
42
|
+
trimHeightInches: clampNumber(toInches(height), 3, 15, previous.trimHeightInches),
|
|
43
|
+
density: previous.density,
|
|
44
|
+
indexEntries: clampNumber(parseInput(root, 'index-entries', previous.indexEntries), ...DISPLAY_LIMITS.indexEntries, previous.indexEntries),
|
|
45
|
+
targetIndexPages: clampNumber(parseInput(root, 'target-index-pages', previous.targetIndexPages), ...DISPLAY_LIMITS.targetIndexPages, previous.targetIndexPages),
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
function setDimensionFields(root: HTMLElement, inputs: BookIndexInputs, unitSystem: UnitSystem): void {
|
|
50
|
+
const width = input(root, 'trim-width');
|
|
51
|
+
const height = input(root, 'trim-height');
|
|
52
|
+
if (width) width.value = displayedDimension(inputs, unitSystem, 'width').toFixed(unitSystem === 'metric' ? 1 : 2);
|
|
53
|
+
if (height) height.value = displayedDimension(inputs, unitSystem, 'height').toFixed(unitSystem === 'metric' ? 1 : 2);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
function setUnitButtons(root: HTMLElement, unitSystem: UnitSystem): void {
|
|
57
|
+
root.querySelectorAll<HTMLButtonElement>('[data-unit]').forEach((button) => {
|
|
58
|
+
button.setAttribute('aria-pressed', String(button.dataset.unit === unitSystem));
|
|
59
|
+
});
|
|
60
|
+
root.dataset.units = unitSystem;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
function setDensityButtons(root: HTMLElement, density: Density): void {
|
|
64
|
+
root.querySelectorAll<HTMLButtonElement>('[data-density]').forEach((button) => {
|
|
65
|
+
button.setAttribute('aria-pressed', String(button.dataset.density === density));
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
function render(root: HTMLElement, ui: BookIndexUI, inputs: BookIndexInputs, unitSystem: UnitSystem): void {
|
|
70
|
+
setUnitButtons(root, unitSystem);
|
|
71
|
+
setDensityButtons(root, inputs.density);
|
|
72
|
+
renderBudget({ root, budget: calculateIndexBudget(inputs), inputs, ui, unitSystem });
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
function bindNumberFields(root: HTMLElement, ui: BookIndexUI, state: { inputs: BookIndexInputs; unitSystem: UnitSystem }): void {
|
|
76
|
+
root.querySelectorAll<HTMLInputElement>('[data-input]').forEach((field) => {
|
|
77
|
+
field.addEventListener('input', () => {
|
|
78
|
+
state.inputs = readInputs(root, state.inputs, state.unitSystem);
|
|
79
|
+
render(root, ui, state.inputs, state.unitSystem);
|
|
80
|
+
});
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
function bindDensity(root: HTMLElement, ui: BookIndexUI, state: { inputs: BookIndexInputs; unitSystem: UnitSystem }): void {
|
|
85
|
+
root.querySelectorAll<HTMLButtonElement>('[data-density]').forEach((button) => {
|
|
86
|
+
button.addEventListener('click', () => {
|
|
87
|
+
const density = button.dataset.density as Density;
|
|
88
|
+
state.inputs = { ...readInputs(root, state.inputs, state.unitSystem), density };
|
|
89
|
+
render(root, ui, state.inputs, state.unitSystem);
|
|
90
|
+
});
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
function bindUnits(root: HTMLElement, ui: BookIndexUI, state: { inputs: BookIndexInputs; unitSystem: UnitSystem }): void {
|
|
95
|
+
root.querySelectorAll<HTMLButtonElement>('[data-unit]').forEach((button) => {
|
|
96
|
+
button.addEventListener('click', () => {
|
|
97
|
+
state.inputs = readInputs(root, state.inputs, state.unitSystem);
|
|
98
|
+
state.unitSystem = button.dataset.unit === 'metric' ? 'metric' : 'imperial';
|
|
99
|
+
saveUnitSystem(state.unitSystem);
|
|
100
|
+
setDimensionFields(root, state.inputs, state.unitSystem);
|
|
101
|
+
render(root, ui, state.inputs, state.unitSystem);
|
|
102
|
+
});
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
export function initBookIndexTool(root: HTMLElement): void {
|
|
107
|
+
const ui = JSON.parse(root.dataset.ui ?? '{}') as BookIndexUI;
|
|
108
|
+
const state = { inputs: DEFAULT_INDEX_INPUTS, unitSystem: loadUnitSystem() };
|
|
109
|
+
bindNumberFields(root, ui, state);
|
|
110
|
+
bindDensity(root, ui, state);
|
|
111
|
+
bindUnits(root, ui, state);
|
|
112
|
+
setDimensionFields(root, state.inputs, state.unitSystem);
|
|
113
|
+
render(root, ui, state.inputs, state.unitSystem);
|
|
114
|
+
}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import type { BookIndexBudget, BookIndexInputs } from './logic';
|
|
2
|
+
import { evaluateBudget } from './evaluator';
|
|
3
|
+
import type { BookIndexUI } from './ui';
|
|
4
|
+
import type { UnitSystem } from './storage';
|
|
5
|
+
|
|
6
|
+
interface RenderArgs {
|
|
7
|
+
root: HTMLElement;
|
|
8
|
+
budget: BookIndexBudget;
|
|
9
|
+
inputs: BookIndexInputs;
|
|
10
|
+
ui: BookIndexUI;
|
|
11
|
+
unitSystem: UnitSystem;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
interface SceneArgs {
|
|
15
|
+
root: HTMLElement;
|
|
16
|
+
budget: BookIndexBudget;
|
|
17
|
+
inputs: BookIndexInputs;
|
|
18
|
+
ui: BookIndexUI;
|
|
19
|
+
unitSystem: UnitSystem;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function number(value: number, digits = 0): string {
|
|
23
|
+
return new Intl.NumberFormat('en-US', { maximumFractionDigits: digits }).format(value);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function setOutput(root: HTMLElement, name: string, value: string): void {
|
|
27
|
+
const output = root.querySelector<HTMLElement>(`[data-output="${name}"]`);
|
|
28
|
+
if (output) output.textContent = value;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function renderOutputs(root: HTMLElement, budget: BookIndexBudget, ui: BookIndexUI): void {
|
|
32
|
+
setOutput(root, 'text-pages', number(budget.textPages));
|
|
33
|
+
setOutput(root, 'index-pages', number(budget.estimatedIndexPages));
|
|
34
|
+
setOutput(root, 'total-pages', number(budget.totalPages));
|
|
35
|
+
setOutput(root, 'target-total-pages', number(budget.targetTotalPages));
|
|
36
|
+
setOutput(root, 'entries-per-page', number(budget.targetEntriesPerPage, 1));
|
|
37
|
+
setOutput(root, 'index-share', `${number(budget.indexSharePercent, 1)}%`);
|
|
38
|
+
setOutput(root, 'words-per-page', `${number(budget.wordsPerPage)} ${ui.wordsLabel.toLowerCase()}`);
|
|
39
|
+
setOutput(root, 'summary-target', number(budget.targetIndexPages));
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function summaryGapCopy(gap: number, ui: BookIndexUI): string {
|
|
43
|
+
if (gap > 0) return `${number(gap)} ${ui.summaryPagesOver}`;
|
|
44
|
+
if (gap < 0) return `${number(Math.abs(gap))} ${ui.summaryPagesSpare}`;
|
|
45
|
+
return ui.summaryOnTarget;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function renderSummary(root: HTMLElement, budget: BookIndexBudget, ui: BookIndexUI): void {
|
|
49
|
+
const gap = budget.estimatedIndexPages - budget.targetIndexPages;
|
|
50
|
+
const gapLabel = summaryGapCopy(gap, ui);
|
|
51
|
+
setOutput(root, 'summary-gap', gapLabel);
|
|
52
|
+
setOutput(root, 'scene-body-count', number(budget.textPages));
|
|
53
|
+
setOutput(root, 'scene-index-count', number(budget.estimatedIndexPages));
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
function statusCopy(status: ReturnType<typeof evaluateBudget>['status'], ui: BookIndexUI): { text: string; hint: string } {
|
|
57
|
+
if (status === 'tight') return { text: ui.statusTight, hint: ui.statusTightHint };
|
|
58
|
+
if (status === 'roomy') return { text: ui.statusRoomy, hint: ui.statusRoomyHint };
|
|
59
|
+
return { text: ui.statusBalanced, hint: ui.statusBalancedHint };
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
function renderStatus(root: HTMLElement, budget: BookIndexBudget, ui: BookIndexUI): void {
|
|
63
|
+
const evaluation = evaluateBudget(budget);
|
|
64
|
+
const copy = statusCopy(evaluation.status, ui);
|
|
65
|
+
root.dataset.status = evaluation.status;
|
|
66
|
+
setOutput(root, 'status', copy.text);
|
|
67
|
+
setOutput(root, 'status-hint', copy.hint);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
function renderScene(args: SceneArgs): void {
|
|
71
|
+
const scene = args.root.querySelector<HTMLElement>('[data-scene]');
|
|
72
|
+
if (!scene) return;
|
|
73
|
+
const bodyShare = (args.budget.textPages / args.budget.totalPages) * 100;
|
|
74
|
+
const indexShare = 100 - bodyShare;
|
|
75
|
+
scene.style.setProperty('--body-share', `${bodyShare}%`);
|
|
76
|
+
scene.style.setProperty('--index-share', `${indexShare}%`);
|
|
77
|
+
scene.dataset.density = args.inputs.density;
|
|
78
|
+
scene.dataset.units = args.unitSystem;
|
|
79
|
+
setOutput(args.root, 'scene-body-label', `${number(args.budget.textPages)} ${args.ui.sceneBodyLabel}`);
|
|
80
|
+
setOutput(args.root, 'scene-index-label', `${number(args.budget.estimatedIndexPages)} ${args.ui.sceneIndexLabel}`);
|
|
81
|
+
setOutput(args.root, 'scene-caption', `${args.ui.sceneCaption} ${number(args.budget.totalPages)}. ${args.ui.sceneTargetCaption} ${number(args.budget.targetTotalPages)}.`);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
export function renderBudget(args: RenderArgs): void {
|
|
85
|
+
renderOutputs(args.root, args.budget, args.ui);
|
|
86
|
+
renderSummary(args.root, args.budget, args.ui);
|
|
87
|
+
renderStatus(args.root, args.budget, args.ui);
|
|
88
|
+
renderScene(args);
|
|
89
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import type { BooksToolEntry, SEOSection, ToolLocaleContent } from '../../types';
|
|
2
|
+
import type { BookIndexUI } from './ui';
|
|
3
|
+
|
|
4
|
+
export type { BookIndexUI } from './ui';
|
|
5
|
+
export type BookIndexLocaleContent = ToolLocaleContent<BookIndexUI>;
|
|
6
|
+
|
|
7
|
+
function withLocalizedSchemas(content: BookIndexLocaleContent): BookIndexLocaleContent {
|
|
8
|
+
const seo: SEOSection[] = content.seo.length >= 10
|
|
9
|
+
? content.seo
|
|
10
|
+
: [...content.seo, { type: 'title', text: content.ui.sceneLabel, level: 2 }, { type: 'paragraph', html: content.ui.sourceNote }];
|
|
11
|
+
const schemas: Record<string, unknown>[] = [
|
|
12
|
+
{ '@context': 'https://schema.org', '@type': 'SoftwareApplication', name: content.title, applicationCategory: 'DesignApplication', operatingSystem: 'Any', offers: { '@type': 'Offer', price: '0', priceCurrency: 'USD' } },
|
|
13
|
+
{ '@context': 'https://schema.org', '@type': 'FAQPage', mainEntity: content.faq.map((item) => ({ '@type': 'Question', name: item.question, acceptedAnswer: { '@type': 'Answer', text: item.answer } })) },
|
|
14
|
+
{ '@context': 'https://schema.org', '@type': 'HowTo', name: content.title, step: content.howTo.map((item) => ({ '@type': 'HowToStep', name: item.name, text: item.text })) },
|
|
15
|
+
];
|
|
16
|
+
return { ...content, seo, schemas };
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export const bookIndexPageBudgetCalculator: BooksToolEntry<BookIndexUI> = {
|
|
20
|
+
id: 'book-index-page-budget-calculator',
|
|
21
|
+
icons: { bg: 'mdi:book-open-page-variant-outline', fg: 'mdi:format-list-numbered' },
|
|
22
|
+
i18n: {
|
|
23
|
+
de: () => import('./i18n/de').then((module) => withLocalizedSchemas(module.content as BookIndexLocaleContent)),
|
|
24
|
+
en: () => import('./i18n/en').then((module) => module.content),
|
|
25
|
+
es: () => import('./i18n/es').then((module) => withLocalizedSchemas(module.content as BookIndexLocaleContent)),
|
|
26
|
+
fr: () => import('./i18n/fr').then((module) => withLocalizedSchemas(module.content as BookIndexLocaleContent)),
|
|
27
|
+
id: () => import('./i18n/id').then((module) => withLocalizedSchemas(module.content as BookIndexLocaleContent)),
|
|
28
|
+
it: () => import('./i18n/it').then((module) => withLocalizedSchemas(module.content as BookIndexLocaleContent)),
|
|
29
|
+
ja: () => import('./i18n/ja').then((module) => withLocalizedSchemas(module.content as BookIndexLocaleContent)),
|
|
30
|
+
ko: () => import('./i18n/ko').then((module) => withLocalizedSchemas(module.content as BookIndexLocaleContent)),
|
|
31
|
+
nl: () => import('./i18n/nl').then((module) => withLocalizedSchemas(module.content as BookIndexLocaleContent)),
|
|
32
|
+
pl: () => import('./i18n/pl').then((module) => withLocalizedSchemas(module.content as BookIndexLocaleContent)),
|
|
33
|
+
pt: () => import('./i18n/pt').then((module) => withLocalizedSchemas(module.content as BookIndexLocaleContent)),
|
|
34
|
+
ru: () => import('./i18n/ru').then((module) => withLocalizedSchemas(module.content as BookIndexLocaleContent)),
|
|
35
|
+
sv: () => import('./i18n/sv').then((module) => withLocalizedSchemas(module.content as BookIndexLocaleContent)),
|
|
36
|
+
tr: () => import('./i18n/tr').then((module) => withLocalizedSchemas(module.content as BookIndexLocaleContent)),
|
|
37
|
+
zh: () => import('./i18n/zh').then((module) => withLocalizedSchemas(module.content as BookIndexLocaleContent)),
|
|
38
|
+
},
|
|
39
|
+
};
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { BookIndexBudget } from './logic';
|
|
2
|
+
|
|
3
|
+
export type BudgetStatus = 'balanced' | 'tight' | 'roomy';
|
|
4
|
+
|
|
5
|
+
export interface BudgetEvaluation {
|
|
6
|
+
status: BudgetStatus;
|
|
7
|
+
gapPages: number;
|
|
8
|
+
targetIsTooDense: boolean;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
function statusForGap(gapPages: number): BudgetStatus {
|
|
12
|
+
if (gapPages < 0) return 'tight';
|
|
13
|
+
if (gapPages > 0) return 'roomy';
|
|
14
|
+
return 'balanced';
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export function evaluateBudget(budget: BookIndexBudget): BudgetEvaluation {
|
|
18
|
+
const gapPages = budget.targetIndexPages - budget.estimatedIndexPages;
|
|
19
|
+
const status = statusForGap(gapPages);
|
|
20
|
+
|
|
21
|
+
return {
|
|
22
|
+
status,
|
|
23
|
+
gapPages,
|
|
24
|
+
targetIsTooDense: budget.targetEntriesPerPage > budget.entriesPerPage,
|
|
25
|
+
};
|
|
26
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import type { BookIndexUI } from '../ui';
|
|
2
|
+
import type { ToolLocaleContent } from '../../../types';
|
|
3
|
+
import { content as base } from './en';
|
|
4
|
+
|
|
5
|
+
const ui: BookIndexUI = {
|
|
6
|
+
...base.ui,
|
|
7
|
+
wordsLabel: 'Wörter im Manuskript', wordsHint: 'Textkörper vor dem Anhang', trimWidthLabel: 'Satzbreite', trimHeightLabel: 'Satzhöhe', trimHint: 'Endformat der Buchseite', unitLabel: 'Seiteneinheiten', metricButtonLabel: 'Metrisch cm', imperialButtonLabel: 'Imperial Zoll', densityLabel: 'Typografische Dichte', densityHint: 'Steuert Wörter und Indexeinträge pro Seite', airyLabel: 'Locker', standardLabel: 'Standard', compactLabel: 'Kompakt', indexEntriesLabel: 'Erwartete Indexeinträge', indexEntriesHint: 'Themen, Namen, Orte und Querverweise', targetIndexPagesLabel: 'Geplante Indexseiten', targetIndexPagesHint: 'Dein Produktionsbudget für den Index', textPagesLabel: 'Textseiten', estimatedIndexPagesLabel: 'Geschätzter Index', totalPagesLabel: 'Geschätzter Buchumfang', targetTotalPagesLabel: 'Mit geplantem Index', entriesPerPageLabel: 'Einträge pro Zielseite', indexShareLabel: 'Indexanteil am Buch', statusBalanced: 'Ziel entspricht der Schätzung', statusTight: 'Ziel ist zu knapp', statusRoomy: 'Ziel lässt Spielraum', statusBalancedHint: 'Dein Indexbudget entspricht dem Dichtemodell.', statusTightHint: 'Plane mehr Seiten ein oder reduziere Einträge vor dem Satz.', statusRoomyHint: 'Das großzügige Budget kann spätere redaktionelle Ergänzungen aufnehmen.', sceneLabel: 'Das Seitenbudget', sceneBodyLabel: 'Textseiten', sceneIndexLabel: 'Indexseiten', sceneCaption: 'Der geschätzte Buchumfang beträgt', sceneTargetCaption: 'Mit deinem Zielbudget ergibt sich', sourceNote: 'Dies ist ein redaktionelles Planungsmodell. Der endgültige Umfang hängt von Satz, Korrekturen, Indexstil sowie Verlag und Druckerei ab.', summaryLabel: 'Budgetsignal', summaryPagesOver: 'Seiten über dem Ziel', summaryPagesSpare: 'Seiten frei', summaryOnTarget: 'Im Zielbereich',
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
const faq = [
|
|
11
|
+
{ question: 'Was soll ich als Indexeinträge eingeben?', answer: 'Gib Themen, Namen, Orte, Untereinträge und Querverweise ein, die im fertigen Index erscheinen sollen.' },
|
|
12
|
+
{ question: 'Warum werden Text- und Indexseiten getrennt berechnet?', answer: 'Der Textumfang hängt von Wörtern und Seitengestaltung ab, der Indexumfang von Einträgen und Indexdichte.' },
|
|
13
|
+
{ question: 'Was bedeutet ein zu knappes Ziel?', answer: 'Das Ziel würde mehr Einträge pro Seite verlangen, als das gewählte Dichtemodell sinnvoll trägt.' },
|
|
14
|
+
{ question: 'Ersetzt das Ergebnis den finalen Indexabzug?', answer: 'Nein. Es ist eine Planungsschätzung. Seitenverweise und Satz müssen am fertigen Korrekturabzug geprüft werden.' },
|
|
15
|
+
];
|
|
16
|
+
|
|
17
|
+
const howTo = [
|
|
18
|
+
{ name: 'Manuskriptumfang eingeben', text: 'Trage die Wörter des Manuskripts ohne Rückentext ein.' },
|
|
19
|
+
{ name: 'Seitengestaltung anpassen', text: 'Wähle Endformat und typografische Dichte.' },
|
|
20
|
+
{ name: 'Index beschreiben', text: 'Schätze Einträge und reserviere ein Seitenbudget.' },
|
|
21
|
+
{ name: 'Vergleich auswerten', text: 'Erhöhe das Budget oder reduziere Einträge, wenn das Ziel zu knapp ist.' },
|
|
22
|
+
];
|
|
23
|
+
|
|
24
|
+
const seo: ToolLocaleContent<BookIndexUI>['seo'] = [
|
|
25
|
+
{ type: 'title', text: 'Indexseiten für ein Buch frühzeitig budgetieren', level: 2 },
|
|
26
|
+
{ type: 'paragraph', html: 'Ein Sachindex fügt einem gedruckten Buch echte Rückseiten hinzu. Dieses Werkzeug verbindet Manuskriptumfang, Seitenformat, typografische Dichte, erwartete Einträge und dein Produktionsbudget zu einer ersten Planung.' },
|
|
27
|
+
{ type: 'title', text: 'So liest du die Schätzung', level: 2 },
|
|
28
|
+
{ type: 'paragraph', html: 'Textseiten entstehen aus Wörtern und der erwarteten Wortdichte. Indexseiten entstehen aus Einträgen und der Eintragsdichte. Vergleiche den geschätzten Index mit dem reservierten Ziel, bevor der Satz beginnt.' },
|
|
29
|
+
{ type: 'list', items: ['Zähle erwartete Einträge statt aller Wörter im Manuskript.', 'Halte Format und Dichte nahe am geplanten Buchdesign.', 'Reserviere zusätzliche Seiten, wenn Querverweise oder Untereinträge wachsen.', 'Prüfe den Wert erneut am stabilen Korrekturabzug.'] },
|
|
30
|
+
{ type: 'title', text: 'Ein knappes Budget ist ein redaktionelles Signal', level: 2 },
|
|
31
|
+
{ type: 'paragraph', html: 'Ein zu knappes Ziel kann zu schwer lesbarer Typografie oder einem überfüllten Index führen. Oft ist es sinnvoller, Verweise zu bereinigen oder mehr Seiten zu reservieren, statt die Dichte immer weiter zu erhöhen.' },
|
|
32
|
+
{ type: 'tip', title: 'Die Schätzung ist kein Druckfreigabewert', html: 'Schrift, Satz, Korrekturen und Indexstil verändern den endgültigen Umfang. Bestätige das Ergebnis mit Verlag, Druckerei oder professionellem Indexer.' },
|
|
33
|
+
];
|
|
34
|
+
|
|
35
|
+
export const content = { ...base, slug: 'buch-index-seitenbudget-rechner', title: 'Budgetrechner für Indexseiten von Büchern', description: 'Schätze die zusätzlichen Indexseiten eines Buches und vergleiche sie mit deinem redaktionellen Seitenbudget.', ui, seo, faq, howTo };
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
import type { ToolLocaleContent } from '../../../types';
|
|
2
|
+
import { BOOK_INDEX_BIBLIOGRAPHY } from '../bibliography';
|
|
3
|
+
import type { BookIndexUI } from '../ui';
|
|
4
|
+
import type { FAQPage, HowTo, SoftwareApplication } from 'schema-dts';
|
|
5
|
+
|
|
6
|
+
const ui: BookIndexUI = {
|
|
7
|
+
wordsLabel: 'Manuscript words',
|
|
8
|
+
wordsHint: 'The body text before back matter',
|
|
9
|
+
trimWidthLabel: 'Trim width',
|
|
10
|
+
trimHeightLabel: 'Trim height',
|
|
11
|
+
trimHint: 'Physical page size',
|
|
12
|
+
unitLabel: 'Page units',
|
|
13
|
+
metricButtonLabel: 'Metric cm',
|
|
14
|
+
imperialButtonLabel: 'Imperial in',
|
|
15
|
+
densityLabel: 'Typography density',
|
|
16
|
+
densityHint: 'Controls body words per page and index entries per page',
|
|
17
|
+
airyLabel: 'Airy',
|
|
18
|
+
standardLabel: 'Standard',
|
|
19
|
+
compactLabel: 'Compact',
|
|
20
|
+
indexEntriesLabel: 'Expected index entries',
|
|
21
|
+
indexEntriesHint: 'Topics, names, places, and cross references',
|
|
22
|
+
targetIndexPagesLabel: 'Target index pages',
|
|
23
|
+
targetIndexPagesHint: 'Your production allowance for the index',
|
|
24
|
+
textPagesLabel: 'Body pages',
|
|
25
|
+
estimatedIndexPagesLabel: 'Estimated index',
|
|
26
|
+
totalPagesLabel: 'Estimated book total',
|
|
27
|
+
targetTotalPagesLabel: 'With target index',
|
|
28
|
+
entriesPerPageLabel: 'Entries per target page',
|
|
29
|
+
indexShareLabel: 'Index share of book',
|
|
30
|
+
statusBalanced: 'Target matches the estimate',
|
|
31
|
+
statusTight: 'Target is too tight',
|
|
32
|
+
statusRoomy: 'Target leaves room',
|
|
33
|
+
statusBalancedHint: 'Your planned index allowance matches the density model.',
|
|
34
|
+
statusTightHint: 'Add pages or reduce entries before typesetting the final index.',
|
|
35
|
+
statusRoomyHint: 'The allowance is generous and may absorb late editorial additions.',
|
|
36
|
+
sceneLabel: 'The page budget',
|
|
37
|
+
sceneBodyLabel: 'body pages',
|
|
38
|
+
sceneIndexLabel: 'index pages',
|
|
39
|
+
sceneCaption: 'The estimated book occupies',
|
|
40
|
+
sceneTargetCaption: 'Your target allowance produces',
|
|
41
|
+
sourceNote: 'This is an editorial planning model. Final pagination depends on typesetting, proof corrections, index style, and the publisher or printer.',
|
|
42
|
+
summaryLabel: 'Budget signal',
|
|
43
|
+
summaryPagesOver: 'pages over target',
|
|
44
|
+
summaryPagesSpare: 'pages spare',
|
|
45
|
+
summaryOnTarget: 'On target',
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
const seo: ToolLocaleContent<BookIndexUI>['seo'] = [
|
|
49
|
+
{ type: 'title', text: 'Budget Index Pages Before Your Book Is Typeset', level: 2 },
|
|
50
|
+
{ type: 'paragraph', html: 'An analytical index is back matter that adds real pages to a printed book. This calculator turns a manuscript word count, trim size, typography density, expected index entries, and a page allowance into a practical editorial budget. It keeps the body estimate and the index estimate visible as separate parts of the same book.' },
|
|
51
|
+
{ type: 'title', text: 'What the Estimate Does', level: 2 },
|
|
52
|
+
{ type: 'paragraph', html: 'Body pages are estimated from manuscript words divided by a density-adjusted words-per-page value. Index pages are estimated from the expected number of entries divided by the entries-per-page capacity of the chosen typography profile, then rounded up to a whole page. The book total adds the body and estimated index pages; the target total adds the body to the page allowance you plan to reserve.' },
|
|
53
|
+
{ type: 'list', items: ['Use expected entries rather than the number of unique words in the manuscript.', 'Compare the estimated index pages with the target allowance before layout begins.', 'Treat a high entries-per-target-page value as a signal to simplify, split, or expand the index budget.', 'Keep the trim size and density close to the intended interior design when comparing scenarios.'] },
|
|
54
|
+
{ type: 'title', text: 'How to Read a Tight Budget', level: 2 },
|
|
55
|
+
{ type: 'paragraph', html: 'A tight target means the planned allowance would require more entries per page than the selected profile supports. That can lead to cramped typography, weaker hierarchy, or an index that is difficult to scan. The useful editorial response is not always to squeeze harder: remove passing references, merge duplicate concepts, clarify cross references, or reserve more pages for the reader-facing navigation tool.' },
|
|
56
|
+
{ type: 'title', text: 'Plan Early and Recheck at Proof', level: 2 },
|
|
57
|
+
{ type: 'paragraph', html: 'Index locators depend on the typeset page sequence, so a late change in the body can move page references and force another index pass. Use this calculator while planning the book, then revisit the budget when the proof has stabilized. The result does not replace publisher instructions or a professional indexer review.' },
|
|
58
|
+
{ type: 'tip', title: 'The index is not a word count', html: 'Two books with the same number of words can need very different indexes. Names, subentries, cross references, and the amount of useful material per locator change the final footprint. Count the entries you expect a reader to use, not every mention in the manuscript.' },
|
|
59
|
+
];
|
|
60
|
+
|
|
61
|
+
const applicationSchema = ({
|
|
62
|
+
'@context': 'https://schema.org',
|
|
63
|
+
'@type': 'SoftwareApplication',
|
|
64
|
+
name: 'Book Index Page Budget Calculator',
|
|
65
|
+
applicationCategory: 'DesignApplication',
|
|
66
|
+
operatingSystem: 'Any',
|
|
67
|
+
offers: { '@type': 'Offer', price: '0', priceCurrency: 'USD' },
|
|
68
|
+
} as unknown) as SoftwareApplication & Record<string, unknown>;
|
|
69
|
+
|
|
70
|
+
const faqSchema = ({
|
|
71
|
+
'@context': 'https://schema.org',
|
|
72
|
+
'@type': 'FAQPage',
|
|
73
|
+
mainEntity: [
|
|
74
|
+
{ '@type': 'Question', name: 'What should I enter as index entries?', acceptedAnswer: { '@type': 'Answer', text: 'Enter the topics, names, places, subentries, and cross references you expect to include in the finished index.' } },
|
|
75
|
+
{ '@type': 'Question', name: 'Why are body and index pages calculated separately?', acceptedAnswer: { '@type': 'Answer', text: 'The body is driven by words and page design, while the index is driven by entries and index density.' } },
|
|
76
|
+
{ '@type': 'Question', name: 'What does a tight target mean?', acceptedAnswer: { '@type': 'Answer', text: 'It means the target pages would require more entries per page than the selected profile is designed to hold.' } },
|
|
77
|
+
{ '@type': 'Question', name: 'Can this replace the final index proof?', acceptedAnswer: { '@type': 'Answer', text: 'No. It is a planning estimate. Final locators and pagination must be checked against typeset proofs.' } },
|
|
78
|
+
],
|
|
79
|
+
} as unknown) as FAQPage & Record<string, unknown>;
|
|
80
|
+
|
|
81
|
+
const howToSchema = ({
|
|
82
|
+
'@context': 'https://schema.org',
|
|
83
|
+
'@type': 'HowTo',
|
|
84
|
+
name: 'Build a preliminary book index page budget',
|
|
85
|
+
step: [
|
|
86
|
+
{ '@type': 'HowToStep', name: 'Enter the manuscript size', text: 'Enter the manuscript word count before back matter.' },
|
|
87
|
+
{ '@type': 'HowToStep', name: 'Match the page design', text: 'Set the trim dimensions and choose airy, standard, or compact typography.' },
|
|
88
|
+
{ '@type': 'HowToStep', name: 'Describe the index', text: 'Enter the expected number of index entries and the page allowance you want to reserve.' },
|
|
89
|
+
{ '@type': 'HowToStep', name: 'Act on the comparison', text: 'Use the estimated index pages and status to adjust the editorial plan before typesetting.' },
|
|
90
|
+
],
|
|
91
|
+
} as unknown) as HowTo & Record<string, unknown>;
|
|
92
|
+
|
|
93
|
+
export const content: ToolLocaleContent<BookIndexUI> = {
|
|
94
|
+
slug: 'book-index-page-budget-calculator',
|
|
95
|
+
title: 'Book Index Page Budget Calculator',
|
|
96
|
+
description: 'Estimate the pages an analytical index will add to your book and compare that footprint with your editorial page allowance.',
|
|
97
|
+
ui,
|
|
98
|
+
seo,
|
|
99
|
+
faq: [
|
|
100
|
+
{ question: 'What should I enter as index entries?', answer: 'Enter the topics, names, places, subentries, and cross references you expect to include in the finished index.' },
|
|
101
|
+
{ question: 'Why are body and index pages calculated separately?', answer: 'The body is driven by words and page design, while the index is driven by entries and index density.' },
|
|
102
|
+
{ question: 'What does a tight target mean?', answer: 'It means the target pages would require more entries per page than the selected profile is designed to hold.' },
|
|
103
|
+
{ question: 'Can this replace the final index proof?', answer: 'No. It is a planning estimate. Final locators and pagination must be checked against typeset proofs.' },
|
|
104
|
+
],
|
|
105
|
+
bibliography: BOOK_INDEX_BIBLIOGRAPHY,
|
|
106
|
+
howTo: [
|
|
107
|
+
{ name: 'Enter the manuscript size', text: 'Enter the manuscript word count before back matter.' },
|
|
108
|
+
{ name: 'Match the page design', text: 'Set the trim dimensions and choose a typography density.' },
|
|
109
|
+
{ name: 'Describe the index', text: 'Enter expected entries and the index page allowance.' },
|
|
110
|
+
{ name: 'Act on the comparison', text: 'Adjust the editorial plan when the allowance is tight.' },
|
|
111
|
+
],
|
|
112
|
+
schemas: [applicationSchema, faqSchema, howToSchema],
|
|
113
|
+
};
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { content as base } from './en';
|
|
2
|
+
import type { BookIndexUI } from '../ui';
|
|
3
|
+
import type { ToolLocaleContent } from '../../../types';
|
|
4
|
+
|
|
5
|
+
const ui: BookIndexUI = {
|
|
6
|
+
...base.ui,
|
|
7
|
+
wordsLabel: 'Palabras del manuscrito', wordsHint: 'Texto principal antes de los anexos', trimWidthLabel: 'Ancho de corte', trimHeightLabel: 'Alto de corte', trimHint: 'Tamaño final de la página', unitLabel: 'Unidades de página', metricButtonLabel: 'Métrico cm', imperialButtonLabel: 'Imperial pulgadas', densityLabel: 'Densidad tipográfica', densityHint: 'Controla palabras y entradas por página', airyLabel: 'Aireada', standardLabel: 'Estándar', compactLabel: 'Compacta', indexEntriesLabel: 'Entradas de índice previstas', indexEntriesHint: 'Temas, nombres, lugares y referencias cruzadas', targetIndexPagesLabel: 'Páginas de índice reservadas', targetIndexPagesHint: 'Tu margen de producción para el índice', textPagesLabel: 'Páginas de texto', estimatedIndexPagesLabel: 'Índice estimado', totalPagesLabel: 'Total estimado del libro', targetTotalPagesLabel: 'Con el índice reservado', entriesPerPageLabel: 'Entradas por página objetivo', indexShareLabel: 'Parte del índice en el libro', statusBalanced: 'El objetivo coincide con la estimación', statusTight: 'El objetivo es demasiado ajustado', statusRoomy: 'El objetivo deja margen', statusBalancedHint: 'La reserva prevista coincide con el modelo de densidad.', statusTightHint: 'Reserva más páginas o reduce entradas antes de maquetar el índice.', statusRoomyHint: 'El margen puede absorber incorporaciones editoriales de última hora.', sceneLabel: 'El presupuesto de páginas', sceneBodyLabel: 'páginas de texto', sceneIndexLabel: 'páginas de índice', sceneCaption: 'El libro estimado ocupa', sceneTargetCaption: 'Con tu reserva el total sería', sourceNote: 'Es un modelo de planificación editorial. La paginación final depende de la maquetación, las correcciones, el estilo del índice y las indicaciones de la editorial o imprenta.', summaryLabel: 'Señal del presupuesto', summaryPagesOver: 'páginas por encima', summaryPagesSpare: 'páginas de margen', summaryOnTarget: 'En objetivo',
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
const faq = [
|
|
11
|
+
{ question: '¿Qué debo introducir como entradas de índice?', answer: 'Introduce los temas, nombres, lugares, subentradas y referencias cruzadas que esperas incluir en el índice final.' },
|
|
12
|
+
{ question: '¿Por qué se calculan por separado el texto y el índice?', answer: 'El texto depende de las palabras y del diseño de página; el índice depende de sus entradas y de su densidad.' },
|
|
13
|
+
{ question: '¿Qué significa un objetivo demasiado ajustado?', answer: 'Significa que necesitarías colocar más entradas por página de las que admite razonablemente el perfil elegido.' },
|
|
14
|
+
{ question: '¿Sustituye esto a la prueba final del índice?', answer: 'No. Es una estimación de planificación. Los localizadores y la paginación deben revisarse sobre las pruebas maquetadas.' },
|
|
15
|
+
];
|
|
16
|
+
|
|
17
|
+
const howTo = [
|
|
18
|
+
{ name: 'Introduce el manuscrito', text: 'Indica las palabras del texto principal antes de los anexos.' },
|
|
19
|
+
{ name: 'Ajusta el diseño', text: 'Elige el tamaño final y la densidad tipográfica prevista.' },
|
|
20
|
+
{ name: 'Describe el índice', text: 'Estima las entradas y reserva un número de páginas.' },
|
|
21
|
+
{ name: 'Actúa sobre la comparación', text: 'Amplía la reserva o reduce entradas cuando el objetivo quede corto.' },
|
|
22
|
+
];
|
|
23
|
+
|
|
24
|
+
const seo: ToolLocaleContent<BookIndexUI>['seo'] = [
|
|
25
|
+
{ type: 'title', text: 'Calcula pronto cuántas páginas añadirá el índice de tu libro', level: 2 },
|
|
26
|
+
{ type: 'paragraph', html: 'Un índice analítico añade páginas reales a la parte final de un libro impreso. Esta herramienta combina palabras, formato, densidad tipográfica, entradas previstas y reserva editorial en una primera previsión útil.' },
|
|
27
|
+
{ type: 'title', text: 'Cómo interpretar el resultado', level: 2 },
|
|
28
|
+
{ type: 'paragraph', html: 'Las páginas de texto se estiman a partir de las palabras y la densidad. Las páginas de índice se estiman a partir de las entradas y la capacidad por página. Compara ambas cifras antes de cerrar la maquetación.' },
|
|
29
|
+
{ type: 'list', items: ['Cuenta entradas previstas, no todas las palabras del manuscrito.', 'Usa el formato y la densidad que tendrá el interior real.', 'Amplía la reserva si habrá muchos subapartados o referencias cruzadas.', 'Vuelve a calcular cuando la prueba de páginas sea estable.'] },
|
|
30
|
+
{ type: 'title', text: 'Un objetivo ajustado requiere una decisión editorial', level: 2 },
|
|
31
|
+
{ type: 'paragraph', html: 'Forzar demasiadas entradas en pocas páginas puede reducir la legibilidad. Antes de apretar la tipografía, depura referencias pasajeras, une conceptos duplicados o reserva más espacio para la herramienta de navegación del lector.' },
|
|
32
|
+
{ type: 'tip', title: 'No es una cifra lista para imprenta', html: 'La fuente, la composición, las correcciones y el estilo del índice cambian el resultado final. Confirma siempre la cifra con la editorial, la imprenta o un profesional del indexado.' },
|
|
33
|
+
];
|
|
34
|
+
|
|
35
|
+
export const content = { ...base, slug: 'calculadora-presupuesto-paginas-indice-libro', title: 'Calculadora de presupuesto de páginas de índice', description: 'Estima las páginas que añadirá un índice analítico y compáralas con la reserva editorial de tu libro.', ui, seo, faq, howTo };
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { content as base } from './en';
|
|
2
|
+
import type { BookIndexUI } from '../ui';
|
|
3
|
+
|
|
4
|
+
const ui: BookIndexUI = { ...base.ui, wordsLabel: 'Mots du manuscrit', wordsHint: 'Texte principal avant les annexes', trimWidthLabel: 'Largeur de coupe', trimHeightLabel: 'Hauteur de coupe', trimHint: 'Format fini de la page', unitLabel: 'Unites de page', metricButtonLabel: 'Metrique cm', imperialButtonLabel: 'Imperial pouces', densityLabel: 'Densite typographique', densityHint: 'Regle les mots et les entrees par page', airyLabel: 'Aeree', standardLabel: 'Standard', compactLabel: 'Compacte', indexEntriesLabel: 'Entrees d index prevues', indexEntriesHint: 'Themes, noms, lieux et renvois', targetIndexPagesLabel: 'Pages d index prevues', targetIndexPagesHint: 'Votre reserve de production pour l index', textPagesLabel: 'Pages de texte', estimatedIndexPagesLabel: 'Index estime', totalPagesLabel: 'Total estime du livre', targetTotalPagesLabel: 'Avec la reserve d index', entriesPerPageLabel: 'Entrees par page cible', indexShareLabel: 'Part de l index dans le livre', statusBalanced: 'La cible correspond a l estimation', statusTight: 'La cible est trop serree', statusRoomy: 'La cible laisse de la marge', statusBalancedHint: 'La reserve prevue correspond au modele de densite.', statusTightHint: 'Ajoutez des pages ou reduisez les entrees avant la composition.', statusRoomyHint: 'La marge peut absorber des ajouts editoriaux tardifs.', sceneLabel: 'Le budget de pages', sceneBodyLabel: 'pages de texte', sceneIndexLabel: 'pages d index', sceneCaption: 'Le livre estime occupe', sceneTargetCaption: 'Avec votre reserve, le total serait', sourceNote: 'Il s agit d un modele de planification editoriale. La pagination finale depend de la composition, des corrections, du style d index et des consignes de l editeur ou de l imprimeur.', summaryLabel: 'Signal du budget', summaryPagesOver: 'pages au dessus de la cible', summaryPagesSpare: 'pages de marge', summaryOnTarget: 'Dans la cible' };
|
|
5
|
+
const faq = [{ question: 'Que dois je saisir comme entrees d index ?', answer: 'Saisissez les themes, noms, lieux, sous entrees et renvois prevus dans l index final.' }, { question: 'Pourquoi separer les pages de texte et d index ?', answer: 'Le texte depend des mots et de la mise en page, tandis que l index depend de ses entrees et de sa densite.' }, { question: 'Que signifie une cible trop serree ?', answer: 'La reserve demanderait plus d entrees par page que le profil choisi ne peut en accueillir confortablement.' }, { question: 'Le resultat remplace t il l epreuve finale ?', answer: 'Non. C est une estimation de planification. Les renvois et la pagination doivent etre verifies sur l epreuve composee.' }];
|
|
6
|
+
const howTo = [{ name: 'Saisir le manuscrit', text: 'Indiquez le nombre de mots du texte principal.' }, { name: 'Adapter la maquette', text: 'Choisissez le format fini et la densite typographique.' }, { name: 'Decrire l index', text: 'Estimez les entrees et reservez un nombre de pages.' }, { name: 'Agir sur l ecart', text: 'Augmentez la reserve ou reduisez les entrees si la cible est trop serree.' }];
|
|
7
|
+
const seo = [{ type: 'title', text: 'Prevoir le budget de pages d index du livre', level: 2 }, { type: 'paragraph', html: 'Un index analytique ajoute des pages reelles a la fin d un livre imprime. Cet outil combine les mots du manuscrit, le format, la densite typographique, les entrees prevues et la reserve editoriale.' }, { type: 'title', text: 'Lire l estimation', level: 2 }, { type: 'paragraph', html: 'Les pages de texte dependent des mots et de la densite. Les pages d index dependent du nombre d entrees et de la capacite par page. Comparez l estimation a la reserve avant de finaliser la composition.' }, { type: 'list', items: ['Comptez les entrees prevues plutot que chaque mot du manuscrit.', 'Utilisez le format et la densite de l interieur prevu.', 'Reservez davantage si les renvois et sous entrees sont nombreux.', 'Recalculez lorsque l epreuve de pages est stabilisee.'] }, { type: 'title', text: 'Une cible serree appelle une decision editoriale', level: 2 }, { type: 'paragraph', html: 'Entasser trop d entrees peut rendre l index difficile a parcourir. Nettoyez les renvois peu utiles ou augmentez la reserve avant de reduire davantage la taille du texte.' }, { type: 'tip', title: 'Ce n est pas une valeur d impression definitive', html: 'La police, la composition, les corrections et le style d index changent le resultat final. Confirmez le avec l editeur, l imprimeur ou un indexeur professionnel.' }];
|
|
8
|
+
export const content = { ...base, slug: 'calculateur-budget-pages-index-livre', title: 'Calculateur du budget de pages indexées', description: 'Estimez les pages ajoutées par un index analytique et comparez-les à la réserve éditoriale de votre livre.', ui, seo, faq, howTo };
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { content as base } from './en';
|
|
2
|
+
import type { BookIndexUI } from '../ui';
|
|
3
|
+
import type { ToolLocaleContent } from '../../../types';
|
|
4
|
+
|
|
5
|
+
const ui: BookIndexUI = {
|
|
6
|
+
...base.ui,
|
|
7
|
+
wordsLabel: 'Kata dalam manuskrip', wordsHint: 'Teks utama sebelum bagian belakang', trimWidthLabel: 'Lebar potong', trimHeightLabel: 'Tinggi potong', trimHint: 'Ukuran halaman jadi', unitLabel: 'Satuan halaman', metricButtonLabel: 'Metrik cm', imperialButtonLabel: 'Imperial inci', densityLabel: 'Kepadatan tipografi', densityHint: 'Mengatur kata dan entri indeks per halaman', airyLabel: 'Renggang', standardLabel: 'Standar', compactLabel: 'Padat', indexEntriesLabel: 'Perkiraan entri indeks', indexEntriesHint: 'Topik, nama, tempat, dan rujuk silang', targetIndexPagesLabel: 'Halaman indeks yang ditargetkan', targetIndexPagesHint: 'Alokasi produksi untuk indeks', textPagesLabel: 'Halaman isi', estimatedIndexPagesLabel: 'Perkiraan indeks', totalPagesLabel: 'Total buku yang diperkirakan', targetTotalPagesLabel: 'Dengan target indeks', entriesPerPageLabel: 'Entri per halaman target', indexShareLabel: 'Porsi indeks dalam buku', statusBalanced: 'Target sesuai perkiraan', statusTight: 'Target terlalu ketat', statusRoomy: 'Target masih longgar', statusBalancedHint: 'Alokasi indeks sesuai dengan model kepadatan.', statusTightHint: 'Tambahkan halaman atau kurangi entri sebelum penyusunan akhir.', statusRoomyHint: 'Kelonggaran ini dapat menampung tambahan editorial di akhir.', sceneLabel: 'Anggaran halaman', sceneBodyLabel: 'halaman isi', sceneIndexLabel: 'halaman indeks', sceneCaption: 'Perkiraan buku menggunakan', sceneTargetCaption: 'Dengan alokasi target, totalnya menjadi', sourceNote: 'Ini adalah model perencanaan editorial. Pagination akhir bergantung pada tata letak, koreksi, gaya indeks, serta arahan penerbit atau percetakan.', summaryLabel: 'Sinyal anggaran', summaryPagesOver: 'halaman di atas target', summaryPagesSpare: 'halaman tersisa', summaryOnTarget: 'Sesuai target',
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
const faq = [
|
|
11
|
+
{ question: 'Apa yang harus dimasukkan sebagai entri indeks?', answer: 'Masukkan topik, nama, tempat, subentri, dan rujuk silang yang akan muncul dalam indeks akhir.' },
|
|
12
|
+
{ question: 'Mengapa halaman isi dan indeks dihitung terpisah?', answer: 'Isi dipengaruhi jumlah kata dan desain halaman, sedangkan indeks dipengaruhi jumlah entri dan kepadatannya.' },
|
|
13
|
+
{ question: 'Apa arti target yang terlalu ketat?', answer: 'Alokasi tersebut menuntut lebih banyak entri per halaman daripada yang wajar untuk profil yang dipilih.' },
|
|
14
|
+
{ question: 'Apakah hasil ini menggantikan pemeriksaan indeks akhir?', answer: 'Tidak. Ini adalah perkiraan perencanaan. Rujukan halaman harus diperiksa pada proof yang sudah ditata.' },
|
|
15
|
+
];
|
|
16
|
+
|
|
17
|
+
const howTo = [
|
|
18
|
+
{ name: 'Masukkan manuskrip', text: 'Masukkan jumlah kata teks utama sebelum bagian belakang.' },
|
|
19
|
+
{ name: 'Sesuaikan desain halaman', text: 'Pilih ukuran jadi dan kepadatan tipografi.' },
|
|
20
|
+
{ name: 'Jelaskan indeks', text: 'Perkirakan entri dan alokasikan jumlah halaman.' },
|
|
21
|
+
{ name: 'Tindak lanjuti hasil', text: 'Tambah alokasi atau kurangi entri jika target terlalu ketat.' },
|
|
22
|
+
];
|
|
23
|
+
|
|
24
|
+
const seo: ToolLocaleContent<BookIndexUI>['seo'] = [
|
|
25
|
+
{ type: 'title', text: 'Rencanakan anggaran halaman indeks buku sejak awal', level: 2 },
|
|
26
|
+
{ type: 'paragraph', html: 'Indeks analitis menambah halaman nyata pada bagian belakang buku cetak. Alat ini menggabungkan kata manuskrip, ukuran halaman, kepadatan tipografi, entri yang diperkirakan, dan alokasi editorial.' },
|
|
27
|
+
{ type: 'title', text: 'Cara membaca perkiraan', level: 2 },
|
|
28
|
+
{ type: 'paragraph', html: 'Halaman isi diperkirakan dari jumlah kata dan kepadatan. Halaman indeks diperkirakan dari jumlah entri dan kapasitas per halaman. Bandingkan perkiraan dengan alokasi sebelum tata letak selesai.' },
|
|
29
|
+
{ type: 'list', items: ['Hitung entri yang diperkirakan, bukan semua kata dalam manuskrip.', 'Gunakan ukuran dan kepadatan yang mendekati desain buku sebenarnya.', 'Sediakan halaman tambahan bila rujuk silang dan subentri banyak.', 'Hitung ulang setelah proof halaman stabil.'] },
|
|
30
|
+
{ type: 'title', text: 'Target ketat adalah sinyal editorial', level: 2 },
|
|
31
|
+
{ type: 'paragraph', html: 'Memaksa terlalu banyak entri dalam sedikit halaman dapat menurunkan keterbacaan. Bersihkan rujukan yang kurang berguna atau tambah ruang sebelum mempersempit tipografi.' },
|
|
32
|
+
{ type: 'tip', title: 'Bukan angka final untuk percetakan', html: 'Font, tata letak, koreksi, dan gaya indeks memengaruhi hasil akhir. Konfirmasikan dengan penerbit, percetakan, atau pengindeks profesional.' },
|
|
33
|
+
];
|
|
34
|
+
|
|
35
|
+
export const content = { ...base, slug: 'kalkulator-anggaran-halaman-indeks-buku', title: 'Kalkulator Anggaran Halaman Indeks Buku', description: 'Perkirakan halaman tambahan dari indeks analitis dan bandingkan dengan alokasi editorial buku Anda.', ui, seo, faq, howTo };
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { content as base } from './en';
|
|
2
|
+
import type { BookIndexUI } from '../ui';
|
|
3
|
+
|
|
4
|
+
const ui: BookIndexUI = { ...base.ui, wordsLabel: 'Parole del manoscritto', wordsHint: 'Testo principale prima degli allegati', trimWidthLabel: 'Larghezza rifilata', trimHeightLabel: 'Altezza rifilata', trimHint: 'Formato finito della pagina', unitLabel: 'Unita della pagina', metricButtonLabel: 'Metrico cm', imperialButtonLabel: 'Imperiale pollici', densityLabel: 'Densita tipografica', densityHint: 'Controlla parole e voci indice per pagina', airyLabel: 'Aria', standardLabel: 'Standard', compactLabel: 'Compatta', indexEntriesLabel: 'Voci indice previste', indexEntriesHint: 'Argomenti, nomi, luoghi e rinvii', targetIndexPagesLabel: 'Pagine indice previste', targetIndexPagesHint: 'Margine di produzione per l indice', textPagesLabel: 'Pagine di testo', estimatedIndexPagesLabel: 'Indice stimato', totalPagesLabel: 'Totale stimato del libro', targetTotalPagesLabel: 'Con l indice previsto', entriesPerPageLabel: 'Voci per pagina obiettivo', indexShareLabel: 'Quota dell indice nel libro', statusBalanced: 'L obiettivo corrisponde alla stima', statusTight: 'L obiettivo e troppo stretto', statusRoomy: 'L obiettivo lascia margine', statusBalancedHint: 'La riserva prevista corrisponde al modello di densita.', statusTightHint: 'Aggiungi pagine o riduci le voci prima della composizione.', statusRoomyHint: 'Il margine puo assorbire aggiunte editoriali tardive.', sceneLabel: 'Il budget di pagine', sceneBodyLabel: 'pagine di testo', sceneIndexLabel: 'pagine indice', sceneCaption: 'Il libro stimato occupa', sceneTargetCaption: 'Con la tua riserva il totale sarebbe', sourceNote: 'E un modello di pianificazione editoriale. La paginazione finale dipende da composizione, correzioni, stile dell indice e indicazioni dell editore o dello stampatore.', summaryLabel: 'Segnale del budget', summaryPagesOver: 'pagine oltre l obiettivo', summaryPagesSpare: 'pagine disponibili', summaryOnTarget: 'In linea' };
|
|
5
|
+
const faq = [{ question: 'Cosa devo inserire come voci indice?', answer: 'Inserisci argomenti, nomi, luoghi, sottovoci e rinvii previsti nell indice finale.' }, { question: 'Perche testo e indice sono calcolati separatamente?', answer: 'Il testo dipende dalle parole e dal progetto della pagina, mentre l indice dipende dalle voci e dalla densita.' }, { question: 'Cosa significa un obiettivo troppo stretto?', answer: 'La riserva richiederebbe piu voci per pagina di quante il profilo scelto possa contenere comodamente.' }, { question: 'Sostituisce la prova finale dell indice?', answer: 'No. E una stima di pianificazione. Rinvii e paginazione vanno verificati sulla prova impaginata.' }];
|
|
6
|
+
const howTo = [{ name: 'Inserisci il manoscritto', text: 'Indica il numero di parole del testo principale.' }, { name: 'Adatta il progetto', text: 'Scegli formato finito e densita tipografica.' }, { name: 'Descrivi l indice', text: 'Stima le voci e riserva un numero di pagine.' }, { name: 'Agisci sul confronto', text: 'Aumenta la riserva o riduci le voci quando l obiettivo e troppo stretto.' }];
|
|
7
|
+
const seo = [{ type: 'title', text: 'Prevedere il budget di pagine dell indice del libro', level: 2 }, { type: 'paragraph', html: 'Un indice analitico aggiunge pagine reali alla parte finale di un libro stampato. Questo strumento combina parole, formato, densita tipografica, voci previste e riserva editoriale.' }, { type: 'title', text: 'Come leggere la stima', level: 2 }, { type: 'paragraph', html: 'Le pagine di testo dipendono dalle parole e dalla densita. Le pagine indice dipendono dalle voci e dalla capacita per pagina. Confronta la stima con la riserva prima di chiudere l impaginazione.' }, { type: 'list', items: ['Conta le voci previste, non tutte le parole del manoscritto.', 'Usa il formato e la densita del progetto reale.', 'Riserva spazio extra se ci sono molti rinvii e sottovoci.', 'Ricalcola quando la prova di pagina e stabile.'] }, { type: 'title', text: 'Un obiettivo stretto richiede una scelta editoriale', level: 2 }, { type: 'paragraph', html: 'Concentrare troppe voci in poche pagine puo ridurre la leggibilita. Pulisci i rinvii poco utili o aumenta lo spazio prima di comprimere ulteriormente la tipografia.' }, { type: 'tip', title: 'Non e un valore definitivo per la stampa', html: 'Font, composizione, correzioni e stile dell indice cambiano il risultato finale. Confermalo con editore, stampatore o indicizzatore professionale.' }];
|
|
8
|
+
export const content = { ...base, slug: 'calcolatore-budget-pagine-indice-libro', title: 'Calcolatore del budget di pagine dell indice', description: 'Stima le pagine aggiunte da un indice analitico e confrontale con la riserva editoriale più adatta del tuo libro.', ui, seo, faq, howTo };
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { content as base } from './en';
|
|
2
|
+
import type { BookIndexUI } from '../ui';
|
|
3
|
+
|
|
4
|
+
const ui: BookIndexUI = { ...base.ui, wordsLabel: '原稿の語数', wordsHint: '後付けを除く本文', trimWidthLabel: '仕上がり幅', trimHeightLabel: '仕上がり高さ', trimHint: '完成時のページサイズ', unitLabel: 'ページ単位', metricButtonLabel: 'メートル cm', imperialButtonLabel: 'インチ', densityLabel: '組版の密度', densityHint: '1ページあたりの本文語数と索引項目数を調整', airyLabel: 'ゆったり', standardLabel: '標準', compactLabel: '詰める', indexEntriesLabel: '想定する索引項目数', indexEntriesHint: 'テーマ、名前、場所、参照項目', targetIndexPagesLabel: '確保する索引ページ', targetIndexPagesHint: '索引の制作に割り当てるページ数', textPagesLabel: '本文ページ', estimatedIndexPagesLabel: '索引の見積もり', totalPagesLabel: '本の総ページ数', targetTotalPagesLabel: '目標ページを使った場合', entriesPerPageLabel: '目標ページあたりの項目数', indexShareLabel: '本に占める索引の割合', statusBalanced: '目標は見積もりどおり', statusTight: '目標が厳しすぎます', statusRoomy: '目標に余裕があります', statusBalancedHint: '確保したページ数は密度モデルと一致しています。', statusTightHint: '組版前にページを増やすか項目を減らしてください。', statusRoomyHint: '余裕があるため、後からの編集追加にも対応できます。', sceneLabel: 'ページ予算', sceneBodyLabel: '本文ページ', sceneIndexLabel: '索引ページ', sceneCaption: '見積もり上の本は', sceneTargetCaption: '目標ページを使うと', sourceNote: 'これは編集段階の計画モデルです。最終ページ数は組版、校正、索引の形式、出版社や印刷所の指定で変わります。', summaryLabel: '予算の状態', summaryPagesOver: 'ページ超過', summaryPagesSpare: 'ページの余裕', summaryOnTarget: '目標どおり', };
|
|
5
|
+
const faq = [{ question: '索引項目には何を入力しますか?', answer: '完成した索引に載せるテーマ、名前、場所、細目、参照項目を入力します。' }, { question: '本文と索引を分けて計算する理由は?', answer: '本文は語数とページ設計、索引は項目数と索引の密度によってページ数が決まるためです。' }, { question: '目標が厳しいとはどういう意味ですか?', answer: '選択した密度で無理なく収まる項目数を超えて、1ページに詰める必要があるという意味です。' }, { question: '最終校正の代わりになりますか?', answer: 'いいえ。計画用の見積もりです。ページ参照とページ数は組版後の校正で確認してください。' }];
|
|
6
|
+
const howTo = [{ name: '原稿量を入力する', text: '本文の語数を入力します。' }, { name: 'ページ設計を合わせる', text: '仕上がりサイズと組版の密度を選びます。' }, { name: '索引を見積もる', text: '項目数と確保するページ数を入力します。' }, { name: '差を確認する', text: '目標が厳しければページを増やすか項目を整理します。' }];
|
|
7
|
+
const seo = [{ type: 'title', text: '本の索引ページ数を早めに見積もる', level: 2 }, { type: 'paragraph', html: '索引は印刷された本の後半に実際のページを追加します。このツールは原稿の語数、仕上がりサイズ、組版密度、想定項目数、編集上の予算を一つの計画にまとめます。' }, { type: 'title', text: '結果の読み方', level: 2 }, { type: 'paragraph', html: '本文ページは語数と密度から、索引ページは項目数と1ページの収容力から見積もります。組版を確定する前に、見積もりと確保したページを比較してください。' }, { type: 'list', items: ['原稿の全語数ではなく、想定する索引項目を数える。', '実際の本に近いサイズと密度を使う。', '参照項目や細目が多い場合は余分なページを確保する。', '校正用のページが安定したら再計算する。'] }, { type: 'title', text: '厳しい目標は編集上の判断材料', level: 2 }, { type: 'paragraph', html: '少ないページに項目を詰め込むと、索引の読みやすさが下がります。文字をさらに圧縮する前に、不要な参照を整理するかページを増やしてください。' }, { type: 'tip', title: '印刷用の確定値ではありません', html: '書体、組版、校正、索引形式で最終結果は変わります。出版社、印刷所、専門の索引作成者に確認してください。' }];
|
|
8
|
+
export const content = { ...base, slug: 'book-index-page-budget-calculator', title: '本の索引ページ予算計算機', description: '索引が追加するページ数を見積もり、本の編集上のページ予算と比較します。', ui, seo, faq, howTo };
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { content as base } from './en';
|
|
2
|
+
import type { BookIndexUI } from '../ui';
|
|
3
|
+
|
|
4
|
+
const ui: BookIndexUI = { ...base.ui, wordsLabel: '원고 단어 수', wordsHint: '부록을 제외한 본문', trimWidthLabel: '재단 너비', trimHeightLabel: '재단 높이', trimHint: '완성 페이지 크기', unitLabel: '페이지 단위', metricButtonLabel: '미터법 cm', imperialButtonLabel: '인치', densityLabel: '조판 밀도', densityHint: '페이지당 본문 단어와 색인 항목 수를 조정합니다', airyLabel: '여유 있게', standardLabel: '표준', compactLabel: '촘촘하게', indexEntriesLabel: '예상 색인 항목', indexEntriesHint: '주제, 이름, 장소 및 상호 참조', targetIndexPagesLabel: '예약할 색인 페이지', targetIndexPagesHint: '색인 제작에 배정할 페이지 수', textPagesLabel: '본문 페이지', estimatedIndexPagesLabel: '예상 색인', totalPagesLabel: '예상 책 전체', targetTotalPagesLabel: '목표 색인 포함', entriesPerPageLabel: '목표 페이지당 항목', indexShareLabel: '책에서 색인이 차지하는 비율', statusBalanced: '목표가 예상치와 일치합니다', statusTight: '목표가 너무 촘촘합니다', statusRoomy: '목표에 여유가 있습니다', statusBalancedHint: '예약한 색인 분량이 밀도 모델과 일치합니다.', statusTightHint: '최종 조판 전에 페이지를 늘리거나 항목을 줄이세요.', statusRoomyHint: '남은 공간이 늦은 편집 추가를 흡수할 수 있습니다.', sceneLabel: '페이지 예산', sceneBodyLabel: '본문 페이지', sceneIndexLabel: '색인 페이지', sceneCaption: '예상 책은', sceneTargetCaption: '목표 분량을 사용하면', sourceNote: '편집 계획을 위한 모델입니다. 최종 페이지 수는 조판, 교정, 색인 방식, 출판사와 인쇄소의 지침에 따라 달라집니다.', summaryLabel: '예산 신호', summaryPagesOver: '페이지 초과', summaryPagesSpare: '페이지 여유', summaryOnTarget: '목표에 맞음', };
|
|
5
|
+
const faq = [{ question: '색인 항목에는 무엇을 입력하나요?', answer: '완성된 색인에 넣을 주제, 이름, 장소, 하위 항목과 상호 참조를 입력합니다.' }, { question: '본문과 색인 페이지를 따로 계산하는 이유는 무엇인가요?', answer: '본문은 단어 수와 페이지 디자인, 색인은 항목 수와 색인 밀도에 따라 달라지기 때문입니다.' }, { question: '목표가 너무 촘촘하다는 뜻은 무엇인가요?', answer: '선택한 밀도에서 편안하게 담을 수 있는 것보다 많은 항목을 한 페이지에 넣어야 한다는 뜻입니다.' }, { question: '최종 색인 교정을 대신할 수 있나요?', answer: '아니요. 계획용 추정치입니다. 페이지 참조와 페이지 수는 조판 교정본에서 확인해야 합니다.' }];
|
|
6
|
+
const howTo = [{ name: '원고 분량 입력', text: '부록을 제외한 본문 단어 수를 입력합니다.' }, { name: '페이지 디자인 맞추기', text: '완성 크기와 조판 밀도를 선택합니다.' }, { name: '색인 설명하기', text: '항목 수와 예약할 페이지를 추정합니다.' }, { name: '차이 확인하기', text: '목표가 촘촘하면 페이지를 늘리거나 항목을 정리합니다.' }];
|
|
7
|
+
const seo = [{ type: 'title', text: '책 색인 페이지 예산을 미리 계획하세요', level: 2 }, { type: 'paragraph', html: '분석 색인은 인쇄 도서 뒷부분에 실제 페이지를 추가합니다. 이 도구는 원고 단어 수, 판형, 조판 밀도, 예상 항목과 편집 예산을 하나의 계획으로 묶습니다.' }, { type: 'title', text: '결과 읽는 법', level: 2 }, { type: 'paragraph', html: '본문 페이지는 단어 수와 밀도로, 색인 페이지는 항목 수와 페이지당 수용량으로 추정합니다. 조판을 확정하기 전에 추정치와 예약 분량을 비교하세요.' }, { type: 'list', items: ['원고의 모든 단어가 아니라 예상 색인 항목을 셉니다.', '실제 책 디자인에 가까운 크기와 밀도를 사용합니다.', '상호 참조와 하위 항목이 많다면 여분의 페이지를 예약합니다.', '페이지 교정본이 안정되면 다시 계산합니다.'] }, { type: 'title', text: '촘촘한 목표는 편집 판단의 신호입니다', level: 2 }, { type: 'paragraph', html: '적은 페이지에 너무 많은 항목을 넣으면 색인을 읽기 어려워집니다. 글자를 더 줄이기 전에 불필요한 참조를 정리하거나 공간을 늘리세요.' }, { type: 'tip', title: '인쇄용 확정값이 아닙니다', html: '서체, 조판, 교정과 색인 방식에 따라 최종 결과가 달라집니다. 출판사, 인쇄소 또는 전문 색인 작성자에게 확인하세요.' }];
|
|
8
|
+
export const content = { ...base, slug: 'book-index-page-budget-calculator', title: '책 색인 페이지 예산 계산기', description: '분석 색인이 추가할 페이지를 추정하고 책의 편집 페이지 예산과 비교합니다.', ui, seo, faq, howTo };
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { content as base } from './en';
|
|
2
|
+
import type { BookIndexUI } from '../ui';
|
|
3
|
+
|
|
4
|
+
const ui: BookIndexUI = { ...base.ui, wordsLabel: 'Woorden in manuscript', wordsHint: 'Hoofdtekst voor het nawerk', trimWidthLabel: 'Snijbreedte', trimHeightLabel: 'Snijhoogte', trimHint: 'Afgewerkt paginaformaat', unitLabel: 'Pagina eenheden', metricButtonLabel: 'Metrisch cm', imperialButtonLabel: 'Imperiaal inch', densityLabel: 'Typografische dichtheid', densityHint: 'Regelt woorden en indexitems per pagina', airyLabel: 'Ruim', standardLabel: 'Standaard', compactLabel: 'Compact', indexEntriesLabel: 'Verwachte indexitems', indexEntriesHint: 'Onderwerpen, namen, plaatsen en kruisverwijzingen', targetIndexPagesLabel: 'Gereserveerde indexpaginas', targetIndexPagesHint: 'Productieruimte voor de index', textPagesLabel: 'Tekstpaginas', estimatedIndexPagesLabel: 'Geschatte index', totalPagesLabel: 'Geschat boektotaal', targetTotalPagesLabel: 'Met indexdoel', entriesPerPageLabel: 'Items per doelpagina', indexShareLabel: 'Aandeel index in boek', statusBalanced: 'Doel komt overeen met schatting', statusTight: 'Doel is te krap', statusRoomy: 'Doel laat ruimte', statusBalancedHint: 'De geplande reserve past bij het dichtheidsmodel.', statusTightHint: 'Reserveer meer paginas of verminder items voor het zetten.', statusRoomyHint: 'De ruimte kan late redactionele toevoegingen opvangen.', sceneLabel: 'Het paginabudget', sceneBodyLabel: 'tekstpaginas', sceneIndexLabel: 'indexpaginas', sceneCaption: 'Het geschatte boek beslaat', sceneTargetCaption: 'Met je doelreserve wordt dat', sourceNote: 'Dit is een redactioneel planningsmodel. De definitieve paginering hangt af van zetwerk, correcties, indexstijl en de uitgever of drukker.', summaryLabel: 'Budgetsignaal', summaryPagesOver: 'paginas boven doel', summaryPagesSpare: 'paginas over', summaryOnTarget: 'Op doel' };
|
|
5
|
+
const faq = [{ question: 'Wat vul ik in als indexitems?', answer: 'Vul onderwerpen, namen, plaatsen, subitems en kruisverwijzingen in die in de uiteindelijke index komen.' }, { question: 'Waarom worden tekst en index apart berekend?', answer: 'De tekst hangt af van woorden en paginadesign, de index van items en indexdichtheid.' }, { question: 'Wat betekent een te krap doel?', answer: 'De reserve zou meer items per pagina vereisen dan het gekozen profiel comfortabel kan dragen.' }, { question: 'Vervangt dit de laatste indexproef?', answer: 'Nee. Het is een planningsschatting. Verwijzingen en paginering moeten in de gezette proef worden gecontroleerd.' }];
|
|
6
|
+
const howTo = [{ name: 'Manuscript invoeren', text: 'Geef het aantal woorden van de hoofdtekst op.' }, { name: 'Paginaontwerp afstemmen', text: 'Kies het afgewerkte formaat en de typografische dichtheid.' }, { name: 'Index beschrijven', text: 'Schat de items en reserveer paginas.' }, { name: 'Het verschil beoordelen', text: 'Vergroot de reserve of verminder items als het doel te krap is.' }];
|
|
7
|
+
const seo = [{ type: 'title', text: 'Plan het paginabudget van een boekindex vroeg', level: 2 }, { type: 'paragraph', html: 'Een analytische index voegt echte paginas toe aan het nawerk van een gedrukt boek. Deze tool combineert manuscriptwoorden, formaat, typografische dichtheid, verwachte items en redactionele reserve.' }, { type: 'title', text: 'De schatting lezen', level: 2 }, { type: 'paragraph', html: 'Tekstpaginas worden geschat vanuit woorden en dichtheid. Indexpaginas komen uit items en capaciteit per pagina. Vergelijk de schatting met de reserve voordat het zetwerk wordt gesloten.' }, { type: 'list', items: ['Tel verwachte indexitems, niet alle woorden in het manuscript.', 'Gebruik formaat en dichtheid van het echte boekontwerp.', 'Reserveer extra ruimte bij veel kruisverwijzingen en subitems.', 'Bereken opnieuw zodra de paginaproef stabiel is.'] }, { type: 'title', text: 'Een krap doel vraagt om een redactionele keuze', level: 2 }, { type: 'paragraph', html: 'Te veel items op weinig paginas maken een index moeilijk te doorzoeken. Ruim zwakke verwijzingen op of vergroot de ruimte voordat je de typografie verder samenperst.' }, { type: 'tip', title: 'Geen definitief drukkersgetal', html: 'Lettertype, zetwerk, correcties en indexstijl veranderen het eindresultaat. Controleer het bij uitgever, drukker of professionele indexmaker.' }];
|
|
8
|
+
export const content = { ...base, slug: 'calculator-index-paginabudget-boek', title: 'Calculator voor het paginabudget van een boekindex', description: 'Schat de extra paginas van een analytische index en vergelijk ze met je redactionele paginabudget.', ui, seo, faq, howTo };
|