@intlayer/core 7.5.0-canary.0 → 7.5.0
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/dist/cjs/deepTransformPlugins/getFilterMissingTranslationsContent.cjs +10 -10
- package/dist/cjs/deepTransformPlugins/getFilterMissingTranslationsContent.cjs.map +1 -1
- package/dist/cjs/deepTransformPlugins/getFilterTranslationsOnlyContent.cjs +11 -11
- package/dist/cjs/deepTransformPlugins/getFilterTranslationsOnlyContent.cjs.map +1 -1
- package/dist/cjs/deepTransformPlugins/getFilteredLocalesContent.cjs +4 -4
- package/dist/cjs/deepTransformPlugins/getFilteredLocalesContent.cjs.map +1 -1
- package/dist/cjs/deepTransformPlugins/getMissingLocalesContent.cjs +7 -7
- package/dist/cjs/deepTransformPlugins/getMissingLocalesContent.cjs.map +1 -1
- package/dist/cjs/deepTransformPlugins/getSplittedContent.cjs +3 -3
- package/dist/cjs/deepTransformPlugins/getSplittedContent.cjs.map +1 -1
- package/dist/cjs/deepTransformPlugins/insertContentInDictionary.cjs +6 -6
- package/dist/cjs/deepTransformPlugins/insertContentInDictionary.cjs.map +1 -1
- package/dist/cjs/dictionaryManipulator/editDictionaryByKeyPath.cjs +6 -6
- package/dist/cjs/dictionaryManipulator/editDictionaryByKeyPath.cjs.map +1 -1
- package/dist/cjs/dictionaryManipulator/getContentNodeByKeyPath.cjs +5 -5
- package/dist/cjs/dictionaryManipulator/getContentNodeByKeyPath.cjs.map +1 -1
- package/dist/cjs/dictionaryManipulator/getDefaultNode.cjs +27 -27
- package/dist/cjs/dictionaryManipulator/getDefaultNode.cjs.map +1 -1
- package/dist/cjs/dictionaryManipulator/getEmptyNode.cjs +5 -5
- package/dist/cjs/dictionaryManipulator/getEmptyNode.cjs.map +1 -1
- package/dist/cjs/dictionaryManipulator/getNodeChildren.cjs +3 -3
- package/dist/cjs/dictionaryManipulator/getNodeChildren.cjs.map +1 -1
- package/dist/cjs/dictionaryManipulator/getNodeType.cjs +11 -11
- package/dist/cjs/dictionaryManipulator/getNodeType.cjs.map +1 -1
- package/dist/cjs/dictionaryManipulator/mergeDictionaries.cjs +5 -5
- package/dist/cjs/dictionaryManipulator/mergeDictionaries.cjs.map +1 -1
- package/dist/cjs/dictionaryManipulator/orderDictionaries.cjs +3 -3
- package/dist/cjs/dictionaryManipulator/orderDictionaries.cjs.map +1 -1
- package/dist/cjs/dictionaryManipulator/removeContentNodeByKeyPath.cjs +4 -4
- package/dist/cjs/dictionaryManipulator/removeContentNodeByKeyPath.cjs.map +1 -1
- package/dist/cjs/dictionaryManipulator/renameContentNodeByKeyPath.cjs +4 -4
- package/dist/cjs/dictionaryManipulator/renameContentNodeByKeyPath.cjs.map +1 -1
- package/dist/cjs/dictionaryManipulator/updateNodeChildren.cjs +3 -3
- package/dist/cjs/dictionaryManipulator/updateNodeChildren.cjs.map +1 -1
- package/dist/cjs/formatters/compact.cjs +3 -3
- package/dist/cjs/formatters/compact.cjs.map +1 -1
- package/dist/cjs/formatters/currency.cjs +3 -3
- package/dist/cjs/formatters/currency.cjs.map +1 -1
- package/dist/cjs/formatters/date.cjs +3 -3
- package/dist/cjs/formatters/date.cjs.map +1 -1
- package/dist/cjs/formatters/list.cjs +3 -3
- package/dist/cjs/formatters/list.cjs.map +1 -1
- package/dist/cjs/formatters/number.cjs +3 -3
- package/dist/cjs/formatters/number.cjs.map +1 -1
- package/dist/cjs/formatters/percentage.cjs +3 -3
- package/dist/cjs/formatters/percentage.cjs.map +1 -1
- package/dist/cjs/formatters/relativeTime.cjs +3 -3
- package/dist/cjs/formatters/relativeTime.cjs.map +1 -1
- package/dist/cjs/formatters/units.cjs +3 -3
- package/dist/cjs/formatters/units.cjs.map +1 -1
- package/dist/cjs/getStorageAttributes.cjs +4 -4
- package/dist/cjs/getStorageAttributes.cjs.map +1 -1
- package/dist/cjs/interpreter/getContent/deepTransform.cjs +3 -3
- package/dist/cjs/interpreter/getContent/deepTransform.cjs.map +1 -1
- package/dist/cjs/interpreter/getContent/getContent.cjs +3 -3
- package/dist/cjs/interpreter/getContent/getContent.cjs.map +1 -1
- package/dist/cjs/interpreter/getContent/plugins.cjs +18 -18
- package/dist/cjs/interpreter/getContent/plugins.cjs.map +1 -1
- package/dist/cjs/interpreter/getIntlayer.cjs +7 -7
- package/dist/cjs/interpreter/getIntlayer.cjs.map +1 -1
- package/dist/cjs/localization/getBrowserLocale.cjs +7 -7
- package/dist/cjs/localization/getBrowserLocale.cjs.map +1 -1
- package/dist/cjs/localization/getHTMLTextDir.cjs +39 -26
- package/dist/cjs/localization/getHTMLTextDir.cjs.map +1 -1
- package/dist/cjs/localization/getLocale.cjs +8 -8
- package/dist/cjs/localization/getLocale.cjs.map +1 -1
- package/dist/cjs/localization/getLocaleFromPath.cjs +5 -5
- package/dist/cjs/localization/getLocaleFromPath.cjs.map +1 -1
- package/dist/cjs/localization/getLocalizedUrl.cjs +6 -6
- package/dist/cjs/localization/getLocalizedUrl.cjs.map +1 -1
- package/dist/cjs/localization/getMultilingualUrls.cjs +6 -6
- package/dist/cjs/localization/getMultilingualUrls.cjs.map +1 -1
- package/dist/cjs/localization/getPathWithoutLocale.cjs +3 -3
- package/dist/cjs/localization/getPathWithoutLocale.cjs.map +1 -1
- package/dist/cjs/localization/getPrefix.cjs +6 -6
- package/dist/cjs/localization/getPrefix.cjs.map +1 -1
- package/dist/cjs/localization/localeMapper.cjs +6 -6
- package/dist/cjs/localization/localeMapper.cjs.map +1 -1
- package/dist/cjs/localization/localeResolver.cjs +3 -3
- package/dist/cjs/localization/localeResolver.cjs.map +1 -1
- package/dist/cjs/localization/validatePrefix.cjs +6 -6
- package/dist/cjs/localization/validatePrefix.cjs.map +1 -1
- package/dist/cjs/messageFormat/ICU.cjs +5 -5
- package/dist/cjs/messageFormat/ICU.cjs.map +1 -1
- package/dist/cjs/messageFormat/i18next.cjs +5 -5
- package/dist/cjs/messageFormat/i18next.cjs.map +1 -1
- package/dist/cjs/messageFormat/verify-icu-format.cjs +65 -0
- package/dist/cjs/messageFormat/verify-icu-format.cjs.map +1 -0
- package/dist/cjs/messageFormat/vue-i18n.cjs +5 -5
- package/dist/cjs/messageFormat/vue-i18n.cjs.map +1 -1
- package/dist/cjs/transpiler/condition/condition.cjs +2 -2
- package/dist/cjs/transpiler/condition/condition.cjs.map +1 -1
- package/dist/cjs/transpiler/enumeration/enumeration.cjs +2 -2
- package/dist/cjs/transpiler/enumeration/enumeration.cjs.map +1 -1
- package/dist/cjs/transpiler/file/file.cjs +7 -7
- package/dist/cjs/transpiler/file/file.cjs.map +1 -1
- package/dist/cjs/transpiler/file/fileBrowser.cjs +1 -1
- package/dist/cjs/transpiler/gender/gender.cjs +2 -2
- package/dist/cjs/transpiler/gender/gender.cjs.map +1 -1
- package/dist/cjs/transpiler/insertion/insertion.cjs +2 -2
- package/dist/cjs/transpiler/insertion/insertion.cjs.map +1 -1
- package/dist/cjs/transpiler/markdown/markdown.cjs +2 -2
- package/dist/cjs/transpiler/markdown/markdown.cjs.map +1 -1
- package/dist/cjs/transpiler/nesting/nesting.cjs +2 -2
- package/dist/cjs/transpiler/nesting/nesting.cjs.map +1 -1
- package/dist/cjs/transpiler/translation/translation.cjs +2 -2
- package/dist/cjs/transpiler/translation/translation.cjs.map +1 -1
- package/dist/cjs/utils/intl.cjs +3 -3
- package/dist/cjs/utils/intl.cjs.map +1 -1
- package/dist/cjs/utils/localeStorage.cjs +5 -5
- package/dist/cjs/utils/localeStorage.cjs.map +1 -1
- package/dist/esm/localization/getHTMLTextDir.mjs +18 -5
- package/dist/esm/localization/getHTMLTextDir.mjs.map +1 -1
- package/dist/esm/messageFormat/ICU.mjs.map +1 -1
- package/dist/esm/messageFormat/verify-icu-format.mjs +65 -0
- package/dist/esm/messageFormat/verify-icu-format.mjs.map +1 -0
- package/dist/esm/utils/intl.mjs +19 -22
- package/dist/esm/utils/intl.mjs.map +1 -1
- package/dist/types/deepTransformPlugins/getFilterTranslationsOnlyContent.d.ts +8 -8
- package/dist/types/deepTransformPlugins/getFilterTranslationsOnlyContent.d.ts.map +1 -1
- package/dist/types/deepTransformPlugins/getFilteredLocalesContent.d.ts +8 -8
- package/dist/types/deepTransformPlugins/getFilteredLocalesContent.d.ts.map +1 -1
- package/dist/types/dictionaryManipulator/orderDictionaries.d.ts +2 -2
- package/dist/types/interpreter/getContent/plugins.d.ts.map +1 -1
- package/dist/types/messageFormat/ICU.d.ts.map +1 -1
- package/dist/types/messageFormat/verify-icu-format.d.ts +1 -0
- package/package.json +9 -9
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"localeMapper.cjs","names":["configuration","Locales"],"sources":["../../../src/localization/localeMapper.ts"],"sourcesContent":["import configuration from '@intlayer/config/built';\nimport { type Locale, Locales, type LocalesValues } from '@intlayer/types';\n\nexport type LocaleData = {\n locale: Locale;\n defaultLocale: Locale;\n isDefault: boolean;\n locales: Locale[];\n urlPrefix: string;\n};\n\n/**\n * Determine if the locale should be prefixed in the URL based on routing mode\n */\nconst shouldPrefixLocale = (\n locale: LocalesValues,\n defaultLocale: LocalesValues,\n mode: 'prefix-no-default' | 'prefix-all' | 'no-prefix' | 'search-params'\n): boolean => {\n if (mode === 'no-prefix' || mode === 'search-params') {\n return false;\n }\n if (mode === 'prefix-all') {\n return true;\n }\n // 'prefix-no-default'\n return locale !== defaultLocale;\n};\n\n/**\n * Map the locale data to an array of objects\n *\n * @example\n * ```ts\n * const routes = localeMap((localizedData) =>\n * ({\n * path: localizedData.urlPrefix,\n * name: localizedData.locale,\n * isDefault: localizedData.isDefault,\n * locales: localizedData.locales,\n * defaultLocale: localizedData.defaultLocale,\n * }),\n * );\n *\n * // Result\n * [\n * { path: '/', name: 'en', isDefault: true, locales: ['en'], defaultLocale: 'en', urlPrefix: '' },\n * { path: '/fr', name: 'fr', isDefault: false, locales: ['fr'], defaultLocale: 'en', urlPrefix: '/fr' },\n * { path: '/es', name: 'es', isDefault: false, locales: ['es'], defaultLocale: 'en', urlPrefix: '/es' },\n * ]\n * ```\n *\n * @param mapper - The mapper function that returns an object\n * @returns An array of objects\n */\nexport const localeMap = <T>(\n mapper: (locale: LocaleData) => T,\n locales: LocalesValues[] = configuration?.internationalization.locales ?? [],\n defaultLocale: LocalesValues = configuration?.internationalization\n .defaultLocale ?? Locales.ENGLISH,\n mode:\n | 'prefix-no-default'\n | 'prefix-all'\n | 'no-prefix'\n | 'search-params' = configuration?.routing?.mode ?? 'prefix-no-default'\n): T[] =>\n (locales ?? []).map((locale) =>\n mapper({\n locale,\n defaultLocale,\n locales,\n isDefault: locale === defaultLocale,\n urlPrefix: shouldPrefixLocale(locale, defaultLocale, mode)\n ? `/${locale}`\n : '',\n } as LocaleData)\n );\n\n/**\n * Flatten the locale map into a single array of objects\n *\n * @example\n * ```ts\n * const routes = localeMap((localizedData) =>\n * [{\n * path: localizedData.urlPrefix,\n * name: localizedData.locale,\n * isDefault: localizedData.isDefault,\n * locales: localizedData.locales,\n * defaultLocale: localizedData.defaultLocale,\n * }],\n * );\n *\n * // Result\n * [\n * path: '/', name: 'en', isDefault: true, locales: ['en'], defaultLocale: 'en', urlPrefix: '' ,\n * path: '/fr', name: 'fr', isDefault: false, locales: ['fr'], defaultLocale: 'en', urlPrefix: '/fr' ,\n * path: '/es', name: 'es', isDefault: false, locales: ['es'], defaultLocale: 'en', urlPrefix: '/es' ,\n * ]\n * ```\n *\n * @param mapper - The mapper function that returns an array of objects\n * @returns An array of objects\n */\nexport const localeFlatMap = <T>(\n mapper: (locale: LocaleData) => T[],\n locales: LocalesValues[] = configuration?.internationalization.locales ?? [],\n defaultLocale: LocalesValues = configuration?.internationalization\n .defaultLocale ?? Locales.ENGLISH,\n mode:\n | 'prefix-no-default'\n | 'prefix-all'\n | 'no-prefix'\n | 'search-params' = configuration?.routing?.mode ?? 'prefix-no-default'\n): T[] =>\n locales.flatMap((locale) =>\n mapper({\n locale,\n defaultLocale,\n locales,\n isDefault: locale === defaultLocale,\n urlPrefix: shouldPrefixLocale(locale, defaultLocale, mode)\n ? `/${locale}`\n : '',\n } as LocaleData)\n );\n\n/**\n * Creates a record object mapping locales to values transformed by the mapper function\n *\n * @example\n * ```ts\n * const translations = localeRecord(({ locale }) =>\n * require(`./translations/${locale}.json`)\n * );\n *\n * // Result\n *\n * en: ... , // Content of translations/en.json\n * fr: ... , // Content of translations/fr.json\n * es: ...\n *\n * ```\n *\n * @param mapper - Function that takes locale data and returns a value for that locale\n * @param locales - Array of locale codes to map over (defaults to configured locales)\n * @param defaultLocale - The default locale (defaults to configured default)\n * @param mode - URL routing mode for locale handling (defaults to configured value)\n * @returns Record mapping locale codes to mapped values\n */\nexport const localeRecord = <T>(\n mapper: (locale: LocaleData) => T,\n locales: LocalesValues[] = configuration?.internationalization.locales ?? [],\n defaultLocale: LocalesValues = configuration?.internationalization\n .defaultLocale ?? Locales.ENGLISH,\n mode:\n | 'prefix-no-default'\n | 'prefix-all'\n | 'no-prefix'\n | 'search-params' = configuration?.routing?.mode ?? 'prefix-no-default'\n): Record<LocalesValues, T> =>\n (locales ?? []).reduce(\n (acc, locale) => {\n acc[locale] = mapper({\n locale,\n defaultLocale,\n locales,\n isDefault: locale === defaultLocale,\n urlPrefix: shouldPrefixLocale(locale, defaultLocale, mode)\n ? `/${locale}`\n : '',\n } as LocaleData);\n return acc;\n },\n {} as Record<LocalesValues, T>\n );\n"],"mappings":";;;;;;;;;AAcA,MAAM,sBACJ,QACA,eACA,SACY;AACZ,KAAI,SAAS,eAAe,SAAS,gBACnC,QAAO;AAET,KAAI,SAAS,aACX,QAAO;AAGT,QAAO,WAAW;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA6BpB,MAAa,aACX,QACA,UAA2BA,
|
|
1
|
+
{"version":3,"file":"localeMapper.cjs","names":["configuration","Locales"],"sources":["../../../src/localization/localeMapper.ts"],"sourcesContent":["import configuration from '@intlayer/config/built';\nimport { type Locale, Locales, type LocalesValues } from '@intlayer/types';\n\nexport type LocaleData = {\n locale: Locale;\n defaultLocale: Locale;\n isDefault: boolean;\n locales: Locale[];\n urlPrefix: string;\n};\n\n/**\n * Determine if the locale should be prefixed in the URL based on routing mode\n */\nconst shouldPrefixLocale = (\n locale: LocalesValues,\n defaultLocale: LocalesValues,\n mode: 'prefix-no-default' | 'prefix-all' | 'no-prefix' | 'search-params'\n): boolean => {\n if (mode === 'no-prefix' || mode === 'search-params') {\n return false;\n }\n if (mode === 'prefix-all') {\n return true;\n }\n // 'prefix-no-default'\n return locale !== defaultLocale;\n};\n\n/**\n * Map the locale data to an array of objects\n *\n * @example\n * ```ts\n * const routes = localeMap((localizedData) =>\n * ({\n * path: localizedData.urlPrefix,\n * name: localizedData.locale,\n * isDefault: localizedData.isDefault,\n * locales: localizedData.locales,\n * defaultLocale: localizedData.defaultLocale,\n * }),\n * );\n *\n * // Result\n * [\n * { path: '/', name: 'en', isDefault: true, locales: ['en'], defaultLocale: 'en', urlPrefix: '' },\n * { path: '/fr', name: 'fr', isDefault: false, locales: ['fr'], defaultLocale: 'en', urlPrefix: '/fr' },\n * { path: '/es', name: 'es', isDefault: false, locales: ['es'], defaultLocale: 'en', urlPrefix: '/es' },\n * ]\n * ```\n *\n * @param mapper - The mapper function that returns an object\n * @returns An array of objects\n */\nexport const localeMap = <T>(\n mapper: (locale: LocaleData) => T,\n locales: LocalesValues[] = configuration?.internationalization.locales ?? [],\n defaultLocale: LocalesValues = configuration?.internationalization\n .defaultLocale ?? Locales.ENGLISH,\n mode:\n | 'prefix-no-default'\n | 'prefix-all'\n | 'no-prefix'\n | 'search-params' = configuration?.routing?.mode ?? 'prefix-no-default'\n): T[] =>\n (locales ?? []).map((locale) =>\n mapper({\n locale,\n defaultLocale,\n locales,\n isDefault: locale === defaultLocale,\n urlPrefix: shouldPrefixLocale(locale, defaultLocale, mode)\n ? `/${locale}`\n : '',\n } as LocaleData)\n );\n\n/**\n * Flatten the locale map into a single array of objects\n *\n * @example\n * ```ts\n * const routes = localeMap((localizedData) =>\n * [{\n * path: localizedData.urlPrefix,\n * name: localizedData.locale,\n * isDefault: localizedData.isDefault,\n * locales: localizedData.locales,\n * defaultLocale: localizedData.defaultLocale,\n * }],\n * );\n *\n * // Result\n * [\n * path: '/', name: 'en', isDefault: true, locales: ['en'], defaultLocale: 'en', urlPrefix: '' ,\n * path: '/fr', name: 'fr', isDefault: false, locales: ['fr'], defaultLocale: 'en', urlPrefix: '/fr' ,\n * path: '/es', name: 'es', isDefault: false, locales: ['es'], defaultLocale: 'en', urlPrefix: '/es' ,\n * ]\n * ```\n *\n * @param mapper - The mapper function that returns an array of objects\n * @returns An array of objects\n */\nexport const localeFlatMap = <T>(\n mapper: (locale: LocaleData) => T[],\n locales: LocalesValues[] = configuration?.internationalization.locales ?? [],\n defaultLocale: LocalesValues = configuration?.internationalization\n .defaultLocale ?? Locales.ENGLISH,\n mode:\n | 'prefix-no-default'\n | 'prefix-all'\n | 'no-prefix'\n | 'search-params' = configuration?.routing?.mode ?? 'prefix-no-default'\n): T[] =>\n locales.flatMap((locale) =>\n mapper({\n locale,\n defaultLocale,\n locales,\n isDefault: locale === defaultLocale,\n urlPrefix: shouldPrefixLocale(locale, defaultLocale, mode)\n ? `/${locale}`\n : '',\n } as LocaleData)\n );\n\n/**\n * Creates a record object mapping locales to values transformed by the mapper function\n *\n * @example\n * ```ts\n * const translations = localeRecord(({ locale }) =>\n * require(`./translations/${locale}.json`)\n * );\n *\n * // Result\n *\n * en: ... , // Content of translations/en.json\n * fr: ... , // Content of translations/fr.json\n * es: ...\n *\n * ```\n *\n * @param mapper - Function that takes locale data and returns a value for that locale\n * @param locales - Array of locale codes to map over (defaults to configured locales)\n * @param defaultLocale - The default locale (defaults to configured default)\n * @param mode - URL routing mode for locale handling (defaults to configured value)\n * @returns Record mapping locale codes to mapped values\n */\nexport const localeRecord = <T>(\n mapper: (locale: LocaleData) => T,\n locales: LocalesValues[] = configuration?.internationalization.locales ?? [],\n defaultLocale: LocalesValues = configuration?.internationalization\n .defaultLocale ?? Locales.ENGLISH,\n mode:\n | 'prefix-no-default'\n | 'prefix-all'\n | 'no-prefix'\n | 'search-params' = configuration?.routing?.mode ?? 'prefix-no-default'\n): Record<LocalesValues, T> =>\n (locales ?? []).reduce(\n (acc, locale) => {\n acc[locale] = mapper({\n locale,\n defaultLocale,\n locales,\n isDefault: locale === defaultLocale,\n urlPrefix: shouldPrefixLocale(locale, defaultLocale, mode)\n ? `/${locale}`\n : '',\n } as LocaleData);\n return acc;\n },\n {} as Record<LocalesValues, T>\n );\n"],"mappings":";;;;;;;;;AAcA,MAAM,sBACJ,QACA,eACA,SACY;AACZ,KAAI,SAAS,eAAe,SAAS,gBACnC,QAAO;AAET,KAAI,SAAS,aACX,QAAO;AAGT,QAAO,WAAW;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA6BpB,MAAa,aACX,QACA,UAA2BA,gCAAe,qBAAqB,WAAW,EAAE,EAC5E,gBAA+BA,gCAAe,qBAC3C,iBAAiBC,wBAAQ,SAC5B,OAIsBD,gCAAe,SAAS,QAAQ,yBAErD,WAAW,EAAE,EAAE,KAAK,WACnB,OAAO;CACL;CACA;CACA;CACA,WAAW,WAAW;CACtB,WAAW,mBAAmB,QAAQ,eAAe,KAAK,GACtD,IAAI,WACJ;CACL,CAAe,CACjB;;;;;;;;;;;;;;;;;;;;;;;;;;;AA4BH,MAAa,iBACX,QACA,UAA2BA,gCAAe,qBAAqB,WAAW,EAAE,EAC5E,gBAA+BA,gCAAe,qBAC3C,iBAAiBC,wBAAQ,SAC5B,OAIsBD,gCAAe,SAAS,QAAQ,wBAEtD,QAAQ,SAAS,WACf,OAAO;CACL;CACA;CACA;CACA,WAAW,WAAW;CACtB,WAAW,mBAAmB,QAAQ,eAAe,KAAK,GACtD,IAAI,WACJ;CACL,CAAe,CACjB;;;;;;;;;;;;;;;;;;;;;;;;AAyBH,MAAa,gBACX,QACA,UAA2BA,gCAAe,qBAAqB,WAAW,EAAE,EAC5E,gBAA+BA,gCAAe,qBAC3C,iBAAiBC,wBAAQ,SAC5B,OAIsBD,gCAAe,SAAS,QAAQ,yBAErD,WAAW,EAAE,EAAE,QACb,KAAK,WAAW;AACf,KAAI,UAAU,OAAO;EACnB;EACA;EACA;EACA,WAAW,WAAW;EACtB,WAAW,mBAAmB,QAAQ,eAAe,KAAK,GACtD,IAAI,WACJ;EACL,CAAe;AAChB,QAAO;GAET,EAAE,CACH"}
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
const require_rolldown_runtime = require('../_virtual/rolldown_runtime.cjs');
|
|
2
|
-
let
|
|
3
|
-
|
|
2
|
+
let _intlayer_config_built = require("@intlayer/config/built");
|
|
3
|
+
_intlayer_config_built = require_rolldown_runtime.__toESM(_intlayer_config_built);
|
|
4
4
|
|
|
5
5
|
//#region src/localization/localeResolver.ts
|
|
6
6
|
/**
|
|
7
7
|
* Resolves the most specific locale from a user-provided list,
|
|
8
8
|
* or falls back to the default locale if no match is found.
|
|
9
9
|
*/
|
|
10
|
-
const localeResolver = (selectedLocale, locales =
|
|
10
|
+
const localeResolver = (selectedLocale, locales = _intlayer_config_built.default?.internationalization?.locales, defaultLocale = _intlayer_config_built.default?.internationalization?.defaultLocale) => {
|
|
11
11
|
const requestedLocales = [selectedLocale].flat();
|
|
12
12
|
const normalize = (locale) => locale.trim().toLowerCase();
|
|
13
13
|
try {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"localeResolver.cjs","names":["configuration"],"sources":["../../../src/localization/localeResolver.ts"],"sourcesContent":["import configuration from '@intlayer/config/built';\nimport type { Locale, LocalesValues } from '@intlayer/types';\n\n/**\n * Resolves the most specific locale from a user-provided list,\n * or falls back to the default locale if no match is found.\n */\nexport const localeResolver = (\n selectedLocale: LocalesValues | LocalesValues[],\n locales: LocalesValues[] = configuration?.internationalization?.locales,\n defaultLocale: LocalesValues = configuration?.internationalization\n ?.defaultLocale\n): Locale => {\n // Ensure we can handle both a single locale or an array of locales uniformly\n const requestedLocales = [selectedLocale].flat();\n\n // Simple helper to normalize locale strings (e.g. \"en-US\" => \"en-us\")\n const normalize = (locale: string): string => locale.trim().toLowerCase();\n\n try {\n // Check each requested locale in order\n for (const requested of requestedLocales) {\n const normalizedRequested = normalize(requested);\n\n // 1) Attempt exact match\n const exactMatch = locales.find(\n (loc) => normalize(loc) === normalizedRequested\n );\n if (exactMatch) {\n return exactMatch as Locale;\n }\n\n // 2) Attempt partial match on language subtag\n // e.g. if requested is \"en-US\" and not found,\n // see if \"en\" is available among locales\n const [requestedLang] = normalizedRequested.split('-');\n const partialMatch = locales.find(\n (loc) => normalize(loc).split('-')[0] === requestedLang\n );\n if (partialMatch) {\n return partialMatch as Locale;\n }\n }\n } catch (_error) {\n // If anything unexpected happened, fall back to default\n }\n\n // If no match was found, return the default\n return defaultLocale as Locale;\n};\n"],"mappings":";;;;;;;;;AAOA,MAAa,kBACX,gBACA,UAA2BA,
|
|
1
|
+
{"version":3,"file":"localeResolver.cjs","names":["configuration"],"sources":["../../../src/localization/localeResolver.ts"],"sourcesContent":["import configuration from '@intlayer/config/built';\nimport type { Locale, LocalesValues } from '@intlayer/types';\n\n/**\n * Resolves the most specific locale from a user-provided list,\n * or falls back to the default locale if no match is found.\n */\nexport const localeResolver = (\n selectedLocale: LocalesValues | LocalesValues[],\n locales: LocalesValues[] = configuration?.internationalization?.locales,\n defaultLocale: LocalesValues = configuration?.internationalization\n ?.defaultLocale\n): Locale => {\n // Ensure we can handle both a single locale or an array of locales uniformly\n const requestedLocales = [selectedLocale].flat();\n\n // Simple helper to normalize locale strings (e.g. \"en-US\" => \"en-us\")\n const normalize = (locale: string): string => locale.trim().toLowerCase();\n\n try {\n // Check each requested locale in order\n for (const requested of requestedLocales) {\n const normalizedRequested = normalize(requested);\n\n // 1) Attempt exact match\n const exactMatch = locales.find(\n (loc) => normalize(loc) === normalizedRequested\n );\n if (exactMatch) {\n return exactMatch as Locale;\n }\n\n // 2) Attempt partial match on language subtag\n // e.g. if requested is \"en-US\" and not found,\n // see if \"en\" is available among locales\n const [requestedLang] = normalizedRequested.split('-');\n const partialMatch = locales.find(\n (loc) => normalize(loc).split('-')[0] === requestedLang\n );\n if (partialMatch) {\n return partialMatch as Locale;\n }\n }\n } catch (_error) {\n // If anything unexpected happened, fall back to default\n }\n\n // If no match was found, return the default\n return defaultLocale as Locale;\n};\n"],"mappings":";;;;;;;;;AAOA,MAAa,kBACX,gBACA,UAA2BA,gCAAe,sBAAsB,SAChE,gBAA+BA,gCAAe,sBAC1C,kBACO;CAEX,MAAM,mBAAmB,CAAC,eAAe,CAAC,MAAM;CAGhD,MAAM,aAAa,WAA2B,OAAO,MAAM,CAAC,aAAa;AAEzE,KAAI;AAEF,OAAK,MAAM,aAAa,kBAAkB;GACxC,MAAM,sBAAsB,UAAU,UAAU;GAGhD,MAAM,aAAa,QAAQ,MACxB,QAAQ,UAAU,IAAI,KAAK,oBAC7B;AACD,OAAI,WACF,QAAO;GAMT,MAAM,CAAC,iBAAiB,oBAAoB,MAAM,IAAI;GACtD,MAAM,eAAe,QAAQ,MAC1B,QAAQ,UAAU,IAAI,CAAC,MAAM,IAAI,CAAC,OAAO,cAC3C;AACD,OAAI,aACF,QAAO;;UAGJ,QAAQ;AAKjB,QAAO"}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
const require_rolldown_runtime = require('../_virtual/rolldown_runtime.cjs');
|
|
2
2
|
const require_localization_getPrefix = require('./getPrefix.cjs');
|
|
3
|
-
let
|
|
4
|
-
let
|
|
5
|
-
|
|
3
|
+
let _intlayer_config_client = require("@intlayer/config/client");
|
|
4
|
+
let _intlayer_config_built = require("@intlayer/config/built");
|
|
5
|
+
_intlayer_config_built = require_rolldown_runtime.__toESM(_intlayer_config_built);
|
|
6
6
|
|
|
7
7
|
//#region src/localization/validatePrefix.ts
|
|
8
8
|
/**
|
|
@@ -29,9 +29,9 @@ __intlayer_config_built = require_rolldown_runtime.__toESM(__intlayer_config_bui
|
|
|
29
29
|
*/
|
|
30
30
|
const validatePrefix = (locale, options) => {
|
|
31
31
|
const { defaultLocale, mode, locales } = {
|
|
32
|
-
defaultLocale:
|
|
33
|
-
mode:
|
|
34
|
-
locales:
|
|
32
|
+
defaultLocale: _intlayer_config_built.default?.internationalization?.defaultLocale ?? _intlayer_config_client.DefaultValues.Internationalization.DEFAULT_LOCALE,
|
|
33
|
+
mode: _intlayer_config_built.default?.routing?.mode ?? _intlayer_config_client.DefaultValues.Routing.ROUTING_MODE,
|
|
34
|
+
locales: _intlayer_config_built.default?.internationalization?.locales ?? _intlayer_config_client.DefaultValues.Internationalization.LOCALES,
|
|
35
35
|
...options
|
|
36
36
|
};
|
|
37
37
|
const { localePrefix } = require_localization_getPrefix.getPrefix(locale || defaultLocale, {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"validatePrefix.cjs","names":["configuration","DefaultValues","getPrefix"],"sources":["../../../src/localization/validatePrefix.ts"],"sourcesContent":["import configuration from '@intlayer/config/built';\nimport { DefaultValues } from '@intlayer/config/client';\nimport type { LocalesValues } from '@intlayer/types';\nimport { getPrefix } from './getPrefix';\n\nexport type ValidatePrefixResult = {\n isValid: boolean;\n localePrefix: string | undefined;\n};\n\n/**\n * Checks whether a given locale is valid based on the configured locales.\n *\n * @param locale - The locale value to validate. Can be `undefined` or `null`.\n * @param options - Optional configuration to override default settings.\n * @param options.locales - Array of valid locales. Defaults to the configured internationalization locales.\n * @param options.defaultLocale - The default locale to use as fallback. Defaults to the configured default locale.\n * @param options.mode - The routing mode (`'prefix'`, `'prefix-all'`, or `'no-prefix'`). Defaults to the configured routing mode.\n * @returns An object containing the validation result and the locale prefix.\n *\n * @example\n * // Check if 'en' is a valid locale\n * const { isValid, localePrefix } = validatePrefix('en');\n *\n * @example\n * // Check with custom options\n * const { isValid, localePrefix } = validatePrefix('fr', {\n * locales: ['en', 'fr', 'es'],\n * defaultLocale: 'en',\n * mode: 'prefix-all',\n * });\n */\nexport const validatePrefix = (\n locale: LocalesValues | undefined | null,\n options?: {\n locales?: LocalesValues[];\n defaultLocale?: LocalesValues;\n mode?: typeof configuration.routing.mode;\n }\n): ValidatePrefixResult => {\n const { defaultLocale, mode, locales } = {\n defaultLocale:\n configuration?.internationalization?.defaultLocale ??\n DefaultValues.Internationalization.DEFAULT_LOCALE,\n mode: configuration?.routing?.mode ?? DefaultValues.Routing.ROUTING_MODE,\n locales:\n configuration?.internationalization?.locales ??\n DefaultValues.Internationalization.LOCALES,\n ...options,\n };\n\n // If no locale provided (optional param), will use default\n // In `routing.mode = 'prefix-all'`, the locale is required to be a valid locale\n const { localePrefix } = getPrefix(locale || defaultLocale, {\n mode,\n locales,\n defaultLocale,\n });\n\n if (localePrefix === locale && locale === undefined) {\n return { isValid: true, localePrefix: undefined };\n }\n\n // Check if the provided locale is valid\n const isValid: boolean = locales.some((localeEl) => localeEl === locale);\n\n return { isValid: isValid, localePrefix };\n};\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAgCA,MAAa,kBACX,QACA,YAKyB;CACzB,MAAM,EAAE,eAAe,MAAM,YAAY;EACvC,eACEA,
|
|
1
|
+
{"version":3,"file":"validatePrefix.cjs","names":["configuration","DefaultValues","getPrefix"],"sources":["../../../src/localization/validatePrefix.ts"],"sourcesContent":["import configuration from '@intlayer/config/built';\nimport { DefaultValues } from '@intlayer/config/client';\nimport type { LocalesValues } from '@intlayer/types';\nimport { getPrefix } from './getPrefix';\n\nexport type ValidatePrefixResult = {\n isValid: boolean;\n localePrefix: string | undefined;\n};\n\n/**\n * Checks whether a given locale is valid based on the configured locales.\n *\n * @param locale - The locale value to validate. Can be `undefined` or `null`.\n * @param options - Optional configuration to override default settings.\n * @param options.locales - Array of valid locales. Defaults to the configured internationalization locales.\n * @param options.defaultLocale - The default locale to use as fallback. Defaults to the configured default locale.\n * @param options.mode - The routing mode (`'prefix'`, `'prefix-all'`, or `'no-prefix'`). Defaults to the configured routing mode.\n * @returns An object containing the validation result and the locale prefix.\n *\n * @example\n * // Check if 'en' is a valid locale\n * const { isValid, localePrefix } = validatePrefix('en');\n *\n * @example\n * // Check with custom options\n * const { isValid, localePrefix } = validatePrefix('fr', {\n * locales: ['en', 'fr', 'es'],\n * defaultLocale: 'en',\n * mode: 'prefix-all',\n * });\n */\nexport const validatePrefix = (\n locale: LocalesValues | undefined | null,\n options?: {\n locales?: LocalesValues[];\n defaultLocale?: LocalesValues;\n mode?: typeof configuration.routing.mode;\n }\n): ValidatePrefixResult => {\n const { defaultLocale, mode, locales } = {\n defaultLocale:\n configuration?.internationalization?.defaultLocale ??\n DefaultValues.Internationalization.DEFAULT_LOCALE,\n mode: configuration?.routing?.mode ?? DefaultValues.Routing.ROUTING_MODE,\n locales:\n configuration?.internationalization?.locales ??\n DefaultValues.Internationalization.LOCALES,\n ...options,\n };\n\n // If no locale provided (optional param), will use default\n // In `routing.mode = 'prefix-all'`, the locale is required to be a valid locale\n const { localePrefix } = getPrefix(locale || defaultLocale, {\n mode,\n locales,\n defaultLocale,\n });\n\n if (localePrefix === locale && locale === undefined) {\n return { isValid: true, localePrefix: undefined };\n }\n\n // Check if the provided locale is valid\n const isValid: boolean = locales.some((localeEl) => localeEl === locale);\n\n return { isValid: isValid, localePrefix };\n};\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAgCA,MAAa,kBACX,QACA,YAKyB;CACzB,MAAM,EAAE,eAAe,MAAM,YAAY;EACvC,eACEA,gCAAe,sBAAsB,iBACrCC,sCAAc,qBAAqB;EACrC,MAAMD,gCAAe,SAAS,QAAQC,sCAAc,QAAQ;EAC5D,SACED,gCAAe,sBAAsB,WACrCC,sCAAc,qBAAqB;EACrC,GAAG;EACJ;CAID,MAAM,EAAE,iBAAiBC,yCAAU,UAAU,eAAe;EAC1D;EACA;EACA;EACD,CAAC;AAEF,KAAI,iBAAiB,UAAU,WAAW,OACxC,QAAO;EAAE,SAAS;EAAM,cAAc;EAAW;AAMnD,QAAO;EAAE,SAFgB,QAAQ,MAAM,aAAa,aAAa,OAAO;EAE7C;EAAc"}
|
|
@@ -3,7 +3,7 @@ const require_interpreter_getContent_deepTransform = require('../interpreter/get
|
|
|
3
3
|
const require_transpiler_enumeration_enumeration = require('../transpiler/enumeration/enumeration.cjs');
|
|
4
4
|
const require_transpiler_gender_gender = require('../transpiler/gender/gender.cjs');
|
|
5
5
|
const require_transpiler_insertion_insertion = require('../transpiler/insertion/insertion.cjs');
|
|
6
|
-
let
|
|
6
|
+
let _intlayer_types = require("@intlayer/types");
|
|
7
7
|
|
|
8
8
|
//#region src/messageFormat/ICU.ts
|
|
9
9
|
const parseICU = (text) => {
|
|
@@ -195,11 +195,11 @@ const icuToIntlayerPlugin = {
|
|
|
195
195
|
}
|
|
196
196
|
};
|
|
197
197
|
const intlayerToIcuPlugin = {
|
|
198
|
-
canHandle: (node) => typeof node === "string" && (node.includes("{") || node.includes("}")) || node && typeof node === "object" && (node.nodeType ===
|
|
198
|
+
canHandle: (node) => typeof node === "string" && (node.includes("{") || node.includes("}")) || node && typeof node === "object" && (node.nodeType === _intlayer_types.NodeType.Insertion || node.nodeType === _intlayer_types.NodeType.Enumeration || node.nodeType === _intlayer_types.NodeType.Gender || node.nodeType === "composite") || Array.isArray(node),
|
|
199
199
|
transform: (node, props, next) => {
|
|
200
200
|
if (typeof node === "string") return node.replace(/\{\{([^}]+)\}\}/g, "{$1}");
|
|
201
|
-
if (node.nodeType ===
|
|
202
|
-
if (node.nodeType ===
|
|
201
|
+
if (node.nodeType === _intlayer_types.NodeType.Insertion) return node.insertion.replace(/\{\{([^}]+)\}\}/g, "{$1}");
|
|
202
|
+
if (node.nodeType === _intlayer_types.NodeType.Enumeration) {
|
|
203
203
|
const options = node.enumeration;
|
|
204
204
|
const transformedOptions = {};
|
|
205
205
|
for (const [key, val] of Object.entries(options)) {
|
|
@@ -260,7 +260,7 @@ const intlayerToIcuPlugin = {
|
|
|
260
260
|
return `{${varName}, select, ${parts.join(" ")}}`;
|
|
261
261
|
}
|
|
262
262
|
}
|
|
263
|
-
if (node.nodeType ===
|
|
263
|
+
if (node.nodeType === _intlayer_types.NodeType.Gender) {
|
|
264
264
|
const options = node.gender;
|
|
265
265
|
const varName = "gender";
|
|
266
266
|
const parts = [];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ICU.cjs","names":["nodes: ICUNode[]","options: Record<string, ICUNode[]>","insert","options: Record<string, any>","enu","gender","NodeType","transformedOptions: Record<string, string>","deepTransformNode"],"sources":["../../../src/messageFormat/ICU.ts"],"sourcesContent":["import { type Dictionary, NodeType } from '@intlayer/types';\nimport { deepTransformNode } from '../interpreter';\nimport { enu, gender, insert } from '../transpiler';\n\n// Types for our AST\ntype ICUNode =\n | string\n | {\n type: 'argument';\n name: string;\n format?: { type: string; style?: string };\n }\n | { type: 'plural'; name: string; options: Record<string, ICUNode[]> }\n | { type: 'select'; name: string; options: Record<string, ICUNode[]> };\n\nexport type JsonValue =\n | string\n | number\n | boolean\n | null\n | JsonValue[]\n | { [key: string]: JsonValue };\n\nconst parseICU = (text: string): ICUNode[] => {\n let index = 0;\n\n const parseNodes = (): ICUNode[] => {\n const nodes: ICUNode[] = [];\n let currentText = '';\n\n while (index < text.length) {\n const char = text[index];\n\n if (char === '{') {\n if (currentText) {\n nodes.push(currentText);\n currentText = '';\n }\n index++; // skip {\n nodes.push(parseArgument());\n } else if (char === '}') {\n // End of current block\n break;\n } else if (char === \"'\") {\n // Escaping\n if (index + 1 < text.length && text[index + 1] === \"'\") {\n currentText += \"'\";\n index += 2;\n } else {\n // Find next quote\n const nextQuote = text.indexOf(\"'\", index + 1);\n if (nextQuote !== -1) {\n // Determine if this is escaping syntax characters\n // For simplicity, we'll treat content between single quotes as literal\n // provided it contains syntax chars.\n // Standard ICU: ' quoted string '\n // If it is just an apostrophe, it should be doubled.\n // But simplified: take content between quotes literally.\n currentText += text.substring(index + 1, nextQuote);\n index = nextQuote + 1;\n } else {\n currentText += \"'\";\n index++;\n }\n }\n } else {\n currentText += char;\n index++;\n }\n }\n\n if (currentText) {\n nodes.push(currentText);\n }\n return nodes;\n };\n\n const parseArgument = (): ICUNode => {\n // We are past '{'\n // Parse name\n let name = '';\n while (index < text.length && /[^,}]/.test(text[index])) {\n name += text[index];\n index++;\n }\n name = name.trim();\n\n if (index >= text.length) throw new Error('Unclosed argument');\n\n if (text[index] === '}') {\n index++;\n return { type: 'argument', name };\n }\n\n // Must be comma\n if (text[index] === ',') {\n index++;\n // Parse type\n let type = '';\n while (index < text.length && /[^,}]/.test(text[index])) {\n type += text[index];\n index++;\n }\n type = type.trim();\n\n if (index >= text.length) throw new Error('Unclosed argument');\n\n if (text[index] === '}') {\n index++;\n return { type: 'argument', name, format: { type } };\n }\n\n if (text[index] === ',') {\n index++;\n\n // If plural or select, parse options\n if (type === 'plural' || type === 'select') {\n // Parse options\n const options: Record<string, ICUNode[]> = {};\n\n while (index < text.length && text[index] !== '}') {\n // skip whitespace\n while (index < text.length && /\\s/.test(text[index])) index++;\n\n // parse key\n let key = '';\n while (index < text.length && /[^{\\s]/.test(text[index])) {\n key += text[index];\n index++;\n }\n\n while (index < text.length && /\\s/.test(text[index])) index++;\n\n if (text[index] !== '{')\n throw new Error('Expected { after option key');\n index++; // skip {\n\n const value = parseNodes();\n\n if (text[index] !== '}')\n throw new Error('Expected } after option value');\n index++; // skip }\n\n options[key] = value;\n\n while (index < text.length && /\\s/.test(text[index])) index++;\n }\n\n index++; // skip closing argument }\n\n if (type === 'plural') {\n return { type: 'plural', name, options };\n } else if (type === 'select') {\n return { type: 'select', name, options };\n }\n } else {\n // Parse style for number/date/time\n let style = '';\n while (index < text.length && text[index] !== '}') {\n style += text[index];\n index++;\n }\n if (index >= text.length) throw new Error('Unclosed argument');\n\n style = style.trim();\n index++; // skip }\n\n return { type: 'argument', name, format: { type, style } };\n }\n }\n }\n\n throw new Error('Malformed argument');\n };\n\n return parseNodes();\n};\n\nconst icuNodesToIntlayer = (nodes: ICUNode[]): any => {\n if (nodes.length === 0) return '';\n if (nodes.length === 1 && typeof nodes[0] === 'string') return nodes[0];\n\n // Check if we can flatten to a single string (insert)\n const canFlatten = nodes.every(\n (node) => typeof node === 'string' || node.type === 'argument'\n );\n if (canFlatten) {\n let str = '';\n for (const node of nodes) {\n if (typeof node === 'string') {\n str += node;\n } else if (typeof node !== 'string' && node.type === 'argument') {\n if (node.format) {\n str += `{${node.name}, ${node.format.type}${\n node.format.style ? `, ${node.format.style}` : ''\n }}`;\n } else {\n str += `{{${node.name}}}`;\n }\n }\n }\n return insert(str);\n }\n\n // Mix of string and complex types.\n // If we have just one complex type and it covers everything?\n if (nodes.length === 1) {\n const node = nodes[0];\n\n if (typeof node === 'string') return node; // already handled\n if (node.type === 'argument') {\n if (node.format) {\n return insert(\n `{${node.name}, ${node.format.type}${\n node.format.style ? `, ${node.format.style}` : ''\n }}`\n );\n }\n return insert(`{{${node.name}}}`);\n }\n if (node.type === 'plural') {\n const options: Record<string, any> = {};\n\n for (const [key, val] of Object.entries(node.options)) {\n // Map ICU keys to Intlayer keys\n let newKey = key;\n if (key.startsWith('=')) {\n newKey = key.substring(1); // =0 -> 0\n } else if (key === 'one') {\n newKey = '1';\n } else if (key === 'two') {\n newKey = '2';\n } else if (key === 'few') {\n newKey = '<=3';\n } else if (key === 'many') {\n newKey = '>=4';\n } else if (key === 'other') {\n newKey = 'fallback';\n }\n // Handle # in plural value\n // For plural, we need to pass the variable name down or replace #\n // Intlayer uses {{n}} (or whatever var name)\n // We should replace # with {{n}} in the string parts of val\n const replacedVal = val.map((v) => {\n if (typeof v === 'string') {\n return v.replace(/#/g, `{{${node.name}}}`);\n }\n return v;\n });\n\n options[newKey] = icuNodesToIntlayer(replacedVal);\n }\n\n // Preserve variable name\n options.__intlayer_icu_var = node.name;\n\n return enu(options);\n }\n if (node.type === 'select') {\n const options: Record<string, any> = {};\n\n for (const [key, val] of Object.entries(node.options)) {\n options[key] = icuNodesToIntlayer(val);\n }\n\n // Check if it looks like gender\n const optionKeys = Object.keys(options);\n // It is gender if it has 'male' OR 'female' AND only contains gender keys (male, female, other)\n const isGender =\n (options.male || options.female) &&\n optionKeys.every((k) =>\n ['male', 'female', 'other', 'fallback'].includes(k)\n );\n\n if (isGender) {\n return gender({\n fallback: options.other,\n male: options.male,\n female: options.female,\n });\n }\n\n // Preserve variable name\n options.__intlayer_icu_var = node.name;\n\n return enu(options);\n }\n }\n\n // If multiple nodes, return array\n return nodes.map((node) => icuNodesToIntlayer([node]));\n};\n\nconst icuToIntlayerPlugin = {\n canHandle: (node: any) =>\n typeof node === 'string' && (node.includes('{') || node.includes('}')),\n transform: (node: any) => {\n try {\n const ast = parseICU(node);\n return icuNodesToIntlayer(ast);\n } catch {\n // If parsing fails, return original string\n return node;\n }\n },\n};\n\nconst intlayerToIcuPlugin = {\n canHandle: (node: any) =>\n (typeof node === 'string' && (node.includes('{') || node.includes('}'))) ||\n (node &&\n typeof node === 'object' &&\n (node.nodeType === NodeType.Insertion ||\n node.nodeType === NodeType.Enumeration ||\n node.nodeType === NodeType.Gender ||\n node.nodeType === 'composite')) ||\n Array.isArray(node),\n transform: (node: any, props: any, next: any) => {\n if (typeof node === 'string') {\n return node.replace(/\\{\\{([^}]+)\\}\\}/g, '{$1}');\n }\n\n if (node.nodeType === NodeType.Insertion) {\n // insert(\"Hello {{name}}\") -> \"Hello {name}\"\n return node.insertion.replace(/\\{\\{([^}]+)\\}\\}/g, '{$1}');\n }\n\n if (node.nodeType === NodeType.Enumeration) {\n const options = node.enumeration;\n\n // Transform all values first\n const transformedOptions: Record<string, string> = {};\n for (const [key, val] of Object.entries(options)) {\n if (key === '__intlayer_icu_var') continue;\n const childVal = next(val, props);\n transformedOptions[key] =\n typeof childVal === 'string' ? childVal : JSON.stringify(childVal);\n }\n\n // Infer variable name\n let varName = options.__intlayer_icu_var || 'n';\n\n if (!options.__intlayer_icu_var) {\n const fallbackVal =\n transformedOptions.fallback ||\n transformedOptions.other ||\n Object.values(transformedOptions)[0];\n // Match {variable} but avoid {variable, ...} (which are nested ICUs)\n // Actually nested ICU starts with {var, ...\n // Simple variable is {var}\n // We look for {var} that is NOT followed by ,\n const match = fallbackVal.match(/\\{([a-zA-Z0-9_]+)\\}(?!,)/);\n if (match) {\n varName = match[1];\n }\n }\n\n const keys = Object.keys(transformedOptions);\n const pluralKeys = [\n '1',\n '2',\n '<=3',\n '>=4',\n 'fallback',\n 'other',\n 'zero',\n 'one',\n 'two',\n 'few',\n 'many',\n ];\n // Also check for numbers\n const isPlural = keys.every(\n (k) => pluralKeys.includes(k) || /^[<>=]?\\d+(\\.\\d+)?$/.test(k)\n );\n\n const parts = [];\n\n if (isPlural) {\n for (const [key, val] of Object.entries(transformedOptions)) {\n let icuKey = key;\n\n if (key === 'fallback') icuKey = 'other';\n else if (key === '<=3') icuKey = 'few';\n else if (key === '>=4') icuKey = 'many';\n else if (/^\\d+$/.test(key)) icuKey = `=${key}`;\n else if (['zero', 'few', 'many'].includes(key)) icuKey = key;\n else icuKey = 'other';\n\n let strVal = val;\n\n // Replace {varName} with #\n // Note: next() has already converted {{var}} -> {var}\n strVal = strVal.replace(new RegExp(`\\\\{${varName}\\\\}`, 'g'), '#');\n\n parts.push(`${icuKey} {${strVal}}`);\n }\n\n return `{${varName}, plural, ${parts.join(' ')}}`;\n } else {\n // Select\n const entries = Object.entries(transformedOptions).sort(\n ([keyA], [keyB]) => {\n if (keyA === 'fallback' || keyA === 'other') return 1;\n if (keyB === 'fallback' || keyB === 'other') return -1;\n return 0;\n }\n );\n\n for (const [key, val] of entries) {\n let icuKey = key;\n if (key === 'fallback') icuKey = 'other';\n // Do NOT map other keys to 'other'. Keep 'active', 'inactive', etc.\n\n parts.push(`${icuKey} {${val}}`);\n }\n return `{${varName}, select, ${parts.join(' ')}}`;\n }\n }\n\n if (node.nodeType === NodeType.Gender) {\n const options = node.gender;\n const varName = 'gender';\n const parts = [];\n\n const entries = Object.entries(options).sort(([keyA], [keyB]) => {\n if (keyA === 'fallback') return 1;\n if (keyB === 'fallback') return -1;\n return 0;\n });\n\n for (const [key, val] of entries) {\n let icuKey = key;\n if (key === 'fallback') icuKey = 'other';\n\n const childVal = next(val, props);\n const strVal =\n typeof childVal === 'string' ? childVal : JSON.stringify(childVal);\n\n parts.push(`${icuKey} {${strVal}}`);\n }\n return `{${varName}, select, ${parts.join(' ')}}`;\n }\n\n if (\n Array.isArray(node) ||\n (node.nodeType === 'composite' && Array.isArray(node.composite))\n ) {\n // handle array/composite\n const arr = Array.isArray(node) ? node : node.composite;\n const items = arr.map((item: any) => next(item, props));\n return items.join('');\n }\n\n return next(node, props);\n },\n};\n\nexport const intlayerToICUFormatter = (\n message: Dictionary['content']\n): JsonValue => {\n return deepTransformNode(message, {\n dictionaryKey: 'icu',\n keyPath: [],\n plugins: [{ id: 'icu', ...intlayerToIcuPlugin }],\n });\n};\n\nexport const icuToIntlayerFormatter = (\n message: Dictionary['content']\n): JsonValue => {\n return deepTransformNode(message, {\n dictionaryKey: 'icu',\n keyPath: [],\n plugins: [{ id: 'icu', ...icuToIntlayerPlugin }],\n });\n};\n"],"mappings":";;;;;;;;AAuBA,MAAM,YAAY,SAA4B;CAC5C,IAAI,QAAQ;CAEZ,MAAM,mBAA8B;EAClC,MAAMA,QAAmB,EAAE;EAC3B,IAAI,cAAc;AAElB,SAAO,QAAQ,KAAK,QAAQ;GAC1B,MAAM,OAAO,KAAK;AAElB,OAAI,SAAS,KAAK;AAChB,QAAI,aAAa;AACf,WAAM,KAAK,YAAY;AACvB,mBAAc;;AAEhB;AACA,UAAM,KAAK,eAAe,CAAC;cAClB,SAAS,IAElB;YACS,SAAS,IAElB,KAAI,QAAQ,IAAI,KAAK,UAAU,KAAK,QAAQ,OAAO,KAAK;AACtD,mBAAe;AACf,aAAS;UACJ;IAEL,MAAM,YAAY,KAAK,QAAQ,KAAK,QAAQ,EAAE;AAC9C,QAAI,cAAc,IAAI;AAOpB,oBAAe,KAAK,UAAU,QAAQ,GAAG,UAAU;AACnD,aAAQ,YAAY;WACf;AACL,oBAAe;AACf;;;QAGC;AACL,mBAAe;AACf;;;AAIJ,MAAI,YACF,OAAM,KAAK,YAAY;AAEzB,SAAO;;CAGT,MAAM,sBAA+B;EAGnC,IAAI,OAAO;AACX,SAAO,QAAQ,KAAK,UAAU,QAAQ,KAAK,KAAK,OAAO,EAAE;AACvD,WAAQ,KAAK;AACb;;AAEF,SAAO,KAAK,MAAM;AAElB,MAAI,SAAS,KAAK,OAAQ,OAAM,IAAI,MAAM,oBAAoB;AAE9D,MAAI,KAAK,WAAW,KAAK;AACvB;AACA,UAAO;IAAE,MAAM;IAAY;IAAM;;AAInC,MAAI,KAAK,WAAW,KAAK;AACvB;GAEA,IAAI,OAAO;AACX,UAAO,QAAQ,KAAK,UAAU,QAAQ,KAAK,KAAK,OAAO,EAAE;AACvD,YAAQ,KAAK;AACb;;AAEF,UAAO,KAAK,MAAM;AAElB,OAAI,SAAS,KAAK,OAAQ,OAAM,IAAI,MAAM,oBAAoB;AAE9D,OAAI,KAAK,WAAW,KAAK;AACvB;AACA,WAAO;KAAE,MAAM;KAAY;KAAM,QAAQ,EAAE,MAAM;KAAE;;AAGrD,OAAI,KAAK,WAAW,KAAK;AACvB;AAGA,QAAI,SAAS,YAAY,SAAS,UAAU;KAE1C,MAAMC,UAAqC,EAAE;AAE7C,YAAO,QAAQ,KAAK,UAAU,KAAK,WAAW,KAAK;AAEjD,aAAO,QAAQ,KAAK,UAAU,KAAK,KAAK,KAAK,OAAO,CAAE;MAGtD,IAAI,MAAM;AACV,aAAO,QAAQ,KAAK,UAAU,SAAS,KAAK,KAAK,OAAO,EAAE;AACxD,cAAO,KAAK;AACZ;;AAGF,aAAO,QAAQ,KAAK,UAAU,KAAK,KAAK,KAAK,OAAO,CAAE;AAEtD,UAAI,KAAK,WAAW,IAClB,OAAM,IAAI,MAAM,8BAA8B;AAChD;MAEA,MAAM,QAAQ,YAAY;AAE1B,UAAI,KAAK,WAAW,IAClB,OAAM,IAAI,MAAM,gCAAgC;AAClD;AAEA,cAAQ,OAAO;AAEf,aAAO,QAAQ,KAAK,UAAU,KAAK,KAAK,KAAK,OAAO,CAAE;;AAGxD;AAEA,SAAI,SAAS,SACX,QAAO;MAAE,MAAM;MAAU;MAAM;MAAS;cAC/B,SAAS,SAClB,QAAO;MAAE,MAAM;MAAU;MAAM;MAAS;WAErC;KAEL,IAAI,QAAQ;AACZ,YAAO,QAAQ,KAAK,UAAU,KAAK,WAAW,KAAK;AACjD,eAAS,KAAK;AACd;;AAEF,SAAI,SAAS,KAAK,OAAQ,OAAM,IAAI,MAAM,oBAAoB;AAE9D,aAAQ,MAAM,MAAM;AACpB;AAEA,YAAO;MAAE,MAAM;MAAY;MAAM,QAAQ;OAAE;OAAM;OAAO;MAAE;;;;AAKhE,QAAM,IAAI,MAAM,qBAAqB;;AAGvC,QAAO,YAAY;;AAGrB,MAAM,sBAAsB,UAA0B;AACpD,KAAI,MAAM,WAAW,EAAG,QAAO;AAC/B,KAAI,MAAM,WAAW,KAAK,OAAO,MAAM,OAAO,SAAU,QAAO,MAAM;AAMrE,KAHmB,MAAM,OACtB,SAAS,OAAO,SAAS,YAAY,KAAK,SAAS,WACrD,EACe;EACd,IAAI,MAAM;AACV,OAAK,MAAM,QAAQ,MACjB,KAAI,OAAO,SAAS,SAClB,QAAO;WACE,OAAO,SAAS,YAAY,KAAK,SAAS,WACnD,KAAI,KAAK,OACP,QAAO,IAAI,KAAK,KAAK,IAAI,KAAK,OAAO,OACnC,KAAK,OAAO,QAAQ,KAAK,KAAK,OAAO,UAAU,GAChD;MAED,QAAO,KAAK,KAAK,KAAK;AAI5B,SAAOC,8CAAO,IAAI;;AAKpB,KAAI,MAAM,WAAW,GAAG;EACtB,MAAM,OAAO,MAAM;AAEnB,MAAI,OAAO,SAAS,SAAU,QAAO;AACrC,MAAI,KAAK,SAAS,YAAY;AAC5B,OAAI,KAAK,OACP,QAAOA,8CACL,IAAI,KAAK,KAAK,IAAI,KAAK,OAAO,OAC5B,KAAK,OAAO,QAAQ,KAAK,KAAK,OAAO,UAAU,GAChD,GACF;AAEH,UAAOA,8CAAO,KAAK,KAAK,KAAK,IAAI;;AAEnC,MAAI,KAAK,SAAS,UAAU;GAC1B,MAAMC,UAA+B,EAAE;AAEvC,QAAK,MAAM,CAAC,KAAK,QAAQ,OAAO,QAAQ,KAAK,QAAQ,EAAE;IAErD,IAAI,SAAS;AACb,QAAI,IAAI,WAAW,IAAI,CACrB,UAAS,IAAI,UAAU,EAAE;aAChB,QAAQ,MACjB,UAAS;aACA,QAAQ,MACjB,UAAS;aACA,QAAQ,MACjB,UAAS;aACA,QAAQ,OACjB,UAAS;aACA,QAAQ,QACjB,UAAS;AAaX,YAAQ,UAAU,mBAPE,IAAI,KAAK,MAAM;AACjC,SAAI,OAAO,MAAM,SACf,QAAO,EAAE,QAAQ,MAAM,KAAK,KAAK,KAAK,IAAI;AAE5C,YAAO;MACP,CAE+C;;AAInD,WAAQ,qBAAqB,KAAK;AAElC,UAAOC,+CAAI,QAAQ;;AAErB,MAAI,KAAK,SAAS,UAAU;GAC1B,MAAMD,UAA+B,EAAE;AAEvC,QAAK,MAAM,CAAC,KAAK,QAAQ,OAAO,QAAQ,KAAK,QAAQ,CACnD,SAAQ,OAAO,mBAAmB,IAAI;GAIxC,MAAM,aAAa,OAAO,KAAK,QAAQ;AAQvC,QALG,QAAQ,QAAQ,QAAQ,WACzB,WAAW,OAAO,MAChB;IAAC;IAAQ;IAAU;IAAS;IAAW,CAAC,SAAS,EAAE,CACpD,CAGD,QAAOE,wCAAO;IACZ,UAAU,QAAQ;IAClB,MAAM,QAAQ;IACd,QAAQ,QAAQ;IACjB,CAAC;AAIJ,WAAQ,qBAAqB,KAAK;AAElC,UAAOD,+CAAI,QAAQ;;;AAKvB,QAAO,MAAM,KAAK,SAAS,mBAAmB,CAAC,KAAK,CAAC,CAAC;;AAGxD,MAAM,sBAAsB;CAC1B,YAAY,SACV,OAAO,SAAS,aAAa,KAAK,SAAS,IAAI,IAAI,KAAK,SAAS,IAAI;CACvE,YAAY,SAAc;AACxB,MAAI;AAEF,UAAO,mBADK,SAAS,KAAK,CACI;UACxB;AAEN,UAAO;;;CAGZ;AAED,MAAM,sBAAsB;CAC1B,YAAY,SACT,OAAO,SAAS,aAAa,KAAK,SAAS,IAAI,IAAI,KAAK,SAAS,IAAI,KACrE,QACC,OAAO,SAAS,aACf,KAAK,aAAaE,0BAAS,aAC1B,KAAK,aAAaA,0BAAS,eAC3B,KAAK,aAAaA,0BAAS,UAC3B,KAAK,aAAa,gBACtB,MAAM,QAAQ,KAAK;CACrB,YAAY,MAAW,OAAY,SAAc;AAC/C,MAAI,OAAO,SAAS,SAClB,QAAO,KAAK,QAAQ,oBAAoB,OAAO;AAGjD,MAAI,KAAK,aAAaA,0BAAS,UAE7B,QAAO,KAAK,UAAU,QAAQ,oBAAoB,OAAO;AAG3D,MAAI,KAAK,aAAaA,0BAAS,aAAa;GAC1C,MAAM,UAAU,KAAK;GAGrB,MAAMC,qBAA6C,EAAE;AACrD,QAAK,MAAM,CAAC,KAAK,QAAQ,OAAO,QAAQ,QAAQ,EAAE;AAChD,QAAI,QAAQ,qBAAsB;IAClC,MAAM,WAAW,KAAK,KAAK,MAAM;AACjC,uBAAmB,OACjB,OAAO,aAAa,WAAW,WAAW,KAAK,UAAU,SAAS;;GAItE,IAAI,UAAU,QAAQ,sBAAsB;AAE5C,OAAI,CAAC,QAAQ,oBAAoB;IAS/B,MAAM,SAPJ,mBAAmB,YACnB,mBAAmB,SACnB,OAAO,OAAO,mBAAmB,CAAC,IAKV,MAAM,2BAA2B;AAC3D,QAAI,MACF,WAAU,MAAM;;GAIpB,MAAM,OAAO,OAAO,KAAK,mBAAmB;GAC5C,MAAM,aAAa;IACjB;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACD;GAED,MAAM,WAAW,KAAK,OACnB,MAAM,WAAW,SAAS,EAAE,IAAI,sBAAsB,KAAK,EAAE,CAC/D;GAED,MAAM,QAAQ,EAAE;AAEhB,OAAI,UAAU;AACZ,SAAK,MAAM,CAAC,KAAK,QAAQ,OAAO,QAAQ,mBAAmB,EAAE;KAC3D,IAAI,SAAS;AAEb,SAAI,QAAQ,WAAY,UAAS;cACxB,QAAQ,MAAO,UAAS;cACxB,QAAQ,MAAO,UAAS;cACxB,QAAQ,KAAK,IAAI,CAAE,UAAS,IAAI;cAChC;MAAC;MAAQ;MAAO;MAAO,CAAC,SAAS,IAAI,CAAE,UAAS;SACpD,UAAS;KAEd,IAAI,SAAS;AAIb,cAAS,OAAO,QAAQ,IAAI,OAAO,MAAM,QAAQ,MAAM,IAAI,EAAE,IAAI;AAEjE,WAAM,KAAK,GAAG,OAAO,IAAI,OAAO,GAAG;;AAGrC,WAAO,IAAI,QAAQ,YAAY,MAAM,KAAK,IAAI,CAAC;UAC1C;IAEL,MAAM,UAAU,OAAO,QAAQ,mBAAmB,CAAC,MAChD,CAAC,OAAO,CAAC,UAAU;AAClB,SAAI,SAAS,cAAc,SAAS,QAAS,QAAO;AACpD,SAAI,SAAS,cAAc,SAAS,QAAS,QAAO;AACpD,YAAO;MAEV;AAED,SAAK,MAAM,CAAC,KAAK,QAAQ,SAAS;KAChC,IAAI,SAAS;AACb,SAAI,QAAQ,WAAY,UAAS;AAGjC,WAAM,KAAK,GAAG,OAAO,IAAI,IAAI,GAAG;;AAElC,WAAO,IAAI,QAAQ,YAAY,MAAM,KAAK,IAAI,CAAC;;;AAInD,MAAI,KAAK,aAAaD,0BAAS,QAAQ;GACrC,MAAM,UAAU,KAAK;GACrB,MAAM,UAAU;GAChB,MAAM,QAAQ,EAAE;GAEhB,MAAM,UAAU,OAAO,QAAQ,QAAQ,CAAC,MAAM,CAAC,OAAO,CAAC,UAAU;AAC/D,QAAI,SAAS,WAAY,QAAO;AAChC,QAAI,SAAS,WAAY,QAAO;AAChC,WAAO;KACP;AAEF,QAAK,MAAM,CAAC,KAAK,QAAQ,SAAS;IAChC,IAAI,SAAS;AACb,QAAI,QAAQ,WAAY,UAAS;IAEjC,MAAM,WAAW,KAAK,KAAK,MAAM;IACjC,MAAM,SACJ,OAAO,aAAa,WAAW,WAAW,KAAK,UAAU,SAAS;AAEpE,UAAM,KAAK,GAAG,OAAO,IAAI,OAAO,GAAG;;AAErC,UAAO,IAAI,QAAQ,YAAY,MAAM,KAAK,IAAI,CAAC;;AAGjD,MACE,MAAM,QAAQ,KAAK,IAClB,KAAK,aAAa,eAAe,MAAM,QAAQ,KAAK,UAAU,CAK/D,SAFY,MAAM,QAAQ,KAAK,GAAG,OAAO,KAAK,WAC5B,KAAK,SAAc,KAAK,MAAM,MAAM,CAAC,CAC1C,KAAK,GAAG;AAGvB,SAAO,KAAK,MAAM,MAAM;;CAE3B;AAED,MAAa,0BACX,YACc;AACd,QAAOE,+DAAkB,SAAS;EAChC,eAAe;EACf,SAAS,EAAE;EACX,SAAS,CAAC;GAAE,IAAI;GAAO,GAAG;GAAqB,CAAC;EACjD,CAAC;;AAGJ,MAAa,0BACX,YACc;AACd,QAAOA,+DAAkB,SAAS;EAChC,eAAe;EACf,SAAS,EAAE;EACX,SAAS,CAAC;GAAE,IAAI;GAAO,GAAG;GAAqB,CAAC;EACjD,CAAC"}
|
|
1
|
+
{"version":3,"file":"ICU.cjs","names":["nodes: ICUNode[]","options: Record<string, ICUNode[]>","insert","options: Record<string, any>","enu","gender","NodeType","transformedOptions: Record<string, string>","deepTransformNode"],"sources":["../../../src/messageFormat/ICU.ts"],"sourcesContent":["import { type Dictionary, NodeType } from '@intlayer/types';\nimport { deepTransformNode } from '../interpreter';\nimport { enu, gender, insert } from '../transpiler';\n\n/**\n * ICU MessageFormat Converter\n *\n * This module converts between ICU MessageFormat and Intlayer's internal format.\n *\n * IMPORTANT: Two different formats are used:\n *\n * 1. ICU MessageFormat (external format):\n * - Simple variables: {name}\n * - Formatted variables: {amount, number, currency}\n * - Plural: {count, plural, =0 {none} other {# items}}\n * - Select: {gender, select, male {He} female {She} other {They}}\n *\n * 2. Intlayer Internal Format:\n * - Simple variables: {{name}} (double braces for clarity and to distinguish from literal text)\n * - Formatted variables: {amount, number, currency} (keeps ICU format)\n * - Plural: enu({ 0: 'none', fallback: '{{count}} items' })\n * - Select/Gender: gender({ male: 'He', female: 'She', fallback: 'They' })\n *\n * Conversion flow:\n * - ICU → Intlayer: {name} → {{name}}\n * - Intlayer → ICU: {{name}} → {name}\n *\n * The double braces in Intlayer format serve to:\n * - Distinguish variables from literal text containing braces\n * - Work with getInsertion() runtime function which expects {{var}} patterns\n * - Provide clear visual distinction in content dictionaries\n */\n\n// Types for our AST\ntype ICUNode =\n | string\n | {\n type: 'argument';\n name: string;\n format?: { type: string; style?: string };\n }\n | { type: 'plural'; name: string; options: Record<string, ICUNode[]> }\n | { type: 'select'; name: string; options: Record<string, ICUNode[]> };\n\nexport type JsonValue =\n | string\n | number\n | boolean\n | null\n | JsonValue[]\n | { [key: string]: JsonValue };\n\nconst parseICU = (text: string): ICUNode[] => {\n let index = 0;\n\n const parseNodes = (): ICUNode[] => {\n const nodes: ICUNode[] = [];\n let currentText = '';\n\n while (index < text.length) {\n const char = text[index];\n\n if (char === '{') {\n if (currentText) {\n nodes.push(currentText);\n currentText = '';\n }\n index++; // skip {\n nodes.push(parseArgument());\n } else if (char === '}') {\n // End of current block\n break;\n } else if (char === \"'\") {\n // Escaping\n if (index + 1 < text.length && text[index + 1] === \"'\") {\n currentText += \"'\";\n index += 2;\n } else {\n // Find next quote\n const nextQuote = text.indexOf(\"'\", index + 1);\n if (nextQuote !== -1) {\n // Determine if this is escaping syntax characters\n // For simplicity, we'll treat content between single quotes as literal\n // provided it contains syntax chars.\n // Standard ICU: ' quoted string '\n // If it is just an apostrophe, it should be doubled.\n // But simplified: take content between quotes literally.\n currentText += text.substring(index + 1, nextQuote);\n index = nextQuote + 1;\n } else {\n currentText += \"'\";\n index++;\n }\n }\n } else {\n currentText += char;\n index++;\n }\n }\n\n if (currentText) {\n nodes.push(currentText);\n }\n return nodes;\n };\n\n const parseArgument = (): ICUNode => {\n // We are past '{'\n // Parse name\n let name = '';\n while (index < text.length && /[^,}]/.test(text[index])) {\n name += text[index];\n index++;\n }\n name = name.trim();\n\n if (index >= text.length) throw new Error('Unclosed argument');\n\n if (text[index] === '}') {\n index++;\n return { type: 'argument', name };\n }\n\n // Must be comma\n if (text[index] === ',') {\n index++;\n // Parse type\n let type = '';\n while (index < text.length && /[^,}]/.test(text[index])) {\n type += text[index];\n index++;\n }\n type = type.trim();\n\n if (index >= text.length) throw new Error('Unclosed argument');\n\n if (text[index] === '}') {\n index++;\n return { type: 'argument', name, format: { type } };\n }\n\n if (text[index] === ',') {\n index++;\n\n // If plural or select, parse options\n if (type === 'plural' || type === 'select') {\n // Parse options\n const options: Record<string, ICUNode[]> = {};\n\n while (index < text.length && text[index] !== '}') {\n // skip whitespace\n while (index < text.length && /\\s/.test(text[index])) index++;\n\n // parse key\n let key = '';\n while (index < text.length && /[^{\\s]/.test(text[index])) {\n key += text[index];\n index++;\n }\n\n while (index < text.length && /\\s/.test(text[index])) index++;\n\n if (text[index] !== '{')\n throw new Error('Expected { after option key');\n index++; // skip {\n\n const value = parseNodes();\n\n if (text[index] !== '}')\n throw new Error('Expected } after option value');\n index++; // skip }\n\n options[key] = value;\n\n while (index < text.length && /\\s/.test(text[index])) index++;\n }\n\n index++; // skip closing argument }\n\n if (type === 'plural') {\n return { type: 'plural', name, options };\n } else if (type === 'select') {\n return { type: 'select', name, options };\n }\n } else {\n // Parse style for number/date/time\n let style = '';\n while (index < text.length && text[index] !== '}') {\n style += text[index];\n index++;\n }\n if (index >= text.length) throw new Error('Unclosed argument');\n\n style = style.trim();\n index++; // skip }\n\n return { type: 'argument', name, format: { type, style } };\n }\n }\n }\n\n throw new Error('Malformed argument');\n };\n\n return parseNodes();\n};\n\nconst icuNodesToIntlayer = (nodes: ICUNode[]): any => {\n if (nodes.length === 0) return '';\n if (nodes.length === 1 && typeof nodes[0] === 'string') return nodes[0];\n\n // Check if we can flatten to a single string (insert)\n const canFlatten = nodes.every(\n (node) => typeof node === 'string' || node.type === 'argument'\n );\n if (canFlatten) {\n let str = '';\n for (const node of nodes) {\n if (typeof node === 'string') {\n str += node;\n } else if (typeof node !== 'string' && node.type === 'argument') {\n if (node.format) {\n // Formatted variables keep ICU format: {var, type, style}\n str += `{${node.name}, ${node.format.type}${\n node.format.style ? `, ${node.format.style}` : ''\n }}`;\n } else {\n // Simple variables use Intlayer format: {{var}}\n str += `{{${node.name}}}`;\n }\n }\n }\n return insert(str);\n }\n\n // Mix of string and complex types.\n // If we have just one complex type and it covers everything?\n if (nodes.length === 1) {\n const node = nodes[0];\n\n if (typeof node === 'string') return node; // already handled\n if (node.type === 'argument') {\n if (node.format) {\n // Formatted variables keep ICU format: {var, type, style}\n return insert(\n `{${node.name}, ${node.format.type}${\n node.format.style ? `, ${node.format.style}` : ''\n }}`\n );\n }\n // Simple variables use Intlayer format: {{var}}\n return insert(`{{${node.name}}}`);\n }\n if (node.type === 'plural') {\n const options: Record<string, any> = {};\n\n for (const [key, val] of Object.entries(node.options)) {\n // Map ICU keys to Intlayer keys\n let newKey = key;\n if (key.startsWith('=')) {\n newKey = key.substring(1); // =0 -> 0\n } else if (key === 'one') {\n newKey = '1';\n } else if (key === 'two') {\n newKey = '2';\n } else if (key === 'few') {\n newKey = '<=3';\n } else if (key === 'many') {\n newKey = '>=4';\n } else if (key === 'other') {\n newKey = 'fallback';\n }\n // Handle # in plural value\n // For plural, we need to pass the variable name down or replace #\n // Intlayer uses {{n}} (or whatever var name) for simple variables\n // We should replace # with {{n}} in the string parts of val\n const replacedVal = val.map((v) => {\n if (typeof v === 'string') {\n return v.replace(/#/g, `{{${node.name}}}`);\n }\n return v;\n });\n\n options[newKey] = icuNodesToIntlayer(replacedVal);\n }\n\n // Preserve variable name\n options.__intlayer_icu_var = node.name;\n\n return enu(options);\n }\n if (node.type === 'select') {\n const options: Record<string, any> = {};\n\n for (const [key, val] of Object.entries(node.options)) {\n options[key] = icuNodesToIntlayer(val);\n }\n\n // Check if it looks like gender\n const optionKeys = Object.keys(options);\n // It is gender if it has 'male' OR 'female' AND only contains gender keys (male, female, other)\n const isGender =\n (options.male || options.female) &&\n optionKeys.every((k) =>\n ['male', 'female', 'other', 'fallback'].includes(k)\n );\n\n if (isGender) {\n return gender({\n fallback: options.other,\n male: options.male,\n female: options.female,\n });\n }\n\n // Preserve variable name\n options.__intlayer_icu_var = node.name;\n\n return enu(options);\n }\n }\n\n // If multiple nodes, return array\n return nodes.map((node) => icuNodesToIntlayer([node]));\n};\n\nconst icuToIntlayerPlugin = {\n canHandle: (node: any) =>\n typeof node === 'string' && (node.includes('{') || node.includes('}')),\n transform: (node: any) => {\n try {\n const ast = parseICU(node);\n return icuNodesToIntlayer(ast);\n } catch {\n // If parsing fails, return original string\n return node;\n }\n },\n};\n\nconst intlayerToIcuPlugin = {\n canHandle: (node: any) =>\n (typeof node === 'string' && (node.includes('{') || node.includes('}'))) ||\n (node &&\n typeof node === 'object' &&\n (node.nodeType === NodeType.Insertion ||\n node.nodeType === NodeType.Enumeration ||\n node.nodeType === NodeType.Gender ||\n node.nodeType === 'composite')) ||\n Array.isArray(node),\n transform: (node: any, props: any, next: any) => {\n // Convert Intlayer's double-brace format {{var}} to ICU's single-brace format {var}\n if (typeof node === 'string') {\n return node.replace(/\\{\\{([^}]+)\\}\\}/g, '{$1}');\n }\n\n if (node.nodeType === NodeType.Insertion) {\n // Convert Intlayer format to ICU format:\n // - {{name}} → {name} (simple variable)\n // - {amount, number, currency} → {amount, number, currency} (formatted variable, already in ICU format)\n return node.insertion.replace(/\\{\\{([^}]+)\\}\\}/g, '{$1}');\n }\n\n if (node.nodeType === NodeType.Enumeration) {\n const options = node.enumeration;\n\n // Transform all values first\n const transformedOptions: Record<string, string> = {};\n for (const [key, val] of Object.entries(options)) {\n if (key === '__intlayer_icu_var') continue;\n const childVal = next(val, props);\n transformedOptions[key] =\n typeof childVal === 'string' ? childVal : JSON.stringify(childVal);\n }\n\n // Infer variable name\n let varName = options.__intlayer_icu_var || 'n';\n\n if (!options.__intlayer_icu_var) {\n const fallbackVal =\n transformedOptions.fallback ||\n transformedOptions.other ||\n Object.values(transformedOptions)[0];\n // Match {variable} but avoid {variable, ...} (which are nested ICUs)\n // Actually nested ICU starts with {var, ...\n // Simple variable is {var}\n // We look for {var} that is NOT followed by ,\n const match = fallbackVal.match(/\\{([a-zA-Z0-9_]+)\\}(?!,)/);\n if (match) {\n varName = match[1];\n }\n }\n\n const keys = Object.keys(transformedOptions);\n const pluralKeys = [\n '1',\n '2',\n '<=3',\n '>=4',\n 'fallback',\n 'other',\n 'zero',\n 'one',\n 'two',\n 'few',\n 'many',\n ];\n // Also check for numbers\n const isPlural = keys.every(\n (k) => pluralKeys.includes(k) || /^[<>=]?\\d+(\\.\\d+)?$/.test(k)\n );\n\n const parts = [];\n\n if (isPlural) {\n for (const [key, val] of Object.entries(transformedOptions)) {\n let icuKey = key;\n\n if (key === 'fallback') icuKey = 'other';\n else if (key === '<=3') icuKey = 'few';\n else if (key === '>=4') icuKey = 'many';\n else if (/^\\d+$/.test(key)) icuKey = `=${key}`;\n else if (['zero', 'few', 'many'].includes(key)) icuKey = key;\n else icuKey = 'other';\n\n let strVal = val;\n\n // Replace {varName} with #\n // Note: next() has already converted {{var}} -> {var}\n strVal = strVal.replace(new RegExp(`\\\\{${varName}\\\\}`, 'g'), '#');\n\n parts.push(`${icuKey} {${strVal}}`);\n }\n\n return `{${varName}, plural, ${parts.join(' ')}}`;\n } else {\n // Select\n const entries = Object.entries(transformedOptions).sort(\n ([keyA], [keyB]) => {\n if (keyA === 'fallback' || keyA === 'other') return 1;\n if (keyB === 'fallback' || keyB === 'other') return -1;\n return 0;\n }\n );\n\n for (const [key, val] of entries) {\n let icuKey = key;\n if (key === 'fallback') icuKey = 'other';\n // Do NOT map other keys to 'other'. Keep 'active', 'inactive', etc.\n\n parts.push(`${icuKey} {${val}}`);\n }\n return `{${varName}, select, ${parts.join(' ')}}`;\n }\n }\n\n if (node.nodeType === NodeType.Gender) {\n const options = node.gender;\n const varName = 'gender';\n const parts = [];\n\n const entries = Object.entries(options).sort(([keyA], [keyB]) => {\n if (keyA === 'fallback') return 1;\n if (keyB === 'fallback') return -1;\n return 0;\n });\n\n for (const [key, val] of entries) {\n let icuKey = key;\n if (key === 'fallback') icuKey = 'other';\n\n const childVal = next(val, props);\n const strVal =\n typeof childVal === 'string' ? childVal : JSON.stringify(childVal);\n\n parts.push(`${icuKey} {${strVal}}`);\n }\n return `{${varName}, select, ${parts.join(' ')}}`;\n }\n\n if (\n Array.isArray(node) ||\n (node.nodeType === 'composite' && Array.isArray(node.composite))\n ) {\n // handle array/composite\n const arr = Array.isArray(node) ? node : node.composite;\n const items = arr.map((item: any) => next(item, props));\n return items.join('');\n }\n\n return next(node, props);\n },\n};\n\nexport const intlayerToICUFormatter = (\n message: Dictionary['content']\n): JsonValue => {\n return deepTransformNode(message, {\n dictionaryKey: 'icu',\n keyPath: [],\n plugins: [{ id: 'icu', ...intlayerToIcuPlugin }],\n });\n};\n\nexport const icuToIntlayerFormatter = (\n message: Dictionary['content']\n): JsonValue => {\n return deepTransformNode(message, {\n dictionaryKey: 'icu',\n keyPath: [],\n plugins: [{ id: 'icu', ...icuToIntlayerPlugin }],\n });\n};\n"],"mappings":"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"}
|
|
@@ -3,7 +3,7 @@ const require_interpreter_getContent_deepTransform = require('../interpreter/get
|
|
|
3
3
|
const require_transpiler_enumeration_enumeration = require('../transpiler/enumeration/enumeration.cjs');
|
|
4
4
|
const require_transpiler_gender_gender = require('../transpiler/gender/gender.cjs');
|
|
5
5
|
const require_transpiler_insertion_insertion = require('../transpiler/insertion/insertion.cjs');
|
|
6
|
-
let
|
|
6
|
+
let _intlayer_types = require("@intlayer/types");
|
|
7
7
|
|
|
8
8
|
//#region src/messageFormat/i18next.ts
|
|
9
9
|
const parseI18Next = (text) => {
|
|
@@ -204,14 +204,14 @@ const i18nextToIntlayerPlugin = {
|
|
|
204
204
|
}
|
|
205
205
|
};
|
|
206
206
|
const intlayerToI18nextPlugin = {
|
|
207
|
-
canHandle: (node) => typeof node === "string" || node && typeof node === "object" && (node.nodeType ===
|
|
207
|
+
canHandle: (node) => typeof node === "string" || node && typeof node === "object" && (node.nodeType === _intlayer_types.NodeType.Insertion || node.nodeType === _intlayer_types.NodeType.Enumeration || node.nodeType === _intlayer_types.NodeType.Gender || node.nodeType === "composite") || Array.isArray(node),
|
|
208
208
|
transform: (node, props, next) => {
|
|
209
209
|
if (typeof node === "string") return node;
|
|
210
|
-
if (node.nodeType ===
|
|
210
|
+
if (node.nodeType === _intlayer_types.NodeType.Insertion) {
|
|
211
211
|
if (node.insertion.match(/\{[^}]*,[^}]*\}/)) return node.insertion;
|
|
212
212
|
return node.insertion;
|
|
213
213
|
}
|
|
214
|
-
if (node.nodeType ===
|
|
214
|
+
if (node.nodeType === _intlayer_types.NodeType.Enumeration) {
|
|
215
215
|
const options = node.enumeration;
|
|
216
216
|
const transformedOptions = {};
|
|
217
217
|
for (const [key, val] of Object.entries(options)) {
|
|
@@ -270,7 +270,7 @@ const intlayerToI18nextPlugin = {
|
|
|
270
270
|
return `{${varName}, select, ${parts.join(" ")}}`;
|
|
271
271
|
}
|
|
272
272
|
}
|
|
273
|
-
if (node.nodeType ===
|
|
273
|
+
if (node.nodeType === _intlayer_types.NodeType.Gender) {
|
|
274
274
|
const options = node.gender;
|
|
275
275
|
const varName = "gender";
|
|
276
276
|
const parts = [];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"i18next.cjs","names":["nodes: I18NextNode[]","options: Record<string, I18NextNode[]>","insert","options: Record<string, any>","enu","gender","NodeType","transformedOptions: Record<string, string>","deepTransformNode"],"sources":["../../../src/messageFormat/i18next.ts"],"sourcesContent":["import type { Dictionary } from '@intlayer/types';\nimport { NodeType } from '@intlayer/types';\nimport { deepTransformNode } from '../interpreter';\nimport { enu, gender, insert } from '../transpiler';\nimport type { JsonValue } from './ICU';\n\n// Types for our AST\ntype I18NextNode =\n | string\n | {\n type: 'argument';\n name: string;\n format?: { type: string; style?: string };\n }\n | { type: 'plural'; name: string; options: Record<string, I18NextNode[]> }\n | { type: 'select'; name: string; options: Record<string, I18NextNode[]> };\n\nconst parseI18Next = (text: string): I18NextNode[] => {\n let index = 0;\n\n const parseNodes = (): I18NextNode[] => {\n const nodes: I18NextNode[] = [];\n let currentText = '';\n\n while (index < text.length) {\n const char = text[index];\n\n // Standard i18next variable: {{var}}\n if (char === '{' && text[index + 1] === '{') {\n if (currentText) {\n nodes.push(currentText);\n currentText = '';\n }\n index += 2; // skip {{\n nodes.push(parseStandardArgument());\n }\n // ICU syntax: {var} or {var, plural, ...}\n else if (char === '{') {\n if (currentText) {\n nodes.push(currentText);\n currentText = '';\n }\n index++; // skip {\n nodes.push(parseICUArgument());\n } else if (char === '}') {\n // End of current block (likely ICU block end)\n break;\n } else {\n currentText += char;\n index++;\n }\n }\n\n if (currentText) {\n nodes.push(currentText);\n }\n return nodes;\n };\n\n const parseStandardArgument = (): I18NextNode => {\n // We are past '{{'\n let name = '';\n while (index < text.length) {\n // Check for closing }}\n if (text[index] === '}' && text[index + 1] === '}') {\n index += 2; // skip }}\n return { type: 'argument', name: name.trim() };\n }\n name += text[index];\n index++;\n }\n throw new Error('Unclosed i18next variable');\n };\n\n const parseICUArgument = (): I18NextNode => {\n // We are past '{'\n let name = '';\n while (index < text.length && /[^,}]/.test(text[index])) {\n name += text[index];\n index++;\n }\n name = name.trim();\n\n if (index >= text.length) throw new Error('Unclosed argument');\n\n if (text[index] === '}') {\n index++;\n return { type: 'argument', name };\n }\n\n // Must be comma\n if (text[index] === ',') {\n index++;\n // Parse type\n let type = '';\n while (index < text.length && /[^,}]/.test(text[index])) {\n type += text[index];\n index++;\n }\n type = type.trim();\n\n if (index >= text.length) throw new Error('Unclosed argument');\n\n if (text[index] === '}') {\n index++;\n return { type: 'argument', name, format: { type } };\n }\n\n if (text[index] === ',') {\n index++;\n\n // If plural or select, parse options\n if (type === 'plural' || type === 'select') {\n const options: Record<string, I18NextNode[]> = {};\n\n while (index < text.length && text[index] !== '}') {\n while (index < text.length && /\\s/.test(text[index])) index++;\n\n let key = '';\n while (index < text.length && /[^{\\s]/.test(text[index])) {\n key += text[index];\n index++;\n }\n\n while (index < text.length && /\\s/.test(text[index])) index++;\n\n if (text[index] !== '{')\n throw new Error('Expected { after option key');\n index++; // skip {\n\n const value = parseNodes();\n\n if (text[index] !== '}')\n throw new Error('Expected } after option value');\n index++; // skip }\n\n options[key] = value;\n\n while (index < text.length && /\\s/.test(text[index])) index++;\n }\n\n index++; // skip closing argument }\n\n if (type === 'plural') {\n return { type: 'plural', name, options };\n } else if (type === 'select') {\n return { type: 'select', name, options };\n }\n } else {\n // Parse style for number/date/time\n let style = '';\n while (index < text.length && text[index] !== '}') {\n style += text[index];\n index++;\n }\n if (index >= text.length) throw new Error('Unclosed argument');\n\n style = style.trim();\n index++; // skip }\n\n return { type: 'argument', name, format: { type, style } };\n }\n }\n }\n\n throw new Error('Malformed argument');\n };\n\n return parseNodes();\n};\n\nconst i18nextNodesToIntlayer = (nodes: I18NextNode[]): any => {\n if (nodes.length === 0) return '';\n if (nodes.length === 1 && typeof nodes[0] === 'string') return nodes[0];\n\n const canFlatten = nodes.every(\n (node) => typeof node === 'string' || node.type === 'argument'\n );\n\n if (canFlatten) {\n let str = '';\n for (const node of nodes) {\n if (typeof node === 'string') {\n str += node;\n } else if (typeof node !== 'string' && node.type === 'argument') {\n if (node.format) {\n // For formatted arguments, use ICU syntax: {name, type, style}\n str += `{${node.name}, ${node.format.type}${\n node.format.style ? `, ${node.format.style}` : ''\n }}`;\n } else {\n // For simple arguments, use standard i18next: {{name}}\n str += `{{${node.name}}}`;\n }\n }\n }\n return insert(str);\n }\n\n if (nodes.length === 1) {\n const node = nodes[0];\n if (typeof node === 'string') return node;\n\n if (node.type === 'argument') {\n if (node.format) {\n return insert(\n `{${node.name}, ${node.format.type}${\n node.format.style ? `, ${node.format.style}` : ''\n }}`\n );\n }\n return insert(`{{${node.name}}}`);\n }\n\n if (node.type === 'plural') {\n const options: Record<string, any> = {};\n for (const [key, val] of Object.entries(node.options)) {\n let newKey = key;\n if (key.startsWith('=')) {\n newKey = key.substring(1);\n } else if (key === 'one') {\n newKey = '1';\n } else if (key === 'two') {\n newKey = '2';\n } else if (key === 'few') {\n newKey = '<=3';\n } else if (key === 'many') {\n newKey = '>=4';\n } else if (key === 'other') {\n newKey = 'fallback';\n }\n // Handle # replacement\n const replacedVal = val.map((v) => {\n if (typeof v === 'string') {\n // In ICU plural, # is replaced by the number\n // In i18next, if using ICU plugin, it behaves same.\n // We map it to {{varName}} in Intlayer\n return v.replace(/#/g, `{{${node.name}}}`);\n }\n return v;\n });\n\n options[newKey] = i18nextNodesToIntlayer(replacedVal);\n }\n\n // Preserve variable name\n options.__intlayer_icu_var = node.name;\n\n return enu(options);\n }\n\n if (node.type === 'select') {\n const options: Record<string, any> = {};\n for (const [key, val] of Object.entries(node.options)) {\n options[key] = i18nextNodesToIntlayer(val);\n }\n\n // Check for gender\n const optionKeys = Object.keys(options);\n const isGender =\n (options.male || options.female) &&\n optionKeys.every((k) =>\n ['male', 'female', 'other', 'fallback'].includes(k)\n );\n\n if (isGender) {\n return gender({\n fallback: options.other,\n male: options.male,\n female: options.female,\n });\n }\n\n // Preserve variable name for generic select\n options.__intlayer_icu_var = node.name;\n\n return enu(options);\n }\n }\n\n return nodes.map((node) => i18nextNodesToIntlayer([node]));\n};\n\nconst i18nextToIntlayerPlugin = {\n canHandle: (node: any) =>\n typeof node === 'string' && (node.includes('{') || node.includes('}')),\n transform: (node: any) => {\n try {\n const ast = parseI18Next(node);\n return i18nextNodesToIntlayer(ast);\n } catch {\n return node;\n }\n },\n};\n\nconst intlayerToI18nextPlugin = {\n canHandle: (node: any) =>\n typeof node === 'string' ||\n (node &&\n typeof node === 'object' &&\n (node.nodeType === NodeType.Insertion ||\n node.nodeType === NodeType.Enumeration ||\n node.nodeType === NodeType.Gender ||\n node.nodeType === 'composite')) ||\n Array.isArray(node),\n transform: (node: any, props: any, next: any) => {\n if (typeof node === 'string') {\n return node;\n }\n\n if (node.nodeType === NodeType.Insertion) {\n // If it contains ICU format syntax (curly braces but not double curly), keep it as is\n // But standard insert creates {{var}}.\n // Check if the original string was formatted (e.g. {val, number})\n if (node.insertion.match(/\\{[^}]*,[^}]*\\}/)) {\n // It's likely an ICU format string like {val, number}\n // We might need to ensure variables inside are not double-braced if they are part of the format\n // But wait, our parser outputs {val, number} as string for insertion.\n return node.insertion;\n }\n\n // Otherwise keep {{name}} for i18next\n return node.insertion;\n }\n\n if (node.nodeType === NodeType.Enumeration) {\n const options = node.enumeration;\n\n const transformedOptions: Record<string, string> = {};\n for (const [key, val] of Object.entries(options)) {\n if (key === '__intlayer_icu_var') continue;\n const childVal = next(val, props);\n transformedOptions[key] =\n typeof childVal === 'string' ? childVal : JSON.stringify(childVal);\n }\n\n // Infer variable name\n let varName = options.__intlayer_icu_var || 'count';\n\n if (!options.__intlayer_icu_var) {\n const fallbackVal =\n transformedOptions.fallback ||\n transformedOptions.other ||\n Object.values(transformedOptions)[0];\n\n // Search for {{var}} or {var}\n // Match {variable} but avoid {variable, ...} (which are nested ICUs)\n const match =\n fallbackVal.match(/\\{\\{([a-zA-Z0-9_]+)\\}\\}/) ||\n fallbackVal.match(/\\{([a-zA-Z0-9_]+)\\}(?!,)/);\n if (match) {\n varName = match[1];\n }\n }\n\n const keys = Object.keys(transformedOptions);\n const pluralKeys = [\n '1',\n '2',\n '<=3',\n '>=4',\n 'fallback',\n 'other',\n 'zero',\n 'one',\n 'two',\n 'few',\n 'many',\n ];\n // Check if it is a plural\n const isPlural = keys.every(\n (k) => pluralKeys.includes(k) || /^[<>=]?\\d+(\\.\\d+)?$/.test(k)\n );\n\n const parts = [];\n\n if (isPlural) {\n for (const [key, val] of Object.entries(transformedOptions)) {\n let icuKey = key;\n if (key === 'fallback') icuKey = 'other';\n else if (key === '<=3') icuKey = 'few';\n else if (key === '>=4') icuKey = 'many';\n else if (/^\\d+$/.test(key)) icuKey = `=${key}`;\n\n let strVal = val;\n\n // Convert {{var}} to {var} inside ICU string\n // Also replace {varName} with # if it matches\n strVal = strVal.replace(/\\{\\{([^}]+)\\}\\}/g, '{$1}');\n strVal = strVal.replace(new RegExp(`\\\\{${varName}\\\\}`, 'g'), '#');\n\n parts.push(`${icuKey} {${strVal}}`);\n }\n return `{${varName}, plural, ${parts.join(' ')}}`;\n } else {\n // Select\n const entries = Object.entries(transformedOptions).sort(\n ([keyA], [keyB]) => {\n if (keyA === 'fallback' || keyA === 'other') return 1;\n if (keyB === 'fallback' || keyB === 'other') return -1;\n return 0;\n }\n );\n\n for (const [key, val] of entries) {\n let icuKey = key;\n if (key === 'fallback') icuKey = 'other';\n\n let strVal = val;\n strVal = strVal.replace(/\\{\\{([^}]+)\\}\\}/g, '{$1}');\n\n parts.push(`${icuKey} {${strVal}}`);\n }\n return `{${varName}, select, ${parts.join(' ')}}`;\n }\n }\n\n if (node.nodeType === NodeType.Gender) {\n const options = node.gender;\n const varName = 'gender';\n const parts = [];\n\n const entries = Object.entries(options).sort(([keyA], [keyB]) => {\n if (keyA === 'fallback') return 1;\n if (keyB === 'fallback') return -1;\n return 0;\n });\n\n for (const [key, val] of entries) {\n let icuKey = key;\n if (key === 'fallback') icuKey = 'other';\n\n const childVal = next(val, props);\n let strVal =\n typeof childVal === 'string' ? childVal : JSON.stringify(childVal);\n\n strVal = strVal.replace(/\\{\\{([^}]+)\\}\\}/g, '{$1}');\n parts.push(`${icuKey} {${strVal}}`);\n }\n return `{${varName}, select, ${parts.join(' ')}}`;\n }\n\n if (\n Array.isArray(node) ||\n (node.nodeType === 'composite' && Array.isArray(node.composite))\n ) {\n const arr = Array.isArray(node) ? node : node.composite;\n const items = arr.map((item: any) => next(item, props));\n return items.join('');\n }\n\n return next(node, props);\n },\n};\n\nexport const intlayerToI18nextFormatter = (\n message: Dictionary['content']\n): JsonValue => {\n return deepTransformNode(message, {\n dictionaryKey: 'i18next',\n keyPath: [],\n plugins: [{ id: 'i18next', ...intlayerToI18nextPlugin }],\n });\n};\n\nexport const i18nextToIntlayerFormatter = (\n message: JsonValue\n): Dictionary['content'] => {\n return deepTransformNode(message, {\n dictionaryKey: 'i18next',\n keyPath: [],\n plugins: [{ id: 'i18next', ...i18nextToIntlayerPlugin }],\n });\n};\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"i18next.cjs","names":["nodes: I18NextNode[]","options: Record<string, I18NextNode[]>","insert","options: Record<string, any>","enu","gender","NodeType","transformedOptions: Record<string, string>","deepTransformNode"],"sources":["../../../src/messageFormat/i18next.ts"],"sourcesContent":["import type { Dictionary } from '@intlayer/types';\nimport { NodeType } from '@intlayer/types';\nimport { deepTransformNode } from '../interpreter';\nimport { enu, gender, insert } from '../transpiler';\nimport type { JsonValue } from './ICU';\n\n// Types for our AST\ntype I18NextNode =\n | string\n | {\n type: 'argument';\n name: string;\n format?: { type: string; style?: string };\n }\n | { type: 'plural'; name: string; options: Record<string, I18NextNode[]> }\n | { type: 'select'; name: string; options: Record<string, I18NextNode[]> };\n\nconst parseI18Next = (text: string): I18NextNode[] => {\n let index = 0;\n\n const parseNodes = (): I18NextNode[] => {\n const nodes: I18NextNode[] = [];\n let currentText = '';\n\n while (index < text.length) {\n const char = text[index];\n\n // Standard i18next variable: {{var}}\n if (char === '{' && text[index + 1] === '{') {\n if (currentText) {\n nodes.push(currentText);\n currentText = '';\n }\n index += 2; // skip {{\n nodes.push(parseStandardArgument());\n }\n // ICU syntax: {var} or {var, plural, ...}\n else if (char === '{') {\n if (currentText) {\n nodes.push(currentText);\n currentText = '';\n }\n index++; // skip {\n nodes.push(parseICUArgument());\n } else if (char === '}') {\n // End of current block (likely ICU block end)\n break;\n } else {\n currentText += char;\n index++;\n }\n }\n\n if (currentText) {\n nodes.push(currentText);\n }\n return nodes;\n };\n\n const parseStandardArgument = (): I18NextNode => {\n // We are past '{{'\n let name = '';\n while (index < text.length) {\n // Check for closing }}\n if (text[index] === '}' && text[index + 1] === '}') {\n index += 2; // skip }}\n return { type: 'argument', name: name.trim() };\n }\n name += text[index];\n index++;\n }\n throw new Error('Unclosed i18next variable');\n };\n\n const parseICUArgument = (): I18NextNode => {\n // We are past '{'\n let name = '';\n while (index < text.length && /[^,}]/.test(text[index])) {\n name += text[index];\n index++;\n }\n name = name.trim();\n\n if (index >= text.length) throw new Error('Unclosed argument');\n\n if (text[index] === '}') {\n index++;\n return { type: 'argument', name };\n }\n\n // Must be comma\n if (text[index] === ',') {\n index++;\n // Parse type\n let type = '';\n while (index < text.length && /[^,}]/.test(text[index])) {\n type += text[index];\n index++;\n }\n type = type.trim();\n\n if (index >= text.length) throw new Error('Unclosed argument');\n\n if (text[index] === '}') {\n index++;\n return { type: 'argument', name, format: { type } };\n }\n\n if (text[index] === ',') {\n index++;\n\n // If plural or select, parse options\n if (type === 'plural' || type === 'select') {\n const options: Record<string, I18NextNode[]> = {};\n\n while (index < text.length && text[index] !== '}') {\n while (index < text.length && /\\s/.test(text[index])) index++;\n\n let key = '';\n while (index < text.length && /[^{\\s]/.test(text[index])) {\n key += text[index];\n index++;\n }\n\n while (index < text.length && /\\s/.test(text[index])) index++;\n\n if (text[index] !== '{')\n throw new Error('Expected { after option key');\n index++; // skip {\n\n const value = parseNodes();\n\n if (text[index] !== '}')\n throw new Error('Expected } after option value');\n index++; // skip }\n\n options[key] = value;\n\n while (index < text.length && /\\s/.test(text[index])) index++;\n }\n\n index++; // skip closing argument }\n\n if (type === 'plural') {\n return { type: 'plural', name, options };\n } else if (type === 'select') {\n return { type: 'select', name, options };\n }\n } else {\n // Parse style for number/date/time\n let style = '';\n while (index < text.length && text[index] !== '}') {\n style += text[index];\n index++;\n }\n if (index >= text.length) throw new Error('Unclosed argument');\n\n style = style.trim();\n index++; // skip }\n\n return { type: 'argument', name, format: { type, style } };\n }\n }\n }\n\n throw new Error('Malformed argument');\n };\n\n return parseNodes();\n};\n\nconst i18nextNodesToIntlayer = (nodes: I18NextNode[]): any => {\n if (nodes.length === 0) return '';\n if (nodes.length === 1 && typeof nodes[0] === 'string') return nodes[0];\n\n const canFlatten = nodes.every(\n (node) => typeof node === 'string' || node.type === 'argument'\n );\n\n if (canFlatten) {\n let str = '';\n for (const node of nodes) {\n if (typeof node === 'string') {\n str += node;\n } else if (typeof node !== 'string' && node.type === 'argument') {\n if (node.format) {\n // For formatted arguments, use ICU syntax: {name, type, style}\n str += `{${node.name}, ${node.format.type}${\n node.format.style ? `, ${node.format.style}` : ''\n }}`;\n } else {\n // For simple arguments, use standard i18next: {{name}}\n str += `{{${node.name}}}`;\n }\n }\n }\n return insert(str);\n }\n\n if (nodes.length === 1) {\n const node = nodes[0];\n if (typeof node === 'string') return node;\n\n if (node.type === 'argument') {\n if (node.format) {\n return insert(\n `{${node.name}, ${node.format.type}${\n node.format.style ? `, ${node.format.style}` : ''\n }}`\n );\n }\n return insert(`{{${node.name}}}`);\n }\n\n if (node.type === 'plural') {\n const options: Record<string, any> = {};\n for (const [key, val] of Object.entries(node.options)) {\n let newKey = key;\n if (key.startsWith('=')) {\n newKey = key.substring(1);\n } else if (key === 'one') {\n newKey = '1';\n } else if (key === 'two') {\n newKey = '2';\n } else if (key === 'few') {\n newKey = '<=3';\n } else if (key === 'many') {\n newKey = '>=4';\n } else if (key === 'other') {\n newKey = 'fallback';\n }\n // Handle # replacement\n const replacedVal = val.map((v) => {\n if (typeof v === 'string') {\n // In ICU plural, # is replaced by the number\n // In i18next, if using ICU plugin, it behaves same.\n // We map it to {{varName}} in Intlayer\n return v.replace(/#/g, `{{${node.name}}}`);\n }\n return v;\n });\n\n options[newKey] = i18nextNodesToIntlayer(replacedVal);\n }\n\n // Preserve variable name\n options.__intlayer_icu_var = node.name;\n\n return enu(options);\n }\n\n if (node.type === 'select') {\n const options: Record<string, any> = {};\n for (const [key, val] of Object.entries(node.options)) {\n options[key] = i18nextNodesToIntlayer(val);\n }\n\n // Check for gender\n const optionKeys = Object.keys(options);\n const isGender =\n (options.male || options.female) &&\n optionKeys.every((k) =>\n ['male', 'female', 'other', 'fallback'].includes(k)\n );\n\n if (isGender) {\n return gender({\n fallback: options.other,\n male: options.male,\n female: options.female,\n });\n }\n\n // Preserve variable name for generic select\n options.__intlayer_icu_var = node.name;\n\n return enu(options);\n }\n }\n\n return nodes.map((node) => i18nextNodesToIntlayer([node]));\n};\n\nconst i18nextToIntlayerPlugin = {\n canHandle: (node: any) =>\n typeof node === 'string' && (node.includes('{') || node.includes('}')),\n transform: (node: any) => {\n try {\n const ast = parseI18Next(node);\n return i18nextNodesToIntlayer(ast);\n } catch {\n return node;\n }\n },\n};\n\nconst intlayerToI18nextPlugin = {\n canHandle: (node: any) =>\n typeof node === 'string' ||\n (node &&\n typeof node === 'object' &&\n (node.nodeType === NodeType.Insertion ||\n node.nodeType === NodeType.Enumeration ||\n node.nodeType === NodeType.Gender ||\n node.nodeType === 'composite')) ||\n Array.isArray(node),\n transform: (node: any, props: any, next: any) => {\n if (typeof node === 'string') {\n return node;\n }\n\n if (node.nodeType === NodeType.Insertion) {\n // If it contains ICU format syntax (curly braces but not double curly), keep it as is\n // But standard insert creates {{var}}.\n // Check if the original string was formatted (e.g. {val, number})\n if (node.insertion.match(/\\{[^}]*,[^}]*\\}/)) {\n // It's likely an ICU format string like {val, number}\n // We might need to ensure variables inside are not double-braced if they are part of the format\n // But wait, our parser outputs {val, number} as string for insertion.\n return node.insertion;\n }\n\n // Otherwise keep {{name}} for i18next\n return node.insertion;\n }\n\n if (node.nodeType === NodeType.Enumeration) {\n const options = node.enumeration;\n\n const transformedOptions: Record<string, string> = {};\n for (const [key, val] of Object.entries(options)) {\n if (key === '__intlayer_icu_var') continue;\n const childVal = next(val, props);\n transformedOptions[key] =\n typeof childVal === 'string' ? childVal : JSON.stringify(childVal);\n }\n\n // Infer variable name\n let varName = options.__intlayer_icu_var || 'count';\n\n if (!options.__intlayer_icu_var) {\n const fallbackVal =\n transformedOptions.fallback ||\n transformedOptions.other ||\n Object.values(transformedOptions)[0];\n\n // Search for {{var}} or {var}\n // Match {variable} but avoid {variable, ...} (which are nested ICUs)\n const match =\n fallbackVal.match(/\\{\\{([a-zA-Z0-9_]+)\\}\\}/) ||\n fallbackVal.match(/\\{([a-zA-Z0-9_]+)\\}(?!,)/);\n if (match) {\n varName = match[1];\n }\n }\n\n const keys = Object.keys(transformedOptions);\n const pluralKeys = [\n '1',\n '2',\n '<=3',\n '>=4',\n 'fallback',\n 'other',\n 'zero',\n 'one',\n 'two',\n 'few',\n 'many',\n ];\n // Check if it is a plural\n const isPlural = keys.every(\n (k) => pluralKeys.includes(k) || /^[<>=]?\\d+(\\.\\d+)?$/.test(k)\n );\n\n const parts = [];\n\n if (isPlural) {\n for (const [key, val] of Object.entries(transformedOptions)) {\n let icuKey = key;\n if (key === 'fallback') icuKey = 'other';\n else if (key === '<=3') icuKey = 'few';\n else if (key === '>=4') icuKey = 'many';\n else if (/^\\d+$/.test(key)) icuKey = `=${key}`;\n\n let strVal = val;\n\n // Convert {{var}} to {var} inside ICU string\n // Also replace {varName} with # if it matches\n strVal = strVal.replace(/\\{\\{([^}]+)\\}\\}/g, '{$1}');\n strVal = strVal.replace(new RegExp(`\\\\{${varName}\\\\}`, 'g'), '#');\n\n parts.push(`${icuKey} {${strVal}}`);\n }\n return `{${varName}, plural, ${parts.join(' ')}}`;\n } else {\n // Select\n const entries = Object.entries(transformedOptions).sort(\n ([keyA], [keyB]) => {\n if (keyA === 'fallback' || keyA === 'other') return 1;\n if (keyB === 'fallback' || keyB === 'other') return -1;\n return 0;\n }\n );\n\n for (const [key, val] of entries) {\n let icuKey = key;\n if (key === 'fallback') icuKey = 'other';\n\n let strVal = val;\n strVal = strVal.replace(/\\{\\{([^}]+)\\}\\}/g, '{$1}');\n\n parts.push(`${icuKey} {${strVal}}`);\n }\n return `{${varName}, select, ${parts.join(' ')}}`;\n }\n }\n\n if (node.nodeType === NodeType.Gender) {\n const options = node.gender;\n const varName = 'gender';\n const parts = [];\n\n const entries = Object.entries(options).sort(([keyA], [keyB]) => {\n if (keyA === 'fallback') return 1;\n if (keyB === 'fallback') return -1;\n return 0;\n });\n\n for (const [key, val] of entries) {\n let icuKey = key;\n if (key === 'fallback') icuKey = 'other';\n\n const childVal = next(val, props);\n let strVal =\n typeof childVal === 'string' ? childVal : JSON.stringify(childVal);\n\n strVal = strVal.replace(/\\{\\{([^}]+)\\}\\}/g, '{$1}');\n parts.push(`${icuKey} {${strVal}}`);\n }\n return `{${varName}, select, ${parts.join(' ')}}`;\n }\n\n if (\n Array.isArray(node) ||\n (node.nodeType === 'composite' && Array.isArray(node.composite))\n ) {\n const arr = Array.isArray(node) ? node : node.composite;\n const items = arr.map((item: any) => next(item, props));\n return items.join('');\n }\n\n return next(node, props);\n },\n};\n\nexport const intlayerToI18nextFormatter = (\n message: Dictionary['content']\n): JsonValue => {\n return deepTransformNode(message, {\n dictionaryKey: 'i18next',\n keyPath: [],\n plugins: [{ id: 'i18next', ...intlayerToI18nextPlugin }],\n });\n};\n\nexport const i18nextToIntlayerFormatter = (\n message: JsonValue\n): Dictionary['content'] => {\n return deepTransformNode(message, {\n dictionaryKey: 'i18next',\n keyPath: [],\n plugins: [{ id: 'i18next', ...i18nextToIntlayerPlugin }],\n });\n};\n"],"mappings":"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"}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
const require_transpiler_enumeration_enumeration = require('../transpiler/enumeration/enumeration.cjs');
|
|
2
|
+
const require_transpiler_gender_gender = require('../transpiler/gender/gender.cjs');
|
|
3
|
+
const require_transpiler_insertion_insertion = require('../transpiler/insertion/insertion.cjs');
|
|
4
|
+
const require_messageFormat_ICU = require('./ICU.cjs');
|
|
5
|
+
|
|
6
|
+
//#region src/messageFormat/verify-icu-format.ts
|
|
7
|
+
/**
|
|
8
|
+
* Verification script to demonstrate ICU format conversion
|
|
9
|
+
* This script shows that Intlayer correctly converts {{var}} (internal format)
|
|
10
|
+
* to {var} (ICU format) when outputting.
|
|
11
|
+
*/
|
|
12
|
+
console.log("=== ICU Format Verification ===\n");
|
|
13
|
+
console.log("Test 1: Simple Interpolation");
|
|
14
|
+
console.log("Intlayer input:", require_transpiler_insertion_insertion.insert("Hello {{name}}"));
|
|
15
|
+
const test1 = require_messageFormat_ICU.intlayerToICUFormatter(require_transpiler_insertion_insertion.insert("Hello {{name}}"));
|
|
16
|
+
console.log("ICU output:", test1);
|
|
17
|
+
console.log("✓ Expected: Single braces {name}");
|
|
18
|
+
console.log("✓ Result:", test1.includes("{name}") && !test1.includes("{{name}}") ? "PASS" : "FAIL");
|
|
19
|
+
console.log();
|
|
20
|
+
console.log("Test 2: Formatted Variable");
|
|
21
|
+
console.log("Intlayer input:", require_transpiler_insertion_insertion.insert("Price: {amount, number, currency}"));
|
|
22
|
+
const test2 = require_messageFormat_ICU.intlayerToICUFormatter(require_transpiler_insertion_insertion.insert("Price: {amount, number, currency}"));
|
|
23
|
+
console.log("ICU output:", test2);
|
|
24
|
+
console.log("✓ Expected: Single braces {amount, number, currency}");
|
|
25
|
+
console.log("✓ Result:", test2.includes("{amount, number, currency}") ? "PASS" : "FAIL");
|
|
26
|
+
console.log();
|
|
27
|
+
console.log("Test 3: Plural with Variable");
|
|
28
|
+
const pluralInput = require_transpiler_enumeration_enumeration.enu({
|
|
29
|
+
"0": "No items",
|
|
30
|
+
"1": "One item",
|
|
31
|
+
fallback: "{{count}} items"
|
|
32
|
+
});
|
|
33
|
+
console.log("Intlayer input:", JSON.stringify(pluralInput, null, 2));
|
|
34
|
+
const test3 = require_messageFormat_ICU.intlayerToICUFormatter(pluralInput);
|
|
35
|
+
console.log("ICU output:", test3);
|
|
36
|
+
console.log("✓ Expected: {count, plural, ...} with # for count");
|
|
37
|
+
console.log("✓ Result:", test3.includes("{count, plural,") && test3.includes("# items") && !test3.includes("{{") ? "PASS" : "FAIL");
|
|
38
|
+
console.log();
|
|
39
|
+
console.log("Test 4: Roundtrip Conversion (ICU → Intlayer → ICU)");
|
|
40
|
+
const original = "Hello {name}, you have {count, plural, =0 {no messages} =1 {one message} other {# messages}}";
|
|
41
|
+
console.log("Original ICU:", original);
|
|
42
|
+
const toIntlayer = require_messageFormat_ICU.icuToIntlayerFormatter(original);
|
|
43
|
+
console.log("Converted to Intlayer:", JSON.stringify(toIntlayer, null, 2));
|
|
44
|
+
const backToICU = require_messageFormat_ICU.intlayerToICUFormatter(toIntlayer);
|
|
45
|
+
console.log("Back to ICU:", backToICU);
|
|
46
|
+
console.log("✓ Expected: No {{...}} in output");
|
|
47
|
+
console.log("✓ Result:", !String(backToICU).includes("{{") ? "PASS" : "FAIL");
|
|
48
|
+
console.log();
|
|
49
|
+
console.log("Test 5: Gender with Nested Structures");
|
|
50
|
+
const test5 = require_messageFormat_ICU.intlayerToICUFormatter(require_transpiler_gender_gender.gender({
|
|
51
|
+
male: "He has items",
|
|
52
|
+
female: "She has items",
|
|
53
|
+
fallback: "They have items"
|
|
54
|
+
}));
|
|
55
|
+
console.log("ICU output:", test5);
|
|
56
|
+
console.log("✓ Expected: Single braces only");
|
|
57
|
+
console.log("✓ Result:", !test5.includes("{{") ? "PASS" : "FAIL");
|
|
58
|
+
console.log();
|
|
59
|
+
console.log("=== Summary ===");
|
|
60
|
+
console.log("ICU MessageFormat uses single braces: {var}");
|
|
61
|
+
console.log("Intlayer internal format uses double braces: {{var}}");
|
|
62
|
+
console.log("The conversion between these formats is handled automatically.");
|
|
63
|
+
|
|
64
|
+
//#endregion
|
|
65
|
+
//# sourceMappingURL=verify-icu-format.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"verify-icu-format.cjs","names":["insert","intlayerToICUFormatter","enu","icuToIntlayerFormatter","gender"],"sources":["../../../src/messageFormat/verify-icu-format.ts"],"sourcesContent":["/**\n * Verification script to demonstrate ICU format conversion\n * This script shows that Intlayer correctly converts {{var}} (internal format)\n * to {var} (ICU format) when outputting.\n */\n\nimport { enu, gender, insert } from '../transpiler';\nimport { icuToIntlayerFormatter, intlayerToICUFormatter } from './ICU';\n\nconsole.log('=== ICU Format Verification ===\\n');\n\n// Test 1: Simple interpolation\nconsole.log('Test 1: Simple Interpolation');\nconsole.log('Intlayer input:', insert('Hello {{name}}'));\nconst test1 = intlayerToICUFormatter(insert('Hello {{name}}'));\nconsole.log('ICU output:', test1);\nconsole.log('✓ Expected: Single braces {name}');\nconsole.log(\n '✓ Result:',\n test1.includes('{name}') && !test1.includes('{{name}}') ? 'PASS' : 'FAIL'\n);\nconsole.log();\n\n// Test 2: Formatted variable\nconsole.log('Test 2: Formatted Variable');\nconsole.log('Intlayer input:', insert('Price: {amount, number, currency}'));\nconst test2 = intlayerToICUFormatter(\n insert('Price: {amount, number, currency}')\n);\nconsole.log('ICU output:', test2);\nconsole.log('✓ Expected: Single braces {amount, number, currency}');\nconsole.log(\n '✓ Result:',\n test2.includes('{amount, number, currency}') ? 'PASS' : 'FAIL'\n);\nconsole.log();\n\n// Test 3: Plural with variable\nconsole.log('Test 3: Plural with Variable');\nconst pluralInput = enu({\n '0': 'No items',\n '1': 'One item',\n fallback: '{{count}} items',\n});\nconsole.log('Intlayer input:', JSON.stringify(pluralInput, null, 2));\nconst test3 = intlayerToICUFormatter(pluralInput);\nconsole.log('ICU output:', test3);\nconsole.log('✓ Expected: {count, plural, ...} with # for count');\nconsole.log(\n '✓ Result:',\n test3.includes('{count, plural,') &&\n test3.includes('# items') &&\n !test3.includes('{{')\n ? 'PASS'\n : 'FAIL'\n);\nconsole.log();\n\n// Test 4: Roundtrip conversion\nconsole.log('Test 4: Roundtrip Conversion (ICU → Intlayer → ICU)');\nconst original =\n 'Hello {name}, you have {count, plural, =0 {no messages} =1 {one message} other {# messages}}';\nconsole.log('Original ICU:', original);\nconst toIntlayer = icuToIntlayerFormatter(original);\nconsole.log('Converted to Intlayer:', JSON.stringify(toIntlayer, null, 2));\nconst backToICU = intlayerToICUFormatter(toIntlayer);\nconsole.log('Back to ICU:', backToICU);\nconsole.log('✓ Expected: No {{...}} in output');\nconsole.log('✓ Result:', !String(backToICU).includes('{{') ? 'PASS' : 'FAIL');\nconsole.log();\n\n// Test 5: Gender with nested plural\nconsole.log('Test 5: Gender with Nested Structures');\nconst genderInput = gender({\n male: 'He has items',\n female: 'She has items',\n fallback: 'They have items',\n});\nconst test5 = intlayerToICUFormatter(genderInput);\nconsole.log('ICU output:', test5);\nconsole.log('✓ Expected: Single braces only');\nconsole.log('✓ Result:', !test5.includes('{{') ? 'PASS' : 'FAIL');\nconsole.log();\n\nconsole.log('=== Summary ===');\nconsole.log('ICU MessageFormat uses single braces: {var}');\nconsole.log('Intlayer internal format uses double braces: {{var}}');\nconsole.log('The conversion between these formats is handled automatically.');\n"],"mappings":";;;;;;;;;;;AASA,QAAQ,IAAI,oCAAoC;AAGhD,QAAQ,IAAI,+BAA+B;AAC3C,QAAQ,IAAI,mBAAmBA,8CAAO,iBAAiB,CAAC;AACxD,MAAM,QAAQC,iDAAuBD,8CAAO,iBAAiB,CAAC;AAC9D,QAAQ,IAAI,eAAe,MAAM;AACjC,QAAQ,IAAI,mCAAmC;AAC/C,QAAQ,IACN,aACA,MAAM,SAAS,SAAS,IAAI,CAAC,MAAM,SAAS,WAAW,GAAG,SAAS,OACpE;AACD,QAAQ,KAAK;AAGb,QAAQ,IAAI,6BAA6B;AACzC,QAAQ,IAAI,mBAAmBA,8CAAO,oCAAoC,CAAC;AAC3E,MAAM,QAAQC,iDACZD,8CAAO,oCAAoC,CAC5C;AACD,QAAQ,IAAI,eAAe,MAAM;AACjC,QAAQ,IAAI,uDAAuD;AACnE,QAAQ,IACN,aACA,MAAM,SAAS,6BAA6B,GAAG,SAAS,OACzD;AACD,QAAQ,KAAK;AAGb,QAAQ,IAAI,+BAA+B;AAC3C,MAAM,cAAcE,+CAAI;CACtB,KAAK;CACL,KAAK;CACL,UAAU;CACX,CAAC;AACF,QAAQ,IAAI,mBAAmB,KAAK,UAAU,aAAa,MAAM,EAAE,CAAC;AACpE,MAAM,QAAQD,iDAAuB,YAAY;AACjD,QAAQ,IAAI,eAAe,MAAM;AACjC,QAAQ,IAAI,oDAAoD;AAChE,QAAQ,IACN,aACA,MAAM,SAAS,kBAAkB,IAC/B,MAAM,SAAS,UAAU,IACzB,CAAC,MAAM,SAAS,KAAK,GACnB,SACA,OACL;AACD,QAAQ,KAAK;AAGb,QAAQ,IAAI,sDAAsD;AAClE,MAAM,WACJ;AACF,QAAQ,IAAI,iBAAiB,SAAS;AACtC,MAAM,aAAaE,iDAAuB,SAAS;AACnD,QAAQ,IAAI,0BAA0B,KAAK,UAAU,YAAY,MAAM,EAAE,CAAC;AAC1E,MAAM,YAAYF,iDAAuB,WAAW;AACpD,QAAQ,IAAI,gBAAgB,UAAU;AACtC,QAAQ,IAAI,mCAAmC;AAC/C,QAAQ,IAAI,aAAa,CAAC,OAAO,UAAU,CAAC,SAAS,KAAK,GAAG,SAAS,OAAO;AAC7E,QAAQ,KAAK;AAGb,QAAQ,IAAI,wCAAwC;AAMpD,MAAM,QAAQA,iDALMG,wCAAO;CACzB,MAAM;CACN,QAAQ;CACR,UAAU;CACX,CAAC,CAC+C;AACjD,QAAQ,IAAI,eAAe,MAAM;AACjC,QAAQ,IAAI,iCAAiC;AAC7C,QAAQ,IAAI,aAAa,CAAC,MAAM,SAAS,KAAK,GAAG,SAAS,OAAO;AACjE,QAAQ,KAAK;AAEb,QAAQ,IAAI,kBAAkB;AAC9B,QAAQ,IAAI,8CAA8C;AAC1D,QAAQ,IAAI,uDAAuD;AACnE,QAAQ,IAAI,iEAAiE"}
|
|
@@ -2,7 +2,7 @@ const require_rolldown_runtime = require('../_virtual/rolldown_runtime.cjs');
|
|
|
2
2
|
const require_interpreter_getContent_deepTransform = require('../interpreter/getContent/deepTransform.cjs');
|
|
3
3
|
const require_transpiler_enumeration_enumeration = require('../transpiler/enumeration/enumeration.cjs');
|
|
4
4
|
const require_transpiler_insertion_insertion = require('../transpiler/insertion/insertion.cjs');
|
|
5
|
-
let
|
|
5
|
+
let _intlayer_types = require("@intlayer/types");
|
|
6
6
|
|
|
7
7
|
//#region src/messageFormat/vue-i18n.ts
|
|
8
8
|
const parseVueI18nPart = (text) => {
|
|
@@ -93,11 +93,11 @@ const vueI18nToIntlayerPlugin = {
|
|
|
93
93
|
}
|
|
94
94
|
};
|
|
95
95
|
const intlayerToVueI18nPlugin = {
|
|
96
|
-
canHandle: (node) => typeof node === "string" || node && typeof node === "object" && (node.nodeType ===
|
|
96
|
+
canHandle: (node) => typeof node === "string" || node && typeof node === "object" && (node.nodeType === _intlayer_types.NodeType.Insertion || node.nodeType === _intlayer_types.NodeType.Enumeration || node.nodeType === _intlayer_types.NodeType.Gender || node.nodeType === "composite") || Array.isArray(node),
|
|
97
97
|
transform: (node, props, next) => {
|
|
98
98
|
if (typeof node === "string") return node.replace(/\{\{([^}]+)\}\}/g, "{$1}");
|
|
99
|
-
if (node.nodeType ===
|
|
100
|
-
if (node.nodeType ===
|
|
99
|
+
if (node.nodeType === _intlayer_types.NodeType.Insertion) return node.insertion.replace(/\{\{([^}]+)\}\}/g, "{$1}");
|
|
100
|
+
if (node.nodeType === _intlayer_types.NodeType.Enumeration) {
|
|
101
101
|
const options = node.enumeration;
|
|
102
102
|
const transformedOptions = {};
|
|
103
103
|
for (const [key, val] of Object.entries(options)) {
|
|
@@ -125,7 +125,7 @@ const intlayerToVueI18nPlugin = {
|
|
|
125
125
|
if (keys.length === 1 && (keys.includes("fallback") || keys.includes("other"))) return transformedOptions.fallback || transformedOptions.other;
|
|
126
126
|
return transformedOptions.fallback || Object.values(transformedOptions)[0];
|
|
127
127
|
}
|
|
128
|
-
if (node.nodeType ===
|
|
128
|
+
if (node.nodeType === _intlayer_types.NodeType.Gender) {
|
|
129
129
|
const options = node.gender;
|
|
130
130
|
const transformedOptions = {};
|
|
131
131
|
for (const [key, val] of Object.entries(options)) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"vue-i18n.cjs","names":["nodes: VueI18nNode[]","parts: string[]","insert","options: Record<string, any>","enu","NodeType","transformedOptions: Record<string, string>","transformedOptions: Record<string, any>","deepTransformNode"],"sources":["../../../src/messageFormat/vue-i18n.ts"],"sourcesContent":["import { type Dictionary, NodeType } from '@intlayer/types';\nimport { deepTransformNode } from '../interpreter';\nimport { enu, insert } from '../transpiler';\nimport type { JsonValue } from './ICU';\n\n// Types for our AST\ntype VueI18nNode =\n | string\n | {\n type: 'argument';\n name: string;\n };\n\nconst parseVueI18nPart = (text: string): VueI18nNode[] => {\n let index = 0;\n const nodes: VueI18nNode[] = [];\n let currentText = '';\n\n while (index < text.length) {\n const char = text[index];\n\n if (char === '{') {\n if (currentText) {\n nodes.push(currentText);\n currentText = '';\n }\n index++; // skip {\n let name = '';\n while (index < text.length && text[index] !== '}') {\n name += text[index];\n index++;\n }\n if (index < text.length) {\n index++; // skip }\n }\n nodes.push({ type: 'argument', name: name.trim() });\n } else {\n currentText += char;\n index++;\n }\n }\n\n if (currentText) {\n nodes.push(currentText);\n }\n\n return nodes;\n};\n\nconst parseVueI18n = (text: string): VueI18nNode[][] => {\n // Split by | but handle escaped \\|\n const parts: string[] = [];\n let currentPart = '';\n let index = 0;\n\n while (index < text.length) {\n const char = text[index];\n if (char === '\\\\' && index + 1 < text.length && text[index + 1] === '|') {\n currentPart += '|';\n index += 2;\n } else if (char === '|') {\n parts.push(currentPart.trim()); // Trim to remove surrounding spaces\n currentPart = '';\n index++;\n } else {\n currentPart += char;\n index++;\n }\n }\n parts.push(currentPart.trim()); // Trim last part too\n\n return parts.map(parseVueI18nPart);\n};\n\nconst vueI18nPartToIntlayer = (nodes: VueI18nNode[]): any => {\n if (nodes.length === 0) return '';\n if (nodes.length === 1 && typeof nodes[0] === 'string') return nodes[0];\n\n let str = '';\n for (const node of nodes) {\n if (typeof node === 'string') {\n str += node;\n } else {\n str += `{{${node.name}}}`;\n }\n }\n return insert(str);\n};\n\nconst vueI18nNodesToIntlayer = (parts: VueI18nNode[][]): any => {\n if (parts.length === 1) {\n return vueI18nPartToIntlayer(parts[0]);\n }\n\n // Handle pluralization (choice)\n const options: Record<string, any> = {};\n const varName = 'count'; // Default variable for vue-i18n choices\n\n if (parts.length === 2) {\n // 2 choices: 1 | other\n options['1'] = vueI18nPartToIntlayer(parts[0]);\n options.fallback = vueI18nPartToIntlayer(parts[1]);\n } else if (parts.length === 3) {\n // 3 choices: 0 | 1 | other\n options['0'] = vueI18nPartToIntlayer(parts[0]);\n options['1'] = vueI18nPartToIntlayer(parts[1]);\n options.fallback = vueI18nPartToIntlayer(parts[2]);\n } else {\n // > 3 choices: 0 | 1 | 2 | ... | other\n parts.forEach((part, index) => {\n if (index === parts.length - 1) {\n options.fallback = vueI18nPartToIntlayer(part);\n } else {\n options[index.toString()] = vueI18nPartToIntlayer(part);\n }\n });\n }\n\n // Preserve variable name\n options.__intlayer_vue_i18n_var = varName;\n\n return enu(options);\n};\n\nconst vueI18nToIntlayerPlugin = {\n canHandle: (node: any) =>\n typeof node === 'string' && (node.includes('{') || node.includes('|')),\n transform: (node: any) => {\n try {\n const ast = parseVueI18n(node);\n return vueI18nNodesToIntlayer(ast);\n } catch {\n return node;\n }\n },\n};\n\nconst intlayerToVueI18nPlugin = {\n canHandle: (node: any) =>\n typeof node === 'string' ||\n (node &&\n typeof node === 'object' &&\n (node.nodeType === NodeType.Insertion ||\n node.nodeType === NodeType.Enumeration ||\n node.nodeType === NodeType.Gender ||\n node.nodeType === 'composite')) ||\n Array.isArray(node),\n transform: (node: any, props: any, next: any) => {\n if (typeof node === 'string') {\n // replace {{...}} with {...} even in strings\n return node.replace(/\\{\\{([^}]+)\\}\\}/g, '{$1}');\n }\n\n if (node.nodeType === NodeType.Insertion) {\n // {{name}} -> {name}\n return node.insertion.replace(/\\{\\{([^}]+)\\}\\}/g, '{$1}');\n }\n\n if (node.nodeType === NodeType.Enumeration) {\n const options = node.enumeration;\n\n const transformedOptions: Record<string, string> = {};\n for (const [key, val] of Object.entries(options)) {\n if (key === '__intlayer_vue_i18n_var') continue;\n const childVal = next(val, props);\n transformedOptions[key] =\n typeof childVal === 'string' ? childVal : JSON.stringify(childVal);\n }\n\n // We need to reconstruct the pipe-separated string.\n // 2 parts: 1, fallback\n // 3 parts: 0, 1, fallback\n\n const keys = Object.keys(transformedOptions);\n\n // Heuristic to decide format\n // Use loose condition for 3 parts: if 0 exists, OR if 2 exists, etc.\n // But typically 0, 1, 2...\n // If '0' is present, we likely want the 3+ parts format.\n if (keys.includes('0')) {\n const indices = keys.filter((key) => /^\\d+$/.test(key)).map(Number);\n const maxIndex = Math.max(...indices);\n\n const fallback =\n transformedOptions.fallback || transformedOptions.other;\n const resultParts = [];\n\n // Check if we can use simple 3-part: 0 | 1 | fallback\n // Only if maxIndex <= 1\n if (maxIndex <= 1 && !keys.includes('2')) {\n const zero = transformedOptions['0'] || '';\n const one = transformedOptions['1'] || ''; // Gap handling?\n return `${zero} | ${one} | ${fallback}`;\n }\n\n // General case: loop until maxIndex\n const limit = Math.max(1, maxIndex);\n\n for (let i = 0; i <= limit; i++) {\n const key = i.toString();\n if (transformedOptions[key]) {\n resultParts.push(transformedOptions[key]);\n } else {\n resultParts.push(''); // Empty string for gaps\n }\n }\n resultParts.push(fallback);\n return resultParts.join(' | ').replace(/ \\| {2}\\| /g, ' | | ');\n }\n\n // 2 parts: 1 | fallback\n if (\n keys.includes('1') &&\n (keys.includes('fallback') || keys.includes('other'))\n ) {\n return `${transformedOptions['1']} | ${transformedOptions.fallback || transformedOptions.other}`;\n }\n\n // Fallback for only fallback?\n if (\n keys.length === 1 &&\n (keys.includes('fallback') || keys.includes('other'))\n ) {\n return transformedOptions.fallback || transformedOptions.other;\n }\n\n // Default fallback\n return (\n transformedOptions.fallback || Object.values(transformedOptions)[0]\n );\n }\n\n // Gender not supported by vue-i18n string format, return object\n if (node.nodeType === NodeType.Gender) {\n const options = node.gender;\n const transformedOptions: Record<string, any> = {};\n\n // Just map values\n for (const [key, val] of Object.entries(options)) {\n let newKey = key;\n if (key === 'fallback') newKey = 'other'; // vue-i18n doesn't strictly have 'other' for gender objects but standard convention often uses similar keys\n\n const childVal = next(val, props);\n transformedOptions[newKey] = childVal;\n }\n return transformedOptions;\n }\n\n if (\n Array.isArray(node) ||\n (node.nodeType === 'composite' && Array.isArray(node.composite))\n ) {\n const arr = Array.isArray(node) ? node : node.composite;\n const items = arr.map((item: any) => next(item, props));\n return items.join('');\n }\n\n return next(node, props);\n },\n};\n\nexport const intlayerToVueI18nFormatter = (\n message: Dictionary['content']\n): JsonValue => {\n return deepTransformNode(message, {\n dictionaryKey: 'vue-i18n',\n keyPath: [],\n plugins: [{ id: 'vue-i18n', ...intlayerToVueI18nPlugin }],\n });\n};\n\nexport const vueI18nToIntlayerFormatter = (\n message: JsonValue\n): Dictionary['content'] => {\n return deepTransformNode(message, {\n dictionaryKey: 'vue-i18n',\n keyPath: [],\n plugins: [{ id: 'vue-i18n', ...vueI18nToIntlayerPlugin }],\n });\n};\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"vue-i18n.cjs","names":["nodes: VueI18nNode[]","parts: string[]","insert","options: Record<string, any>","enu","NodeType","transformedOptions: Record<string, string>","transformedOptions: Record<string, any>","deepTransformNode"],"sources":["../../../src/messageFormat/vue-i18n.ts"],"sourcesContent":["import { type Dictionary, NodeType } from '@intlayer/types';\nimport { deepTransformNode } from '../interpreter';\nimport { enu, insert } from '../transpiler';\nimport type { JsonValue } from './ICU';\n\n// Types for our AST\ntype VueI18nNode =\n | string\n | {\n type: 'argument';\n name: string;\n };\n\nconst parseVueI18nPart = (text: string): VueI18nNode[] => {\n let index = 0;\n const nodes: VueI18nNode[] = [];\n let currentText = '';\n\n while (index < text.length) {\n const char = text[index];\n\n if (char === '{') {\n if (currentText) {\n nodes.push(currentText);\n currentText = '';\n }\n index++; // skip {\n let name = '';\n while (index < text.length && text[index] !== '}') {\n name += text[index];\n index++;\n }\n if (index < text.length) {\n index++; // skip }\n }\n nodes.push({ type: 'argument', name: name.trim() });\n } else {\n currentText += char;\n index++;\n }\n }\n\n if (currentText) {\n nodes.push(currentText);\n }\n\n return nodes;\n};\n\nconst parseVueI18n = (text: string): VueI18nNode[][] => {\n // Split by | but handle escaped \\|\n const parts: string[] = [];\n let currentPart = '';\n let index = 0;\n\n while (index < text.length) {\n const char = text[index];\n if (char === '\\\\' && index + 1 < text.length && text[index + 1] === '|') {\n currentPart += '|';\n index += 2;\n } else if (char === '|') {\n parts.push(currentPart.trim()); // Trim to remove surrounding spaces\n currentPart = '';\n index++;\n } else {\n currentPart += char;\n index++;\n }\n }\n parts.push(currentPart.trim()); // Trim last part too\n\n return parts.map(parseVueI18nPart);\n};\n\nconst vueI18nPartToIntlayer = (nodes: VueI18nNode[]): any => {\n if (nodes.length === 0) return '';\n if (nodes.length === 1 && typeof nodes[0] === 'string') return nodes[0];\n\n let str = '';\n for (const node of nodes) {\n if (typeof node === 'string') {\n str += node;\n } else {\n str += `{{${node.name}}}`;\n }\n }\n return insert(str);\n};\n\nconst vueI18nNodesToIntlayer = (parts: VueI18nNode[][]): any => {\n if (parts.length === 1) {\n return vueI18nPartToIntlayer(parts[0]);\n }\n\n // Handle pluralization (choice)\n const options: Record<string, any> = {};\n const varName = 'count'; // Default variable for vue-i18n choices\n\n if (parts.length === 2) {\n // 2 choices: 1 | other\n options['1'] = vueI18nPartToIntlayer(parts[0]);\n options.fallback = vueI18nPartToIntlayer(parts[1]);\n } else if (parts.length === 3) {\n // 3 choices: 0 | 1 | other\n options['0'] = vueI18nPartToIntlayer(parts[0]);\n options['1'] = vueI18nPartToIntlayer(parts[1]);\n options.fallback = vueI18nPartToIntlayer(parts[2]);\n } else {\n // > 3 choices: 0 | 1 | 2 | ... | other\n parts.forEach((part, index) => {\n if (index === parts.length - 1) {\n options.fallback = vueI18nPartToIntlayer(part);\n } else {\n options[index.toString()] = vueI18nPartToIntlayer(part);\n }\n });\n }\n\n // Preserve variable name\n options.__intlayer_vue_i18n_var = varName;\n\n return enu(options);\n};\n\nconst vueI18nToIntlayerPlugin = {\n canHandle: (node: any) =>\n typeof node === 'string' && (node.includes('{') || node.includes('|')),\n transform: (node: any) => {\n try {\n const ast = parseVueI18n(node);\n return vueI18nNodesToIntlayer(ast);\n } catch {\n return node;\n }\n },\n};\n\nconst intlayerToVueI18nPlugin = {\n canHandle: (node: any) =>\n typeof node === 'string' ||\n (node &&\n typeof node === 'object' &&\n (node.nodeType === NodeType.Insertion ||\n node.nodeType === NodeType.Enumeration ||\n node.nodeType === NodeType.Gender ||\n node.nodeType === 'composite')) ||\n Array.isArray(node),\n transform: (node: any, props: any, next: any) => {\n if (typeof node === 'string') {\n // replace {{...}} with {...} even in strings\n return node.replace(/\\{\\{([^}]+)\\}\\}/g, '{$1}');\n }\n\n if (node.nodeType === NodeType.Insertion) {\n // {{name}} -> {name}\n return node.insertion.replace(/\\{\\{([^}]+)\\}\\}/g, '{$1}');\n }\n\n if (node.nodeType === NodeType.Enumeration) {\n const options = node.enumeration;\n\n const transformedOptions: Record<string, string> = {};\n for (const [key, val] of Object.entries(options)) {\n if (key === '__intlayer_vue_i18n_var') continue;\n const childVal = next(val, props);\n transformedOptions[key] =\n typeof childVal === 'string' ? childVal : JSON.stringify(childVal);\n }\n\n // We need to reconstruct the pipe-separated string.\n // 2 parts: 1, fallback\n // 3 parts: 0, 1, fallback\n\n const keys = Object.keys(transformedOptions);\n\n // Heuristic to decide format\n // Use loose condition for 3 parts: if 0 exists, OR if 2 exists, etc.\n // But typically 0, 1, 2...\n // If '0' is present, we likely want the 3+ parts format.\n if (keys.includes('0')) {\n const indices = keys.filter((key) => /^\\d+$/.test(key)).map(Number);\n const maxIndex = Math.max(...indices);\n\n const fallback =\n transformedOptions.fallback || transformedOptions.other;\n const resultParts = [];\n\n // Check if we can use simple 3-part: 0 | 1 | fallback\n // Only if maxIndex <= 1\n if (maxIndex <= 1 && !keys.includes('2')) {\n const zero = transformedOptions['0'] || '';\n const one = transformedOptions['1'] || ''; // Gap handling?\n return `${zero} | ${one} | ${fallback}`;\n }\n\n // General case: loop until maxIndex\n const limit = Math.max(1, maxIndex);\n\n for (let i = 0; i <= limit; i++) {\n const key = i.toString();\n if (transformedOptions[key]) {\n resultParts.push(transformedOptions[key]);\n } else {\n resultParts.push(''); // Empty string for gaps\n }\n }\n resultParts.push(fallback);\n return resultParts.join(' | ').replace(/ \\| {2}\\| /g, ' | | ');\n }\n\n // 2 parts: 1 | fallback\n if (\n keys.includes('1') &&\n (keys.includes('fallback') || keys.includes('other'))\n ) {\n return `${transformedOptions['1']} | ${transformedOptions.fallback || transformedOptions.other}`;\n }\n\n // Fallback for only fallback?\n if (\n keys.length === 1 &&\n (keys.includes('fallback') || keys.includes('other'))\n ) {\n return transformedOptions.fallback || transformedOptions.other;\n }\n\n // Default fallback\n return (\n transformedOptions.fallback || Object.values(transformedOptions)[0]\n );\n }\n\n // Gender not supported by vue-i18n string format, return object\n if (node.nodeType === NodeType.Gender) {\n const options = node.gender;\n const transformedOptions: Record<string, any> = {};\n\n // Just map values\n for (const [key, val] of Object.entries(options)) {\n let newKey = key;\n if (key === 'fallback') newKey = 'other'; // vue-i18n doesn't strictly have 'other' for gender objects but standard convention often uses similar keys\n\n const childVal = next(val, props);\n transformedOptions[newKey] = childVal;\n }\n return transformedOptions;\n }\n\n if (\n Array.isArray(node) ||\n (node.nodeType === 'composite' && Array.isArray(node.composite))\n ) {\n const arr = Array.isArray(node) ? node : node.composite;\n const items = arr.map((item: any) => next(item, props));\n return items.join('');\n }\n\n return next(node, props);\n },\n};\n\nexport const intlayerToVueI18nFormatter = (\n message: Dictionary['content']\n): JsonValue => {\n return deepTransformNode(message, {\n dictionaryKey: 'vue-i18n',\n keyPath: [],\n plugins: [{ id: 'vue-i18n', ...intlayerToVueI18nPlugin }],\n });\n};\n\nexport const vueI18nToIntlayerFormatter = (\n message: JsonValue\n): Dictionary['content'] => {\n return deepTransformNode(message, {\n dictionaryKey: 'vue-i18n',\n keyPath: [],\n plugins: [{ id: 'vue-i18n', ...vueI18nToIntlayerPlugin }],\n });\n};\n"],"mappings":";;;;;;;AAaA,MAAM,oBAAoB,SAAgC;CACxD,IAAI,QAAQ;CACZ,MAAMA,QAAuB,EAAE;CAC/B,IAAI,cAAc;AAElB,QAAO,QAAQ,KAAK,QAAQ;EAC1B,MAAM,OAAO,KAAK;AAElB,MAAI,SAAS,KAAK;AAChB,OAAI,aAAa;AACf,UAAM,KAAK,YAAY;AACvB,kBAAc;;AAEhB;GACA,IAAI,OAAO;AACX,UAAO,QAAQ,KAAK,UAAU,KAAK,WAAW,KAAK;AACjD,YAAQ,KAAK;AACb;;AAEF,OAAI,QAAQ,KAAK,OACf;AAEF,SAAM,KAAK;IAAE,MAAM;IAAY,MAAM,KAAK,MAAM;IAAE,CAAC;SAC9C;AACL,kBAAe;AACf;;;AAIJ,KAAI,YACF,OAAM,KAAK,YAAY;AAGzB,QAAO;;AAGT,MAAM,gBAAgB,SAAkC;CAEtD,MAAMC,QAAkB,EAAE;CAC1B,IAAI,cAAc;CAClB,IAAI,QAAQ;AAEZ,QAAO,QAAQ,KAAK,QAAQ;EAC1B,MAAM,OAAO,KAAK;AAClB,MAAI,SAAS,QAAQ,QAAQ,IAAI,KAAK,UAAU,KAAK,QAAQ,OAAO,KAAK;AACvE,kBAAe;AACf,YAAS;aACA,SAAS,KAAK;AACvB,SAAM,KAAK,YAAY,MAAM,CAAC;AAC9B,iBAAc;AACd;SACK;AACL,kBAAe;AACf;;;AAGJ,OAAM,KAAK,YAAY,MAAM,CAAC;AAE9B,QAAO,MAAM,IAAI,iBAAiB;;AAGpC,MAAM,yBAAyB,UAA8B;AAC3D,KAAI,MAAM,WAAW,EAAG,QAAO;AAC/B,KAAI,MAAM,WAAW,KAAK,OAAO,MAAM,OAAO,SAAU,QAAO,MAAM;CAErE,IAAI,MAAM;AACV,MAAK,MAAM,QAAQ,MACjB,KAAI,OAAO,SAAS,SAClB,QAAO;KAEP,QAAO,KAAK,KAAK,KAAK;AAG1B,QAAOC,8CAAO,IAAI;;AAGpB,MAAM,0BAA0B,UAAgC;AAC9D,KAAI,MAAM,WAAW,EACnB,QAAO,sBAAsB,MAAM,GAAG;CAIxC,MAAMC,UAA+B,EAAE;CACvC,MAAM,UAAU;AAEhB,KAAI,MAAM,WAAW,GAAG;AAEtB,UAAQ,OAAO,sBAAsB,MAAM,GAAG;AAC9C,UAAQ,WAAW,sBAAsB,MAAM,GAAG;YACzC,MAAM,WAAW,GAAG;AAE7B,UAAQ,OAAO,sBAAsB,MAAM,GAAG;AAC9C,UAAQ,OAAO,sBAAsB,MAAM,GAAG;AAC9C,UAAQ,WAAW,sBAAsB,MAAM,GAAG;OAGlD,OAAM,SAAS,MAAM,UAAU;AAC7B,MAAI,UAAU,MAAM,SAAS,EAC3B,SAAQ,WAAW,sBAAsB,KAAK;MAE9C,SAAQ,MAAM,UAAU,IAAI,sBAAsB,KAAK;GAEzD;AAIJ,SAAQ,0BAA0B;AAElC,QAAOC,+CAAI,QAAQ;;AAGrB,MAAM,0BAA0B;CAC9B,YAAY,SACV,OAAO,SAAS,aAAa,KAAK,SAAS,IAAI,IAAI,KAAK,SAAS,IAAI;CACvE,YAAY,SAAc;AACxB,MAAI;AAEF,UAAO,uBADK,aAAa,KAAK,CACI;UAC5B;AACN,UAAO;;;CAGZ;AAED,MAAM,0BAA0B;CAC9B,YAAY,SACV,OAAO,SAAS,YACf,QACC,OAAO,SAAS,aACf,KAAK,aAAaC,yBAAS,aAC1B,KAAK,aAAaA,yBAAS,eAC3B,KAAK,aAAaA,yBAAS,UAC3B,KAAK,aAAa,gBACtB,MAAM,QAAQ,KAAK;CACrB,YAAY,MAAW,OAAY,SAAc;AAC/C,MAAI,OAAO,SAAS,SAElB,QAAO,KAAK,QAAQ,oBAAoB,OAAO;AAGjD,MAAI,KAAK,aAAaA,yBAAS,UAE7B,QAAO,KAAK,UAAU,QAAQ,oBAAoB,OAAO;AAG3D,MAAI,KAAK,aAAaA,yBAAS,aAAa;GAC1C,MAAM,UAAU,KAAK;GAErB,MAAMC,qBAA6C,EAAE;AACrD,QAAK,MAAM,CAAC,KAAK,QAAQ,OAAO,QAAQ,QAAQ,EAAE;AAChD,QAAI,QAAQ,0BAA2B;IACvC,MAAM,WAAW,KAAK,KAAK,MAAM;AACjC,uBAAmB,OACjB,OAAO,aAAa,WAAW,WAAW,KAAK,UAAU,SAAS;;GAOtE,MAAM,OAAO,OAAO,KAAK,mBAAmB;AAM5C,OAAI,KAAK,SAAS,IAAI,EAAE;IACtB,MAAM,UAAU,KAAK,QAAQ,QAAQ,QAAQ,KAAK,IAAI,CAAC,CAAC,IAAI,OAAO;IACnE,MAAM,WAAW,KAAK,IAAI,GAAG,QAAQ;IAErC,MAAM,WACJ,mBAAmB,YAAY,mBAAmB;IACpD,MAAM,cAAc,EAAE;AAItB,QAAI,YAAY,KAAK,CAAC,KAAK,SAAS,IAAI,CAGtC,QAAO,GAFM,mBAAmB,QAAQ,GAEzB,KADH,mBAAmB,QAAQ,GACf,KAAK;IAI/B,MAAM,QAAQ,KAAK,IAAI,GAAG,SAAS;AAEnC,SAAK,IAAI,IAAI,GAAG,KAAK,OAAO,KAAK;KAC/B,MAAM,MAAM,EAAE,UAAU;AACxB,SAAI,mBAAmB,KACrB,aAAY,KAAK,mBAAmB,KAAK;SAEzC,aAAY,KAAK,GAAG;;AAGxB,gBAAY,KAAK,SAAS;AAC1B,WAAO,YAAY,KAAK,MAAM,CAAC,QAAQ,eAAe,QAAQ;;AAIhE,OACE,KAAK,SAAS,IAAI,KACjB,KAAK,SAAS,WAAW,IAAI,KAAK,SAAS,QAAQ,EAEpD,QAAO,GAAG,mBAAmB,KAAK,KAAK,mBAAmB,YAAY,mBAAmB;AAI3F,OACE,KAAK,WAAW,MACf,KAAK,SAAS,WAAW,IAAI,KAAK,SAAS,QAAQ,EAEpD,QAAO,mBAAmB,YAAY,mBAAmB;AAI3D,UACE,mBAAmB,YAAY,OAAO,OAAO,mBAAmB,CAAC;;AAKrE,MAAI,KAAK,aAAaD,yBAAS,QAAQ;GACrC,MAAM,UAAU,KAAK;GACrB,MAAME,qBAA0C,EAAE;AAGlD,QAAK,MAAM,CAAC,KAAK,QAAQ,OAAO,QAAQ,QAAQ,EAAE;IAChD,IAAI,SAAS;AACb,QAAI,QAAQ,WAAY,UAAS;AAGjC,uBAAmB,UADF,KAAK,KAAK,MAAM;;AAGnC,UAAO;;AAGT,MACE,MAAM,QAAQ,KAAK,IAClB,KAAK,aAAa,eAAe,MAAM,QAAQ,KAAK,UAAU,CAI/D,SAFY,MAAM,QAAQ,KAAK,GAAG,OAAO,KAAK,WAC5B,KAAK,SAAc,KAAK,MAAM,MAAM,CAAC,CAC1C,KAAK,GAAG;AAGvB,SAAO,KAAK,MAAM,MAAM;;CAE3B;AAED,MAAa,8BACX,YACc;AACd,QAAOC,+DAAkB,SAAS;EAChC,eAAe;EACf,SAAS,EAAE;EACX,SAAS,CAAC;GAAE,IAAI;GAAY,GAAG;GAAyB,CAAC;EAC1D,CAAC;;AAGJ,MAAa,8BACX,YAC0B;AAC1B,QAAOA,+DAAkB,SAAS;EAChC,eAAe;EACf,SAAS,EAAE;EACX,SAAS,CAAC;GAAE,IAAI;GAAY,GAAG;GAAyB,CAAC;EAC1D,CAAC"}
|