localize-ai 1.0.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.
Files changed (46) hide show
  1. package/dist/cli.d.ts +3 -0
  2. package/dist/cli.d.ts.map +1 -0
  3. package/dist/cli.js +25 -0
  4. package/dist/cli.js.map +1 -0
  5. package/dist/context/LanguageContext.d.ts +9 -0
  6. package/dist/context/LanguageContext.d.ts.map +1 -0
  7. package/dist/context/LanguageContext.js +5 -0
  8. package/dist/context/LanguageContext.js.map +1 -0
  9. package/dist/context/LanguageContextProvider.d.ts +5 -0
  10. package/dist/context/LanguageContextProvider.d.ts.map +1 -0
  11. package/dist/context/LanguageContextProvider.js +38 -0
  12. package/dist/context/LanguageContextProvider.js.map +1 -0
  13. package/dist/generate.d.ts +2 -0
  14. package/dist/generate.d.ts.map +1 -0
  15. package/dist/generate.js +16 -0
  16. package/dist/generate.js.map +1 -0
  17. package/dist/hooks/useTranslations.d.ts +7 -0
  18. package/dist/hooks/useTranslations.d.ts.map +1 -0
  19. package/dist/hooks/useTranslations.js +17 -0
  20. package/dist/hooks/useTranslations.js.map +1 -0
  21. package/dist/index.d.ts +3 -0
  22. package/dist/index.d.ts.map +1 -0
  23. package/dist/index.js +3 -0
  24. package/dist/index.js.map +1 -0
  25. package/dist/loadConfig.d.ts +2 -0
  26. package/dist/loadConfig.d.ts.map +1 -0
  27. package/dist/loadConfig.js +14 -0
  28. package/dist/loadConfig.js.map +1 -0
  29. package/dist/react.d.ts +3 -0
  30. package/dist/react.d.ts.map +1 -0
  31. package/dist/react.js +3 -0
  32. package/dist/react.js.map +1 -0
  33. package/dist/scripts/cleanTranslations.d.ts +2 -0
  34. package/dist/scripts/cleanTranslations.d.ts.map +1 -0
  35. package/dist/scripts/cleanTranslations.js +27 -0
  36. package/dist/scripts/cleanTranslations.js.map +1 -0
  37. package/dist/scripts/extractText.d.ts +2 -0
  38. package/dist/scripts/extractText.d.ts.map +1 -0
  39. package/dist/scripts/extractText.js +48 -0
  40. package/dist/scripts/extractText.js.map +1 -0
  41. package/dist/scripts/translate.d.ts +2 -0
  42. package/dist/scripts/translate.d.ts.map +1 -0
  43. package/dist/scripts/translate.js +115 -0
  44. package/dist/scripts/translate.js.map +1 -0
  45. package/package.json +54 -0
  46. package/readme.md +223 -0
package/dist/cli.d.ts ADDED
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=cli.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":""}
package/dist/cli.js ADDED
@@ -0,0 +1,25 @@
1
+ #!/usr/bin/env node
2
+ import { execSync } from "child_process";
3
+ import { generateRuntimeConfig } from "./generate.js";
4
+ import path from "path";
5
+ import { fileURLToPath } from "url";
6
+ const __filename = fileURLToPath(import.meta.url);
7
+ const __dirname = path.dirname(__filename);
8
+ const command = process.argv[2];
9
+ if (command === "init") {
10
+ generateRuntimeConfig();
11
+ }
12
+ else if (command === "translate") {
13
+ console.log("๐Ÿš€ Running localization pipeline...");
14
+ const extractPath = path.join(__dirname, "scripts", "extractText.js");
15
+ const cleanPath = path.join(__dirname, "scripts", "cleanTranslations.js");
16
+ const translatePath = path.join(__dirname, "scripts", "translate.js");
17
+ execSync(`node "${extractPath}"`, { stdio: "inherit" });
18
+ execSync(`node "${cleanPath}"`, { stdio: "inherit" });
19
+ execSync(`node "${translatePath}"`, { stdio: "inherit" });
20
+ console.log("โœ… Done");
21
+ }
22
+ else {
23
+ console.log("โŒ Unknown command");
24
+ }
25
+ //# sourceMappingURL=cli.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AAEA,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,OAAO,EAAE,qBAAqB,EAAE,MAAM,eAAe,CAAC;AACtD,OAAO,IAAI,MAAM,MAAM,CAAC;AACxB,OAAO,EAAE,aAAa,EAAE,MAAM,KAAK,CAAC;AAEpC,MAAM,UAAU,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAClD,MAAM,SAAS,GAAG,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC;AAC3C,MAAM,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAEhC,IAAI,OAAO,KAAK,MAAM,EAAE,CAAC;IACvB,qBAAqB,EAAE,CAAC;AAC1B,CAAC;KACI,IAAI,OAAO,KAAK,WAAW,EAAE,CAAC;IACjC,OAAO,CAAC,GAAG,CAAC,qCAAqC,CAAC,CAAC;IAEnD,MAAM,WAAW,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,SAAS,EAAE,gBAAgB,CAAC,CAAC;IACtE,MAAM,SAAS,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,SAAS,EAAE,sBAAsB,CAAC,CAAC;IAC1E,MAAM,aAAa,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,SAAS,EAAE,cAAc,CAAC,CAAC;IAEtE,QAAQ,CAAC,SAAS,WAAW,GAAG,EAAE,EAAE,KAAK,EAAE,SAAS,EAAE,CAAC,CAAC;IACxD,QAAQ,CAAC,SAAS,SAAS,GAAG,EAAE,EAAE,KAAK,EAAE,SAAS,EAAE,CAAC,CAAC;IACtD,QAAQ,CAAC,SAAS,aAAa,GAAG,EAAE,EAAE,KAAK,EAAE,SAAS,EAAE,CAAC,CAAC;IAE1D,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;AACxB,CAAC;KACI,CAAC;IACJ,OAAO,CAAC,GAAG,CAAC,mBAAmB,CAAC,CAAC;AACnC,CAAC"}
@@ -0,0 +1,9 @@
1
+ type LanguageContextType = {
2
+ lang: string;
3
+ supportedLangs: string[];
4
+ setLang: (lang: string) => void;
5
+ translations: Record<string, Record<string, string>>;
6
+ };
7
+ declare const LanguageContext: import("react").Context<LanguageContextType | null>;
8
+ export default LanguageContext;
9
+ //# sourceMappingURL=LanguageContext.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"LanguageContext.d.ts","sourceRoot":"","sources":["../../src/context/LanguageContext.ts"],"names":[],"mappings":"AAEA,KAAK,mBAAmB,GAAG;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,cAAc,EAAE,MAAM,EAAE,CAAC;IACzB,OAAO,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IAC9B,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;CAExD,CAAC;AAGF,QAAA,MAAM,eAAe,qDAAkD,CAAC;AAExE,eAAe,eAAe,CAAC"}
@@ -0,0 +1,5 @@
1
+ import { createContext, useContext } from "react";
2
+ // ๐Ÿ‘‡ safe: default is null
3
+ const LanguageContext = createContext(null);
4
+ export default LanguageContext;
5
+ //# sourceMappingURL=LanguageContext.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"LanguageContext.js","sourceRoot":"","sources":["../../src/context/LanguageContext.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,OAAO,CAAC;AAUlD,2BAA2B;AAC3B,MAAM,eAAe,GAAG,aAAa,CAA6B,IAAI,CAAC,CAAC;AAExE,eAAe,eAAe,CAAC"}
@@ -0,0 +1,5 @@
1
+ declare function LanguageContextProvider({ children }: {
2
+ children: React.ReactNode;
3
+ }): import("react/jsx-runtime").JSX.Element | null;
4
+ export default LanguageContextProvider;
5
+ //# sourceMappingURL=LanguageContextProvider.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"LanguageContextProvider.d.ts","sourceRoot":"","sources":["../../src/context/LanguageContextProvider.tsx"],"names":[],"mappings":"AAGA,iBAAS,uBAAuB,CAAC,EAAE,QAAQ,EAAE,EAAE;IAAE,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAA;CAAE,kDA6C3E;AAED,eAAe,uBAAuB,CAAC"}
@@ -0,0 +1,38 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { useEffect, useState } from "react";
3
+ import LanguageContext from "./LanguageContext.js";
4
+ function LanguageContextProvider({ children }) {
5
+ const [lang, setLang] = useState("en");
6
+ const [supportedLangs, setSupportedLangs] = useState([]);
7
+ const [translations, setTranslations] = useState({});
8
+ const [isReady, setIsReady] = useState(false);
9
+ useEffect(() => {
10
+ async function load() {
11
+ try {
12
+ const configRes = await fetch("/localize.runtime.json");
13
+ const config = await configRes.json();
14
+ setSupportedLangs(config.supportedLangs || []);
15
+ setLang(config.supportedLangs?.includes(config.sourceLanguage)
16
+ ? config.sourceLanguage
17
+ : "en");
18
+ const transRes = await fetch("/translations.json");
19
+ if (!transRes.ok)
20
+ throw new Error("No translations");
21
+ const data = await transRes.json();
22
+ setTranslations(data);
23
+ setIsReady(true);
24
+ }
25
+ catch (err) {
26
+ console.warn("โš ๏ธ Failed to load localization", err);
27
+ setTranslations({});
28
+ setIsReady(true);
29
+ }
30
+ }
31
+ load();
32
+ }, []);
33
+ if (!isReady)
34
+ return null;
35
+ return (_jsx(LanguageContext.Provider, { value: { lang, setLang, supportedLangs, translations }, children: children }));
36
+ }
37
+ export default LanguageContextProvider;
38
+ //# sourceMappingURL=LanguageContextProvider.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"LanguageContextProvider.js","sourceRoot":"","sources":["../../src/context/LanguageContextProvider.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AAC5C,OAAO,eAAe,MAAM,sBAAsB,CAAC;AAEnD,SAAS,uBAAuB,CAAC,EAAE,QAAQ,EAAiC;IAC1E,MAAM,CAAC,IAAI,EAAE,OAAO,CAAC,GAAG,QAAQ,CAAS,IAAI,CAAC,CAAC;IAC/C,MAAM,CAAC,cAAc,EAAE,iBAAiB,CAAC,GAAG,QAAQ,CAAW,EAAE,CAAC,CAAC;IACnE,MAAM,CAAC,YAAY,EAAE,eAAe,CAAC,GAAG,QAAQ,CAAM,EAAE,CAAC,CAAC;IAC1D,MAAM,CAAC,OAAO,EAAE,UAAU,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC;IAE9C,SAAS,CAAC,GAAG,EAAE;QACb,KAAK,UAAU,IAAI;YACjB,IAAI,CAAC;gBACH,MAAM,SAAS,GAAG,MAAM,KAAK,CAAC,wBAAwB,CAAC,CAAC;gBACxD,MAAM,MAAM,GAAG,MAAM,SAAS,CAAC,IAAI,EAAE,CAAC;gBAEtC,iBAAiB,CAAC,MAAM,CAAC,cAAc,IAAI,EAAE,CAAC,CAAC;gBAC/C,OAAO,CACL,MAAM,CAAC,cAAc,EAAE,QAAQ,CAAC,MAAM,CAAC,cAAc,CAAC;oBACpD,CAAC,CAAC,MAAM,CAAC,cAAc;oBACvB,CAAC,CAAC,IAAI,CACT,CAAC;gBAEF,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,oBAAoB,CAAC,CAAC;gBACnD,IAAI,CAAC,QAAQ,CAAC,EAAE;oBAAE,MAAM,IAAI,KAAK,CAAC,iBAAiB,CAAC,CAAC;gBAErD,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC;gBACnC,eAAe,CAAC,IAAI,CAAC,CAAC;gBAEtB,UAAU,CAAC,IAAI,CAAC,CAAC;YACnB,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACb,OAAO,CAAC,IAAI,CAAC,gCAAgC,EAAE,GAAG,CAAC,CAAC;gBACpD,eAAe,CAAC,EAAE,CAAC,CAAC;gBACpB,UAAU,CAAC,IAAI,CAAC,CAAC;YACnB,CAAC;QACH,CAAC;QAED,IAAI,EAAE,CAAC;IACT,CAAC,EAAE,EAAE,CAAC,CAAC;IAEP,IAAI,CAAC,OAAO;QAAE,OAAO,IAAI,CAAC;IAE1B,OAAO,CACL,KAAC,eAAe,CAAC,QAAQ,IACvB,KAAK,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,cAAc,EAAE,YAAY,EAAE,YAErD,QAAQ,GACgB,CAC5B,CAAC;AACJ,CAAC;AAED,eAAe,uBAAuB,CAAC"}
@@ -0,0 +1,2 @@
1
+ export declare function generateRuntimeConfig(): Promise<void>;
2
+ //# sourceMappingURL=generate.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"generate.d.ts","sourceRoot":"","sources":["../src/generate.ts"],"names":[],"mappings":"AAIA,wBAAsB,qBAAqB,kBAe1C"}
@@ -0,0 +1,16 @@
1
+ import fs from "fs";
2
+ import path from "path";
3
+ import { loadUserConfig } from "./loadConfig.js";
4
+ export async function generateRuntimeConfig() {
5
+ const config = await loadUserConfig();
6
+ // Transform config if needed
7
+ const runtimeConfig = {
8
+ sourceLanguage: config.sourceLanguage,
9
+ supportedLangs: config.translationLanguages,
10
+ apikey: config.apikey
11
+ };
12
+ const outputPath = path.resolve(process.cwd(), "localize.runtime.json");
13
+ fs.writeFileSync(outputPath, JSON.stringify(runtimeConfig, null, 2));
14
+ console.log("โœ… localize.runtime.json generated successfully!");
15
+ }
16
+ //# sourceMappingURL=generate.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"generate.js","sourceRoot":"","sources":["../src/generate.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,IAAI,CAAC;AACpB,OAAO,IAAI,MAAM,MAAM,CAAC;AACxB,OAAO,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAEjD,MAAM,CAAC,KAAK,UAAU,qBAAqB;IACzC,MAAM,MAAM,GAAG,MAAM,cAAc,EAAE,CAAC;IAEtC,6BAA6B;IAC7B,MAAM,aAAa,GAAG;QACpB,cAAc,EAAE,MAAM,CAAC,cAAc;QACrC,cAAc,EAAE,MAAM,CAAC,oBAAoB;QAC3C,MAAM,EAAE,MAAM,CAAC,MAAM;KACtB,CAAC;IAEF,MAAM,UAAU,GAAG,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,uBAAuB,CAAC,CAAC;IAExE,EAAE,CAAC,aAAa,CAAC,UAAU,EAAE,IAAI,CAAC,SAAS,CAAC,aAAa,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;IAErE,OAAO,CAAC,GAAG,CAAC,iDAAiD,CAAC,CAAC;AACjE,CAAC"}
@@ -0,0 +1,7 @@
1
+ export declare function useTranslation(): {
2
+ t: (key: string) => string;
3
+ setLang: (lang: string) => void;
4
+ lang: string;
5
+ supportedLangs: string[];
6
+ };
7
+ //# sourceMappingURL=useTranslations.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useTranslations.d.ts","sourceRoot":"","sources":["../../src/hooks/useTranslations.ts"],"names":[],"mappings":"AAGA,wBAAgB,cAAc;aASZ,MAAM,KAAG,MAAM;;;;EAShC"}
@@ -0,0 +1,17 @@
1
+ import { useContext } from "react";
2
+ import LanguageContext from "../context/LanguageContext.js";
3
+ export function useTranslation() {
4
+ const context = useContext(LanguageContext);
5
+ if (!context) {
6
+ throw new Error("useTranslation must be used within LanguageContextProvider");
7
+ }
8
+ const { lang, translations, setLang, supportedLangs } = context;
9
+ function t(key) {
10
+ const entry = translations[key];
11
+ if (!entry)
12
+ return key;
13
+ return entry[lang] || entry["en"] || key;
14
+ }
15
+ return { t, setLang, lang, supportedLangs };
16
+ }
17
+ //# sourceMappingURL=useTranslations.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useTranslations.js","sourceRoot":"","sources":["../../src/hooks/useTranslations.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,OAAO,CAAC;AACnC,OAAO,eAAe,MAAM,+BAA+B,CAAC;AAE5D,MAAM,UAAU,cAAc;IAC5B,MAAM,OAAO,GAAG,UAAU,CAAC,eAAe,CAAC,CAAC;IAE5C,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,MAAM,IAAI,KAAK,CAAC,4DAA4D,CAAC,CAAC;IAChF,CAAC;IAED,MAAM,EAAE,IAAI,EAAE,YAAY,EAAE,OAAO,EAAE,cAAc,EAAE,GAAG,OAAO,CAAC;IAEhE,SAAS,CAAC,CAAC,GAAW;QACpB,MAAM,KAAK,GAAG,YAAY,CAAC,GAAG,CAAC,CAAC;QAEhC,IAAI,CAAC,KAAK;YAAE,OAAO,GAAG,CAAC;QAEvB,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,KAAK,CAAC,IAAI,CAAC,IAAI,GAAG,CAAC;IAC3C,CAAC;IAED,OAAO,EAAE,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,cAAc,EAAE,CAAC;AAC9C,CAAC"}
@@ -0,0 +1,3 @@
1
+ export { default as LanguageContextProvider } from "./context/LanguageContextProvider.js";
2
+ export { useTranslation } from "./hooks/useTranslations.js";
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,IAAI,uBAAuB,EAAE,MAAM,sCAAsC,CAAC;AAC1F,OAAO,EAAE,cAAc,EAAE,MAAM,4BAA4B,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,3 @@
1
+ export { default as LanguageContextProvider } from "./context/LanguageContextProvider.js";
2
+ export { useTranslation } from "./hooks/useTranslations.js";
3
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,IAAI,uBAAuB,EAAE,MAAM,sCAAsC,CAAC;AAC1F,OAAO,EAAE,cAAc,EAAE,MAAM,4BAA4B,CAAC"}
@@ -0,0 +1,2 @@
1
+ export declare function loadUserConfig(): Promise<any>;
2
+ //# sourceMappingURL=loadConfig.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"loadConfig.d.ts","sourceRoot":"","sources":["../src/loadConfig.ts"],"names":[],"mappings":"AAGA,wBAAsB,cAAc,iBAUnC"}
@@ -0,0 +1,14 @@
1
+ import path from "path";
2
+ import { pathToFileURL } from "url";
3
+ export async function loadUserConfig() {
4
+ const configPath = path.resolve(process.cwd(), "localize.config.js");
5
+ try {
6
+ const config = await import(pathToFileURL(configPath).href);
7
+ return config.default;
8
+ }
9
+ catch (err) {
10
+ console.error("โŒ Failed to load localize.config.js");
11
+ process.exit(1);
12
+ }
13
+ }
14
+ //# sourceMappingURL=loadConfig.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"loadConfig.js","sourceRoot":"","sources":["../src/loadConfig.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,MAAM,CAAC;AACxB,OAAO,EAAE,aAAa,EAAE,MAAM,KAAK,CAAC;AAEpC,MAAM,CAAC,KAAK,UAAU,cAAc;IAClC,MAAM,UAAU,GAAG,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,oBAAoB,CAAC,CAAC;IAErE,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,aAAa,CAAC,UAAU,CAAC,CAAC,IAAI,CAAC,CAAC;QAC5D,OAAO,MAAM,CAAC,OAAO,CAAC;IACxB,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,OAAO,CAAC,KAAK,CAAC,qCAAqC,CAAC,CAAC;QACrD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;AACH,CAAC"}
@@ -0,0 +1,3 @@
1
+ export { default as LanguageContextProvider } from "./context/LanguageContextProvider.js";
2
+ export { useTranslation } from "./hooks/useTranslations.js";
3
+ //# sourceMappingURL=react.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"react.d.ts","sourceRoot":"","sources":["../src/react.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,IAAI,uBAAuB,EAAE,MAAM,sCAAsC,CAAC;AAC1F,OAAO,EAAE,cAAc,EAAE,MAAM,4BAA4B,CAAC"}
package/dist/react.js ADDED
@@ -0,0 +1,3 @@
1
+ export { default as LanguageContextProvider } from "./context/LanguageContextProvider.js";
2
+ export { useTranslation } from "./hooks/useTranslations.js";
3
+ //# sourceMappingURL=react.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"react.js","sourceRoot":"","sources":["../src/react.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,IAAI,uBAAuB,EAAE,MAAM,sCAAsC,CAAC;AAC1F,OAAO,EAAE,cAAc,EAAE,MAAM,4BAA4B,CAAC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=cleanTranslations.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cleanTranslations.d.ts","sourceRoot":"","sources":["../../src/scripts/cleanTranslations.ts"],"names":[],"mappings":""}
@@ -0,0 +1,27 @@
1
+ import fs from "fs";
2
+ import path from "path";
3
+ const ROOT = process.cwd();
4
+ const INPUT = path.join(ROOT, "extractedText.json");
5
+ const OUTPUT = path.join(ROOT, "cleaned_strings.json");
6
+ function isValid(text) {
7
+ if (!text || text.length < 3)
8
+ return false;
9
+ if (/^\d+$/.test(text))
10
+ return false;
11
+ if (text.includes("@"))
12
+ return false;
13
+ if (/^[^a-zA-Z]+$/.test(text))
14
+ return false;
15
+ if (text.includes("\\\\"))
16
+ return false;
17
+ return true;
18
+ }
19
+ if (!fs.existsSync(INPUT)) {
20
+ console.error("โŒ translations_en.json not found");
21
+ process.exit(1);
22
+ }
23
+ const raw = JSON.parse(fs.readFileSync(INPUT, "utf-8"));
24
+ const cleaned = raw.filter(isValid);
25
+ fs.writeFileSync(OUTPUT, JSON.stringify(cleaned, null, 2));
26
+ console.log(`โœ… Cleaned strings: ${cleaned.length}`);
27
+ //# sourceMappingURL=cleanTranslations.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cleanTranslations.js","sourceRoot":"","sources":["../../src/scripts/cleanTranslations.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,IAAI,CAAC;AACpB,OAAO,IAAI,MAAM,MAAM,CAAC;AAExB,MAAM,IAAI,GAAG,OAAO,CAAC,GAAG,EAAE,CAAC;AAE3B,MAAM,KAAK,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,oBAAoB,CAAC,CAAC;AACpD,MAAM,MAAM,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,sBAAsB,CAAC,CAAC;AAEvD,SAAS,OAAO,CAAC,IAAY;IAC3B,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,MAAM,GAAG,CAAC;QAAE,OAAO,KAAK,CAAC;IAC3C,IAAI,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC;QAAE,OAAO,KAAK,CAAC;IACrC,IAAI,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC;QAAE,OAAO,KAAK,CAAC;IACrC,IAAI,cAAc,CAAC,IAAI,CAAC,IAAI,CAAC;QAAE,OAAO,KAAK,CAAC;IAC5C,IAAI,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC;QAAE,OAAO,KAAK,CAAC;IACxC,OAAO,IAAI,CAAC;AACd,CAAC;AAED,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,KAAK,CAAC,EAAE,CAAC;IAC1B,OAAO,CAAC,KAAK,CAAC,kCAAkC,CAAC,CAAC;IAClD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC;AAED,MAAM,GAAG,GAAa,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,YAAY,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC,CAAC;AAElE,MAAM,OAAO,GAAG,GAAG,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;AAEpC,EAAE,CAAC,aAAa,CAAC,MAAM,EAAE,IAAI,CAAC,SAAS,CAAC,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;AAE3D,OAAO,CAAC,GAAG,CAAC,sBAAsB,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=extractText.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"extractText.d.ts","sourceRoot":"","sources":["../../src/scripts/extractText.ts"],"names":[],"mappings":""}
@@ -0,0 +1,48 @@
1
+ import fs from "fs";
2
+ import path from "path";
3
+ const ROOT = process.cwd(); // โœ… user project
4
+ const SRC_DIR = path.join(ROOT, "src");
5
+ const OUTPUT_FILE = path.join(ROOT, "extractedText.json");
6
+ let existingStrings = new Set();
7
+ if (fs.existsSync(OUTPUT_FILE)) {
8
+ existingStrings = new Set(JSON.parse(fs.readFileSync(OUTPUT_FILE, "utf-8")));
9
+ }
10
+ const newStrings = new Set();
11
+ function isValidText(text) {
12
+ if (!text || text.length < 2)
13
+ return false;
14
+ if (/^\d+$/.test(text))
15
+ return false;
16
+ if (text.includes("@"))
17
+ return false;
18
+ if (/^[A-Z0-9-]+$/.test(text))
19
+ return false;
20
+ if (/โ‚น|\$|โ‚ฌ/.test(text))
21
+ return false;
22
+ return true;
23
+ }
24
+ function scanDir(dir) {
25
+ const files = fs.readdirSync(dir);
26
+ for (const file of files) {
27
+ const fullPath = path.join(dir, file);
28
+ if (fs.statSync(fullPath).isDirectory()) {
29
+ scanDir(fullPath);
30
+ }
31
+ else if (/\.(tsx|jsx|ts|js)$/.test(file)) {
32
+ const content = fs.readFileSync(fullPath, "utf-8");
33
+ const regex = /t\(\s*["'`]([^"'`]+)["'`]\s*(?:,\s*[a-zA-Z0-9_.]+)?\s*\)/g;
34
+ let match;
35
+ while ((match = regex.exec(content)) !== null) {
36
+ const text = match[1].trim();
37
+ if (isValidText(text) && !existingStrings.has(text)) {
38
+ newStrings.add(text);
39
+ }
40
+ }
41
+ }
42
+ }
43
+ }
44
+ scanDir(SRC_DIR);
45
+ const updated = [...existingStrings, ...newStrings];
46
+ fs.writeFileSync(OUTPUT_FILE, JSON.stringify(updated, null, 2));
47
+ console.log(`โœ… Added ${newStrings.size} new strings`);
48
+ //# sourceMappingURL=extractText.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"extractText.js","sourceRoot":"","sources":["../../src/scripts/extractText.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,IAAI,CAAC;AACpB,OAAO,IAAI,MAAM,MAAM,CAAC;AAExB,MAAM,IAAI,GAAG,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC,iBAAiB;AAC7C,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;AACvC,MAAM,WAAW,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,EAAC,oBAAoB,CAAC,CAAC;AAEzD,IAAI,eAAe,GAAG,IAAI,GAAG,EAAU,CAAC;AAExC,IAAI,EAAE,CAAC,UAAU,CAAC,WAAW,CAAC,EAAE,CAAC;IAC/B,eAAe,GAAG,IAAI,GAAG,CACvB,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,YAAY,CAAC,WAAW,EAAE,OAAO,CAAC,CAAC,CAClD,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,GAAG,IAAI,GAAG,EAAU,CAAC;AAErC,SAAS,WAAW,CAAC,IAAY;IAC/B,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,MAAM,GAAG,CAAC;QAAE,OAAO,KAAK,CAAC;IAC3C,IAAI,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC;QAAE,OAAO,KAAK,CAAC;IACrC,IAAI,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC;QAAE,OAAO,KAAK,CAAC;IACrC,IAAI,cAAc,CAAC,IAAI,CAAC,IAAI,CAAC;QAAE,OAAO,KAAK,CAAC;IAC5C,IAAI,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC;QAAE,OAAO,KAAK,CAAC;IACtC,OAAO,IAAI,CAAC;AACd,CAAC;AAED,SAAS,OAAO,CAAC,GAAW;IAC1B,MAAM,KAAK,GAAG,EAAE,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC;IAElC,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;QAEtC,IAAI,EAAE,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC,WAAW,EAAE,EAAE,CAAC;YACxC,OAAO,CAAC,QAAQ,CAAC,CAAC;QACpB,CAAC;aAAM,IAAI,oBAAoB,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;YAC3C,MAAM,OAAO,GAAG,EAAE,CAAC,YAAY,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;YAEnD,MAAM,KAAK,GACT,2DAA2D,CAAC;YAE9D,IAAI,KAA6B,CAAC;YAExC,OAAO,CAAC,KAAK,GAAG,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,KAAK,IAAI,EAAE,CAAC;gBAC9C,MAAM,IAAI,GAAG,KAAK,CAAC,CAAC,CAAE,CAAC,IAAI,EAAE,CAAC;gBAE9B,IAAI,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,eAAe,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC;oBACpD,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;gBACvB,CAAC;YACH,CAAC;QACG,CAAC;IACH,CAAC;AACH,CAAC;AAED,OAAO,CAAC,OAAO,CAAC,CAAC;AAEjB,MAAM,OAAO,GAAG,CAAC,GAAG,eAAe,EAAE,GAAG,UAAU,CAAC,CAAC;AAEpD,EAAE,CAAC,aAAa,CAAC,WAAW,EAAE,IAAI,CAAC,SAAS,CAAC,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;AAEhE,OAAO,CAAC,GAAG,CAAC,WAAW,UAAU,CAAC,IAAI,cAAc,CAAC,CAAC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=translate.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"translate.d.ts","sourceRoot":"","sources":["../../src/scripts/translate.ts"],"names":[],"mappings":""}
@@ -0,0 +1,115 @@
1
+ import dotenv from "dotenv";
2
+ import path from "path";
3
+ import fs from "fs";
4
+ import { GoogleGenerativeAI } from "@google/generative-ai";
5
+ dotenv.config({ path: path.resolve(process.cwd(), ".env") }); // โœ… USER ENV
6
+ const ROOT = process.cwd();
7
+ const runtimeConfigPath = path.join(ROOT, "localize.runtime.json");
8
+ if (!fs.existsSync(runtimeConfigPath)) {
9
+ console.error("โŒ localize.runtime.json not found. Run init first.");
10
+ process.exit(1);
11
+ }
12
+ const runtimeConfig = JSON.parse(fs.readFileSync(runtimeConfigPath, "utf-8"));
13
+ const { sourceLanguage, supportedLangs, apikey } = runtimeConfig;
14
+ const API_KEY = process.env[apikey];
15
+ if (!API_KEY) {
16
+ console.error("โŒ GEMINI_API_KEY missing in .env");
17
+ process.exit(1);
18
+ }
19
+ const genAI = new GoogleGenerativeAI(API_KEY);
20
+ const INPUT = path.join(ROOT, "cleaned_strings.json");
21
+ const OUTPUT = path.join(ROOT, "public", "translations.json");
22
+ const CHUNK_SIZE = 100;
23
+ function chunk(arr, size) {
24
+ const res = [];
25
+ for (let i = 0; i < arr.length; i += size) {
26
+ res.push(arr.slice(i, i + size));
27
+ }
28
+ return res;
29
+ }
30
+ // ๐Ÿ”ฅ NEW: detect missing languages per text
31
+ function getMissingLangs(text, existing, supportedLangs) {
32
+ const existingEntry = existing[text] || {};
33
+ return supportedLangs.filter((lang) => !existingEntry[lang]);
34
+ }
35
+ function buildPrompt(chunk, existing, supportedLangs) {
36
+ const instructions = chunk.map((text) => {
37
+ const missing = getMissingLangs(text, existing, supportedLangs);
38
+ return `"${text}": {
39
+ "${sourceLanguage}": "${text}",
40
+ ${missing.map((l) => `"${l}": "..."`).join(",\n ")}
41
+ }`;
42
+ });
43
+ return `
44
+ You are a translation engine.
45
+
46
+ Translate ONLY the missing languages.
47
+
48
+ Rules:
49
+ - Return ONLY valid JSON
50
+ - No explanation
51
+ - No markdown
52
+ - Do NOT overwrite existing translations
53
+
54
+ Structure:
55
+ {
56
+ ${instructions.join(",\n")}
57
+ }
58
+
59
+ Input:
60
+ ${JSON.stringify(chunk)}
61
+ `;
62
+ }
63
+ async function translateChunk(model, chunkData, existing, supportedLangs) {
64
+ const prompt = buildPrompt(chunkData, existing, supportedLangs);
65
+ const result = await model.generateContent(prompt);
66
+ const response = await result.response;
67
+ let text = response.text();
68
+ text = text.replace(/```json|```/g, "").trim();
69
+ return JSON.parse(text);
70
+ }
71
+ async function run() {
72
+ const model = genAI.getGenerativeModel({
73
+ model: "gemini-2.5-flash",
74
+ });
75
+ const texts = JSON.parse(fs.readFileSync(INPUT, "utf-8"));
76
+ let existing = {};
77
+ if (fs.existsSync(OUTPUT)) {
78
+ existing = JSON.parse(fs.readFileSync(OUTPUT, "utf-8"));
79
+ }
80
+ const filtered = texts.filter((t) => {
81
+ const existingEntry = existing[t];
82
+ // new string โ†’ translate
83
+ if (!existingEntry)
84
+ return true;
85
+ // check if any language missing
86
+ const missingLangs = supportedLangs.filter((lang) => !existingEntry[lang]);
87
+ return missingLangs.length > 0;
88
+ });
89
+ const chunks = chunk(filtered, CHUNK_SIZE);
90
+ let final = { ...existing };
91
+ for (const [i, chunk] of chunks.entries()) {
92
+ console.log(`๐Ÿš€ Chunk ${i + 1}/${chunks.length}`);
93
+ try {
94
+ const res = await translateChunk(model, chunk, existing, supportedLangs);
95
+ for (const key in res) {
96
+ if (!final[key]) {
97
+ final[key] = res[key];
98
+ }
99
+ else {
100
+ final[key] = {
101
+ ...final[key],
102
+ ...res[key], // only adds missing languages
103
+ };
104
+ }
105
+ }
106
+ }
107
+ catch {
108
+ console.log("โŒ chunk failed");
109
+ }
110
+ }
111
+ fs.writeFileSync(OUTPUT, JSON.stringify(final, null, 2));
112
+ console.log("โœ… translations.json created");
113
+ }
114
+ run();
115
+ //# sourceMappingURL=translate.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"translate.js","sourceRoot":"","sources":["../../src/scripts/translate.ts"],"names":[],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,54 @@
1
+ {
2
+ "name": "localize-ai",
3
+ "version": "1.0.0",
4
+ "description": "plug and play localization package",
5
+ "main": "dist/index.js",
6
+ "types": "dist/index.d.ts",
7
+ "type": "module",
8
+ "files": ["dist"],
9
+ "module": "dist/index.js",
10
+ "exports": {
11
+ ".": {
12
+ "import": "./dist/index.js",
13
+ "types": "./dist/index.d.ts"
14
+ }
15
+ },
16
+ "bin": {
17
+ "localize-ai": "dist/cli.js"
18
+ },
19
+ "scripts": {
20
+ "build": "tsc",
21
+ "test": "echo \"Error: no test specified\" && exit 1"
22
+ },
23
+ "keywords": [
24
+ "localization",
25
+ "i18n",
26
+ "translation",
27
+ "react-i18n",
28
+ "ai-translation",
29
+ "gemini"
30
+ ],
31
+ "author": "Parth Gupta",
32
+ "license": "MIT",
33
+ "dependencies": {
34
+ "@google/generative-ai": "^0.24.1",
35
+ "dotenv": "^17.3.1"
36
+ },
37
+ "peerDependencies": {
38
+ "react": ">=18"
39
+ },
40
+ "devDependencies": {
41
+ "typescript": "^5.9.3",
42
+ "@types/node": "^25.5.0",
43
+ "@types/react": "^19.2.14",
44
+ "react": "^19.2.4"
45
+ },
46
+ "repository": {
47
+ "type": "git",
48
+ "url": "https://github.com/Parth-Gupta05/localize-ai.git"
49
+ },
50
+ "homepage": "https://github.com/Parth-Gupta05/localize-ai",
51
+ "bugs": {
52
+ "url": "https://github.com/Parth-Gupta05/localize-ai/issues"
53
+ }
54
+ }
package/readme.md ADDED
@@ -0,0 +1,223 @@
1
+ # ๐Ÿš€ localize-ai
2
+
3
+ **Plug & Play AI-powered localization for React apps**
4
+
5
+ Automatically extract, translate, and serve multilingual UI โ€” powered by AI โšก
6
+
7
+ ---
8
+
9
+ ## โœจ Features
10
+
11
+ * ๐Ÿ” Auto-extract static text from your codebase (`t("...")`)
12
+ * ๐ŸŒ AI-powered translations (Gemini)
13
+ * โšก Incremental translation (only new strings + languages)
14
+ * ๐Ÿง  Zero config runtime (auto loads translations)
15
+ * โš›๏ธ React hooks + context out of the box
16
+ * ๐Ÿ’ธ Cost optimized (no re-translation of existing content)
17
+
18
+ ---
19
+
20
+ ## ๐Ÿ“ฆ Installation
21
+
22
+ ```bash
23
+ npm install localize-ai
24
+ ```
25
+
26
+ ---
27
+
28
+ ## โš™๏ธ Setup (2 steps)
29
+
30
+ ### 1๏ธโƒฃ Create config
31
+
32
+ ```js
33
+ // localize.config.js
34
+ export default {
35
+ sourceLanguage: "en",
36
+ translationLanguages: ["hi", "fr"],
37
+ provider: "gemini",
38
+ apikey: "VITE_GEMINI_API_KEY"
39
+ };
40
+ ```
41
+
42
+ ---
43
+
44
+ ### 2๏ธโƒฃ Add your API key
45
+
46
+ ```env
47
+ VITE_GEMINI_API_KEY=your_api_key_here
48
+ ```
49
+
50
+ ---
51
+
52
+ ## ๐Ÿš€ Usage
53
+
54
+ ### Step 1: Initialize
55
+
56
+ ```bash
57
+ npx localize-ai init
58
+ ```
59
+
60
+ ---
61
+
62
+ ### Step 2: Extract & translate
63
+
64
+ ```bash
65
+ npx localize-ai translate
66
+ ```
67
+
68
+ This will:
69
+
70
+ * scan your codebase
71
+ * extract `t("text")`
72
+ * generate translations
73
+ * create:
74
+
75
+ ```
76
+ public/translations.json
77
+ public/localize.runtime.json
78
+ ```
79
+
80
+ ---
81
+
82
+ ### Step 3: Wrap your app
83
+
84
+ ```tsx
85
+ import { LanguageContextProvider } from "localize-ai";
86
+
87
+ <LanguageContextProvider>
88
+ <App />
89
+ </LanguageContextProvider>
90
+ ```
91
+
92
+ ---
93
+
94
+ ### Step 4: Use translations
95
+
96
+ ```tsx
97
+ import { useTranslation } from "localize-ai";
98
+
99
+ function App() {
100
+ const { t } = useTranslation();
101
+
102
+ return <h1>{t("Hello world")}</h1>;
103
+ }
104
+ ```
105
+
106
+ ---
107
+
108
+ ## ๐ŸŒ Change language
109
+
110
+ ```tsx
111
+ const { setLang } = useTranslation();
112
+
113
+ setLang("hi"); // switch language
114
+ ```
115
+
116
+ ---
117
+
118
+ ## ๐Ÿง  How it works
119
+
120
+ ```text
121
+ Code โ†’ Extract โ†’ Clean โ†’ AI Translate โ†’ JSON โ†’ React Context โ†’ UI
122
+ ```
123
+
124
+ * Only new strings are translated
125
+ * Only missing languages are generated
126
+ * Existing translations are reused
127
+
128
+ ---
129
+
130
+ ## ๐Ÿ“ Output
131
+
132
+ ```bash
133
+ public/
134
+ โ”œโ”€โ”€ translations.json
135
+ โ””โ”€โ”€ localize.runtime.json
136
+ ```
137
+
138
+ ---
139
+
140
+ ## โšก Example
141
+
142
+ ```tsx
143
+ <h1>{t("Get started")}</h1>
144
+ ```
145
+
146
+ โžก๏ธ Automatically becomes:
147
+
148
+ ```json
149
+ {
150
+ "Get started": {
151
+ "en": "Get started",
152
+ "hi": "เคถเฅเคฐเฅ‚ เค•เคฐเฅ‡เค‚",
153
+ "fr": "Commencer"
154
+ }
155
+ }
156
+ ```
157
+
158
+ ---
159
+
160
+ ## ๐Ÿ›  CLI Commands
161
+
162
+ ```bash
163
+ npx localize-ai init # generate runtime config
164
+ npx localize-ai translate # extract + translate
165
+ ```
166
+
167
+ ---
168
+
169
+ ## ๐ŸŽฏ Why localize-ai?
170
+
171
+ | Feature | localize-ai | traditional i18n |
172
+ | ------------------- | ----------- | ---------------- |
173
+ | Auto extraction | โœ… | โŒ |
174
+ | AI translation | โœ… | โŒ |
175
+ | Incremental updates | โœ… | โŒ |
176
+ | Setup time | โšก minutes | โณ hours |
177
+
178
+ ---
179
+
180
+ ## โš ๏ธ Notes
181
+
182
+ * Only static strings inside `t("...")` are extracted
183
+ * Ensure `public/` folder exists
184
+ * API key is required only for translation step
185
+
186
+ ---
187
+
188
+ ## ๐Ÿ—บ Roadmap
189
+
190
+ * [ ] AST-based extraction (no regex)
191
+ * [ ] Multi-provider support (OpenAI, etc.)
192
+ * [ ] Lazy loading translations
193
+ * [ ] CLI UI improvements
194
+
195
+ ---
196
+
197
+ ## ๐Ÿค Contributing
198
+
199
+ PRs welcome! Feel free to open issues or suggest improvements.
200
+
201
+ ---
202
+
203
+ ## ๐Ÿ“„ License
204
+
205
+ MIT
206
+
207
+ ---
208
+
209
+ ## ๐Ÿ’ฌ Author
210
+
211
+ **Parth Gupta**
212
+
213
+ ---
214
+
215
+ ## โญ Support
216
+
217
+ If you like this project:
218
+
219
+ ๐Ÿ‘‰ Star the repo
220
+ ๐Ÿ‘‰ Share with developers
221
+ ๐Ÿ‘‰ Give feedback
222
+
223
+ ---