@koine/i18n 2.0.0-beta.71 → 2.0.0-beta.73
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.
- package/adapter-js/code/config.cjs.js +14 -0
- package/adapter-js/code/config.js +14 -0
- package/adapter-js/code/defaultLocale.js +7 -0
- package/adapter-js/code/deriveLocalisedPathnames.js +78 -0
- package/adapter-js/code/index.js +57 -0
- package/adapter-js/code/isLocale.js +9 -0
- package/adapter-js/code/locales.js +8 -0
- package/adapter-js/code/pathnameToRouteId.js +20 -0
- package/adapter-js/code/routes.js +10 -0
- package/adapter-js/code/routesSlim.js +13 -0
- package/adapter-js/code/routesSpa.js +11 -0
- package/adapter-js/code/tFns.js +75 -0
- package/adapter-js/code/tInterpolateParams.js +21 -0
- package/adapter-js/code/tPluralise.js +12 -0
- package/adapter-js/code/to.js +32 -0
- package/adapter-js/code/toFns.js +41 -0
- package/adapter-js/code/toFormat.js +58 -0
- package/adapter-js/code/toSpa.js +42 -0
- package/adapter-js/code/types.js +382 -0
- package/adapter-next/code/index.js +27 -0
- package/adapter-next/code/next-redirects.js +5 -0
- package/adapter-next/code/next-rewrites.js +5 -0
- package/adapter-next/code/useCurrentLocalisedPathnames.js +20 -0
- package/adapter-next/code/useLocale.js +8 -0
- package/adapter-next/code/useRouteId.js +10 -0
- package/adapter-next/code/useTo.js +26 -0
- package/adapter-next/code/useToSpa.js +34 -0
- package/adapter-next/plugin-async.js +21 -0
- package/adapter-next/plugin-legacy.js +246 -0
- package/adapter-next/plugin-shared.js +49 -0
- package/adapter-next/plugin.js +24 -0
- package/adapter-next/redirects.js +77 -0
- package/adapter-next/rewrites.js +68 -0
- package/adapter-next/transformPathname.js +20 -0
- package/adapter-next/webpackPluginI18n.js +19 -0
- package/adapter-next-translate/code/DynamicNamespaces.js +9 -0
- package/adapter-next-translate/code/T.js +31 -0
- package/adapter-next-translate/code/TransText.js +9 -0
- package/adapter-next-translate/code/getT.js +15 -0
- package/adapter-next-translate/code/index.js +26 -0
- package/adapter-next-translate/code/nextTranslateI18n.js +19 -0
- package/adapter-next-translate/code/useT.js +43 -0
- package/api.cjs.js +4 -3
- package/api.esm.js +4 -3
- package/client/formatRoutePathname.d.ts +2 -2
- package/client/formatRoutePathname.js +8 -0
- package/client/index.js +3 -0
- package/client/interpolateTo.js +36 -0
- package/client/routeHasDynamicPortion.js +1 -0
- package/compiler/api.js +23 -0
- package/compiler/code/data-routes.js +174 -0
- package/compiler/code/data-translations.js +148 -0
- package/compiler/code/data.js +22 -0
- package/compiler/code/generate.js +73 -0
- package/compiler/code/index.js +3 -0
- package/compiler/code/tsCompile.js +40 -0
- package/compiler/code/write.js +78 -0
- package/compiler/config.js +14 -0
- package/compiler/helpers.js +19 -0
- package/compiler/input/data-local.js +70 -0
- package/compiler/input/data-remote.js +65 -0
- package/compiler/input/data.js +17 -0
- package/compiler/input/index.js +4 -0
- package/compiler/input/types.js +1 -0
- package/compiler/input/write.js +15 -0
- package/compiler/pluralisation.d.ts +1 -0
- package/compiler/pluralisation.js +67 -0
- package/compiler/summary/data.js +55 -0
- package/compiler/summary/generate.js +73 -0
- package/compiler/summary/index.js +2 -0
- package/compiler/summary/write.js +28 -0
- package/compiler/types.js +1 -0
- package/compiler-sync.js +3 -0
- package/compiler-worker.js +3 -0
- package/compiler.js +1 -0
- package/index.js +2 -0
- package/next.js +3 -0
- package/package.json +3 -3
- package/types.js +1 -0
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export default ({ config }) => `
|
|
2
|
+
const { locales } = require("./locales");
|
|
3
|
+
const { defaultLocale } = require("./defaultLocale");
|
|
4
|
+
|
|
5
|
+
const config = {
|
|
6
|
+
locales,
|
|
7
|
+
defaultLocale,
|
|
8
|
+
hideDefaultLocaleInUrl: ${config.hideDefaultLocaleInUrl},
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
exports.config = config;
|
|
12
|
+
|
|
13
|
+
module.exports = config;
|
|
14
|
+
`;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export default ({ config }) => `
|
|
2
|
+
import { locales } from "./locales";
|
|
3
|
+
import { defaultLocale } from "./defaultLocale";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
*/
|
|
7
|
+
export const config = {
|
|
8
|
+
locales,
|
|
9
|
+
defaultLocale,
|
|
10
|
+
hideDefaultLocaleInUrl: ${config.hideDefaultLocaleInUrl},
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export default config;
|
|
14
|
+
`;
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
export default () => `
|
|
2
|
+
import { locales } from "./locales";
|
|
3
|
+
import { to } from "./to";
|
|
4
|
+
import type { I18n } from "./types";
|
|
5
|
+
|
|
6
|
+
function getPathnameDynamicPortionName(pathname: string) {
|
|
7
|
+
const res = pathname.match(/\\[(.+)\\]/);
|
|
8
|
+
return res ? res[1] : false;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
function isStaticPathname(pathname: string) {
|
|
12
|
+
return !/\\[/.test(pathname);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
// e.g. ['my', 'path', 'id', 'view'] or ['nl' 'my', 'path', 'id', 'view']
|
|
16
|
+
// where the first might be the locale (depending on hideDefaultLocaleInUrl)
|
|
17
|
+
function getPathnameParts(pathname: string) {
|
|
18
|
+
return pathname
|
|
19
|
+
.split("/")
|
|
20
|
+
.slice(1)
|
|
21
|
+
.filter((p, i) => (i === 0 ? !locales.includes(p as I18n.Locale) : true));
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
function localisePathname(
|
|
25
|
+
locale: I18n.Locale,
|
|
26
|
+
// e.g. "my.path.[id].view"
|
|
27
|
+
routeId: I18n.RouteIdDynamic | I18n.RouteIdStatic,
|
|
28
|
+
locationLike: LocationLike
|
|
29
|
+
) {
|
|
30
|
+
const toPathname = to(routeId as I18n.RouteIdStatic, locale);
|
|
31
|
+
|
|
32
|
+
if (isStaticPathname(toPathname)) {
|
|
33
|
+
return toPathname;
|
|
34
|
+
}
|
|
35
|
+
// e.g. ['my', 'path', '[id]', 'view']
|
|
36
|
+
const toPathnameParts = getPathnameParts(toPathname);
|
|
37
|
+
// e.g. "my.path.[id].view"
|
|
38
|
+
const routeIdDynamic = routeId as I18n.RouteIdDynamic;
|
|
39
|
+
// e.g. /my/path/123/view
|
|
40
|
+
const currentPathname = locationLike.pathname;
|
|
41
|
+
// e.g. ['my', 'path', '123', 'view']
|
|
42
|
+
const currentPathnameParts = getPathnameParts(currentPathname);
|
|
43
|
+
// e.g. { id: "123" }
|
|
44
|
+
const params: Record<string, string> = {};
|
|
45
|
+
|
|
46
|
+
for (let i = 0; i < toPathnameParts.length; i++) {
|
|
47
|
+
// e.g. "my" or "[id]"
|
|
48
|
+
const part = toPathnameParts[i];
|
|
49
|
+
// e.g. "id"
|
|
50
|
+
const name = getPathnameDynamicPortionName(part);
|
|
51
|
+
if (name) {
|
|
52
|
+
// e.g. "123"
|
|
53
|
+
const value = currentPathnameParts[i];
|
|
54
|
+
if (value) {
|
|
55
|
+
params[name] = value;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
return (
|
|
61
|
+
to(routeIdDynamic, params as never, locale) +
|
|
62
|
+
location?.search || "" +
|
|
63
|
+
location?.hash || ""
|
|
64
|
+
);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
type LocationLike = { pathname: string; search?: string; hash?: string; };
|
|
68
|
+
|
|
69
|
+
export type LocalisedPathnames = Record<I18n.Locale, string>;
|
|
70
|
+
|
|
71
|
+
export const deriveLocalisedPathnames = (routeId: I18n.RouteId, locationLike: LocationLike) =>
|
|
72
|
+
locales.reduce((pathnames, locale) => {
|
|
73
|
+
pathnames[locale] = localisePathname(locale, routeId, locationLike);
|
|
74
|
+
return pathnames;
|
|
75
|
+
}, {} as LocalisedPathnames);
|
|
76
|
+
|
|
77
|
+
export default deriveLocalisedPathnames;
|
|
78
|
+
`;
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import config from "./config";
|
|
2
|
+
import configCjs from "./config.cjs";
|
|
3
|
+
import defaultLocale from "./defaultLocale";
|
|
4
|
+
import deriveLocalisedPathnames from "./deriveLocalisedPathnames";
|
|
5
|
+
import isLocale from "./isLocale";
|
|
6
|
+
import locales from "./locales";
|
|
7
|
+
import pathnameToRouteId from "./pathnameToRouteId";
|
|
8
|
+
import routes from "./routes";
|
|
9
|
+
import routesSlim from "./routesSlim";
|
|
10
|
+
import routesSpa from "./routesSpa";
|
|
11
|
+
import tFns from "./tFns";
|
|
12
|
+
import tInterpolateParams from "./tInterpolateParams";
|
|
13
|
+
import tPluralise from "./tPluralise";
|
|
14
|
+
import to from "./to";
|
|
15
|
+
import toFns from "./toFns";
|
|
16
|
+
import toFormat from "./toFormat";
|
|
17
|
+
import toSpa from "./toSpa";
|
|
18
|
+
import types from "./types";
|
|
19
|
+
const adapter = () => {
|
|
20
|
+
return {
|
|
21
|
+
files: [
|
|
22
|
+
{ name: "config.cjs", fn: configCjs, ext: "js" },
|
|
23
|
+
{ name: "config", fn: config, ext: "ts", index: true },
|
|
24
|
+
{ name: "defaultLocale", fn: defaultLocale, ext: "ts", index: true },
|
|
25
|
+
{
|
|
26
|
+
name: "deriveLocalisedPathnames",
|
|
27
|
+
fn: deriveLocalisedPathnames,
|
|
28
|
+
ext: "ts",
|
|
29
|
+
index: true,
|
|
30
|
+
},
|
|
31
|
+
{ name: "isLocale", fn: isLocale, ext: "ts", index: true },
|
|
32
|
+
{ name: "locales", fn: locales, ext: "ts", index: true },
|
|
33
|
+
{
|
|
34
|
+
name: "pathnameToRouteId",
|
|
35
|
+
fn: pathnameToRouteId,
|
|
36
|
+
ext: "ts",
|
|
37
|
+
index: true,
|
|
38
|
+
},
|
|
39
|
+
{ name: "routes", fn: routes, ext: "ts" },
|
|
40
|
+
{ name: "routesSlim", fn: routesSlim, ext: "ts" },
|
|
41
|
+
{ name: "routesSpa", fn: routesSpa, ext: "ts" },
|
|
42
|
+
{ name: "tFns", fn: tFns, ext: "ts" },
|
|
43
|
+
{
|
|
44
|
+
name: "tInterpolateParams",
|
|
45
|
+
fn: tInterpolateParams,
|
|
46
|
+
ext: "ts",
|
|
47
|
+
},
|
|
48
|
+
{ name: "to", fn: to, ext: "ts", index: true },
|
|
49
|
+
{ name: "toFns", fn: toFns, ext: "ts", index: true },
|
|
50
|
+
{ name: "toFormat", fn: toFormat, ext: "ts", index: true },
|
|
51
|
+
{ name: "toSpa", fn: toSpa, ext: "ts", index: true },
|
|
52
|
+
{ name: "tPluralise", fn: tPluralise, ext: "ts" },
|
|
53
|
+
{ name: "types", fn: types, ext: "ts", index: true },
|
|
54
|
+
],
|
|
55
|
+
};
|
|
56
|
+
};
|
|
57
|
+
export default adapter;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export default () => `
|
|
2
|
+
import { locales } from "./locales";
|
|
3
|
+
import type { I18n } from "./types";
|
|
4
|
+
|
|
5
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
6
|
+
export const isLocale = (payload: any): payload is I18n.Locale => locales.includes(payload);
|
|
7
|
+
|
|
8
|
+
export default isLocale;
|
|
9
|
+
`;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { escapeRegExp } from "@koine/utils";
|
|
2
|
+
export default ({ options }) => {
|
|
3
|
+
const { idDelimiter, optionalCatchAll, catchAll } = options.routes.tokens;
|
|
4
|
+
return `
|
|
5
|
+
/**
|
|
6
|
+
* Convert a URL like pathname to a "named route"
|
|
7
|
+
* E.g. it transforms:
|
|
8
|
+
* - \`/dashboard/user/[id]\` into \`dashboard.user.[id]\`
|
|
9
|
+
*/
|
|
10
|
+
export const pathnameToRouteId = (pathname: string) =>
|
|
11
|
+
pathname
|
|
12
|
+
.replace(/^\\//g, "")
|
|
13
|
+
.replace(/\\//g, "${idDelimiter}")
|
|
14
|
+
.replace(/${escapeRegExp(idDelimiter)}${escapeRegExp(optionalCatchAll.start)}.+$/, "")
|
|
15
|
+
.replace(/${escapeRegExp(idDelimiter)}${escapeRegExp(catchAll.start)}.+$/, "")
|
|
16
|
+
.replace(/\\/index$/, "");
|
|
17
|
+
|
|
18
|
+
export default pathnameToRouteId;
|
|
19
|
+
`;
|
|
20
|
+
};
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export default ({ routes }) => {
|
|
2
|
+
const value = JSON.stringify(Object.fromEntries(Object.entries(routes.byId)
|
|
3
|
+
.map(([routeId, { pathnames }]) => [routeId, pathnames])
|
|
4
|
+
.sort()), null, 2);
|
|
5
|
+
return `
|
|
6
|
+
export const routes = ${value} as const;
|
|
7
|
+
|
|
8
|
+
export default routes;
|
|
9
|
+
`;
|
|
10
|
+
};
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export default ({ routes }) => {
|
|
2
|
+
const value = JSON.stringify(Object.fromEntries(Object.entries(routes.byId)
|
|
3
|
+
.map(([routeId, { pathnamesSlim, pathnames }]) => [
|
|
4
|
+
routeId,
|
|
5
|
+
pathnamesSlim || pathnames,
|
|
6
|
+
])
|
|
7
|
+
.sort()), null, 2);
|
|
8
|
+
return `
|
|
9
|
+
export const routesSlim = ${value} as const;
|
|
10
|
+
|
|
11
|
+
export default routesSlim;
|
|
12
|
+
`;
|
|
13
|
+
};
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export default ({ routes }) => {
|
|
2
|
+
const value = JSON.stringify(Object.fromEntries(Object.entries(routes.byId)
|
|
3
|
+
.filter(([, { pathnamesSpa }]) => !!pathnamesSpa)
|
|
4
|
+
.map(([routeId, { pathnamesSpa }]) => [routeId, pathnamesSpa])
|
|
5
|
+
.sort()), null, 2);
|
|
6
|
+
return `
|
|
7
|
+
export const routesSpa = ${value} as const;
|
|
8
|
+
|
|
9
|
+
export default routesSpa;
|
|
10
|
+
`;
|
|
11
|
+
};
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { areEqual, isArray, isBoolean, isNumber, isPrimitive, isString, } from "@koine/utils";
|
|
2
|
+
import { dataParamsToTsInterfaceBody } from "../../compiler/helpers";
|
|
3
|
+
const getTranslationValueOutput = (value) => {
|
|
4
|
+
if (isString(value) || isNumber(value)) {
|
|
5
|
+
return `"${value}"`;
|
|
6
|
+
}
|
|
7
|
+
else if (isBoolean(value)) {
|
|
8
|
+
return `${value}`;
|
|
9
|
+
}
|
|
10
|
+
else if (isArray(value)) {
|
|
11
|
+
return JSON.stringify(value);
|
|
12
|
+
}
|
|
13
|
+
return `(${JSON.stringify(value)})`;
|
|
14
|
+
};
|
|
15
|
+
const areEqualTranslationsValues = (a, b) => areEqual(a, b);
|
|
16
|
+
const getFunctionBodyWithLocales = (config, perLocaleValues) => {
|
|
17
|
+
const { defaultLocale } = config;
|
|
18
|
+
let output = "";
|
|
19
|
+
for (const locale in perLocaleValues) {
|
|
20
|
+
const value = perLocaleValues[locale];
|
|
21
|
+
if (locale !== defaultLocale &&
|
|
22
|
+
!areEqualTranslationsValues(value, perLocaleValues[defaultLocale])) {
|
|
23
|
+
output += `locale === "${locale}" ? ${getTranslationValueOutput(value)} : `;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
output += getTranslationValueOutput(perLocaleValues[defaultLocale]);
|
|
27
|
+
return output;
|
|
28
|
+
};
|
|
29
|
+
export default ({ config, options, translations }) => {
|
|
30
|
+
let output = `
|
|
31
|
+
/* eslint-disable @typescript-eslint/no-unused-vars */
|
|
32
|
+
/* eslint-disable prefer-const */
|
|
33
|
+
import type { I18n } from "./types";
|
|
34
|
+
import { tInterpolateParams } from "./tInterpolateParams";
|
|
35
|
+
import { tPluralise } from "./tPluralise";
|
|
36
|
+
|
|
37
|
+
`;
|
|
38
|
+
for (const translationId in translations) {
|
|
39
|
+
let { values, params, plural } = translations[translationId];
|
|
40
|
+
const name = `${options.translations.fnsPrefix}${translationId}`;
|
|
41
|
+
if (plural) {
|
|
42
|
+
if (params) {
|
|
43
|
+
params["count"] = "number";
|
|
44
|
+
}
|
|
45
|
+
else {
|
|
46
|
+
params = { count: "number" };
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
const argParam = params
|
|
50
|
+
? `params: { ${dataParamsToTsInterfaceBody(params)} }`
|
|
51
|
+
: "";
|
|
52
|
+
const argLocale = "locale?: I18n.Locale";
|
|
53
|
+
const args = [argParam, argLocale].filter(Boolean).join(", ");
|
|
54
|
+
output += `export let ${name} = (${args}) => `;
|
|
55
|
+
let outputFnReturn = "";
|
|
56
|
+
if (isPrimitive(values)) {
|
|
57
|
+
outputFnReturn += getTranslationValueOutput(values);
|
|
58
|
+
}
|
|
59
|
+
else {
|
|
60
|
+
outputFnReturn += getFunctionBodyWithLocales(config, values);
|
|
61
|
+
}
|
|
62
|
+
if (plural) {
|
|
63
|
+
outputFnReturn = `tPluralise(${outputFnReturn}, params.count)`;
|
|
64
|
+
}
|
|
65
|
+
if (params) {
|
|
66
|
+
outputFnReturn = `tInterpolateParams(${outputFnReturn}, params);`;
|
|
67
|
+
}
|
|
68
|
+
else {
|
|
69
|
+
outputFnReturn = `${outputFnReturn};`;
|
|
70
|
+
}
|
|
71
|
+
output += outputFnReturn;
|
|
72
|
+
output += `\n`;
|
|
73
|
+
}
|
|
74
|
+
return output;
|
|
75
|
+
};
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
const escapeEachChar = (input) => input
|
|
2
|
+
.split("")
|
|
3
|
+
.map((v) => `\\${v}`)
|
|
4
|
+
.join("");
|
|
5
|
+
export default ({ options }) => {
|
|
6
|
+
const { start, end } = options.translations.dynamicDelimiters;
|
|
7
|
+
return `
|
|
8
|
+
/* eslint-disable prefer-const */
|
|
9
|
+
export let tInterpolateParams = (
|
|
10
|
+
value: string,
|
|
11
|
+
params?: object,
|
|
12
|
+
) =>
|
|
13
|
+
params ? value.replace(
|
|
14
|
+
/${escapeEachChar(start)}(.*?)${escapeEachChar(end)}/g,
|
|
15
|
+
(_, key) =>
|
|
16
|
+
params[key.trim() as keyof typeof params] + "",
|
|
17
|
+
) : value;
|
|
18
|
+
|
|
19
|
+
export default tInterpolateParams;
|
|
20
|
+
`;
|
|
21
|
+
};
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export default () => {
|
|
2
|
+
return `
|
|
3
|
+
/* eslint-disable prefer-const */
|
|
4
|
+
let pluralRules = new Intl.PluralRules();
|
|
5
|
+
|
|
6
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
7
|
+
export let tPluralise = (values: any, count: number) =>
|
|
8
|
+
values[count] || values[pluralRules.select(count)] || (count === 0 ? values.zero : values["other"]);
|
|
9
|
+
|
|
10
|
+
export default tPluralise;
|
|
11
|
+
`;
|
|
12
|
+
};
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
export default ({ config }) => `
|
|
2
|
+
import { isLocale } from "./isLocale";
|
|
3
|
+
import { toFormat } from "./toFormat";
|
|
4
|
+
import { routesSlim } from "./routesSlim";
|
|
5
|
+
import type { I18n } from "./types";
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* *To* route utility
|
|
9
|
+
*
|
|
10
|
+
* @returns A localised relative URL based on your i18nCompiler configuration
|
|
11
|
+
*/
|
|
12
|
+
export function to<Id extends I18n.RouteId>(
|
|
13
|
+
id: Id,
|
|
14
|
+
...args: Id extends I18n.RouteIdDynamic
|
|
15
|
+
?
|
|
16
|
+
| [I18n.RouteParams[Id]]
|
|
17
|
+
| [I18n.RouteParams[Id], I18n.Locale]
|
|
18
|
+
: [] | [I18n.Locale]
|
|
19
|
+
) {
|
|
20
|
+
const locale = (isLocale(args[0]) ? args[0] : args[1]) || "${config.defaultLocale}";
|
|
21
|
+
|
|
22
|
+
return toFormat(
|
|
23
|
+
locale,
|
|
24
|
+
(routesSlim[id] as Record<string, string>)[locale] ??
|
|
25
|
+
(routesSlim[id] as Record<string, string>)["${config.defaultLocale}"] ??
|
|
26
|
+
routesSlim[id],
|
|
27
|
+
isLocale(args[0]) ? undefined : args[0]
|
|
28
|
+
) as I18n.RoutePathnames[Id];
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export default to;
|
|
32
|
+
`;
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { changeCaseSnake, isString } from "@koine/utils";
|
|
2
|
+
const getFunctionBodyWithLocales = (config, perLocaleValues) => {
|
|
3
|
+
const { defaultLocale } = config;
|
|
4
|
+
let output = "";
|
|
5
|
+
for (const locale in perLocaleValues) {
|
|
6
|
+
const value = perLocaleValues[locale];
|
|
7
|
+
if (locale !== defaultLocale && value !== perLocaleValues[defaultLocale]) {
|
|
8
|
+
output += `locale === "${locale}" ? "${value}" : `;
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
output += '"' + perLocaleValues[defaultLocale] + '"';
|
|
12
|
+
return output;
|
|
13
|
+
};
|
|
14
|
+
export default ({ config, routes, options }) => {
|
|
15
|
+
const hasOneLocale = config.locales.length === 1;
|
|
16
|
+
let output = `
|
|
17
|
+
/* eslint-disable prefer-const */
|
|
18
|
+
import { toFormat } from "./toFormat";
|
|
19
|
+
import type { I18n } from "./types";
|
|
20
|
+
|
|
21
|
+
`;
|
|
22
|
+
for (const routeId in routes.byId) {
|
|
23
|
+
const { pathnames, params } = routes.byId[routeId];
|
|
24
|
+
const name = `${options.routes.fnsPrefix}${changeCaseSnake(routeId)}`;
|
|
25
|
+
const paramsType = `I18n.RouteParams["${routeId}"]`;
|
|
26
|
+
const argParam = params ? `params: ${paramsType}` : "";
|
|
27
|
+
const argLocale = hasOneLocale ? "" : "locale?: I18n.Locale";
|
|
28
|
+
const args = [argParam, argLocale].filter(Boolean).join(", ");
|
|
29
|
+
const formatArgLocale = hasOneLocale ? `""` : "locale";
|
|
30
|
+
const formatArgParams = params ? ", params" : "";
|
|
31
|
+
output += `export let ${name} = (${args}) => `;
|
|
32
|
+
if (isString(pathnames)) {
|
|
33
|
+
output += `toFormat(${formatArgLocale}, "${pathnames}"${formatArgParams});`;
|
|
34
|
+
}
|
|
35
|
+
else {
|
|
36
|
+
output += `toFormat(${formatArgLocale}, ${getFunctionBodyWithLocales(config, pathnames)}${formatArgParams});`;
|
|
37
|
+
}
|
|
38
|
+
output += `\n`;
|
|
39
|
+
}
|
|
40
|
+
return output;
|
|
41
|
+
};
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
export default ({ config }) => `
|
|
2
|
+
export function toFormat(
|
|
3
|
+
locale: string | undefined,
|
|
4
|
+
pathname: string,
|
|
5
|
+
params?: object,
|
|
6
|
+
) {
|
|
7
|
+
locale = locale || "${config.defaultLocale}";
|
|
8
|
+
if (process.env["NODE_ENV"] === "development") {
|
|
9
|
+
if (params) {
|
|
10
|
+
pathname.replace(/\\[(.*?)\\]/g, (_, dynamicKey) => {
|
|
11
|
+
const key = dynamicKey as Extract<keyof typeof params, string>;
|
|
12
|
+
|
|
13
|
+
if (!(key in params)) {
|
|
14
|
+
console.warn(
|
|
15
|
+
"[@koine/i18n]::interpolateTo, using '" +
|
|
16
|
+
pathname +
|
|
17
|
+
"' without param '" +
|
|
18
|
+
key +
|
|
19
|
+
"'",
|
|
20
|
+
{ params }
|
|
21
|
+
);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
if (!["string", "number"].includes(typeof params[key])) {
|
|
25
|
+
console.warn(
|
|
26
|
+
"[@koine/i18n]::toFormat, using '" +
|
|
27
|
+
pathname +
|
|
28
|
+
"' with unserializable param '" +
|
|
29
|
+
key +
|
|
30
|
+
"' (type '" +
|
|
31
|
+
Object.prototype.toString.call((params[key])).slice(8, -1) +
|
|
32
|
+
"')",
|
|
33
|
+
);
|
|
34
|
+
}
|
|
35
|
+
return "";
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
if (params) {
|
|
41
|
+
pathname = pathname.replace(
|
|
42
|
+
/\\[(.*?)\\]/g,
|
|
43
|
+
(_, key) =>
|
|
44
|
+
params[key as keyof typeof params] + "",
|
|
45
|
+
)
|
|
46
|
+
}
|
|
47
|
+
${config.hideDefaultLocaleInUrl
|
|
48
|
+
? `
|
|
49
|
+
if (locale !== "${config.defaultLocale}") {
|
|
50
|
+
return "/" + locale + pathname;
|
|
51
|
+
}
|
|
52
|
+
`
|
|
53
|
+
: ``}
|
|
54
|
+
return pathname;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export default toFormat;
|
|
58
|
+
`;
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
export default ({ config, options }) => {
|
|
2
|
+
const { idDelimiter } = options.routes.tokens;
|
|
3
|
+
return `
|
|
4
|
+
import { isLocale } from "./isLocale";
|
|
5
|
+
import { routesSpa } from "./routesSpa";
|
|
6
|
+
import { toFormat } from "./toFormat";
|
|
7
|
+
import type { I18n } from "./types";
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* *To spa* route utility
|
|
11
|
+
*
|
|
12
|
+
* @returns A localised relative URL based on your i18nCompiler configuration
|
|
13
|
+
*/
|
|
14
|
+
export function toSpa<
|
|
15
|
+
Root extends keyof I18n.RouteSpa,
|
|
16
|
+
Path extends Extract<keyof I18n.RouteSpa[Root], string>,
|
|
17
|
+
>(
|
|
18
|
+
rootId: Root,
|
|
19
|
+
pathId: Path,
|
|
20
|
+
...args: I18n.RouteJoinedId<Root, Path> extends I18n.RouteIdDynamic
|
|
21
|
+
?
|
|
22
|
+
| [I18n.RouteParams[I18n.RouteJoinedId<Root, Path>]]
|
|
23
|
+
| [I18n.RouteParams[I18n.RouteJoinedId<Root, Path>], I18n.Locale]
|
|
24
|
+
: [] | [I18n.Locale]
|
|
25
|
+
) {
|
|
26
|
+
const locale = (isLocale(args[0]) ? args[0] : args[1]) || "${config.defaultLocale}";
|
|
27
|
+
const fullId = \`\${rootId}${idDelimiter}\${pathId}\` as I18n.RouteJoinedId<Root, Path>;
|
|
28
|
+
return toFormat(
|
|
29
|
+
// FIXME: actually the locale will be prepended if hideDefaultLocaleInUrl will be false
|
|
30
|
+
"", // do not pass the locale so that won't be prepended
|
|
31
|
+
(routesSpa[fullId] as Record<string, string>)[locale],
|
|
32
|
+
args.length === 2
|
|
33
|
+
? args[0]
|
|
34
|
+
: args[0] && !isLocale(args[0])
|
|
35
|
+
? args[0]
|
|
36
|
+
: void 0,
|
|
37
|
+
) as I18n.RouteSpa[Root][Path];
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export default toSpa;
|
|
41
|
+
`;
|
|
42
|
+
};
|