langctl 0.1.2 → 0.3.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 (63) hide show
  1. package/CHANGELOG.md +42 -0
  2. package/LICENSE +1 -1
  3. package/README.md +159 -1151
  4. package/dist/commands/auth.js +82 -24
  5. package/dist/commands/config.js +36 -25
  6. package/dist/commands/export.js +11 -112
  7. package/dist/commands/import.js +32 -164
  8. package/dist/commands/init.js +59 -80
  9. package/dist/commands/keys.js +145 -381
  10. package/dist/commands/org.js +45 -140
  11. package/dist/commands/projects.js +125 -390
  12. package/dist/commands/pull.js +78 -183
  13. package/dist/commands/push.js +125 -0
  14. package/dist/commands/team.js +68 -272
  15. package/dist/core/config.js +130 -0
  16. package/dist/core/errors.js +67 -0
  17. package/dist/core/files.js +38 -0
  18. package/dist/core/http.js +121 -0
  19. package/dist/core/output.js +96 -0
  20. package/dist/core/project.js +58 -0
  21. package/dist/core/prompts.js +56 -0
  22. package/dist/formats/index.js +285 -0
  23. package/dist/index.js +261 -508
  24. package/dist/version.js +4 -0
  25. package/package.json +22 -16
  26. package/.gitattributes +0 -2
  27. package/NEXT_PHASE.md +0 -618
  28. package/WORKING_INSTRUCTIONS.md +0 -1389
  29. package/dist/auth.d.ts +0 -37
  30. package/dist/auth.js +0 -112
  31. package/dist/commands/auth.d.ts +0 -3
  32. package/dist/commands/config.d.ts +0 -2
  33. package/dist/commands/debug.d.ts +0 -3
  34. package/dist/commands/debug.js +0 -57
  35. package/dist/commands/export.d.ts +0 -14
  36. package/dist/commands/import.d.ts +0 -11
  37. package/dist/commands/init.d.ts +0 -2
  38. package/dist/commands/keys.d.ts +0 -25
  39. package/dist/commands/org.d.ts +0 -13
  40. package/dist/commands/projects.d.ts +0 -30
  41. package/dist/commands/pull.d.ts +0 -9
  42. package/dist/commands/team.d.ts +0 -29
  43. package/dist/config.d.ts +0 -47
  44. package/dist/config.js +0 -69
  45. package/dist/exporters/index.d.ts +0 -36
  46. package/dist/exporters/index.js +0 -214
  47. package/dist/index.d.ts +0 -3
  48. package/dist/supabase.d.ts +0 -14
  49. package/dist/supabase.js +0 -30
  50. package/dist/utils/banner.d.ts +0 -9
  51. package/dist/utils/banner.js +0 -24
  52. package/translations/en.json +0 -5
  53. package/translations/en.xml +0 -9
  54. package/translations/fr.json +0 -4
  55. package/translations/fr.xml +0 -7
  56. package/translations/hi.json +0 -4
  57. package/translations/hi.xml +0 -7
  58. package/translations/ios/en.strings +0 -9
  59. package/translations/ios/fr.strings +0 -6
  60. package/translations/ios/hi.strings +0 -6
  61. package/translations/ios/ja.strings +0 -6
  62. package/translations/ja.json +0 -4
  63. package/translations/ja.xml +0 -7
@@ -1,214 +0,0 @@
1
- /**
2
- * Helper: Set nested value in object based on dot-notation key
3
- */
4
- function setNestedValue(obj, path, value) {
5
- const keys = path.split('.');
6
- let current = obj;
7
- for (let i = 0; i < keys.length - 1; i++) {
8
- const key = keys[i];
9
- if (!current[key] || typeof current[key] !== 'object') {
10
- current[key] = {};
11
- }
12
- current = current[key];
13
- }
14
- current[keys[keys.length - 1]] = value;
15
- }
16
- /**
17
- * Helper: Convert i18n format {{param}} to Android format %1$s, %2$s, etc.
18
- */
19
- function convertToAndroidFormat(text) {
20
- const matches = text.match(/\{\{([^}]+)\}\}/g);
21
- if (!matches)
22
- return text;
23
- let result = text;
24
- matches.forEach((match, index) => {
25
- const paramNum = index + 1;
26
- result = result.replace(match, `%${paramNum}$s`);
27
- });
28
- return result;
29
- }
30
- /**
31
- * Helper: Convert i18n format {{param}} to iOS format %1$@, %2$@, etc.
32
- */
33
- function convertToIosFormat(text) {
34
- const matches = text.match(/\{\{([^}]+)\}\}/g);
35
- if (!matches)
36
- return text;
37
- let result = text;
38
- matches.forEach((match, index) => {
39
- const paramNum = index + 1;
40
- result = result.replace(match, `%${paramNum}$@`);
41
- });
42
- return result;
43
- }
44
- /**
45
- * Helper: Convert i18n format {{param}} to Flutter format {param}
46
- */
47
- function convertToFlutterFormat(text) {
48
- return text.replace(/\{\{([^}]+)\}\}/g, '{$1}');
49
- }
50
- /**
51
- * Helper: Extract placeholder names from Flutter format {param}
52
- */
53
- function extractPlaceholders(text) {
54
- const matches = text.match(/\{([^}]+)\}/g);
55
- if (!matches)
56
- return [];
57
- return matches.map(match => match.slice(1, -1));
58
- }
59
- /**
60
- * Helper: Escape XML special characters
61
- */
62
- function escapeXml(text) {
63
- return text
64
- .replace(/&/g, '&amp;')
65
- .replace(/</g, '&lt;')
66
- .replace(/>/g, '&gt;')
67
- .replace(/"/g, '&quot;')
68
- .replace(/'/g, '&apos;');
69
- }
70
- /**
71
- * Helper: Escape .strings special characters
72
- */
73
- function escapeStrings(text) {
74
- return text
75
- .replace(/\\/g, '\\\\')
76
- .replace(/"/g, '\\"')
77
- .replace(/\n/g, '\\n')
78
- .replace(/\r/g, '\\r')
79
- .replace(/\t/g, '\\t');
80
- }
81
- /**
82
- * Export as flat JSON (simple key-value pairs)
83
- */
84
- export function exportFlatJson(keys, languageCode) {
85
- const translations = {};
86
- keys.forEach(key => {
87
- const translation = key.translations[languageCode];
88
- if (translation) {
89
- translations[key.key] = translation;
90
- }
91
- });
92
- return {
93
- content: JSON.stringify(translations, null, 2),
94
- filename: `${languageCode}.json`
95
- };
96
- }
97
- /**
98
- * Export as nested JSON (organized by key structure)
99
- */
100
- export function exportNestedJson(keys, languageCode) {
101
- const translations = {};
102
- keys.forEach(key => {
103
- const translation = key.translations[languageCode];
104
- if (translation) {
105
- setNestedValue(translations, key.key, translation);
106
- }
107
- });
108
- return {
109
- content: JSON.stringify(translations, null, 2),
110
- filename: `${languageCode}.json`
111
- };
112
- }
113
- /**
114
- * Export as iOS .strings format
115
- */
116
- export function exportIosStrings(keys, languageCode) {
117
- let content = '';
118
- keys.forEach(key => {
119
- const translation = key.translations[languageCode];
120
- if (translation) {
121
- const iosTranslation = convertToIosFormat(translation);
122
- const escapedTranslation = escapeStrings(iosTranslation);
123
- if (key.description) {
124
- content += `/* ${key.description} */\n`;
125
- }
126
- content += `"${key.key}" = "${escapedTranslation}";\n\n`;
127
- }
128
- });
129
- return {
130
- content,
131
- filename: `Localizable.strings`
132
- };
133
- }
134
- /**
135
- * Export as Android XML format
136
- */
137
- export function exportAndroidXml(keys, languageCode) {
138
- let xml = '<?xml version="1.0" encoding="utf-8"?>\n';
139
- xml += '<resources>\n';
140
- keys.forEach(key => {
141
- const translation = key.translations[languageCode];
142
- if (translation) {
143
- const androidTranslation = convertToAndroidFormat(translation);
144
- const escapedTranslation = escapeXml(androidTranslation);
145
- if (key.description) {
146
- xml += ` <!-- ${escapeXml(key.description)} -->\n`;
147
- }
148
- xml += ` <string name="${key.key}">${escapedTranslation}</string>\n`;
149
- }
150
- });
151
- xml += '</resources>\n';
152
- return {
153
- content: xml,
154
- filename: `strings.xml`
155
- };
156
- }
157
- /**
158
- * Export as Flutter ARB format
159
- */
160
- export function exportFlutterArb(keys, languageCode) {
161
- const arb = {
162
- '@@locale': languageCode,
163
- '@@last_modified': new Date().toISOString()
164
- };
165
- keys.forEach(key => {
166
- const translation = key.translations[languageCode];
167
- if (translation) {
168
- const flutterTranslation = convertToFlutterFormat(translation);
169
- arb[key.key] = flutterTranslation;
170
- // Add metadata
171
- const metadata = {};
172
- if (key.description) {
173
- metadata.description = key.description;
174
- }
175
- // Extract placeholders from translation
176
- const placeholders = extractPlaceholders(flutterTranslation);
177
- if (placeholders.length > 0) {
178
- metadata.placeholders = {};
179
- placeholders.forEach(placeholder => {
180
- metadata.placeholders[placeholder] = {
181
- type: 'String'
182
- };
183
- });
184
- }
185
- if (Object.keys(metadata).length > 0) {
186
- arb[`@${key.key}`] = metadata;
187
- }
188
- }
189
- });
190
- return {
191
- content: JSON.stringify(arb, null, 2),
192
- filename: `intl_${languageCode}.arb`
193
- };
194
- }
195
- /**
196
- * Export translations in the specified format
197
- */
198
- export function exportTranslations(keys, languageCode, format) {
199
- switch (format) {
200
- case 'json':
201
- return exportFlatJson(keys, languageCode);
202
- case 'json-nested':
203
- return exportNestedJson(keys, languageCode);
204
- case 'ios':
205
- return exportIosStrings(keys, languageCode);
206
- case 'android':
207
- return exportAndroidXml(keys, languageCode);
208
- case 'flutter':
209
- return exportFlutterArb(keys, languageCode);
210
- default:
211
- throw new Error(`Unsupported export format: ${format}`);
212
- }
213
- }
214
- //# sourceMappingURL=index.js.map
package/dist/index.d.ts DELETED
@@ -1,3 +0,0 @@
1
- #!/usr/bin/env node
2
- export {};
3
- //# sourceMappingURL=index.d.ts.map
@@ -1,14 +0,0 @@
1
- import { SupabaseClient } from '@supabase/supabase-js';
2
- /**
3
- * Initialize Supabase client with hardcoded credentials
4
- */
5
- export declare function initializeSupabase(): SupabaseClient;
6
- /**
7
- * Get existing Supabase client or initialize it
8
- */
9
- export declare function getSupabase(): SupabaseClient;
10
- /**
11
- * Reset Supabase client (useful for tests)
12
- */
13
- export declare function resetSupabase(): void;
14
- //# sourceMappingURL=supabase.d.ts.map
package/dist/supabase.js DELETED
@@ -1,30 +0,0 @@
1
- import { createClient } from '@supabase/supabase-js';
2
- // Hardcoded Supabase credentials (safe for client-side use with RLS)
3
- const SUPABASE_URL = 'https://bcgnmvkgkbhbxzzflwdb.supabase.co';
4
- const SUPABASE_ANON_KEY = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6ImJjZ25tdmtna2JoYnh6emZsd2RiIiwicm9sZSI6ImFub24iLCJpYXQiOjE3MzQ3OTE4ODEsImV4cCI6MjA1MDM2Nzg4MX0.LqZYO8GGQfI-C9WCF_a2NTKqIrO1TDsPXU9LHRE8b0E';
5
- let supabaseClient = null;
6
- /**
7
- * Initialize Supabase client with hardcoded credentials
8
- */
9
- export function initializeSupabase() {
10
- if (!supabaseClient) {
11
- supabaseClient = createClient(SUPABASE_URL, SUPABASE_ANON_KEY);
12
- }
13
- return supabaseClient;
14
- }
15
- /**
16
- * Get existing Supabase client or initialize it
17
- */
18
- export function getSupabase() {
19
- if (!supabaseClient) {
20
- return initializeSupabase();
21
- }
22
- return supabaseClient;
23
- }
24
- /**
25
- * Reset Supabase client (useful for tests)
26
- */
27
- export function resetSupabase() {
28
- supabaseClient = null;
29
- }
30
- //# sourceMappingURL=supabase.js.map
@@ -1,9 +0,0 @@
1
- /**
2
- * Langctl ASCII Logo - Emerald Green
3
- */
4
- export declare function showLogo(): void;
5
- /**
6
- * Simple banner for quick commands
7
- */
8
- export declare function showBanner(title: string): void;
9
- //# sourceMappingURL=banner.d.ts.map
@@ -1,24 +0,0 @@
1
- import chalk from 'chalk';
2
- /**
3
- * Langctl ASCII Logo - Emerald Green
4
- */
5
- export function showLogo() {
6
- const logo = `
7
- ██╗ █████╗ ███╗ ██╗ ██████╗ ██████╗████████╗██╗
8
- ██║ ██╔══██╗████╗ ██║██╔════╝ ██╔════╝╚══██╔══╝██║
9
- ██║ ███████║██╔██╗ ██║██║ ███╗██║ ██║ ██║
10
- ██║ ██╔══██║██║╚██╗██║██║ ██║██║ ██║ ██║
11
- ███████╗██║ ██║██║ ╚████║╚██████╔╝╚██████╗ ██║ ███████╗
12
- ╚══════╝╚═╝ ╚═╝╚═╝ ╚═══╝ ╚═════╝ ╚═════╝ ╚═╝ ╚══════╝
13
- `;
14
- console.log(chalk.hex('#10b981')(logo)); // Emerald-500
15
- console.log(chalk.gray(' CLI-first translation management for developers\n'));
16
- }
17
- /**
18
- * Simple banner for quick commands
19
- */
20
- export function showBanner(title) {
21
- console.log(chalk.hex('#10b981').bold(`\n${title}`));
22
- console.log(chalk.gray('─'.repeat(title.length)));
23
- }
24
- //# sourceMappingURL=banner.js.map
@@ -1,5 +0,0 @@
1
- {
2
- "home.translation_mgmt": "Translation Management",
3
- "home.welcome_message": "Welcome Home",
4
- "new_item": "New Item"
5
- }
@@ -1,9 +0,0 @@
1
- <?xml version="1.0" encoding="utf-8"?>
2
- <resources>
3
- <!-- Hero text -->
4
- <string name="home.translation_mgmt">Translation Management</string>
5
- <!-- Homepage wlecome message -->
6
- <string name="home.welcome_message">Welcome Home</string>
7
- <!-- This is a new item -->
8
- <string name="new_item">New Item</string>
9
- </resources>
@@ -1,4 +0,0 @@
1
- {
2
- "home.translation_mgmt": "Gestion des traductions",
3
- "home.welcome_message": "bienvenue à la maison"
4
- }
@@ -1,7 +0,0 @@
1
- <?xml version="1.0" encoding="utf-8"?>
2
- <resources>
3
- <!-- Hero text -->
4
- <string name="home.translation_mgmt">Gestion des traductions</string>
5
- <!-- Homepage wlecome message -->
6
- <string name="home.welcome_message">bienvenue à la maison</string>
7
- </resources>
@@ -1,4 +0,0 @@
1
- {
2
- "home.translation_mgmt": "अनुवाद प्रबंधन",
3
- "home.welcome_message": "घर में आपका स्वागत है"
4
- }
@@ -1,7 +0,0 @@
1
- <?xml version="1.0" encoding="utf-8"?>
2
- <resources>
3
- <!-- Hero text -->
4
- <string name="home.translation_mgmt">अनुवाद प्रबंधन</string>
5
- <!-- Homepage wlecome message -->
6
- <string name="home.welcome_message">घर में आपका स्वागत है</string>
7
- </resources>
@@ -1,9 +0,0 @@
1
- /* Hero text */
2
- "home.translation_mgmt" = "Translation Management";
3
-
4
- /* Homepage wlecome message */
5
- "home.welcome_message" = "Welcome Home";
6
-
7
- /* This is a new item */
8
- "new_item" = "New Item";
9
-
@@ -1,6 +0,0 @@
1
- /* Hero text */
2
- "home.translation_mgmt" = "Gestion des traductions";
3
-
4
- /* Homepage wlecome message */
5
- "home.welcome_message" = "bienvenue à la maison";
6
-
@@ -1,6 +0,0 @@
1
- /* Hero text */
2
- "home.translation_mgmt" = "अनुवाद प्रबंधन";
3
-
4
- /* Homepage wlecome message */
5
- "home.welcome_message" = "घर में आपका स्वागत है";
6
-
@@ -1,6 +0,0 @@
1
- /* Hero text */
2
- "home.translation_mgmt" = "翻訳管理";
3
-
4
- /* Homepage wlecome message */
5
- "home.welcome_message" = "お家へようこそ";
6
-
@@ -1,4 +0,0 @@
1
- {
2
- "home.translation_mgmt": "翻訳管理",
3
- "home.welcome_message": "お家へようこそ"
4
- }
@@ -1,7 +0,0 @@
1
- <?xml version="1.0" encoding="utf-8"?>
2
- <resources>
3
- <!-- Hero text -->
4
- <string name="home.translation_mgmt">翻訳管理</string>
5
- <!-- Homepage wlecome message -->
6
- <string name="home.welcome_message">お家へようこそ</string>
7
- </resources>