Skip to content

Commit

Permalink
Merge pull request #386 from easyops-cn/steve/i18n-search-context-labels
Browse files Browse the repository at this point in the history
feat: i18n for search context labels and force ignore noIndex
  • Loading branch information
weareoutman committed Dec 19, 2023
2 parents 0be2e80 + 09d0f30 commit 183e4b7
Show file tree
Hide file tree
Showing 11 changed files with 187 additions and 87 deletions.
57 changes: 29 additions & 28 deletions README.md

Large diffs are not rendered by default.

74 changes: 46 additions & 28 deletions docusaurus-search-local/src/client/theme/SearchBar/SearchBar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,12 @@ import {
indexDocs,
searchContextByPaths,
hideSearchBarWithNoSearchContext,
useAllContextsWithNoSearchContext,
} from "../../utils/proxiedGenerated";
import LoadingRing from "../LoadingRing/LoadingRing";

import styles from "./SearchBar.module.css";
import { normalizeContextByPath } from "../../utils/normalizeContextByPath";

async function fetchAutoCompleteJS(): Promise<any> {
const autoCompleteModule = await import("@easyops-cn/autocomplete.js");
Expand Down Expand Up @@ -62,6 +64,7 @@ export default function SearchBar({
const isBrowser = useIsBrowser();
const {
siteConfig: { baseUrl },
i18n: { currentLocale },
} = useDocusaurusContext();

// It returns undefined for non-docs pages
Expand Down Expand Up @@ -161,39 +164,51 @@ export default function SearchBar({
const a = document.createElement("a");
const params = new URLSearchParams();

const seeAllResultsText = translate({
id: "theme.SearchBar.seeAll",
message: "See all results",
});

const seeAllResultsOutsideContextText = translate(
{
id: "theme.SearchBar.seeAllOutsideContext",
message: "See results outside {context}",
},
{ context: searchContext }
);

const seeAllResultsInContextText = translate(
{
id: "theme.SearchBar.searchInContext",
message: "See all results in {context}",
},
{ context: searchContext }
);

params.set("q", query);

let linkText;
if (searchContext && isEmpty) {
linkText = seeAllResultsOutsideContextText;
} else if (searchContext) {
linkText = seeAllResultsInContextText;
if (searchContext) {
const detailedSearchContext =
searchContext && Array.isArray(searchContextByPaths)
? searchContextByPaths.find((item) =>
typeof item === "string"
? item === searchContext
: item.path === searchContext
)
: searchContext;
const translatedSearchContext = detailedSearchContext
? normalizeContextByPath(detailedSearchContext, currentLocale).label
: searchContext;

if (useAllContextsWithNoSearchContext && isEmpty) {
linkText = translate(
{
id: "theme.SearchBar.seeAllOutsideContext",
message: "See results outside {context}",
},
{ context: translatedSearchContext }
);
} else {
linkText = translate(
{
id: "theme.SearchBar.searchInContext",
message: "See all results in {context}",
},
{ context: translatedSearchContext }
);
}
} else {
linkText = seeAllResultsText;
linkText = translate({
id: "theme.SearchBar.seeAll",
message: "See all results",
});
}

if (Array.isArray(searchContextByPaths) && !isEmpty) {
if (
searchContext &&
Array.isArray(searchContextByPaths) &&
(!useAllContextsWithNoSearchContext || !isEmpty)
) {
params.set("ctx", searchContext);
}

Expand Down Expand Up @@ -250,7 +265,10 @@ export default function SearchBar({
suggestion: SuggestionTemplate,
empty: EmptyTemplate,
footer: ({ query, isEmpty }: any) => {
if (isEmpty && !searchContext) {
if (
isEmpty &&
(!searchContext || !useAllContextsWithNoSearchContext)
) {
return;
}
const a = searchFooterLinkElement({ query, isEmpty });
Expand Down
37 changes: 18 additions & 19 deletions docusaurus-search-local/src/client/theme/SearchPage/SearchPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import {
} from "../../utils/proxiedGenerated";

import styles from "./SearchPage.module.css";
import { normalizeContextByPath } from "../../utils/normalizeContextByPath";

export default function SearchPage(): React.ReactElement {
return (
Expand All @@ -35,6 +36,7 @@ export default function SearchPage(): React.ReactElement {
function SearchPageContent(): React.ReactElement {
const {
siteConfig: { baseUrl },
i18n: { currentLocale },
} = useDocusaurusContext();

const { selectMessage } = usePluralForm();
Expand Down Expand Up @@ -106,10 +108,10 @@ function SearchPageContent(): React.ReactElement {

useEffect(() => {
async function doFetchIndexes() {
const { wrappedIndexes, zhDictionary } = await fetchIndexes(
versionUrl,
searchContext
);
const { wrappedIndexes, zhDictionary } =
searchContext || useAllContextsWithNoSearchContext
? await fetchIndexes(versionUrl, searchContext)
: { wrappedIndexes: [], zhDictionary: [] };
setSearchSource(() =>
SearchSourceFactory(wrappedIndexes, zhDictionary, 100)
);
Expand Down Expand Up @@ -166,22 +168,19 @@ function SearchPageContent(): React.ReactElement {
value={searchContext}
onChange={(e) => updateSearchContext(e.target.value)}
>
<option value="">
{useAllContextsWithNoSearchContext
? translate({
id: "theme.SearchPage.searchContext.everywhere",
message: "everywhere",
})
: ""}
</option>
{useAllContextsWithNoSearchContext && (
<option value="">
{translate({
id: "theme.SearchPage.searchContext.everywhere",
message: "everywhere",
})}
</option>
)}
{searchContextByPaths.map((context) => {
let label: string;
let path: string;
if (typeof context === "string") {
label = path = context;
} else {
({ label, path } = context);
}
const { label, path } = normalizeContextByPath(
context,
currentLocale
);
return (
<option key={path} value={path}>
{label}
Expand Down
18 changes: 14 additions & 4 deletions docusaurus-search-local/src/client/theme/hooks/useSearchQuery.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import { useHistory, useLocation } from "@docusaurus/router";
import useIsBrowser from "@docusaurus/useIsBrowser";
import useDocusaurusContext from "@docusaurus/useDocusaurusContext";
import { searchContextByPaths } from "../../utils/proxiedGenerated";

const SEARCH_PARAM_QUERY = "q";
const SEARCH_PARAM_CONTEXT = "ctx";
Expand All @@ -34,21 +35,30 @@ function useSearchQuery(): any {
searchParams.delete(SEARCH_PARAM_QUERY);
}
return searchParams;
}
};

return {
searchValue,
searchContext,
searchContext:
searchContext &&
Array.isArray(searchContextByPaths) &&
searchContextByPaths.some((item) =>
typeof item === "string"
? item === searchContext
: item.path === searchContext
)
? searchContext
: "",
searchVersion,
updateSearchPath: (searchValue: string) => {
const searchParams = getSearchParams(searchValue);
history.replace({
search: searchParams.toString(),
});
},
updateSearchContext: (searchContext: string) => {
updateSearchContext: (value: string) => {
const searchParams = new URLSearchParams(location.search);
searchParams.set(SEARCH_PARAM_CONTEXT, searchContext);
searchParams.set(SEARCH_PARAM_CONTEXT, value);
history.replace({
search: searchParams.toString(),
});
Expand Down
36 changes: 36 additions & 0 deletions docusaurus-search-local/src/client/utils/normalizeContextByPath.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
interface DetailedItem {
label: string | Record<string, string>;
path: string;
}

interface NormalizedItem {
path: string;
label: string;
}

export function normalizeContextByPath(
context: string | DetailedItem,
currentLocale: string
): NormalizedItem {
if (typeof context === "string") {
return {
label: context,
path: context,
};
} else {
const { label, path } = context;
if (typeof label === "string") {
return { label, path };
}
if (Object.prototype.hasOwnProperty.call(label, currentLocale)) {
return {
label: label[currentLocale],
path,
};
}
return {
label: path,
path,
};
}
}
3 changes: 2 additions & 1 deletion docusaurus-search-local/src/declarations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,11 @@ declare module "*/generated.js" {
export const indexDocs: boolean;
export const searchContextByPaths: (
| string
| { label: string; path: string }
| { label: string | Record<string, string>; path: string }
)[];
export const hideSearchBarWithNoSearchContext: boolean;
export const useAllContextsWithNoSearchContext: boolean;
export const forceIgnoreNoIndex: boolean;
// These below are for mocking only.
export const __setLanguage: (value: string[]) => void;
export const __setRemoveDefaultStopWordFilter: (value: boolean) => void;
Expand Down
12 changes: 11 additions & 1 deletion docusaurus-search-local/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,10 @@ export interface PluginOptions {
* Provide an list of sub-paths as separate search context, E.g.: `["docs", "community", "legacy/resources"]`.
* It will create multiple search indexes by these paths.
*/
searchContextByPaths?: (string | { label: string; path: string })[];
searchContextByPaths?: (
| string
| { label: string | Record<string, string>; path: string }
)[];

/**
* Whether to hide the search bar when no search context was matched.
Expand All @@ -189,4 +192,11 @@ export interface PluginOptions {
* @default false
*/
useAllContextsWithNoSearchContext?: boolean;

/**
* Force enable search index even if noIndex: true is set, this also affects unlisted articles.
*
* @default false
*/
forceIgnoreNoIndex?: boolean;
}
4 changes: 2 additions & 2 deletions docusaurus-search-local/src/server/utils/parse.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,12 @@ export function parse(
html: string,
type: "docs" | "blog" | "page",
url: string,
{ ignoreCssSelectors }: ProcessedPluginOptions
{ ignoreCssSelectors, forceIgnoreNoIndex }: ProcessedPluginOptions
): ParsedDocument | null {
const $ = cheerio.load(html);

const robotsMeta = $('meta[name="robots"]');
if (robotsMeta.attr("content")?.includes("noindex")) {
if (!forceIgnoreNoIndex && robotsMeta.attr("content")?.includes("noindex")) {
// Unlisted content
return null;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ describe("validateOptions", () => {
searchBarShortcut: true,
searchBarShortcutHint: true,
searchBarPosition: "auto",
forceIgnoreNoIndex: false,
},
],
[
Expand Down Expand Up @@ -83,6 +84,7 @@ describe("validateOptions", () => {
searchBarShortcut: true,
searchBarShortcutHint: true,
searchBarPosition: "auto",
forceIgnoreNoIndex: false,
},
],
[
Expand Down Expand Up @@ -110,6 +112,7 @@ describe("validateOptions", () => {
searchBarShortcut: true,
searchBarShortcutHint: true,
searchBarPosition: "auto",
forceIgnoreNoIndex: false,
},
],
[
Expand Down Expand Up @@ -137,6 +140,7 @@ describe("validateOptions", () => {
searchBarShortcut: true,
searchBarShortcutHint: true,
searchBarPosition: "auto",
forceIgnoreNoIndex: false,
},
],
[
Expand All @@ -151,6 +155,7 @@ describe("validateOptions", () => {
explicitSearchResultPath: false,
searchResultContextMaxLength: 30,
searchBarShortcut: false,
forceIgnoreNoIndex: true,
},
{
blogRouteBasePath: ["blog"],
Expand All @@ -175,6 +180,7 @@ describe("validateOptions", () => {
searchBarShortcut: false,
searchBarShortcutHint: true,
searchBarPosition: "auto",
forceIgnoreNoIndex: true,
},
],
[
Expand Down Expand Up @@ -207,6 +213,7 @@ describe("validateOptions", () => {
searchBarShortcut: true,
searchBarShortcutHint: false,
searchBarPosition: "auto",
forceIgnoreNoIndex: false,
},
],
[
Expand Down Expand Up @@ -245,6 +252,7 @@ describe("validateOptions", () => {
searchBarPosition: "left",
docsPluginIdForPreferredVersion: "product",
searchContextByPaths: ["docs", "community"],
forceIgnoreNoIndex: false,
},
],
[
Expand Down Expand Up @@ -282,6 +290,7 @@ describe("validateOptions", () => {
searchBarPosition: "left",
docsPluginIdForPreferredVersion: "product",
searchContextByPaths: ["docs", "community"],
forceIgnoreNoIndex: false,
},
],
])("validateOptions(...) should work", (options, config) => {
Expand Down

0 comments on commit 183e4b7

Please sign in to comment.