Skip to content

Commit

Permalink
fix: take astro base path into account when using localizePath or loc…
Browse files Browse the repository at this point in the history
…alizeUrl functions

fixes #27
  • Loading branch information
yassinedoghri committed Sep 4, 2022
1 parent 1339181 commit 5c35eaf
Show file tree
Hide file tree
Showing 3 changed files with 94 additions and 28 deletions.
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -363,7 +363,7 @@ const interpolated = interpolate(

### localizePath function

`localizePath(path: string, locale: string | null = null): string`
`localizePath(path: string, locale: string | null = null, base: string = import.meta.env.BASE_URL): string`

Sets a path within a given locale. If the locale param is not specified, the
current language will be used.
Expand All @@ -385,7 +385,7 @@ i18next.changeLanguage("fr");

### localizeUrl function

`localizeUrl(url: string, locale: string | null = null): string`
`localizeUrl(url: string, locale: string | null = null, base: string = import.meta.env.BASE_URL): string`

Sets a url within a given locale. If the locale param is not specified, the
current language will be used.
Expand Down
88 changes: 71 additions & 17 deletions src/__tests__/utils.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -108,42 +108,42 @@ describe("localizePath(...)", () => {
i18next.changeLanguage("en");
expect(localizePath("/")).toBe("/");
expect(localizePath("/fr")).toBe("/");
expect(localizePath("/about")).toBe("/about");
expect(localizePath("/fr/about")).toBe("/about");
expect(localizePath("/about")).toBe("/about/");
expect(localizePath("/fr/about")).toBe("/about/");

i18next.changeLanguage("fr");
expect(localizePath("/")).toBe("/fr/");
expect(localizePath("/about")).toBe("/fr/about");
expect(localizePath("/fr/about")).toBe("/fr/about");
expect(localizePath("/fr-CA/about")).toBe("/fr/about");
expect(localizePath("/about")).toBe("/fr/about/");
expect(localizePath("/fr/about")).toBe("/fr/about/");
expect(localizePath("/fr-CA/about")).toBe("/fr/about/");

i18next.changeLanguage("fr-CA");
expect(localizePath("/fr/about")).toBe("/fr-CA/about");
expect(localizePath("/about")).toBe("/fr-CA/about");
expect(localizePath("/fr/about")).toBe("/fr-CA/about/");
expect(localizePath("/about")).toBe("/fr-CA/about/");
});

it("with longer paths", () => {
i18next.changeLanguage("fr");
expect(localizePath("/really/long/path")).toBe("/fr/really/long/path");
expect(localizePath("/really/long/path")).toBe("/fr/really/long/path/");
expect(localizePath("/super/huge/and/really/long/path")).toBe(
"/fr/super/huge/and/really/long/path"
"/fr/super/huge/and/really/long/path/"
);

i18next.changeLanguage("fr-CA");
expect(localizePath("/fr/really/long/path/with/locale/before")).toBe(
"/fr-CA/really/long/path/with/locale/before"
"/fr-CA/really/long/path/with/locale/before/"
);

i18next.changeLanguage("en");
expect(localizePath("/fr/really/long/path/with/locale/before")).toBe(
"/really/long/path/with/locale/before"
"/really/long/path/with/locale/before/"
);
});

it("with multiple leading slashes", () => {
i18next.changeLanguage("fr");
expect(localizePath("//fr-CA/about")).toBe("/fr/about");
expect(localizePath("////fr/about")).toBe("/fr/about");
expect(localizePath("//fr-CA/about")).toBe("/fr/about/");
expect(localizePath("////fr/about")).toBe("/fr/about/");
});

it("with an empty string as path", () => {
Expand All @@ -164,27 +164,81 @@ describe("localizePath(...)", () => {

it("with an unsupported locale", () => {
i18next.changeLanguage("de");
expect(localizePath("/fr/about")).toBe("/fr/about");
expect(localizePath("/fr/about")).toBe("/fr/about/");
expect(console.warn).toHaveBeenCalled();
});

it("with base path", () => {
i18next.changeLanguage("fr");
expect(localizePath("/base", null, "/base/")).toBe("/base/fr/");
expect(localizePath("/base/about", null, "/base/")).toBe("/base/fr/about/");
expect(localizePath("/about", null, "/base/")).toBe("/base/fr/about/");
expect(localizePath("/", null, "/base/")).toBe("/base/fr/");
expect(localizePath("", null, "/base/")).toBe("/base/fr/");

i18next.changeLanguage("en");
expect(localizePath("/base/about", null, "/base/")).toBe("/base/about/");
expect(localizePath("/about", null, "/base/")).toBe("/base/about/");
expect(localizePath("/", null, "/base/")).toBe("/base/");
expect(localizePath("", null, "/base/")).toBe("/base/");

i18next.changeLanguage("de");
expect(localizePath("/fr/about", null, "/base/")).toBe("/base/fr/about/");
expect(localizePath("base/fr/about", null, "base")).toBe("/base/fr/about/");
expect(console.warn).toHaveBeenCalled();
});

it("with base path written weirdly", () => {
i18next.changeLanguage("fr");
expect(localizePath("", null, "base")).toBe("/base/fr/");
expect(localizePath("", null, "/base")).toBe("/base/fr/");
expect(localizePath("", null, "base/")).toBe("/base/fr/");
expect(localizePath("", null, "//base//")).toBe("/base/fr/");
expect(localizePath("", null, "/base///")).toBe("/base/fr/");
expect(localizePath("", null, "///base/")).toBe("/base/fr/");
});
});

describe("localizeUrl(...)", () => {
it("generates the correct url given a url with supported locale", () => {
i18next.changeLanguage("en");
expect(localizeUrl("https://example.com/")).toBe("https://example.com/");
expect(localizeUrl("https://example.com/about")).toBe(
"https://example.com/about"
"https://example.com/about/"
);
expect(localizeUrl("https://example.com/fr/")).toBe("https://example.com/");
expect(localizeUrl("https://example.com/fr/about")).toBe(
"https://example.com/about"
"https://example.com/about/"
);

i18next.changeLanguage("fr");
expect(localizeUrl("https://example.com/")).toBe("https://example.com/fr/");
expect(localizeUrl("https://example.com/about")).toBe(
"https://example.com/fr/about"
"https://example.com/fr/about/"
);
});

it("generates the correct url given a url with a base path", () => {
i18next.changeLanguage("en");
expect(localizeUrl("https://example.com/base/", null, "/base/")).toBe(
"https://example.com/base/"
);
expect(localizeUrl("https://example.com/base/about/", null, "/base/")).toBe(
"https://example.com/base/about/"
);
expect(localizeUrl("https://example.com/fr/", null, "/base/")).toBe(
"https://example.com/base/"
);
expect(
localizeUrl("https://example.com/base/fr/about", null, "/base/")
).toBe("https://example.com/base/about/");

i18next.changeLanguage("fr");
expect(localizeUrl("https://example.com/", null, "/base/")).toBe(
"https://example.com/base/fr/"
);
expect(localizeUrl("https://example.com/about", null, "/base/")).toBe(
"https://example.com/base/fr/about/"
);
});
});
Expand Down
30 changes: 21 additions & 9 deletions src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -103,29 +103,40 @@ export const interpolate = (
*/
export const localizePath = (
path: string = "/",
locale: string | null = null
locale: string | null = null,
base: string = import.meta.env.BASE_URL
): string => {
if (!locale) {
locale = i18next.language;
}

// remove all leading slashes off of path
path = path.replace(/^\/+|\/+$/g, "");
path = path === "" ? "/" : "/" + path + "/";

// remove leading and trailing slashes off of base path
base = base.replace(/^\/+|\/+$/g, "");
base = base === "" ? "/" : "/" + base + "/";

// remove base path if found
path = path.startsWith(base) ? path.slice(base.length) : path.slice(1);

if (!(i18next.options.supportedLngs as string[]).includes(locale)) {
console.warn(
`WARNING(astro-i18next): "${locale}" locale is not supported, add it to the supportedLngs in your astro config.`
);
return path;
return base + path;
}

// remove all leading slashes
path = path.replace(/^\/+/g, "");

let pathSegments = path.split("/");

if (
JSON.stringify(pathSegments) === JSON.stringify([""]) ||
JSON.stringify(pathSegments) === JSON.stringify(["", ""])
) {
return locale === i18next.options.supportedLngs[0] ? `/` : `/${locale}/`;
return locale === i18next.options.supportedLngs[0]
? base
: `${base}${locale}/`;
}

// make a copy of i18next's supportedLngs
Expand All @@ -146,20 +157,21 @@ export const localizePath = (
pathSegments = [locale, ...pathSegments];
}

return "/" + pathSegments.join("/");
return base + pathSegments.join("/");
};

/**
* Injects the given locale to a url
*/
export const localizeUrl = (
url: string,
locale: string | null = null
locale: string | null = null,
base: string = import.meta.env.BASE_URL
): string => {
const [protocol, , host, ...path] = url.split("/");
const baseUrl = protocol + "//" + host;

return baseUrl + localizePath(path.join("/"), locale);
return baseUrl + localizePath(path.join("/"), locale, base);
};

/**
Expand Down

0 comments on commit 5c35eaf

Please sign in to comment.