@localheroai/cli 0.0.72 → 0.0.74-rc.1

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.
@@ -0,0 +1,68 @@
1
+ import path from 'path';
2
+ import { extractLocaleFromPath } from './files.js';
3
+ import { parsePoFile } from './po-utils.js';
4
+ const LANGUAGE_NAMES = new Intl.DisplayNames(['en'], { type: 'language', fallback: 'none' });
5
+ const GETTEXT_SOURCE_SHARE = 0.9;
6
+ // "ui.json" or "db.yml" match the locale pattern but name no language.
7
+ function isLanguage(code) {
8
+ try {
9
+ return LANGUAGE_NAMES.of(code.replace('_', '-')) !== undefined;
10
+ }
11
+ catch {
12
+ return false;
13
+ }
14
+ }
15
+ // The default locale pattern misses flat gettext names (sv.po) and script
16
+ // tags (zh-Hant), so the folder and file names are tried as languages too.
17
+ function localeOf(filePath) {
18
+ const candidates = [path.basename(path.dirname(filePath)), path.basename(filePath, path.extname(filePath))];
19
+ try {
20
+ candidates.unshift(extractLocaleFromPath(filePath));
21
+ }
22
+ catch {
23
+ // no locale in the conventional places
24
+ }
25
+ return candidates.find(isLanguage) ?? null;
26
+ }
27
+ export function detectLocalesFromPaths(filePaths) {
28
+ const locales = {};
29
+ const templates = [];
30
+ const unrecognized = [];
31
+ for (const filePath of filePaths) {
32
+ if (path.extname(filePath) === '.pot') {
33
+ templates.push(filePath);
34
+ continue;
35
+ }
36
+ const locale = localeOf(filePath);
37
+ if (!locale) {
38
+ unrecognized.push(filePath);
39
+ continue;
40
+ }
41
+ (locales[locale] ??= []).push(filePath);
42
+ }
43
+ return { locales, templates, unrecognized };
44
+ }
45
+ // A gettext source catalog leaves msgstr empty or repeats the msgid.
46
+ export function looksLikeGettextSource(content) {
47
+ const { entries } = parsePoFile(content);
48
+ if (entries.length === 0)
49
+ return false;
50
+ const untranslated = entries.filter((entry) => entry.msgstr.every((value) => value === '' || value === entry.msgid || value === entry.msgid_plural));
51
+ return untranslated.length / entries.length >= GETTEXT_SOURCE_SHARE;
52
+ }
53
+ export function chooseSourceLocale(input) {
54
+ const { explicit, locales, keyCounts, gettextSources, hasTemplate } = input;
55
+ if (explicit)
56
+ return { locale: explicit, reason: 'option' };
57
+ if (gettextSources.length === 1)
58
+ return { locale: gettextSources[0], reason: 'gettext' };
59
+ if (hasTemplate)
60
+ return { locale: 'en', reason: 'template' };
61
+ if (locales.length === 0)
62
+ return null;
63
+ if (locales.includes('en'))
64
+ return { locale: 'en', reason: 'en' };
65
+ const [mostKeys] = [...locales].sort((a, b) => (keyCounts[b] ?? 0) - (keyCounts[a] ?? 0));
66
+ return { locale: mostKeys, reason: 'guessed' };
67
+ }
68
+ //# sourceMappingURL=locale-detection.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"locale-detection.js","sourceRoot":"","sources":["../../src/utils/locale-detection.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,88 @@
1
+ /**
2
+ * Alternation order matters: `%%` first so an escaped percent cannot start a directive, and longer
3
+ * forms (`{{name}}`, `%<name>s`) before the shorter ones they contain, or both are miscounted.
4
+ * A `%` right after a digit ("5%discount") is a literal percent sign, not a directive.
5
+ */
6
+ const PLACEHOLDER_PATTERN = /(%%)|\{\{\s*-?\s*([\w.]+)\s*(?:,[^}]*)?\}\}|%<([\w.]+)>[sdf]|%\{([\w.]+)\}|%\(([\w.]+)\)[sdf]|%(\d+)\$([sdfiugx])|(?<!\d)%([sdfiugx])|\{([\w.]+)\}/g;
7
+ /**
8
+ * Branch text in `{count, plural, one {# item} ...}` is not a placeholder, but a one-word
9
+ * branch ({He}, {Han}) would read as one, so each complex argument is reduced to `{count}`.
10
+ */
11
+ const ICU_COMPLEX_START = /\{\s*([\w.]+)\s*,\s*(plural|select|selectordinal)\s*,/g;
12
+ const MAX_ICU_REDUCTIONS = 20;
13
+ export function reduceIcuComplexArguments(text) {
14
+ let result = text;
15
+ for (let pass = 0; pass < MAX_ICU_REDUCTIONS; pass++) {
16
+ ICU_COMPLEX_START.lastIndex = 0;
17
+ const match = ICU_COMPLEX_START.exec(result);
18
+ if (!match)
19
+ break;
20
+ const end = matchingBrace(result, match.index);
21
+ if (end === -1)
22
+ break;
23
+ result = `${result.slice(0, match.index)}{${match[1]}}${result.slice(end + 1)}`;
24
+ }
25
+ return result;
26
+ }
27
+ function matchingBrace(text, start) {
28
+ let depth = 0;
29
+ for (let i = start; i < text.length; i++) {
30
+ if (text[i] === '{')
31
+ depth++;
32
+ else if (text[i] === '}' && --depth === 0)
33
+ return i;
34
+ }
35
+ return -1;
36
+ }
37
+ export function extractPlaceholders(text) {
38
+ if (typeof text !== 'string')
39
+ return [];
40
+ const found = [];
41
+ for (const match of reduceIcuComplexArguments(text).matchAll(PLACEHOLDER_PATTERN)) {
42
+ const [full, escaped, i18next, railsTyped, rails, python, , positionalType, printf, icu] = match;
43
+ if (escaped)
44
+ continue;
45
+ const name = i18next ?? railsTyped ?? rails ?? python ?? positionalType ?? printf ?? icu;
46
+ found.push({ kind: classify(full), name });
47
+ }
48
+ return found;
49
+ }
50
+ function classify(full) {
51
+ if (full.startsWith('{{'))
52
+ return 'i18next';
53
+ if (full.startsWith('{'))
54
+ return 'icu';
55
+ if (full.startsWith('%<'))
56
+ return 'rails-typed';
57
+ if (full.startsWith('%{'))
58
+ return 'rails';
59
+ if (full.startsWith('%('))
60
+ return 'python';
61
+ if (/^%\d/.test(full))
62
+ return 'positional';
63
+ return 'printf';
64
+ }
65
+ /**
66
+ * gettext lets translators reorder arguments ("%s: %s" as "%2$s: %1$s"), so a positional
67
+ * directive compares as a plain printf one of the same conversion type.
68
+ */
69
+ function token(placeholder) {
70
+ if (placeholder.kind === 'positional')
71
+ return `printf:${placeholder.name}`;
72
+ return `${placeholder.kind}:${placeholder.name}`;
73
+ }
74
+ // Rails date.formats/time.formats are strftime, where %d is a day, not a number.
75
+ // Only directives printf never uses mark a string as a date format.
76
+ const STRFTIME_DIRECTIVE = /%[-_0^#]?[aAbBCDFGhHIjklLmMnNpPrRSTUVwWXyYzZ]/;
77
+ export function isStrftimeFormat(text) {
78
+ return STRFTIME_DIRECTIVE.test(text.replace(/%%/g, ''));
79
+ }
80
+ export function placeholderMultiset(text) {
81
+ const counts = new Map();
82
+ for (const placeholder of extractPlaceholders(text)) {
83
+ const key = token(placeholder);
84
+ counts.set(key, (counts.get(key) ?? 0) + 1);
85
+ }
86
+ return counts;
87
+ }
88
+ //# sourceMappingURL=placeholders.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"placeholders.js","sourceRoot":"","sources":["../../src/utils/placeholders.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,324 @@
1
+ import { promises as fs } from 'fs';
2
+ import { findFirstExistingPath, findFirstGettextCatalogPath, getDirectoryContents } from './files.js';
3
+ export const PROJECT_TYPES = {
4
+ django: {
5
+ directIndicators: ['manage.py'],
6
+ defaults: {
7
+ translationPath: 'translations/',
8
+ // Django deletes its .pot unless makemessages runs with --keep-pot, and a stock
9
+ // Django app has no source-locale catalog, so the kept .pot is the source file.
10
+ filePattern: '**/*.{po,pot}',
11
+ ignorePaths: ['**/sources/**'],
12
+ workflow: 'django',
13
+ extractor: 'django',
14
+ sourceCodePaths: ['**/*.py', '**/*.html', '**/*.txt']
15
+ },
16
+ commonPaths: [
17
+ 'locale',
18
+ 'locales',
19
+ 'translations'
20
+ ]
21
+ },
22
+ rails: {
23
+ directIndicators: ['config/application.rb', 'Gemfile'],
24
+ defaults: {
25
+ translationPath: 'config/locales/',
26
+ filePattern: '**/*.{yml,yaml}'
27
+ },
28
+ commonPaths: [
29
+ 'config/locales'
30
+ ]
31
+ },
32
+ phoenix: {
33
+ directIndicators: ['mix.exs'],
34
+ defaults: {
35
+ translationPath: 'priv/gettext/',
36
+ filePattern: '**/*.po',
37
+ extractor: 'phoenix',
38
+ // Umbrella projects keep code in apps/<app>/lib, so both shapes are watched.
39
+ sourceCodePaths: [
40
+ 'lib/**/*.ex', 'lib/**/*.exs', 'lib/**/*.eex', 'lib/**/*.heex', 'lib/**/*.leex',
41
+ 'apps/*/lib/**/*.ex', 'apps/*/lib/**/*.exs', 'apps/*/lib/**/*.eex',
42
+ 'apps/*/lib/**/*.heex', 'apps/*/lib/**/*.leex'
43
+ ]
44
+ },
45
+ commonPaths: [
46
+ 'priv/gettext',
47
+ 'apps/*/priv/gettext'
48
+ ]
49
+ },
50
+ nextIntl: {
51
+ directIndicators: [],
52
+ packageCheck: {
53
+ requires: ['next', 'next-intl']
54
+ },
55
+ defaults: {
56
+ translationPath: 'messages/',
57
+ filePattern: '**/*.json'
58
+ },
59
+ commonPaths: [
60
+ 'messages',
61
+ 'src/messages',
62
+ 'app/messages'
63
+ ]
64
+ },
65
+ nextjs: {
66
+ directIndicators: ['next.config.js', 'next.config.mjs'],
67
+ packageCheck: {
68
+ requires: ['next'],
69
+ oneOf: ['next-i18next', 'next-translate']
70
+ },
71
+ defaults: {
72
+ translationPath: 'public/locales/',
73
+ filePattern: '**/*.json'
74
+ },
75
+ commonPaths: [
76
+ 'public/locales',
77
+ 'src/locales',
78
+ 'locales'
79
+ ]
80
+ },
81
+ vueI18n: {
82
+ directIndicators: ['vue.config.js'],
83
+ packageCheck: {
84
+ oneOf: ['vue-i18n', '@nuxtjs/i18n']
85
+ },
86
+ defaults: {
87
+ translationPath: 'src/locales/',
88
+ filePattern: '**/*.json'
89
+ },
90
+ commonPaths: [
91
+ 'src/locales',
92
+ 'src/i18n',
93
+ 'locales',
94
+ 'i18n'
95
+ ]
96
+ },
97
+ i18next: {
98
+ directIndicators: ['i18next.config.js', 'i18n.js', 'i18n/index.js'],
99
+ packageCheck: {
100
+ requires: ['i18next']
101
+ },
102
+ defaults: {
103
+ translationPath: 'public/locales/',
104
+ filePattern: '**/*.json'
105
+ },
106
+ commonPaths: [
107
+ 'public/locales',
108
+ 'src/locales',
109
+ 'locales',
110
+ 'src/i18n',
111
+ 'i18n'
112
+ ]
113
+ },
114
+ lingui: {
115
+ directIndicators: [
116
+ 'lingui.config.js',
117
+ 'lingui.config.ts',
118
+ 'lingui.config.cjs',
119
+ 'lingui.config.mjs',
120
+ '.linguirc',
121
+ '.linguirc.json'
122
+ ],
123
+ packageCheck: {
124
+ oneOf: ['@lingui/cli', '@lingui/core', '@lingui/react', '@lingui/macro']
125
+ },
126
+ defaults: {
127
+ translationPath: 'src/locales/',
128
+ filePattern: '**/*.po',
129
+ sourceCodePaths: ['src/**/*.ts', 'src/**/*.tsx', 'src/**/*.js', 'src/**/*.jsx']
130
+ },
131
+ commonPaths: [
132
+ 'src/locales',
133
+ 'locales',
134
+ 'locale'
135
+ ]
136
+ },
137
+ reactIntl: {
138
+ directIndicators: ['.babelrc'],
139
+ packageCheck: {
140
+ requires: ['react-intl']
141
+ },
142
+ defaults: {
143
+ translationPath: 'src/translations/',
144
+ filePattern: '**/*.json'
145
+ },
146
+ commonPaths: [
147
+ 'src/i18n',
148
+ 'src/translations',
149
+ 'src/lang',
150
+ 'src/locales',
151
+ 'translations',
152
+ 'locales'
153
+ ]
154
+ },
155
+ gatsbyReact: {
156
+ directIndicators: ['gatsby-config.js'],
157
+ packageCheck: {
158
+ requires: ['gatsby'],
159
+ oneOf: ['gatsby-plugin-intl', 'gatsby-plugin-i18n']
160
+ },
161
+ defaults: {
162
+ translationPath: 'src/data/i18n/',
163
+ filePattern: '**/*.json'
164
+ },
165
+ commonPaths: [
166
+ 'src/data/i18n',
167
+ 'src/i18n',
168
+ 'src/locales',
169
+ 'locales'
170
+ ]
171
+ },
172
+ react: {
173
+ directIndicators: ['src/App.js', 'src/App.jsx', 'src/index.js', 'src/index.jsx'],
174
+ packageCheck: {
175
+ requires: ['react']
176
+ },
177
+ defaults: {
178
+ translationPath: 'src/locales/',
179
+ filePattern: '**/*.{json,yml}'
180
+ },
181
+ commonPaths: [
182
+ 'src/locales',
183
+ 'public/locales',
184
+ 'src/i18n',
185
+ 'src/translations',
186
+ 'src/lang',
187
+ 'assets/i18n',
188
+ 'locales'
189
+ ]
190
+ },
191
+ generic: {
192
+ directIndicators: [],
193
+ defaults: {
194
+ translationPath: 'locales/',
195
+ filePattern: '**/*.{json,yml,yaml,po}'
196
+ },
197
+ commonPaths: [
198
+ 'src/locales',
199
+ 'public/locales',
200
+ 'config/locales',
201
+ 'locales',
202
+ 'messages',
203
+ 'src/messages',
204
+ 'src/i18n',
205
+ 'app/i18n',
206
+ 'src/translations',
207
+ 'src/lang',
208
+ 'assets/i18n',
209
+ 'i18n',
210
+ 'translations',
211
+ 'lang'
212
+ ]
213
+ }
214
+ };
215
+ async function checkPackageJson() {
216
+ try {
217
+ const content = await fs.readFile('package.json', 'utf8');
218
+ const pkg = JSON.parse(content);
219
+ return { ...pkg.dependencies, ...pkg.devDependencies };
220
+ }
221
+ catch {
222
+ return null;
223
+ }
224
+ }
225
+ async function detectFramework(config) {
226
+ for (const indicator of config.directIndicators || []) {
227
+ try {
228
+ const stats = await fs.stat(indicator);
229
+ if (stats.isFile())
230
+ return true;
231
+ }
232
+ catch {
233
+ continue;
234
+ }
235
+ }
236
+ if (config.packageCheck) {
237
+ const deps = await checkPackageJson();
238
+ if (deps) {
239
+ const { requires = [], oneOf = [] } = config.packageCheck;
240
+ if (requires.length && !requires.every(pkg => deps[pkg])) {
241
+ return false;
242
+ }
243
+ if (oneOf.length && !oneOf.some(pkg => deps[pkg])) {
244
+ return false;
245
+ }
246
+ return true;
247
+ }
248
+ }
249
+ return false;
250
+ }
251
+ export function buildFilePatternFromContents(contents) {
252
+ const formats = [];
253
+ if (contents.jsonFiles.length > 0)
254
+ formats.push('json');
255
+ if (contents.yamlFiles.length > 0)
256
+ formats.push('yml', 'yaml');
257
+ if (contents.poFiles.length > 0)
258
+ formats.push('po');
259
+ if (formats.length === 0) {
260
+ return '**/*.{json,yml,yaml,po}';
261
+ }
262
+ if (formats.length === 1 && formats[0] !== 'yml') {
263
+ return `**/*.${formats[0]}`;
264
+ }
265
+ return `**/*.{${formats.join(',')}}`;
266
+ }
267
+ export async function detectProjectType() {
268
+ for (const [type, config] of Object.entries(PROJECT_TYPES)) {
269
+ if (!config.directIndicators?.length && !config.packageCheck)
270
+ continue;
271
+ const isFramework = await detectFramework(config);
272
+ if (!isFramework)
273
+ continue;
274
+ if (config.commonPaths) {
275
+ // For gettext projects the catalog check is authoritative: falling back to a
276
+ // name-only match would re-propose the directories it just rejected (a Django
277
+ // app named locales/, a Python package named translations/). When it finds
278
+ // nothing, the framework default is the better answer than a wrong directory.
279
+ const translationPath = config.defaults.extractor
280
+ ? await findFirstGettextCatalogPath(config.commonPaths)
281
+ : await findFirstExistingPath(config.commonPaths);
282
+ if (translationPath) {
283
+ return {
284
+ type,
285
+ defaults: {
286
+ ...config.defaults,
287
+ translationPath: `${translationPath}/`,
288
+ commonPaths: config.commonPaths
289
+ }
290
+ };
291
+ }
292
+ }
293
+ return {
294
+ type,
295
+ defaults: {
296
+ ...config.defaults,
297
+ commonPaths: config.commonPaths
298
+ }
299
+ };
300
+ }
301
+ const commonPaths = PROJECT_TYPES.generic.commonPaths || [];
302
+ const translationPath = await findFirstExistingPath(commonPaths);
303
+ if (translationPath) {
304
+ const contents = await getDirectoryContents(translationPath);
305
+ if (contents) {
306
+ return {
307
+ type: 'detected',
308
+ defaults: {
309
+ commonPaths: commonPaths,
310
+ translationPath: `${translationPath}/`,
311
+ filePattern: buildFilePatternFromContents(contents)
312
+ }
313
+ };
314
+ }
315
+ }
316
+ return {
317
+ type: 'generic',
318
+ defaults: {
319
+ ...PROJECT_TYPES.generic.defaults,
320
+ commonPaths: commonPaths
321
+ }
322
+ };
323
+ }
324
+ //# sourceMappingURL=project-detection.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"project-detection.js","sourceRoot":"","sources":["../../src/utils/project-detection.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,28 @@
1
+ import { parse, parseDocument, stringify, isMap, isScalar } from 'yaml';
2
+ function display(node) {
3
+ return isScalar(node) ? String(node.value) : JSON.stringify(node?.toJSON?.() ?? node);
4
+ }
5
+ // Rails loads a mapping with a repeated key and keeps the last value; the
6
+ // earlier one is dead text. Keys are returned without the locale wrapper.
7
+ export function findDuplicateYamlKeys(content, locale) {
8
+ const values = new Map();
9
+ const walk = (node, prefix) => {
10
+ if (!isMap(node))
11
+ return;
12
+ for (const pair of node.items) {
13
+ const name = String(isScalar(pair.key) ? pair.key.value : pair.key);
14
+ const key = prefix ? `${prefix}.${name}` : name;
15
+ values.set(key, [...(values.get(key) ?? []), display(pair.value)]);
16
+ walk(pair.value, key);
17
+ }
18
+ };
19
+ walk(parseDocument(content, { uniqueKeys: false }).contents, '');
20
+ const wrapper = `${locale}.`;
21
+ return [...values]
22
+ .filter(([, found]) => found.length > 1)
23
+ .map(([key, found]) => ({ key: key.startsWith(wrapper) ? key.slice(wrapper.length) : key, values: found }));
24
+ }
25
+ export function dedupeYaml(content) {
26
+ return stringify(parse(content, { uniqueKeys: false }));
27
+ }
28
+ //# sourceMappingURL=yaml-duplicates.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"yaml-duplicates.js","sourceRoot":"","sources":["../../src/utils/yaml-duplicates.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,aAAa,EAAE,SAAS,EAAE,KAAK,EAAE,QAAQ,EAAa,MAAM,MAAM,CAAC;AAOnF,SAAS,OAAO,CAAC,IAAa;IAC5B,OAAO,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAE,IAAoB,EAAE,MAAM,EAAE,EAAE,IAAI,IAAI,CAAC,CAAC;AACzG,CAAC;AAED,0EAA0E;AAC1E,0EAA0E;AAC1E,MAAM,UAAU,qBAAqB,CAAC,OAAe,EAAE,MAAc;IACnE,MAAM,MAAM,GAAG,IAAI,GAAG,EAAoB,CAAC;IAE3C,MAAM,IAAI,GAAG,CAAC,IAAa,EAAE,MAAc,EAAQ,EAAE;QACnD,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC;YAAE,OAAO;QACzB,KAAK,MAAM,IAAI,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;YAC9B,MAAM,IAAI,GAAG,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;YACpE,MAAM,GAAG,GAAG,MAAM,CAAC,CAAC,CAAC,GAAG,MAAM,IAAI,IAAI,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;YAChD,MAAM,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,EAAE,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;YACnE,IAAI,CAAC,IAAI,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;QACxB,CAAC;IACH,CAAC,CAAC;IACF,IAAI,CAAC,aAAa,CAAC,OAAO,EAAE,EAAE,UAAU,EAAE,KAAK,EAAE,CAAC,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC;IAEjE,MAAM,OAAO,GAAG,GAAG,MAAM,GAAG,CAAC;IAC7B,OAAO,CAAC,GAAG,MAAM,CAAC;SACf,MAAM,CAAC,CAAC,CAAC,EAAE,KAAK,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC;SACvC,GAAG,CAAC,CAAC,CAAC,GAAG,EAAE,KAAK,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,GAAG,EAAE,GAAG,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC;AAChH,CAAC;AAED,MAAM,UAAU,UAAU,CAAC,OAAe;IACxC,OAAO,SAAS,CAAC,KAAK,CAAC,OAAO,EAAE,EAAE,UAAU,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC;AAC1D,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@localheroai/cli",
3
- "version": "0.0.72",
3
+ "version": "0.0.74-rc.1",
4
4
  "description": "CLI tool for managing translations with LocalHero.ai",
5
5
  "homepage": "https://localhero.ai",
6
6
  "repository": {