@localheroai/cli 0.0.5 → 0.0.7

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 (116) hide show
  1. package/{README → README.md} +28 -10
  2. package/dist/api/auth.d.ts +2 -0
  3. package/dist/api/auth.js +28 -0
  4. package/dist/api/auth.js.map +1 -0
  5. package/dist/api/client.d.ts +3 -0
  6. package/dist/api/client.js +80 -0
  7. package/dist/api/client.js.map +1 -0
  8. package/dist/api/imports.d.ts +5 -0
  9. package/dist/api/imports.js +43 -0
  10. package/dist/api/imports.js.map +1 -0
  11. package/dist/api/projects.d.ts +2 -0
  12. package/dist/api/projects.js +42 -0
  13. package/dist/api/projects.js.map +1 -0
  14. package/dist/api/translations.d.ts +15 -0
  15. package/dist/api/translations.js +71 -0
  16. package/dist/api/translations.js.map +1 -0
  17. package/dist/cli.d.ts +2 -0
  18. package/dist/cli.js +79 -0
  19. package/dist/cli.js.map +1 -0
  20. package/dist/commands/_sync.js +22 -0
  21. package/dist/commands/_sync.js.map +1 -0
  22. package/dist/commands/_translate.js +3 -0
  23. package/dist/commands/_translate.js.map +1 -0
  24. package/dist/commands/init.d.ts +1 -0
  25. package/dist/commands/init.js +439 -0
  26. package/dist/commands/init.js.map +1 -0
  27. package/dist/commands/login.d.ts +16 -0
  28. package/dist/commands/login.js +58 -0
  29. package/dist/commands/login.js.map +1 -0
  30. package/dist/commands/pull.js +22 -0
  31. package/dist/commands/pull.js.map +1 -0
  32. package/dist/commands/push.js +56 -0
  33. package/dist/commands/push.js.map +1 -0
  34. package/dist/commands/sync.d.ts +20 -0
  35. package/dist/commands/sync.js +22 -0
  36. package/dist/commands/sync.js.map +1 -0
  37. package/dist/commands/translate.d.ts +14 -0
  38. package/dist/commands/translate.js +152 -0
  39. package/dist/commands/translate.js.map +1 -0
  40. package/dist/index.d.ts +5 -0
  41. package/dist/index.js +8 -0
  42. package/dist/index.js.map +1 -0
  43. package/dist/types/index.d.ts +75 -0
  44. package/dist/types/index.js +17 -0
  45. package/dist/types/index.js.map +1 -0
  46. package/dist/types/translate/index.js +2 -0
  47. package/dist/types/translate/index.js.map +1 -0
  48. package/dist/utils/auth.d.ts +2 -0
  49. package/dist/utils/auth.js +29 -0
  50. package/dist/utils/auth.js.map +1 -0
  51. package/dist/utils/common.js +9 -0
  52. package/dist/utils/common.js.map +1 -0
  53. package/dist/utils/config.d.ts +23 -0
  54. package/dist/utils/config.js +137 -0
  55. package/dist/utils/config.js.map +1 -0
  56. package/dist/utils/errors.js +37 -0
  57. package/dist/utils/errors.js.map +1 -0
  58. package/dist/utils/files.d.ts +32 -0
  59. package/dist/utils/files.js +355 -0
  60. package/dist/utils/files.js.map +1 -0
  61. package/dist/utils/git.d.ts +21 -0
  62. package/dist/utils/git.js +87 -0
  63. package/dist/utils/git.js.map +1 -0
  64. package/dist/utils/github.d.ts +241 -0
  65. package/dist/utils/github.js +161 -0
  66. package/dist/utils/github.js.map +1 -0
  67. package/dist/utils/import-service.d.ts +4 -0
  68. package/dist/utils/import-service.js +218 -0
  69. package/dist/utils/import-service.js.map +1 -0
  70. package/dist/utils/prompt-service.d.ts +44 -0
  71. package/dist/utils/prompt-service.js +104 -0
  72. package/dist/utils/prompt-service.js.map +1 -0
  73. package/dist/utils/sync-service.d.ts +58 -0
  74. package/dist/utils/sync-service.js +159 -0
  75. package/dist/utils/sync-service.js.map +1 -0
  76. package/dist/utils/translation-processor.js +197 -0
  77. package/dist/utils/translation-processor.js.map +1 -0
  78. package/dist/utils/translation-updater/common.d.ts +6 -0
  79. package/{src → dist}/utils/translation-updater/common.js +16 -10
  80. package/dist/utils/translation-updater/common.js.map +1 -0
  81. package/dist/utils/translation-updater/index.d.ts +5 -0
  82. package/{src → dist}/utils/translation-updater/index.js +21 -9
  83. package/dist/utils/translation-updater/index.js.map +1 -0
  84. package/dist/utils/translation-updater/json-handler.d.ts +5 -0
  85. package/dist/utils/translation-updater/json-handler.js +123 -0
  86. package/dist/utils/translation-updater/json-handler.js.map +1 -0
  87. package/dist/utils/translation-updater/yaml-handler.d.ts +5 -0
  88. package/dist/utils/translation-updater/yaml-handler.js +193 -0
  89. package/dist/utils/translation-updater/yaml-handler.js.map +1 -0
  90. package/dist/utils/translation-utils.d.ts +30 -0
  91. package/dist/utils/translation-utils.js +334 -0
  92. package/dist/utils/translation-utils.js.map +1 -0
  93. package/dist/utils/updater.js +38 -0
  94. package/dist/utils/updater.js.map +1 -0
  95. package/package.json +26 -26
  96. package/src/api/auth.js +0 -24
  97. package/src/api/client.js +0 -83
  98. package/src/api/imports.js +0 -22
  99. package/src/api/projects.js +0 -24
  100. package/src/api/translations.js +0 -58
  101. package/src/cli.js +0 -78
  102. package/src/commands/init.js +0 -485
  103. package/src/commands/login.js +0 -80
  104. package/src/commands/sync.js +0 -28
  105. package/src/commands/translate.js +0 -267
  106. package/src/utils/auth.js +0 -23
  107. package/src/utils/config.js +0 -125
  108. package/src/utils/files.js +0 -381
  109. package/src/utils/git.js +0 -72
  110. package/src/utils/github.js +0 -128
  111. package/src/utils/import-service.js +0 -128
  112. package/src/utils/prompt-service.js +0 -67
  113. package/src/utils/sync-service.js +0 -147
  114. package/src/utils/translation-updater/json-handler.js +0 -111
  115. package/src/utils/translation-updater/yaml-handler.js +0 -207
  116. package/src/utils/translation-utils.js +0 -278
@@ -13,9 +13,9 @@ LocalHero.ai is an AI-powered I18n translation service that seamlessly integrate
13
13
 
14
14
  ## Getting Started 🏁
15
15
 
16
- 1. Sign up for a free trial at [localhero.ai](https://localhero.ai/) (currently closed beta, get in touch if you are interested in trying it out)
16
+ 1. Sign up for a free trial at [localhero.ai](https://localhero.ai/).
17
17
  2. Get your API key from [localhero.ai/api-keys](https://localhero.ai/api-keys)
18
- 3. Run the init command in your project:
18
+ 3. Run the init command in your project to setup the configuration:
19
19
  ```bash
20
20
  npx @localheroai/cli init
21
21
  ```
@@ -29,6 +29,7 @@ npx @localheroai/cli init
29
29
  ```
30
30
 
31
31
  The init command helps you set up your project with LocalHero.ai. It will:
32
+ - Setup your API key if it hasn't been done already
32
33
  - Detect your project type (Rails, React, or generic)
33
34
  - Link to an existing LocalHero.ai project
34
35
  - Configure translation paths and file patterns
@@ -49,7 +50,9 @@ The configuration file is used by the tool to interact with your translations an
49
50
  npx @localheroai/cli login
50
51
  ```
51
52
 
52
- Authenticate with your LocalHero.ai account. Use this when:
53
+ Authenticate with the API using your API key. This will save your API key to `.localhero_key` and add the file to .gitignore if needed.
54
+
55
+ Use this when:
53
56
  - Setting up a new development environment
54
57
  - Updating your API key
55
58
  - Verifying your authentication status
@@ -63,10 +66,26 @@ npx @localheroai/cli translate
63
66
  Translating your missing keys:
64
67
  - Automatically detects missing translations and sends them to the Localhero.ai translation API for translation
65
68
  - Updates translation files with any new or update translations
66
- - It's run manually or by GitHub Actions
69
+ - It's run manually or by GitHub Actions. When run as a GitHub action any new translations are automatically committed to git.
70
+
71
+ ### Pull / push
72
+
73
+ ```bash
74
+ npx @localheroai/cli pull
75
+ ```
76
+
77
+ Pull the latest translation updates from LocalHero.ai to your local files. This command will download any new or modified translations from the service to your local files.
78
+
79
+ ```bash
80
+ npx @localheroai/cli push
81
+ ```
82
+
83
+ Push updates from your local translation files to LocalHero.ai. This command will upload any new or modified translations from your local files to the service.
67
84
 
68
85
  ## Environment Variables ⚙️
69
86
 
87
+ Typically you don't need to set these. The cli will use `LOCALHERO_API_KEY` if it's set, otherwise it will check the file `.localhero_key` for a API key.
88
+
70
89
  Configure the CLI behavior with these environment variables:
71
90
 
72
91
  | Variable | Description | Default |
@@ -79,19 +98,18 @@ Configure the CLI behavior with these environment variables:
79
98
  LocalHero.ai automatically translate your I18n files when you push changes. During the `init` command, you'll be prompted to set up GitHub Actions.
80
99
 
81
100
  1. Add your API key to your repository secrets:
82
- - Go to Settings > Secrets > Actions
101
+ - Go to Settings > Secrets and variables > Actions
83
102
  - Create a new secret named `LOCALHERO_API_KEY`
84
103
  - Add your API key as the value
85
104
 
86
105
  2. The workflow will:
87
- - Run on push to your main branch
88
- - Check for missing translations
89
- - Create a pull request with new translations
106
+ - Run on push to pull requests
107
+ - Check for missing translations and add new/updated translations to the repo.
90
108
 
91
109
  ## Support 💬
92
110
 
93
- - Documentation: [localhero.ai/docs](https://docs.localhero.ai/docs)
94
- - Email: support@localhero.ai
111
+ - Documentation: [localhero.ai/docs](https://localhero.ai/docs)
112
+ - Email: hi@localhero.ai
95
113
 
96
114
  ## License 📄
97
115
 
@@ -0,0 +1,2 @@
1
+ import { VerifyApiKeyResult } from '../types/index.js';
2
+ export declare function verifyApiKey(apiKey: string): Promise<VerifyApiKeyResult>;
@@ -0,0 +1,28 @@
1
+ import { apiRequest } from './client.js';
2
+ import { ApiResponseError } from '../types/index.js';
3
+ export async function verifyApiKey(apiKey) {
4
+ try {
5
+ return await apiRequest('/api/v1/auth/verify', {
6
+ apiKey
7
+ });
8
+ }
9
+ catch (error) {
10
+ if (error instanceof ApiResponseError) {
11
+ return {
12
+ error: {
13
+ code: error.code,
14
+ message: error.message
15
+ }
16
+ };
17
+ }
18
+ return {
19
+ error: {
20
+ code: error.code || 'verification_failed',
21
+ message: error instanceof Error && error.message
22
+ ? error.message
23
+ : 'Failed to verify API key'
24
+ }
25
+ };
26
+ }
27
+ }
28
+ //# sourceMappingURL=auth.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth.js","sourceRoot":"","sources":["../../src/api/auth.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAWrD,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,MAAc;IAC/C,IAAI,CAAC;QACH,OAAO,MAAM,UAAU,CAAC,qBAAqB,EAAE;YAC7C,MAAM;SACP,CAAC,CAAC;IACL,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,IAAI,KAAK,YAAY,gBAAgB,EAAE,CAAC;YACtC,OAAO;gBACL,KAAK,EAAE;oBACL,IAAI,EAAE,KAAK,CAAC,IAAI;oBAChB,OAAO,EAAE,KAAK,CAAC,OAAO;iBACvB;aACF,CAAC;QACJ,CAAC;QAED,OAAO;YACL,KAAK,EAAE;gBACL,IAAI,EAAG,KAAa,CAAC,IAAI,IAAI,qBAAqB;gBAClD,OAAO,EAAE,KAAK,YAAY,KAAK,IAAI,KAAK,CAAC,OAAO;oBAC9C,CAAC,CAAC,KAAK,CAAC,OAAO;oBACf,CAAC,CAAC,0BAA0B;aAC/B;SACF,CAAC;IACJ,CAAC;AACH,CAAC"}
@@ -0,0 +1,3 @@
1
+ import { ApiRequestOptions } from '../types/index.js';
2
+ export declare function getApiHost(): string;
3
+ export declare function apiRequest<T = any>(endpoint: string, options?: ApiRequestOptions): Promise<T>;
@@ -0,0 +1,80 @@
1
+ import { ApiResponseError } from '../types/index.js';
2
+ const DEFAULT_API_HOST = 'https://api.localhero.ai';
3
+ export function getApiHost() {
4
+ return process.env.LOCALHERO_API_HOST || DEFAULT_API_HOST;
5
+ }
6
+ function getNetworkErrorMessage(error) {
7
+ if (error.code === 'ECONNREFUSED') {
8
+ return `Unable to connect to ${getApiHost()}. Please check your internet connection and try again.`;
9
+ }
10
+ if (error.cause?.code === 'ENOTFOUND') {
11
+ return `Could not resolve host ${getApiHost()}. Please check your internet connection and try again.`;
12
+ }
13
+ if (error.cause?.code === 'ETIMEDOUT') {
14
+ return `Connection to ${getApiHost()} timed out. Please try again later.`;
15
+ }
16
+ return `Network error while connecting to ${getApiHost()}. Please check your internet connection and try again.`;
17
+ }
18
+ export async function apiRequest(endpoint, options = {}) {
19
+ const apiHost = getApiHost();
20
+ const url = `${apiHost}${endpoint}`;
21
+ const apiKey = process.env.LOCALHERO_API_KEY || options.apiKey;
22
+ const headers = {
23
+ 'Content-Type': 'application/json',
24
+ ...options.headers
25
+ };
26
+ if (apiKey) {
27
+ headers['Authorization'] = `Bearer ${apiKey}`;
28
+ }
29
+ const fetchOptions = {
30
+ method: options.method || 'GET',
31
+ headers,
32
+ };
33
+ if (options.body) {
34
+ fetchOptions.body = JSON.stringify(options.body);
35
+ }
36
+ let response;
37
+ try {
38
+ response = await fetch(url, fetchOptions);
39
+ }
40
+ catch (error) {
41
+ const networkError = error;
42
+ const message = getNetworkErrorMessage(networkError);
43
+ networkError.message = message;
44
+ networkError.cliErrorMessage = message;
45
+ throw networkError;
46
+ }
47
+ let data;
48
+ try {
49
+ data = await response.json();
50
+ }
51
+ catch (error) {
52
+ const parseError = error;
53
+ const message = 'Failed to parse API response. Error: ' + error;
54
+ parseError.message = message;
55
+ parseError.cliErrorMessage = message;
56
+ throw parseError;
57
+ }
58
+ if (!response.ok) {
59
+ if (response.status === 401 && data?.error?.code === 'invalid_api_key') {
60
+ const message = 'Your API key is invalid or has been revoked. Please run `npx @localheroai/cli login` to update your API key.';
61
+ const error = new ApiResponseError(message);
62
+ error.cliErrorMessage = message;
63
+ error.code = 'invalid_api_key';
64
+ error.data = data;
65
+ error.details = null;
66
+ throw error;
67
+ }
68
+ const message = Array.isArray(data?.errors)
69
+ ? data.errors.map((err) => typeof err === 'string' ? err : err.message).join(', ')
70
+ : data?.error?.message || 'API request failed';
71
+ const error = new ApiResponseError(message);
72
+ error.cliErrorMessage = message;
73
+ error.code = data?.error?.code || 'API_ERROR';
74
+ error.details = data?.error?.details || null;
75
+ error.data = data;
76
+ throw error;
77
+ }
78
+ return data;
79
+ }
80
+ //# sourceMappingURL=client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.js","sourceRoot":"","sources":["../../src/api/client.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ export function createImport({ projectId, translations }: {
2
+ projectId: any;
3
+ translations: any;
4
+ }): Promise<any>;
5
+ export function checkImportStatus(projectId: any, importId: any): Promise<any>;
@@ -0,0 +1,43 @@
1
+ import { getApiKey } from '../utils/auth.js';
2
+ import { apiRequest } from './client.js';
3
+ /**
4
+ * Create a new import of translations
5
+ * @param params Import parameters
6
+ * @returns The created import details
7
+ */
8
+ export async function createImport(params) {
9
+ const apiKey = await getApiKey();
10
+ const response = await apiRequest(`/api/v1/projects/${params.projectId}/imports`, {
11
+ method: 'POST',
12
+ body: {
13
+ translations: params.translations
14
+ },
15
+ apiKey
16
+ });
17
+ return response;
18
+ }
19
+ export async function bulkUpdateTranslations(params) {
20
+ const apiKey = await getApiKey();
21
+ const response = await apiRequest(`/api/v1/projects/${params.projectId}/imports`, {
22
+ method: 'PATCH',
23
+ body: {
24
+ translations: params.translations
25
+ },
26
+ apiKey
27
+ });
28
+ return response;
29
+ }
30
+ /**
31
+ * Check the status of an import
32
+ * @param projectId The ID of the project
33
+ * @param importId The ID of the import to check
34
+ * @returns The import status response
35
+ */
36
+ export async function checkImportStatus(projectId, importId) {
37
+ const apiKey = await getApiKey();
38
+ const response = await apiRequest(`/api/v1/projects/${projectId}/imports/${importId}`, {
39
+ apiKey
40
+ });
41
+ return response;
42
+ }
43
+ //# sourceMappingURL=imports.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"imports.js","sourceRoot":"","sources":["../../src/api/imports.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAC7C,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AA6CzC;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,MAA0B;IAC3D,MAAM,MAAM,GAAG,MAAM,SAAS,EAAE,CAAC;IACjC,MAAM,QAAQ,GAAG,MAAM,UAAU,CAAC,oBAAoB,MAAM,CAAC,SAAS,UAAU,EAAE;QAChF,MAAM,EAAE,MAAM;QACd,IAAI,EAAE;YACJ,YAAY,EAAE,MAAM,CAAC,YAAY;SAClC;QACD,MAAM;KACP,CAAC,CAAC;IACH,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,sBAAsB,CAAC,MAAoC;IAC/E,MAAM,MAAM,GAAG,MAAM,SAAS,EAAE,CAAC;IACjC,MAAM,QAAQ,GAAG,MAAM,UAAU,CAAC,oBAAoB,MAAM,CAAC,SAAS,UAAU,EAAE;QAChF,MAAM,EAAE,OAAO;QACf,IAAI,EAAE;YACJ,YAAY,EAAE,MAAM,CAAC,YAAY;SAClC;QACD,MAAM;KACP,CAAC,CAAC;IACH,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,iBAAiB,CAAC,SAAiB,EAAE,QAAgB;IACzE,MAAM,MAAM,GAAG,MAAM,SAAS,EAAE,CAAC;IACjC,MAAM,QAAQ,GAAG,MAAM,UAAU,CAAC,oBAAoB,SAAS,YAAY,QAAQ,EAAE,EAAE;QACrF,MAAM;KACP,CAAC,CAAC;IACH,OAAO,QAAQ,CAAC;AAClB,CAAC"}
@@ -0,0 +1,2 @@
1
+ export function listProjects(): Promise<any>;
2
+ export function createProject(data: any): Promise<any>;
@@ -0,0 +1,42 @@
1
+ import { getApiKey } from '../utils/auth.js';
2
+ import { apiRequest } from './client.js';
3
+ /**
4
+ * List all projects the user has access to
5
+ * @returns Array of project details
6
+ */
7
+ export async function listProjects() {
8
+ const apiKey = await getApiKey();
9
+ const response = await apiRequest('/api/v1/projects', { apiKey });
10
+ return response.projects;
11
+ }
12
+ /**
13
+ * Create a new project
14
+ * @param data Project creation parameters
15
+ * @returns The created project details
16
+ */
17
+ export async function createProject(data) {
18
+ const apiKey = await getApiKey();
19
+ const response = await apiRequest('/api/v1/projects', {
20
+ method: 'POST',
21
+ body: {
22
+ project: {
23
+ name: data.name,
24
+ source_language: data.sourceLocale,
25
+ target_languages: data.targetLocales
26
+ }
27
+ },
28
+ apiKey
29
+ });
30
+ return response.project;
31
+ }
32
+ /**
33
+ * Get details for a specific project
34
+ * @param projectId The ID of the project to fetch
35
+ * @returns The project details
36
+ */
37
+ export async function getProject(projectId) {
38
+ const apiKey = await getApiKey();
39
+ const response = await apiRequest(`/api/v1/projects/${projectId}`, { apiKey });
40
+ return response.project;
41
+ }
42
+ //# sourceMappingURL=projects.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"projects.js","sourceRoot":"","sources":["../../src/api/projects.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAC7C,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAczC;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,YAAY;IAChC,MAAM,MAAM,GAAG,MAAM,SAAS,EAAE,CAAC;IACjC,MAAM,QAAQ,GAAG,MAAM,UAAU,CAAC,kBAAkB,EAAE,EAAE,MAAM,EAAE,CAAC,CAAC;IAClE,OAAO,QAAQ,CAAC,QAAQ,CAAC;AAC3B,CAAC;AAWD;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,IAAyB;IAC3D,MAAM,MAAM,GAAG,MAAM,SAAS,EAAE,CAAC;IACjC,MAAM,QAAQ,GAAG,MAAM,UAAU,CAAC,kBAAkB,EAAE;QACpD,MAAM,EAAE,MAAM;QACd,IAAI,EAAE;YACJ,OAAO,EAAE;gBACP,IAAI,EAAE,IAAI,CAAC,IAAI;gBACf,eAAe,EAAE,IAAI,CAAC,YAAY;gBAClC,gBAAgB,EAAE,IAAI,CAAC,aAAa;aACrC;SACF;QACD,MAAM;KACP,CAAC,CAAC;IACH,OAAO,QAAQ,CAAC,OAAO,CAAC;AAC1B,CAAC;AAED;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,UAAU,CAAC,SAAiB;IAChD,MAAM,MAAM,GAAG,MAAM,SAAS,EAAE,CAAC;IACjC,MAAM,QAAQ,GAAG,MAAM,UAAU,CAAC,oBAAoB,SAAS,EAAE,EAAE,EAAE,MAAM,EAAE,CAAC,CAAC;IAC/E,OAAO,QAAQ,CAAC,OAAO,CAAC;AAC1B,CAAC"}
@@ -0,0 +1,15 @@
1
+ export function createTranslationJob({ sourceFiles, targetLocales, projectId, targetPaths }: {
2
+ sourceFiles: any;
3
+ targetLocales: any;
4
+ projectId: any;
5
+ targetPaths: any;
6
+ }): Promise<{
7
+ jobs: any;
8
+ totalJobs: any;
9
+ }>;
10
+ export function checkJobStatus(jobId: any, includeTranslations?: boolean): Promise<any>;
11
+ export function getTranslations(jobId: any): Promise<any>;
12
+ export function getUpdates(projectId: any, { since, page }: {
13
+ since: any;
14
+ page?: number | undefined;
15
+ }): Promise<any>;
@@ -0,0 +1,71 @@
1
+ import { getApiKey } from '../utils/auth.js';
2
+ import { apiRequest } from './client.js';
3
+ import { getCurrentBranch } from '../utils/git.js';
4
+ /**
5
+ * Create a new translation job
6
+ * @param params Job parameters
7
+ * @returns The created translation jobs
8
+ */
9
+ export async function createTranslationJob(params) {
10
+ const apiKey = await getApiKey();
11
+ const branch = await getCurrentBranch();
12
+ const response = await apiRequest(`/api/v1/projects/${params.projectId}/translation_jobs`, {
13
+ method: 'POST',
14
+ body: {
15
+ target_languages: params.targetLocales,
16
+ files: params.sourceFiles.map(file => ({
17
+ path: file.path,
18
+ content: file.content,
19
+ format: file.format,
20
+ target_paths: params.targetPaths
21
+ })),
22
+ ...(branch && { branch })
23
+ },
24
+ apiKey
25
+ });
26
+ if (!response.jobs || !response.jobs.length) {
27
+ throw new Error('No translation jobs were created');
28
+ }
29
+ return {
30
+ jobs: response.jobs,
31
+ totalJobs: response.jobs.length
32
+ };
33
+ }
34
+ /**
35
+ * Check the status of a translation job
36
+ * @param jobId The ID of the job to check
37
+ * @param includeTranslations Whether to include translations in the response
38
+ * @returns The job status
39
+ */
40
+ export async function checkJobStatus(jobId, includeTranslations = false) {
41
+ const apiKey = await getApiKey();
42
+ const endpoint = `/api/v1/translation_jobs/${jobId}${includeTranslations ? '?include_translations=true' : ''}`;
43
+ return apiRequest(endpoint, { apiKey });
44
+ }
45
+ /**
46
+ * Get translations for a completed job
47
+ * @param jobId The ID of the job
48
+ * @returns The translations
49
+ */
50
+ export async function getTranslations(jobId) {
51
+ const apiKey = await getApiKey();
52
+ return apiRequest(`/api/v1/translation_jobs/${jobId}/translations`, { apiKey });
53
+ }
54
+ /**
55
+ * Get translation updates for a project
56
+ * @param projectId The ID of the project
57
+ * @param params Parameters for the request
58
+ * @returns The updates
59
+ */
60
+ export async function getUpdates(projectId, { since, page = 1 }) {
61
+ const apiKey = await getApiKey();
62
+ if (!since) {
63
+ throw new Error('Missing required parameter: since (ISO 8601 timestamp)');
64
+ }
65
+ const queryParams = new URLSearchParams({
66
+ since,
67
+ page: page.toString()
68
+ });
69
+ return apiRequest(`/api/v1/projects/${projectId}/updates?${queryParams}`, { apiKey });
70
+ }
71
+ //# sourceMappingURL=translations.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"translations.js","sourceRoot":"","sources":["../../src/api/translations.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAC7C,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AA+BnD;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,oBAAoB,CAAC,MAAkC;IAC3E,MAAM,MAAM,GAAG,MAAM,SAAS,EAAE,CAAC;IACjC,MAAM,MAAM,GAAG,MAAM,gBAAgB,EAAE,CAAC;IAExC,MAAM,QAAQ,GAAG,MAAM,UAAU,CAAC,oBAAoB,MAAM,CAAC,SAAS,mBAAmB,EAAE;QACzF,MAAM,EAAE,MAAM;QACd,IAAI,EAAE;YACJ,gBAAgB,EAAE,MAAM,CAAC,aAAa;YACtC,KAAK,EAAE,MAAM,CAAC,WAAW,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;gBACrC,IAAI,EAAE,IAAI,CAAC,IAAI;gBACf,OAAO,EAAE,IAAI,CAAC,OAAO;gBACrB,MAAM,EAAE,IAAI,CAAC,MAAM;gBACnB,YAAY,EAAE,MAAM,CAAC,WAAW;aACjC,CAAC,CAAC;YACH,GAAG,CAAC,MAAM,IAAI,EAAE,MAAM,EAAE,CAAC;SAC1B;QACD,MAAM;KACP,CAAC,CAAC;IAEH,IAAI,CAAC,QAAQ,CAAC,IAAI,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC;QAC5C,MAAM,IAAI,KAAK,CAAC,kCAAkC,CAAC,CAAC;IACtD,CAAC;IAED,OAAO;QACL,IAAI,EAAE,QAAQ,CAAC,IAAI;QACnB,SAAS,EAAE,QAAQ,CAAC,IAAI,CAAC,MAAM;KAChC,CAAC;AACJ,CAAC;AAgBD;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,cAAc,CAClC,KAAa,EACb,mBAAmB,GAAG,KAAK;IAE3B,MAAM,MAAM,GAAG,MAAM,SAAS,EAAE,CAAC;IACjC,MAAM,QAAQ,GAAG,4BAA4B,KAAK,GAAG,mBAAmB,CAAC,CAAC,CAAC,4BAA4B,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC;IAC/G,OAAO,UAAU,CAAC,QAAQ,EAAE,EAAE,MAAM,EAAE,CAAC,CAAC;AAC1C,CAAC;AAOD;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,eAAe,CAAC,KAAa;IACjD,MAAM,MAAM,GAAG,MAAM,SAAS,EAAE,CAAC;IACjC,OAAO,UAAU,CAAC,4BAA4B,KAAK,eAAe,EAAE,EAAE,MAAM,EAAE,CAAC,CAAC;AAClF,CAAC;AA2BD;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,UAAU,CAC9B,SAAiB,EACjB,EAAE,KAAK,EAAE,IAAI,GAAG,CAAC,EAAoB;IAErC,MAAM,MAAM,GAAG,MAAM,SAAS,EAAE,CAAC;IAEjC,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,MAAM,IAAI,KAAK,CAAC,wDAAwD,CAAC,CAAC;IAC5E,CAAC;IAED,MAAM,WAAW,GAAG,IAAI,eAAe,CAAC;QACtC,KAAK;QACL,IAAI,EAAE,IAAI,CAAC,QAAQ,EAAE;KACtB,CAAC,CAAC;IAEH,OAAO,UAAU,CAAC,oBAAoB,SAAS,YAAY,WAAW,EAAE,EAAE,EAAE,MAAM,EAAE,CAAC,CAAC;AACxF,CAAC"}
package/dist/cli.d.ts ADDED
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export {};
package/dist/cli.js ADDED
@@ -0,0 +1,79 @@
1
+ #!/usr/bin/env node
2
+ import { Command } from 'commander';
3
+ import chalk from 'chalk';
4
+ import { readFileSync } from 'fs';
5
+ import { fileURLToPath } from 'url';
6
+ import { dirname, resolve } from 'path';
7
+ import { login } from './commands/login.js';
8
+ import { pull } from './commands/pull.js';
9
+ import { push } from './commands/push.js';
10
+ import { init } from './commands/init.js';
11
+ import { translate } from './commands/translate.js';
12
+ import { configService } from './utils/config.js';
13
+ const __filename = fileURLToPath(import.meta.url);
14
+ const __dirname = dirname(__filename);
15
+ const program = new Command();
16
+ function getVersion() {
17
+ const packageJson = JSON.parse(readFileSync(resolve(__dirname, '../package.json'), 'utf-8'));
18
+ return packageJson.version;
19
+ }
20
+ function handleApiError(error) {
21
+ console.error(chalk.red(`❌ ${error.cliErrorMessage || error.message}`));
22
+ if (program.opts().debug) {
23
+ console.error(chalk.dim(error.stack || error));
24
+ if (error.cause) {
25
+ console.error(chalk.dim(error.cause.stack || error.cause));
26
+ }
27
+ }
28
+ else {
29
+ console.error(chalk.dim('\nRun with --debug for more information'));
30
+ }
31
+ process.exit(1);
32
+ }
33
+ function wrapCommandAction(action) {
34
+ return function (...args) {
35
+ return Promise.resolve(action(...args)).catch(handleApiError);
36
+ };
37
+ }
38
+ program
39
+ .name('localhero')
40
+ .description('CLI tool for automatic I18n translations with LocalHero.ai, more info at https://localhero.ai.')
41
+ .version(getVersion())
42
+ .option('--debug', 'Show debug information when errors occur')
43
+ .action(() => {
44
+ console.log('LocalHero.ai is automatic I18n translations service that easily integrates with your dev workflow.');
45
+ console.log(`\nVersion: ${getVersion()}`);
46
+ console.log('\n🔗 Visit https://localhero.ai for more information');
47
+ console.log('👏 Set up your project with `npx @localheroai/cli init`');
48
+ console.log('💡 Use --help to see available commands');
49
+ });
50
+ program
51
+ .command('login')
52
+ .description('Authenticate with LocalHero.ai using an API key')
53
+ .action(wrapCommandAction(() => login()));
54
+ program
55
+ .command('init')
56
+ .description('Initialize a new LocalHero.ai project')
57
+ .action(wrapCommandAction(() => init()));
58
+ program
59
+ .command('translate')
60
+ .description('Translate missing keys in your i18n files')
61
+ .option('-v, --verbose', 'Show detailed progress information')
62
+ .option('-c, --commit', 'Automatically commit changes (useful for CI/CD)')
63
+ .action(wrapCommandAction((options) => translate(options)));
64
+ program
65
+ .command('pull')
66
+ .description('Pull updates from LocalHero.ai to your local files')
67
+ .option('-v, --verbose', 'Show detailed progress information')
68
+ .action(wrapCommandAction((options) => pull(options)));
69
+ program
70
+ .command('push')
71
+ .description('Push updates from your local files to LocalHero.ai')
72
+ .option('-v, --verbose', 'Show detailed progress information')
73
+ .option('-y, --yes', 'Skip confirmation prompt')
74
+ .action(wrapCommandAction(async (options) => {
75
+ const config = await configService.getValidProjectConfig();
76
+ return push(config, options);
77
+ }));
78
+ program.parse();
79
+ //# sourceMappingURL=cli.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,22 @@
1
+ import { syncService as defaultSyncService } from '../utils/sync-service.js';
2
+ import chalk from 'chalk';
3
+ export async function sync({ verbose = false } = {}, deps = { syncService: defaultSyncService }) {
4
+ const { syncService } = deps;
5
+ const { hasUpdates, updates } = await syncService.checkForUpdates({ verbose });
6
+ if (!hasUpdates) {
7
+ console.log(chalk.green('✓ All translations are up to date'));
8
+ return;
9
+ }
10
+ const result = await syncService.applyUpdates(updates, { verbose });
11
+ const { totalUpdates = 0, totalDeleted = 0 } = result;
12
+ if (!verbose) {
13
+ if (totalUpdates > 0) {
14
+ console.log(chalk.green(`✓ Updated ${totalUpdates} translations`));
15
+ }
16
+ if (totalDeleted > 0) {
17
+ console.log(chalk.green(`✓ Deleted ${totalDeleted} keys`));
18
+ }
19
+ }
20
+ return result;
21
+ }
22
+ //# sourceMappingURL=_sync.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"_sync.js","sourceRoot":"","sources":["../../src/commands/_sync.js"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,IAAI,kBAAkB,EAAE,MAAM,0BAA0B,CAAC;AAC7E,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,MAAM,CAAC,KAAK,UAAU,IAAI,CAAC,EAAE,OAAO,GAAG,KAAK,EAAE,GAAG,EAAE,EAAE,IAAI,GAAG,EAAE,WAAW,EAAE,kBAAkB,EAAE;IAC7F,MAAM,EAAE,WAAW,EAAE,GAAG,IAAI,CAAC;IAC7B,MAAM,EAAE,UAAU,EAAE,OAAO,EAAE,GAAG,MAAM,WAAW,CAAC,eAAe,CAAC,EAAE,OAAO,EAAE,CAAC,CAAC;IAE/E,IAAI,CAAC,UAAU,EAAE,CAAC;QAChB,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,mCAAmC,CAAC,CAAC,CAAC;QAC9D,OAAO;IACT,CAAC;IAED,MAAM,MAAM,GAAG,MAAM,WAAW,CAAC,YAAY,CAAC,OAAO,EAAE,EAAE,OAAO,EAAE,CAAC,CAAC;IAEpE,MAAM,EAAE,YAAY,GAAG,CAAC,EAAE,YAAY,GAAG,CAAC,EAAE,GAAG,MAAM,CAAC;IAEtD,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,IAAI,YAAY,GAAG,CAAC,EAAE,CAAC;YACrB,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,aAAa,YAAY,eAAe,CAAC,CAAC,CAAC;QACrE,CAAC;QAED,IAAI,YAAY,GAAG,CAAC,EAAE,CAAC;YACrB,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,aAAa,YAAY,OAAO,CAAC,CAAC,CAAC;QAC7D,CAAC;IACH,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC"}
@@ -0,0 +1,3 @@
1
+ // This is a compatibility wrapper for the TypeScript implementation
2
+ export { translate } from './translate.ts';
3
+ //# sourceMappingURL=_translate.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"_translate.js","sourceRoot":"","sources":["../../src/commands/_translate.js"],"names":[],"mappings":"AAAA,oEAAoE;AACpE,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC"}
@@ -0,0 +1 @@
1
+ export function init(deps?: {}): Promise<void>;