translate-kit 0.3.0 → 0.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/dist/cli.js CHANGED
@@ -45,7 +45,7 @@ var init_config = __esm({
45
45
  translation: z.object({
46
46
  batchSize: z.number().int().positive().default(50),
47
47
  context: z.string().optional(),
48
- glossary: z.record(z.string()).optional(),
48
+ glossary: z.record(z.string(), z.string()).optional(),
49
49
  tone: z.string().optional(),
50
50
  retries: z.number().int().min(0).default(2),
51
51
  concurrency: z.number().int().positive().default(3),
@@ -2649,17 +2649,38 @@ function parseAcceptLanguage(header: string): Locale {
2649
2649
  return defaultLocale;
2650
2650
  }
2651
2651
 
2652
+ const getLocaleStore = cache(() => ({ current: null as string | null }));
2653
+
2654
+ export function setLocale(locale: string) {
2655
+ getLocaleStore().current = locale;
2656
+ }
2657
+
2652
2658
  // Per-request cached message loading \u2014 works even when layout is cached during client-side navigation
2653
2659
  // Uses dynamic imports so this file can be safely imported from client components
2654
2660
  const getCachedMessages = cache(async (): Promise<Messages> => {
2655
- const { headers } = await import("next/headers");
2656
- const { readFile } = await import("node:fs/promises");
2657
- const { join } = await import("node:path");
2661
+ let locale: Locale | null = getLocaleStore().current as Locale | null;
2662
+
2663
+ if (!locale) {
2664
+ try {
2665
+ const { cookies } = await import("next/headers");
2666
+ const c = await cookies();
2667
+ const cookieLocale = c.get("NEXT_LOCALE")?.value;
2668
+ if (cookieLocale && supported.includes(cookieLocale as Locale)) {
2669
+ locale = cookieLocale as Locale;
2670
+ }
2671
+ } catch {}
2672
+ }
2673
+
2674
+ if (!locale) {
2675
+ const { headers } = await import("next/headers");
2676
+ const h = await headers();
2677
+ const acceptLang = h.get("accept-language") ?? "";
2678
+ locale = parseAcceptLanguage(acceptLang);
2679
+ }
2658
2680
 
2659
- const h = await headers();
2660
- const acceptLang = h.get("accept-language") ?? "";
2661
- const locale = parseAcceptLanguage(acceptLang);
2662
2681
  if (locale === defaultLocale) return {};
2682
+ const { readFile } = await import("node:fs/promises");
2683
+ const { join } = await import("node:path");
2663
2684
  try {
2664
2685
  const filePath = join(process.cwd(), messagesDir, \`\${locale}.json\`);
2665
2686
  const content = await readFile(filePath, "utf-8");
@@ -2725,7 +2746,7 @@ export function createT(messages?: Messages): TFn & PromiseLike<TFn> {
2725
2746
  function generateI18nHelper(opts) {
2726
2747
  const allLocales = [opts.sourceLocale, ...opts.targetLocales];
2727
2748
  const allLocalesStr = allLocales.map((l) => `"${l}"`).join(", ");
2728
- return `import { headers } from "next/headers";
2749
+ return `import { headers, cookies } from "next/headers";
2729
2750
  import { readFile } from "node:fs/promises";
2730
2751
  import { join } from "node:path";
2731
2752
 
@@ -2749,6 +2770,13 @@ function parseAcceptLanguage(header: string): Locale {
2749
2770
  }
2750
2771
 
2751
2772
  export async function getLocale(): Promise<Locale> {
2773
+ try {
2774
+ const c = await cookies();
2775
+ const cookieLocale = c.get("NEXT_LOCALE")?.value;
2776
+ if (cookieLocale && supported.includes(cookieLocale as Locale)) {
2777
+ return cookieLocale as Locale;
2778
+ }
2779
+ } catch {}
2752
2780
  const h = await headers();
2753
2781
  const acceptLang = h.get("accept-language") ?? "";
2754
2782
  return parseAcceptLanguage(acceptLang);
@@ -2771,12 +2799,17 @@ var init_t_component = __esm({
2771
2799
  "src/templates/t-component.ts"() {
2772
2800
  "use strict";
2773
2801
  CLIENT_TEMPLATE = `"use client";
2774
- import { createContext, useContext, type ReactNode } from "react";
2802
+ import { createContext, useContext, useEffect, type ReactNode } from "react";
2775
2803
 
2776
2804
  type Messages = Record<string, string>;
2777
2805
  const I18nCtx = createContext<Messages>({});
2778
2806
 
2779
- export function I18nProvider({ messages = {}, children }: { messages?: Messages; children: ReactNode }) {
2807
+ export function I18nProvider({ messages = {}, locale, children }: { messages?: Messages; locale?: string; children: ReactNode }) {
2808
+ useEffect(() => {
2809
+ if (locale) {
2810
+ document.cookie = \`NEXT_LOCALE=\${locale}; path=/; max-age=31536000; SameSite=Lax\`;
2811
+ }
2812
+ }, [locale]);
2780
2813
  return <I18nCtx.Provider value={messages}>{children}</I18nCtx.Provider>;
2781
2814
  }
2782
2815
 
@@ -3091,18 +3124,18 @@ async function setupInlineI18n(cwd, componentPath, sourceLocale, targetLocales,
3091
3124
  let layoutContent = await readFile5(layoutPath, "utf-8");
3092
3125
  if (!layoutContent.includes("I18nProvider")) {
3093
3126
  const importLines = `import { I18nProvider } from "${componentPath}";
3094
- import { setServerMessages } from "${componentPath}-server";
3127
+ import { setServerMessages, setLocale } from "${componentPath}-server";
3095
3128
  import { getLocale, getMessages } from "@/i18n";
3096
3129
  `;
3097
3130
  layoutContent = insertImportsAfterLast(layoutContent, importLines);
3098
3131
  layoutContent = ensureAsyncLayout(layoutContent);
3099
3132
  layoutContent = layoutContent.replace(
3100
3133
  /return\s*\(/,
3101
- "const locale = await getLocale();\n const messages = await getMessages(locale);\n setServerMessages(messages);\n\n return ("
3134
+ "const locale = await getLocale();\n setLocale(locale);\n const messages = await getMessages(locale);\n setServerMessages(messages);\n\n return ("
3102
3135
  );
3103
3136
  layoutContent = layoutContent.replace(
3104
3137
  /(<body[^>]*>)/,
3105
- "$1\n <I18nProvider messages={messages}>"
3138
+ "$1\n <I18nProvider messages={messages} locale={locale}>"
3106
3139
  );
3107
3140
  layoutContent = layoutContent.replace(
3108
3141
  /<\/body>/,
@@ -3173,7 +3206,7 @@ async function runInitWizard() {
3173
3206
  const sourceLocale = await p.text({
3174
3207
  message: "Source locale:",
3175
3208
  initialValue: "en",
3176
- validate(value) {
3209
+ validate(value = "") {
3177
3210
  if (!validateLocale(value)) {
3178
3211
  return "Invalid locale. Use only letters, numbers, hyphens, and underscores.";
3179
3212
  }