Skip to content

Commit 54c6a1e

Browse files
formatted useLocalesMap error and added additional checks
1 parent 4222517 commit 54c6a1e

File tree

1 file changed

+54
-13
lines changed

1 file changed

+54
-13
lines changed

components/use-locales-map.js

+54-13
Original file line numberDiff line numberDiff line change
@@ -5,37 +5,64 @@ import { useRouter } from "next/router";
55
* @typedef {DefaultLocale | "zh-CN" | "es-ES" | "pt-BR" | "ja" | "ko" | "ru"} Locale
66
* @typedef {{locale?: Locale | undefined; locales?: Locale[] | undefined; defaultLocale?: DefaultLocale | undefined}} TypedRouter
77
* @typedef {Omit<import('next/router').NextRouter, "locale" | "locales" | "defaultLocale"> & TypedRouter} NextRouter
8+
*/
9+
10+
/**
811
* @template T
912
* @type {(localesMap: Record<Locale, T>) => T}
1013
*/
1114
export default function useLocalesMap(localesMap) {
1215
/** @type {NextRouter} */
1316
const router = useRouter();
14-
const { locale, defaultLocale } = router;
17+
const { locale, locales, defaultLocale } = router;
18+
1519
if (!localesMap) {
16-
throw new Error("Pass a locales map as argument to useLocalesMap");
20+
throw new Error("Pass a locales map as argument to useLocalesMap hook.");
1721
}
1822

19-
if (!isObject(localesMap)) {
20-
throw new Error("Locales map must be an object");
23+
if (typeof localesMap !== "object") {
24+
localesMapError(
25+
localesMap,
26+
`Locales map must be an object, but you passed ${typeof localesMap}.`
27+
);
28+
}
29+
30+
if (Array.isArray(localesMap)) {
31+
localesMapError(
32+
localesMap,
33+
"Locales map must be an object, but you passed an array."
34+
);
2135
}
2236

2337
if (!localesMap.hasOwnProperty(defaultLocale)) {
24-
throw new Error(
38+
localesMapError(
39+
localesMap,
2540
`Locales map must contain default locale "${defaultLocale}"`
2641
);
2742
}
2843

29-
if (
30-
localesMap.hasOwnProperty(locale) &&
31-
typeof localesMap[locale] !== typeof localesMap[defaultLocale]
32-
) {
33-
throw new Error(
34-
`Invalid locales map: Shape of "${locale}" must be the same as "${defaultLocale}"`
35-
);
44+
for (const key in localesMap) {
45+
if (!locales.includes(key)) {
46+
const list = locales.map((l) => `"${l}"`).join(", ");
47+
48+
localesMapError(
49+
localesMap,
50+
`"${key}" is not a valid locale.`,
51+
`Available locales are defined in "next.config.js": ${list}.`
52+
);
53+
}
54+
55+
if (typeof localesMap[key] !== typeof localesMap[defaultLocale]) {
56+
localesMapError(
57+
localesMap,
58+
`Shape of "${key}" must be the same as "${defaultLocale}"`
59+
);
60+
}
3661
}
3762

38-
if (["string", "number", "symbol"].includes(typeof localesMap[defaultLocale])) {
63+
if (
64+
["string", "number", "symbol"].includes(typeof localesMap[defaultLocale])
65+
) {
3966
return localesMap[locale] || localesMap[defaultLocale];
4067
}
4168

@@ -76,3 +103,17 @@ function mergeDeep(target, ...sources) {
76103

77104
return mergeDeep(target, ...sources);
78105
}
106+
107+
/**
108+
* Throw an error with a formatted message.
109+
* @template T
110+
* @param {Record<Locale, T>} localesMap
111+
* @param {string[]} args
112+
*/
113+
export function localesMapError(localesMap, ...args) {
114+
throw new Error(
115+
["Invalid locales map", JSON.stringify(localesMap, null, 2), ...args].join(
116+
"\n"
117+
)
118+
);
119+
}

0 commit comments

Comments
 (0)