Skip to content

Commit

Permalink
feat: allow relative urls to be localized and parsed
Browse files Browse the repository at this point in the history
  • Loading branch information
stas-nc committed Feb 4, 2025
1 parent b8ed63a commit 04edf2d
Show file tree
Hide file tree
Showing 4 changed files with 35 additions and 14 deletions.
8 changes: 3 additions & 5 deletions src/app/utils/localizeUrl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,6 @@ export function localizeUrl(config: IntlAdapterConfig, url: string, configOverri

const { path, origin } = parseAsFullyQualifiedURI(url);

if (!path.startsWith('/')) {
throw new Error(`Localization of relative URLs is not supported. Received: "${url}"`);
}

const { cleanUrl } = parseUrl(config, path);

const receivedLocale = configOverride.locale ?? config.default.locale;
Expand All @@ -32,5 +28,7 @@ export function localizeUrl(config: IntlAdapterConfig, url: string, configOverri
return origin + cleanUrl;
}

return `${origin}/${getShortenedLocale(locale, config.supported.locale)}${cleanUrl}`;
const separator = cleanUrl.startsWith('/') ? '' : '/';

return `${origin}/${getShortenedLocale(locale, config.supported.locale)}${separator}${cleanUrl}`;
}
2 changes: 1 addition & 1 deletion src/app/utils/parseAsFullyQualifiedURI.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ export function parseAsFullyQualifiedURI(uri: string): ParsedUri {
// Normalize multiple slashes to a single slash, but don't affect the initial "http://" or "https://"
const normalizedUri = uri.replace(/([^:])\/{2,}/g, '$1/');

if (normalizedUri.startsWith('/')) {
if (!normalizedUri.startsWith('http://') && !normalizedUri.startsWith('https://')) {
return { origin: '', path: normalizedUri };
}

Expand Down
7 changes: 2 additions & 5 deletions src/app/utils/parseUrl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,9 @@ export function parseUrl(config: IntlAdapterConfig, url: string): ParsedUrl {
}

const { path, origin } = parseAsFullyQualifiedURI(url);
const trimmedPath = path.charAt(0) === '/' ? path.slice(1) : path;

if (!path.startsWith('/')) {
throw new Error(`Localization of relative URLs is not supported. Received: "${url}"`);
}

const [, langPart, ...unlocalizedPath] = path.split('/');
const [langPart, ...unlocalizedPath] = trimmedPath.split('/');
const locale = getCanonicalLocale(langPart, config.supported.locale);

if (locale !== null && config.supported.locale.indexOf(locale) !== -1) {
Expand Down
32 changes: 29 additions & 3 deletions test/app/IlcIntl.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,13 @@ describe('IlcIntl', () => {
expect(IlcIntl.localizeUrl(baseConfig, 'http://tst.com', { locale: 'es-ES' })).to.eq('http://tst.com/es/');
expect(IlcIntl.localizeUrl(baseConfig, 'http://tst.com/', { locale: 'es-ES' })).to.eq('http://tst.com/es/');
});
it('handles relative URI cases', () => {
expect(IlcIntl.localizeUrl(baseConfig, 'path/1')).to.eq('path/1');
expect(IlcIntl.localizeUrl(baseConfig, 'path/1/')).to.eq('path/1/');

expect(IlcIntl.localizeUrl(baseConfig, 'path/1', { locale: 'es-ES' })).to.eq('/es/path/1');
expect(IlcIntl.localizeUrl(baseConfig, 'path/1/', { locale: 'es-ES' })).to.eq('/es/path/1/');
});

it('handles multiple slashes in the URL correctly', () => {
expect(IlcIntl.localizeUrl(baseConfig, 'http://tst.com/es///google.com', { locale: 'es-ES' })).to.eq(
Expand Down Expand Up @@ -212,8 +219,10 @@ describe('IlcIntl', () => {
expect(IlcIntl.localizeUrl(baseConfig, 'javascript:void(0)', { locale: 'es-ES' })).to.equal(
'javascript:void(0)',
);
});

expect(() => IlcIntl.localizeUrl(baseConfig, 'tst', { locale: 'es-ES' })).throws(Error);
it('fallbacks to original value on invalid urls', () => {
expect(IlcIntl.localizeUrl(baseConfig, 'http://:')).to.equal('http://:');
});
});

Expand Down Expand Up @@ -257,6 +266,25 @@ describe('IlcIntl', () => {
});
});

it('handles relative url cases', () => {
expect(IlcIntl.parseUrl(baseConfig, 'path/1')).to.eql({
cleanUrl: 'path/1',
locale: baseConfig.default.locale,
});
expect(IlcIntl.parseUrl(baseConfig, 'path/1/')).to.eql({
cleanUrl: 'path/1/',
locale: baseConfig.default.locale,
});
expect(IlcIntl.parseUrl(baseConfig, 'es/path/1')).to.eql({
cleanUrl: '/path/1',
locale: 'es-ES',
});
expect(IlcIntl.parseUrl(baseConfig, 'es/path/1/')).to.eql({
cleanUrl: '/path/1/',
locale: 'es-ES',
});
});

it('handles multiple slashes in the URL correctly', () => {
expect(IlcIntl.parseUrl(baseConfig, 'http://tst.com/es///google.com')).to.eql({
cleanUrl: 'http://tst.com/google.com',
Expand Down Expand Up @@ -306,8 +334,6 @@ describe('IlcIntl', () => {
cleanUrl: 'javascript:void(0)',
locale: baseConfig.default.locale,
});

expect(() => IlcIntl.parseUrl(baseConfig, 'tst')).to.throw(Error);
});
});

Expand Down

0 comments on commit 04edf2d

Please sign in to comment.