react-autolocale 0.1.0 → 0.3.0-beta.0

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.
@@ -18,9 +18,12 @@ function redirectTarget(opts) {
18
18
  return `/${target}${pathname}${opts.search ?? ""}${opts.hash ?? ""}`;
19
19
  }
20
20
  const STORAGE_KEY = "react-autolocale:language";
21
- /** The same logic as a tiny inline script, so the root page redirects before anything paints. */
21
+ /**
22
+ * The same logic as a tiny inline script, so the root page redirects before anything paints. When the visitor stays,
23
+ * the URL is rewritten to the original language's prefix (no reload) so client-side routers see a prefixed path.
24
+ */
22
25
  function redirectScript(codes, original) {
23
- return `(function(){try{var C=${JSON.stringify(codes)},O=${JSON.stringify(original)},p=location.pathname,m=/^\\/([a-z]{2,3})(?=\\/|$)/i.exec(p);if(m&&C.indexOf(m[1].toLowerCase())>-1)return;var t=null,s=localStorage.getItem(${JSON.stringify(STORAGE_KEY)});if(s&&C.indexOf(s)>-1)t=s;var l=navigator.languages||[navigator.language];for(var i=0;i<l.length&&!t;i++){var c=String(l[i]).toLowerCase();if(C.indexOf(c)>-1)t=c;else if(C.indexOf(c.split("-")[0])>-1)t=c.split("-")[0]}if(t&&t!==O)location.replace("/"+t+p+location.search+location.hash)}catch(e){}})()`;
26
+ return `(function(){try{var C=${JSON.stringify(codes)},O=${JSON.stringify(original)},p=location.pathname,m=/^\\/([a-z]{2,3})(?=\\/|$)/i.exec(p);if(m&&C.indexOf(m[1].toLowerCase())>-1)return;var t=null,s=localStorage.getItem(${JSON.stringify(STORAGE_KEY)});if(s&&C.indexOf(s)>-1)t=s;var l=navigator.languages||[navigator.language];for(var i=0;i<l.length&&!t;i++){var c=String(l[i]).toLowerCase();if(C.indexOf(c)>-1)t=c;else if(C.indexOf(c.split("-")[0])>-1)t=c.split("-")[0]}if(t&&t!==O)location.replace("/"+t+p+location.search+location.hash);else history.replaceState(history.state,"","/"+O+p+location.search+location.hash)}catch(e){}})()`;
24
27
  }
25
28
  //#endregion
26
29
  export { redirectScript as n, redirectTarget as r, STORAGE_KEY as t };
@@ -0,0 +1,24 @@
1
+ //#region src/core/suggestion.ts
2
+ /**
3
+ * Should we offer the visitor another language? Looks at the first browser language we support:
4
+ * if it is the page's own language, was dismissed, or the visitor already chose a language, offer nothing.
5
+ */
6
+ function suggestLanguage(opts) {
7
+ if (opts.chosen) return null;
8
+ for (const tag of opts.browser) {
9
+ const lower = String(tag).toLowerCase();
10
+ const base = lower.split("-")[0];
11
+ const code = opts.codes.includes(lower) ? lower : opts.codes.includes(base) ? base : null;
12
+ if (!code) continue;
13
+ return code === opts.current || opts.dismissed.includes(code) ? null : code;
14
+ }
15
+ return null;
16
+ }
17
+ const DISMISSED_KEY = "react-autolocale:banner-dismissed";
18
+ const BANNER_EN = {
19
+ prompt: "This page is also available in {language}.",
20
+ switch: "Read in {language}",
21
+ dismiss: "Not now"
22
+ };
23
+ //#endregion
24
+ export { DISMISSED_KEY as n, suggestLanguage as r, BANNER_EN as t };
@@ -0,0 +1,22 @@
1
+ //#region src/core/translate.d.ts
2
+ interface Translator {
3
+ /** `contexts[i]` says where `texts[i]` appears ("button", "h1", "placeholder", ...). Engines may ignore it. */
4
+ translate(texts: string[], from: string, to: string, contexts?: string[]): Promise<string[]>;
5
+ }
6
+ /** The simplest way to plug in your own engine (DeepL, an LLM, ...): one function. */
7
+ type TranslateFn = (request: {
8
+ texts: string[];
9
+ contexts: string[];
10
+ from: string;
11
+ to: string;
12
+ }) => Promise<string[]>;
13
+ /**
14
+ * Uses a local LLM through Ollama (free, runs on your machine). Unlike the default models it is told
15
+ * where each string appears, which fixes most one-word mistakes ("Home" in a nav bar is not "Sommaire").
16
+ */
17
+ declare function ollama(options?: {
18
+ model: string;
19
+ url?: string;
20
+ }): Translator;
21
+ //#endregion
22
+ export { Translator as n, ollama as r, TranslateFn as t };
package/dist/vite.d.ts CHANGED
@@ -1,16 +1,25 @@
1
+ import { n as Translator, r as ollama, t as TranslateFn } from "./translate-COrJX1KS.js";
1
2
  import { Plugin } from "vite";
2
3
  //#region src/vite/index.d.ts
3
4
  export interface ReactAutolocaleOptions {
4
- /** Folders (relative to the project root) scanned for JSX. Defaults to "src". */
5
+ /** Folders (relative to the project root) scanned for JSX. Prefer `include` in auto-locale.config.ts, which the CLI also reads. */
5
6
  include?: string[];
6
- /** Fix individual translations by hand, e.g. { fr: { Contact: "Contact" } }. */
7
+ /** Fix individual translations in code, e.g. { fr: { Contact: "Contact" } }. Adds to (and wins over) react-autolocale.overrides.json. */
7
8
  overrides?: Record<string, Record<string, string>>;
8
9
  /**
9
10
  * Extra pages to build, mainly dynamic ones such as "/users/1" (a function can fetch them). Pages reached
10
11
  * by links and fixed routes written in your router (<Route path="/thank-you">) are found automatically.
11
12
  */
12
13
  routes?: string[] | (() => string[] | Promise<string[]>);
14
+ /** @deprecated Builds no longer translate. Set `provider` in auto-locale.config.ts; `react-autolocale translate` uses it. */
15
+ engine?: Translator | TranslateFn;
16
+ /** @deprecated Builds no longer translate. Set `glossary` in auto-locale.config.ts. */
17
+ glossary?: Record<string, Record<string, string>>;
13
18
  }
19
+ /**
20
+ * Reads the generated catalogs and serves them to the runtime. It never translates, downloads a model or calls
21
+ * a translation API: missing translations show the source text, and `react-autolocale sync` fills them.
22
+ */
14
23
  export default function reactAutolocale(options?: ReactAutolocaleOptions): Plugin;
15
24
  //#endregion
16
- export { reactAutolocale };
25
+ export { type TranslateFn, type Translator, reactAutolocale, ollama };