anylang-dev 0.1.0 → 0.1.2

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 CHANGED
@@ -11,7 +11,7 @@ It works in JSX and TSX when the text is wrapped in a JavaScript expression:
11
11
 
12
12
  ```tsx
13
13
  export function Hero() {
14
- const $tr = useAnyLang(language);
14
+ const $tr = useTr();
15
15
 
16
16
  return (
17
17
  <section>
@@ -32,22 +32,18 @@ By default, `anylang` scans `.js`, `.jsx`, `.ts`, `.tsx`, `.vue`, and `.html` fi
32
32
  `anylang` does not require a built-in selector. Build any selector UI you want and pass the selected locale to `setLanguage`.
33
33
 
34
34
  ```tsx
35
- const [language, setSelectedLanguage] = useState<LanguageCode>("en");
36
- const $tr = useAnyLang(language);
37
-
38
- function handleLanguageChange(nextLanguage: LanguageCode) {
39
- setLanguage(nextLanguage);
40
- setSelectedLanguage(nextLanguage);
41
- }
35
+ const { language, languages, setLanguage } = useLanguage();
42
36
 
43
37
  return (
44
38
  <select
45
39
  value={language}
46
- onChange={(event) => handleLanguageChange(event.target.value as LanguageCode)}
40
+ onChange={(event) => setLanguage(event.target.value as LanguageCode)}
47
41
  >
48
- <option value="en">English</option>
49
- <option value="hi">हिन्दी</option>
50
- <option value="ja">日本語</option>
42
+ {languages.map((language) => (
43
+ <option key={language.code} value={language.code}>
44
+ {language.nativeLabel}
45
+ </option>
46
+ ))}
51
47
  </select>
52
48
  );
53
49
  ```
@@ -90,7 +86,7 @@ anylang translate
90
86
  "exclude": ["node_modules", ".git", "dist", "build", ".next"],
91
87
  "outDir": "locales",
92
88
  "runtime": {
93
- "output": "src/anylang.generated.ts",
89
+ "output": "anylang.ts",
94
90
  "importFrom": "anylang-dev/runtime"
95
91
  },
96
92
  "functionName": "$tr",
@@ -155,8 +151,7 @@ locales/
155
151
  en.json
156
152
  hi.json
157
153
  anylang.lock.json
158
- src/
159
- anylang.generated.ts
154
+ anylang.ts
160
155
  ```
161
156
 
162
157
  The lock file stores SHA-256 fingerprints so unchanged strings are skipped on later runs.
@@ -176,7 +171,7 @@ anylang scan
176
171
  ```
177
172
 
178
173
  This writes keyed source entries to `locales/en.json` and creates placeholder entries in each target locale.
179
- It also generates `src/anylang.generated.ts`, which imports all locale JSON files and exports runtime helpers.
174
+ It also generates `anylang.ts`, which imports all locale JSON files and exports runtime helpers.
180
175
 
181
176
  3. Translate with Gemini:
182
177
 
@@ -221,11 +216,51 @@ Import the generated runtime file in your app:
221
216
 
222
217
  ```tsx
223
218
  import {
224
- languages,
225
- setLanguage,
226
- useAnyLang,
219
+ AnyLangProvider,
220
+ useLanguage,
221
+ useTr,
227
222
  type LanguageCode
228
- } from "./anylang.generated";
223
+ } from "./anylang";
229
224
  ```
230
225
 
231
226
  You do not manually import `en.json`, `hi.json`, `ja.json`, etc. The generated file does that for you based on `sourceLocale` and `targetLocales`.
227
+
228
+ Wrap your app once:
229
+
230
+ ```tsx
231
+ root.render(
232
+ <AnyLangProvider>
233
+ <App />
234
+ </AnyLangProvider>
235
+ );
236
+ ```
237
+
238
+ Then use translations in any component:
239
+
240
+ ```tsx
241
+ function Hero() {
242
+ const $tr = useTr();
243
+ return <h1>{$tr("hero.title", "Translate your website with anylang")}</h1>;
244
+ }
245
+ ```
246
+
247
+ And build any selector with `useLanguage`:
248
+
249
+ ```tsx
250
+ function LanguageSelector() {
251
+ const { language, languages, setLanguage } = useLanguage();
252
+
253
+ return (
254
+ <select
255
+ value={language}
256
+ onChange={(event) => setLanguage(event.target.value as LanguageCode)}
257
+ >
258
+ {languages.map((language) => (
259
+ <option key={language.code} value={language.code}>
260
+ {language.nativeLabel}
261
+ </option>
262
+ ))}
263
+ </select>
264
+ );
265
+ }
266
+ ```
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "anylang-dev",
3
- "version": "0.1.0",
3
+ "version": "0.1.2",
4
4
  "description": "Bring-your-own-key website translation JSON generator.",
5
5
  "type": "module",
6
6
  "files": [
package/src/config.js CHANGED
@@ -8,7 +8,7 @@ export const DEFAULT_CONFIG = {
8
8
  exclude: ["node_modules", ".git", "dist", "build", ".next"],
9
9
  outDir: "locales",
10
10
  runtime: {
11
- output: "src/anylang.generated.ts",
11
+ output: "anylang.ts",
12
12
  importFrom: "anylang-dev/runtime"
13
13
  },
14
14
  functionName: "$tr",
package/src/pipeline.js CHANGED
@@ -131,7 +131,7 @@ function normalizeTargetEntry(entry) {
131
131
  async function writeGeneratedRuntime(config) {
132
132
  if (config.runtime === false) return;
133
133
 
134
- const output = path.resolve(config.runtime?.output || "src/anylang.generated.ts");
134
+ const output = path.resolve(config.runtime?.output || "anylang.ts");
135
135
  const outDir = path.resolve(config.outDir);
136
136
  const locales = [config.sourceLocale, ...config.targetLocales.filter((locale) => locale !== config.sourceLocale)];
137
137
  const importFrom = config.runtime?.importFrom || "anylang-dev/runtime";
@@ -159,7 +159,7 @@ function generatedRuntimeSource({ importFrom, localeImports, sourceLocale }) {
159
159
  .join(",\n");
160
160
 
161
161
  return `/* This file is generated by anylang. Do not edit by hand. */
162
- import { useCallback } from 'react'
162
+ import { createContext, createElement, useCallback, useContext, useMemo, useState, type ReactNode } from 'react'
163
163
  import { $tr as translate, configureAnyLang, setAnyLangLocale } from '${importFrom}'
164
164
  ${imports}
165
165
 
@@ -185,6 +185,54 @@ export function useAnyLang(locale: LanguageCode) {
185
185
  export function setLanguage(locale: LanguageCode) {
186
186
  setAnyLangLocale(locale)
187
187
  }
188
+
189
+ type AnyLangContextValue = {
190
+ language: LanguageCode
191
+ languages: typeof languages
192
+ setLanguage: (locale: LanguageCode) => void
193
+ $tr: (key: string, source?: string) => string
194
+ }
195
+
196
+ const AnyLangContext = createContext<AnyLangContextValue | null>(null)
197
+
198
+ export function AnyLangProvider({
199
+ children,
200
+ defaultLanguage = '${sourceLocale}' as LanguageCode,
201
+ }: {
202
+ children: ReactNode
203
+ defaultLanguage?: LanguageCode
204
+ }) {
205
+ const [language, setSelectedLanguage] = useState<LanguageCode>(defaultLanguage)
206
+ const $tr = useAnyLang(language)
207
+
208
+ const value = useMemo(() => ({
209
+ language,
210
+ languages,
211
+ setLanguage(nextLanguage: LanguageCode) {
212
+ setAnyLangLocale(nextLanguage)
213
+ setSelectedLanguage(nextLanguage)
214
+ },
215
+ $tr,
216
+ }), [language, $tr])
217
+
218
+ return createElement(AnyLangContext.Provider, { value }, children)
219
+ }
220
+
221
+ export function useLanguage() {
222
+ const context = useContext(AnyLangContext)
223
+ if (!context) throw new Error('useLanguage must be used inside AnyLangProvider')
224
+ return {
225
+ language: context.language,
226
+ languages: context.languages,
227
+ setLanguage: context.setLanguage,
228
+ }
229
+ }
230
+
231
+ export function useTr() {
232
+ const context = useContext(AnyLangContext)
233
+ if (!context) throw new Error('useTr must be used inside AnyLangProvider')
234
+ return context.$tr
235
+ }
188
236
  `;
189
237
  }
190
238