Skip to content

Commit f57e208

Browse files
committed
I18N cleanup, update changelog
1 parent e5bfa10 commit f57e208

File tree

14 files changed

+123
-114
lines changed

14 files changed

+123
-114
lines changed

CHANGELOG.md

Lines changed: 33 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -4,31 +4,49 @@ title: Changelog
44

55
## Beta
66

7+
### Breaking Changes
8+
79
- TypeDoc now expects all input globs paths to be specified with `/` path separators, #2825.
10+
- TypeDoc's `--entryPointStrategy merge` mode now requires JSON from at least version 0.28.0.
11+
- Removed `jp` translations from `lang`, to migrate switch to `ja`.
12+
- File name references in `intentionallyNotExported` now use a package name/package relative path instead of an absolute path for matching.
13+
- The `source-order` sort ordering now considers package names / package relative paths instead of using the absolute paths to a file.
14+
15+
### API Breaking Changes
16+
17+
- `Path` and `PathArray` parameter types now always contain normalized paths.
18+
- Introduced a `Router` which is used for URL creation. `Reflection.url`,
19+
`Reflection.anchor`, and `Reflection.hasOwnDocument` have been removed.
20+
- `Deserializer.reviveProject(s)` no longer accepts an option to add project documents.
21+
- `Deserializer.reviveProjects` now requires an `alwaysCreateEntryPointModule` option.
22+
- `Comment.serializeDisplayParts` no longer requires a serializer argument.
23+
- `ReflectionSymbolId.fileName` has been removed, TypeDoc now stores a combination of a package name and package relative path instead.
24+
- Removed `DeclarationReflection.relevanceBoost` attribute which was added for plugins, but never used.
25+
- `i18n` proxy is no longer passed to many functions, instead, reference `i18n` exported from the module directly.
26+
- `ReflectionKind.singularString` and `ReflectionKind.pluralString` now returns translated strings.
27+
The methods on `Internationalization` to do this previously have been removed.
28+
- The HTML output structure for the search box has changed to support the new modal.
29+
30+
### Features
31+
32+
- The search modal in the HTML output has been rewritten to provide better mobile support
833
- Added a `--router` option which can be used to modify TypeDoc's output folder
934
structure. This can be extended with plugins, #2111.
10-
- TypeDoc will now only create references for symbols re-exported from modules.
11-
- API: `Path` and `PathArray` parameter types now always contain normalized paths.
12-
- API: Introduced a `Router` which is used for URL creation. `Reflection.url`,
13-
`Reflection.anchor`, and `Reflection.hasOwnDocument` have been removed.
14-
- Removed `jp` translations from `lang`, to migrate switch to `ja`.
1535
- Introduced the `@primaryExport` modifier tag to provide more fine grained
1636
control over export conversion order, #2856
17-
- API: `Deserializer.reviveProject(s)` no longer accepts an option to add project documents.
18-
- API: `Deserializer.reviveProjects` now requires an `alwaysCreateEntryPointModule` option.
19-
- API: `Comment.serializeDisplayParts` no longer requires a serializer argument.
20-
- API: `ReflectionSymbolId.fileName` has been removed, TypeDoc now stores a combination of a package name and package relative path instead.
21-
- API: Removed `DeclarationReflection.relevanceBoost` attribute which was added for plugins, but never used.
22-
- The `source-order` sort ordering now considers package names / package relative paths instead of using the absolute paths to a file.
23-
- File name references in `intentionallyNotExported` now use a package name/package relative path instead of an absolute path for matching.
2437
- Introduced `packagesRequiringDocumentation` option for `validation.notDocumented`, TypeDoc will expect comments to be present for symbols in the specified packages.
25-
- TypeDoc's `--entryPointStrategy merge` mode now requires JSON from at least version 0.28.0.
2638
- TypeDoc now exports a `typedoc/browser` entrypoint for parsing and using serialized JSON files, #2528.
39+
40+
### Bug Fixes
41+
42+
- TypeDoc will now only create references for symbols re-exported from modules.
2743
- Variable-functions will now prefer placing the comment on the signature if there is only one signature present, #2824.
44+
- User filter settings will no longer sometimes cause the search to have fewer visible results than expected.
2845

29-
TODO:
46+
### Thanks!
3047

31-
- Clean up Internationalization class, it probably doesn't make sense anymore.
48+
- @phoneticallySAARTHaK
49+
- @XeroAlpha
3250

3351
## Unreleased
3452

src/browser-utils.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
export * from "#models";
22

33
export {
4+
addTranslations,
45
type ComponentPath,
56
ConsoleLogger,
67
type DeclarationReference,

src/index.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,10 @@
55
* entry point which exports some functions which may be useful during plugin
66
* development or debugging. Exports from that entry point are **not stable**
77
* and may change or be removed at any time.
8+
*
9+
* TypeDoc also exports a `typedoc/browser` entry point which exports a subset
10+
* of the members described here which makes it suitable for usage in browser
11+
* bundles which want to use TypeDoc's JSON output in the browser.
812
*/
913
export { Application, type ApplicationEvents } from "./lib/application.js";
1014

@@ -125,6 +129,7 @@ export {
125129
EventDispatcher,
126130
EventHooks,
127131
type GlobString,
132+
i18n,
128133
JSX,
129134
Logger,
130135
LogLevel,
@@ -135,6 +140,7 @@ export {
135140
type NormalizedPath,
136141
type NormalizedPathOrModule,
137142
type SymbolReference,
143+
translateTagName,
138144
} from "#utils";
139145

140146
export {

src/lib/application.ts

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,6 @@ import { validateDocumentation } from "./validation/documentation.js";
3535
import { validateLinks } from "./validation/links.js";
3636
import { ApplicationEvents } from "./application-events.js";
3737
import { deriveRootDir, findTsConfigFile, glob, readFile } from "#node-utils";
38-
import { Internationalization } from "./internationalization/internationalization.js";
3938
import { FileRegistry } from "./models/FileRegistry.js";
4039
import { readFileSync } from "fs";
4140
import { fileURLToPath } from "url";
@@ -45,6 +44,7 @@ import { validateMergeModuleWith } from "./validation/unusedMergeModuleWith.js";
4544
import { diagnostic, diagnostics } from "./utils/loggers.js";
4645
import { ValidatingFileRegistry } from "./utils/ValidatingFileRegistry.js";
4746
import { addInferredDeclarationMapPaths } from "./converter/factories/symbol-id.js";
47+
import { Internationalization } from "./internationalization/internationalization.js";
4848

4949
const packageInfo = JSON.parse(
5050
readFileSync(
@@ -145,7 +145,7 @@ export class Application extends AbstractComponent<
145145
* Internationalization module which supports translating according to
146146
* the `lang` option.
147147
*/
148-
internationalization = new Internationalization(this);
148+
internationalization = new Internationalization();
149149

150150
options = new Options();
151151

@@ -226,7 +226,9 @@ export class Application extends AbstractComponent<
226226
readers.forEach((r) => app.options.addReader(r));
227227
app.options.reset();
228228
app.setOptions(options, /* reportErrors */ false);
229+
app.internationalization.setLocale(app.lang);
229230
await app.options.read(new Logger(), undefined, (path) => app.watchConfigFile(path));
231+
app.internationalization.setLocale(app.lang);
230232
app.logger.level = app.options.getValue("logLevel");
231233

232234
await loadPlugins(app, app.options.getValue("plugin"));
@@ -260,8 +262,11 @@ export class Application extends AbstractComponent<
260262
private async _bootstrap(options: Partial<TypeDocOptions>) {
261263
this.options.reset();
262264
this.setOptions(options, /* reportErrors */ false);
265+
this.internationalization.setLocale(this.lang);
266+
263267
await this.options.read(this.logger, undefined, (path) => this.watchConfigFile(path));
264268
this.setOptions(options);
269+
this.internationalization.setLocale(this.lang);
265270

266271
if (isDebugging()) {
267272
this.logger.level = LogLevel.Verbose;

src/lib/converter/comments/textParser.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,14 @@
55
* them into references.
66
* @module
77
*/
8-
import type { TranslatedString, TranslationProxy } from "../../internationalization/index.js";
8+
import type { TranslationProxy } from "../../internationalization/index.js";
99
import type { CommentDisplayPart, RelativeLinkDisplayPart } from "../../models/index.js";
1010
import type { FileRegistry } from "../../models/FileRegistry.js";
1111
import { HtmlAttributeParser, ParserState } from "#node-utils";
1212
import { type Token, TokenSyntaxKind } from "./lexer.js";
1313

1414
import MarkdownIt from "markdown-it";
15-
import type { NormalizedPath } from "#utils";
15+
import type { NormalizedPath, TranslatedString } from "#utils";
1616
const MdHelpers = new MarkdownIt().helpers;
1717

1818
interface TextParserData {

src/lib/internationalization/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,5 +3,5 @@
33
* @summary Internationalization module for localized strings in output.
44
* @module
55
*/
6-
export type { TranslatedString } from "#utils";
6+
export { i18n, type TranslatedString } from "#utils";
77
export { Internationalization, type TranslatableStrings, type TranslationProxy } from "./internationalization.js";
Lines changed: 54 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,7 @@
11
import { ok } from "assert";
2-
import type { Application } from "../application.js";
3-
import { DefaultMap, setTranslations, type TranslatedString, unique } from "#utils";
2+
import { addTranslations, DefaultMap, setTranslations, type TranslatedString } from "#utils";
43
import { readdirSync } from "fs";
54
import { join } from "path";
6-
import translatable from "./locales/en.cjs";
75
import { type BuiltinTranslatableStringArgs } from "./translatable.js";
86
import { createRequire } from "node:module";
97
import { fileURLToPath } from "node:url";
@@ -54,85 +52,70 @@ export type TranslationProxy = {
5452
) => TranslatedString;
5553
};
5654

55+
const req = createRequire(fileURLToPath(import.meta.url));
56+
5757
/**
58-
* Simple internationalization module which supports placeholders.
59-
* See {@link TranslatableStrings} for a description of how this module works and how
60-
* plugins should add translations.
58+
* Load TypeDoc's translations for a specified language
6159
*/
62-
export class Internationalization {
63-
private allTranslations = new DefaultMap<string, Map<string, string>>(
64-
(lang) => {
65-
const req = createRequire(fileURLToPath(import.meta.url));
66-
// Make sure this isn't abused to load some random file by mistake
67-
ok(
68-
/^[A-Za-z-]+$/.test(lang),
69-
"Locale names may only contain letters and dashes",
70-
);
71-
try {
72-
return new Map(Object.entries(req(`./locales/${lang}.cjs`)));
73-
} catch {
74-
return new Map();
75-
}
76-
},
60+
export function loadTranslations(lang: string): Record<string, string> {
61+
// Make sure this isn't abused to load some random file by mistake
62+
ok(
63+
/^[A-Za-z-]+$/.test(lang),
64+
"Locale names may only contain letters and dashes",
7765
);
66+
try {
67+
return req(`./locales/${lang}.cjs`);
68+
} catch {
69+
return {};
70+
}
71+
}
7872

79-
/**
80-
* If constructed without an application, will use the default language.
81-
* Intended for use in unit tests only.
82-
* @internal
83-
*/
84-
constructor(private application: Application | null) {
85-
// TODO: Get rid of this extra proxy
86-
setTranslations(
87-
new Proxy(this, {
88-
get(i, p) {
89-
const t = i.allTranslations.get(i.application?.lang ?? "en") ??
90-
translatable;
91-
return t instanceof Map ? t.get(p as string) : t[p];
92-
},
93-
has(i, p) {
94-
const t = i.allTranslations.get(i.application?.lang ?? "en") ??
95-
translatable;
96-
return t instanceof Map ? t.has(p as string) : Object.prototype.hasOwnProperty.call(t, p);
97-
},
98-
}) as never,
99-
);
73+
/**
74+
* Get languages which TypeDoc includes translations for
75+
*/
76+
export function getNativelySupportedLanguages(): string[] {
77+
return readdirSync(join(fileURLToPath(import.meta.url), "../locales"))
78+
.map((x) => x.substring(0, x.indexOf(".")));
79+
}
80+
81+
/**
82+
* Responsible for maintaining loaded internationalized strings.
83+
*/
84+
export class Internationalization {
85+
private locales = new DefaultMap<string, Record<string, string>>(() => ({}));
86+
private loadedLocale!: string;
87+
88+
constructor() {
89+
this.setLocale("en");
10090
}
10191

102-
/**
103-
* Add translations for a string which will be displayed to the user.
104-
*/
105-
addTranslations(
106-
lang: string,
107-
translations: Partial<Record<keyof TranslatableStrings, string>>,
108-
override = false,
109-
): void {
110-
const target = this.allTranslations.get(lang);
111-
for (const [key, val] of Object.entries(translations)) {
112-
if (!target.has(key) || override) {
113-
target.set(key, val);
114-
}
92+
setLocale(locale: string): void {
93+
if (this.loadedLocale !== locale) {
94+
const defaultTranslations = loadTranslations(locale);
95+
const overrides = this.locales.get(locale);
96+
setTranslations({ ...defaultTranslations, ...overrides });
97+
this.loadedLocale = locale;
11598
}
11699
}
117100

118-
/**
119-
* Checks if we have any translations in the specified language.
120-
*/
121-
hasTranslations(lang: string): boolean {
122-
return this.allTranslations.get(lang).size > 0;
101+
addTranslations(locale: string, translations: Record<string, string>): void {
102+
Object.assign(this.locales.get(locale), translations);
103+
if (locale === this.loadedLocale) {
104+
addTranslations(translations);
105+
}
106+
}
107+
108+
hasTranslations(locale: string) {
109+
return this.getSupportedLanguages().includes(locale);
123110
}
124111

125-
/**
126-
* Gets a list of all languages with at least one translation.
127-
*/
128112
getSupportedLanguages(): string[] {
129-
return unique([
130-
...readdirSync(
131-
join(fileURLToPath(import.meta.url), "../locales"),
132-
).map((x) => x.substring(0, x.indexOf("."))),
133-
...this.allTranslations.keys(),
134-
])
135-
.filter((lang) => this.hasTranslations(lang))
136-
.sort();
113+
const supported = new Set(getNativelySupportedLanguages());
114+
for (const [locale, translations] of this.locales) {
115+
if (Object.entries(translations).length) {
116+
supported.add(locale);
117+
}
118+
}
119+
return Array.from(supported);
137120
}
138121
}

src/lib/output/output.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
1-
import { i18n } from "#utils";
1+
import { i18n, type TranslatedString } from "#utils";
22
import type { Application } from "../application.js";
3-
import type { TranslatedString } from "../internationalization/index.js";
43
import type { ProjectReflection } from "../models/index.js";
54
import { type OutputSpecification, ParameterType, type StringDeclarationOption } from "../utils/options/declaration.js";
65
import { nicePath } from "../utils/paths.js";

src/lib/output/themes/MarkedPlugin.tsx

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import { MarkdownEvent, type PageEvent, RendererEvent } from "../events.js";
77
import { Option, type ValidationOptions } from "../../utils/index.js";
88
import { highlight, isLoadedLanguage, isSupportedLanguage } from "../../utils/highlighter.js";
99
import type { BundledTheme } from "@gerrit0/mini-shiki";
10-
import { assertNever, escapeHtml, i18n, JSX } from "#utils";
10+
import { assertNever, escapeHtml, i18n, JSX, type TranslatedString } from "#utils";
1111
import type { DefaultThemeRenderContext, Renderer } from "../index.js";
1212
import { anchorIcon } from "./default/partials/anchor-icon.js";
1313
import {
@@ -16,7 +16,6 @@ import {
1616
ReflectionKind,
1717
type RelativeLinkDisplayPart,
1818
} from "../../models/index.js";
19-
import type { TranslatedString } from "../../internationalization/index.js";
2019

2120
/**
2221
* Implements markdown and relativeURL helpers for templates.

src/lib/output/themes/default/DefaultThemeRenderContext.ts

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
import type { PageEvent, Renderer } from "../../index.js";
2-
import type { Internationalization } from "../../../internationalization/internationalization.js";
32
import type { CommentDisplayPart, Reflection } from "../../../models/index.js";
43
import { type Options } from "../../../utils/index.js";
54
import type { DefaultTheme } from "./DefaultTheme.js";
@@ -47,7 +46,6 @@ function bind<F, L extends any[], R>(fn: (f: F, ...a: L) => R, first: F) {
4746
export class DefaultThemeRenderContext {
4847
private _refIcons: Icons;
4948
options: Options;
50-
internationalization: Internationalization;
5149

5250
model: Reflection;
5351

@@ -59,7 +57,6 @@ export class DefaultThemeRenderContext {
5957
) {
6058
this._refIcons = buildRefIcons(theme.icons, this);
6159
this.options = options;
62-
this.internationalization = theme.application.internationalization;
6360
this.model = page.model;
6461
}
6562

0 commit comments

Comments
 (0)