generaltranslation 1.2.15 → 1.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.
package/codes/codes.js CHANGED
@@ -1,15 +1,43 @@
1
1
  // ----- IMPORTS ----- //
2
2
 
3
+ // Import modules for mapping ISO 639 codes to language names and vice versa
3
4
  const CodeToLanguage = require('./639-1/CodeToLanguage.js');
4
5
  const LanguageToCode = require('./639-1/LanguageToCode.js');
5
6
 
6
- // only for languages which have no two-letter code
7
+ // Import modules for mapping ISO 639-3 codes (for languages without two-letter codes)
7
8
  const CodeToLanguageTriletter = require('./639-3/CodeToLanguageTriletter.js');
8
9
  const LanguageToCodeTriletter = require('./639-3/LanguageToCodeTriletter.js');
9
10
 
10
- // ----- LANGUAGE CODES ----- //
11
+ // Import module for mapping ISO 15924 script codes to script names
12
+ const ScriptToCode = require('./15924/ScriptToCode.js');
13
+ const CodeToScript = require('./15924/CodeToScript.js');
11
14
 
12
- // Returns the name of a language from an ISO 639 code or an array of codes
15
+ // Import module for mapping ISO 3166 region codes to region names
16
+ const RegionToCode = require('./3166/RegionToCode.js');
17
+ const CodeToRegion = require('./3166/CodeToRegion.js');
18
+
19
+ // Import predefined common regions
20
+ const Predefined = require('./predefined/Predefined.js')
21
+
22
+ // ----- FORMATTING HELPER FUNCTIONS ----- //
23
+
24
+ /**
25
+ * Capitalizes the first letter of a code and converts the rest to lowercase.
26
+ * @param {string} code - The code to capitalize.
27
+ * @returns {string} The capitalized code.
28
+ */
29
+ const _capitalize = (code) => {
30
+ if (code.length === 0) return code;
31
+ return code.charAt(0).toUpperCase() + code.slice(1).toLowerCase();
32
+ }
33
+
34
+ // ----- MAPPING FUNCTIONS ----- //
35
+
36
+ /**
37
+ * Returns the name of a language from an ISO 639 code.
38
+ * @param {string} code - The ISO 639 code.
39
+ * @returns {string} The language name.
40
+ */
13
41
  const _mapCodeToLanguage = code => {
14
42
  code = code?.toLowerCase();
15
43
  if (code?.length === 2) {
@@ -17,27 +45,248 @@ const _mapCodeToLanguage = code => {
17
45
  }
18
46
  if (code?.length === 3) {
19
47
  return CodeToLanguageTriletter[code];
20
- } else {
21
- return CodeToLanguage[code?.slice(0, 2)] || '';
22
48
  }
49
+ return '';
23
50
  }
24
51
 
25
- const _getLanguageName = codes => {
26
- return Array.isArray(codes) ? codes.map(_mapCodeToLanguage) : _mapCodeToLanguage(codes);
52
+ /**
53
+ * Returns an ISO 639 code from a language name.
54
+ * Preferentially returns two-letter codes.
55
+ * @param {string} language - The language name.
56
+ * @returns {string} The ISO 639 code.
57
+ */
58
+ const _mapLanguageToCode = language => {
59
+ language = language?.toLowerCase();
60
+ return LanguageToCode[language] || LanguageToCodeTriletter[language] || '';
27
61
  }
28
62
 
29
- // Returns an ISO 639 code from a language name or an array of language names
30
- // Preferentially returns two-letter codes
31
- const _mapLanguageToCode = language => {
32
- const lowerCaseLanguage = language?.toLowerCase();
33
- return LanguageToCode[lowerCaseLanguage] || LanguageToCodeTriletter[lowerCaseLanguage] || '';
63
+ /**
64
+ * Returns the name of a script from an ISO 15924 code.
65
+ * @param {string} code - The ISO 15924 code.
66
+ * @returns {string} The script name.
67
+ */
68
+ const _mapCodeToScript = code => {
69
+ code = _capitalize(code);
70
+ return CodeToScript[code] || '';
71
+ }
72
+
73
+ /**
74
+ * Returns an ISO 15924 code from a script name.
75
+ * @param {string} script - The script name.
76
+ * @returns {string} The ISO 15924 code.
77
+ */
78
+ const _mapScriptToCode = script => {
79
+ script = script?.toLowerCase();
80
+ return ScriptToCode[script] || '';
81
+ }
82
+ /**
83
+ * Returns the name of a region from an ISO 3166 code.
84
+ * @param {string} code - The ISO 3166 code.
85
+ * @returns {string} The region name.
86
+ */
87
+ const _mapCodeToRegion = code => {
88
+ code = code?.toUpperCase();
89
+ return CodeToRegion[code] || '';
90
+ }
91
+
92
+ /**
93
+ * Returns an ISO 3166 code from a region name.
94
+ * @param {string} region - The region name.
95
+ * @returns {string} The ISO 3166 code.
96
+ */
97
+ const _mapRegionToCode = region => {
98
+ region = region?.toLowerCase();
99
+ return RegionToCode[region] || '';
100
+ }
101
+
102
+ // ----- LANGUAGE OBJECTS FROM CODES ----- //
103
+
104
+ /**
105
+ * Returns a language object from an array of codes or a single code.
106
+ * @param {string|string[]} codes - The code or array of codes.
107
+ * @returns {Object|Object[]} The language object(s).
108
+ */
109
+ const _getLanguageObject = codes => {
110
+ return Array.isArray(codes) ? codes.map(_handleGetLanguageObject) : _handleGetLanguageObject(codes);
111
+ }
112
+
113
+ /**
114
+ * Helper function to create a language object from a code.
115
+ * @param {string} code - The language code.
116
+ * @returns {Object|null} The language object.
117
+ */
118
+ const _handleGetLanguageObject = code => {
119
+ if (!code) return null;
120
+ let languageObject = {
121
+ language: '',
122
+ script: '',
123
+ region: ''
124
+ };
125
+ const subtags = code.split('-');
126
+ // Look for language
127
+ const languageCode = subtags[0];
128
+ languageObject.language = _mapCodeToLanguage(languageCode);
129
+ // Look for script and region
130
+ if (subtags.length === 3) { // language-script-region
131
+ languageObject.script = _mapCodeToScript(subtags[1]);
132
+ languageObject.region = _mapCodeToRegion(subtags[2]);
133
+ }
134
+ else if (subtags.length === 2) { // either language-script or language-region
135
+ if (_isScriptCode(subtags[1])) {
136
+ languageObject.script = _mapCodeToScript(subtags[1]);
137
+ } else {
138
+ languageObject.region = _mapCodeToRegion(subtags[1]);
139
+ }
140
+ }
141
+ return languageObject.language ? languageObject : null;
142
+ }
143
+
144
+ /**
145
+ * Helper function to determine if a code is a script code.
146
+ * @param {string} code - The code to check.
147
+ * @returns {boolean} True if the code is a script code, false otherwise.
148
+ */
149
+ const _isScriptCode = (code) => { // if not assume region
150
+ if (code.length !== 4) return false;
151
+ return true;
152
+ }
153
+
154
+ // ----- LANGUAGE NAMES FROM CODES ----- //
155
+
156
+ /**
157
+ * Returns the language name(s) from an array of codes or a single code.
158
+ * @param {string|string[]} codes - The code or array of codes.
159
+ * @returns {string|string[]} The language name(s).
160
+ */
161
+ const _getLanguageName = (codes) => {
162
+ return Array.isArray(codes) ? codes.map(_handleGetLanguageName) : _handleGetLanguageName(codes);
34
163
  }
35
164
 
165
+ /**
166
+ * Helper function to get the language name from a code.
167
+ * @param {string} code - The language code.
168
+ * @returns {string} The language name.
169
+ */
170
+ const _handleGetLanguageName = code => {
171
+ if (!code) return '';
172
+ if (Predefined[code]) return Predefined[code];
173
+ const languageObject = _getLanguageObject(code);
174
+ if (!languageObject) return '';
175
+ let result = languageObject.language;
176
+ if (languageObject.script) {
177
+ result += `, ${languageObject.script}`
178
+ }
179
+ if (languageObject.region) {
180
+ result += `, ${languageObject.region}`
181
+ }
182
+ return result;
183
+ }
184
+
185
+ // ----- LANGUAGE CODES FROM NAMES ----- //
186
+
187
+ /**
188
+ * Returns the language code(s) from an array of language names or a single name.
189
+ * @param {string|string[]} languages - The language name or array of language names.
190
+ * @returns {string|string[]} The language code(s).
191
+ */
36
192
  const _getLanguageCode = languages => {
37
- return Array.isArray(languages) ? languages.map(_mapLanguageToCode) : _mapLanguageToCode(languages);
193
+ return Array.isArray(languages) ? languages.map(_handleGetLanguageCode) : _handleGetLanguageCode(languages);
194
+ }
195
+
196
+ /**
197
+ * Helper function to get the language code from a language name.
198
+ * @param {string|Object} language - The language name or object.
199
+ * @returns {string} The language code.
200
+ */
201
+ const _handleGetLanguageCode = language => {
202
+ if (typeof language === 'string') return _handleGetLanguageCodeFromString(language);
203
+ return _handleGetLanguageCodeFromObject(language);
38
204
  }
39
205
 
206
+ /**
207
+ * Helper function to get the language code from a language name string.
208
+ * @param {string} language - The language name.
209
+ * @returns {string} The language code.
210
+ */
211
+ const _handleGetLanguageCodeFromString = language => {
212
+ const subtagStrings = language.split(',').map(string => string.trim());
213
+ let code = _mapLanguageToCode(subtagStrings[0]);
214
+ if (code) {
215
+ if (subtagStrings.length === 3) {
216
+ code += `-${_mapScriptToCode(subtagStrings[1])}`
217
+ code += `-${_mapRegionToCode(subtagStrings[2])}`
218
+ }
219
+ else if (subtagStrings.length === 2) {
220
+ let tag = _mapScriptToCode(subtagStrings[1]);
221
+ if (!tag) tag = _mapRegionToCode(subtagStrings[1]);
222
+ if (tag) code += `-${tag}`;
223
+ }
224
+ }
225
+ if (!code) {
226
+ for (const key in Predefined) {
227
+ if (Predefined[key] === language) {
228
+ return key;
229
+ }
230
+ }
231
+ }
232
+ return code;
233
+ }
234
+
235
+ /**
236
+ * Helper function to get the language code from a language object.
237
+ * @param {Object} languageObject - The language object.
238
+ * @returns {string} The language code.
239
+ */
240
+ const _handleGetLanguageCodeFromObject = languageObject => {
241
+ if (!languageObject?.language) return '';
242
+ let code = languageObject.language.toLowerCase();
243
+ if (languageObject.script) {
244
+ code += `-${_capitalize(languageObject.script)}`
245
+ }
246
+ if (languageObject.region) {
247
+ code += `-${languageObject.region.toUpperCase()}`
248
+ }
249
+ return code;
250
+ }
251
+
252
+ // ----- COMPARISON FUNCTION ----- //
253
+
254
+ /**
255
+ * Determines if all provided language codes represent the same language.
256
+ * Can take either an array of codes or a plain set of parameters.
257
+ * @param {...(string|string[])} codes - The language codes, either as separate arguments or as an array.
258
+ * @returns {boolean} True if all codes represent the same language, false otherwise.
259
+ */
260
+ const _isSameLanguage = (...codes) => {
261
+ // Flatten the array in case the codes are provided as an array
262
+ if (codes.length === 1 && Array.isArray(codes[0])) {
263
+ codes = codes[0];
264
+ }
265
+
266
+ if (codes.length < 2) return false;
267
+
268
+ let language = null;
269
+ for (let i = 0; i < codes.length; i++) {
270
+ if (typeof codes[i] !== 'string') return false;
271
+
272
+ const languageCode = codes[i].split('-')[0];
273
+ const currentLanguage = _mapCodeToLanguage(languageCode);
274
+
275
+ if (language === null) {
276
+ language = currentLanguage;
277
+ } else if (language !== currentLanguage) {
278
+ return false;
279
+ }
280
+ }
281
+ return true;
282
+ }
283
+
284
+ // ----- EXPORTS ----- //
285
+
286
+ // Export functions for external use
40
287
  module.exports = {
288
+ _getLanguageObject,
41
289
  _getLanguageName,
42
- _getLanguageCode
290
+ _getLanguageCode,
291
+ _isSameLanguage
43
292
  };
@@ -0,0 +1,29 @@
1
+ const Predefined = {
2
+ "en-US": "English",
3
+ "en-GB": "British English",
4
+ "en-CA": "Canadian English",
5
+ "en-AU": "Australian English",
6
+ "es-ES": "Spanish",
7
+ "es-MX": "Mexican Spanish",
8
+ "es-AR": "Argentinian Spanish",
9
+ "es-CO": "Colombian Spanish",
10
+ "fr-FR": "French",
11
+ "fr-CA": "Canadian French",
12
+ "fr-BE": "Belgian French",
13
+ "fr-CH": "Swiss French",
14
+ "zh-CN": "Mandarin Chinese",
15
+ "zh-TW": "Traditional Chinese",
16
+ "zh-HK": "Hong Kong Chinese",
17
+ "pt-PT": "Portuguese",
18
+ "pt-BR": "Brazilian Portuguese",
19
+ "de-DE": "German",
20
+ "de-AT": "Austrian German",
21
+ "de-CH": "Swiss German",
22
+ "ar-SA": "Saudi Arabic",
23
+ "ar-EG": "Egyptian Arabic",
24
+ "ar-AE": "Emirati Arabic",
25
+ "ar-MA": "Moroccan Arabic",
26
+ "nl-BE": "Belgian Dutch",
27
+ "it-CH": "Swiss Italian"
28
+ };
29
+ module.exports = Predefined;
package/index.js CHANGED
@@ -3,14 +3,12 @@
3
3
 
4
4
  // ----- IMPORTS ----- //
5
5
 
6
- const { _getLanguageCode, _getLanguageName } = require('./codes/codes.js');
7
- const { _translate, _translateMany } = require('./translate/translate.js');
8
- const _translateHTML = require('./translate/html.js');
6
+ const { _getLanguageObject, _getLanguageCode, _getLanguageName, _isSameLanguage } = require('./codes/codes.js');
9
7
 
10
8
  // TO DO
9
+ // - Translation API
11
10
  // - Times/dates?
12
11
  // - Currency conversion?
13
- // - Regions (e.g. en-GB)
14
12
 
15
13
  // ----- CORE CLASS ----- //
16
14
 
@@ -29,7 +27,7 @@ class GT {
29
27
  apiKey = '',
30
28
  defaultLanguage = 'en',
31
29
  projectID = '',
32
- baseURL = 'https://translate.gtx.dev'
30
+ baseURL = 'https://prod.gtx.dev'
33
31
  } = {}) {
34
32
  this.apiKey = apiKey || getDefaultFromEnv('GT_API_KEY');
35
33
  this.projectID = projectID || getDefaultFromEnv('GT_PROJECT_ID');
@@ -37,32 +35,7 @@ class GT {
37
35
  this.baseURL = baseURL;
38
36
  }
39
37
 
40
- // Site I18N
41
- async translateHTML({ page, userLanguage, defaultLanguage, content, ...metadata }) {
42
- return await _translateHTML({
43
- page: page,
44
- userLanguage: userLanguage,
45
- defaultLanguage: defaultLanguage,
46
- content: content,
47
- config: this,
48
- ...metadata
49
- });
50
- }
51
-
52
- // String translation
53
- async translate(content, language, ...options) {
54
- return await _translate({
55
- content: content, language: language, config: this, ...options,
56
- });
57
- }
58
-
59
- // String translation, of an array of strings
60
- // requestArray looks like { content: '', language: '' }
61
- async translateMany(contentArray, language, ...options) {
62
- return await _translateMany({
63
- contentArray, language, config: this, ...options
64
- });
65
- }
38
+ // TBD
66
39
 
67
40
  }
68
41
 
@@ -72,5 +45,7 @@ class GT {
72
45
  module.exports = GT;
73
46
 
74
47
  // Export the functions
48
+ module.exports.getLanguageObject = _getLanguageObject;
75
49
  module.exports.getLanguageCode = _getLanguageCode;
76
- module.exports.getLanguageName = _getLanguageName;
50
+ module.exports.getLanguageName = _getLanguageName;
51
+ module.exports.isSameLanguage= _isSameLanguage;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "generaltranslation",
3
- "version": "1.2.15",
3
+ "version": "1.3.0",
4
4
  "description": "A language toolkit for AI developers",
5
5
  "main": "index.js",
6
6
  "scripts": {
package/translate/html.js DELETED
@@ -1,50 +0,0 @@
1
- const _translateHTML = async ({
2
- page,
3
- userLanguage,
4
- defaultLanguage,
5
- content,
6
- config,
7
- ...metadata
8
- }) => {
9
-
10
- const apiKey = config?.apiKey;
11
- if (!apiKey) {
12
- throw new Error('Missing API Key!')
13
- };
14
-
15
- const projectID = config?.projectID;
16
- if (!projectID) {
17
- throw new Error('Missing Project ID!')
18
- };
19
-
20
- try {
21
- const response = await fetch('https://html.gtx.dev', {
22
- method: 'POST',
23
- headers: {
24
- 'Content-Type': 'application/json',
25
- 'gtx-api-key': apiKey,
26
- },
27
- body: JSON.stringify({
28
- projectID: projectID,
29
- page: page,
30
- userLanguage: userLanguage,
31
- defaultLanguage: defaultLanguage,
32
- content: content,
33
- metadata: { ...metadata }
34
- })
35
- });
36
- if (!response.ok) {
37
- const result = await response.text();
38
- throw new Error(`${result || response.status}`);
39
- } else {
40
- const result = await response.json();
41
- return result;
42
- }
43
- } catch (error) {
44
- console.error(error);
45
- return {};
46
- }
47
-
48
- }
49
-
50
- module.exports = _translateHTML;
@@ -1,191 +0,0 @@
1
- // ----- TRANSLATION ----- //
2
-
3
- // Decides whether an item object should be translated
4
- const _shouldTranslate = item => typeof item?.translate === 'boolean' ? item.translate : true;
5
-
6
- // Pre-processes content to send to the API
7
- // Separates out text that shouldn't be translated.
8
- const _processContent = ({ content }) => {
9
- const processed = [];
10
- const untranslated = [];
11
- if (Array.isArray(content)) {
12
- for (const item of content) {
13
- if (typeof item === 'string') {
14
- processed.push({
15
- text: item
16
- });
17
- } else if (_shouldTranslate(item)) {
18
- processed.push(item);
19
- } else {
20
- processed.push({text: '', translate: false});
21
- untranslated.push(item);
22
- }
23
- }
24
- } else {
25
- if (typeof content === 'string') {
26
- processed.push({
27
- text: content
28
- });
29
- } else if (_shouldTranslate(content)) {
30
- processed.push(content);
31
- } else {
32
- processed.push({text: '', translate: false});
33
- untranslated.push(content);
34
- }
35
- }
36
- return {
37
- processed: processed,
38
- untranslated: untranslated.length > 0 ? untranslated : null
39
- }
40
- }
41
-
42
- // Build content string from array or single item
43
- const _constructContent = ({ content, untranslated = null}) => {
44
- if (Array.isArray(content)) {
45
- let final = '';
46
- for (const item of content) {
47
- if (typeof item === 'string') final += item;
48
- else if (_shouldTranslate(item)) final += item?.text || '';
49
- else {
50
- if (untranslated?.length > 0) {
51
- final += untranslated?.shift().text || '';
52
- } else {
53
- final += item?.text || '';
54
- }
55
- }
56
- }
57
- return final;
58
- } else if (typeof content === 'string') {
59
- return content;
60
- } else {
61
- return content?.text || '';
62
- }
63
- }
64
-
65
- // Get a translation via General Translation API
66
- // Returns string
67
- const _translate = async ({
68
- content, language, config, ...options
69
- }) => {
70
-
71
- const apiKey = config?.apiKey;
72
- if (!apiKey) {
73
- throw new Error('Missing API Key!')
74
- };
75
-
76
- const defaultLanguage = config?.defaultLanguage;
77
- if (language === defaultLanguage) {
78
- return _constructContent({ content: content });
79
- };
80
-
81
- const { processed, untranslated } = _processContent({ content });
82
-
83
- try {
84
- const response = await fetch(`${config?.baseURL}`, {
85
- method: 'POST',
86
- headers: {
87
- 'Content-Type': 'application/json',
88
- 'gtx-api-key': apiKey,
89
- },
90
- body: JSON.stringify({
91
- content: processed,
92
- targetLanguage: language,
93
- defaultLanguage: defaultLanguage,
94
- options: { ...options }
95
- })
96
- })
97
- if (!response.ok) {
98
- const result = await response.text();
99
- throw new Error(`${result || response.status}`);
100
- } else {
101
- const result = await response.json();
102
- return _constructContent({content: result, untranslated: untranslated });
103
- }
104
- } catch (error) {
105
- console.error(error)
106
- return _constructContent({ content: content })
107
- }
108
-
109
- }
110
-
111
- const constructAll = (contentArray) => {
112
- const returnArray = [];
113
- for (const item of contentArray) {
114
- returnArray.push(_constructContent({ content: item }))
115
- }
116
- return returnArray;
117
- }
118
-
119
- // Get a translation of multiple strings via General Translation API
120
- // Returns array of strings
121
- const _translateMany = async ({
122
- contentArray, language, config, ...options
123
- }) => {
124
-
125
- const apiKey = config?.apiKey;
126
- if (!apiKey) {
127
- throw new Error('Missing API Key!')
128
- };
129
-
130
- const defaultLanguage = config?.defaultLanguage;
131
- if (language === defaultLanguage) {
132
- return constructAll(contentArray);
133
- };
134
-
135
- /*
136
- // [{content, language,...options}], config
137
- ->
138
- [{
139
- content: processed,
140
- targetLanguage: language,
141
- defaultLanguage: defaultLanguage,
142
- options: { ...options }
143
- }]
144
- */
145
-
146
- const processedArray = [];
147
- const untranslatedArray = [];
148
-
149
- for (const item of contentArray) {
150
- const { processed, untranslated } = _processContent({ content: item });
151
- processedArray.push(processed);
152
- untranslatedArray.push(untranslated);
153
- }
154
-
155
- try {
156
- const response = await fetch(`${config?.baseURL}/many`, {
157
- method: 'POST',
158
- headers: {
159
- 'Content-Type': 'application/json',
160
- 'gtx-api-key': apiKey,
161
- },
162
- body: JSON.stringify({
163
- contentArray: processedArray,
164
- targetLanguage: language,
165
- defaultLanguage: defaultLanguage,
166
- options: { ...options }
167
- })
168
- })
169
- if (!response.ok) {
170
-
171
- const result = await response.text();
172
- throw new Error(`${result || response.status}`);
173
- } else {
174
- const result = await response.json();
175
- if (!Array.isArray(result)) {
176
- throw new Error(`${result || response.status}`);
177
- }
178
- const returnArray = [];
179
- for (const [index, item] of result.entries()) {
180
- returnArray.push(_constructContent({content: item, untranslated: untranslatedArray[index] }));
181
- }
182
- return returnArray;
183
- }
184
- } catch (error) {
185
- console.error(error)
186
- return constructAll(contentArray);
187
- }
188
-
189
- }
190
-
191
- module.exports = { _translate, _translateMany };