@scoutello/i18n-magic 0.14.0 → 0.15.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.
package/README.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  Your CLI toolkit to help you with managing your translations in your project.
4
4
 
5
- This currently only works for JSON based translation systems, like: [Next-Translate](https://github.com/aralroca/next-translate)
5
+ This currently works for JSON based translation systems
6
6
 
7
7
  To use:
8
8
 
@@ -23,28 +23,31 @@ module.exports = {
23
23
  context:
24
24
  'This is a context which increases the quality of the translations by giving context to the LLM',
25
25
  // Optional configurations
26
- model: 'gemini-2.0-flash-lite', // or any OpenAI/Gemini model like 'gemini-2.0-flash'
26
+ model: 'gemini-2.0-flash-lite', // or any OpenAI/Gemini model like 'gpt-4.1-mini'
27
27
  OPENAI_API_KEY: '.', // Alternative to using .env file
28
28
  GEMINI_API_KEY: '', // Alternative to using .env file
29
- disableTranslation: false, // Set to true to skip automatic translations during the scan step. Useful if you want to sync the other languages during CI/CD for example.
29
+ disableTranslation: false, // Set to true to skip automatic translations during the scan step. Useful if you want to sync the other languages during CI/CD using sync.
30
30
  };
31
31
  ```
32
32
 
33
33
  You can also provide custom functions for `loadPath` and `savePath` to store translations in other systems like S3:
34
34
 
35
35
  ```js
36
- module.exports = {
37
- // Basic configurations
38
- globPatterns: ['./components/**/*.tsx', './pages/**/*.tsx', './lib/**/*.ts'],
39
- locales: ['en', 'de'],
40
- defaultLocale: 'de',
41
- defaultNamespace: 'common',
42
- namespaces: ['common', 'forms'],
36
+ const { S3Client, PutObjectCommand } = require("@aws-sdk/client-s3")
43
37
 
38
+ const s3Client = new S3Client({
39
+ region: process.env.S3_REGION,
40
+ credentials: {
41
+ accessKeyId: process.env.S3_ACCESS_KEY,
42
+ secretAccessKey: process.env.S3_SECRET_KEY,
43
+ },
44
+ })
45
+
46
+ module.exports = {
47
+ ...
44
48
  // Custom load function
45
49
  loadPath: async (locale, namespace) => {
46
50
  // Example: Load from S3
47
- const s3Client = new S3Client({ region: 'us-east-1' });
48
51
  const response = await s3Client.send(
49
52
  new GetObjectCommand({
50
53
  Bucket: 'my-translations-bucket',
@@ -58,7 +61,6 @@ module.exports = {
58
61
  // Custom save function
59
62
  savePath: async (locale, namespace, data) => {
60
63
  // Example: Save to S3
61
- const s3Client = new S3Client({ region: 'us-east-1' });
62
64
  await s3Client.send(
63
65
  new PutObjectCommand({
64
66
  Bucket: 'my-translations-bucket',
@@ -74,7 +76,7 @@ module.exports = {
74
76
  then just run:
75
77
 
76
78
  ```bash
77
- npx i18n-magic [command]
79
+ npx @scoutello/i18n-magic [command]
78
80
  ```
79
81
 
80
82
  `scan`
@@ -85,10 +87,14 @@ Scan for missing translations, get prompted for each, translate it to the other
85
87
 
86
88
  Replace a translation based on the key, and translate it to the other locales and save it to the JSON file.
87
89
 
90
+ Optional arguments:
91
+
92
+ - `-k, --key <key>`: Specify the translation key to replace directly.
93
+
88
94
  `check-missing`
89
95
 
90
96
  Checks if there are any missing translations. Useful for CI/CD or for a husky hook.
91
97
 
92
98
  `sync`
93
99
 
94
- Sync the translations from the default locale to the other locales. Useful for a CI/CD pipeline or husky hook.
100
+ Sync the translations from the default locale to the other locales. Useful for a CI/CD pipeline or husky hook. Should be used together with `disableTranslation: true`
@@ -1,2 +1,2 @@
1
1
  import type { Configuration } from "../lib/types";
2
- export declare const replaceTranslation: (config: Configuration) => Promise<void>;
2
+ export declare const replaceTranslation: (config: Configuration, key?: string) => Promise<void>;
@@ -995,7 +995,7 @@ var getKeyToReplace = /*#__PURE__*/function () {
995
995
  };
996
996
  }();
997
997
  var replaceTranslation = /*#__PURE__*/function () {
998
- var _ref2 = /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee2(config) {
998
+ var _ref2 = /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee2(config, key) {
999
999
  var loadPath, savePath, defaultLocale, defaultNamespace, locales, context, openai, keys, keyToReplace, newTranslation, _iterator, _step, locale, newValue, _object, translation, existingKeys;
1000
1000
  return _regeneratorRuntime().wrap(function _callee2$(_context2) {
1001
1001
  while (1) switch (_context2.prev = _context2.next) {
@@ -1005,32 +1005,55 @@ var replaceTranslation = /*#__PURE__*/function () {
1005
1005
  return loadLocalesFile(config.loadPath, config.defaultLocale, config.defaultNamespace);
1006
1006
  case 3:
1007
1007
  keys = _context2.sent;
1008
- _context2.next = 6;
1008
+ if (!key) {
1009
+ _context2.next = 16;
1010
+ break;
1011
+ }
1012
+ if (!keys[key]) {
1013
+ _context2.next = 10;
1014
+ break;
1015
+ }
1016
+ keyToReplace = key;
1017
+ console.log("The key \"" + keyToReplace + "\" exists.");
1018
+ _context2.next = 14;
1019
+ break;
1020
+ case 10:
1021
+ console.log("The key \"" + key + "\" does not exist.");
1022
+ _context2.next = 13;
1009
1023
  return getKeyToReplace(keys);
1010
- case 6:
1024
+ case 13:
1025
+ keyToReplace = _context2.sent;
1026
+ case 14:
1027
+ _context2.next = 19;
1028
+ break;
1029
+ case 16:
1030
+ _context2.next = 18;
1031
+ return getKeyToReplace(keys);
1032
+ case 18:
1011
1033
  keyToReplace = _context2.sent;
1034
+ case 19:
1012
1035
  console.log("The current translation in " + defaultLocale + " for \"" + keyToReplace + "\" is \"" + keys[keyToReplace] + "\".");
1013
- _context2.next = 10;
1036
+ _context2.next = 22;
1014
1037
  return getTextInput("Enter the new translation: ");
1015
- case 10:
1038
+ case 22:
1016
1039
  newTranslation = _context2.sent;
1017
1040
  _iterator = _createForOfIteratorHelperLoose(locales);
1018
- case 12:
1041
+ case 24:
1019
1042
  if ((_step = _iterator()).done) {
1020
- _context2.next = 31;
1043
+ _context2.next = 43;
1021
1044
  break;
1022
1045
  }
1023
1046
  locale = _step.value;
1024
1047
  newValue = "";
1025
1048
  if (!(locale === defaultLocale)) {
1026
- _context2.next = 19;
1049
+ _context2.next = 31;
1027
1050
  break;
1028
1051
  }
1029
1052
  newValue = newTranslation;
1030
- _context2.next = 23;
1053
+ _context2.next = 35;
1031
1054
  break;
1032
- case 19:
1033
- _context2.next = 21;
1055
+ case 31:
1056
+ _context2.next = 33;
1034
1057
  return translateKey({
1035
1058
  context: context,
1036
1059
  inputLanguage: defaultLocale,
@@ -1039,27 +1062,27 @@ var replaceTranslation = /*#__PURE__*/function () {
1039
1062
  openai: openai,
1040
1063
  model: config.model
1041
1064
  });
1042
- case 21:
1065
+ case 33:
1043
1066
  translation = _context2.sent;
1044
1067
  newValue = translation[keyToReplace];
1045
- case 23:
1046
- _context2.next = 25;
1068
+ case 35:
1069
+ _context2.next = 37;
1047
1070
  return loadLocalesFile(loadPath, locale, defaultNamespace);
1048
- case 25:
1071
+ case 37:
1049
1072
  existingKeys = _context2.sent;
1050
1073
  existingKeys[keyToReplace] = newValue;
1051
1074
  writeLocalesFile(savePath, locale, defaultNamespace, existingKeys);
1052
1075
  console.log("The new translation for \"" + keyToReplace + "\" in " + locale + " is \"" + newValue + "\".");
1053
- case 29:
1054
- _context2.next = 12;
1076
+ case 41:
1077
+ _context2.next = 24;
1055
1078
  break;
1056
- case 31:
1079
+ case 43:
1057
1080
  case "end":
1058
1081
  return _context2.stop();
1059
1082
  }
1060
1083
  }, _callee2);
1061
1084
  }));
1062
- return function replaceTranslation(_x2) {
1085
+ return function replaceTranslation(_x2, _x3) {
1063
1086
  return _ref2.apply(this, arguments);
1064
1087
  };
1065
1088
  }();
@@ -1363,44 +1386,60 @@ var commands = [{
1363
1386
  }];
1364
1387
  var _loop = function _loop() {
1365
1388
  var command = _commands[_i];
1366
- program.command(command.name).description(command.description).action( /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee() {
1367
- var _config$model;
1368
- var res, config, isGemini, openaiKey, geminiKey, key, keyType, openai;
1369
- return _regeneratorRuntime().wrap(function _callee$(_context) {
1370
- while (1) switch (_context.prev = _context.next) {
1371
- case 0:
1372
- res = dotenv.config({
1373
- path: program.opts().env || ".env"
1374
- });
1375
- _context.next = 3;
1376
- return loadConfig({
1377
- configPath: program.opts().config
1378
- });
1379
- case 3:
1380
- config = _context.sent;
1381
- isGemini = (_config$model = config.model) == null ? void 0 : _config$model.includes("gemini"); // Get API key from environment or config
1382
- openaiKey = res.parsed.OPENAI_API_KEY || config.OPENAI_API_KEY;
1383
- geminiKey = res.parsed.GEMINI_API_KEY || config.GEMINI_API_KEY; // Select appropriate key based on model type
1384
- key = isGemini ? geminiKey : openaiKey;
1385
- if (!key) {
1386
- keyType = isGemini ? "GEMINI_API_KEY" : "OPENAI_API_KEY";
1387
- console.error("Please provide a" + (isGemini ? " Gemini" : "n OpenAI") + " API key in your .env file or config, called " + keyType + ".");
1388
- process.exit(1);
1389
- }
1390
- openai = new OpenAI(_extends({
1391
- apiKey: key
1392
- }, isGemini && {
1393
- baseURL: "https://generativelanguage.googleapis.com/v1beta/openai/"
1394
- }));
1395
- command.action(_extends({}, config, {
1396
- openai: openai
1397
- }));
1398
- case 11:
1399
- case "end":
1400
- return _context.stop();
1401
- }
1402
- }, _callee);
1403
- })));
1389
+ var cmd = program.command(command.name).description(command.description);
1390
+ // Add key option to replace command
1391
+ if (command.name === "replace") {
1392
+ cmd.option("-k, --key <key>", "translation key to replace");
1393
+ }
1394
+ cmd.action( /*#__PURE__*/function () {
1395
+ var _ref = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee(options) {
1396
+ var _config$model;
1397
+ var res, config, isGemini, openaiKey, geminiKey, key, keyType, openai;
1398
+ return _regeneratorRuntime().wrap(function _callee$(_context) {
1399
+ while (1) switch (_context.prev = _context.next) {
1400
+ case 0:
1401
+ res = dotenv.config({
1402
+ path: program.opts().env || ".env"
1403
+ });
1404
+ _context.next = 3;
1405
+ return loadConfig({
1406
+ configPath: program.opts().config
1407
+ });
1408
+ case 3:
1409
+ config = _context.sent;
1410
+ isGemini = (_config$model = config.model) == null ? void 0 : _config$model.includes("gemini"); // Get API key from environment or config
1411
+ openaiKey = res.parsed.OPENAI_API_KEY || config.OPENAI_API_KEY;
1412
+ geminiKey = res.parsed.GEMINI_API_KEY || config.GEMINI_API_KEY; // Select appropriate key based on model type
1413
+ key = isGemini ? geminiKey : openaiKey;
1414
+ if (!key) {
1415
+ keyType = isGemini ? "GEMINI_API_KEY" : "OPENAI_API_KEY";
1416
+ console.error("Please provide a" + (isGemini ? " Gemini" : "n OpenAI") + " API key in your .env file or config, called " + keyType + ".");
1417
+ process.exit(1);
1418
+ }
1419
+ openai = new OpenAI(_extends({
1420
+ apiKey: key
1421
+ }, isGemini && {
1422
+ baseURL: "https://generativelanguage.googleapis.com/v1beta/openai/"
1423
+ }));
1424
+ if (command.name === "replace" && options.key) {
1425
+ command.action(_extends({}, config, {
1426
+ openai: openai
1427
+ }), options.key);
1428
+ } else {
1429
+ command.action(_extends({}, config, {
1430
+ openai: openai
1431
+ }));
1432
+ }
1433
+ case 11:
1434
+ case "end":
1435
+ return _context.stop();
1436
+ }
1437
+ }, _callee);
1438
+ }));
1439
+ return function (_x) {
1440
+ return _ref.apply(this, arguments);
1441
+ };
1442
+ }());
1404
1443
  };
1405
1444
  for (var _i = 0, _commands = commands; _i < _commands.length; _i++) {
1406
1445
  _loop();