@babelize/next 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/README.md ADDED
@@ -0,0 +1,126 @@
1
+ # @babelize/next
2
+
3
+ **Next.js build plugin for Babelize** — automatically discover and pre-translate strings during `next build`.
4
+
5
+ ```ts
6
+ // next.config.ts
7
+ import withBabelize from "@babelize/next";
8
+
9
+ export default withBabelize(
10
+ { /* your Next.js config */ },
11
+ { locales: ["ja", "fr", "de"] },
12
+ );
13
+ ```
14
+
15
+ ---
16
+
17
+ ## Install
18
+
19
+ ```bash
20
+ bun add @babelize/next -D
21
+ ```
22
+
23
+ ---
24
+
25
+ ## Quick Start
26
+
27
+ ### 1. Wrap your Next.js config
28
+
29
+ ```ts
30
+ // next.config.ts
31
+ import withBabelize from "@babelize/next";
32
+
33
+ const nextConfig = {
34
+ // your existing config
35
+ };
36
+
37
+ export default withBabelize(nextConfig, {
38
+ locales: ["ja", "fr", "de"],
39
+ });
40
+ ```
41
+
42
+ ### 2. Set your API key
43
+
44
+ ```env
45
+ # .env.local
46
+ BABELIZE_API_KEY=blz_sk_xxxxxxxxx
47
+ ```
48
+
49
+ ### 3. Build
50
+
51
+ ```bash
52
+ bun run build
53
+ ```
54
+
55
+ The plugin scans your source files during the build, translates discovered strings, and writes `babelize-lock.json` to your project root.
56
+
57
+ ---
58
+
59
+ ## How It Works
60
+
61
+ The plugin integrates with Next.js's webpack build pipeline:
62
+
63
+ 1. **Scans** source files for `babelize("...")`, `babelize.p(...)`, and `<BabelizeTag>` calls
64
+ 2. **Translates** via the Babelize API for each configured locale
65
+ 3. **Writes** `babelize-lock.json` after the build completes
66
+
67
+ The lockfile is then consumed by `@babelize/sdk-next` at runtime:
68
+
69
+ ```tsx
70
+ // app/page.tsx
71
+ import { babelizeRSC, loadLockfile } from "@babelize/sdk-next";
72
+ import lockfile from "./babelize-lock.json";
73
+
74
+ loadLockfile(lockfile);
75
+
76
+ export default async function Home() {
77
+ return <h1>{await babelizeRSC("Welcome to Babelize")}</h1>;
78
+ }
79
+ ```
80
+
81
+ ---
82
+
83
+ ## Options
84
+
85
+ ```ts
86
+ interface BabelizeNextPluginOptions {
87
+ apiKey?: string;
88
+ locales?: string[];
89
+ output?: string;
90
+ functionName?: string;
91
+ apiUrl?: string;
92
+ include?: string[];
93
+ }
94
+ ```
95
+
96
+ | Option | Type | Default | Description |
97
+ |--------|------|---------|-------------|
98
+ | `locales` | `string[]` | — | Target locales to translate to |
99
+ | `apiKey` | `string` | `process.env.BABELIZE_API_KEY` | Babelize API key |
100
+ | `output` | `string` | `"babelize-lock.json"` | Output path for the lockfile |
101
+ | `functionName` | `string` | `"babelize"` | Function name to scan for |
102
+ | `apiUrl` | `string` | `"https://api.babelize.co/api"` | API base URL |
103
+ | `include` | `string[]` | `["src/**/*.{tsx,ts,jsx,js}", "app/**/*.{tsx,ts,jsx,js}", "pages/**/*.{tsx,ts,jsx,js}"]` | Glob patterns for source files |
104
+
105
+ ---
106
+
107
+ ## Lockfile
108
+
109
+ The generated `babelize-lock.json` is identical in format to the one produced by `@babelize/vite`. See the [Vite plugin documentation](https://github.com/babelize/babelize-dashboard/tree/main/packages/sdk-plugin-vite) for the full format reference.
110
+
111
+ ---
112
+
113
+ ## TypeScript
114
+
115
+ ```ts
116
+ import type { BabelizeNextPluginOptions } from "@babelize/next";
117
+
118
+ interface BabelizeNextPluginOptions {
119
+ apiKey?: string;
120
+ locales?: string[];
121
+ output?: string;
122
+ functionName?: string;
123
+ apiUrl?: string;
124
+ include?: string[];
125
+ }
126
+ ```
package/dist/index.cjs ADDED
@@ -0,0 +1,127 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/index.ts
21
+ var index_exports = {};
22
+ __export(index_exports, {
23
+ default: () => index_default,
24
+ withBabelize: () => withBabelize
25
+ });
26
+ module.exports = __toCommonJS(index_exports);
27
+ var import_node_fs = require("fs");
28
+ var import_node_path = require("path");
29
+ var import_glob = require("glob");
30
+ var DEFAULT_INCLUDE = ["src/**/*.{tsx,ts,jsx,js}", "app/**/*.{tsx,ts,jsx,js}", "pages/**/*.{tsx,ts,jsx,js}"];
31
+ var DEFAULT_OUTPUT = "babelize-lock.json";
32
+ var DEFAULT_API_URL = "https://api.babelize.co/api";
33
+ var BABELIZE_CALL_REGEX = /\bbabelize\s*\(\s*(["'`])((?:[^\\"']|\\.)*?)\1\s*[),]/g;
34
+ function scanFiles(rootDir, patterns) {
35
+ const strings = [];
36
+ for (const pattern of patterns) {
37
+ const files = (0, import_glob.globSync)(pattern, { cwd: rootDir, ignore: ["**/node_modules/**"] });
38
+ for (const file of files) {
39
+ try {
40
+ const content = (0, import_node_fs.readFileSync)((0, import_node_path.resolve)(rootDir, file), "utf-8");
41
+ const matches = content.matchAll(BABELIZE_CALL_REGEX);
42
+ for (const match of matches) {
43
+ strings.push(match[2]);
44
+ }
45
+ } catch {
46
+ }
47
+ }
48
+ }
49
+ return strings;
50
+ }
51
+ var BabelizeWebpackPlugin = class {
52
+ constructor(rootDir, options, output) {
53
+ this.rootDir = rootDir;
54
+ this.options = options;
55
+ this.output = output;
56
+ }
57
+ apply(compiler) {
58
+ compiler.hooks.done.tapPromise("BabelizeWebpackPlugin", async () => {
59
+ const apiKey = this.options.apiKey ?? process.env.BABELIZE_API_KEY;
60
+ const locales = this.options.locales;
61
+ const apiUrl = this.options.apiUrl ?? DEFAULT_API_URL;
62
+ const include = this.options.include ?? DEFAULT_INCLUDE;
63
+ const strings = scanFiles(this.rootDir, include);
64
+ const uniqueStrings = [...new Set(strings)];
65
+ if (uniqueStrings.length === 0) return;
66
+ const translationsByLocale = {};
67
+ if (apiKey && locales && locales.length > 0) {
68
+ for (const locale of locales) {
69
+ try {
70
+ const response = await fetch(`${apiUrl}/v1/translate`, {
71
+ method: "POST",
72
+ headers: {
73
+ "Content-Type": "application/json",
74
+ Authorization: `Bearer ${apiKey}`
75
+ },
76
+ body: JSON.stringify({ locale, strings: uniqueStrings })
77
+ });
78
+ if (response.ok) {
79
+ const data = await response.json();
80
+ translationsByLocale[locale] = data.translations;
81
+ }
82
+ } catch {
83
+ }
84
+ }
85
+ }
86
+ const lockfile = {
87
+ version: 1,
88
+ meta: {
89
+ generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
90
+ locales: Object.keys(translationsByLocale),
91
+ totalStrings: uniqueStrings.length
92
+ },
93
+ strings: Object.fromEntries(
94
+ uniqueStrings.map((str) => [
95
+ str,
96
+ Object.fromEntries(
97
+ Object.entries(translationsByLocale).map(([locale, t]) => [
98
+ locale,
99
+ t[str] ?? str
100
+ ])
101
+ )
102
+ ])
103
+ )
104
+ };
105
+ (0, import_node_fs.writeFileSync)((0, import_node_path.resolve)(this.rootDir, this.output), JSON.stringify(lockfile, null, 2));
106
+ });
107
+ }
108
+ };
109
+ function withBabelize(nextConfig = {}, pluginOptions = {}) {
110
+ const output = pluginOptions.output ?? DEFAULT_OUTPUT;
111
+ const originalWebpack = nextConfig.webpack;
112
+ return {
113
+ ...nextConfig,
114
+ webpack(config, options) {
115
+ if (!options.isServer) {
116
+ config.plugins.push(new BabelizeWebpackPlugin(options.dir, pluginOptions, output));
117
+ }
118
+ if (originalWebpack) return originalWebpack(config, options);
119
+ return config;
120
+ }
121
+ };
122
+ }
123
+ var index_default = withBabelize;
124
+ // Annotate the CommonJS export names for ESM import in node:
125
+ 0 && (module.exports = {
126
+ withBabelize
127
+ });
@@ -0,0 +1,14 @@
1
+ interface BabelizeNextPluginOptions {
2
+ apiKey?: string;
3
+ locales?: string[];
4
+ output?: string;
5
+ functionName?: string;
6
+ apiUrl?: string;
7
+ include?: string[];
8
+ }
9
+ interface NextConfig {
10
+ [key: string]: unknown;
11
+ }
12
+ declare function withBabelize(nextConfig?: NextConfig, pluginOptions?: BabelizeNextPluginOptions): NextConfig;
13
+
14
+ export { type BabelizeNextPluginOptions, withBabelize as default, withBabelize };
@@ -0,0 +1,14 @@
1
+ interface BabelizeNextPluginOptions {
2
+ apiKey?: string;
3
+ locales?: string[];
4
+ output?: string;
5
+ functionName?: string;
6
+ apiUrl?: string;
7
+ include?: string[];
8
+ }
9
+ interface NextConfig {
10
+ [key: string]: unknown;
11
+ }
12
+ declare function withBabelize(nextConfig?: NextConfig, pluginOptions?: BabelizeNextPluginOptions): NextConfig;
13
+
14
+ export { type BabelizeNextPluginOptions, withBabelize as default, withBabelize };
package/dist/index.js ADDED
@@ -0,0 +1,102 @@
1
+ // src/index.ts
2
+ import { readFileSync, writeFileSync } from "fs";
3
+ import { resolve } from "path";
4
+ import { globSync } from "glob";
5
+ var DEFAULT_INCLUDE = ["src/**/*.{tsx,ts,jsx,js}", "app/**/*.{tsx,ts,jsx,js}", "pages/**/*.{tsx,ts,jsx,js}"];
6
+ var DEFAULT_OUTPUT = "babelize-lock.json";
7
+ var DEFAULT_API_URL = "https://api.babelize.co/api";
8
+ var BABELIZE_CALL_REGEX = /\bbabelize\s*\(\s*(["'`])((?:[^\\"']|\\.)*?)\1\s*[),]/g;
9
+ function scanFiles(rootDir, patterns) {
10
+ const strings = [];
11
+ for (const pattern of patterns) {
12
+ const files = globSync(pattern, { cwd: rootDir, ignore: ["**/node_modules/**"] });
13
+ for (const file of files) {
14
+ try {
15
+ const content = readFileSync(resolve(rootDir, file), "utf-8");
16
+ const matches = content.matchAll(BABELIZE_CALL_REGEX);
17
+ for (const match of matches) {
18
+ strings.push(match[2]);
19
+ }
20
+ } catch {
21
+ }
22
+ }
23
+ }
24
+ return strings;
25
+ }
26
+ var BabelizeWebpackPlugin = class {
27
+ constructor(rootDir, options, output) {
28
+ this.rootDir = rootDir;
29
+ this.options = options;
30
+ this.output = output;
31
+ }
32
+ apply(compiler) {
33
+ compiler.hooks.done.tapPromise("BabelizeWebpackPlugin", async () => {
34
+ const apiKey = this.options.apiKey ?? process.env.BABELIZE_API_KEY;
35
+ const locales = this.options.locales;
36
+ const apiUrl = this.options.apiUrl ?? DEFAULT_API_URL;
37
+ const include = this.options.include ?? DEFAULT_INCLUDE;
38
+ const strings = scanFiles(this.rootDir, include);
39
+ const uniqueStrings = [...new Set(strings)];
40
+ if (uniqueStrings.length === 0) return;
41
+ const translationsByLocale = {};
42
+ if (apiKey && locales && locales.length > 0) {
43
+ for (const locale of locales) {
44
+ try {
45
+ const response = await fetch(`${apiUrl}/v1/translate`, {
46
+ method: "POST",
47
+ headers: {
48
+ "Content-Type": "application/json",
49
+ Authorization: `Bearer ${apiKey}`
50
+ },
51
+ body: JSON.stringify({ locale, strings: uniqueStrings })
52
+ });
53
+ if (response.ok) {
54
+ const data = await response.json();
55
+ translationsByLocale[locale] = data.translations;
56
+ }
57
+ } catch {
58
+ }
59
+ }
60
+ }
61
+ const lockfile = {
62
+ version: 1,
63
+ meta: {
64
+ generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
65
+ locales: Object.keys(translationsByLocale),
66
+ totalStrings: uniqueStrings.length
67
+ },
68
+ strings: Object.fromEntries(
69
+ uniqueStrings.map((str) => [
70
+ str,
71
+ Object.fromEntries(
72
+ Object.entries(translationsByLocale).map(([locale, t]) => [
73
+ locale,
74
+ t[str] ?? str
75
+ ])
76
+ )
77
+ ])
78
+ )
79
+ };
80
+ writeFileSync(resolve(this.rootDir, this.output), JSON.stringify(lockfile, null, 2));
81
+ });
82
+ }
83
+ };
84
+ function withBabelize(nextConfig = {}, pluginOptions = {}) {
85
+ const output = pluginOptions.output ?? DEFAULT_OUTPUT;
86
+ const originalWebpack = nextConfig.webpack;
87
+ return {
88
+ ...nextConfig,
89
+ webpack(config, options) {
90
+ if (!options.isServer) {
91
+ config.plugins.push(new BabelizeWebpackPlugin(options.dir, pluginOptions, output));
92
+ }
93
+ if (originalWebpack) return originalWebpack(config, options);
94
+ return config;
95
+ }
96
+ };
97
+ }
98
+ var index_default = withBabelize;
99
+ export {
100
+ index_default as default,
101
+ withBabelize
102
+ };
package/package.json ADDED
@@ -0,0 +1,37 @@
1
+ {
2
+ "name": "@babelize/next",
3
+ "version": "0.0.1",
4
+ "description": "Next.js build plugin for Babelize — auto-discover strings and generate lockfile during Next.js builds",
5
+ "type": "module",
6
+ "main": "./dist/index.js",
7
+ "module": "./dist/index.js",
8
+ "types": "./dist/index.d.ts",
9
+ "exports": {
10
+ ".": {
11
+ "types": "./dist/index.d.ts",
12
+ "import": "./dist/index.js",
13
+ "require": "./dist/index.cjs"
14
+ }
15
+ },
16
+ "files": ["dist"],
17
+ "publishConfig": {
18
+ "access": "public"
19
+ },
20
+ "scripts": {
21
+ "build": "tsup src/index.ts --format esm,cjs --dts --clean --external next",
22
+ "dev": "tsup src/index.ts --format esm,cjs --dts --watch --external next",
23
+ "typecheck": "tsc --noEmit"
24
+ },
25
+ "peerDependencies": {
26
+ "next": "^14.x || ^15.x"
27
+ },
28
+ "dependencies": {
29
+ "glob": "^11.0.0"
30
+ },
31
+ "devDependencies": {
32
+ "@types/node": "^22.0.0",
33
+ "next": "^15.x",
34
+ "tsup": "^8.4.0",
35
+ "typescript": "^5.7.3"
36
+ }
37
+ }