docpensieve 0.5.0-beta.1 → 0.5.0-beta.2

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.
@@ -34,6 +34,7 @@ program
34
34
  .option('-t, --theme <framework>', 'tailwind | custom')
35
35
  .option('-u, --site-url <url>', 'public URL of the site')
36
36
  .option('--version-name <version>', 'first version, e.g. 1.0')
37
+ .option('--translation <code>', 'code of a second language, e.g. fr')
37
38
  .option('-y, --yes', 'accept the defaults without a dialogue')
38
39
  .option('-f, --force', 'overwrite an existing configuration')
39
40
  .option('--minimal', "leave DocPensieve's documentation out of the new site")
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "docpensieve",
3
- "version": "0.5.0-beta.1",
3
+ "version": "0.5.0-beta.2",
4
4
  "description": "DocPensieve command-line interface (init, build, check, dev, serve)",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -24,10 +24,10 @@
24
24
  "types"
25
25
  ],
26
26
  "dependencies": {
27
- "@docpensieve/components": "0.5.0-beta.1",
28
- "@docpensieve/core": "0.5.0-beta.1",
29
- "@docpensieve/shared": "0.5.0-beta.1",
30
- "@docpensieve/theme": "0.5.0-beta.1",
27
+ "@docpensieve/components": "0.5.0-beta.2",
28
+ "@docpensieve/core": "0.5.0-beta.2",
29
+ "@docpensieve/shared": "0.5.0-beta.2",
30
+ "@docpensieve/theme": "0.5.0-beta.2",
31
31
  "chalk": "^6.0.0",
32
32
  "chokidar": "^5.0.0",
33
33
  "commander": "^15.0.0"
@@ -18,6 +18,8 @@ import {
18
18
  DocPensieveError,
19
19
  THEME_FOLDER,
20
20
  THEME_FRAMEWORKS,
21
+ isLanguageCode,
22
+ languageName,
21
23
  } from '@docpensieve/shared';
22
24
 
23
25
  /**
@@ -30,7 +32,16 @@ const FRAMEWORK_LABELS = {
30
32
  };
31
33
 
32
34
  /** Answers used when there is no dialogue. */
33
- const DEFAULTS = { name: 'My documentation', siteUrl: '', theme: 'tailwind', version: '1.0' };
35
+ const DEFAULTS = {
36
+ name: 'My documentation',
37
+ siteUrl: '',
38
+ theme: 'tailwind',
39
+ version: '1.0',
40
+ translation: '',
41
+ };
42
+
43
+ /** Second language offered first, being the one whose wording ships too. */
44
+ const DEFAULT_TRANSLATION = 'fr';
34
45
 
35
46
  /**
36
47
  * Folder of the installed DocPensieve documentation, inside the version folder.
@@ -125,15 +136,43 @@ async function askDocumentation(rl) {
125
136
  }
126
137
  }
127
138
 
139
+ /**
140
+ * Asks whether the site will carry a second language, and which one.
141
+ *
142
+ * Asked rather than left to the configuration: a translation changes the
143
+ * shape of the project — a folder per language beside the pages — and that is
144
+ * cheaper to set up at the start than to retrofit.
145
+ *
146
+ * @param {import('node:readline/promises').Interface} rl
147
+ * @returns {Promise<string>} Language code, or `''` for a single language.
148
+ */
149
+ async function askTranslation(rl) {
150
+ for (;;) {
151
+ const answer = (await rl.question('Will the site be in several languages? [y/N]: '))
152
+ .trim()
153
+ .toLowerCase();
154
+ if (answer === '' || answer === 'n' || answer === 'no') return '';
155
+ if (answer === 'y' || answer === 'yes') break;
156
+ console.log('Answer not understood. Expected: y or n.');
157
+ }
158
+
159
+ for (;;) {
160
+ const code = (await ask(rl, 'Code of the second language', DEFAULT_TRANSLATION)).trim();
161
+ if (isLanguageCode(code)) return code;
162
+ console.log(`"${code}" does not name a language. Expected a code: fr, de, pt-BR, zh-Hans.`);
163
+ }
164
+ }
165
+
128
166
  /**
129
167
  * Gathers the answers, through a dialogue or from the options.
130
168
  *
131
169
  * @param {{
132
170
  * name?: string, theme?: string, siteUrl?: string, version?: string,
133
- * yes?: boolean, minimal?: boolean,
171
+ * translation?: string, yes?: boolean, minimal?: boolean,
134
172
  * }} options
135
173
  * @returns {Promise<{
136
174
  * name: string, theme: string, siteUrl: string, version: string, docs: boolean,
175
+ * translation: string,
137
176
  * }>}
138
177
  */
139
178
  async function collect(options) {
@@ -142,6 +181,7 @@ async function collect(options) {
142
181
  siteUrl: options.siteUrl ?? DEFAULTS.siteUrl,
143
182
  theme: options.theme ?? DEFAULTS.theme,
144
183
  version: options.version ?? DEFAULTS.version,
184
+ translation: options.translation ?? DEFAULTS.translation,
145
185
  docs: !options.minimal,
146
186
  };
147
187
 
@@ -154,7 +194,7 @@ async function collect(options) {
154
194
  if (!process.stdin.isTTY) {
155
195
  console.log('No interactive terminal: no questions asked, the options and defaults apply.');
156
196
  console.log(
157
- 'To choose, pass --name, --site-url, --theme, --version-name or --minimal; --yes silences this notice.',
197
+ 'To choose, pass --name, --site-url, --theme, --version-name, --translation or --minimal; --yes silences this notice.',
158
198
  );
159
199
  return fromOptions;
160
200
  }
@@ -164,9 +204,10 @@ async function collect(options) {
164
204
  const name = await ask(rl, 'Project name', fromOptions.name);
165
205
  const siteUrl = await ask(rl, 'Public URL of the site (optional)', fromOptions.siteUrl);
166
206
  const version = await ask(rl, 'First version', fromOptions.version);
207
+ const translation = options.translation ?? (await askTranslation(rl));
167
208
  const theme = options.theme ?? (await askFramework(rl));
168
209
  const docs = options.minimal ? false : await askDocumentation(rl);
169
- return { name, siteUrl, version, theme, docs };
210
+ return { name, siteUrl, version, theme, docs, translation };
170
211
  } finally {
171
212
  rl.close();
172
213
  }
@@ -183,6 +224,18 @@ async function collect(options) {
183
224
  */
184
225
  const quote = (value) => `'${String(value).replace(/\\/g, '\\\\').replace(/'/g, "\\'")}'`;
185
226
 
227
+ /**
228
+ * Writes a language code as a property name.
229
+ *
230
+ * `fr` stands on its own; `pt-BR` and `zh-Hans` carry a hyphen, which is a
231
+ * minus sign to JavaScript — unquoted, the generated configuration would not
232
+ * parse.
233
+ *
234
+ * @param {string} code
235
+ * @returns {string}
236
+ */
237
+ const key = (code) => (/^[A-Za-z_$][A-Za-z0-9_$]*$/.test(code) ? code : quote(code));
238
+
186
239
  /**
187
240
  * Renders `docpensieve.config.mjs`.
188
241
  *
@@ -190,10 +243,13 @@ const quote = (value) => `'${String(value).replace(/\\/g, '\\\\').replace(/'/g,
190
243
  * or commented out with an example — so that the first file a user opens also
191
244
  * tells them everything they can change.
192
245
  *
193
- * @param {{ name: string, theme: string, siteUrl: string, version: string }} answers
246
+ * @param {{
247
+ * name: string, theme: string, siteUrl: string, version: string,
248
+ * translation?: string,
249
+ * }} answers
194
250
  * @returns {string} Contents of `docpensieve.config.mjs`.
195
251
  */
196
- function renderConfig({ name, theme, siteUrl, version }) {
252
+ function renderConfig({ name, theme, siteUrl, version, translation = '' }) {
197
253
  const slug = versionSlug(version);
198
254
  // A type annotation rather than an `import`: `defineConfig` transforms
199
255
  // nothing, it is only there for autocompletion. Actually importing it would
@@ -233,9 +289,14 @@ function renderConfig({ name, theme, siteUrl, version }) {
233
289
  ` name: ${quote(version)}, // label in the version switcher`,
234
290
  ` folder: ${quote(`docs/${slug}`)},`,
235
291
  ' current: true,',
236
- ' // Pages of this version in another language, served under /fr/.',
292
+ ` // Pages of this version in another language, served under /${translation || 'fr'}/.`,
237
293
  ' // Your own language stays where it is, and keeps its addresses.',
238
- ` // translations: { fr: ${quote(`docs/${slug}-fr`)} },`,
294
+ // Written out, not left as an example, once the language is known: the
295
+ // field is the whole of the feature, and the folder beside it already
296
+ // holds a page.
297
+ translation
298
+ ? ` translations: { ${key(translation)}: ${quote(`docs/${slug}-${translation}`)} },`
299
+ : ` // translations: { fr: ${quote(`docs/${slug}-fr`)} },`,
239
300
  ' },',
240
301
  ' ],',
241
302
  '',
@@ -353,11 +414,12 @@ function versionSlug(version) {
353
414
  }
354
415
 
355
416
  /**
356
- * @param {string} name Project name, for the title of the home page.
357
- * @param {boolean} docs Whether DocPensieve's documentation is installed.
417
+ * Home page of the project, in the language of the site.
418
+ *
419
+ * @param {{ name: string, docs: boolean, slug: string, translation: string }} answers
358
420
  * @returns {string}
359
421
  */
360
- const renderIndex = (name, docs) => `---
422
+ const renderIndex = ({ name, docs, slug, translation }) => `---
361
423
  title: Introduction
362
424
  description: Documentation of ${name}.
363
425
  date: ${new Date().toISOString().slice(0, 10)}
@@ -378,6 +440,20 @@ without appearing in the URL.
378
440
 
379
441
  See the [installation guide](/guide/installation/).
380
442
  ${
443
+ translation
444
+ ? `
445
+ ## In ${languageName(translation)}
446
+
447
+ The same pages live in \`docs/${slug}-${translation}/\`, and the language switcher
448
+ in the header moves between them.
449
+
450
+ A page with no twin there does not exist in that language: it stays out of the
451
+ menu and out of the sitemap, and the switcher names the language without
452
+ offering it. The installation page is in that case — write
453
+ \`docs/${slug}-${translation}/01-guide/01-installation.md\` and it appears.
454
+ ${docs ? '\nThe [languages guide](/docpensieve/guide/languages/) covers the rest.\n' : ''}`
455
+ : ''
456
+ }${
381
457
  docs
382
458
  ? `
383
459
  ## Learning DocPensieve
@@ -389,6 +465,70 @@ tool that builds this site, installed along with it. Delete its folder,
389
465
  : ''
390
466
  }`;
391
467
 
468
+ /**
469
+ * Home page of the second language.
470
+ *
471
+ * French is written out, the tool shipping its wording too. Any other
472
+ * language gets the page in English, saying in its first line that it is
473
+ * there to be translated: a copy passing for a translation is the one failure
474
+ * this feature invites — the reader gets English under an address that
475
+ * promised their language, and nothing reports it.
476
+ *
477
+ * Only the home page is written. Its twin, the installation page, is left
478
+ * untranslated on purpose: it is what shows that an untranslated page does
479
+ * not exist in that language, which no sentence explains as well as the menu
480
+ * that lacks it.
481
+ *
482
+ * @param {{ name: string, slug: string, translation: string }} answers
483
+ * @returns {string}
484
+ */
485
+ function renderTranslatedIndex({ name, slug, translation }) {
486
+ const french = translation.toLowerCase().split('-')[0] === 'fr';
487
+ const head = `---
488
+ title: Introduction
489
+ description: ${french ? `Documentation de ${name}.` : `Documentation of ${name}.`}
490
+ date: ${new Date().toISOString().slice(0, 10)}
491
+
492
+ jsonld:
493
+ type: TechArticle
494
+ breadcrumbs: true
495
+ ---
496
+
497
+ # ${name}
498
+ `;
499
+
500
+ if (french) {
501
+ return `${head}
502
+ Bienvenue dans la documentation.
503
+
504
+ ## Une page et sa jumelle
505
+
506
+ Cette page est la version française de \`docs/${slug}/index.md\`. Le sélecteur
507
+ de langue, dans l'en-tête, passe de l'une à l'autre.
508
+
509
+ La page d'installation, elle, n'est pas traduite : elle **n'existe pas** en
510
+ français. Elle ne figure ni dans le menu ni dans le plan du site, et le
511
+ sélecteur la nomme sans la proposer. Écrivez
512
+ \`docs/${slug}-${translation}/01-guide/01-installation.md\` pour la voir apparaître.
513
+ `;
514
+ }
515
+
516
+ return `${head}
517
+ **Replace this page with your translation.** It is the ${languageName(translation)}
518
+ twin of \`docs/${slug}/index.md\`, written in English so that the site builds:
519
+ left as it is, a reader who picks ${languageName(translation, translation)} gets English.
520
+
521
+ ## One page, two languages
522
+
523
+ The language switcher in the header moves between this page and its twin.
524
+
525
+ The installation page has no twin here, so it does not exist in this language:
526
+ it stays out of the menu and out of the sitemap, and the switcher names the
527
+ language without offering it. Write
528
+ \`docs/${slug}-${translation}/01-guide/01-installation.md\` and it appears.
529
+ `;
530
+ }
531
+
392
532
  /** @returns {string} Sample page, showing ordering and highlighting. */
393
533
  const renderGuide = () => `---
394
534
  title: Installation
@@ -478,11 +618,14 @@ async function installDocumentation(source, target, slug) {
478
618
  * @param {string} [dir] Target folder, created if needed.
479
619
  * @param {{
480
620
  * name?: string, theme?: string, siteUrl?: string, version?: string,
481
- * yes?: boolean, force?: boolean, minimal?: boolean,
482
- * }} [options] `minimal` leaves DocPensieve's documentation out of the site.
483
- * @returns {Promise<{ dir: string, theme: string, docs: boolean }>}
484
- * @throws {DocPensieveError} Unknown framework, project already initialised,
485
- * or documentation to install missing.
621
+ * translation?: string, yes?: boolean, force?: boolean, minimal?: boolean,
622
+ * }} [options] `minimal` leaves DocPensieve's documentation out of the site;
623
+ * `translation` is the code of a second language, `fr` for instance.
624
+ * @returns {Promise<{
625
+ * dir: string, theme: string, docs: boolean, translation: string,
626
+ * }>}
627
+ * @throws {DocPensieveError} Unknown framework, unknown language, project
628
+ * already initialised, or documentation to install missing.
486
629
  */
487
630
  export async function init(dir = '.', options = {}) {
488
631
  const target = path.resolve(dir);
@@ -504,6 +647,14 @@ export async function init(dir = '.', options = {}) {
504
647
  });
505
648
  }
506
649
 
650
+ // Checked here for the same reason as the framework: a code refused after
651
+ // five questions would be five questions wasted.
652
+ if (options.translation && !isLanguageCode(options.translation)) {
653
+ throw new DocPensieveError(`"${options.translation}" does not name a language.`, {
654
+ hint: 'Write the code, not the name: "fr" for French, "pt-BR", "zh-Hans". It becomes the lang of the document and a segment of the address.',
655
+ });
656
+ }
657
+
507
658
  const answers = await collect(options);
508
659
 
509
660
  // Located before anything is written: a project left half set up would be
@@ -535,8 +686,21 @@ export async function init(dir = '.', options = {}) {
535
686
 
536
687
  await mkdir(path.join(docsDir, '01-guide'), { recursive: true });
537
688
  await writeFile(configPath, renderConfig(answers), 'utf8');
538
- await writeFile(path.join(docsDir, 'index.md'), renderIndex(answers.name, answers.docs), 'utf8');
689
+ await writeFile(
690
+ path.join(docsDir, 'index.md'),
691
+ renderIndex({ name: answers.name, docs: answers.docs, slug, translation: answers.translation }),
692
+ 'utf8',
693
+ );
539
694
  await writeFile(path.join(docsDir, '01-guide', '01-installation.md'), renderGuide(), 'utf8');
695
+ if (answers.translation) {
696
+ const folder = path.join(target, 'docs', `${slug}-${answers.translation}`);
697
+ await mkdir(folder, { recursive: true });
698
+ await writeFile(
699
+ path.join(folder, 'index.md'),
700
+ renderTranslatedIndex({ name: answers.name, slug, translation: answers.translation }),
701
+ 'utf8',
702
+ );
703
+ }
540
704
  if (documentation) {
541
705
  await installDocumentation(documentation, path.join(docsDir, DOCS_FOLDER), slug);
542
706
  }
@@ -548,14 +712,31 @@ export async function init(dir = '.', options = {}) {
548
712
  console.log(` ${CONFIG_FILENAME}`);
549
713
  console.log(` docs/${slug}/index.md`);
550
714
  console.log(` docs/${slug}/01-guide/01-installation.md`);
715
+ if (answers.translation) {
716
+ const state =
717
+ answers.translation.toLowerCase().split('-')[0] === 'fr'
718
+ ? `in ${languageName(answers.translation)}`
719
+ : 'to translate';
720
+ console.log(` docs/${slug}-${answers.translation}/index.md the home page, ${state}`);
721
+ }
551
722
  if (documentation) {
552
723
  console.log(` docs/${slug}/${DOCS_FOLDER}/ DocPensieve's documentation, to delete when done`);
553
724
  }
554
725
  for (const line of stylesheets) console.log(` ${line}`);
555
726
  console.log(`\nTheme: ${answers.theme} — ${FRAMEWORK_LABELS[answers.theme]}`);
727
+ if (answers.translation) {
728
+ console.log(
729
+ `Second language: ${languageName(answers.translation)} (${answers.translation}) — served under /${answers.translation}/`,
730
+ );
731
+ }
556
732
  console.log('\nNext: npx docpensieve dev');
557
733
 
558
- return { dir: target, theme: answers.theme, docs: answers.docs };
734
+ return {
735
+ dir: target,
736
+ theme: answers.theme,
737
+ docs: answers.docs,
738
+ translation: answers.translation,
739
+ };
559
740
  }
560
741
 
561
742
  /**
@@ -46,6 +46,7 @@ npx docpensieve init my-site --yes --name "My documentation"
46
46
  | `-t, --theme <framework>` | `tailwind` or `custom` |
47
47
  | `-u, --site-url <url>` | Public URL, from which the deployment prefix is derived |
48
48
  | `--version-name <version>` | First version, `1.0` for instance |
49
+ | `--translation <code>` | Code of a second language, `fr` for instance |
49
50
  | `-y, --yes` | Accepts the defaults without a dialogue |
50
51
  | `-f, --force` | Overwrites an existing configuration |
51
52
  | `--minimal` | Leaves DocPensieve's documentation out of the site |
@@ -13,6 +13,19 @@ jsonld:
13
13
  A version can be published in several languages. Each one is a folder of pages
14
14
  of its own, standing beside the version it translates.
15
15
 
16
+ ## Starting from init
17
+
18
+ `init` asks whether the site will be in several languages. Answer yes, give a
19
+ code, and the project comes out wired: the folder beside your pages, the field
20
+ in the configuration, and a home page in that language to start from.
21
+
22
+ ```bash
23
+ npx docpensieve init my-site --translation fr
24
+ ```
25
+
26
+ Everything below is what that answer sets up — and what to do when you add a
27
+ language to a project that already exists.
28
+
16
29
  ## Declaring a translation
17
30
 
18
31
  ```js
@@ -29,6 +29,7 @@ npx docpensieve init [dir]
29
29
  | `-t, --theme <framework>` | `tailwind` or `custom` |
30
30
  | `-u, --site-url <url>` | Public URL of the site |
31
31
  | `--version-name <version>` | First version, `1.0` for instance |
32
+ | `--translation <code>` | Code of a second language, `fr` |
32
33
  | `-y, --yes` | Accepts the defaults without a dialogue |
33
34
  | `-f, --force` | Overwrites an existing configuration |
34
35
  | `--minimal` | Leaves DocPensieve's documentation out |
@@ -346,6 +346,39 @@ a language nobody thought of.
346
346
 
347
347
  **Returns** `'ltr' \| 'rtl'` — `ltr` when the language is unknown — the safe default, and what every page did before this existed.
348
348
 
349
+ ### `isLanguageCode`
350
+
351
+ `isLanguageCode(value)`
352
+
353
+ Whether a string names a language, as BCP 47 and CLDR understand it.
354
+
355
+ The standard is BCP 47, and `Intl` carries it: a regex of our own refused
356
+ `zh-Hans-CN`, which is valid, and accepted shapes that are not. Well formed
357
+ is not the same as real, though — BCP 47 allows a language subtag of five
358
+ to eight letters, so `francais` passes that check and would land in the
359
+ markup as `lang="francais"`, a value no browser maps to a language. CLDR
360
+ knows which tags name one; the subtag alone is asked, so that a region, a
361
+ script or a private extension does not get in the way.
362
+
363
+ | Parameter | Type | |
364
+ | --- | --- | --- |
365
+ | `value` | `string` | |
366
+
367
+ **Returns** `boolean`
368
+
369
+ ### `languageName`
370
+
371
+ `languageName(code, [inLang])`
372
+
373
+ Name of a language, written in a language.
374
+
375
+ | Parameter | Type | |
376
+ | --- | --- | --- |
377
+ | `code` | `string` | Language code. |
378
+ | `[inLang]` | `string` | Language the name is written in. |
379
+
380
+ **Returns** `string` — The name, or the code itself when nothing names it.
381
+
349
382
  ## `@docpensieve/core`
350
383
 
351
384
  Configuration, loading, compilation, structured data and generation.
@@ -1211,11 +1244,11 @@ Sets up a documentation project.
1211
1244
  | Parameter | Type | |
1212
1245
  | --- | --- | --- |
1213
1246
  | `[dir]` | `string` | Target folder, created if needed. |
1214
- | `[options]` | `{ name?: string, theme?: string, siteUrl?: string, version?: string, yes?: boolean, force?: boolean, minimal?: boolean, }` | `minimal` leaves DocPensieve's documentation out of the site. |
1247
+ | `[options]` | `{ name?: string, theme?: string, siteUrl?: string, version?: string, translation?: string, yes?: boolean, force?: boolean, minimal?: boolean, }` | `minimal` leaves DocPensieve's documentation out of the site; `translation` is the code of a second language, `fr` for instance. |
1215
1248
 
1216
- **Returns** `Promise<{ dir: string, theme: string, docs: boolean }>`
1249
+ **Returns** `Promise<{ dir: string, theme: string, docs: boolean, translation: string, }>`
1217
1250
 
1218
- **Throws** `DocPensieveError` — Unknown framework, project already initialised, or documentation to install missing.
1251
+ **Throws** `DocPensieveError` — Unknown framework, unknown language, project already initialised, or documentation to install missing.
1219
1252
 
1220
1253
  ### `serve`
1221
1254
 
@@ -20,11 +20,27 @@ written.
20
20
 
21
21
  ## Already there
22
22
 
23
- Nothing yet: the 0.5 has just opened. Each feature is listed here as it
24
- arrives, beside what it asks of a project already built on the 0.4.
23
+ ### init asks about languages
24
+
25
+ `init` now asks whether the site will be in several languages, and sets the
26
+ answer up: the folder beside your pages, `translations` written out in the
27
+ configuration, and a home page in that language to start from. The second
28
+ sample page is deliberately left untranslated, so that the menu shows what an
29
+ untranslated page does — nothing, in that language.
30
+
31
+ ```bash
32
+ npx docpensieve init my-site --translation fr
33
+ ```
34
+
35
+ A code is a BCP 47 one: `fr`, `pt-BR`, `zh-Hans`. French and English ship with
36
+ their wording for the shell; any other language keeps the English wording
37
+ until the `ui` field gives it its own.
38
+
39
+ [Languages](./guide/languages/) · [The init options](./reference/cli/)
25
40
 
26
41
  ## For a 0.4 project
27
42
 
28
- Nothing to change: a 0.4 configuration builds as it is.
43
+ Nothing to change: a 0.4 configuration builds as it is, and a site already in
44
+ two languages is untouched — the question only shapes a **new** project.
29
45
  [Migrate from latest to beta](./guide/migrate-to-beta/) lists what changes on
30
46
  its own, and what is worth turning on.
@@ -9,17 +9,21 @@
9
9
  * @param {string} [dir] Target folder, created if needed.
10
10
  * @param {{
11
11
  * name?: string, theme?: string, siteUrl?: string, version?: string,
12
- * yes?: boolean, force?: boolean, minimal?: boolean,
13
- * }} [options] `minimal` leaves DocPensieve's documentation out of the site.
14
- * @returns {Promise<{ dir: string, theme: string, docs: boolean }>}
15
- * @throws {DocPensieveError} Unknown framework, project already initialised,
16
- * or documentation to install missing.
12
+ * translation?: string, yes?: boolean, force?: boolean, minimal?: boolean,
13
+ * }} [options] `minimal` leaves DocPensieve's documentation out of the site;
14
+ * `translation` is the code of a second language, `fr` for instance.
15
+ * @returns {Promise<{
16
+ * dir: string, theme: string, docs: boolean, translation: string,
17
+ * }>}
18
+ * @throws {DocPensieveError} Unknown framework, unknown language, project
19
+ * already initialised, or documentation to install missing.
17
20
  */
18
21
  export declare function init(dir?: string, options?: {
19
22
  name?: string;
20
23
  theme?: string;
21
24
  siteUrl?: string;
22
25
  version?: string;
26
+ translation?: string;
23
27
  yes?: boolean;
24
28
  force?: boolean;
25
29
  minimal?: boolean;
@@ -27,4 +31,5 @@ export declare function init(dir?: string, options?: {
27
31
  dir: string;
28
32
  theme: string;
29
33
  docs: boolean;
34
+ translation: string;
30
35
  }>;