react-native-intlayer 9.2.0 → 9.3.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/README.md +24 -24
- package/dist/cjs/client/format/index.cjs +0 -1
- package/dist/cjs/configMetroIntlayer.cjs +2 -1
- package/dist/cjs/configMetroIntlayer.cjs.map +1 -1
- package/dist/cjs/html/index.cjs +0 -1
- package/dist/cjs/intlayerPolyfill.cjs +0 -1
- package/dist/cjs/intlayerPolyfill.cjs.map +1 -1
- package/dist/cjs/markdown/index.cjs +0 -1
- package/dist/esm/configMetroIntlayer.mjs +2 -1
- package/dist/esm/configMetroIntlayer.mjs.map +1 -1
- package/package.json +8 -8
package/README.md
CHANGED
|
@@ -47,27 +47,27 @@ With **per-locale content files**, **TypeScript autocompletion**, **tree-shakabl
|
|
|
47
47
|
|
|
48
48
|
## Keys benefits of Intlayer:
|
|
49
49
|
|
|
50
|
-
| Feature | Description
|
|
51
|
-
| --------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
52
|
-
| <img src="https://github.com/aymericzip/intlayer/blob/main/docs/assets/frameworks.png?raw=true" alt="Feature" width="700"> | **Cross-Frameworks Support**<br><br>Intlayer is compatible with all major frameworks and libraries, including Next.js, React, Vite, Vue.js, Nuxt, Preact, Express, and more.
|
|
53
|
-
| <img src="https://github.com/aymericzip/intlayer/blob/main/docs/assets/javascript_content_management.jpg?raw=true" alt="Feature" width="700"> | **JavaScript-Powered Content Management**<br><br>Harness the flexibility of JavaScript to define and manage your content efficiently. <br><br> - [Content declaration](https://intlayer.org/doc/concept/content)
|
|
54
|
-
| <img src="https://github.com/aymericzip/intlayer/blob/main/docs/assets/per_locale_content_declaration_file.png?raw=true" alt="Feature" width="700"> | **Per-Locale Content Declaration File**<br><br>Speed up your development by declaring your content once, before auto generation.<br><br> - [Per-Locale Content Declaration File](https://intlayer.org/doc/concept/per-locale-file)
|
|
55
|
-
| <img src="https://github.com/aymericzip/intlayer/blob/main/docs/assets/compiler.jpg?raw=true" alt="Feature" width="700"> | **Compiler**<br><br>The Intlayer Compiler extract automatically the content from the components and generate the dictionary files.<br><br> - [Compiler](https://intlayer.org/doc/compiler)
|
|
56
|
-
| <img src="https://github.com/aymericzip/intlayer/blob/main/docs/assets/autocompletion.png?raw=true" alt="Feature" width="700"> | **Type-Safe Environment**<br><br>Leverage TypeScript to ensure your content definitions and code are error-free, while also benefiting from IDE autocompletion.<br><br> - [TypeScript configuration](https://intlayer.org/doc/environment/vite-and-react#configure-typescript)
|
|
57
|
-
| <img src="https://github.com/aymericzip/intlayer/blob/main/docs/assets/config_file.png?raw=true" alt="Feature" width="700"> | **Simplified Setup**<br><br>Get up and running quickly with minimal configuration. Adjust settings for internationalization, routing, AI, build, and content handling with ease. <br><br> - [Explore Next.js integration](https://intlayer.org/doc/environment/nextjs)
|
|
58
|
-
| <img src="https://github.com/aymericzip/intlayer/blob/main/docs/assets/content_retrieval.png?raw=true" alt="Feature" width="700"> | **Simplified Content Retrieval**<br><br>No need to call your `t` function for each piece of content. Retrieve all your content directly using a single hook.<br><br> - [React integration](https://intlayer.org/doc/environment/create-react-app)
|
|
59
|
-
| <img src="https://github.com/aymericzip/intlayer/blob/main/docs/assets/server_component.png?raw=true" alt="Feature" width="700"> | **Consistent Server Component Implementation**<br><br>Perfectly suited for Next.js server components, use the same implementation for both client and server components, no need to pass your `t` function across each server component. <br><br> - [Server Components](https://intlayer.org/doc/environment/nextjs#step-7-utilize-content-in-your-code)
|
|
60
|
-
| <img src="https://github.com/aymericzip/intlayer/blob/main/docs/assets/file_tree.png?raw=true" alt="Feature" width="700"> | **Organized Codebase**<br><br>Keep your codebase more organized: 1 component = 1 dictionary in the same folder. Translations close to their respective components, enhance maintainability and clarity. <br><br> - [How Intlayer works](https://intlayer.org/doc/concept/how-works-intlayer)
|
|
61
|
-
| <img src="https://github.com/aymericzip/intlayer/blob/main/docs/assets/url_routing.png?raw=true" alt="Feature" width="700"> | **Enhanced Routing**<br><br>Full support of app routing, adapting seamlessly to complex application structures, for Next.js, React, Vite, Vue.js, etc.<br><br> - [Explore Next.js integration](https://intlayer.org/doc/environment/nextjs)
|
|
62
|
-
| <img src="https://github.com/aymericzip/intlayer/blob/main/docs/assets/markdown.png?raw=true" alt="Feature" width="700"> | **Markdown Support**<br><br>Import and interpret, locale files and remote Markdown for multilingual content like privacy policies, documentation, etc. Interpret and make Markdown metadata accessible in your code.<br><br> - [Content files](https://intlayer.org/doc/concept/content/file)
|
|
63
|
-
| <img src="https://github.com/aymericzip/intlayer/blob/main/docs/assets/visual_editor.png?raw=true" alt="Feature" width="700"> | **Free Visual Editor & CMS**<br><br>A free visual editor and CMS are available for content writers, removing the need for a localization platform. Keep your content synchronized using Git, or externalize it totally or partially with the CMS.<br><br> - [Intlayer Editor](https://intlayer.org/doc/concept/editor) <br> - [Intlayer CMS](https://intlayer.org/doc/concept/cms)
|
|
64
|
-
| <img src="https://github.com/aymericzip/intlayer/blob/main/docs/assets/bundle.png?raw=true" alt="Feature" width="700"> | **Tree-shakable Content**<br><br>Tree-shakable content, reducing the size of the final bundle. Loads content per component, excluding any unused content from your bundle. Supports lazy loading to enhance app loading efficiency. <br><br> - [App build optimization](https://intlayer.org/doc/concept/how-works-intlayer#app-build-optimization)
|
|
65
|
-
| <img src="https://github.com/aymericzip/intlayer/blob/main/docs/assets/static_rendering.png?raw=true" alt="Feature" width="700"> | **Static Rendering**<br><br>Doesn't block Static Rendering. <br><br> - [Next.js integration](https://intlayer.org/doc/environment/nextjs)
|
|
66
|
-
| <img src="https://github.com/aymericzip/intlayer/blob/main/docs/assets/AI_translation.png?raw=true" alt="Feature" width="700"> | **AI-Powered Translation**<br><br>Transform your website into 231 languages with just one click using Intlayer's advanced AI-powered translation tools using your own AI provider / API key. <br><br> - [CI/CD integration](https://intlayer.org/doc/concept/ci-cd) <br> - [Intlayer CLI](https://intlayer.org/doc/concept/cli) <br> - [Auto fill](https://intlayer.org/doc/concept/auto-fill)
|
|
67
|
-
| <img src="https://github.com/aymericzip/intlayer/blob/main/docs/assets/mcp.png?raw=true" alt="Feature" width="700"> | **MCP Server Integration**<br><br>Provides an MCP (Model Context Protocol) server for IDE automation, enabling seamless content management and i18n workflows directly within your development environment. <br><br> - [MCP Server](https://github.com/aymericzip/intlayer/blob/main/docs/docs/en/mcp_server.md)
|
|
68
|
-
| <img src="https://github.com/aymericzip/intlayer/blob/main/docs/assets/vscode_extension.png?raw=true" alt="Feature" width="700"> | **VSCode Extension**<br><br>Intlayer provides a VSCode extension to help you manage your content and translations, building your dictionaries, translating your content, and more. <br><br> - [VSCode Extension](https://intlayer.org/doc/vs-code-extension)
|
|
69
|
-
| <img src="https://github.com/aymericzip/intlayer/blob/main/docs/assets/interoperability.png?raw=true" alt="Feature" width="700"> | **Interoperability**<br><br>Allow interoperability with react-i18next, next-i18next, next-intl, react-intl, vue-i18n. <br><br> - [Intlayer and react-intl](https://intlayer.org/blog/intlayer-with-react-intl) <br> - [Intlayer and next-intl](https://intlayer.org/blog/intlayer-with-next-intl) <br> - [Intlayer and next-i18next](https://intlayer.org/blog/intlayer-with-next-i18next) <br> - [Intlayer and vue-i18n](https://intlayer.org/blog/intlayer-with-vue-i18n) |
|
|
70
|
-
| <img src="https://github.com/aymericzip/intlayer/blob/main/docs/assets/benchmark.png?raw=true" alt="Feature" width="700"> | **Performances & Benchmark**<br><br>Uses advanced tree-shaking and dynamic loading to boost performances and keep the solution as light as possible. <br><br> - [Performances & Benchmark](https://intlayer.org/doc/benchmark)
|
|
50
|
+
| Feature | Description |
|
|
51
|
+
| --------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
52
|
+
| <img src="https://github.com/aymericzip/intlayer/blob/main/docs/assets/frameworks.png?raw=true" alt="Feature" width="700"> | **Cross-Frameworks Support**<br><br>Intlayer is compatible with all major frameworks and libraries, including Next.js, React, Vite, Vue.js, Nuxt, Preact, Express, and more. |
|
|
53
|
+
| <img src="https://github.com/aymericzip/intlayer/blob/main/docs/assets/javascript_content_management.jpg?raw=true" alt="Feature" width="700"> | **JavaScript-Powered Content Management**<br><br>Harness the flexibility of JavaScript to define and manage your content efficiently. <br><br> - [Content declaration](https://intlayer.org/doc/concept/content) |
|
|
54
|
+
| <img src="https://github.com/aymericzip/intlayer/blob/main/docs/assets/per_locale_content_declaration_file.png?raw=true" alt="Feature" width="700"> | **Per-Locale Content Declaration File**<br><br>Speed up your development by declaring your content once, before auto generation.<br><br> - [Per-Locale Content Declaration File](https://intlayer.org/doc/concept/per-locale-file) |
|
|
55
|
+
| <img src="https://github.com/aymericzip/intlayer/blob/main/docs/assets/compiler.jpg?raw=true" alt="Feature" width="700"> | **Compiler**<br><br>The Intlayer Compiler extract automatically the content from the components and generate the dictionary files.<br><br> - [Compiler](https://intlayer.org/doc/compiler) |
|
|
56
|
+
| <img src="https://github.com/aymericzip/intlayer/blob/main/docs/assets/autocompletion.png?raw=true" alt="Feature" width="700"> | **Type-Safe Environment**<br><br>Leverage TypeScript to ensure your content definitions and code are error-free, while also benefiting from IDE autocompletion.<br><br> - [TypeScript configuration](https://intlayer.org/doc/environment/vite-and-react#configure-typescript) |
|
|
57
|
+
| <img src="https://github.com/aymericzip/intlayer/blob/main/docs/assets/config_file.png?raw=true" alt="Feature" width="700"> | **Simplified Setup**<br><br>Get up and running quickly with minimal configuration. Adjust settings for internationalization, routing, AI, build, and content handling with ease. <br><br> - [Explore Next.js integration](https://intlayer.org/doc/environment/nextjs) |
|
|
58
|
+
| <img src="https://github.com/aymericzip/intlayer/blob/main/docs/assets/content_retrieval.png?raw=true" alt="Feature" width="700"> | **Simplified Content Retrieval**<br><br>No need to call your `t` function for each piece of content. Retrieve all your content directly using a single hook.<br><br> - [React integration](https://intlayer.org/doc/environment/create-react-app) |
|
|
59
|
+
| <img src="https://github.com/aymericzip/intlayer/blob/main/docs/assets/server_component.png?raw=true" alt="Feature" width="700"> | **Consistent Server Component Implementation**<br><br>Perfectly suited for Next.js server components, use the same implementation for both client and server components, no need to pass your `t` function across each server component. <br><br> - [Server Components](https://intlayer.org/doc/environment/nextjs#step-7-utilize-content-in-your-code) |
|
|
60
|
+
| <img src="https://github.com/aymericzip/intlayer/blob/main/docs/assets/file_tree.png?raw=true" alt="Feature" width="700"> | **Organized Codebase**<br><br>Keep your codebase more organized: 1 component = 1 dictionary in the same folder. Translations close to their respective components, enhance maintainability and clarity. <br><br> - [How Intlayer works](https://intlayer.org/doc/concept/how-works-intlayer) |
|
|
61
|
+
| <img src="https://github.com/aymericzip/intlayer/blob/main/docs/assets/url_routing.png?raw=true" alt="Feature" width="700"> | **Enhanced Routing**<br><br>Full support of app routing, adapting seamlessly to complex application structures, for Next.js, React, Vite, Vue.js, etc.<br><br> - [Explore Next.js integration](https://intlayer.org/doc/environment/nextjs) |
|
|
62
|
+
| <img src="https://github.com/aymericzip/intlayer/blob/main/docs/assets/markdown.png?raw=true" alt="Feature" width="700"> | **Markdown Support**<br><br>Import and interpret, locale files and remote Markdown for multilingual content like privacy policies, documentation, etc. Interpret and make Markdown metadata accessible in your code.<br><br> - [Content files](https://intlayer.org/doc/concept/content/file) |
|
|
63
|
+
| <img src="https://github.com/aymericzip/intlayer/blob/main/docs/assets/visual_editor.png?raw=true" alt="Feature" width="700"> | **Free Visual Editor & CMS**<br><br>A free visual editor and CMS are available for content writers, removing the need for a localization platform. Keep your content synchronized using Git, or externalize it totally or partially with the CMS.<br><br> - [Intlayer Editor](https://intlayer.org/doc/concept/editor) <br> - [Intlayer CMS](https://intlayer.org/doc/concept/cms) |
|
|
64
|
+
| <img src="https://github.com/aymericzip/intlayer/blob/main/docs/assets/bundle.png?raw=true" alt="Feature" width="700"> | **Tree-shakable Content**<br><br>Tree-shakable content, reducing the size of the final bundle. Loads content per component, excluding any unused content from your bundle. Supports lazy loading to enhance app loading efficiency. <br><br> - [App build optimization](https://intlayer.org/doc/concept/how-works-intlayer#app-build-optimization) |
|
|
65
|
+
| <img src="https://github.com/aymericzip/intlayer/blob/main/docs/assets/static_rendering.png?raw=true" alt="Feature" width="700"> | **Static Rendering**<br><br>Doesn't block Static Rendering. <br><br> - [Next.js integration](https://intlayer.org/doc/environment/nextjs) |
|
|
66
|
+
| <img src="https://github.com/aymericzip/intlayer/blob/main/docs/assets/AI_translation.png?raw=true" alt="Feature" width="700"> | **AI-Powered Translation**<br><br>Transform your website into 231 languages with just one click using Intlayer's advanced AI-powered translation tools using your own AI provider / API key. <br><br> - [CI/CD integration](https://intlayer.org/doc/concept/ci-cd) <br> - [Intlayer CLI](https://intlayer.org/doc/concept/cli) <br> - [Auto fill](https://intlayer.org/doc/concept/auto-fill) |
|
|
67
|
+
| <img src="https://github.com/aymericzip/intlayer/blob/main/docs/assets/mcp.png?raw=true" alt="Feature" width="700"> | **MCP Server Integration**<br><br>Provides an MCP (Model Context Protocol) server for IDE automation, enabling seamless content management and i18n workflows directly within your development environment. <br><br> - [MCP Server](https://github.com/aymericzip/intlayer/blob/main/docs/docs/en/mcp_server.md) |
|
|
68
|
+
| <img src="https://github.com/aymericzip/intlayer/blob/main/docs/assets/vscode_extension.png?raw=true" alt="Feature" width="700"> | **VSCode Extension**<br><br>Intlayer provides a VSCode extension to help you manage your content and translations, building your dictionaries, translating your content, and more. <br><br> - [VSCode Extension](https://intlayer.org/doc/vs-code-extension) |
|
|
69
|
+
| <img src="https://github.com/aymericzip/intlayer/blob/main/docs/assets/interoperability.png?raw=true" alt="Feature" width="700"> | **Interoperability**<br><br>Allow interoperability with react-i18next, next-i18next, next-intl, react-intl, vue-i18n. <br><br> - [Intlayer and react-intl](https://intlayer.org/blog/intlayer-with-react-intl) <br> - [Intlayer and next-intl](https://intlayer.org/blog/intlayer-with-next-intl) <br> - [Intlayer and next-i18next](https://intlayer.org/blog/intlayer-with-next-i18next) <br> - [Intlayer and vue-i18n](https://intlayer.org/blog/intlayer-with-vue-i18n) <br> - [Intlayer compat adapters](https://intlayer.org/doc/compatibility) |
|
|
70
|
+
| <img src="https://github.com/aymericzip/intlayer/blob/main/docs/assets/benchmark.png?raw=true" alt="Feature" width="700"> | **Performances & Benchmark**<br><br>Uses advanced tree-shaking and dynamic loading to boost performances and keep the solution as light as possible. <br><br> - [Performances & Benchmark](https://intlayer.org/doc/benchmark) |
|
|
71
71
|
|
|
72
72
|
---
|
|
73
73
|
|
|
@@ -162,7 +162,7 @@ Explore our comprehensive documentation to get started with Intlayer and learn h
|
|
|
162
162
|
<li><a href="https://intlayer.org/doc/concept/cms" rel=''>Intlayer CMS</a></li>
|
|
163
163
|
<li><a href="https://intlayer.org/doc/concept/content" rel=''>Dictionary</a>
|
|
164
164
|
<ul>
|
|
165
|
-
<li><a href="https://intlayer.org/doc/concept/
|
|
165
|
+
<li><a href="https://intlayer.org/doc/concept/per-locale-file" rel=''>Per-Locale Content Declaration File</a></li>
|
|
166
166
|
<li><a href="https://intlayer.org/doc/concept/content/translation" rel=''>Translation</a></li>
|
|
167
167
|
<li><a href="https://intlayer.org/doc/concept/content/enumeration" rel=''>Enumeration</a></li>
|
|
168
168
|
<li><a href="https://intlayer.org/doc/concept/content/condition" rel=''>Condition</a></li>
|
|
@@ -183,7 +183,7 @@ Explore our comprehensive documentation to get started with Intlayer and learn h
|
|
|
183
183
|
<ul>
|
|
184
184
|
<li><a href="https://intlayer.org/doc/environment/nextjs/15" rel=''>Next.js 15</a></li>
|
|
185
185
|
<li><a href="https://intlayer.org/doc/environment/nextjs/14" rel=''>Next.js 14 (App Router)</a></li>
|
|
186
|
-
<li><a href="https://intlayer.org/doc/environment/nextjs/next-with-
|
|
186
|
+
<li><a href="https://intlayer.org/doc/environment/nextjs/next-with-page-router" rel=''>Next.js Page Router</a></li>
|
|
187
187
|
<li><a href="https://intlayer.org/doc/environment/nextjs/compiler" rel=''>Next.js using Compiler</a></li>
|
|
188
188
|
</ul>
|
|
189
189
|
</li>
|
|
@@ -212,7 +212,7 @@ Explore our comprehensive documentation to get started with Intlayer and learn h
|
|
|
212
212
|
<li><a href="https://intlayer.org/doc/environment/sveltekit" rel=''>SvelteKit</a></li>
|
|
213
213
|
<li><a href="https://intlayer.org/doc/environment/vite-and-preact" rel=''>Vite + Preact</a></li>
|
|
214
214
|
<li><a href="https://intlayer.org/doc/environment/vite-and-vue" rel=''>Vite + Vue</a></li>
|
|
215
|
-
<li><a href="https://intlayer.org/doc/environment/
|
|
215
|
+
<li><a href="https://intlayer.org/doc/environment/nuxt-and-vue" rel=''>Vite + Nuxt</a></li>
|
|
216
216
|
<li><a href="https://intlayer.org/doc/environment/vite-and-solid" rel=''>Vite + Solid</a></li>
|
|
217
217
|
<li><a href="https://intlayer.org/doc/environment/angular" rel=''>Angular</a></li>
|
|
218
218
|
<li>
|
|
@@ -133,7 +133,8 @@ const configMetroIntlayerSync = (baseConfig) => {
|
|
|
133
133
|
* > Note: `configMetroIntlayer` builds intlayer dictionaries on server start. Use `configMetroIntlayerSync` instead if you want to skip that.
|
|
134
134
|
*/
|
|
135
135
|
const configMetroIntlayer = async (baseConfig) => {
|
|
136
|
-
|
|
136
|
+
const configuration = (0, _intlayer_config_node.getConfiguration)();
|
|
137
|
+
await (0, _intlayer_engine_build.prepareIntlayer)(configuration);
|
|
137
138
|
return configMetroIntlayerSync(baseConfig);
|
|
138
139
|
};
|
|
139
140
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"configMetroIntlayer.cjs","names":["pathResolve"],"sources":["../../src/configMetroIntlayer.ts"],"sourcesContent":["import { resolve as pathResolve } from 'node:path';\nimport { getConfiguration } from '@intlayer/config/node';\nimport { getAlias } from '@intlayer/config/utils';\nimport { prepareIntlayer } from '@intlayer/engine/build';\nimport type { getDefaultConfig } from 'expo/metro-config';\n\n/**\n * Returns the `resolve` function from metro-resolver, preferring the copy\n * bundled inside Metro itself. Loading from Metro's own package directory\n * ensures we use the same resolver instance that Metro uses internally,\n * which prevents the cross-version recursion described in\n * https://github.com/aymericzip/intlayer/issues/457.\n */\ntype AnyResolver = (context: any, moduleName: string, ...args: any[]) => any;\n\nconst getMetroResolve = (): AnyResolver => {\n try {\n const metroPackageDir = pathResolve(\n require.resolve('metro/package.json'),\n '..'\n );\n return (\n require(\n pathResolve(metroPackageDir, 'node_modules', 'metro-resolver')\n ) as typeof import('metro-resolver')\n ).resolve as AnyResolver;\n } catch {\n return (require('metro-resolver') as typeof import('metro-resolver'))\n .resolve as AnyResolver;\n }\n};\n\ntype MetroConfig = ReturnType<typeof getDefaultConfig>;\n\n/**\n * // metro.config.js\n * const { getDefaultConfig } = require(\"expo/metro-config\");\n * const { configMetroIntlayerSync } = require(\"react-native-intlayer/metro\");\n *\n *\n * const defaultConfig = getDefaultConfig(__dirname);\n *\n * return configMetroIntlayerSync(defaultConfig);\n * ```\n *\n * > Note: `configMetroIntlayerSync` does not build intlayer dictionaries on server start. Use `configMetroIntlayer` for that.\n */\nexport const configMetroIntlayerSync = (\n baseConfig?: MetroConfig\n): MetroConfig => {\n const configuration = getConfiguration();\n\n const alias = getAlias({\n configuration,\n formatter: pathResolve, // get absolute path\n });\n\n /**\n * Project root, used to force `react-intlayer` to resolve to a single copy.\n *\n * Metro does not deduplicate packages the way web bundlers do. When a\n * dependency (e.g. `react-native-intlayer`) pins a different patch of\n * `react-intlayer` than the app, npm/yarn keep two physical copies. The\n * provider would then create its React context from one copy while\n * `useLocale`/`useIntlayer` read the context from the other — two distinct\n * `IntlayerClientContext` instances. The provider's updates never reach the\n * consumers, so `setLocale()` silently does nothing on native.\n *\n * Resolving every `react-intlayer` request from the project root collapses\n * those copies to a single module instance (and therefore a single context).\n */\n const projectRoot = configuration.system.baseDir;\n\n const existingBlockList = baseConfig?.resolver?.blockList;\n const existingPatterns: RegExp[] =\n existingBlockList instanceof RegExp\n ? [existingBlockList]\n : (existingBlockList ?? []);\n\n const existingResolveRequest = baseConfig?.resolver?.resolveRequest;\n\n /**\n * Tracks resolution contexts that are currently executing inside the\n * metro-resolver fallback call. When metro-resolver cannot find a module it\n * may call back through `context.resolveRequest` (the outermost resolver in\n * the chain, e.g. Sentry → NativeWind → ours). That callback eventually\n * reaches our resolver again. Without a guard we would recurse indefinitely\n * (see issue #457).\n *\n * On the second entry we break the cycle by stripping `resolveRequest` from\n * the context so metro-resolver finishes with its built-in logic only\n * (alias, extraNodeModules, …) rather than calling back a third time.\n *\n * Metro creates a fresh context object per module resolution, so using a\n * WeakSet keyed on context is safe and causes no cross-resolution\n * interference.\n */\n const inflightFallbackContexts = new WeakSet<object>();\n\n const config = {\n ...baseConfig,\n\n resolver: {\n ...baseConfig?.resolver,\n resolveRequest: (context, moduleName, ...args) => {\n if (Object.keys(alias).includes(moduleName)) {\n return {\n filePath: alias[moduleName as keyof typeof alias],\n type: 'sourceFile',\n };\n }\n\n // Because metro does not resolve submodules, we need to resolve the path manually\n if (moduleName === '@intlayer/config/client') {\n return {\n filePath: require.resolve('@intlayer/config/client'),\n type: 'sourceFile',\n };\n }\n\n // Because metro does not resolve submodules, we need to resolve the path manually\n if (moduleName === '@intlayer/core/file') {\n // Force React Native to use the correct transpiled version\n return {\n filePath: require.resolve('@intlayer/core/file/browser'),\n type: 'sourceFile',\n };\n }\n\n // Force a single `react-intlayer` instance regardless of which package\n // imports it (the app or a nested dependency). This prevents the\n // duplicate-context bug that silently breaks locale switching on native\n // when two `react-intlayer` copies are installed (see projectRoot doc).\n if (\n moduleName === 'react-intlayer' ||\n moduleName.startsWith('react-intlayer/')\n ) {\n try {\n return {\n filePath: require.resolve(moduleName, { paths: [projectRoot] }),\n type: 'sourceFile',\n };\n } catch {\n // Fall through to the default resolution below if the project root\n // copy cannot be resolved for some reason.\n }\n }\n\n // @formatjs packages have invalid exports configuration or missing exports for polyfills\n // By disabling package exports for these modules, we avoid the Metro warnings and let it\n // fall back cleanly to file-based resolution.\n if (moduleName.startsWith('@formatjs/')) {\n inflightFallbackContexts.add(context);\n try {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const cleanContext = {\n ...(context as any),\n unstable_enablePackageExports: false,\n };\n return getMetroResolve()(cleanContext, moduleName, ...args);\n } finally {\n inflightFallbackContexts.delete(context);\n }\n }\n\n // Delegate to the user-provided resolver if present\n if (existingResolveRequest) {\n return existingResolveRequest(context, moduleName, ...args);\n }\n\n // Re-entry guard: metro-resolver has already been invoked for this\n // context and is now calling back through context.resolveRequest (the\n // outer chain) which has bubbled back to us. Strip resolveRequest so\n // metro-resolver resolves the module with only its built-in rules\n // (alias, extraNodeModules, etc.) and does not recurse again.\n if (inflightFallbackContexts.has(context)) {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const { resolveRequest: _r, ...pureContext } = context as any;\n return getMetroResolve()(pureContext, moduleName, ...args);\n }\n\n // First pass: call metro-resolver while preserving context.resolveRequest\n // so outer wrappers (NativeWind, Sentry, …) still get a chance to\n // handle modules that metro-resolver cannot locate on its own (e.g. @/\n // tsconfig path aliases that a wrapper resolves via its own logic).\n inflightFallbackContexts.add(context);\n try {\n return getMetroResolve()(context, moduleName, ...args);\n } finally {\n inflightFallbackContexts.delete(context);\n }\n },\n blockList: [\n ...existingPatterns,\n ...configuration.content.fileExtensions.map(\n (ext) => new RegExp(`.*${ext.replace(/\\./g, '\\\\.')}$`)\n ),\n ],\n },\n } as MetroConfig;\n\n return config;\n};\n\n/**\n * // metro.config.js\n * const { getDefaultConfig } = require(\"expo/metro-config\");\n * const { configMetroIntlayer } = require(\"react-native-intlayer/metro\");\n *\n * module.exports = (async () => {\n * const defaultConfig = getDefaultConfig(__dirname);\n *\n * return await configMetroIntlayer(defaultConfig);\n * })();\n * ```\n *\n * > Note: `configMetroIntlayer` builds intlayer dictionaries on server start. Use `configMetroIntlayerSync` instead if you want to skip that.\n */\nexport const configMetroIntlayer = async (\n baseConfig?: MetroConfig\n): Promise<MetroConfig> => {\n const configuration = getConfiguration();\n\n await prepareIntlayer(configuration);\n\n return configMetroIntlayerSync(baseConfig);\n};\n"],"mappings":";;;;;;;AAeA,MAAM,wBAAqC;CACzC,IAAI;EACF,MAAM,yCACJ,QAAQ,QAAQ,oBAAoB,GACpC,IACF;EACA,OACE,+BACc,iBAAiB,gBAAgB,gBAAgB,CAC/D,CAAC,CACD;CACJ,QAAQ;EACN,OAAQ,QAAQ,gBAAgB,CAAC,CAC9B;CACL;AACF;;;;;;;;;;;;;;AAiBA,MAAa,2BACX,eACgB;CAChB,MAAM,4DAAiC;CAEvC,MAAM,6CAAiB;EACrB;EACA,WAAWA;CACb,CAAC;;;;;;;;;;;;;;;CAgBD,MAAM,cAAc,cAAc,OAAO;CAEzC,MAAM,oBAAoB,YAAY,UAAU;CAChD,MAAM,mBACJ,6BAA6B,SACzB,CAAC,iBAAiB,IACjB,qBAAqB,CAAC;CAE7B,MAAM,yBAAyB,YAAY,UAAU;;;;;;;;;;;;;;;;;CAkBrD,MAAM,2CAA2B,IAAI,QAAgB;CAwGrD,OAAO;EArGL,GAAG;EAEH,UAAU;GACR,GAAG,YAAY;GACf,iBAAiB,SAAS,YAAY,GAAG,SAAS;IAChD,IAAI,OAAO,KAAK,KAAK,CAAC,CAAC,SAAS,UAAU,GACxC,OAAO;KACL,UAAU,MAAM;KAChB,MAAM;IACR;IAIF,IAAI,eAAe,2BACjB,OAAO;KACL,UAAU,QAAQ,QAAQ,yBAAyB;KACnD,MAAM;IACR;IAIF,IAAI,eAAe,uBAEjB,OAAO;KACL,UAAU,QAAQ,QAAQ,6BAA6B;KACvD,MAAM;IACR;IAOF,IACE,eAAe,oBACf,WAAW,WAAW,iBAAiB,GAEvC,IAAI;KACF,OAAO;MACL,UAAU,QAAQ,QAAQ,YAAY,EAAE,OAAO,CAAC,WAAW,EAAE,CAAC;MAC9D,MAAM;KACR;IACF,QAAQ,CAGR;IAMF,IAAI,WAAW,WAAW,YAAY,GAAG;KACvC,yBAAyB,IAAI,OAAO;KACpC,IAAI;MAEF,MAAM,eAAe;OACnB,GAAI;OACJ,+BAA+B;MACjC;MACA,OAAO,gBAAgB,CAAC,CAAC,cAAc,YAAY,GAAG,IAAI;KAC5D,UAAU;MACR,yBAAyB,OAAO,OAAO;KACzC;IACF;IAGA,IAAI,wBACF,OAAO,uBAAuB,SAAS,YAAY,GAAG,IAAI;IAQ5D,IAAI,yBAAyB,IAAI,OAAO,GAAG;KAEzC,MAAM,EAAE,gBAAgB,IAAI,GAAG,gBAAgB;KAC/C,OAAO,gBAAgB,CAAC,CAAC,aAAa,YAAY,GAAG,IAAI;IAC3D;IAMA,yBAAyB,IAAI,OAAO;IACpC,IAAI;KACF,OAAO,gBAAgB,CAAC,CAAC,SAAS,YAAY,GAAG,IAAI;IACvD,UAAU;KACR,yBAAyB,OAAO,OAAO;IACzC;GACF;GACA,WAAW,CACT,GAAG,kBACH,GAAG,cAAc,QAAQ,eAAe,KACrC,QAAQ,IAAI,OAAO,KAAK,IAAI,QAAQ,OAAO,KAAK,EAAE,EAAE,CACvD,CACF;EACF;CAGU;AACd;;;;;;;;;;;;;;;AAgBA,MAAa,sBAAsB,OACjC,eACyB;CAGzB,8FAAkC,CAAC;CAEnC,OAAO,wBAAwB,UAAU;AAC3C"}
|
|
1
|
+
{"version":3,"file":"configMetroIntlayer.cjs","names":["pathResolve","getConfiguration","getAlias","prepareIntlayer"],"sources":["../../src/configMetroIntlayer.ts"],"sourcesContent":["import { resolve as pathResolve } from 'node:path';\nimport { getConfiguration } from '@intlayer/config/node';\nimport { getAlias } from '@intlayer/config/utils';\nimport { prepareIntlayer } from '@intlayer/engine/build';\nimport type { getDefaultConfig } from 'expo/metro-config';\n\n/**\n * Returns the `resolve` function from metro-resolver, preferring the copy\n * bundled inside Metro itself. Loading from Metro's own package directory\n * ensures we use the same resolver instance that Metro uses internally,\n * which prevents the cross-version recursion described in\n * https://github.com/aymericzip/intlayer/issues/457.\n */\ntype AnyResolver = (context: any, moduleName: string, ...args: any[]) => any;\n\nconst getMetroResolve = (): AnyResolver => {\n try {\n const metroPackageDir = pathResolve(\n require.resolve('metro/package.json'),\n '..'\n );\n return (\n require(\n pathResolve(metroPackageDir, 'node_modules', 'metro-resolver')\n ) as typeof import('metro-resolver')\n ).resolve as AnyResolver;\n } catch {\n return (require('metro-resolver') as typeof import('metro-resolver'))\n .resolve as AnyResolver;\n }\n};\n\ntype MetroConfig = ReturnType<typeof getDefaultConfig>;\n\n/**\n * // metro.config.js\n * const { getDefaultConfig } = require(\"expo/metro-config\");\n * const { configMetroIntlayerSync } = require(\"react-native-intlayer/metro\");\n *\n *\n * const defaultConfig = getDefaultConfig(__dirname);\n *\n * return configMetroIntlayerSync(defaultConfig);\n * ```\n *\n * > Note: `configMetroIntlayerSync` does not build intlayer dictionaries on server start. Use `configMetroIntlayer` for that.\n */\nexport const configMetroIntlayerSync = (\n baseConfig?: MetroConfig\n): MetroConfig => {\n const configuration = getConfiguration();\n\n const alias = getAlias({\n configuration,\n formatter: pathResolve, // get absolute path\n });\n\n /**\n * Project root, used to force `react-intlayer` to resolve to a single copy.\n *\n * Metro does not deduplicate packages the way web bundlers do. When a\n * dependency (e.g. `react-native-intlayer`) pins a different patch of\n * `react-intlayer` than the app, npm/yarn keep two physical copies. The\n * provider would then create its React context from one copy while\n * `useLocale`/`useIntlayer` read the context from the other — two distinct\n * `IntlayerClientContext` instances. The provider's updates never reach the\n * consumers, so `setLocale()` silently does nothing on native.\n *\n * Resolving every `react-intlayer` request from the project root collapses\n * those copies to a single module instance (and therefore a single context).\n */\n const projectRoot = configuration.system.baseDir;\n\n const existingBlockList = baseConfig?.resolver?.blockList;\n const existingPatterns: RegExp[] =\n existingBlockList instanceof RegExp\n ? [existingBlockList]\n : (existingBlockList ?? []);\n\n const existingResolveRequest = baseConfig?.resolver?.resolveRequest;\n\n /**\n * Tracks resolution contexts that are currently executing inside the\n * metro-resolver fallback call. When metro-resolver cannot find a module it\n * may call back through `context.resolveRequest` (the outermost resolver in\n * the chain, e.g. Sentry → NativeWind → ours). That callback eventually\n * reaches our resolver again. Without a guard we would recurse indefinitely\n * (see issue #457).\n *\n * On the second entry we break the cycle by stripping `resolveRequest` from\n * the context so metro-resolver finishes with its built-in logic only\n * (alias, extraNodeModules, …) rather than calling back a third time.\n *\n * Metro creates a fresh context object per module resolution, so using a\n * WeakSet keyed on context is safe and causes no cross-resolution\n * interference.\n */\n const inflightFallbackContexts = new WeakSet<object>();\n\n const config = {\n ...baseConfig,\n\n resolver: {\n ...baseConfig?.resolver,\n resolveRequest: (context, moduleName, ...args) => {\n if (Object.keys(alias).includes(moduleName)) {\n return {\n filePath: alias[moduleName as keyof typeof alias],\n type: 'sourceFile',\n };\n }\n\n // Because metro does not resolve submodules, we need to resolve the path manually\n if (moduleName === '@intlayer/config/client') {\n return {\n filePath: require.resolve('@intlayer/config/client'),\n type: 'sourceFile',\n };\n }\n\n // Because metro does not resolve submodules, we need to resolve the path manually\n if (moduleName === '@intlayer/core/file') {\n // Force React Native to use the correct transpiled version\n return {\n filePath: require.resolve('@intlayer/core/file/browser'),\n type: 'sourceFile',\n };\n }\n\n // Force a single `react-intlayer` instance regardless of which package\n // imports it (the app or a nested dependency). This prevents the\n // duplicate-context bug that silently breaks locale switching on native\n // when two `react-intlayer` copies are installed (see projectRoot doc).\n if (\n moduleName === 'react-intlayer' ||\n moduleName.startsWith('react-intlayer/')\n ) {\n try {\n return {\n filePath: require.resolve(moduleName, { paths: [projectRoot] }),\n type: 'sourceFile',\n };\n } catch {\n // Fall through to the default resolution below if the project root\n // copy cannot be resolved for some reason.\n }\n }\n\n // @formatjs packages have invalid exports configuration or missing exports for polyfills\n // By disabling package exports for these modules, we avoid the Metro warnings and let it\n // fall back cleanly to file-based resolution.\n if (moduleName.startsWith('@formatjs/')) {\n inflightFallbackContexts.add(context);\n try {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const cleanContext = {\n ...(context as any),\n unstable_enablePackageExports: false,\n };\n return getMetroResolve()(cleanContext, moduleName, ...args);\n } finally {\n inflightFallbackContexts.delete(context);\n }\n }\n\n // Delegate to the user-provided resolver if present\n if (existingResolveRequest) {\n return existingResolveRequest(context, moduleName, ...args);\n }\n\n // Re-entry guard: metro-resolver has already been invoked for this\n // context and is now calling back through context.resolveRequest (the\n // outer chain) which has bubbled back to us. Strip resolveRequest so\n // metro-resolver resolves the module with only its built-in rules\n // (alias, extraNodeModules, etc.) and does not recurse again.\n if (inflightFallbackContexts.has(context)) {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const { resolveRequest: _r, ...pureContext } = context as any;\n return getMetroResolve()(pureContext, moduleName, ...args);\n }\n\n // First pass: call metro-resolver while preserving context.resolveRequest\n // so outer wrappers (NativeWind, Sentry, …) still get a chance to\n // handle modules that metro-resolver cannot locate on its own (e.g. @/\n // tsconfig path aliases that a wrapper resolves via its own logic).\n inflightFallbackContexts.add(context);\n try {\n return getMetroResolve()(context, moduleName, ...args);\n } finally {\n inflightFallbackContexts.delete(context);\n }\n },\n blockList: [\n ...existingPatterns,\n ...configuration.content.fileExtensions.map(\n (ext) => new RegExp(`.*${ext.replace(/\\./g, '\\\\.')}$`)\n ),\n ],\n },\n } as MetroConfig;\n\n return config;\n};\n\n/**\n * // metro.config.js\n * const { getDefaultConfig } = require(\"expo/metro-config\");\n * const { configMetroIntlayer } = require(\"react-native-intlayer/metro\");\n *\n * module.exports = (async () => {\n * const defaultConfig = getDefaultConfig(__dirname);\n *\n * return await configMetroIntlayer(defaultConfig);\n * })();\n * ```\n *\n * > Note: `configMetroIntlayer` builds intlayer dictionaries on server start. Use `configMetroIntlayerSync` instead if you want to skip that.\n */\nexport const configMetroIntlayer = async (\n baseConfig?: MetroConfig\n): Promise<MetroConfig> => {\n const configuration = getConfiguration();\n\n await prepareIntlayer(configuration);\n\n return configMetroIntlayerSync(baseConfig);\n};\n"],"mappings":";;;;;;;AAeA,MAAM,wBAAqC;CACzC,IAAI;EACF,MAAM,sBAAkBA,mBACtB,QAAQ,QAAQ,oBAAoB,GACpC,IACF;EACA,OACE,YACEA,mBAAY,iBAAiB,gBAAgB,gBAAgB,CAC/D,CAAC,CACD;CACJ,QAAQ;EACN,OAAQ,QAAQ,gBAAgB,CAAC,CAC9B;CACL;AACF;;;;;;;;;;;;;;AAiBA,MAAa,2BACX,eACgB;CAChB,MAAM,oBAAgBC,wCAAiB;CAEvC,MAAM,YAAQC,iCAAS;EACrB;EACA,WAAWF;CACb,CAAC;;;;;;;;;;;;;;;CAgBD,MAAM,cAAc,cAAc,OAAO;CAEzC,MAAM,oBAAoB,YAAY,UAAU;CAChD,MAAM,mBACJ,6BAA6B,SACzB,CAAC,iBAAiB,IACjB,qBAAqB,CAAC;CAE7B,MAAM,yBAAyB,YAAY,UAAU;;;;;;;;;;;;;;;;;CAkBrD,MAAM,2CAA2B,IAAI,QAAgB;CAwGrD,OAAO;EArGL,GAAG;EAEH,UAAU;GACR,GAAG,YAAY;GACf,iBAAiB,SAAS,YAAY,GAAG,SAAS;IAChD,IAAI,OAAO,KAAK,KAAK,CAAC,CAAC,SAAS,UAAU,GACxC,OAAO;KACL,UAAU,MAAM;KAChB,MAAM;IACR;IAIF,IAAI,eAAe,2BACjB,OAAO;KACL,UAAU,QAAQ,QAAQ,yBAAyB;KACnD,MAAM;IACR;IAIF,IAAI,eAAe,uBAEjB,OAAO;KACL,UAAU,QAAQ,QAAQ,6BAA6B;KACvD,MAAM;IACR;IAOF,IACE,eAAe,oBACf,WAAW,WAAW,iBAAiB,GAEvC,IAAI;KACF,OAAO;MACL,UAAU,QAAQ,QAAQ,YAAY,EAAE,OAAO,CAAC,WAAW,EAAE,CAAC;MAC9D,MAAM;KACR;IACF,QAAQ,CAGR;IAMF,IAAI,WAAW,WAAW,YAAY,GAAG;KACvC,yBAAyB,IAAI,OAAO;KACpC,IAAI;MAEF,MAAM,eAAe;OACnB,GAAI;OACJ,+BAA+B;MACjC;MACA,OAAO,gBAAgB,CAAC,CAAC,cAAc,YAAY,GAAG,IAAI;KAC5D,UAAU;MACR,yBAAyB,OAAO,OAAO;KACzC;IACF;IAGA,IAAI,wBACF,OAAO,uBAAuB,SAAS,YAAY,GAAG,IAAI;IAQ5D,IAAI,yBAAyB,IAAI,OAAO,GAAG;KAEzC,MAAM,EAAE,gBAAgB,IAAI,GAAG,gBAAgB;KAC/C,OAAO,gBAAgB,CAAC,CAAC,aAAa,YAAY,GAAG,IAAI;IAC3D;IAMA,yBAAyB,IAAI,OAAO;IACpC,IAAI;KACF,OAAO,gBAAgB,CAAC,CAAC,SAAS,YAAY,GAAG,IAAI;IACvD,UAAU;KACR,yBAAyB,OAAO,OAAO;IACzC;GACF;GACA,WAAW,CACT,GAAG,kBACH,GAAG,cAAc,QAAQ,eAAe,KACrC,QAAQ,IAAI,OAAO,KAAK,IAAI,QAAQ,OAAO,KAAK,EAAE,EAAE,CACvD,CACF;EACF;CAGU;AACd;;;;;;;;;;;;;;;AAgBA,MAAa,sBAAsB,OACjC,eACyB;CACzB,MAAM,oBAAgBC,wCAAiB;CAEvC,UAAME,wCAAgB,aAAa;CAEnC,OAAO,wBAAwB,UAAU;AAC3C"}
|
package/dist/cjs/html/index.cjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"intlayerPolyfill.cjs","names":[],"sources":["../../src/intlayerPolyfill.ts"],"sourcesContent":["/**\n * Applies necessary polyfills for React Native to support Intlayer.\n *\n * This includes:\n * - Polyfilling `structuredClone` if it is missing.\n * - Providing no-op implementations for standard DOM `window` methods\n * (`addEventListener`, `removeEventListener`, `postMessage`) and a stub\n * `window.location`, which React Native leaves undefined.\n * - Providing in-memory stubs for `document.cookie`, `localStorage`, and\n * `sessionStorage` so that `@intlayer/core`'s locale-storage helpers work\n * without crashing in a React Native environment.\n *\n * Note: These stubs are in-memory only. The locale selection will survive\n * hot-reloads but not full app restarts. To persist across restarts, pass a\n * custom `setLocale` to `<IntlayerProvider>` backed by AsyncStorage.\n */\nconst createStorage = () => {\n const store: Record<string, string> = {};\n return {\n getItem: (key: string) => store[key] ?? null,\n setItem: (key: string, value: string) => {\n store[key] = String(value);\n },\n removeItem: (key: string) => {\n delete store[key];\n },\n clear: () => {\n for (const key in store) {\n delete store[key];\n }\n },\n get length() {\n return Object.keys(store).length;\n },\n key: (index: number) => Object.keys(store)[index] ?? null,\n };\n};\n\nexport const intlayerPolyfill = () => {\n if (typeof global.structuredClone !== 'function') {\n global.structuredClone = (obj) => JSON.parse(JSON.stringify(obj));\n }\n\n if (typeof window !== 'undefined') {\n const noop = () => null;\n if (typeof window.addEventListener !== 'function') {\n window.addEventListener = noop;\n }\n if (typeof window.removeEventListener !== 'function') {\n window.removeEventListener = noop;\n }\n if (typeof window.postMessage !== 'function') {\n window.postMessage = noop;\n }\n\n // React Native defines `window` (aliased to `global`) but leaves\n // `window.location` undefined. Any library reading `window.location.href`\n // — a very common `typeof window !== 'undefined'` guard pattern — then\n // crashes with `Cannot read property 'href' of undefined`, often at module\n // evaluation time, before any component renders.\n if (typeof window.location === 'undefined') {\n const appOrigin = 'http://localhost';\n\n Object.defineProperty(window, 'location', {\n configurable: true,\n writable: true,\n value: {\n href: `${appOrigin}/`,\n origin: appOrigin,\n protocol: 'http:',\n host: 'localhost',\n hostname: 'localhost',\n port: '',\n pathname: '/',\n search: '',\n hash: '',\n assign: noop,\n replace: noop,\n reload: noop,\n toString: () => `${appOrigin}/`,\n },\n });\n }\n }\n\n // `@intlayer/core`'s localeStorageOptions accesses document.cookie directly.\n // In React Native native, `document` is undefined — we provide a minimal\n // in-memory cookie jar so reads/writes work without throwing.\n //\n // We guard with `navigator.product === 'ReactNative'` to avoid installing\n // the stub in SSR / Expo Web pre-render contexts where `document` is also\n // undefined (Node.js) but browser code will later need the real DOM object\n // (e.g. document.createElement called by third-party RN libraries on web).\n const isNativeReactNative =\n typeof navigator !== 'undefined' &&\n (navigator as Navigator & { product?: string }).product === 'ReactNative';\n\n if (typeof document === 'undefined' && isNativeReactNative) {\n let cookieJar = '';\n Object.defineProperty(global, 'document', {\n configurable: true,\n get: () => ({\n get cookie() {\n return cookieJar;\n },\n set cookie(value: string) {\n // Simplified cookie setter: just append/overwrite the key\n const [pair] = value.split(';');\n const [key, val] = pair?.split('=') ?? [];\n const name = key?.trim();\n const existing = cookieJar\n .split(';')\n .filter((c) => !c.trim().startsWith(`${name}=`))\n .filter(Boolean);\n cookieJar = [...existing, `${name}=${val ?? ''}`].join('; ');\n },\n documentElement: { lang: '', dir: 'ltr', style: {} },\n createElement: () => null,\n getElementById: () => null,\n querySelector: () => null,\n querySelectorAll: () => [],\n addEventListener: () => undefined,\n removeEventListener: () => undefined,\n }),\n });\n }\n\n if (typeof localStorage === 'undefined') {\n Object.defineProperty(global, 'localStorage', {\n configurable: true,\n value: createStorage(),\n });\n }\n\n if (typeof sessionStorage === 'undefined') {\n Object.defineProperty(global, 'sessionStorage', {\n configurable: true,\n value: createStorage(),\n });\n }\n};\n"],"mappings":"
|
|
1
|
+
{"version":3,"file":"intlayerPolyfill.cjs","names":[],"sources":["../../src/intlayerPolyfill.ts"],"sourcesContent":["/**\n * Applies necessary polyfills for React Native to support Intlayer.\n *\n * This includes:\n * - Polyfilling `structuredClone` if it is missing.\n * - Providing no-op implementations for standard DOM `window` methods\n * (`addEventListener`, `removeEventListener`, `postMessage`) and a stub\n * `window.location`, which React Native leaves undefined.\n * - Providing in-memory stubs for `document.cookie`, `localStorage`, and\n * `sessionStorage` so that `@intlayer/core`'s locale-storage helpers work\n * without crashing in a React Native environment.\n *\n * Note: These stubs are in-memory only. The locale selection will survive\n * hot-reloads but not full app restarts. To persist across restarts, pass a\n * custom `setLocale` to `<IntlayerProvider>` backed by AsyncStorage.\n */\nconst createStorage = () => {\n const store: Record<string, string> = {};\n return {\n getItem: (key: string) => store[key] ?? null,\n setItem: (key: string, value: string) => {\n store[key] = String(value);\n },\n removeItem: (key: string) => {\n delete store[key];\n },\n clear: () => {\n for (const key in store) {\n delete store[key];\n }\n },\n get length() {\n return Object.keys(store).length;\n },\n key: (index: number) => Object.keys(store)[index] ?? null,\n };\n};\n\nexport const intlayerPolyfill = () => {\n if (typeof global.structuredClone !== 'function') {\n global.structuredClone = (obj) => JSON.parse(JSON.stringify(obj));\n }\n\n if (typeof window !== 'undefined') {\n const noop = () => null;\n if (typeof window.addEventListener !== 'function') {\n window.addEventListener = noop;\n }\n if (typeof window.removeEventListener !== 'function') {\n window.removeEventListener = noop;\n }\n if (typeof window.postMessage !== 'function') {\n window.postMessage = noop;\n }\n\n // React Native defines `window` (aliased to `global`) but leaves\n // `window.location` undefined. Any library reading `window.location.href`\n // — a very common `typeof window !== 'undefined'` guard pattern — then\n // crashes with `Cannot read property 'href' of undefined`, often at module\n // evaluation time, before any component renders.\n if (typeof window.location === 'undefined') {\n const appOrigin = 'http://localhost';\n\n Object.defineProperty(window, 'location', {\n configurable: true,\n writable: true,\n value: {\n href: `${appOrigin}/`,\n origin: appOrigin,\n protocol: 'http:',\n host: 'localhost',\n hostname: 'localhost',\n port: '',\n pathname: '/',\n search: '',\n hash: '',\n assign: noop,\n replace: noop,\n reload: noop,\n toString: () => `${appOrigin}/`,\n },\n });\n }\n }\n\n // `@intlayer/core`'s localeStorageOptions accesses document.cookie directly.\n // In React Native native, `document` is undefined — we provide a minimal\n // in-memory cookie jar so reads/writes work without throwing.\n //\n // We guard with `navigator.product === 'ReactNative'` to avoid installing\n // the stub in SSR / Expo Web pre-render contexts where `document` is also\n // undefined (Node.js) but browser code will later need the real DOM object\n // (e.g. document.createElement called by third-party RN libraries on web).\n const isNativeReactNative =\n typeof navigator !== 'undefined' &&\n (navigator as Navigator & { product?: string }).product === 'ReactNative';\n\n if (typeof document === 'undefined' && isNativeReactNative) {\n let cookieJar = '';\n Object.defineProperty(global, 'document', {\n configurable: true,\n get: () => ({\n get cookie() {\n return cookieJar;\n },\n set cookie(value: string) {\n // Simplified cookie setter: just append/overwrite the key\n const [pair] = value.split(';');\n const [key, val] = pair?.split('=') ?? [];\n const name = key?.trim();\n const existing = cookieJar\n .split(';')\n .filter((c) => !c.trim().startsWith(`${name}=`))\n .filter(Boolean);\n cookieJar = [...existing, `${name}=${val ?? ''}`].join('; ');\n },\n documentElement: { lang: '', dir: 'ltr', style: {} },\n createElement: () => null,\n getElementById: () => null,\n querySelector: () => null,\n querySelectorAll: () => [],\n addEventListener: () => undefined,\n removeEventListener: () => undefined,\n }),\n });\n }\n\n if (typeof localStorage === 'undefined') {\n Object.defineProperty(global, 'localStorage', {\n configurable: true,\n value: createStorage(),\n });\n }\n\n if (typeof sessionStorage === 'undefined') {\n Object.defineProperty(global, 'sessionStorage', {\n configurable: true,\n value: createStorage(),\n });\n }\n};\n"],"mappings":";;;;;;;;;;;;;;;;;;AAgBA,MAAM,sBAAsB;CAC1B,MAAM,QAAgC,CAAC;CACvC,OAAO;EACL,UAAU,QAAgB,MAAM,QAAQ;EACxC,UAAU,KAAa,UAAkB;GACvC,MAAM,OAAO,OAAO,KAAK;EAC3B;EACA,aAAa,QAAgB;GAC3B,OAAO,MAAM;EACf;EACA,aAAa;GACX,KAAK,MAAM,OAAO,OAChB,OAAO,MAAM;EAEjB;EACA,IAAI,SAAS;GACX,OAAO,OAAO,KAAK,KAAK,CAAC,CAAC;EAC5B;EACA,MAAM,UAAkB,OAAO,KAAK,KAAK,CAAC,CAAC,UAAU;CACvD;AACF;AAEA,MAAa,yBAAyB;CACpC,IAAI,OAAO,OAAO,oBAAoB,YACpC,OAAO,mBAAmB,QAAQ,KAAK,MAAM,KAAK,UAAU,GAAG,CAAC;CAGlE,IAAI,OAAO,WAAW,aAAa;EACjC,MAAM,aAAa;EACnB,IAAI,OAAO,OAAO,qBAAqB,YACrC,OAAO,mBAAmB;EAE5B,IAAI,OAAO,OAAO,wBAAwB,YACxC,OAAO,sBAAsB;EAE/B,IAAI,OAAO,OAAO,gBAAgB,YAChC,OAAO,cAAc;EAQvB,IAAI,OAAO,OAAO,aAAa,aAAa;GAC1C,MAAM,YAAY;GAElB,OAAO,eAAe,QAAQ,YAAY;IACxC,cAAc;IACd,UAAU;IACV,OAAO;KACL,MAAM,GAAG,UAAU;KACnB,QAAQ;KACR,UAAU;KACV,MAAM;KACN,UAAU;KACV,MAAM;KACN,UAAU;KACV,QAAQ;KACR,MAAM;KACN,QAAQ;KACR,SAAS;KACT,QAAQ;KACR,gBAAgB,GAAG,UAAU;IAC/B;GACF,CAAC;EACH;CACF;CAUA,MAAM,sBACJ,OAAO,cAAc,eACpB,UAA+C,YAAY;CAE9D,IAAI,OAAO,aAAa,eAAe,qBAAqB;EAC1D,IAAI,YAAY;EAChB,OAAO,eAAe,QAAQ,YAAY;GACxC,cAAc;GACd,YAAY;IACV,IAAI,SAAS;KACX,OAAO;IACT;IACA,IAAI,OAAO,OAAe;KAExB,MAAM,CAAC,QAAQ,MAAM,MAAM,GAAG;KAC9B,MAAM,CAAC,KAAK,OAAO,MAAM,MAAM,GAAG,KAAK,CAAC;KACxC,MAAM,OAAO,KAAK,KAAK;KAKvB,YAAY,CAAC,GAJI,UACd,MAAM,GAAG,CAAC,CACV,QAAQ,MAAM,CAAC,EAAE,KAAK,CAAC,CAAC,WAAW,GAAG,KAAK,EAAE,CAAC,CAAC,CAC/C,OAAO,OACa,GAAG,GAAG,KAAK,GAAG,OAAO,IAAI,CAAC,CAAC,KAAK,IAAI;IAC7D;IACA,iBAAiB;KAAE,MAAM;KAAI,KAAK;KAAO,OAAO,CAAC;IAAE;IACnD,qBAAqB;IACrB,sBAAsB;IACtB,qBAAqB;IACrB,wBAAwB,CAAC;IACzB,wBAAwB;IACxB,2BAA2B;GAC7B;EACF,CAAC;CACH;CAEA,IAAI,OAAO,iBAAiB,aAC1B,OAAO,eAAe,QAAQ,gBAAgB;EAC5C,cAAc;EACd,OAAO,cAAc;CACvB,CAAC;CAGH,IAAI,OAAO,mBAAmB,aAC5B,OAAO,eAAe,QAAQ,kBAAkB;EAC9C,cAAc;EACd,OAAO,cAAc;CACvB,CAAC;AAEL"}
|
|
@@ -133,7 +133,8 @@ const configMetroIntlayerSync = (baseConfig) => {
|
|
|
133
133
|
* > Note: `configMetroIntlayer` builds intlayer dictionaries on server start. Use `configMetroIntlayerSync` instead if you want to skip that.
|
|
134
134
|
*/
|
|
135
135
|
const configMetroIntlayer = async (baseConfig) => {
|
|
136
|
-
|
|
136
|
+
const configuration = getConfiguration();
|
|
137
|
+
await prepareIntlayer(configuration);
|
|
137
138
|
return configMetroIntlayerSync(baseConfig);
|
|
138
139
|
};
|
|
139
140
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"configMetroIntlayer.mjs","names":["pathResolve"],"sources":["../../src/configMetroIntlayer.ts"],"sourcesContent":["import { resolve as pathResolve } from 'node:path';\nimport { getConfiguration } from '@intlayer/config/node';\nimport { getAlias } from '@intlayer/config/utils';\nimport { prepareIntlayer } from '@intlayer/engine/build';\nimport type { getDefaultConfig } from 'expo/metro-config';\n\n/**\n * Returns the `resolve` function from metro-resolver, preferring the copy\n * bundled inside Metro itself. Loading from Metro's own package directory\n * ensures we use the same resolver instance that Metro uses internally,\n * which prevents the cross-version recursion described in\n * https://github.com/aymericzip/intlayer/issues/457.\n */\ntype AnyResolver = (context: any, moduleName: string, ...args: any[]) => any;\n\nconst getMetroResolve = (): AnyResolver => {\n try {\n const metroPackageDir = pathResolve(\n require.resolve('metro/package.json'),\n '..'\n );\n return (\n require(\n pathResolve(metroPackageDir, 'node_modules', 'metro-resolver')\n ) as typeof import('metro-resolver')\n ).resolve as AnyResolver;\n } catch {\n return (require('metro-resolver') as typeof import('metro-resolver'))\n .resolve as AnyResolver;\n }\n};\n\ntype MetroConfig = ReturnType<typeof getDefaultConfig>;\n\n/**\n * // metro.config.js\n * const { getDefaultConfig } = require(\"expo/metro-config\");\n * const { configMetroIntlayerSync } = require(\"react-native-intlayer/metro\");\n *\n *\n * const defaultConfig = getDefaultConfig(__dirname);\n *\n * return configMetroIntlayerSync(defaultConfig);\n * ```\n *\n * > Note: `configMetroIntlayerSync` does not build intlayer dictionaries on server start. Use `configMetroIntlayer` for that.\n */\nexport const configMetroIntlayerSync = (\n baseConfig?: MetroConfig\n): MetroConfig => {\n const configuration = getConfiguration();\n\n const alias = getAlias({\n configuration,\n formatter: pathResolve, // get absolute path\n });\n\n /**\n * Project root, used to force `react-intlayer` to resolve to a single copy.\n *\n * Metro does not deduplicate packages the way web bundlers do. When a\n * dependency (e.g. `react-native-intlayer`) pins a different patch of\n * `react-intlayer` than the app, npm/yarn keep two physical copies. The\n * provider would then create its React context from one copy while\n * `useLocale`/`useIntlayer` read the context from the other — two distinct\n * `IntlayerClientContext` instances. The provider's updates never reach the\n * consumers, so `setLocale()` silently does nothing on native.\n *\n * Resolving every `react-intlayer` request from the project root collapses\n * those copies to a single module instance (and therefore a single context).\n */\n const projectRoot = configuration.system.baseDir;\n\n const existingBlockList = baseConfig?.resolver?.blockList;\n const existingPatterns: RegExp[] =\n existingBlockList instanceof RegExp\n ? [existingBlockList]\n : (existingBlockList ?? []);\n\n const existingResolveRequest = baseConfig?.resolver?.resolveRequest;\n\n /**\n * Tracks resolution contexts that are currently executing inside the\n * metro-resolver fallback call. When metro-resolver cannot find a module it\n * may call back through `context.resolveRequest` (the outermost resolver in\n * the chain, e.g. Sentry → NativeWind → ours). That callback eventually\n * reaches our resolver again. Without a guard we would recurse indefinitely\n * (see issue #457).\n *\n * On the second entry we break the cycle by stripping `resolveRequest` from\n * the context so metro-resolver finishes with its built-in logic only\n * (alias, extraNodeModules, …) rather than calling back a third time.\n *\n * Metro creates a fresh context object per module resolution, so using a\n * WeakSet keyed on context is safe and causes no cross-resolution\n * interference.\n */\n const inflightFallbackContexts = new WeakSet<object>();\n\n const config = {\n ...baseConfig,\n\n resolver: {\n ...baseConfig?.resolver,\n resolveRequest: (context, moduleName, ...args) => {\n if (Object.keys(alias).includes(moduleName)) {\n return {\n filePath: alias[moduleName as keyof typeof alias],\n type: 'sourceFile',\n };\n }\n\n // Because metro does not resolve submodules, we need to resolve the path manually\n if (moduleName === '@intlayer/config/client') {\n return {\n filePath: require.resolve('@intlayer/config/client'),\n type: 'sourceFile',\n };\n }\n\n // Because metro does not resolve submodules, we need to resolve the path manually\n if (moduleName === '@intlayer/core/file') {\n // Force React Native to use the correct transpiled version\n return {\n filePath: require.resolve('@intlayer/core/file/browser'),\n type: 'sourceFile',\n };\n }\n\n // Force a single `react-intlayer` instance regardless of which package\n // imports it (the app or a nested dependency). This prevents the\n // duplicate-context bug that silently breaks locale switching on native\n // when two `react-intlayer` copies are installed (see projectRoot doc).\n if (\n moduleName === 'react-intlayer' ||\n moduleName.startsWith('react-intlayer/')\n ) {\n try {\n return {\n filePath: require.resolve(moduleName, { paths: [projectRoot] }),\n type: 'sourceFile',\n };\n } catch {\n // Fall through to the default resolution below if the project root\n // copy cannot be resolved for some reason.\n }\n }\n\n // @formatjs packages have invalid exports configuration or missing exports for polyfills\n // By disabling package exports for these modules, we avoid the Metro warnings and let it\n // fall back cleanly to file-based resolution.\n if (moduleName.startsWith('@formatjs/')) {\n inflightFallbackContexts.add(context);\n try {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const cleanContext = {\n ...(context as any),\n unstable_enablePackageExports: false,\n };\n return getMetroResolve()(cleanContext, moduleName, ...args);\n } finally {\n inflightFallbackContexts.delete(context);\n }\n }\n\n // Delegate to the user-provided resolver if present\n if (existingResolveRequest) {\n return existingResolveRequest(context, moduleName, ...args);\n }\n\n // Re-entry guard: metro-resolver has already been invoked for this\n // context and is now calling back through context.resolveRequest (the\n // outer chain) which has bubbled back to us. Strip resolveRequest so\n // metro-resolver resolves the module with only its built-in rules\n // (alias, extraNodeModules, etc.) and does not recurse again.\n if (inflightFallbackContexts.has(context)) {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const { resolveRequest: _r, ...pureContext } = context as any;\n return getMetroResolve()(pureContext, moduleName, ...args);\n }\n\n // First pass: call metro-resolver while preserving context.resolveRequest\n // so outer wrappers (NativeWind, Sentry, …) still get a chance to\n // handle modules that metro-resolver cannot locate on its own (e.g. @/\n // tsconfig path aliases that a wrapper resolves via its own logic).\n inflightFallbackContexts.add(context);\n try {\n return getMetroResolve()(context, moduleName, ...args);\n } finally {\n inflightFallbackContexts.delete(context);\n }\n },\n blockList: [\n ...existingPatterns,\n ...configuration.content.fileExtensions.map(\n (ext) => new RegExp(`.*${ext.replace(/\\./g, '\\\\.')}$`)\n ),\n ],\n },\n } as MetroConfig;\n\n return config;\n};\n\n/**\n * // metro.config.js\n * const { getDefaultConfig } = require(\"expo/metro-config\");\n * const { configMetroIntlayer } = require(\"react-native-intlayer/metro\");\n *\n * module.exports = (async () => {\n * const defaultConfig = getDefaultConfig(__dirname);\n *\n * return await configMetroIntlayer(defaultConfig);\n * })();\n * ```\n *\n * > Note: `configMetroIntlayer` builds intlayer dictionaries on server start. Use `configMetroIntlayerSync` instead if you want to skip that.\n */\nexport const configMetroIntlayer = async (\n baseConfig?: MetroConfig\n): Promise<MetroConfig> => {\n const configuration = getConfiguration();\n\n await prepareIntlayer(configuration);\n\n return configMetroIntlayerSync(baseConfig);\n};\n"],"mappings":";;;;;;;AAeA,MAAM,wBAAqC;CACzC,IAAI;EACF,MAAM,kBAAkBA,kBACd,QAAQ,oBAAoB,GACpC,IACF;EACA,iBAEIA,QAAY,iBAAiB,gBAAgB,gBAAgB,CAC/D,CAAC,CACD;CACJ,QAAQ;EACN,iBAAgB,gBAAgB,CAAC,CAC9B;CACL;AACF;;;;;;;;;;;;;;AAiBA,MAAa,2BACX,eACgB;CAChB,MAAM,gBAAgB,iBAAiB;CAEvC,MAAM,QAAQ,SAAS;EACrB;EACA,WAAWA;CACb,CAAC;;;;;;;;;;;;;;;CAgBD,MAAM,cAAc,cAAc,OAAO;CAEzC,MAAM,oBAAoB,YAAY,UAAU;CAChD,MAAM,mBACJ,6BAA6B,SACzB,CAAC,iBAAiB,IACjB,qBAAqB,CAAC;CAE7B,MAAM,yBAAyB,YAAY,UAAU;;;;;;;;;;;;;;;;;CAkBrD,MAAM,2CAA2B,IAAI,QAAgB;CAwGrD,OAAO;EArGL,GAAG;EAEH,UAAU;GACR,GAAG,YAAY;GACf,iBAAiB,SAAS,YAAY,GAAG,SAAS;IAChD,IAAI,OAAO,KAAK,KAAK,CAAC,CAAC,SAAS,UAAU,GACxC,OAAO;KACL,UAAU,MAAM;KAChB,MAAM;IACR;IAIF,IAAI,eAAe,2BACjB,OAAO;KACL,oBAAkB,QAAQ,yBAAyB;KACnD,MAAM;IACR;IAIF,IAAI,eAAe,uBAEjB,OAAO;KACL,oBAAkB,QAAQ,6BAA6B;KACvD,MAAM;IACR;IAOF,IACE,eAAe,oBACf,WAAW,WAAW,iBAAiB,GAEvC,IAAI;KACF,OAAO;MACL,oBAAkB,QAAQ,YAAY,EAAE,OAAO,CAAC,WAAW,EAAE,CAAC;MAC9D,MAAM;KACR;IACF,QAAQ,CAGR;IAMF,IAAI,WAAW,WAAW,YAAY,GAAG;KACvC,yBAAyB,IAAI,OAAO;KACpC,IAAI;MAEF,MAAM,eAAe;OACnB,GAAI;OACJ,+BAA+B;MACjC;MACA,OAAO,gBAAgB,CAAC,CAAC,cAAc,YAAY,GAAG,IAAI;KAC5D,UAAU;MACR,yBAAyB,OAAO,OAAO;KACzC;IACF;IAGA,IAAI,wBACF,OAAO,uBAAuB,SAAS,YAAY,GAAG,IAAI;IAQ5D,IAAI,yBAAyB,IAAI,OAAO,GAAG;KAEzC,MAAM,EAAE,gBAAgB,IAAI,GAAG,gBAAgB;KAC/C,OAAO,gBAAgB,CAAC,CAAC,aAAa,YAAY,GAAG,IAAI;IAC3D;IAMA,yBAAyB,IAAI,OAAO;IACpC,IAAI;KACF,OAAO,gBAAgB,CAAC,CAAC,SAAS,YAAY,GAAG,IAAI;IACvD,UAAU;KACR,yBAAyB,OAAO,OAAO;IACzC;GACF;GACA,WAAW,CACT,GAAG,kBACH,GAAG,cAAc,QAAQ,eAAe,KACrC,QAAQ,IAAI,OAAO,KAAK,IAAI,QAAQ,OAAO,KAAK,EAAE,EAAE,CACvD,CACF;EACF;CAGU;AACd;;;;;;;;;;;;;;;AAgBA,MAAa,sBAAsB,OACjC,eACyB;CAGzB,MAAM,gBAFgB,iBAEY,CAAC;CAEnC,OAAO,wBAAwB,UAAU;AAC3C"}
|
|
1
|
+
{"version":3,"file":"configMetroIntlayer.mjs","names":["pathResolve"],"sources":["../../src/configMetroIntlayer.ts"],"sourcesContent":["import { resolve as pathResolve } from 'node:path';\nimport { getConfiguration } from '@intlayer/config/node';\nimport { getAlias } from '@intlayer/config/utils';\nimport { prepareIntlayer } from '@intlayer/engine/build';\nimport type { getDefaultConfig } from 'expo/metro-config';\n\n/**\n * Returns the `resolve` function from metro-resolver, preferring the copy\n * bundled inside Metro itself. Loading from Metro's own package directory\n * ensures we use the same resolver instance that Metro uses internally,\n * which prevents the cross-version recursion described in\n * https://github.com/aymericzip/intlayer/issues/457.\n */\ntype AnyResolver = (context: any, moduleName: string, ...args: any[]) => any;\n\nconst getMetroResolve = (): AnyResolver => {\n try {\n const metroPackageDir = pathResolve(\n require.resolve('metro/package.json'),\n '..'\n );\n return (\n require(\n pathResolve(metroPackageDir, 'node_modules', 'metro-resolver')\n ) as typeof import('metro-resolver')\n ).resolve as AnyResolver;\n } catch {\n return (require('metro-resolver') as typeof import('metro-resolver'))\n .resolve as AnyResolver;\n }\n};\n\ntype MetroConfig = ReturnType<typeof getDefaultConfig>;\n\n/**\n * // metro.config.js\n * const { getDefaultConfig } = require(\"expo/metro-config\");\n * const { configMetroIntlayerSync } = require(\"react-native-intlayer/metro\");\n *\n *\n * const defaultConfig = getDefaultConfig(__dirname);\n *\n * return configMetroIntlayerSync(defaultConfig);\n * ```\n *\n * > Note: `configMetroIntlayerSync` does not build intlayer dictionaries on server start. Use `configMetroIntlayer` for that.\n */\nexport const configMetroIntlayerSync = (\n baseConfig?: MetroConfig\n): MetroConfig => {\n const configuration = getConfiguration();\n\n const alias = getAlias({\n configuration,\n formatter: pathResolve, // get absolute path\n });\n\n /**\n * Project root, used to force `react-intlayer` to resolve to a single copy.\n *\n * Metro does not deduplicate packages the way web bundlers do. When a\n * dependency (e.g. `react-native-intlayer`) pins a different patch of\n * `react-intlayer` than the app, npm/yarn keep two physical copies. The\n * provider would then create its React context from one copy while\n * `useLocale`/`useIntlayer` read the context from the other — two distinct\n * `IntlayerClientContext` instances. The provider's updates never reach the\n * consumers, so `setLocale()` silently does nothing on native.\n *\n * Resolving every `react-intlayer` request from the project root collapses\n * those copies to a single module instance (and therefore a single context).\n */\n const projectRoot = configuration.system.baseDir;\n\n const existingBlockList = baseConfig?.resolver?.blockList;\n const existingPatterns: RegExp[] =\n existingBlockList instanceof RegExp\n ? [existingBlockList]\n : (existingBlockList ?? []);\n\n const existingResolveRequest = baseConfig?.resolver?.resolveRequest;\n\n /**\n * Tracks resolution contexts that are currently executing inside the\n * metro-resolver fallback call. When metro-resolver cannot find a module it\n * may call back through `context.resolveRequest` (the outermost resolver in\n * the chain, e.g. Sentry → NativeWind → ours). That callback eventually\n * reaches our resolver again. Without a guard we would recurse indefinitely\n * (see issue #457).\n *\n * On the second entry we break the cycle by stripping `resolveRequest` from\n * the context so metro-resolver finishes with its built-in logic only\n * (alias, extraNodeModules, …) rather than calling back a third time.\n *\n * Metro creates a fresh context object per module resolution, so using a\n * WeakSet keyed on context is safe and causes no cross-resolution\n * interference.\n */\n const inflightFallbackContexts = new WeakSet<object>();\n\n const config = {\n ...baseConfig,\n\n resolver: {\n ...baseConfig?.resolver,\n resolveRequest: (context, moduleName, ...args) => {\n if (Object.keys(alias).includes(moduleName)) {\n return {\n filePath: alias[moduleName as keyof typeof alias],\n type: 'sourceFile',\n };\n }\n\n // Because metro does not resolve submodules, we need to resolve the path manually\n if (moduleName === '@intlayer/config/client') {\n return {\n filePath: require.resolve('@intlayer/config/client'),\n type: 'sourceFile',\n };\n }\n\n // Because metro does not resolve submodules, we need to resolve the path manually\n if (moduleName === '@intlayer/core/file') {\n // Force React Native to use the correct transpiled version\n return {\n filePath: require.resolve('@intlayer/core/file/browser'),\n type: 'sourceFile',\n };\n }\n\n // Force a single `react-intlayer` instance regardless of which package\n // imports it (the app or a nested dependency). This prevents the\n // duplicate-context bug that silently breaks locale switching on native\n // when two `react-intlayer` copies are installed (see projectRoot doc).\n if (\n moduleName === 'react-intlayer' ||\n moduleName.startsWith('react-intlayer/')\n ) {\n try {\n return {\n filePath: require.resolve(moduleName, { paths: [projectRoot] }),\n type: 'sourceFile',\n };\n } catch {\n // Fall through to the default resolution below if the project root\n // copy cannot be resolved for some reason.\n }\n }\n\n // @formatjs packages have invalid exports configuration or missing exports for polyfills\n // By disabling package exports for these modules, we avoid the Metro warnings and let it\n // fall back cleanly to file-based resolution.\n if (moduleName.startsWith('@formatjs/')) {\n inflightFallbackContexts.add(context);\n try {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const cleanContext = {\n ...(context as any),\n unstable_enablePackageExports: false,\n };\n return getMetroResolve()(cleanContext, moduleName, ...args);\n } finally {\n inflightFallbackContexts.delete(context);\n }\n }\n\n // Delegate to the user-provided resolver if present\n if (existingResolveRequest) {\n return existingResolveRequest(context, moduleName, ...args);\n }\n\n // Re-entry guard: metro-resolver has already been invoked for this\n // context and is now calling back through context.resolveRequest (the\n // outer chain) which has bubbled back to us. Strip resolveRequest so\n // metro-resolver resolves the module with only its built-in rules\n // (alias, extraNodeModules, etc.) and does not recurse again.\n if (inflightFallbackContexts.has(context)) {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const { resolveRequest: _r, ...pureContext } = context as any;\n return getMetroResolve()(pureContext, moduleName, ...args);\n }\n\n // First pass: call metro-resolver while preserving context.resolveRequest\n // so outer wrappers (NativeWind, Sentry, …) still get a chance to\n // handle modules that metro-resolver cannot locate on its own (e.g. @/\n // tsconfig path aliases that a wrapper resolves via its own logic).\n inflightFallbackContexts.add(context);\n try {\n return getMetroResolve()(context, moduleName, ...args);\n } finally {\n inflightFallbackContexts.delete(context);\n }\n },\n blockList: [\n ...existingPatterns,\n ...configuration.content.fileExtensions.map(\n (ext) => new RegExp(`.*${ext.replace(/\\./g, '\\\\.')}$`)\n ),\n ],\n },\n } as MetroConfig;\n\n return config;\n};\n\n/**\n * // metro.config.js\n * const { getDefaultConfig } = require(\"expo/metro-config\");\n * const { configMetroIntlayer } = require(\"react-native-intlayer/metro\");\n *\n * module.exports = (async () => {\n * const defaultConfig = getDefaultConfig(__dirname);\n *\n * return await configMetroIntlayer(defaultConfig);\n * })();\n * ```\n *\n * > Note: `configMetroIntlayer` builds intlayer dictionaries on server start. Use `configMetroIntlayerSync` instead if you want to skip that.\n */\nexport const configMetroIntlayer = async (\n baseConfig?: MetroConfig\n): Promise<MetroConfig> => {\n const configuration = getConfiguration();\n\n await prepareIntlayer(configuration);\n\n return configMetroIntlayerSync(baseConfig);\n};\n"],"mappings":";;;;;;;AAeA,MAAM,wBAAqC;CACzC,IAAI;EACF,MAAM,kBAAkBA,kBACd,QAAQ,oBAAoB,GACpC,IACF;EACA,iBAEIA,QAAY,iBAAiB,gBAAgB,gBAAgB,CAC/D,CAAC,CACD;CACJ,QAAQ;EACN,iBAAgB,gBAAgB,CAAC,CAC9B;CACL;AACF;;;;;;;;;;;;;;AAiBA,MAAa,2BACX,eACgB;CAChB,MAAM,gBAAgB,iBAAiB;CAEvC,MAAM,QAAQ,SAAS;EACrB;EACA,WAAWA;CACb,CAAC;;;;;;;;;;;;;;;CAgBD,MAAM,cAAc,cAAc,OAAO;CAEzC,MAAM,oBAAoB,YAAY,UAAU;CAChD,MAAM,mBACJ,6BAA6B,SACzB,CAAC,iBAAiB,IACjB,qBAAqB,CAAC;CAE7B,MAAM,yBAAyB,YAAY,UAAU;;;;;;;;;;;;;;;;;CAkBrD,MAAM,2CAA2B,IAAI,QAAgB;CAwGrD,OAAO;EArGL,GAAG;EAEH,UAAU;GACR,GAAG,YAAY;GACf,iBAAiB,SAAS,YAAY,GAAG,SAAS;IAChD,IAAI,OAAO,KAAK,KAAK,CAAC,CAAC,SAAS,UAAU,GACxC,OAAO;KACL,UAAU,MAAM;KAChB,MAAM;IACR;IAIF,IAAI,eAAe,2BACjB,OAAO;KACL,oBAAkB,QAAQ,yBAAyB;KACnD,MAAM;IACR;IAIF,IAAI,eAAe,uBAEjB,OAAO;KACL,oBAAkB,QAAQ,6BAA6B;KACvD,MAAM;IACR;IAOF,IACE,eAAe,oBACf,WAAW,WAAW,iBAAiB,GAEvC,IAAI;KACF,OAAO;MACL,oBAAkB,QAAQ,YAAY,EAAE,OAAO,CAAC,WAAW,EAAE,CAAC;MAC9D,MAAM;KACR;IACF,QAAQ,CAGR;IAMF,IAAI,WAAW,WAAW,YAAY,GAAG;KACvC,yBAAyB,IAAI,OAAO;KACpC,IAAI;MAEF,MAAM,eAAe;OACnB,GAAI;OACJ,+BAA+B;MACjC;MACA,OAAO,gBAAgB,CAAC,CAAC,cAAc,YAAY,GAAG,IAAI;KAC5D,UAAU;MACR,yBAAyB,OAAO,OAAO;KACzC;IACF;IAGA,IAAI,wBACF,OAAO,uBAAuB,SAAS,YAAY,GAAG,IAAI;IAQ5D,IAAI,yBAAyB,IAAI,OAAO,GAAG;KAEzC,MAAM,EAAE,gBAAgB,IAAI,GAAG,gBAAgB;KAC/C,OAAO,gBAAgB,CAAC,CAAC,aAAa,YAAY,GAAG,IAAI;IAC3D;IAMA,yBAAyB,IAAI,OAAO;IACpC,IAAI;KACF,OAAO,gBAAgB,CAAC,CAAC,SAAS,YAAY,GAAG,IAAI;IACvD,UAAU;KACR,yBAAyB,OAAO,OAAO;IACzC;GACF;GACA,WAAW,CACT,GAAG,kBACH,GAAG,cAAc,QAAQ,eAAe,KACrC,QAAQ,IAAI,OAAO,KAAK,IAAI,QAAQ,OAAO,KAAK,EAAE,EAAE,CACvD,CACF;EACF;CAGU;AACd;;;;;;;;;;;;;;;AAgBA,MAAa,sBAAsB,OACjC,eACyB;CACzB,MAAM,gBAAgB,iBAAiB;CAEvC,MAAM,gBAAgB,aAAa;CAEnC,OAAO,wBAAwB,UAAU;AAC3C"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "react-native-intlayer",
|
|
3
|
-
"version": "9.
|
|
3
|
+
"version": "9.3.1",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "A React Native plugin for seamless internationalization (i18n), providing locale detection, redirection, and environment-based configuration",
|
|
6
6
|
"keywords": [
|
|
@@ -114,19 +114,19 @@
|
|
|
114
114
|
"typecheck": "tsc --noEmit --project tsconfig.types.json"
|
|
115
115
|
},
|
|
116
116
|
"dependencies": {
|
|
117
|
-
"@intlayer/config": "9.
|
|
118
|
-
"@intlayer/core": "9.
|
|
119
|
-
"@intlayer/engine": "9.
|
|
120
|
-
"@intlayer/types": "9.
|
|
121
|
-
"react-intlayer": "9.
|
|
117
|
+
"@intlayer/config": "9.3.1",
|
|
118
|
+
"@intlayer/core": "9.3.1",
|
|
119
|
+
"@intlayer/engine": "9.3.1",
|
|
120
|
+
"@intlayer/types": "9.3.1",
|
|
121
|
+
"react-intlayer": "9.3.1"
|
|
122
122
|
},
|
|
123
123
|
"devDependencies": {
|
|
124
|
-
"@types/node": "26.
|
|
124
|
+
"@types/node": "26.2.0",
|
|
125
125
|
"@types/react": ">=18.0.0",
|
|
126
126
|
"@utils/ts-config": "1.0.4",
|
|
127
127
|
"@utils/ts-config-types": "1.0.4",
|
|
128
128
|
"@utils/tsdown-config": "1.0.4",
|
|
129
|
-
"expo": "57.0.
|
|
129
|
+
"expo": "57.0.11",
|
|
130
130
|
"metro-resolver": "0.87.0",
|
|
131
131
|
"react": ">=18.0.0",
|
|
132
132
|
"rimraf": "6.1.3",
|