{"_id":"@atmina/inting","name":"@atmina/inting","dist-tags":{"latest":"0.0.1"},"versions":{"0.0.1":{"name":"@atmina/inting","version":"0.0.1","main":"./dist/index.js","types":"./dist/index.d.ts","license":"MIT","scripts":{"clean":"rimraf ./dist","prebuild":"pnpm clean","build/":"tsup ./src/index.ts --target es6 --dts && tsup src/internals/middleware.ts --target es6 && tsup ./src/cli.ts --target esnext --format esm && copyfiles src/templates/* dist -u 1","build":"tsc && rimraf ./dist/templates/*.* && copyfiles ./src/templates/* ./dist -u 1","lint":"eslint src/**/*.ts*"},"bin":{"inting":"bin/inting.js"},"sideEffects":false,"devDependencies":{"@types/node":"^17.0.12","@types/react":"^18.0.17","@types/react-dom":"^18.0.6","copyfiles":"^2.4.1","eslint":"^7.32.0","eslint-config-custom":"workspace:*","next":"^13.1.1","react":"^18.2.0","react-dom":"18.2.0","rimraf":"^3.0.2","tsconfig":"workspace:*","tsup":"^6.5.0","typescript":"^4.5.2"},"dependencies":{"@boost/module":"^4.0.0","dataloader":"^2.1.0","filenamify":"^5.1.1","find-up":"^6.3.0","strip-indent":"^4.0.0","yaml":"^2.1.3"},"peerDependencies":{"next":"^13.0.0","react":"^18.2.0","react-dom":"18.2.0"},"publishConfig":{"access":"public"},"gitHead":"f6a348e980793f87c7b35c70f0455f3a3e634f5c","description":"A simple type-safe translation micro-framework for server components in Next.js 13+.","_id":"@atmina/inting@0.0.1","_nodeVersion":"19.0.0","_npmVersion":"8.19.2","dist":{"integrity":"sha512-eLuW+hNaTTnP8nurf4MWvlXwmzrz2mPIF7Nd57EO8q45/1JfeZx0nEtJd7cLxHgMeXvTucFkaCT8C9jvcBoGIQ==","shasum":"9fa1092a8bc01f04cf40979d6698373f6b7ab939","tarball":"https://registry.npmjs.org/@atmina/inting/-/inting-0.0.1.tgz","fileCount":37,"unpackedSize":36500,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQDwXHC1ecU+7bp2wluskb4zmZyUjGTgLNwLF2sC9wW4wAIhAK8YJrl/F7UXJNjCpIW2mrRqr6UTAsY1OZdLX4l4jPeB"}],"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJjwR+rACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2Vmrd/Q/9EotVm0tPwQVg9DA15kbUfQ8fD92PyYdE1wO6rBSvfp81KKu4\r\nHQHtPKj/2BC2Ft1wLtIiNatcKzh+35drwqVTSI8lUxNKfvdy2dZ1HgwBiNvy\r\nYMmifUjicTyskblxLfkT/mmq0xYgxwZYvHMr8pVCsUijGc/TT9m6L64lJSCb\r\ntX7zvMUOxacYH1oV7rKV3dOh8vW41KdQo1L1bQJ6RjOTQhK8Xs6Ia0kYaZvG\r\nOcB8pn+icLib8KznhW4wlaOqO0Z/cJwUAIbbA/wqCERwJtAIjAwfnW8/np4/\r\npidJGCKvsk8Xmoc6wuC0ktSMTQK537A7jhO+mpZyV3CaM6Mx4tytLTwB82p9\r\ndu+5WFlZOw6gp/XczdNue9j0IV0GWOcB0vw6xY5Rm2+AmkbyEwEiBUP7yzvX\r\nB3qh55BjVsYl33ilmvkwrMWYVDs00WeRUkYAj5VxQ5Ck/I9rRo5ZQs49byGu\r\nHBQfavUBTnAEHmztK6NYArK34mcfZbqdvvfo5aDz3p4P8gGU6Dd4IGooGqBh\r\nFxbzhK9hogdfkKI5Lwq7Hcuvsl+RT4cj2zgoTPMnmF96OJAw7QPD0BLLbvMP\r\nQTi7JnbalEb0GLknfQTyXSDWl5nCMN0BPlvuTS5T3SGVMUBErxkSHJHBeA2p\r\nr2RGJlwYauYgzWvUDWlLkwp6JDPlXxNxnzg=\r\n=EblX\r\n-----END PGP SIGNATURE-----\r\n"},"_npmUser":{"name":"atmina-owner","email":"info@atmina.de"},"directories":{},"maintainers":[{"name":"atmina-owner","email":"info@atmina.de"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/inting_0.0.1_1673600939509_0.47941542360622025"},"_hasShrinkwrap":false}},"time":{"created":"2023-01-13T09:08:59.457Z","0.0.1":"2023-01-13T09:08:59.713Z","modified":"2023-01-13T09:08:59.862Z"},"maintainers":[{"name":"atmina-owner","email":"info@atmina.de"}],"description":"A simple type-safe translation micro-framework for server components in Next.js 13+.","license":"MIT","readme":"# @atmina/inting\n\nA simple type-safe translation micro-framework for server components in Next.js 13+.\n\n## Usage\n\n1. Create an `inting.config.ts` next to your `package.json`.\n   \n   ```ts\n    import { IntingConfig } from \"@atmina/inting\";\n    import { presetFiles } from \"@atmina/inting-preset-files\";\n\n    const config: IntingConfig = {\n        locales: [\"en\", \"de\"],\n        defaultLocale: \"en\",\n        outDir: \"./src/__generated__\",\n        ...presetFiles('./translations'),\n    };\n\n    export default config;\n   ```\n2. Run `npm/pnpm/yarn inting`\n3. Create a layout that wraps your content in a `LocaleProvider`.\n\n   ```tsx\n   // app/[locale]/layout.tsx\n\n   import { LocaleProvider } from \"../../__generated__/server\";\n   import { ReactNode } from \"react\";\n\n   const Layout = ({ params, children }: { params?: any; children: ReactNode }) => {\n     if (!params) {\n       return null;\n     }\n   \n     return <LocaleProvider value={params.locale}>{children}</LocaleProvider>;\n   };\n\n   export default Layout;\n   ```\n   \n4. Consume translations with the `useTranslation` hook. Note that you can only import this in server components.\n\n   ```tsx\n   // app/[locale]/page.tsx\n   \n   import { useTranslation } from \"../../__generated__/server\";\n\n   const PageContent = async () => {\n     const t = useTranslation();\n   \n     return (\n       <>\n         <h1>{t(\"home.title\")}</h1>\n         <p>{t(\"home.content\")}</p>\n       </>\n     );\n   }\n   \n   export default () => <PageContent />;\n   ```\n\n## Config\n\n### `locales`\n\nAn array of locale codes.\n\n### `defaultLocale`\n\nThe default locale is treated specially when `implicitDefaultLocale` is enabled.\n\n### `implicitDefaultLocale`\n\nWhen `true`, the default locale is not prefixed to the path unless explicitly provided.\n\nDefault: `true`\n\n### `cookieName`\n\nThe cookie that is read when detecting the browser's locale. This takes precedence over `accept-language`. Use it to\npersist the user's locale preference.\n\nDefault: `\"NEXT_LOCALE\"`\n\n### `getTranslations(locale, keys, getNamespace)`\n\nReceives the current locale and the requested keys. Returns a `Promise` of strings corresponding to the requested keys.\nThe order of the returned values must match the order of the keys (if this sounds a lot like a `DataLoader`, that is\nbecause it is).\n\n### `getStaticNamespaces(context)`\n\nOptional. Use this to retrieve resources (e.g. from the local file system or a remote API) to be bundled with your\ngenerated source files. This is invoked when running the `inting` command. A static namespace can be loaded with the\nprovided function in `getTranslations`.\n\n### `getStaticKeys(context, namespaces)`\n\nOptional. Return an exhaustive list of keys that should be made available for looking up translations. Use this to add\ntype-checking to your translation keys and provide tooltips in some IDEs such as WebStorm.\n\n\n## Presets\n\nPresets can be built by creating an object that exposes the same three config API methods described above. These can\nsimply be added to the final config with spread notation `{...preset(options)}`.\n\nFor file-based translations, you can install `@atmina/inting-preset-files` or use it as a basis for your own config.\n\n## Generated modules\n\n| Filename        | Description                                   |\n|-----------------|-----------------------------------------------|\n| `static/`       | Statically generated namespace files          |\n| `types.ts`      | Types of locales and translation keys         |\n| `server.ts`     | Server-only code (e.g. `useTranslation` hook) |\n| `shared.ts`     | Code for server and client components         |\n| `link.ts`       | `LocaleLink`, a wrapper for `next/link`       |\n| `middleware.ts` | Middleware implementation                     |\n\nWe encourage you to re-export these modules to fit your project's needs and conventions.\n\n## Middleware\n\nUse the generated middleware to enable the following behaviors:\n\n- Detecting locale from the browser's `accept-language` header or a cookie, if provided\n- Prefixing the path with the locale if it isn't already present\n    - For non-default locales, this is a redirect\n    - In the default locale and with `implicitDefaultLocale`, this is a rewrite, concealing the actual path.\n\nThis closely mirrors what Next.js does with its built-in i18n support in the `/pages` directory.\n\nYour `middleware.ts` should be located next to the `/pages` directory. Bear in mind that the config is statically\nanalyzed and must therefore contain only constant values (no imports or function calls).\n\n```ts\nimport { middleware } from \"./__generated__/middleware\";\n\nexport { middleware };\n\nexport const config = {\n  /*\n   * Match all request paths except for the ones starting with:\n   * - api (API routes)\n   * - _next/static (static files)\n   * - favicon.ico (favicon file)\n   * Note: These patterns are NOT excluded in the default middleware config.\n   */\n  matcher: \"/((?!api|_next/static|favicon.ico).*)\",\n};\n```\n\n## Client components\n\nGetting translations into client components requires a bit more effort. Note that in client components, any code written\nfor the server side (including `server.ts`) may not be imported directly. Therefore, the required translation strings\nmust be retrieved in a parent server component and passed to the client component. \n\nFor simple cases, it may be enough to pass the result of one or more `t(...)` calls via props or children. For\ncomponents that depend on multiple translations known in advance, the framework provides a `translateClientComponent`\nhelper. To use it, first define a set of translation keys required by the client component. It is important to separate\nthis definition from the actual component code that is contained in the `\"use client\"` boundary, as it cannot be\nimported from server code otherwise.\n\n```tsx\n// translations.ts\n\nimport { createClientTranslation } from './__generated__/shared';\n\nexport const counterTranslation = createClientTranslation(['counter.increment', 'counter.decrement']);\n\nexport type CounterTranslation = typeof counterTranslation;\n```\n\nThe `TFC` (translatable function component) type describes a component that expects these translations to be provided\nvia a `t` prop, which is just a mapping of keys to values.\n\n```tsx\n// counter.tsx  (Logic omitted for brevity)\n\n\"use client\";\n\nimport { TFC } from './__generated__/shared';\nimport { type CounterTranslation } from './translations';\n\nexport const Counter: TFC<{initialValue: number}, CounterTranslation> = ({\n  t, // t contains the set of translations provided from the server side\n}) => {\n  return (\n    <div>\n      <code>{value}</code>\n      <hr />\n      <div>\n        <button>\n          (+) {t[\"counter.increment\"]}\n        </button>\n        <button>\n          (-) {t[\"counter.decrement\"]}\n        </button>\n      </div>\n    </div>\n  );\n};\n```\n\nFinally, on the server side, wrap this component in `translateClientComponent`, which takes care  of retrieving the\nnecessary translations when the component is rendered.\n\n```tsx\nimport { Counter } from './counter';\nimport { counterTranslation } from './translations';\nimport { translateClientComponent } from \"./__generated__/server\";\n\nconst TranslatedCounter = translateClientComponent(Counter, counterTranslation);\n```\n\n## License\n\nMIT","readmeFilename":"README.md"}