Skip to content

Commit 74f3fa5

Browse files
authored
Merge pull request #60 from easyops-cn/steve/translations
feat: support translations in plugin options
2 parents d0877dd + c6dc344 commit 74f3fa5

File tree

14 files changed

+220
-10
lines changed

14 files changed

+220
-10
lines changed

README.md

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,25 @@ yarn add nodejieba
9292
| highlightSearchTermsOnTargetPage | boolean | `false` | Highlight search terms on target page. |
9393
| searchResultLimits | number | `8` | Limit the search results. |
9494
| searchResultContextMaxLength | number | `50` | Set the max length of characters of each search result to show. |
95+
| translations | TranslationMap | - | Set translations of this plugin, see [docs below](#translations). |
96+
97+
### Translations
98+
99+
To make this plugin localized, pass a `translations` option which defaults to:
100+
101+
```json
102+
{
103+
"search_placeholder": "Search",
104+
"see_all_results": "See all results",
105+
"no_results": "No results.",
106+
"search_results_for": "Search results for \"{{ keyword }}\"",
107+
"search_the_documentation": "Search the documentation",
108+
"count_documents_found": "{{ count }} document found",
109+
// `*_plural` can be omitted if it is the same as singular.
110+
"count_documents_found_plural": "{{ count }} documents found",
111+
"no_documents_were_found": "No documents were found"
112+
}
113+
```
95114

96115
## Custom Styles
97116

src/client/theme/SearchBar/EmptyTemplate.spec.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
import { EmptyTemplate } from "./EmptyTemplate";
22

3+
jest.mock("../../utils/proxiedGenerated");
4+
35
describe("EmptyTemplate", () => {
46
const OLD_ENV = process.env;
57

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
1+
import { translations } from "../../utils/proxiedGenerated";
12
import { iconNoResults } from "./icons";
23
import styles from "./SearchBar.module.css";
34

45
export function EmptyTemplate(): string {
56
if (process.env.NODE_ENV === "production") {
6-
return `<span class="${styles.noResults}"><span class="${styles.noResultsIcon}">${iconNoResults}</span><span>No results.</span></span>`;
7+
return `<span class="${styles.noResults}"><span class="${styles.noResultsIcon}">${iconNoResults}</span><span>${translations.no_results}</span></span>`;
78
}
89
return `<span class="${styles.noResults}">⚠️ The search index is only available when you run docusaurus build!</span>`;
910
}

src/client/theme/SearchBar/SearchBar.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ import { SearchSourceFactory } from "../../utils/SearchSourceFactory";
1515
import { SuggestionTemplate } from "./SuggestionTemplate";
1616
import { EmptyTemplate } from "./EmptyTemplate";
1717
import { SearchResult } from "../../../shared/interfaces";
18-
import { searchResultLimits, Mark } from "../../utils/proxiedGenerated";
18+
import { searchResultLimits, Mark, translations } from "../../utils/proxiedGenerated";
1919
import LoadingRing from "../LoadingRing/LoadingRing";
2020

2121
import styles from "./SearchBar.module.css";
@@ -96,7 +96,7 @@ export default function SearchBar({
9696
const a = document.createElement("a");
9797
const url = `${baseUrl}search?q=${encodeURIComponent(query)}`;
9898
a.href = url;
99-
a.textContent = "See all results";
99+
a.textContent = translations.see_all_results;
100100
a.addEventListener("click", (e) => {
101101
if (!e.ctrlKey && !e.metaKey) {
102102
e.preventDefault();
@@ -191,7 +191,7 @@ export default function SearchBar({
191191
})}
192192
>
193193
<input
194-
placeholder="Search"
194+
placeholder={translations.search_placeholder}
195195
aria-label="Search"
196196
className="navbar__search-input"
197197
onMouseEnter={onInputMouseEnter}

src/client/theme/SearchPage/SearchPage.tsx

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ import { highlight } from "../../utils/highlight";
1212
import { highlightStemmed } from "../../utils/highlightStemmed";
1313
import { getStemmedPositions } from "../../utils/getStemmedPositions";
1414
import LoadingRing from "../LoadingRing/LoadingRing";
15+
import { translations } from "../../utils/proxiedGenerated";
16+
import { simpleTemplate } from "../../utils/simpleTemplate";
1517

1618
import styles from "./SearchPage.module.css";
1719

@@ -29,8 +31,8 @@ export default function SearchPage(): React.ReactElement {
2931
const pageTitle = useMemo(
3032
() =>
3133
searchQuery
32-
? `Search results for "${searchQuery}"`
33-
: "Search the documentation",
34+
? simpleTemplate(translations.search_results_for, { keyword: searchQuery })
35+
: translations.search_the_documentation,
3436
[searchQuery]
3537
);
3638

@@ -106,11 +108,19 @@ export default function SearchPage(): React.ReactElement {
106108
{searchResults &&
107109
(searchResults.length > 0 ? (
108110
<p>
109-
{searchResults.length} document
110-
{searchResults.length === 1 ? "" : "s"} found
111+
{
112+
simpleTemplate(
113+
searchResults.length === 1
114+
? translations.count_documents_found
115+
: translations.count_documents_found_plural,
116+
{
117+
count: searchResults.length
118+
}
119+
)
120+
}
111121
</p>
112122
) : process.env.NODE_ENV === "production" ? (
113-
<p>No documents were found</p>
123+
<p>{translations.no_documents_were_found}</p>
114124
) : (
115125
<p>
116126
⚠️ The search index is only available when you run docusaurus

src/client/utils/__mocks__/proxiedGenerated.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,16 @@ export let removeDefaultStopWordFilter = false;
33
export const indexHash = "abc";
44
export const searchResultLimits = 8;
55
export const searchResultContextMaxLength = 50;
6+
export const translations = {
7+
"search_placeholder": "Search",
8+
"see_all_results": "See all results",
9+
"no_results": "No results.",
10+
"search_results_for": "Search results for \"{{ keyword }}\"",
11+
"search_the_documentation": "Search the documentation",
12+
"count_documents_found": "{{ count }} document found",
13+
"count_documents_found_plural": "{{ count }} documents found",
14+
"no_documents_were_found": "No documents were found"
15+
}
616

717
export function __setLanguage(value: string[]): void {
818
language = value;
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
import { simpleTemplate } from "./simpleTemplate";
2+
3+
describe("simpleTemplate", () => {
4+
test.each<[string, Record<string, unknown>, string]>([
5+
[
6+
"search for '{{ keyword }}'",
7+
{
8+
keyword: "any"
9+
},
10+
"search for 'any'"
11+
],
12+
[
13+
"{{ count }} documents found",
14+
{
15+
count: 2
16+
},
17+
"2 documents found"
18+
],
19+
])("simpleTemplate(%j, $j) should return %j", (template, params, result) => {
20+
expect(simpleTemplate(template, params)).toBe(result);
21+
});
22+
});

src/client/utils/simpleTemplate.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
export function simpleTemplate(template: string, params: Record<string, unknown>): string {
2+
return template.replace(/\{\{\s*(\w+)\s*\}\}/g, (raw, keyword) => {
3+
if (Object.prototype.hasOwnProperty.call(params, keyword)) {
4+
return String(params[keyword]);
5+
}
6+
return raw;
7+
});
8+
}

src/declarations.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
// import { TranslationMap } from "./shared/interfaces";
2+
13
declare module "@docusaurus/router" {
24
export const useHistory: () => {
35
push: (url: string) => void;
@@ -20,9 +22,21 @@ declare module "*/generated.js" {
2022
export const indexHash: string | undefined;
2123
export const searchResultLimits: number;
2224
export const searchResultContextMaxLength: number;
25+
export const translations: Required<TranslationMap>;
2326
// These below are for mocking only.
2427
export const __setLanguage: (value: string[]) => void;
2528
export const __setRemoveDefaultStopWordFilter: (value: boolean) => void;
2629
}
2730

2831
declare module "@docusaurus/Head";
32+
33+
declare interface TranslationMap {
34+
search_placeholder?: string;
35+
see_all_results?: string;
36+
no_results?: string;
37+
search_results_for?: string;
38+
search_the_documentation?: string;
39+
count_documents_found?: string;
40+
count_documents_found_plural?: string;
41+
no_documents_were_found?: string;
42+
}

src/server/utils/generate.spec.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ describe("generate", () => {
2525
'export const indexHash = "abc";',
2626
"export const searchResultLimits = 8;",
2727
"export const searchResultContextMaxLength = 50;",
28+
'export const translations = {"hello":"hola"};',
2829
],
2930
],
3031
[
@@ -41,6 +42,7 @@ describe("generate", () => {
4142
'export const indexHash = "abc";',
4243
"export const searchResultLimits = 8;",
4344
"export const searchResultContextMaxLength = 50;",
45+
'export const translations = {"hello":"hola"};',
4446
],
4547
],
4648
[
@@ -59,6 +61,7 @@ describe("generate", () => {
5961
'export const indexHash = "abc";',
6062
"export const searchResultLimits = 8;",
6163
"export const searchResultContextMaxLength = 50;",
64+
'export const translations = {"hello":"hola"};',
6265
],
6366
],
6467
[
@@ -80,6 +83,7 @@ describe("generate", () => {
8083
'export const indexHash = "abc";',
8184
"export const searchResultLimits = 8;",
8285
"export const searchResultContextMaxLength = 50;",
86+
'export const translations = {"hello":"hola"};',
8387
],
8488
],
8589
[
@@ -99,6 +103,7 @@ describe("generate", () => {
99103
'export const indexHash = "abc";',
100104
"export const searchResultLimits = 8;",
101105
"export const searchResultContextMaxLength = 50;",
106+
'export const translations = {"hello":"hola"};',
102107
],
103108
],
104109
[
@@ -121,6 +126,7 @@ describe("generate", () => {
121126
'export const indexHash = "abc";',
122127
"export const searchResultLimits = 8;",
123128
"export const searchResultContextMaxLength = 50;",
129+
'export const translations = {"hello":"hola"};',
124130
],
125131
],
126132
])("generate({ language: %j }, dir) should work", (language, contents) => {
@@ -130,6 +136,9 @@ describe("generate", () => {
130136
removeDefaultStopWordFilter: false,
131137
searchResultLimits: 8,
132138
searchResultContextMaxLength: 50,
139+
translations: {
140+
"hello": "hola"
141+
},
133142
} as ProcessedPluginOptions,
134143
"/tmp"
135144
);
@@ -151,6 +160,9 @@ describe("generate", () => {
151160
highlightSearchTermsOnTargetPage: true,
152161
searchResultLimits: 8,
153162
searchResultContextMaxLength: 50,
163+
translations: {
164+
"hello": "hola"
165+
}
154166
} as ProcessedPluginOptions,
155167
"/tmp"
156168
);

0 commit comments

Comments
 (0)