convex-cms 0.0.1
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/cli/commands/admin.d.ts +16 -0
- package/dist/cli/commands/admin.d.ts.map +1 -0
- package/dist/cli/commands/admin.js +88 -0
- package/dist/cli/commands/admin.js.map +1 -0
- package/dist/cli/index.d.ts +3 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +18 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/cli/utils/detectConvexUrl.d.ts +13 -0
- package/dist/cli/utils/detectConvexUrl.d.ts.map +1 -0
- package/dist/cli/utils/detectConvexUrl.js +48 -0
- package/dist/cli/utils/detectConvexUrl.js.map +1 -0
- package/dist/cli/utils/openBrowser.d.ts +7 -0
- package/dist/cli/utils/openBrowser.d.ts.map +1 -0
- package/dist/cli/utils/openBrowser.js +17 -0
- package/dist/cli/utils/openBrowser.js.map +1 -0
- package/dist/client/admin-config.d.ts +126 -0
- package/dist/client/admin-config.d.ts.map +1 -0
- package/dist/client/admin-config.js +117 -0
- package/dist/client/admin-config.js.map +1 -0
- package/dist/client/adminApi.d.ts +2273 -0
- package/dist/client/adminApi.d.ts.map +1 -0
- package/dist/client/adminApi.js +716 -0
- package/dist/client/adminApi.js.map +1 -0
- package/dist/client/agentTools.d.ts +933 -0
- package/dist/client/agentTools.d.ts.map +1 -0
- package/dist/client/agentTools.js +1004 -0
- package/dist/client/agentTools.js.map +1 -0
- package/dist/client/argTypes.d.ts +212 -0
- package/dist/client/argTypes.d.ts.map +1 -0
- package/dist/client/argTypes.js +5 -0
- package/dist/client/argTypes.js.map +1 -0
- package/dist/client/field-types.d.ts +55 -0
- package/dist/client/field-types.d.ts.map +1 -0
- package/dist/client/field-types.js +152 -0
- package/dist/client/field-types.js.map +1 -0
- package/dist/client/index.d.ts +189 -0
- package/dist/client/index.d.ts.map +1 -0
- package/dist/client/index.js +668 -0
- package/dist/client/index.js.map +1 -0
- package/dist/client/queryBuilder.d.ts +765 -0
- package/dist/client/queryBuilder.d.ts.map +1 -0
- package/dist/client/queryBuilder.js +970 -0
- package/dist/client/queryBuilder.js.map +1 -0
- package/dist/client/schema/codegen.d.ts +128 -0
- package/dist/client/schema/codegen.d.ts.map +1 -0
- package/dist/client/schema/codegen.js +318 -0
- package/dist/client/schema/codegen.js.map +1 -0
- package/dist/client/schema/defineContentType.d.ts +221 -0
- package/dist/client/schema/defineContentType.d.ts.map +1 -0
- package/dist/client/schema/defineContentType.js +380 -0
- package/dist/client/schema/defineContentType.js.map +1 -0
- package/dist/client/schema/index.d.ts +85 -0
- package/dist/client/schema/index.d.ts.map +1 -0
- package/dist/client/schema/index.js +92 -0
- package/dist/client/schema/index.js.map +1 -0
- package/dist/client/schema/schemaDrift.d.ts +199 -0
- package/dist/client/schema/schemaDrift.d.ts.map +1 -0
- package/dist/client/schema/schemaDrift.js +340 -0
- package/dist/client/schema/schemaDrift.js.map +1 -0
- package/dist/client/schema/typedClient.d.ts +401 -0
- package/dist/client/schema/typedClient.d.ts.map +1 -0
- package/dist/client/schema/typedClient.js +269 -0
- package/dist/client/schema/typedClient.js.map +1 -0
- package/dist/client/schema/types.d.ts +477 -0
- package/dist/client/schema/types.d.ts.map +1 -0
- package/dist/client/schema/types.js +39 -0
- package/dist/client/schema/types.js.map +1 -0
- package/dist/client/types.d.ts +449 -0
- package/dist/client/types.d.ts.map +1 -0
- package/dist/client/types.js +149 -0
- package/dist/client/types.js.map +1 -0
- package/dist/client/workflows.d.ts +51 -0
- package/dist/client/workflows.d.ts.map +1 -0
- package/dist/client/workflows.js +103 -0
- package/dist/client/workflows.js.map +1 -0
- package/dist/client/wrapper.d.ts +2198 -0
- package/dist/client/wrapper.d.ts.map +1 -0
- package/dist/client/wrapper.js +2651 -0
- package/dist/client/wrapper.js.map +1 -0
- package/dist/component/_generated/api.d.ts +124 -0
- package/dist/component/_generated/api.d.ts.map +1 -0
- package/dist/component/_generated/api.js +31 -0
- package/dist/component/_generated/api.js.map +1 -0
- package/dist/component/_generated/component.d.ts +4321 -0
- package/dist/component/_generated/component.d.ts.map +1 -0
- package/dist/component/_generated/component.js +11 -0
- package/dist/component/_generated/component.js.map +1 -0
- package/dist/component/_generated/dataModel.d.ts +46 -0
- package/dist/component/_generated/dataModel.d.ts.map +1 -0
- package/dist/component/_generated/dataModel.js +11 -0
- package/dist/component/_generated/dataModel.js.map +1 -0
- package/dist/component/_generated/server.d.ts +121 -0
- package/dist/component/_generated/server.d.ts.map +1 -0
- package/dist/component/_generated/server.js +78 -0
- package/dist/component/_generated/server.js.map +1 -0
- package/dist/component/auditLog.d.ts +410 -0
- package/dist/component/auditLog.d.ts.map +1 -0
- package/dist/component/auditLog.js +607 -0
- package/dist/component/auditLog.js.map +1 -0
- package/dist/component/authorization.d.ts +323 -0
- package/dist/component/authorization.d.ts.map +1 -0
- package/dist/component/authorization.js +464 -0
- package/dist/component/authorization.js.map +1 -0
- package/dist/component/authorizationHooks.d.ts +184 -0
- package/dist/component/authorizationHooks.d.ts.map +1 -0
- package/dist/component/authorizationHooks.js +521 -0
- package/dist/component/authorizationHooks.js.map +1 -0
- package/dist/component/bulkOperations.d.ts +200 -0
- package/dist/component/bulkOperations.d.ts.map +1 -0
- package/dist/component/bulkOperations.js +568 -0
- package/dist/component/bulkOperations.js.map +1 -0
- package/dist/component/contentEntries.d.ts +719 -0
- package/dist/component/contentEntries.d.ts.map +1 -0
- package/dist/component/contentEntries.js +1617 -0
- package/dist/component/contentEntries.js.map +1 -0
- package/dist/component/contentEntryMutations.d.ts +505 -0
- package/dist/component/contentEntryMutations.d.ts.map +1 -0
- package/dist/component/contentEntryMutations.js +1009 -0
- package/dist/component/contentEntryMutations.js.map +1 -0
- package/dist/component/contentEntryValidation.d.ts +115 -0
- package/dist/component/contentEntryValidation.d.ts.map +1 -0
- package/dist/component/contentEntryValidation.js +546 -0
- package/dist/component/contentEntryValidation.js.map +1 -0
- package/dist/component/contentLock.d.ts +328 -0
- package/dist/component/contentLock.d.ts.map +1 -0
- package/dist/component/contentLock.js +471 -0
- package/dist/component/contentLock.js.map +1 -0
- package/dist/component/contentTypeMigration.d.ts +411 -0
- package/dist/component/contentTypeMigration.d.ts.map +1 -0
- package/dist/component/contentTypeMigration.js +805 -0
- package/dist/component/contentTypeMigration.js.map +1 -0
- package/dist/component/contentTypeMutations.d.ts +975 -0
- package/dist/component/contentTypeMutations.d.ts.map +1 -0
- package/dist/component/contentTypeMutations.js +768 -0
- package/dist/component/contentTypeMutations.js.map +1 -0
- package/dist/component/contentTypes.d.ts +538 -0
- package/dist/component/contentTypes.d.ts.map +1 -0
- package/dist/component/contentTypes.js +304 -0
- package/dist/component/contentTypes.js.map +1 -0
- package/dist/component/convex.config.d.ts +42 -0
- package/dist/component/convex.config.d.ts.map +1 -0
- package/dist/component/convex.config.js +43 -0
- package/dist/component/convex.config.js.map +1 -0
- package/dist/component/documentTypes.d.ts +186 -0
- package/dist/component/documentTypes.d.ts.map +1 -0
- package/dist/component/documentTypes.js +23 -0
- package/dist/component/documentTypes.js.map +1 -0
- package/dist/component/eventEmitter.d.ts +281 -0
- package/dist/component/eventEmitter.d.ts.map +1 -0
- package/dist/component/eventEmitter.js +300 -0
- package/dist/component/eventEmitter.js.map +1 -0
- package/dist/component/exportImport.d.ts +1120 -0
- package/dist/component/exportImport.d.ts.map +1 -0
- package/dist/component/exportImport.js +931 -0
- package/dist/component/exportImport.js.map +1 -0
- package/dist/component/index.d.ts +28 -0
- package/dist/component/index.d.ts.map +1 -0
- package/dist/component/index.js +142 -0
- package/dist/component/index.js.map +1 -0
- package/dist/component/lib/deepReferenceResolver.d.ts +252 -0
- package/dist/component/lib/deepReferenceResolver.d.ts.map +1 -0
- package/dist/component/lib/deepReferenceResolver.js +601 -0
- package/dist/component/lib/deepReferenceResolver.js.map +1 -0
- package/dist/component/lib/errors.d.ts +306 -0
- package/dist/component/lib/errors.d.ts.map +1 -0
- package/dist/component/lib/errors.js +407 -0
- package/dist/component/lib/errors.js.map +1 -0
- package/dist/component/lib/index.d.ts +10 -0
- package/dist/component/lib/index.d.ts.map +1 -0
- package/dist/component/lib/index.js +33 -0
- package/dist/component/lib/index.js.map +1 -0
- package/dist/component/lib/mediaReferenceResolver.d.ts +217 -0
- package/dist/component/lib/mediaReferenceResolver.d.ts.map +1 -0
- package/dist/component/lib/mediaReferenceResolver.js +326 -0
- package/dist/component/lib/mediaReferenceResolver.js.map +1 -0
- package/dist/component/lib/metadataExtractor.d.ts +245 -0
- package/dist/component/lib/metadataExtractor.d.ts.map +1 -0
- package/dist/component/lib/metadataExtractor.js +548 -0
- package/dist/component/lib/metadataExtractor.js.map +1 -0
- package/dist/component/lib/mutationAuth.d.ts +95 -0
- package/dist/component/lib/mutationAuth.d.ts.map +1 -0
- package/dist/component/lib/mutationAuth.js +146 -0
- package/dist/component/lib/mutationAuth.js.map +1 -0
- package/dist/component/lib/queries.d.ts +17 -0
- package/dist/component/lib/queries.d.ts.map +1 -0
- package/dist/component/lib/queries.js +49 -0
- package/dist/component/lib/queries.js.map +1 -0
- package/dist/component/lib/ragContentChunker.d.ts +423 -0
- package/dist/component/lib/ragContentChunker.d.ts.map +1 -0
- package/dist/component/lib/ragContentChunker.js +897 -0
- package/dist/component/lib/ragContentChunker.js.map +1 -0
- package/dist/component/lib/referenceResolver.d.ts +175 -0
- package/dist/component/lib/referenceResolver.d.ts.map +1 -0
- package/dist/component/lib/referenceResolver.js +293 -0
- package/dist/component/lib/referenceResolver.js.map +1 -0
- package/dist/component/lib/slugGenerator.d.ts +71 -0
- package/dist/component/lib/slugGenerator.d.ts.map +1 -0
- package/dist/component/lib/slugGenerator.js +207 -0
- package/dist/component/lib/slugGenerator.js.map +1 -0
- package/dist/component/lib/slugUniqueness.d.ts +131 -0
- package/dist/component/lib/slugUniqueness.d.ts.map +1 -0
- package/dist/component/lib/slugUniqueness.js +229 -0
- package/dist/component/lib/slugUniqueness.js.map +1 -0
- package/dist/component/lib/softDelete.d.ts +18 -0
- package/dist/component/lib/softDelete.d.ts.map +1 -0
- package/dist/component/lib/softDelete.js +29 -0
- package/dist/component/lib/softDelete.js.map +1 -0
- package/dist/component/localeFallbackChain.d.ts +410 -0
- package/dist/component/localeFallbackChain.d.ts.map +1 -0
- package/dist/component/localeFallbackChain.js +467 -0
- package/dist/component/localeFallbackChain.js.map +1 -0
- package/dist/component/localeFields.d.ts +508 -0
- package/dist/component/localeFields.d.ts.map +1 -0
- package/dist/component/localeFields.js +592 -0
- package/dist/component/localeFields.js.map +1 -0
- package/dist/component/mediaAssetMutations.d.ts +235 -0
- package/dist/component/mediaAssetMutations.d.ts.map +1 -0
- package/dist/component/mediaAssetMutations.js +558 -0
- package/dist/component/mediaAssetMutations.js.map +1 -0
- package/dist/component/mediaAssets.d.ts +168 -0
- package/dist/component/mediaAssets.d.ts.map +1 -0
- package/dist/component/mediaAssets.js +618 -0
- package/dist/component/mediaAssets.js.map +1 -0
- package/dist/component/mediaFolderMutations.d.ts +642 -0
- package/dist/component/mediaFolderMutations.d.ts.map +1 -0
- package/dist/component/mediaFolderMutations.js +849 -0
- package/dist/component/mediaFolderMutations.js.map +1 -0
- package/dist/component/mediaUploadMutations.d.ts +136 -0
- package/dist/component/mediaUploadMutations.d.ts.map +1 -0
- package/dist/component/mediaUploadMutations.js +205 -0
- package/dist/component/mediaUploadMutations.js.map +1 -0
- package/dist/component/mediaVariantMutations.d.ts +468 -0
- package/dist/component/mediaVariantMutations.d.ts.map +1 -0
- package/dist/component/mediaVariantMutations.js +737 -0
- package/dist/component/mediaVariantMutations.js.map +1 -0
- package/dist/component/mediaVariants.d.ts +525 -0
- package/dist/component/mediaVariants.d.ts.map +1 -0
- package/dist/component/mediaVariants.js +661 -0
- package/dist/component/mediaVariants.js.map +1 -0
- package/dist/component/ragContentIndexer.d.ts +595 -0
- package/dist/component/ragContentIndexer.d.ts.map +1 -0
- package/dist/component/ragContentIndexer.js +794 -0
- package/dist/component/ragContentIndexer.js.map +1 -0
- package/dist/component/rateLimitHooks.d.ts +266 -0
- package/dist/component/rateLimitHooks.d.ts.map +1 -0
- package/dist/component/rateLimitHooks.js +412 -0
- package/dist/component/rateLimitHooks.js.map +1 -0
- package/dist/component/roles.d.ts +649 -0
- package/dist/component/roles.d.ts.map +1 -0
- package/dist/component/roles.js +884 -0
- package/dist/component/roles.js.map +1 -0
- package/dist/component/scheduledPublish.d.ts +182 -0
- package/dist/component/scheduledPublish.d.ts.map +1 -0
- package/dist/component/scheduledPublish.js +304 -0
- package/dist/component/scheduledPublish.js.map +1 -0
- package/dist/component/schema.d.ts +4114 -0
- package/dist/component/schema.d.ts.map +1 -0
- package/dist/component/schema.js +469 -0
- package/dist/component/schema.js.map +1 -0
- package/dist/component/taxonomies.d.ts +476 -0
- package/dist/component/taxonomies.d.ts.map +1 -0
- package/dist/component/taxonomies.js +785 -0
- package/dist/component/taxonomies.js.map +1 -0
- package/dist/component/taxonomyMutations.d.ts +206 -0
- package/dist/component/taxonomyMutations.d.ts.map +1 -0
- package/dist/component/taxonomyMutations.js +1001 -0
- package/dist/component/taxonomyMutations.js.map +1 -0
- package/dist/component/trash.d.ts +265 -0
- package/dist/component/trash.d.ts.map +1 -0
- package/dist/component/trash.js +621 -0
- package/dist/component/trash.js.map +1 -0
- package/dist/component/types.d.ts +4 -0
- package/dist/component/types.d.ts.map +1 -0
- package/dist/component/types.js +2 -0
- package/dist/component/types.js.map +1 -0
- package/dist/component/userContext.d.ts +508 -0
- package/dist/component/userContext.d.ts.map +1 -0
- package/dist/component/userContext.js +615 -0
- package/dist/component/userContext.js.map +1 -0
- package/dist/component/validation.d.ts +387 -0
- package/dist/component/validation.d.ts.map +1 -0
- package/dist/component/validation.js +1052 -0
- package/dist/component/validation.js.map +1 -0
- package/dist/component/validators.d.ts +4645 -0
- package/dist/component/validators.d.ts.map +1 -0
- package/dist/component/validators.js +641 -0
- package/dist/component/validators.js.map +1 -0
- package/dist/component/versionMutations.d.ts +216 -0
- package/dist/component/versionMutations.d.ts.map +1 -0
- package/dist/component/versionMutations.js +321 -0
- package/dist/component/versionMutations.js.map +1 -0
- package/dist/component/webhookTrigger.d.ts +770 -0
- package/dist/component/webhookTrigger.d.ts.map +1 -0
- package/dist/component/webhookTrigger.js +1413 -0
- package/dist/component/webhookTrigger.js.map +1 -0
- package/dist/react/index.d.ts +316 -0
- package/dist/react/index.d.ts.map +1 -0
- package/dist/react/index.js +558 -0
- package/dist/react/index.js.map +1 -0
- package/dist/test.d.ts +2230 -0
- package/dist/test.d.ts.map +1 -0
- package/dist/test.js +1107 -0
- package/dist/test.js.map +1 -0
- package/package.json +95 -0
- package/src/cli/commands/admin.ts +104 -0
- package/src/cli/index.ts +21 -0
- package/src/cli/utils/detectConvexUrl.ts +54 -0
- package/src/cli/utils/openBrowser.ts +16 -0
- package/src/client/admin-config.ts +138 -0
- package/src/client/adminApi.ts +942 -0
- package/src/client/agentTools.ts +1311 -0
- package/src/client/argTypes.ts +316 -0
- package/src/client/field-types.ts +187 -0
- package/src/client/index.ts +1301 -0
- package/src/client/queryBuilder.ts +1100 -0
- package/src/client/schema/codegen.ts +500 -0
- package/src/client/schema/defineContentType.ts +501 -0
- package/src/client/schema/index.ts +169 -0
- package/src/client/schema/schemaDrift.ts +574 -0
- package/src/client/schema/typedClient.ts +688 -0
- package/src/client/schema/types.ts +666 -0
- package/src/client/types.ts +723 -0
- package/src/client/workflows.ts +141 -0
- package/src/client/wrapper.ts +4304 -0
- package/src/component/_generated/api.ts +140 -0
- package/src/component/_generated/component.ts +5029 -0
- package/src/component/_generated/dataModel.ts +60 -0
- package/src/component/_generated/server.ts +156 -0
- package/src/component/authorization.ts +647 -0
- package/src/component/authorizationHooks.ts +668 -0
- package/src/component/bulkOperations.ts +687 -0
- package/src/component/contentEntries.ts +1976 -0
- package/src/component/contentEntryMutations.ts +1223 -0
- package/src/component/contentEntryValidation.ts +707 -0
- package/src/component/contentLock.ts +550 -0
- package/src/component/contentTypeMigration.ts +1064 -0
- package/src/component/contentTypeMutations.ts +969 -0
- package/src/component/contentTypes.ts +346 -0
- package/src/component/convex.config.ts +44 -0
- package/src/component/documentTypes.ts +240 -0
- package/src/component/eventEmitter.ts +485 -0
- package/src/component/exportImport.ts +1169 -0
- package/src/component/index.ts +491 -0
- package/src/component/lib/deepReferenceResolver.ts +999 -0
- package/src/component/lib/errors.ts +816 -0
- package/src/component/lib/index.ts +145 -0
- package/src/component/lib/mediaReferenceResolver.ts +495 -0
- package/src/component/lib/metadataExtractor.ts +792 -0
- package/src/component/lib/mutationAuth.ts +199 -0
- package/src/component/lib/queries.ts +79 -0
- package/src/component/lib/ragContentChunker.ts +1371 -0
- package/src/component/lib/referenceResolver.ts +430 -0
- package/src/component/lib/slugGenerator.ts +262 -0
- package/src/component/lib/slugUniqueness.ts +333 -0
- package/src/component/lib/softDelete.ts +44 -0
- package/src/component/localeFallbackChain.ts +673 -0
- package/src/component/localeFields.ts +896 -0
- package/src/component/mediaAssetMutations.ts +725 -0
- package/src/component/mediaAssets.ts +932 -0
- package/src/component/mediaFolderMutations.ts +1046 -0
- package/src/component/mediaUploadMutations.ts +224 -0
- package/src/component/mediaVariantMutations.ts +900 -0
- package/src/component/mediaVariants.ts +793 -0
- package/src/component/ragContentIndexer.ts +1067 -0
- package/src/component/rateLimitHooks.ts +572 -0
- package/src/component/roles.ts +1360 -0
- package/src/component/scheduledPublish.ts +358 -0
- package/src/component/schema.ts +617 -0
- package/src/component/taxonomies.ts +949 -0
- package/src/component/taxonomyMutations.ts +1210 -0
- package/src/component/trash.ts +724 -0
- package/src/component/userContext.ts +898 -0
- package/src/component/validation.ts +1388 -0
- package/src/component/validators.ts +949 -0
- package/src/component/versionMutations.ts +392 -0
- package/src/component/webhookTrigger.ts +1922 -0
- package/src/react/index.ts +898 -0
- package/src/test.ts +1580 -0
|
@@ -0,0 +1,673 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Locale Fallback Chain Configuration and Utilities
|
|
3
|
+
*
|
|
4
|
+
* This module provides configuration and utility functions for locale fallback chains.
|
|
5
|
+
* When content isn't available in a requested locale, the system falls back through
|
|
6
|
+
* a configured chain until content is found.
|
|
7
|
+
*
|
|
8
|
+
* @example
|
|
9
|
+
* ```typescript
|
|
10
|
+
* // Configure fallback chains
|
|
11
|
+
* const config: LocaleFallbackConfig = {
|
|
12
|
+
* defaultLocale: "en-US",
|
|
13
|
+
* fallbackChains: {
|
|
14
|
+
* "es-MX": ["es-ES", "en-US"], // Mexican Spanish -> Spain Spanish -> US English
|
|
15
|
+
* "es-ES": ["en-US"], // Spain Spanish -> US English
|
|
16
|
+
* "fr-CA": ["fr-FR", "en-US"], // Canadian French -> France French -> US English
|
|
17
|
+
* "zh-Hans-CN": ["zh-Hans", "en-US"], // Simplified Chinese (China) -> Simplified Chinese -> US English
|
|
18
|
+
* },
|
|
19
|
+
* };
|
|
20
|
+
*
|
|
21
|
+
* // Resolve fallback chain for a locale
|
|
22
|
+
* const chain = resolveFallbackChain("es-MX", config);
|
|
23
|
+
* // Returns: ["es-ES", "en-US", "en-US"] -> deduplicated to ["es-ES", "en-US"]
|
|
24
|
+
* ```
|
|
25
|
+
*
|
|
26
|
+
* @module localeFallbackChain
|
|
27
|
+
*/
|
|
28
|
+
|
|
29
|
+
import type { LocaleResolutionOptions } from "./localeFields.js";
|
|
30
|
+
|
|
31
|
+
// =============================================================================
|
|
32
|
+
// Types
|
|
33
|
+
// =============================================================================
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* BCP 47 locale code (e.g., "en-US", "zh-Hans", "zh-Hans-CN").
|
|
37
|
+
*/
|
|
38
|
+
export type LocaleCode = string;
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Configuration for locale fallback behavior.
|
|
42
|
+
*
|
|
43
|
+
* Defines how the system should resolve content when the requested locale
|
|
44
|
+
* is not available. Fallback chains are tried in order until content is found.
|
|
45
|
+
*/
|
|
46
|
+
export interface LocaleFallbackConfig {
|
|
47
|
+
/**
|
|
48
|
+
* The default locale used as the final fallback when all other options are exhausted.
|
|
49
|
+
* This should be the locale with the most complete content.
|
|
50
|
+
*
|
|
51
|
+
* @default "en"
|
|
52
|
+
*/
|
|
53
|
+
defaultLocale: LocaleCode;
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Mapping of locale codes to their fallback chains.
|
|
57
|
+
* Each locale can have an ordered array of fallback locales to try.
|
|
58
|
+
*
|
|
59
|
+
* @example
|
|
60
|
+
* ```typescript
|
|
61
|
+
* fallbackChains: {
|
|
62
|
+
* "es-MX": ["es-ES", "en-US"], // Try Spain Spanish, then US English
|
|
63
|
+
* "es-AR": ["es-ES", "en-US"], // Argentine Spanish also falls back to Spain Spanish
|
|
64
|
+
* "pt-BR": ["pt-PT", "en-US"], // Brazilian Portuguese -> Portugal Portuguese
|
|
65
|
+
* }
|
|
66
|
+
* ```
|
|
67
|
+
*/
|
|
68
|
+
fallbackChains?: Record<LocaleCode, LocaleCode[]>;
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Whether to automatically generate fallback chains based on locale hierarchy.
|
|
72
|
+
*
|
|
73
|
+
* When enabled, the system will automatically create fallback chains based on
|
|
74
|
+
* the BCP 47 locale structure:
|
|
75
|
+
* - "zh-Hans-CN" -> ["zh-Hans", "zh", defaultLocale]
|
|
76
|
+
* - "en-US" -> ["en", defaultLocale]
|
|
77
|
+
*
|
|
78
|
+
* Explicit fallbackChains take precedence over auto-generated ones.
|
|
79
|
+
*
|
|
80
|
+
* @default true
|
|
81
|
+
*/
|
|
82
|
+
autoGenerateFallbacks?: boolean;
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* List of supported locales. If provided, fallback chains will only include
|
|
86
|
+
* locales from this list.
|
|
87
|
+
*
|
|
88
|
+
* @example
|
|
89
|
+
* ```typescript
|
|
90
|
+
* supportedLocales: ["en-US", "es-ES", "fr-FR", "de-DE"]
|
|
91
|
+
* ```
|
|
92
|
+
*/
|
|
93
|
+
supportedLocales?: LocaleCode[];
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Result of resolving a fallback chain for a locale.
|
|
98
|
+
*/
|
|
99
|
+
export interface ResolvedFallbackChain {
|
|
100
|
+
/**
|
|
101
|
+
* The original locale that was requested.
|
|
102
|
+
*/
|
|
103
|
+
requestedLocale: LocaleCode;
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* The complete fallback chain in priority order.
|
|
107
|
+
* Does not include the requested locale itself.
|
|
108
|
+
*/
|
|
109
|
+
fallbackChain: LocaleCode[];
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* The default locale (final fallback).
|
|
113
|
+
*/
|
|
114
|
+
defaultLocale: LocaleCode;
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* Whether the chain was auto-generated or explicitly configured.
|
|
118
|
+
*/
|
|
119
|
+
isAutoGenerated: boolean;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* Options for building a fallback chain.
|
|
124
|
+
*/
|
|
125
|
+
export interface BuildFallbackChainOptions {
|
|
126
|
+
/**
|
|
127
|
+
* Whether to include the default locale in the chain.
|
|
128
|
+
* @default true
|
|
129
|
+
*/
|
|
130
|
+
includeDefault?: boolean;
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* Whether to deduplicate the chain (remove duplicate locales).
|
|
134
|
+
* @default true
|
|
135
|
+
*/
|
|
136
|
+
deduplicate?: boolean;
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* Maximum length of the fallback chain.
|
|
140
|
+
* @default 10
|
|
141
|
+
*/
|
|
142
|
+
maxLength?: number;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
// =============================================================================
|
|
146
|
+
// Constants
|
|
147
|
+
// =============================================================================
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
* Default fallback configuration.
|
|
151
|
+
*/
|
|
152
|
+
export const DEFAULT_FALLBACK_CONFIG: Required<LocaleFallbackConfig> = {
|
|
153
|
+
defaultLocale: "en",
|
|
154
|
+
fallbackChains: {},
|
|
155
|
+
autoGenerateFallbacks: true,
|
|
156
|
+
supportedLocales: [],
|
|
157
|
+
};
|
|
158
|
+
|
|
159
|
+
// =============================================================================
|
|
160
|
+
// Locale Parsing Utilities
|
|
161
|
+
// =============================================================================
|
|
162
|
+
|
|
163
|
+
/**
|
|
164
|
+
* Parsed components of a BCP 47 locale code.
|
|
165
|
+
*/
|
|
166
|
+
export interface ParsedLocale {
|
|
167
|
+
/**
|
|
168
|
+
* The language code (2-3 lowercase letters).
|
|
169
|
+
* @example "en", "zh", "pt"
|
|
170
|
+
*/
|
|
171
|
+
language: string;
|
|
172
|
+
|
|
173
|
+
/**
|
|
174
|
+
* The script code (4 letters, title case), if present.
|
|
175
|
+
* @example "Hans", "Hant", "Latn"
|
|
176
|
+
*/
|
|
177
|
+
script?: string;
|
|
178
|
+
|
|
179
|
+
/**
|
|
180
|
+
* The region code (2 uppercase letters), if present.
|
|
181
|
+
* @example "US", "CN", "BR"
|
|
182
|
+
*/
|
|
183
|
+
region?: string;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
/**
|
|
187
|
+
* Parses a BCP 47 locale code into its components.
|
|
188
|
+
*
|
|
189
|
+
* Supports the following formats:
|
|
190
|
+
* - "en" (language only)
|
|
191
|
+
* - "en-US" (language + region)
|
|
192
|
+
* - "zh-Hans" (language + script)
|
|
193
|
+
* - "zh-Hans-CN" (language + script + region)
|
|
194
|
+
*
|
|
195
|
+
* @param locale - The locale code to parse
|
|
196
|
+
* @returns The parsed locale components, or null if invalid
|
|
197
|
+
*
|
|
198
|
+
* @example
|
|
199
|
+
* ```typescript
|
|
200
|
+
* parseLocale("en-US");
|
|
201
|
+
* // Returns: { language: "en", region: "US" }
|
|
202
|
+
*
|
|
203
|
+
* parseLocale("zh-Hans-CN");
|
|
204
|
+
* // Returns: { language: "zh", script: "Hans", region: "CN" }
|
|
205
|
+
*
|
|
206
|
+
* parseLocale("invalid");
|
|
207
|
+
* // Returns: null
|
|
208
|
+
* ```
|
|
209
|
+
*/
|
|
210
|
+
export function parseLocale(locale: LocaleCode): ParsedLocale | null {
|
|
211
|
+
if (!locale || typeof locale !== "string") {
|
|
212
|
+
return null;
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
// Pattern: language[-Script][-REGION]
|
|
216
|
+
// Language: 2-3 lowercase letters
|
|
217
|
+
// Script: 4 letters, title case (optional)
|
|
218
|
+
// Region: 2 uppercase letters (optional)
|
|
219
|
+
const pattern = /^([a-z]{2,3})(?:-([A-Z][a-z]{3}))?(?:-([A-Z]{2}))?$/;
|
|
220
|
+
const match = locale.match(pattern);
|
|
221
|
+
|
|
222
|
+
if (!match) {
|
|
223
|
+
// Try simpler patterns
|
|
224
|
+
// Just language
|
|
225
|
+
if (/^[a-z]{2,3}$/.test(locale)) {
|
|
226
|
+
return { language: locale };
|
|
227
|
+
}
|
|
228
|
+
return null;
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
const [, language, script, region] = match;
|
|
232
|
+
|
|
233
|
+
const result: ParsedLocale = { language };
|
|
234
|
+
if (script) result.script = script;
|
|
235
|
+
if (region) result.region = region;
|
|
236
|
+
|
|
237
|
+
return result;
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
/**
|
|
241
|
+
* Formats parsed locale components back into a BCP 47 locale code.
|
|
242
|
+
*
|
|
243
|
+
* @param parsed - The parsed locale components
|
|
244
|
+
* @returns The formatted locale code
|
|
245
|
+
*
|
|
246
|
+
* @example
|
|
247
|
+
* ```typescript
|
|
248
|
+
* formatLocale({ language: "en", region: "US" });
|
|
249
|
+
* // Returns: "en-US"
|
|
250
|
+
*
|
|
251
|
+
* formatLocale({ language: "zh", script: "Hans", region: "CN" });
|
|
252
|
+
* // Returns: "zh-Hans-CN"
|
|
253
|
+
* ```
|
|
254
|
+
*/
|
|
255
|
+
export function formatLocale(parsed: ParsedLocale): LocaleCode {
|
|
256
|
+
let result = parsed.language;
|
|
257
|
+
if (parsed.script) result += `-${parsed.script}`;
|
|
258
|
+
if (parsed.region) result += `-${parsed.region}`;
|
|
259
|
+
return result;
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
/**
|
|
263
|
+
* Generates the locale hierarchy (parent locales) for a given locale.
|
|
264
|
+
*
|
|
265
|
+
* @param locale - The locale to get hierarchy for
|
|
266
|
+
* @returns Array of parent locales from most specific to least specific
|
|
267
|
+
*
|
|
268
|
+
* @example
|
|
269
|
+
* ```typescript
|
|
270
|
+
* getLocaleHierarchy("zh-Hans-CN");
|
|
271
|
+
* // Returns: ["zh-Hans", "zh"]
|
|
272
|
+
*
|
|
273
|
+
* getLocaleHierarchy("en-US");
|
|
274
|
+
* // Returns: ["en"]
|
|
275
|
+
*
|
|
276
|
+
* getLocaleHierarchy("en");
|
|
277
|
+
* // Returns: []
|
|
278
|
+
* ```
|
|
279
|
+
*/
|
|
280
|
+
export function getLocaleHierarchy(locale: LocaleCode): LocaleCode[] {
|
|
281
|
+
const parsed = parseLocale(locale);
|
|
282
|
+
if (!parsed) return [];
|
|
283
|
+
|
|
284
|
+
const hierarchy: LocaleCode[] = [];
|
|
285
|
+
|
|
286
|
+
// If we have region, add without region
|
|
287
|
+
if (parsed.region) {
|
|
288
|
+
if (parsed.script) {
|
|
289
|
+
// zh-Hans-CN -> zh-Hans
|
|
290
|
+
hierarchy.push(formatLocale({ language: parsed.language, script: parsed.script }));
|
|
291
|
+
}
|
|
292
|
+
// zh-Hans-CN -> zh, or en-US -> en
|
|
293
|
+
hierarchy.push(parsed.language);
|
|
294
|
+
} else if (parsed.script) {
|
|
295
|
+
// zh-Hans -> zh
|
|
296
|
+
hierarchy.push(parsed.language);
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
return hierarchy;
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
// =============================================================================
|
|
303
|
+
// Fallback Chain Resolution
|
|
304
|
+
// =============================================================================
|
|
305
|
+
|
|
306
|
+
/**
|
|
307
|
+
* Resolves the complete fallback chain for a locale.
|
|
308
|
+
*
|
|
309
|
+
* The resolution order is:
|
|
310
|
+
* 1. Explicit fallback chain from configuration (if defined)
|
|
311
|
+
* 2. Auto-generated hierarchy-based chain (if enabled)
|
|
312
|
+
* 3. Default locale as final fallback
|
|
313
|
+
*
|
|
314
|
+
* @param locale - The locale to resolve the fallback chain for
|
|
315
|
+
* @param config - The fallback configuration
|
|
316
|
+
* @param options - Options for building the chain
|
|
317
|
+
* @returns The resolved fallback chain
|
|
318
|
+
*
|
|
319
|
+
* @example
|
|
320
|
+
* ```typescript
|
|
321
|
+
* const config: LocaleFallbackConfig = {
|
|
322
|
+
* defaultLocale: "en-US",
|
|
323
|
+
* fallbackChains: {
|
|
324
|
+
* "es-MX": ["es-ES"],
|
|
325
|
+
* },
|
|
326
|
+
* };
|
|
327
|
+
*
|
|
328
|
+
* // Explicit chain
|
|
329
|
+
* resolveFallbackChain("es-MX", config);
|
|
330
|
+
* // Returns: { requestedLocale: "es-MX", fallbackChain: ["es-ES", "en-US"], ... }
|
|
331
|
+
*
|
|
332
|
+
* // Auto-generated chain
|
|
333
|
+
* resolveFallbackChain("fr-CA", config);
|
|
334
|
+
* // Returns: { requestedLocale: "fr-CA", fallbackChain: ["fr", "en-US"], ... }
|
|
335
|
+
* ```
|
|
336
|
+
*/
|
|
337
|
+
export function resolveFallbackChain(
|
|
338
|
+
locale: LocaleCode,
|
|
339
|
+
config: LocaleFallbackConfig = DEFAULT_FALLBACK_CONFIG,
|
|
340
|
+
options: BuildFallbackChainOptions = {}
|
|
341
|
+
): ResolvedFallbackChain {
|
|
342
|
+
const {
|
|
343
|
+
includeDefault = true,
|
|
344
|
+
deduplicate = true,
|
|
345
|
+
maxLength = 10,
|
|
346
|
+
} = options;
|
|
347
|
+
|
|
348
|
+
const {
|
|
349
|
+
defaultLocale = DEFAULT_FALLBACK_CONFIG.defaultLocale,
|
|
350
|
+
fallbackChains = {},
|
|
351
|
+
autoGenerateFallbacks = true,
|
|
352
|
+
supportedLocales = [],
|
|
353
|
+
} = config;
|
|
354
|
+
|
|
355
|
+
let chain: LocaleCode[] = [];
|
|
356
|
+
let isAutoGenerated = false;
|
|
357
|
+
|
|
358
|
+
// Check for explicit fallback chain
|
|
359
|
+
if (fallbackChains[locale]) {
|
|
360
|
+
chain = [...fallbackChains[locale]];
|
|
361
|
+
} else if (autoGenerateFallbacks) {
|
|
362
|
+
// Auto-generate based on locale hierarchy
|
|
363
|
+
chain = getLocaleHierarchy(locale);
|
|
364
|
+
isAutoGenerated = true;
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
// Add default locale if not already in chain
|
|
368
|
+
if (includeDefault && !chain.includes(defaultLocale)) {
|
|
369
|
+
chain.push(defaultLocale);
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
// Filter to supported locales if specified
|
|
373
|
+
if (supportedLocales.length > 0) {
|
|
374
|
+
chain = chain.filter((l) => supportedLocales.includes(l));
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
// Deduplicate
|
|
378
|
+
if (deduplicate) {
|
|
379
|
+
chain = [...new Set(chain)];
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
// Remove the requested locale itself if present
|
|
383
|
+
chain = chain.filter((l) => l !== locale);
|
|
384
|
+
|
|
385
|
+
// Limit length
|
|
386
|
+
if (chain.length > maxLength) {
|
|
387
|
+
chain = chain.slice(0, maxLength);
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
return {
|
|
391
|
+
requestedLocale: locale,
|
|
392
|
+
fallbackChain: chain,
|
|
393
|
+
defaultLocale,
|
|
394
|
+
isAutoGenerated,
|
|
395
|
+
};
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
/**
|
|
399
|
+
* Gets the fallback chain as a simple array of locale codes.
|
|
400
|
+
*
|
|
401
|
+
* This is a convenience function for use with `getLocalizedValue`.
|
|
402
|
+
*
|
|
403
|
+
* @param locale - The locale to get fallback chain for
|
|
404
|
+
* @param config - The fallback configuration
|
|
405
|
+
* @returns Array of fallback locale codes
|
|
406
|
+
*
|
|
407
|
+
* @example
|
|
408
|
+
* ```typescript
|
|
409
|
+
* const chain = getFallbackChain("es-MX", config);
|
|
410
|
+
* // Returns: ["es-ES", "en-US"]
|
|
411
|
+
*
|
|
412
|
+
* // Use with getLocalizedValue
|
|
413
|
+
* const result = getLocalizedValue(value, {
|
|
414
|
+
* locale: "es-MX",
|
|
415
|
+
* fallbackChain: chain,
|
|
416
|
+
* });
|
|
417
|
+
* ```
|
|
418
|
+
*/
|
|
419
|
+
export function getFallbackChain(
|
|
420
|
+
locale: LocaleCode,
|
|
421
|
+
config: LocaleFallbackConfig = DEFAULT_FALLBACK_CONFIG
|
|
422
|
+
): LocaleCode[] {
|
|
423
|
+
return resolveFallbackChain(locale, config).fallbackChain;
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
// =============================================================================
|
|
427
|
+
// Configuration Utilities
|
|
428
|
+
// =============================================================================
|
|
429
|
+
|
|
430
|
+
/**
|
|
431
|
+
* Creates a LocaleFallbackConfig with defaults applied.
|
|
432
|
+
*
|
|
433
|
+
* @param config - Partial configuration to merge with defaults
|
|
434
|
+
* @returns Complete configuration with defaults
|
|
435
|
+
*
|
|
436
|
+
* @example
|
|
437
|
+
* ```typescript
|
|
438
|
+
* const config = createFallbackConfig({
|
|
439
|
+
* defaultLocale: "en-US",
|
|
440
|
+
* fallbackChains: {
|
|
441
|
+
* "es-MX": ["es-ES"],
|
|
442
|
+
* },
|
|
443
|
+
* });
|
|
444
|
+
* ```
|
|
445
|
+
*/
|
|
446
|
+
export function createFallbackConfig(
|
|
447
|
+
config: Partial<LocaleFallbackConfig> = {}
|
|
448
|
+
): Required<LocaleFallbackConfig> {
|
|
449
|
+
return {
|
|
450
|
+
defaultLocale: config.defaultLocale ?? DEFAULT_FALLBACK_CONFIG.defaultLocale,
|
|
451
|
+
fallbackChains: config.fallbackChains ?? DEFAULT_FALLBACK_CONFIG.fallbackChains,
|
|
452
|
+
autoGenerateFallbacks: config.autoGenerateFallbacks ?? DEFAULT_FALLBACK_CONFIG.autoGenerateFallbacks,
|
|
453
|
+
supportedLocales: config.supportedLocales ?? DEFAULT_FALLBACK_CONFIG.supportedLocales,
|
|
454
|
+
};
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
/**
|
|
458
|
+
* Validates a LocaleFallbackConfig for common issues.
|
|
459
|
+
*
|
|
460
|
+
* @param config - The configuration to validate
|
|
461
|
+
* @returns Array of validation errors (empty if valid)
|
|
462
|
+
*
|
|
463
|
+
* @example
|
|
464
|
+
* ```typescript
|
|
465
|
+
* const errors = validateFallbackConfig({
|
|
466
|
+
* defaultLocale: "en-US",
|
|
467
|
+
* fallbackChains: {
|
|
468
|
+
* "es-MX": ["invalid-locale"],
|
|
469
|
+
* },
|
|
470
|
+
* supportedLocales: ["en-US", "es-ES"],
|
|
471
|
+
* });
|
|
472
|
+
* // Returns: ["Fallback chain for 'es-MX' contains unsupported locale: 'invalid-locale'"]
|
|
473
|
+
* ```
|
|
474
|
+
*/
|
|
475
|
+
export function validateFallbackConfig(config: LocaleFallbackConfig): string[] {
|
|
476
|
+
const errors: string[] = [];
|
|
477
|
+
const { defaultLocale, fallbackChains = {}, supportedLocales = [] } = config;
|
|
478
|
+
|
|
479
|
+
// Check default locale
|
|
480
|
+
if (!defaultLocale) {
|
|
481
|
+
errors.push("defaultLocale is required");
|
|
482
|
+
} else if (!parseLocale(defaultLocale)) {
|
|
483
|
+
errors.push(`Invalid defaultLocale format: '${defaultLocale}'`);
|
|
484
|
+
}
|
|
485
|
+
|
|
486
|
+
// Check supported locales include default
|
|
487
|
+
if (supportedLocales.length > 0 && defaultLocale && !supportedLocales.includes(defaultLocale)) {
|
|
488
|
+
errors.push(`defaultLocale '${defaultLocale}' is not in supportedLocales`);
|
|
489
|
+
}
|
|
490
|
+
|
|
491
|
+
// Validate fallback chains
|
|
492
|
+
for (const [locale, chain] of Object.entries(fallbackChains)) {
|
|
493
|
+
// Check locale format
|
|
494
|
+
if (!parseLocale(locale)) {
|
|
495
|
+
errors.push(`Invalid locale format in fallbackChains: '${locale}'`);
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
// Check chain items
|
|
499
|
+
for (const fallback of chain) {
|
|
500
|
+
if (!parseLocale(fallback)) {
|
|
501
|
+
errors.push(`Invalid fallback locale format for '${locale}': '${fallback}'`);
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
// Check against supported locales
|
|
505
|
+
if (supportedLocales.length > 0 && !supportedLocales.includes(fallback)) {
|
|
506
|
+
errors.push(`Fallback chain for '${locale}' contains unsupported locale: '${fallback}'`);
|
|
507
|
+
}
|
|
508
|
+
}
|
|
509
|
+
|
|
510
|
+
// Check for circular references
|
|
511
|
+
if (chain.includes(locale)) {
|
|
512
|
+
errors.push(`Fallback chain for '${locale}' contains self-reference`);
|
|
513
|
+
}
|
|
514
|
+
}
|
|
515
|
+
|
|
516
|
+
// Validate supported locales formats
|
|
517
|
+
for (const locale of supportedLocales) {
|
|
518
|
+
if (!parseLocale(locale)) {
|
|
519
|
+
errors.push(`Invalid locale format in supportedLocales: '${locale}'`);
|
|
520
|
+
}
|
|
521
|
+
}
|
|
522
|
+
|
|
523
|
+
return errors;
|
|
524
|
+
}
|
|
525
|
+
|
|
526
|
+
// =============================================================================
|
|
527
|
+
// Integration with LocaleResolutionOptions
|
|
528
|
+
// =============================================================================
|
|
529
|
+
|
|
530
|
+
/**
|
|
531
|
+
* Builds LocaleResolutionOptions from a locale and fallback configuration.
|
|
532
|
+
*
|
|
533
|
+
* This function creates the options object needed by `getLocalizedValue` and
|
|
534
|
+
* `resolveContentData` from the locale fallback configuration.
|
|
535
|
+
*
|
|
536
|
+
* @param locale - The requested locale
|
|
537
|
+
* @param config - The fallback configuration
|
|
538
|
+
* @returns LocaleResolutionOptions for use with locale resolution functions
|
|
539
|
+
*
|
|
540
|
+
* @example
|
|
541
|
+
* ```typescript
|
|
542
|
+
* const config: LocaleFallbackConfig = {
|
|
543
|
+
* defaultLocale: "en-US",
|
|
544
|
+
* fallbackChains: {
|
|
545
|
+
* "es-MX": ["es-ES"],
|
|
546
|
+
* },
|
|
547
|
+
* };
|
|
548
|
+
*
|
|
549
|
+
* const options = buildLocaleResolutionOptions("es-MX", config);
|
|
550
|
+
* // Returns: {
|
|
551
|
+
* // locale: "es-MX",
|
|
552
|
+
* // fallbackChain: ["es-ES", "en-US"],
|
|
553
|
+
* // defaultLocale: "en-US"
|
|
554
|
+
* // }
|
|
555
|
+
*
|
|
556
|
+
* // Use with getLocalizedValue
|
|
557
|
+
* const result = getLocalizedValue(value, options);
|
|
558
|
+
* ```
|
|
559
|
+
*/
|
|
560
|
+
export function buildLocaleResolutionOptions(
|
|
561
|
+
locale: LocaleCode,
|
|
562
|
+
config: LocaleFallbackConfig = DEFAULT_FALLBACK_CONFIG
|
|
563
|
+
): LocaleResolutionOptions {
|
|
564
|
+
const resolved = resolveFallbackChain(locale, config);
|
|
565
|
+
|
|
566
|
+
return {
|
|
567
|
+
locale,
|
|
568
|
+
fallbackChain: resolved.fallbackChain,
|
|
569
|
+
defaultLocale: resolved.defaultLocale,
|
|
570
|
+
};
|
|
571
|
+
}
|
|
572
|
+
|
|
573
|
+
// =============================================================================
|
|
574
|
+
// Common Fallback Chain Presets
|
|
575
|
+
// =============================================================================
|
|
576
|
+
|
|
577
|
+
/**
|
|
578
|
+
* Preset fallback configurations for common localization scenarios.
|
|
579
|
+
*/
|
|
580
|
+
export const FALLBACK_PRESETS = {
|
|
581
|
+
/**
|
|
582
|
+
* Spanish locale family fallback chain.
|
|
583
|
+
* Regional Spanish variants fall back to Spain Spanish, then English.
|
|
584
|
+
*/
|
|
585
|
+
spanish: {
|
|
586
|
+
"es-MX": ["es-ES", "en"], // Mexican Spanish
|
|
587
|
+
"es-AR": ["es-ES", "en"], // Argentine Spanish
|
|
588
|
+
"es-CO": ["es-ES", "en"], // Colombian Spanish
|
|
589
|
+
"es-CL": ["es-ES", "en"], // Chilean Spanish
|
|
590
|
+
"es-PE": ["es-ES", "en"], // Peruvian Spanish
|
|
591
|
+
"es-VE": ["es-ES", "en"], // Venezuelan Spanish
|
|
592
|
+
"es-ES": ["en"], // Spain Spanish
|
|
593
|
+
},
|
|
594
|
+
|
|
595
|
+
/**
|
|
596
|
+
* Portuguese locale family fallback chain.
|
|
597
|
+
* Brazilian Portuguese falls back to Portugal Portuguese, then English.
|
|
598
|
+
*/
|
|
599
|
+
portuguese: {
|
|
600
|
+
"pt-BR": ["pt-PT", "en"], // Brazilian Portuguese
|
|
601
|
+
"pt-PT": ["en"], // Portugal Portuguese
|
|
602
|
+
},
|
|
603
|
+
|
|
604
|
+
/**
|
|
605
|
+
* Chinese locale family fallback chain.
|
|
606
|
+
* Simplified and Traditional Chinese with regional variants.
|
|
607
|
+
*/
|
|
608
|
+
chinese: {
|
|
609
|
+
"zh-Hans-CN": ["zh-Hans", "zh", "en"], // Simplified Chinese (China)
|
|
610
|
+
"zh-Hans-SG": ["zh-Hans", "zh", "en"], // Simplified Chinese (Singapore)
|
|
611
|
+
"zh-Hant-TW": ["zh-Hant", "zh", "en"], // Traditional Chinese (Taiwan)
|
|
612
|
+
"zh-Hant-HK": ["zh-Hant", "zh", "en"], // Traditional Chinese (Hong Kong)
|
|
613
|
+
"zh-Hans": ["zh", "en"], // Simplified Chinese
|
|
614
|
+
"zh-Hant": ["zh", "en"], // Traditional Chinese
|
|
615
|
+
},
|
|
616
|
+
|
|
617
|
+
/**
|
|
618
|
+
* French locale family fallback chain.
|
|
619
|
+
*/
|
|
620
|
+
french: {
|
|
621
|
+
"fr-CA": ["fr-FR", "en"], // Canadian French
|
|
622
|
+
"fr-BE": ["fr-FR", "en"], // Belgian French
|
|
623
|
+
"fr-CH": ["fr-FR", "en"], // Swiss French
|
|
624
|
+
"fr-FR": ["en"], // France French
|
|
625
|
+
},
|
|
626
|
+
|
|
627
|
+
/**
|
|
628
|
+
* German locale family fallback chain.
|
|
629
|
+
*/
|
|
630
|
+
german: {
|
|
631
|
+
"de-AT": ["de-DE", "en"], // Austrian German
|
|
632
|
+
"de-CH": ["de-DE", "en"], // Swiss German
|
|
633
|
+
"de-DE": ["en"], // Germany German
|
|
634
|
+
},
|
|
635
|
+
|
|
636
|
+
/**
|
|
637
|
+
* English locale family fallback chain.
|
|
638
|
+
*/
|
|
639
|
+
english: {
|
|
640
|
+
"en-GB": ["en-US", "en"], // British English
|
|
641
|
+
"en-AU": ["en-GB", "en-US", "en"], // Australian English
|
|
642
|
+
"en-CA": ["en-US", "en"], // Canadian English
|
|
643
|
+
"en-NZ": ["en-AU", "en-GB", "en"], // New Zealand English
|
|
644
|
+
"en-US": ["en"], // US English
|
|
645
|
+
},
|
|
646
|
+
} as const;
|
|
647
|
+
|
|
648
|
+
/**
|
|
649
|
+
* Merges multiple fallback chain presets into a single configuration.
|
|
650
|
+
*
|
|
651
|
+
* @param presets - Array of preset names to merge
|
|
652
|
+
* @returns Combined fallback chains
|
|
653
|
+
*
|
|
654
|
+
* @example
|
|
655
|
+
* ```typescript
|
|
656
|
+
* const chains = mergeFallbackPresets(["spanish", "portuguese"]);
|
|
657
|
+
* // Returns merged chains for both Spanish and Portuguese locales
|
|
658
|
+
* ```
|
|
659
|
+
*/
|
|
660
|
+
export function mergeFallbackPresets(
|
|
661
|
+
presets: (keyof typeof FALLBACK_PRESETS)[]
|
|
662
|
+
): Record<LocaleCode, LocaleCode[]> {
|
|
663
|
+
const merged: Record<LocaleCode, LocaleCode[]> = {};
|
|
664
|
+
|
|
665
|
+
for (const presetName of presets) {
|
|
666
|
+
const preset = FALLBACK_PRESETS[presetName];
|
|
667
|
+
if (preset) {
|
|
668
|
+
Object.assign(merged, preset);
|
|
669
|
+
}
|
|
670
|
+
}
|
|
671
|
+
|
|
672
|
+
return merged;
|
|
673
|
+
}
|