@intlayer/core 9.0.0-canary.2 → 9.0.0-canary.4

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.
@@ -63,6 +63,7 @@ const require_dictionaryManipulator_renameContentNodeByKeyPath = require('./dict
63
63
  const require_dictionaryManipulator_updateNodeChildren = require('./dictionaryManipulator/updateNodeChildren.cjs');
64
64
  const require_utils_checkIsURLAbsolute = require('./utils/checkIsURLAbsolute.cjs');
65
65
  const require_localization_getPathWithoutLocale = require('./localization/getPathWithoutLocale.cjs');
66
+ const require_localization_comparePaths = require('./localization/comparePaths.cjs');
66
67
  const require_localization_getPrefix = require('./localization/getPrefix.cjs');
67
68
  const require_localization_rewriteUtils = require('./localization/rewriteUtils.cjs');
68
69
  const require_localization_getLocalizedUrl = require('./localization/getLocalizedUrl.cjs');
@@ -186,6 +187,7 @@ exports.captureNothing = require_markdown_utils.captureNothing;
186
187
  exports.checkIsURLAbsolute = require_utils_checkIsURLAbsolute.checkIsURLAbsolute;
187
188
  exports.checkMissingLocalesPlugin = require_deepTransformPlugins_getMissingLocalesContent.checkMissingLocalesPlugin;
188
189
  exports.compact = require_formatters_compact.compact;
190
+ exports.comparePaths = require_localization_comparePaths.comparePaths;
189
191
  exports.compile = require_markdown_compiler.compile;
190
192
  exports.compileWithOptions = require_markdown_compiler.compileWithOptions;
191
193
  exports.cond = require_transpiler_condition_condition.cond;
@@ -303,6 +305,7 @@ exports.nestedPlugin = require_interpreter_getContent_plugins.nestedPlugin;
303
305
  exports.normalizeAttributeKey = require_markdown_utils.normalizeAttributeKey;
304
306
  exports.normalizeDictionaries = require_dictionaryManipulator_normalizeDictionary.normalizeDictionaries;
305
307
  exports.normalizeDictionary = require_dictionaryManipulator_normalizeDictionary.normalizeDictionary;
308
+ exports.normalizePath = require_localization_comparePaths.normalizePath;
306
309
  exports.normalizeWhitespace = require_markdown_utils.normalizeWhitespace;
307
310
  exports.number = require_formatters_number.number;
308
311
  exports.orderDictionaries = require_dictionaryManipulator_orderDictionaries.orderDictionaries;
@@ -0,0 +1,75 @@
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
2
+ const require_utils_checkIsURLAbsolute = require('../utils/checkIsURLAbsolute.cjs');
3
+ const require_localization_getPathWithoutLocale = require('./getPathWithoutLocale.cjs');
4
+
5
+ //#region src/localization/comparePaths.ts
6
+ /**
7
+ * Normalizes a URL or pathname into a canonical, locale-agnostic pathname so
8
+ * that two paths pointing to the same page compare equal — useful for
9
+ * highlighting the active navigation link.
10
+ *
11
+ * The normalization:
12
+ * - strips the locale segment (reusing {@link getPathWithoutLocale})
13
+ * - strips the protocol/host so absolute and relative inputs compare equally
14
+ * - drops the query string and hash
15
+ * - ensures a single leading slash
16
+ * - removes any trailing slash (except for the root path)
17
+ * - falls back to `'/'` for empty values
18
+ *
19
+ * Example:
20
+ *
21
+ * ```ts
22
+ * normalizePath('/ru/path') // '/path'
23
+ * normalizePath('/ru/path/') // '/path'
24
+ * normalizePath('ru/path') // '/path'
25
+ * normalizePath('/ru/') // '/'
26
+ * normalizePath('/ru') // '/'
27
+ * normalizePath('') // '/'
28
+ * normalizePath('https://example.com/ru/path') // '/path'
29
+ * ```
30
+ *
31
+ * @param inputUrl - The URL string or pathname to normalize.
32
+ * @param locales - Optional array of supported locales. Defaults to the
33
+ * configured locales.
34
+ * @returns The normalized, locale-agnostic pathname.
35
+ */
36
+ const normalizePath = (inputUrl, locales) => {
37
+ const withoutLocale = require_localization_getPathWithoutLocale.getPathWithoutLocale(inputUrl || "/", locales);
38
+ const { pathname } = require_utils_checkIsURLAbsolute.checkIsURLAbsolute(withoutLocale) ? new URL(withoutLocale) : new URL(withoutLocale, "http://example.com");
39
+ if (pathname.length > 1 && pathname.endsWith("/")) return pathname.slice(0, -1);
40
+ return pathname || "/";
41
+ };
42
+ /**
43
+ * Compares two URLs or pathnames for equality, ignoring locale segment,
44
+ * protocol/host, query string, hash and trailing slashes.
45
+ *
46
+ * Both inputs are normalized through {@link normalizePath} before comparison,
47
+ * making this ideal for matching the current pathname against a navigation
48
+ * link's `href`.
49
+ *
50
+ * Example:
51
+ *
52
+ * ```ts
53
+ * comparePaths('/ru/path', '/path') // true
54
+ * comparePaths('/ru/path/', '/path') // true
55
+ * comparePaths('/ru/path', '/path/') // true
56
+ * comparePaths('/ru/', '/') // true
57
+ * comparePaths('/ru', '/') // true
58
+ * comparePaths('ru/path', '/path') // true
59
+ * comparePaths('', '/') // true
60
+ * comparePaths('/ru', '') // true
61
+ * comparePaths('/ru/path', '/other') // false
62
+ * ```
63
+ *
64
+ * @param pathname - The first URL string or pathname to compare.
65
+ * @param href - The second URL string or pathname to compare.
66
+ * @param locales - Optional array of supported locales. Defaults to the
67
+ * configured locales.
68
+ * @returns `true` when both inputs resolve to the same locale-agnostic path.
69
+ */
70
+ const comparePaths = (pathname, href, locales) => normalizePath(pathname, locales) === normalizePath(href, locales);
71
+
72
+ //#endregion
73
+ exports.comparePaths = comparePaths;
74
+ exports.normalizePath = normalizePath;
75
+ //# sourceMappingURL=comparePaths.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"comparePaths.cjs","names":["getPathWithoutLocale","checkIsURLAbsolute"],"sources":["../../../src/localization/comparePaths.ts"],"sourcesContent":["import type {\n DeclaredLocales,\n LocalesValues,\n} from '@intlayer/types/module_augmentation';\nimport { checkIsURLAbsolute } from '../utils/checkIsURLAbsolute';\nimport { getPathWithoutLocale } from './getPathWithoutLocale';\n\n/**\n * Normalizes a URL or pathname into a canonical, locale-agnostic pathname so\n * that two paths pointing to the same page compare equal — useful for\n * highlighting the active navigation link.\n *\n * The normalization:\n * - strips the locale segment (reusing {@link getPathWithoutLocale})\n * - strips the protocol/host so absolute and relative inputs compare equally\n * - drops the query string and hash\n * - ensures a single leading slash\n * - removes any trailing slash (except for the root path)\n * - falls back to `'/'` for empty values\n *\n * Example:\n *\n * ```ts\n * normalizePath('/ru/path') // '/path'\n * normalizePath('/ru/path/') // '/path'\n * normalizePath('ru/path') // '/path'\n * normalizePath('/ru/') // '/'\n * normalizePath('/ru') // '/'\n * normalizePath('') // '/'\n * normalizePath('https://example.com/ru/path') // '/path'\n * ```\n *\n * @param inputUrl - The URL string or pathname to normalize.\n * @param locales - Optional array of supported locales. Defaults to the\n * configured locales.\n * @returns The normalized, locale-agnostic pathname.\n */\nexport const normalizePath = <const L extends LocalesValues = DeclaredLocales>(\n inputUrl: string,\n locales?: L[]\n): string => {\n const withoutLocale = getPathWithoutLocale(inputUrl || '/', locales);\n\n // Reuse the URL API to isolate the pathname from any host/query/hash.\n const url = checkIsURLAbsolute(withoutLocale)\n ? new URL(withoutLocale)\n : new URL(withoutLocale, 'http://example.com');\n\n const { pathname } = url;\n\n // Remove a trailing slash, keeping the root path intact.\n if (pathname.length > 1 && pathname.endsWith('/')) {\n return pathname.slice(0, -1);\n }\n\n return pathname || '/';\n};\n\n/**\n * Compares two URLs or pathnames for equality, ignoring locale segment,\n * protocol/host, query string, hash and trailing slashes.\n *\n * Both inputs are normalized through {@link normalizePath} before comparison,\n * making this ideal for matching the current pathname against a navigation\n * link's `href`.\n *\n * Example:\n *\n * ```ts\n * comparePaths('/ru/path', '/path') // true\n * comparePaths('/ru/path/', '/path') // true\n * comparePaths('/ru/path', '/path/') // true\n * comparePaths('/ru/', '/') // true\n * comparePaths('/ru', '/') // true\n * comparePaths('ru/path', '/path') // true\n * comparePaths('', '/') // true\n * comparePaths('/ru', '') // true\n * comparePaths('/ru/path', '/other') // false\n * ```\n *\n * @param pathname - The first URL string or pathname to compare.\n * @param href - The second URL string or pathname to compare.\n * @param locales - Optional array of supported locales. Defaults to the\n * configured locales.\n * @returns `true` when both inputs resolve to the same locale-agnostic path.\n */\nexport const comparePaths = <const L extends LocalesValues = DeclaredLocales>(\n pathname: string,\n href: string,\n locales?: L[]\n): boolean => normalizePath(pathname, locales) === normalizePath(href, locales);\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAqCA,MAAa,iBACX,UACA,YACW;CACX,MAAM,gBAAgBA,+DAAqB,YAAY,KAAK,QAAQ;CAOpE,MAAM,EAAE,aAJIC,oDAAmB,cAAc,GACzC,IAAI,IAAI,cAAc,GACtB,IAAI,IAAI,eAAe,qBAAqB;AAKhD,KAAI,SAAS,SAAS,KAAK,SAAS,SAAS,IAAI,CAC/C,QAAO,SAAS,MAAM,GAAG,GAAG;AAG9B,QAAO,YAAY;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA+BrB,MAAa,gBACX,UACA,MACA,YACY,cAAc,UAAU,QAAQ,KAAK,cAAc,MAAM,QAAQ"}
@@ -1,5 +1,6 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
2
2
  const require_localization_getPathWithoutLocale = require('./getPathWithoutLocale.cjs');
3
+ const require_localization_comparePaths = require('./comparePaths.cjs');
3
4
  const require_localization_getPrefix = require('./getPrefix.cjs');
4
5
  const require_localization_rewriteUtils = require('./rewriteUtils.cjs');
5
6
  const require_localization_getLocalizedUrl = require('./getLocalizedUrl.cjs');
@@ -16,6 +17,7 @@ const require_localization_getLocaleName = require('./getLocaleName.cjs');
16
17
  const require_localization_localeMapper = require('./localeMapper.cjs');
17
18
  const require_localization_validatePrefix = require('./validatePrefix.cjs');
18
19
 
20
+ exports.comparePaths = require_localization_comparePaths.comparePaths;
19
21
  exports.generateSitemap = require_localization_generateSitemap.generateSitemap;
20
22
  exports.generateSitemapUrl = require_localization_generateSitemap.generateSitemapUrl;
21
23
  exports.getBrowserLocale = require_localization_getBrowserLocale.getBrowserLocale;
@@ -38,4 +40,5 @@ exports.localeFlatMap = require_localization_localeMapper.localeFlatMap;
38
40
  exports.localeMap = require_localization_localeMapper.localeMap;
39
41
  exports.localeRecord = require_localization_localeMapper.localeRecord;
40
42
  exports.localeResolver = require_localization_localeResolver.localeResolver;
43
+ exports.normalizePath = require_localization_comparePaths.normalizePath;
41
44
  exports.validatePrefix = require_localization_validatePrefix.validatePrefix;
@@ -62,6 +62,7 @@ import { renameContentNodeByKeyPath } from "./dictionaryManipulator/renameConten
62
62
  import { updateNodeChildren } from "./dictionaryManipulator/updateNodeChildren.mjs";
63
63
  import { checkIsURLAbsolute } from "./utils/checkIsURLAbsolute.mjs";
64
64
  import { getPathWithoutLocale } from "./localization/getPathWithoutLocale.mjs";
65
+ import { comparePaths, normalizePath } from "./localization/comparePaths.mjs";
65
66
  import { getPrefix } from "./localization/getPrefix.mjs";
66
67
  import { getCanonicalPath, getInternalPath, getLocalizedPath, getRewritePath, getRewriteRules } from "./localization/rewriteUtils.mjs";
67
68
  import { getLocalizedUrl } from "./localization/getLocalizedUrl.mjs";
@@ -92,4 +93,4 @@ import { interpolateMessage, parseTaggedMessage, resolveMessage, resolveMessageN
92
93
  import { isSameKeyPath } from "./utils/isSameKeyPath.mjs";
93
94
  import { stringifyYaml } from "./utils/stringifyYaml.mjs";
94
95
 
95
- export { ATTRIBUTES_TO_SANITIZE, ATTRIBUTE_TO_NODE_PROP_MAP, ATTR_EXTRACTOR_R, BLOCKQUOTE_ALERT_R, BLOCKQUOTE_R, BLOCKQUOTE_TRIM_LEFT_MULTILINE_R, BLOCK_END_R, BREAK_LINE_R, BREAK_THEMATIC_R, CAPTURE_LETTER_AFTER_HYPHEN, CODE_BLOCK_FENCED_R, CODE_BLOCK_R, CODE_INLINE_R, COMPOSITE_ID_SEPARATOR, CONSECUTIVE_NEWLINE_R, CR_NEWLINE_R, CUSTOM_COMPONENT_R, CachedIntl, CachedIntl as Intl, DO_NOT_PROCESS_HTML_ELEMENTS, DURATION_DELAY_TRIGGER, FOOTNOTE_R, FOOTNOTE_REFERENCE_R, FORMFEED_R, FRONT_MATTER_R, GFM_TASK_R, HEADING_ATX_COMPLIANT_R, HEADING_R, HEADING_SETEXT_R, HTML_BLOCK_ELEMENT_R, HTML_CHAR_CODE_R, HTML_COMMENT_R, HTML_CUSTOM_ATTR_R, HTML_LEFT_TRIM_AMOUNT_R, HTML_SELF_CLOSING_ELEMENT_R, HTML_TAGS, INLINE_SKIP_R, INTERPOLATION_R, LINK_AUTOLINK_BARE_URL_R, LINK_AUTOLINK_R, LIST_LOOKBEHIND_R, LOOKAHEAD, LocaleStorage, LocaleStorageClient, LocaleStorageServer, NAMED_CODES_TO_UNICODE, NP_TABLE_R, ORDERED, ORDERED_LIST_BULLET, ORDERED_LIST_ITEM_PREFIX, ORDERED_LIST_ITEM_PREFIX_R, ORDERED_LIST_ITEM_R, ORDERED_LIST_R, PARAGRAPH_R, Priority, QUALIFIER_DYNAMIC_TYPES_KEY, QUALIFIER_ORDER, REFERENCE_IMAGE_OR_LINK, REFERENCE_IMAGE_R, REFERENCE_LINK_R, RuleType, SHORTCODE_R, SHOULD_RENDER_AS_BLOCK_R, TABLE_CENTER_ALIGN, TABLE_LEFT_ALIGN, TABLE_RIGHT_ALIGN, TABLE_TRIM_PIPES, TAB_R, TEXT_BOLD_R, TEXT_EMPHASIZED_R, TEXT_ESCAPED_R, TEXT_MARKED_R, TEXT_PLAIN_R, TEXT_STRIKETHROUGHED_R, TRIM_STARTING_NEWLINES, UNESCAPE_R, UNORDERED, UNORDERED_LIST_BULLET, UNORDERED_LIST_ITEM_PREFIX, UNORDERED_LIST_ITEM_PREFIX_R, UNORDERED_LIST_ITEM_R, UNORDERED_LIST_R, VOID_HTML_ELEMENTS, allowInline, anyScopeRegex, attributeValueToNodePropValue, bindIntl, blockRegex, buildMaskPlugin, captureNothing, checkIsURLAbsolute, checkMissingLocalesPlugin, compact, compile, compileWithOptions, condition as cond, conditionPlugin, createCompiler, createRenderer, currency, cx, date, deepTransformNode, editDictionaryByKeyPath, enumeration as enu, enumerationPlugin, fallbackPlugin, filePlugin, filterMissingTranslationsOnlyPlugin, filterTranslationsOnlyPlugin, findMatchingCondition, gender, genderPlugin, generateListItemPrefix, generateListItemPrefixRegex, generateListItemRegex, generateListRegex, generateSitemap, generateSitemapUrl, get, getBasePlugins, getBrowserLocale, getCachedIntl, getCanonicalPath, getCondition, getContent, getContentNodeByKeyPath, getCookie, getDefaultNode, getDictionary, getDictionaryCompositeId, getDictionaryQualifierId, getDictionaryQualifierSegments, getDictionaryQualifierTypes, getDictionarySelectorCacheKey, getEditedContent, getEditedDictionary, getEmptyNode, getEnumeration, getFilterMissingTranslationsContent, getFilterMissingTranslationsDictionary, getFilterTranslationsOnlyContent, getFilterTranslationsOnlyDictionary, getFilteredLocalesContent, getFilteredLocalesDictionary, getHTML, getHTMLTextDir, getInsertionValues, getInternalPath, getIntlayer, getLocale, getLocaleFromPath, getLocaleFromStorage, getLocaleFromStorageClient, getLocaleFromStorageServer, getLocaleLang, getLocaleName, getLocalizedContent, getLocalizedPath, getLocalizedUrl, getMarkdownMetadata, getMaskContent, getMissingLocalesContent, getMissingLocalesContentFromDictionary, getMultilingualDictionary, getMultilingualUrls, getNesting, getNodeChildren, getNodeType, getPathWithoutLocale, getPerLocaleDictionary, getPlural, getPrefix, getReplacedValuesContent, getRewritePath, getRewriteRules, getSplittedContent, getSplittedDictionaryContent, getTranslation, html, i18nextToIntlayerFormatter, icuToIntlayerFormatter, inlineRegex, insertion as insert, insertContentInDictionary, insertionPlugin, interpolateMessage, intlayerToI18nextFormatter, intlayerToICUFormatter, intlayerToPortableObjectFormatter, intlayerToVueI18nFormatter, isQualifiedDictionaryGroup, isQualifiedDynamicLoaderMap, isSameKeyPath, isValidElement, list, localeDetector, localeFlatMap, localeMap, localeRecord, localeResolver, localeStorageOptions, markdown as md, mergeDictionaries, mergeQualifiedDictionaries, nesting as nest, nestedPlugin, normalizeAttributeKey, normalizeDictionaries, normalizeDictionary, normalizeWhitespace, number, orderDictionaries, parseBlock, parseCaptureInline, parseDictionarySelector, parseInline, parseMarkdown, parseSimpleInline, parseStyleAttribute, parseTableAlign, parseTableAlignCapture, parseTableCells, parseTableRow, parseTaggedMessage, parseYaml, parserFor, percentage, plural, pluralPlugin, portableObjectToIntlayerFormatter, presets, qualifies, reconstructQualifiedEntry, relativeTime, removeContentNodeByKeyPath, renameContentNodeByKeyPath, renderFor, renderMarkdownAst, renderNothing, resolveMessage, resolveMessageNode, resolveQualifiedDictionary, resolveQualifiedDynamicContent, resolveQualifiedDynamicContentAsync, sanitizer, setLocaleInStorage, setLocaleInStorageClient, setLocaleInStorageServer, simpleInlineRegex, slugify, some, splitInsertionTemplate, startsWith, stringifyYaml, translation as t, translationPlugin, trimEnd, trimLeadingWhitespaceOutsideFences, unescapeString, units, unquote, updateNodeChildren, validateHTML, validateMarkdown, validatePrefix, vueI18nToIntlayerFormatter };
96
+ export { ATTRIBUTES_TO_SANITIZE, ATTRIBUTE_TO_NODE_PROP_MAP, ATTR_EXTRACTOR_R, BLOCKQUOTE_ALERT_R, BLOCKQUOTE_R, BLOCKQUOTE_TRIM_LEFT_MULTILINE_R, BLOCK_END_R, BREAK_LINE_R, BREAK_THEMATIC_R, CAPTURE_LETTER_AFTER_HYPHEN, CODE_BLOCK_FENCED_R, CODE_BLOCK_R, CODE_INLINE_R, COMPOSITE_ID_SEPARATOR, CONSECUTIVE_NEWLINE_R, CR_NEWLINE_R, CUSTOM_COMPONENT_R, CachedIntl, CachedIntl as Intl, DO_NOT_PROCESS_HTML_ELEMENTS, DURATION_DELAY_TRIGGER, FOOTNOTE_R, FOOTNOTE_REFERENCE_R, FORMFEED_R, FRONT_MATTER_R, GFM_TASK_R, HEADING_ATX_COMPLIANT_R, HEADING_R, HEADING_SETEXT_R, HTML_BLOCK_ELEMENT_R, HTML_CHAR_CODE_R, HTML_COMMENT_R, HTML_CUSTOM_ATTR_R, HTML_LEFT_TRIM_AMOUNT_R, HTML_SELF_CLOSING_ELEMENT_R, HTML_TAGS, INLINE_SKIP_R, INTERPOLATION_R, LINK_AUTOLINK_BARE_URL_R, LINK_AUTOLINK_R, LIST_LOOKBEHIND_R, LOOKAHEAD, LocaleStorage, LocaleStorageClient, LocaleStorageServer, NAMED_CODES_TO_UNICODE, NP_TABLE_R, ORDERED, ORDERED_LIST_BULLET, ORDERED_LIST_ITEM_PREFIX, ORDERED_LIST_ITEM_PREFIX_R, ORDERED_LIST_ITEM_R, ORDERED_LIST_R, PARAGRAPH_R, Priority, QUALIFIER_DYNAMIC_TYPES_KEY, QUALIFIER_ORDER, REFERENCE_IMAGE_OR_LINK, REFERENCE_IMAGE_R, REFERENCE_LINK_R, RuleType, SHORTCODE_R, SHOULD_RENDER_AS_BLOCK_R, TABLE_CENTER_ALIGN, TABLE_LEFT_ALIGN, TABLE_RIGHT_ALIGN, TABLE_TRIM_PIPES, TAB_R, TEXT_BOLD_R, TEXT_EMPHASIZED_R, TEXT_ESCAPED_R, TEXT_MARKED_R, TEXT_PLAIN_R, TEXT_STRIKETHROUGHED_R, TRIM_STARTING_NEWLINES, UNESCAPE_R, UNORDERED, UNORDERED_LIST_BULLET, UNORDERED_LIST_ITEM_PREFIX, UNORDERED_LIST_ITEM_PREFIX_R, UNORDERED_LIST_ITEM_R, UNORDERED_LIST_R, VOID_HTML_ELEMENTS, allowInline, anyScopeRegex, attributeValueToNodePropValue, bindIntl, blockRegex, buildMaskPlugin, captureNothing, checkIsURLAbsolute, checkMissingLocalesPlugin, compact, comparePaths, compile, compileWithOptions, condition as cond, conditionPlugin, createCompiler, createRenderer, currency, cx, date, deepTransformNode, editDictionaryByKeyPath, enumeration as enu, enumerationPlugin, fallbackPlugin, filePlugin, filterMissingTranslationsOnlyPlugin, filterTranslationsOnlyPlugin, findMatchingCondition, gender, genderPlugin, generateListItemPrefix, generateListItemPrefixRegex, generateListItemRegex, generateListRegex, generateSitemap, generateSitemapUrl, get, getBasePlugins, getBrowserLocale, getCachedIntl, getCanonicalPath, getCondition, getContent, getContentNodeByKeyPath, getCookie, getDefaultNode, getDictionary, getDictionaryCompositeId, getDictionaryQualifierId, getDictionaryQualifierSegments, getDictionaryQualifierTypes, getDictionarySelectorCacheKey, getEditedContent, getEditedDictionary, getEmptyNode, getEnumeration, getFilterMissingTranslationsContent, getFilterMissingTranslationsDictionary, getFilterTranslationsOnlyContent, getFilterTranslationsOnlyDictionary, getFilteredLocalesContent, getFilteredLocalesDictionary, getHTML, getHTMLTextDir, getInsertionValues, getInternalPath, getIntlayer, getLocale, getLocaleFromPath, getLocaleFromStorage, getLocaleFromStorageClient, getLocaleFromStorageServer, getLocaleLang, getLocaleName, getLocalizedContent, getLocalizedPath, getLocalizedUrl, getMarkdownMetadata, getMaskContent, getMissingLocalesContent, getMissingLocalesContentFromDictionary, getMultilingualDictionary, getMultilingualUrls, getNesting, getNodeChildren, getNodeType, getPathWithoutLocale, getPerLocaleDictionary, getPlural, getPrefix, getReplacedValuesContent, getRewritePath, getRewriteRules, getSplittedContent, getSplittedDictionaryContent, getTranslation, html, i18nextToIntlayerFormatter, icuToIntlayerFormatter, inlineRegex, insertion as insert, insertContentInDictionary, insertionPlugin, interpolateMessage, intlayerToI18nextFormatter, intlayerToICUFormatter, intlayerToPortableObjectFormatter, intlayerToVueI18nFormatter, isQualifiedDictionaryGroup, isQualifiedDynamicLoaderMap, isSameKeyPath, isValidElement, list, localeDetector, localeFlatMap, localeMap, localeRecord, localeResolver, localeStorageOptions, markdown as md, mergeDictionaries, mergeQualifiedDictionaries, nesting as nest, nestedPlugin, normalizeAttributeKey, normalizeDictionaries, normalizeDictionary, normalizePath, normalizeWhitespace, number, orderDictionaries, parseBlock, parseCaptureInline, parseDictionarySelector, parseInline, parseMarkdown, parseSimpleInline, parseStyleAttribute, parseTableAlign, parseTableAlignCapture, parseTableCells, parseTableRow, parseTaggedMessage, parseYaml, parserFor, percentage, plural, pluralPlugin, portableObjectToIntlayerFormatter, presets, qualifies, reconstructQualifiedEntry, relativeTime, removeContentNodeByKeyPath, renameContentNodeByKeyPath, renderFor, renderMarkdownAst, renderNothing, resolveMessage, resolveMessageNode, resolveQualifiedDictionary, resolveQualifiedDynamicContent, resolveQualifiedDynamicContentAsync, sanitizer, setLocaleInStorage, setLocaleInStorageClient, setLocaleInStorageServer, simpleInlineRegex, slugify, some, splitInsertionTemplate, startsWith, stringifyYaml, translation as t, translationPlugin, trimEnd, trimLeadingWhitespaceOutsideFences, unescapeString, units, unquote, updateNodeChildren, validateHTML, validateMarkdown, validatePrefix, vueI18nToIntlayerFormatter };
@@ -0,0 +1,73 @@
1
+ import { checkIsURLAbsolute } from "../utils/checkIsURLAbsolute.mjs";
2
+ import { getPathWithoutLocale } from "./getPathWithoutLocale.mjs";
3
+
4
+ //#region src/localization/comparePaths.ts
5
+ /**
6
+ * Normalizes a URL or pathname into a canonical, locale-agnostic pathname so
7
+ * that two paths pointing to the same page compare equal — useful for
8
+ * highlighting the active navigation link.
9
+ *
10
+ * The normalization:
11
+ * - strips the locale segment (reusing {@link getPathWithoutLocale})
12
+ * - strips the protocol/host so absolute and relative inputs compare equally
13
+ * - drops the query string and hash
14
+ * - ensures a single leading slash
15
+ * - removes any trailing slash (except for the root path)
16
+ * - falls back to `'/'` for empty values
17
+ *
18
+ * Example:
19
+ *
20
+ * ```ts
21
+ * normalizePath('/ru/path') // '/path'
22
+ * normalizePath('/ru/path/') // '/path'
23
+ * normalizePath('ru/path') // '/path'
24
+ * normalizePath('/ru/') // '/'
25
+ * normalizePath('/ru') // '/'
26
+ * normalizePath('') // '/'
27
+ * normalizePath('https://example.com/ru/path') // '/path'
28
+ * ```
29
+ *
30
+ * @param inputUrl - The URL string or pathname to normalize.
31
+ * @param locales - Optional array of supported locales. Defaults to the
32
+ * configured locales.
33
+ * @returns The normalized, locale-agnostic pathname.
34
+ */
35
+ const normalizePath = (inputUrl, locales) => {
36
+ const withoutLocale = getPathWithoutLocale(inputUrl || "/", locales);
37
+ const { pathname } = checkIsURLAbsolute(withoutLocale) ? new URL(withoutLocale) : new URL(withoutLocale, "http://example.com");
38
+ if (pathname.length > 1 && pathname.endsWith("/")) return pathname.slice(0, -1);
39
+ return pathname || "/";
40
+ };
41
+ /**
42
+ * Compares two URLs or pathnames for equality, ignoring locale segment,
43
+ * protocol/host, query string, hash and trailing slashes.
44
+ *
45
+ * Both inputs are normalized through {@link normalizePath} before comparison,
46
+ * making this ideal for matching the current pathname against a navigation
47
+ * link's `href`.
48
+ *
49
+ * Example:
50
+ *
51
+ * ```ts
52
+ * comparePaths('/ru/path', '/path') // true
53
+ * comparePaths('/ru/path/', '/path') // true
54
+ * comparePaths('/ru/path', '/path/') // true
55
+ * comparePaths('/ru/', '/') // true
56
+ * comparePaths('/ru', '/') // true
57
+ * comparePaths('ru/path', '/path') // true
58
+ * comparePaths('', '/') // true
59
+ * comparePaths('/ru', '') // true
60
+ * comparePaths('/ru/path', '/other') // false
61
+ * ```
62
+ *
63
+ * @param pathname - The first URL string or pathname to compare.
64
+ * @param href - The second URL string or pathname to compare.
65
+ * @param locales - Optional array of supported locales. Defaults to the
66
+ * configured locales.
67
+ * @returns `true` when both inputs resolve to the same locale-agnostic path.
68
+ */
69
+ const comparePaths = (pathname, href, locales) => normalizePath(pathname, locales) === normalizePath(href, locales);
70
+
71
+ //#endregion
72
+ export { comparePaths, normalizePath };
73
+ //# sourceMappingURL=comparePaths.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"comparePaths.mjs","names":[],"sources":["../../../src/localization/comparePaths.ts"],"sourcesContent":["import type {\n DeclaredLocales,\n LocalesValues,\n} from '@intlayer/types/module_augmentation';\nimport { checkIsURLAbsolute } from '../utils/checkIsURLAbsolute';\nimport { getPathWithoutLocale } from './getPathWithoutLocale';\n\n/**\n * Normalizes a URL or pathname into a canonical, locale-agnostic pathname so\n * that two paths pointing to the same page compare equal — useful for\n * highlighting the active navigation link.\n *\n * The normalization:\n * - strips the locale segment (reusing {@link getPathWithoutLocale})\n * - strips the protocol/host so absolute and relative inputs compare equally\n * - drops the query string and hash\n * - ensures a single leading slash\n * - removes any trailing slash (except for the root path)\n * - falls back to `'/'` for empty values\n *\n * Example:\n *\n * ```ts\n * normalizePath('/ru/path') // '/path'\n * normalizePath('/ru/path/') // '/path'\n * normalizePath('ru/path') // '/path'\n * normalizePath('/ru/') // '/'\n * normalizePath('/ru') // '/'\n * normalizePath('') // '/'\n * normalizePath('https://example.com/ru/path') // '/path'\n * ```\n *\n * @param inputUrl - The URL string or pathname to normalize.\n * @param locales - Optional array of supported locales. Defaults to the\n * configured locales.\n * @returns The normalized, locale-agnostic pathname.\n */\nexport const normalizePath = <const L extends LocalesValues = DeclaredLocales>(\n inputUrl: string,\n locales?: L[]\n): string => {\n const withoutLocale = getPathWithoutLocale(inputUrl || '/', locales);\n\n // Reuse the URL API to isolate the pathname from any host/query/hash.\n const url = checkIsURLAbsolute(withoutLocale)\n ? new URL(withoutLocale)\n : new URL(withoutLocale, 'http://example.com');\n\n const { pathname } = url;\n\n // Remove a trailing slash, keeping the root path intact.\n if (pathname.length > 1 && pathname.endsWith('/')) {\n return pathname.slice(0, -1);\n }\n\n return pathname || '/';\n};\n\n/**\n * Compares two URLs or pathnames for equality, ignoring locale segment,\n * protocol/host, query string, hash and trailing slashes.\n *\n * Both inputs are normalized through {@link normalizePath} before comparison,\n * making this ideal for matching the current pathname against a navigation\n * link's `href`.\n *\n * Example:\n *\n * ```ts\n * comparePaths('/ru/path', '/path') // true\n * comparePaths('/ru/path/', '/path') // true\n * comparePaths('/ru/path', '/path/') // true\n * comparePaths('/ru/', '/') // true\n * comparePaths('/ru', '/') // true\n * comparePaths('ru/path', '/path') // true\n * comparePaths('', '/') // true\n * comparePaths('/ru', '') // true\n * comparePaths('/ru/path', '/other') // false\n * ```\n *\n * @param pathname - The first URL string or pathname to compare.\n * @param href - The second URL string or pathname to compare.\n * @param locales - Optional array of supported locales. Defaults to the\n * configured locales.\n * @returns `true` when both inputs resolve to the same locale-agnostic path.\n */\nexport const comparePaths = <const L extends LocalesValues = DeclaredLocales>(\n pathname: string,\n href: string,\n locales?: L[]\n): boolean => normalizePath(pathname, locales) === normalizePath(href, locales);\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAqCA,MAAa,iBACX,UACA,YACW;CACX,MAAM,gBAAgB,qBAAqB,YAAY,KAAK,QAAQ;CAOpE,MAAM,EAAE,aAJI,mBAAmB,cAAc,GACzC,IAAI,IAAI,cAAc,GACtB,IAAI,IAAI,eAAe,qBAAqB;AAKhD,KAAI,SAAS,SAAS,KAAK,SAAS,SAAS,IAAI,CAC/C,QAAO,SAAS,MAAM,GAAG,GAAG;AAG9B,QAAO,YAAY;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA+BrB,MAAa,gBACX,UACA,MACA,YACY,cAAc,UAAU,QAAQ,KAAK,cAAc,MAAM,QAAQ"}
@@ -1,4 +1,5 @@
1
1
  import { getPathWithoutLocale } from "./getPathWithoutLocale.mjs";
2
+ import { comparePaths, normalizePath } from "./comparePaths.mjs";
2
3
  import { getPrefix } from "./getPrefix.mjs";
3
4
  import { getCanonicalPath, getInternalPath, getLocalizedPath, getRewritePath, getRewriteRules } from "./rewriteUtils.mjs";
4
5
  import { getLocalizedUrl } from "./getLocalizedUrl.mjs";
@@ -15,4 +16,4 @@ import { getLocaleName } from "./getLocaleName.mjs";
15
16
  import { localeFlatMap, localeMap, localeRecord } from "./localeMapper.mjs";
16
17
  import { validatePrefix } from "./validatePrefix.mjs";
17
18
 
18
- export { generateSitemap, generateSitemapUrl, getBrowserLocale, getCanonicalPath, getHTMLTextDir, getInternalPath, getLocale, getLocaleFromPath, getLocaleLang, getLocaleName, getLocalizedPath, getLocalizedUrl, getMultilingualUrls, getPathWithoutLocale, getPrefix, getRewritePath, getRewriteRules, localeDetector, localeFlatMap, localeMap, localeRecord, localeResolver, validatePrefix };
19
+ export { comparePaths, generateSitemap, generateSitemapUrl, getBrowserLocale, getCanonicalPath, getHTMLTextDir, getInternalPath, getLocale, getLocaleFromPath, getLocaleLang, getLocaleName, getLocalizedPath, getLocalizedUrl, getMultilingualUrls, getPathWithoutLocale, getPrefix, getRewritePath, getRewriteRules, localeDetector, localeFlatMap, localeMap, localeRecord, localeResolver, normalizePath, validatePrefix };
@@ -59,6 +59,7 @@ import { number } from "./formatters/number.js";
59
59
  import { percentage } from "./formatters/percentage.js";
60
60
  import { relativeTime } from "./formatters/relativeTime.js";
61
61
  import { units } from "./formatters/units.js";
62
+ import { comparePaths, normalizePath } from "./localization/comparePaths.js";
62
63
  import { GenerateSitemapOptions, SitemapUrlEntry, generateSitemap, generateSitemapUrl } from "./localization/generateSitemap.js";
63
64
  import { getBrowserLocale } from "./localization/getBrowserLocale.js";
64
65
  import { getHTMLTextDir } from "./localization/getHTMLTextDir.js";
@@ -93,4 +94,4 @@ import { isValidElement } from "./utils/isValidReactElement.js";
93
94
  import { CookieBuildAttributes, LocaleStorage, LocaleStorageClient, LocaleStorageClientOptions, LocaleStorageOptions, LocaleStorageServer, LocaleStorageServerOptions, getLocaleFromStorage, getLocaleFromStorageClient, getLocaleFromStorageServer, localeStorageOptions, setLocaleInStorage, setLocaleInStorageClient, setLocaleInStorageServer } from "./utils/localeStorage.js";
94
95
  import { YamlRecord, YamlValue, parseYaml } from "./utils/parseYaml.js";
95
96
  import { stringifyYaml } from "./utils/stringifyYaml.js";
96
- export { ATTRIBUTES_TO_SANITIZE, ATTRIBUTE_TO_NODE_PROP_MAP, ATTR_EXTRACTOR_R, BLOCKQUOTE_ALERT_R, BLOCKQUOTE_R, BLOCKQUOTE_TRIM_LEFT_MULTILINE_R, BLOCK_END_R, BREAK_LINE_R, BREAK_THEMATIC_R, BlockQuoteNode, BoldTextNode, BreakLineNode, BreakThematicNode, CAPTURE_LETTER_AFTER_HYPHEN, CODE_BLOCK_FENCED_R, CODE_BLOCK_R, CODE_INLINE_R, COMPOSITE_ID_SEPARATOR, CONSECUTIVE_NEWLINE_R, CR_NEWLINE_R, CUSTOM_COMPONENT_R, CachedIntl, CachedIntl as Intl, CodeBlockNode, CodeFencedNode, CodeInlineNode, CompileOptions, ComponentOverrides, ConditionCond, ConditionContent, ConditionContentStates, CookieBuildAttributes, CustomComponentNode, DO_NOT_PROCESS_HTML_ELEMENTS, DURATION_DELAY_TRIGGER, DateTimePreset, DeepTransformContent, DotPath, DynamicDictionaryLoader, ElementType, EnterFormat, EnumerationCond, EnumerationContent, EnumerationContentState, EscapedTextNode, FOOTNOTE_R, FOOTNOTE_REFERENCE_R, FORMFEED_R, FRONT_MATTER_R, FileCond, FileContent, FileContentConstructor, FootnoteNode, FootnoteReferenceNode, GFMTaskNode, GFM_TASK_R, Gender, GenderCond, GenderContent, GenderContentStates, GenerateSitemapOptions, GetNestingResult, GetPrefixOptions, GetPrefixResult, HEADING_ATX_COMPLIANT_R, HEADING_R, HEADING_SETEXT_R, HTMLCommentNode, HTMLContent, HTMLContentConstructor, HTMLNode, HTMLSelfClosingNode, HTMLTag, HTMLTagsType, HTMLValidationIssue, HTMLValidationResult, HTML_BLOCK_ELEMENT_R, HTML_CHAR_CODE_R, HTML_COMMENT_R, HTML_CUSTOM_ATTR_R, HTML_LEFT_TRIM_AMOUNT_R, HTML_SELF_CLOSING_ELEMENT_R, HTML_TAGS, HeadingNode, HeadingSetextNode, IInterpreterPlugin, IInterpreterPluginState, INLINE_SKIP_R, INTERPOLATION_R, ImageNode, InsertionCond, InsertionContent, InsertionContentConstructor, IsAny, ItalicTextNode, JsonValue, LINK_AUTOLINK_BARE_URL_R, LINK_AUTOLINK_R, LIST_LOOKBEHIND_R, LOOKAHEAD, LinkAngleBraceNode, LinkBareURLNode, LinkNode, ListType, LocaleStorage, LocaleStorageClient, LocaleStorageClientOptions, LocaleStorageOptions, LocaleStorageServer, LocaleStorageServerOptions, LocalizedPathResult, MarkdownContent, MarkdownContentConstructor, MarkdownContext, MarkdownOptions, MarkdownRuntime, HTMLValidationIssue as MarkdownValidationIssue, MarkdownValidationResult, MarkedTextNode, MessageFormatDialect, MessageValues, NAMED_CODES_TO_UNICODE, NP_TABLE_R, NestedCond, NestedContent, NestedContentState, NestedParser, NewlineNode, NodeProps, ORDERED, ORDERED_LIST_BULLET, ORDERED_LIST_ITEM_PREFIX, ORDERED_LIST_ITEM_PREFIX_R, ORDERED_LIST_ITEM_R, ORDERED_LIST_R, OrderedListNode, PARAGRAPH_R, ParagraphNode, ParseState, ParsedMarkdown, Parser, ParserResult, Plugins, PluralCategory, PluralCond, PluralContent, PluralContentState, PortableObject, Priority, PriorityValue, QUALIFIER_DYNAMIC_TYPES_KEY, QUALIFIER_ORDER, QualifiedDynamicLoaderMap, QualifiedDynamicLoaderTree, REFERENCE_IMAGE_OR_LINK, REFERENCE_IMAGE_R, REFERENCE_LINK_R, ReferenceImageNode, ReferenceLinkNode, ReferenceNode, RenderRuleHook, Rule, RuleOutput, RuleType, RuleTypeValue, Rules, SHORTCODE_R, SHOULD_RENDER_AS_BLOCK_R, SitemapUrlEntry, StrikethroughTextNode, TABLE_CENTER_ALIGN, TABLE_LEFT_ALIGN, TABLE_RIGHT_ALIGN, TABLE_TRIM_PIPES, TAB_R, TEXT_BOLD_R, TEXT_EMPHASIZED_R, TEXT_ESCAPED_R, TEXT_MARKED_R, TEXT_PLAIN_R, TEXT_STRIKETHROUGHED_R, TRIM_STARTING_NEWLINES, TableNode, TableSeparatorNode, TaggedMessageToken, TextNode, TranslationCond, TranslationContent, UNESCAPE_R, UNORDERED, UNORDERED_LIST_BULLET, UNORDERED_LIST_ITEM_PREFIX, UNORDERED_LIST_ITEM_PREFIX_R, UNORDERED_LIST_ITEM_R, UNORDERED_LIST_R, UnionKeys, UnorderedListNode, VOID_HTML_ELEMENTS, ValidDotPathsFor, ValueAtKey, WrappedIntl, YamlRecord, YamlValue, allowInline, anyScopeRegex, attributeValueToNodePropValue, bindIntl, blockRegex, buildMaskPlugin, captureNothing, checkIsURLAbsolute, checkMissingLocalesPlugin, compact, compile, compileWithOptions, condition as cond, conditionPlugin, createCompiler, createRenderer, currency, cx, date, deepTransformNode, editDictionaryByKeyPath, enumeration as enu, enumerationPlugin, fallbackPlugin, file, fileContent, filePlugin, filterMissingTranslationsOnlyPlugin, filterTranslationsOnlyPlugin, findMatchingCondition, gender, genderPlugin, generateListItemPrefix, generateListItemPrefixRegex, generateListItemRegex, generateListRegex, generateSitemap, generateSitemapUrl, get, getBasePlugins, getBrowserLocale, getCachedIntl, getCanonicalPath, getCondition, getContent, getContentNodeByKeyPath, getCookie, getDefaultNode, getDictionary, getDictionaryCompositeId, getDictionaryQualifierId, getDictionaryQualifierSegments, getDictionaryQualifierTypes, getDictionarySelectorCacheKey, getEditedContent, getEditedDictionary, getEmptyNode, getEnumeration, getFilterMissingTranslationsContent, getFilterMissingTranslationsDictionary, getFilterTranslationsOnlyContent, getFilterTranslationsOnlyDictionary, getFilteredLocalesContent, getFilteredLocalesDictionary, getHTML, getHTMLTextDir, getInsertionValues, getInternalPath, getIntlayer, getLocale, getLocaleFromPath, getLocaleFromStorage, getLocaleFromStorageClient, getLocaleFromStorageServer, getLocaleLang, getLocaleName, getLocalizedContent, getLocalizedPath, getLocalizedUrl, getMarkdownMetadata, getMaskContent, getMissingLocalesContent, getMissingLocalesContentFromDictionary, getMultilingualDictionary, getMultilingualUrls, getNesting, getNodeChildren, getNodeType, getPathWithoutLocale, getPerLocaleDictionary, getPlural, getPrefix, getReplacedValuesContent, getRewritePath, getRewriteRules, getSplittedContent, getSplittedDictionaryContent, getTranslation, html, i18nextToIntlayerFormatter, icuToIntlayerFormatter, inlineRegex, insertion as insert, insertContentInDictionary, insertionPlugin, interpolateMessage, intlayerToI18nextFormatter, intlayerToICUFormatter, intlayerToPortableObjectFormatter, intlayerToVueI18nFormatter, isQualifiedDictionaryGroup, isQualifiedDynamicLoaderMap, isSameKeyPath, isValidElement, list, localeDetector, localeFlatMap, localeMap, localeRecord, localeResolver, localeStorageOptions, markdown as md, mergeDictionaries, mergeQualifiedDictionaries, nesting as nest, nestedPlugin, normalizeAttributeKey, normalizeDictionaries, normalizeDictionary, normalizeWhitespace, number, orderDictionaries, parseBlock, parseCaptureInline, parseDictionarySelector, parseInline, parseMarkdown, parseSimpleInline, parseStyleAttribute, parseTableAlign, parseTableAlignCapture, parseTableCells, parseTableRow, parseTaggedMessage, parseYaml, parserFor, percentage, plural, pluralPlugin, portableObjectToIntlayerFormatter, presets, qualifies, reconstructQualifiedEntry, relativeTime, removeContentNodeByKeyPath, renameContentNodeByKeyPath, renderFor, renderMarkdownAst, renderNothing, resolveMessage, resolveMessageNode, resolveQualifiedDictionary, resolveQualifiedDynamicContent, resolveQualifiedDynamicContentAsync, sanitizer, setLocaleInStorage, setLocaleInStorageClient, setLocaleInStorageServer, simpleInlineRegex, slugify, some, splitInsertionTemplate, startsWith, stringifyYaml, translation as t, translationPlugin, trimEnd, trimLeadingWhitespaceOutsideFences, unescapeString, units, unquote, updateNodeChildren, validateHTML, validateMarkdown, validatePrefix, vueI18nToIntlayerFormatter };
97
+ export { ATTRIBUTES_TO_SANITIZE, ATTRIBUTE_TO_NODE_PROP_MAP, ATTR_EXTRACTOR_R, BLOCKQUOTE_ALERT_R, BLOCKQUOTE_R, BLOCKQUOTE_TRIM_LEFT_MULTILINE_R, BLOCK_END_R, BREAK_LINE_R, BREAK_THEMATIC_R, BlockQuoteNode, BoldTextNode, BreakLineNode, BreakThematicNode, CAPTURE_LETTER_AFTER_HYPHEN, CODE_BLOCK_FENCED_R, CODE_BLOCK_R, CODE_INLINE_R, COMPOSITE_ID_SEPARATOR, CONSECUTIVE_NEWLINE_R, CR_NEWLINE_R, CUSTOM_COMPONENT_R, CachedIntl, CachedIntl as Intl, CodeBlockNode, CodeFencedNode, CodeInlineNode, CompileOptions, ComponentOverrides, ConditionCond, ConditionContent, ConditionContentStates, CookieBuildAttributes, CustomComponentNode, DO_NOT_PROCESS_HTML_ELEMENTS, DURATION_DELAY_TRIGGER, DateTimePreset, DeepTransformContent, DotPath, DynamicDictionaryLoader, ElementType, EnterFormat, EnumerationCond, EnumerationContent, EnumerationContentState, EscapedTextNode, FOOTNOTE_R, FOOTNOTE_REFERENCE_R, FORMFEED_R, FRONT_MATTER_R, FileCond, FileContent, FileContentConstructor, FootnoteNode, FootnoteReferenceNode, GFMTaskNode, GFM_TASK_R, Gender, GenderCond, GenderContent, GenderContentStates, GenerateSitemapOptions, GetNestingResult, GetPrefixOptions, GetPrefixResult, HEADING_ATX_COMPLIANT_R, HEADING_R, HEADING_SETEXT_R, HTMLCommentNode, HTMLContent, HTMLContentConstructor, HTMLNode, HTMLSelfClosingNode, HTMLTag, HTMLTagsType, HTMLValidationIssue, HTMLValidationResult, HTML_BLOCK_ELEMENT_R, HTML_CHAR_CODE_R, HTML_COMMENT_R, HTML_CUSTOM_ATTR_R, HTML_LEFT_TRIM_AMOUNT_R, HTML_SELF_CLOSING_ELEMENT_R, HTML_TAGS, HeadingNode, HeadingSetextNode, IInterpreterPlugin, IInterpreterPluginState, INLINE_SKIP_R, INTERPOLATION_R, ImageNode, InsertionCond, InsertionContent, InsertionContentConstructor, IsAny, ItalicTextNode, JsonValue, LINK_AUTOLINK_BARE_URL_R, LINK_AUTOLINK_R, LIST_LOOKBEHIND_R, LOOKAHEAD, LinkAngleBraceNode, LinkBareURLNode, LinkNode, ListType, LocaleStorage, LocaleStorageClient, LocaleStorageClientOptions, LocaleStorageOptions, LocaleStorageServer, LocaleStorageServerOptions, LocalizedPathResult, MarkdownContent, MarkdownContentConstructor, MarkdownContext, MarkdownOptions, MarkdownRuntime, HTMLValidationIssue as MarkdownValidationIssue, MarkdownValidationResult, MarkedTextNode, MessageFormatDialect, MessageValues, NAMED_CODES_TO_UNICODE, NP_TABLE_R, NestedCond, NestedContent, NestedContentState, NestedParser, NewlineNode, NodeProps, ORDERED, ORDERED_LIST_BULLET, ORDERED_LIST_ITEM_PREFIX, ORDERED_LIST_ITEM_PREFIX_R, ORDERED_LIST_ITEM_R, ORDERED_LIST_R, OrderedListNode, PARAGRAPH_R, ParagraphNode, ParseState, ParsedMarkdown, Parser, ParserResult, Plugins, PluralCategory, PluralCond, PluralContent, PluralContentState, PortableObject, Priority, PriorityValue, QUALIFIER_DYNAMIC_TYPES_KEY, QUALIFIER_ORDER, QualifiedDynamicLoaderMap, QualifiedDynamicLoaderTree, REFERENCE_IMAGE_OR_LINK, REFERENCE_IMAGE_R, REFERENCE_LINK_R, ReferenceImageNode, ReferenceLinkNode, ReferenceNode, RenderRuleHook, Rule, RuleOutput, RuleType, RuleTypeValue, Rules, SHORTCODE_R, SHOULD_RENDER_AS_BLOCK_R, SitemapUrlEntry, StrikethroughTextNode, TABLE_CENTER_ALIGN, TABLE_LEFT_ALIGN, TABLE_RIGHT_ALIGN, TABLE_TRIM_PIPES, TAB_R, TEXT_BOLD_R, TEXT_EMPHASIZED_R, TEXT_ESCAPED_R, TEXT_MARKED_R, TEXT_PLAIN_R, TEXT_STRIKETHROUGHED_R, TRIM_STARTING_NEWLINES, TableNode, TableSeparatorNode, TaggedMessageToken, TextNode, TranslationCond, TranslationContent, UNESCAPE_R, UNORDERED, UNORDERED_LIST_BULLET, UNORDERED_LIST_ITEM_PREFIX, UNORDERED_LIST_ITEM_PREFIX_R, UNORDERED_LIST_ITEM_R, UNORDERED_LIST_R, UnionKeys, UnorderedListNode, VOID_HTML_ELEMENTS, ValidDotPathsFor, ValueAtKey, WrappedIntl, YamlRecord, YamlValue, allowInline, anyScopeRegex, attributeValueToNodePropValue, bindIntl, blockRegex, buildMaskPlugin, captureNothing, checkIsURLAbsolute, checkMissingLocalesPlugin, compact, comparePaths, compile, compileWithOptions, condition as cond, conditionPlugin, createCompiler, createRenderer, currency, cx, date, deepTransformNode, editDictionaryByKeyPath, enumeration as enu, enumerationPlugin, fallbackPlugin, file, fileContent, filePlugin, filterMissingTranslationsOnlyPlugin, filterTranslationsOnlyPlugin, findMatchingCondition, gender, genderPlugin, generateListItemPrefix, generateListItemPrefixRegex, generateListItemRegex, generateListRegex, generateSitemap, generateSitemapUrl, get, getBasePlugins, getBrowserLocale, getCachedIntl, getCanonicalPath, getCondition, getContent, getContentNodeByKeyPath, getCookie, getDefaultNode, getDictionary, getDictionaryCompositeId, getDictionaryQualifierId, getDictionaryQualifierSegments, getDictionaryQualifierTypes, getDictionarySelectorCacheKey, getEditedContent, getEditedDictionary, getEmptyNode, getEnumeration, getFilterMissingTranslationsContent, getFilterMissingTranslationsDictionary, getFilterTranslationsOnlyContent, getFilterTranslationsOnlyDictionary, getFilteredLocalesContent, getFilteredLocalesDictionary, getHTML, getHTMLTextDir, getInsertionValues, getInternalPath, getIntlayer, getLocale, getLocaleFromPath, getLocaleFromStorage, getLocaleFromStorageClient, getLocaleFromStorageServer, getLocaleLang, getLocaleName, getLocalizedContent, getLocalizedPath, getLocalizedUrl, getMarkdownMetadata, getMaskContent, getMissingLocalesContent, getMissingLocalesContentFromDictionary, getMultilingualDictionary, getMultilingualUrls, getNesting, getNodeChildren, getNodeType, getPathWithoutLocale, getPerLocaleDictionary, getPlural, getPrefix, getReplacedValuesContent, getRewritePath, getRewriteRules, getSplittedContent, getSplittedDictionaryContent, getTranslation, html, i18nextToIntlayerFormatter, icuToIntlayerFormatter, inlineRegex, insertion as insert, insertContentInDictionary, insertionPlugin, interpolateMessage, intlayerToI18nextFormatter, intlayerToICUFormatter, intlayerToPortableObjectFormatter, intlayerToVueI18nFormatter, isQualifiedDictionaryGroup, isQualifiedDynamicLoaderMap, isSameKeyPath, isValidElement, list, localeDetector, localeFlatMap, localeMap, localeRecord, localeResolver, localeStorageOptions, markdown as md, mergeDictionaries, mergeQualifiedDictionaries, nesting as nest, nestedPlugin, normalizeAttributeKey, normalizeDictionaries, normalizeDictionary, normalizePath, normalizeWhitespace, number, orderDictionaries, parseBlock, parseCaptureInline, parseDictionarySelector, parseInline, parseMarkdown, parseSimpleInline, parseStyleAttribute, parseTableAlign, parseTableAlignCapture, parseTableCells, parseTableRow, parseTaggedMessage, parseYaml, parserFor, percentage, plural, pluralPlugin, portableObjectToIntlayerFormatter, presets, qualifies, reconstructQualifiedEntry, relativeTime, removeContentNodeByKeyPath, renameContentNodeByKeyPath, renderFor, renderMarkdownAst, renderNothing, resolveMessage, resolveMessageNode, resolveQualifiedDictionary, resolveQualifiedDynamicContent, resolveQualifiedDynamicContentAsync, sanitizer, setLocaleInStorage, setLocaleInStorageClient, setLocaleInStorageServer, simpleInlineRegex, slugify, some, splitInsertionTemplate, startsWith, stringifyYaml, translation as t, translationPlugin, trimEnd, trimLeadingWhitespaceOutsideFences, unescapeString, units, unquote, updateNodeChildren, validateHTML, validateMarkdown, validatePrefix, vueI18nToIntlayerFormatter };
@@ -0,0 +1,66 @@
1
+ import { DeclaredLocales, LocalesValues } from "@intlayer/types/module_augmentation";
2
+
3
+ //#region src/localization/comparePaths.d.ts
4
+ /**
5
+ * Normalizes a URL or pathname into a canonical, locale-agnostic pathname so
6
+ * that two paths pointing to the same page compare equal — useful for
7
+ * highlighting the active navigation link.
8
+ *
9
+ * The normalization:
10
+ * - strips the locale segment (reusing {@link getPathWithoutLocale})
11
+ * - strips the protocol/host so absolute and relative inputs compare equally
12
+ * - drops the query string and hash
13
+ * - ensures a single leading slash
14
+ * - removes any trailing slash (except for the root path)
15
+ * - falls back to `'/'` for empty values
16
+ *
17
+ * Example:
18
+ *
19
+ * ```ts
20
+ * normalizePath('/ru/path') // '/path'
21
+ * normalizePath('/ru/path/') // '/path'
22
+ * normalizePath('ru/path') // '/path'
23
+ * normalizePath('/ru/') // '/'
24
+ * normalizePath('/ru') // '/'
25
+ * normalizePath('') // '/'
26
+ * normalizePath('https://example.com/ru/path') // '/path'
27
+ * ```
28
+ *
29
+ * @param inputUrl - The URL string or pathname to normalize.
30
+ * @param locales - Optional array of supported locales. Defaults to the
31
+ * configured locales.
32
+ * @returns The normalized, locale-agnostic pathname.
33
+ */
34
+ declare const normalizePath: <const L extends LocalesValues = DeclaredLocales>(inputUrl: string, locales?: L[]) => string;
35
+ /**
36
+ * Compares two URLs or pathnames for equality, ignoring locale segment,
37
+ * protocol/host, query string, hash and trailing slashes.
38
+ *
39
+ * Both inputs are normalized through {@link normalizePath} before comparison,
40
+ * making this ideal for matching the current pathname against a navigation
41
+ * link's `href`.
42
+ *
43
+ * Example:
44
+ *
45
+ * ```ts
46
+ * comparePaths('/ru/path', '/path') // true
47
+ * comparePaths('/ru/path/', '/path') // true
48
+ * comparePaths('/ru/path', '/path/') // true
49
+ * comparePaths('/ru/', '/') // true
50
+ * comparePaths('/ru', '/') // true
51
+ * comparePaths('ru/path', '/path') // true
52
+ * comparePaths('', '/') // true
53
+ * comparePaths('/ru', '') // true
54
+ * comparePaths('/ru/path', '/other') // false
55
+ * ```
56
+ *
57
+ * @param pathname - The first URL string or pathname to compare.
58
+ * @param href - The second URL string or pathname to compare.
59
+ * @param locales - Optional array of supported locales. Defaults to the
60
+ * configured locales.
61
+ * @returns `true` when both inputs resolve to the same locale-agnostic path.
62
+ */
63
+ declare const comparePaths: <const L extends LocalesValues = DeclaredLocales>(pathname: string, href: string, locales?: L[]) => boolean;
64
+ //#endregion
65
+ export { comparePaths, normalizePath };
66
+ //# sourceMappingURL=comparePaths.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"comparePaths.d.ts","names":[],"sources":["../../../src/localization/comparePaths.ts"],"mappings":";;;;;AAqCA;;;;;;;;;;;;;;;;AAiDA;;;;;;;;;;;;cAjDa,aAAA,mBAAiC,aAAA,GAAgB,eAAA,EAC5D,QAAA,UACA,OAAA,GAAU,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;cA+CC,YAAA,mBAAgC,aAAA,GAAgB,eAAA,EAC3D,QAAA,UACA,IAAA,UACA,OAAA,GAAU,CAAA"}
@@ -1,3 +1,4 @@
1
+ import { comparePaths, normalizePath } from "./comparePaths.js";
1
2
  import { GenerateSitemapOptions, SitemapUrlEntry, generateSitemap, generateSitemapUrl } from "./generateSitemap.js";
2
3
  import { getBrowserLocale } from "./getBrowserLocale.js";
3
4
  import { getHTMLTextDir } from "./getHTMLTextDir.js";
@@ -14,4 +15,4 @@ import { localeFlatMap, localeMap, localeRecord } from "./localeMapper.js";
14
15
  import { localeResolver } from "./localeResolver.js";
15
16
  import { LocalizedPathResult, getCanonicalPath, getInternalPath, getLocalizedPath, getRewritePath, getRewriteRules } from "./rewriteUtils.js";
16
17
  import { validatePrefix } from "./validatePrefix.js";
17
- export { type GenerateSitemapOptions, type GetPrefixOptions, type GetPrefixResult, type LocalizedPathResult, type SitemapUrlEntry, generateSitemap, generateSitemapUrl, getBrowserLocale, getCanonicalPath, getHTMLTextDir, getInternalPath, getLocale, getLocaleFromPath, getLocaleLang, getLocaleName, getLocalizedPath, getLocalizedUrl, getMultilingualUrls, getPathWithoutLocale, getPrefix, getRewritePath, getRewriteRules, localeDetector, localeFlatMap, localeMap, localeRecord, localeResolver, validatePrefix };
18
+ export { type GenerateSitemapOptions, type GetPrefixOptions, type GetPrefixResult, type LocalizedPathResult, type SitemapUrlEntry, comparePaths, generateSitemap, generateSitemapUrl, getBrowserLocale, getCanonicalPath, getHTMLTextDir, getInternalPath, getLocale, getLocaleFromPath, getLocaleLang, getLocaleName, getLocalizedPath, getLocalizedUrl, getMultilingualUrls, getPathWithoutLocale, getPrefix, getRewritePath, getRewriteRules, localeDetector, localeFlatMap, localeMap, localeRecord, localeResolver, normalizePath, validatePrefix };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@intlayer/core",
3
- "version": "9.0.0-canary.2",
3
+ "version": "9.0.0-canary.4",
4
4
  "private": false,
5
5
  "description": "Includes core Intlayer functions like translation, dictionary, and utility functions shared across multiple packages.",
6
6
  "keywords": [
@@ -172,15 +172,15 @@
172
172
  "typecheck": "tsc --noEmit --project tsconfig.types.json"
173
173
  },
174
174
  "dependencies": {
175
- "@intlayer/api": "9.0.0-canary.2",
176
- "@intlayer/config": "9.0.0-canary.2",
177
- "@intlayer/dictionaries-entry": "9.0.0-canary.2",
178
- "@intlayer/types": "9.0.0-canary.2",
179
- "@intlayer/unmerged-dictionaries-entry": "9.0.0-canary.2",
175
+ "@intlayer/api": "9.0.0-canary.4",
176
+ "@intlayer/config": "9.0.0-canary.4",
177
+ "@intlayer/dictionaries-entry": "9.0.0-canary.4",
178
+ "@intlayer/types": "9.0.0-canary.4",
179
+ "@intlayer/unmerged-dictionaries-entry": "9.0.0-canary.4",
180
180
  "defu": "6.1.7"
181
181
  },
182
182
  "devDependencies": {
183
- "@types/node": "25.9.3",
183
+ "@types/node": "25.9.4",
184
184
  "@utils/ts-config": "1.0.4",
185
185
  "@utils/ts-config-types": "1.0.4",
186
186
  "@utils/tsdown-config": "1.0.4",