@adminforth/i18n 2.3.2 → 2.5.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/dist/index.js CHANGED
@@ -7,7 +7,8 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
7
7
  step((generator = generator.apply(thisArg, _arguments || [])).next());
8
8
  });
9
9
  };
10
- import { AdminForthPlugin, Filters, suggestIfTypo, AdminForthDataTypes, RAMLock, filtersTools, AdminForthFilterOperators } from "adminforth";
10
+ import { Filters, suggestIfTypo, AdminForthDataTypes, RAMLock, filtersTools, AdminForthFilterOperators } from "adminforth";
11
+ import { I18nBase, getCountryCodeFromLangCode, getPrimaryLanguageCode, requiresSlavicPlurals, SLAVIC_PLURAL_EXAMPLES, SLAVIC_PLURAL_FORMS, SLAVIC_PLURAL_FORMS_HINT, SOURCE_LANGUAGE } from './base.js';
11
12
  import { z } from "zod";
12
13
  import iso6391 from 'iso-639-1';
13
14
  const updateFieldBodySchema = z.object({
@@ -28,61 +29,10 @@ import path from 'path';
28
29
  import fs from 'fs-extra';
29
30
  import chokidar from 'chokidar';
30
31
  import { AsyncQueue } from '@sapphire/async-queue';
31
- import getFlagEmoji from 'country-flag-svg';
32
32
  import { parse } from 'bcp-47';
33
33
  import pLimit from 'p-limit';
34
34
  import { afLogger } from "adminforth";
35
35
  const processFrontendMessagesQueue = new AsyncQueue();
36
- const SLAVIC_PLURAL_EXAMPLES = {
37
- uk: 'яблук | Яблуко | Яблука | Яблук', // zero | singular | 2-4 | 5+
38
- bg: 'ябълки | ябълка | ябълки | ябълки', // zero | singular | 2-4 | 5+
39
- cs: 'jablek | jablko | jablka | jablek', // zero | singular | 2-4 | 5+
40
- hr: 'jabuka | jabuka | jabuke | jabuka', // zero | singular | 2-4 | 5+
41
- mk: 'јаболка | јаболко | јаболка | јаболка', // zero | singular | 2-4 | 5+
42
- pl: 'jabłek | jabłko | jabłka | jabłek', // zero | singular | 2-4 | 5+
43
- sk: 'jabĺk | jablko | jablká | jabĺk', // zero | singular | 2-4 | 5+
44
- sl: 'jabolk | jabolko | jabolka | jabolk', // zero | singular | 2-4 | 5+
45
- sr: 'јабука | јабука | јабуке | јабука', // zero | singular | 2-4 | 5+
46
- be: 'яблыкаў | яблык | яблыкі | яблыкаў', // zero | singular | 2-4 | 5+
47
- ru: 'яблок | яблоко | яблока | яблок', // zero | singular | 2-4 | 5+
48
- };
49
- const countryISO31661ByLangISO6391 = {
50
- en: 'us', // English → United States
51
- zh: 'cn', // Chinese → China
52
- hi: 'in', // Hindi → India
53
- ar: 'sa', // Arabic → Saudi Arabia
54
- ko: 'kr', // Korean → South Korea
55
- ja: 'jp', // Japanese → Japan
56
- uk: 'ua', // Ukrainian → Ukraine
57
- ur: 'pk', // Urdu → Pakistan
58
- sr: 'rs', // Serbian → Serbia
59
- da: 'dk' // Danish → Denmark
60
- };
61
- function getCountryCodeFromLangCode(lang) {
62
- const [langCode, region] = String(lang).split('-');
63
- if (region && /^[A-Z]{2}$/.test(region)) {
64
- return region.toLowerCase();
65
- }
66
- return countryISO31661ByLangISO6391[langCode] || langCode;
67
- }
68
- function getPrimaryLanguageCode(langCode) {
69
- return String(langCode).split('-')[0];
70
- }
71
- function isValidSupportedLanguageTag(langCode) {
72
- try {
73
- const schema = parse(String(langCode), {
74
- normalize: true,
75
- warning: (reason, code, offset) => {
76
- console.warn(`Warning in validating language tag ${langCode}: reason=${reason}, code=${code}, offset=${offset}`);
77
- }
78
- });
79
- const isValid = schema.language.length === 2;
80
- return isValid;
81
- }
82
- catch (e) {
83
- return false;
84
- }
85
- }
86
36
  class CachingAdapterMemory {
87
37
  constructor() {
88
38
  this.cache = {};
@@ -121,29 +71,30 @@ class AiTranslateError extends Error {
121
71
  this.name = 'AiTranslateError';
122
72
  }
123
73
  }
124
- export default class I18nPlugin extends AdminForthPlugin {
74
+ export default class I18nPlugin extends I18nBase {
125
75
  constructor(options) {
126
- super(options, import.meta.url);
127
- this.options = options;
76
+ super(options);
128
77
  this.cache = new CachingAdapterMemory();
129
78
  this.trFieldNames = {};
130
- this.primaryLanguage = options.primaryLanguage || 'en';
79
+ }
80
+ // translated languages joined by '|', e.g. 'uk|ja', stored in completedFieldName to filter not fully translated strings
81
+ completedLangsValue(isTranslated) {
82
+ return this.targetLanguages().filter(isTranslated).join('|');
131
83
  }
132
84
  computeCompletedFieldValue(record) {
133
- return __awaiter(this, void 0, void 0, function* () {
134
- return this.options.supportedLanguages.reduce((acc, lang) => {
135
- if (lang === 'en') {
136
- return acc;
137
- }
138
- if (record[this.trFieldNames[lang]]) {
139
- if (acc !== '') {
140
- acc += '|';
141
- }
142
- acc += lang;
143
- }
144
- return acc;
145
- }, '');
146
- });
85
+ return this.completedLangsValue((lang) => Boolean(record[this.trFieldNames[lang]]));
86
+ }
87
+ // all translations of category for frontend_messages
88
+ categoryCacheKey(category, lang) {
89
+ return `${this.resourceConfig.resourceId}:${category}:${lang}`;
90
+ }
91
+ // one string translated by backend tr
92
+ messageCacheKey(category, lang, enString) {
93
+ return `${this.categoryCacheKey(category, lang)}:${enString}`;
94
+ }
95
+ clearTranslationCache(category, lang, enString) {
96
+ this.cache.clear(this.categoryCacheKey(category, lang));
97
+ this.cache.clear(this.messageCacheKey(category, lang, enString));
147
98
  }
148
99
  updateUntranslatedMenuBadge() {
149
100
  return __awaiter(this, void 0, void 0, function* () {
@@ -169,12 +120,6 @@ export default class I18nPlugin extends AdminForthPlugin {
169
120
  this.adminforth.config.componentsToExplicitRegister.push({
170
121
  file: this.componentPath('TranslationJobViewComponent.vue')
171
122
  });
172
- // validate each supported language: ISO 639-1 or BCP-47 with region (e.g., en-GB)
173
- this.options.supportedLanguages.forEach((lang) => {
174
- if (!isValidSupportedLanguageTag(lang)) {
175
- throw new Error(`Invalid language code ${lang}. Use ISO 639-1 (e.g., 'en') or BCP-47 with region (e.g., 'en-GB').`);
176
- }
177
- });
178
123
  if (this.options.translateLangAsBCP47Code) {
179
124
  for (const [lang, bcp47] of Object.entries(this.options.translateLangAsBCP47Code)) {
180
125
  if (!this.options.supportedLanguages.includes(lang)) {
@@ -189,10 +134,7 @@ export default class I18nPlugin extends AdminForthPlugin {
189
134
  throw new Error(`Primary key field not found in resource ${resourceConfig.resourceId}`);
190
135
  }
191
136
  // parse trFieldNames
192
- for (const lang of this.options.supportedLanguages) {
193
- if (lang === 'en') {
194
- continue;
195
- }
137
+ for (const lang of this.targetLanguages()) {
196
138
  if ((_b = this.options.translationFieldNames) === null || _b === void 0 ? void 0 : _b[lang]) {
197
139
  this.trFieldNames[lang] = this.options.translationFieldNames[lang];
198
140
  }
@@ -224,17 +166,8 @@ export default class I18nPlugin extends AdminForthPlugin {
224
166
  },
225
167
  };
226
168
  }
227
- this.enFieldName = this.trFieldNames['en'] || 'en_string';
228
- this.fullCompleatedFieldValue = this.options.supportedLanguages.reduce((acc, lang) => {
229
- if (lang === 'en') {
230
- return acc;
231
- }
232
- if (acc !== '') {
233
- acc += '|';
234
- }
235
- acc += lang;
236
- return acc;
237
- }, '');
169
+ this.enFieldName = this.trFieldNames[SOURCE_LANGUAGE] || `${SOURCE_LANGUAGE}_string`;
170
+ this.fullCompleatedFieldValue = this.completedLangsValue(() => true);
238
171
  // if not enFieldName column is not found, throw error
239
172
  const enColumn = resourceConfig.columns.find(c => c.name === this.enFieldName);
240
173
  if (!enColumn) {
@@ -293,40 +226,15 @@ export default class I18nPlugin extends AdminForthPlugin {
293
226
  type: AdminForthDataTypes.BOOLEAN,
294
227
  });
295
228
  }
296
- const compMeta = {
297
- brandSlug: adminforth.config.customization.brandNameSlug,
298
- pluginInstanceId: this.pluginInstanceId,
299
- primaryLanguage: this.primaryLanguage,
300
- afOrder: this.options.loginPageLanguageSelectorOrder || 0,
301
- supportedLanguages: this.options.supportedLanguages.map(lang => ({
302
- code: lang,
303
- // lang name on on language native name
304
- name: iso6391.getNativeName(getPrimaryLanguageCode(lang)),
305
- }))
306
- };
307
229
  // add underLogin component
308
230
  if (!this.externalAppOnly) {
309
- adminforth.config.customization.loginPageInjections.underLoginButton.push({
310
- file: this.componentPath('LanguageUnderLogin.vue'),
311
- meta: compMeta
312
- });
313
- (adminforth.config.customization.globalInjections.userMenu).push({
314
- file: this.componentPath('LanguageInUserMenu.vue'),
315
- meta: compMeta
316
- });
317
- adminforth.config.customization.globalInjections.everyPageBottom.push({
318
- file: this.componentPath('LanguageEveryPageLoader.vue'),
319
- meta: compMeta
320
- });
231
+ this.injectLanguageSelectors(adminforth);
321
232
  }
322
233
  // disable create allowedActions for translations
323
234
  resourceConfig.options.allowedActions.create = false;
324
235
  // add hook to validate user did not screw up with template params
325
236
  resourceConfig.hooks.edit.beforeSave.push((_a) => __awaiter(this, [_a], void 0, function* ({ updates, oldRecord }) {
326
- for (const lang of this.options.supportedLanguages) {
327
- if (lang === 'en') {
328
- continue;
329
- }
237
+ for (const lang of this.targetLanguages()) {
330
238
  if (updates[this.trFieldNames[lang]]) { // if user set '', it will have '' in updates, then it is fine, we shoudl nto check it
331
239
  if (!ensureTemplateHasAllParams(oldRecord[this.enFieldName], updates[this.trFieldNames[lang]])) {
332
240
  return { ok: false, error: `Template params mismatch for ${updates[this.enFieldName]}. Template param names should be the same as in original string. E. g. 'Hello {name}', should be 'Hola {name}' and not 'Hola {nombre}'!` };
@@ -339,19 +247,10 @@ export default class I18nPlugin extends AdminForthPlugin {
339
247
  resourceConfig.hooks.edit.afterSave.push((_a) => __awaiter(this, [_a], void 0, function* ({ updates, oldRecord }) {
340
248
  if (oldRecord) {
341
249
  // find lang which changed
342
- let langsChanged = [];
343
- for (const lang of this.options.supportedLanguages) {
344
- if (lang === 'en') {
345
- continue;
346
- }
347
- if (updates[this.trFieldNames[lang]] !== undefined) {
348
- langsChanged.push(lang);
349
- }
350
- }
250
+ const langsChanged = this.targetLanguages().filter((lang) => updates[this.trFieldNames[lang]] !== undefined);
351
251
  // clear frontend cache for all langsChanged
352
252
  for (const lang of langsChanged) {
353
- this.cache.clear(`${this.resourceConfig.resourceId}:${oldRecord[this.options.categoryFieldName]}:${lang}`);
354
- this.cache.clear(`${this.resourceConfig.resourceId}:${oldRecord[this.options.categoryFieldName]}:${lang}:${oldRecord[this.enFieldName]}`);
253
+ this.clearTranslationCache(oldRecord[this.options.categoryFieldName], lang, oldRecord[this.enFieldName]);
355
254
  }
356
255
  this.updateUntranslatedMenuBadge();
357
256
  }
@@ -361,9 +260,7 @@ export default class I18nPlugin extends AdminForthPlugin {
361
260
  // add hook on delete of any translation to reset cache
362
261
  resourceConfig.hooks.delete.afterSave.push((_a) => __awaiter(this, [_a], void 0, function* ({ record }) {
363
262
  for (const lang of this.options.supportedLanguages) {
364
- // if frontend, clear frontend cache
365
- this.cache.clear(`${this.resourceConfig.resourceId}:${record[this.options.categoryFieldName]}:${lang}`);
366
- this.cache.clear(`${this.resourceConfig.resourceId}:${record[this.options.categoryFieldName]}:${lang}:${record[this.enFieldName]}`);
263
+ this.clearTranslationCache(record[this.options.categoryFieldName], lang, record[this.enFieldName]);
367
264
  }
368
265
  this.updateUntranslatedMenuBadge();
369
266
  return { ok: true };
@@ -422,6 +319,7 @@ export default class I18nPlugin extends AdminForthPlugin {
422
319
  file: this.componentPath('BulkActionButton.vue'),
423
320
  meta: {
424
321
  supportedLanguages: this.options.supportedLanguages,
322
+ countryCodes: Object.fromEntries(this.options.supportedLanguages.map((lang) => [lang, getCountryCodeFromLangCode(lang)])),
425
323
  pluginInstanceId: this.pluginInstanceId,
426
324
  }
427
325
  };
@@ -568,13 +466,8 @@ export default class I18nPlugin extends AdminForthPlugin {
568
466
  yield this.adminforth.resource(this.resourceConfig.resourceId).update(strId, Object.assign(Object.assign({}, updates), { [this.options.completedFieldName]: futureCompletedFieldValue }));
569
467
  })));
570
468
  for (const lang of langsInvolved) {
571
- const categoriesInvolved = new Set();
572
469
  for (const { enStr, category } of Object.values(updateStrings)) {
573
- categoriesInvolved.add(category);
574
- yield this.cache.clear(`${this.resourceConfig.resourceId}:${category}:${lang}:${enStr}`);
575
- }
576
- for (const category of categoriesInvolved) {
577
- yield this.cache.clear(`${this.resourceConfig.resourceId}:${category}:${lang}`);
470
+ this.clearTranslationCache(category, lang, enStr);
578
471
  }
579
472
  }
580
473
  return { ok: true };
@@ -628,14 +521,14 @@ export default class I18nPlugin extends AdminForthPlugin {
628
521
  const lang = langIsoCode;
629
522
  const primaryLang = getPrimaryLanguageCode(lang);
630
523
  const langName = iso6391.getName(primaryLang);
631
- const requestSlavicPlurals = Object.keys(SLAVIC_PLURAL_EXAMPLES).includes(primaryLang) && plurals;
524
+ const requestSlavicPlurals = requiresSlavicPlurals(lang) && plurals;
632
525
  const region = langSchema.region;
633
526
  const basePrompt = `
634
527
  I need to translate strings in JSON to ${langName} language ${replacedLanguageCodeForTranslations || lang.length > 2 ? `BCP-47 code ${langCode}` : `ISO 639-1 code ${langIsoCode}`} from English for my web app.
635
528
 
636
529
 
637
530
  ${region ? `Use the regional conventions for ${langCode} (region ${region}), including spelling, punctuation, and formatting.` : ''}
638
- ${requestSlavicPlurals ? `You should provide 4 slavic forms (in format "zero count | singular count | 2-4 | 5+") e.g. "apple | apples" should become "${SLAVIC_PLURAL_EXAMPLES[lang]}"` : ''}
531
+ ${requestSlavicPlurals ? `You should provide ${SLAVIC_PLURAL_FORMS} slavic forms (in format "${SLAVIC_PLURAL_FORMS_HINT}") e.g. "apple | apples" should become "${SLAVIC_PLURAL_EXAMPLES[primaryLang]}"` : ''}
639
532
  JSON keys are internal identifiers. Keep keys as is and write translations into values. If values have variables (in curly brackets), then translated strings should have them as well (variables itself should not be translated). Here are the strings:
640
533
  \`\`\`json
641
534
  {
@@ -702,6 +595,7 @@ export default class I18nPlugin extends AdminForthPlugin {
702
595
  translations: translations.filter(t => stringBanchCopy.includes(t.en_string)),
703
596
  updateStrings,
704
597
  lang,
598
+ countryCode: getCountryCodeFromLangCode(lang),
705
599
  failedToTranslate,
706
600
  needToTranslateByLang,
707
601
  promptCost: basePromptTokenLength + banchTokens,
@@ -718,8 +612,8 @@ export default class I18nPlugin extends AdminForthPlugin {
718
612
  const translations = yield this.adminforth.resource(this.resourceConfig.resourceId).list(Filters.IN(this.primaryKeyFieldName, selectedIds));
719
613
  const languagesToProcess = selectedLanguages || this.options.supportedLanguages;
720
614
  for (const lang of languagesToProcess) {
721
- if (lang === 'en') {
722
- // all strings are in English, no need to translate
615
+ if (lang === SOURCE_LANGUAGE) {
616
+ // all strings are in source language, no need to translate
723
617
  continue;
724
618
  }
725
619
  for (const translation of translations) {
@@ -849,10 +743,7 @@ export default class I18nPlugin extends AdminForthPlugin {
849
743
  if (this.options.completeAdapter) {
850
744
  this.options.completeAdapter.validate();
851
745
  }
852
- for (const lang of this.options.supportedLanguages) {
853
- if (lang === 'en') {
854
- continue;
855
- }
746
+ for (const lang of this.targetLanguages()) {
856
747
  const column = resourceConfig.columns.find(c => c.name === this.trFieldNames[lang]);
857
748
  if (!column) {
858
749
  throw new Error(`Field ${this.trFieldNames[lang]} not found for storing translation for language ${lang}
@@ -887,134 +778,47 @@ export default class I18nPlugin extends AdminForthPlugin {
887
778
  // in this plugin we will use plugin to fill the database with missing language messages
888
779
  if (!this.externalAppOnly) {
889
780
  this.tryProcessAndWatch(adminforth);
890
- adminforth.tr = (msg, category, lang, params, pluralizationNumber) => __awaiter(this, void 0, void 0, function* () {
891
- if (!msg) {
892
- return msg;
893
- }
781
+ this.installBackendTranslator(adminforth, (msg, category, lang) => __awaiter(this, void 0, void 0, function* () {
894
782
  if (category === 'frontend') {
895
783
  throw new Error(`Category 'frontend' is reserved for frontend messages, use any other category for backend messages`);
896
784
  }
897
- // console.log('🪲tr', msg, category, lang);
898
- // if lang is not supported, fallback to primaryLanguage, then to english
899
- if (!this.options.supportedLanguages.includes(lang)) {
900
- lang = this.primaryLanguage; // fallback to primary language first
901
- if (!this.options.supportedLanguages.includes(lang)) {
902
- lang = 'en'; // final fallback to english
903
- }
904
- }
905
- let result;
906
785
  // try to get translation from cache
907
- const cacheKey = `${resourceConfig.resourceId}:${category}:${lang}:${msg}`;
786
+ const cacheKey = this.messageCacheKey(category, lang, msg);
908
787
  const cached = yield this.cache.get(cacheKey);
909
788
  if (cached) {
910
- result = cached;
911
- }
912
- if (!result) {
913
- const resource = adminforth.resource(resourceConfig.resourceId);
914
- const translation = yield resource.get([Filters.EQ(this.enFieldName, msg), Filters.EQ(this.options.categoryFieldName, category)]);
915
- if (!translation) {
916
- yield resource.create({
917
- [this.enFieldName]: msg,
918
- [this.options.categoryFieldName]: category,
919
- });
920
- this.updateUntranslatedMenuBadge();
921
- }
922
- // do this check here, to faster register missing translations
923
- // also not cache it - no sense to cache english strings
924
- if (lang === 'en') {
925
- // set to cache to return faster next time
926
- result = msg;
927
- }
928
- else {
929
- result = translation === null || translation === void 0 ? void 0 : translation[this.trFieldNames[lang]];
930
- if (!result) {
931
- // return english
932
- result = msg;
933
- }
934
- }
935
- // cache so even if key does not exist, we will not hit database
936
- yield this.cache.set(cacheKey, result);
937
- }
938
- // if msg has '|' in it, then we need to aplly pluralization
939
- if (msg.includes('|') && pluralizationNumber !== undefined) {
940
- result = this.applyPluralization(result, pluralizationNumber, lang);
941
- }
942
- if (params) {
943
- for (const [key, value] of Object.entries(params)) {
944
- if (result) {
945
- result = result.replace(`{${key}}`, value);
946
- }
947
- }
789
+ return cached;
790
+ }
791
+ const resource = adminforth.resource(resourceConfig.resourceId);
792
+ const translation = yield resource.get([Filters.EQ(this.enFieldName, msg), Filters.EQ(this.options.categoryFieldName, category)]);
793
+ if (!translation) {
794
+ yield resource.create({
795
+ [this.enFieldName]: msg,
796
+ [this.options.categoryFieldName]: category,
797
+ });
798
+ this.updateUntranslatedMenuBadge();
948
799
  }
800
+ // do this check here, to faster register missing translations
801
+ const result = lang === SOURCE_LANGUAGE ? msg : (translation === null || translation === void 0 ? void 0 : translation[this.trFieldNames[lang]]) || msg;
802
+ // cache so even if key does not exist, we will not hit database
803
+ yield this.cache.set(cacheKey, result);
949
804
  return result;
950
- });
951
- }
952
- }
953
- applyPluralization(str, number, lang) {
954
- const choices = str.split('|');
955
- const choicesLength = choices.length;
956
- if (choicesLength > 2) {
957
- // this is slavic pluralization
958
- return choices[this.slavicPluralRule(number, choicesLength)];
959
- }
960
- else {
961
- return number === 1 ? choices[0] : choices[1];
962
- }
963
- }
964
- // taken from here https://vue-i18n.intlify.dev/guide/essentials/pluralization.html#custom-pluralization
965
- slavicPluralRule(choice, choicesLength) {
966
- if (choice === 0) {
967
- return 0;
968
- }
969
- const teen = choice > 10 && choice < 20;
970
- const endsWithOne = choice % 10 === 1;
971
- if (!teen && endsWithOne) {
972
- return 1;
973
- }
974
- if (!teen && choice % 10 >= 2 && choice % 10 <= 4) {
975
- return 2;
805
+ }));
976
806
  }
977
- return choicesLength < 4 ? 2 : 3;
978
- }
979
- instanceUniqueRepresentation(pluginOptions) {
980
- // optional method to return unique string representation of plugin instance.
981
- // Needed if plugin can have multiple instances on one resource
982
- return `single`;
983
807
  }
984
808
  getCategoryTranslations(category, lang) {
985
809
  return __awaiter(this, void 0, void 0, function* () {
986
810
  const resource = this.adminforth.resource(this.resourceConfig.resourceId);
987
- const cacheKey = `${this.resourceConfig.resourceId}:${category}:${lang}`;
811
+ const cacheKey = this.categoryCacheKey(category, lang);
988
812
  const cached = yield this.cache.get(cacheKey);
989
813
  if (cached) {
990
814
  return cached;
991
815
  }
992
- const translations = {};
993
816
  const allTranslations = yield resource.list([Filters.EQ(this.options.categoryFieldName, category)]);
994
- for (const tr of allTranslations) {
995
- const translatedValue = tr[this.trFieldNames[lang]];
996
- translations[tr[this.enFieldName]] = translatedValue || tr[this.enFieldName];
997
- }
817
+ const translations = this.fallbackToOriginal(Object.fromEntries(allTranslations.map((tr) => [tr[this.enFieldName], tr[this.trFieldNames[lang]]])));
998
818
  yield this.cache.set(cacheKey, translations);
999
819
  return translations;
1000
820
  });
1001
821
  }
1002
- languagesList() {
1003
- return __awaiter(this, void 0, void 0, function* () {
1004
- return Promise.all(this.options.supportedLanguages.map((lang) => __awaiter(this, void 0, void 0, function* () {
1005
- const flagEmoji = typeof getFlagEmoji === 'function'
1006
- ? getFlagEmoji
1007
- : getFlagEmoji.default;
1008
- return {
1009
- code: lang,
1010
- nameOnNative: iso6391.getNativeName(getPrimaryLanguageCode(lang)),
1011
- nameEnglish: iso6391.getName(getPrimaryLanguageCode(lang)),
1012
- emojiFlag: getCountryCodeFromLangCode(lang).toUpperCase().replace(/./g, char => String.fromCodePoint(char.charCodeAt(0) + 127397)),
1013
- svgFlagB64: yield flagEmoji(getCountryCodeFromLangCode(lang)),
1014
- };
1015
- })));
1016
- });
1017
- }
1018
822
  feedCategoryTranslations(messages, category) {
1019
823
  return __awaiter(this, void 0, void 0, function* () {
1020
824
  const adminforth = this.adminforth;
@@ -1049,17 +853,7 @@ export default class I18nPlugin extends AdminForthPlugin {
1049
853
  });
1050
854
  }
1051
855
  setupEndpoints(server) {
1052
- server.endpoint({
1053
- method: 'GET',
1054
- path: `/plugin/${this.pluginInstanceId}/frontend_messages`,
1055
- noAuth: true,
1056
- handler: (_a) => __awaiter(this, [_a], void 0, function* ({ query }) {
1057
- const lang = query.lang;
1058
- // form map of translations
1059
- const translations = yield this.getCategoryTranslations('frontend', lang);
1060
- return translations;
1061
- })
1062
- });
856
+ super.setupEndpoints(server);
1063
857
  const lock = new RAMLock();
1064
858
  server.endpoint({
1065
859
  method: 'POST',
@@ -1203,3 +997,4 @@ export default class I18nPlugin extends AdminForthPlugin {
1203
997
  });
1204
998
  }
1205
999
  }
1000
+ export { I18nBase, getCountryCodeFromLangCode, getPrimaryLanguageCode, isValidSupportedLanguageTag, requiresSlavicPlurals, SOURCE_LANGUAGE, PLURAL_SEPARATOR, SLAVIC_PLURAL_FORMS, SLAVIC_PLURAL_FORMS_HINT } from './base.js';
package/dist/types.d.ts CHANGED
@@ -5,8 +5,24 @@ import { type PluginsCommonOptions } from "adminforth";
5
5
  type Alpha2Code = keyof typeof iso31661Alpha2ToAlpha3;
6
6
  type Bcp47LanguageTag = `${LanguageCode}-${Alpha2Code}`;
7
7
  export type SupportedLanguage = LanguageCode | Bcp47LanguageTag;
8
- export interface PluginOptions extends PluginsCommonOptions {
8
+ /**
9
+ * Options shared by all i18n plugins built on top of I18nBase
10
+ */
11
+ export interface I18nBaseOptions extends PluginsCommonOptions {
9
12
  supportedLanguages: SupportedLanguage[];
13
+ /**
14
+ * Language selector on login page order
15
+ */
16
+ loginPageLanguageSelectorOrder?: number;
17
+ /**
18
+ * Primary language for the application. This is the default language shown to users.
19
+ * English is always used as the source language for translations, even if primaryLanguage is different.
20
+ * When a translation is missing for the primaryLanguage, English will be shown as fallback.
21
+ * Defaults to 'en' if not specified.
22
+ */
23
+ primaryLanguage?: SupportedLanguage;
24
+ }
25
+ export interface PluginOptions extends I18nBaseOptions {
10
26
  /**
11
27
  * Each translation string will be stored in a separate field, you can remap it to existing columns using this option
12
28
  * By default it will assume field are named like `${lang_code}_string` (e.g. 'en_string', 'uk_string', 'ja_string', 'fr_string')
@@ -18,10 +34,6 @@ export interface PluginOptions extends PluginsCommonOptions {
18
34
  * We recommend to put index on this column
19
35
  */
20
36
  categoryFieldName: string;
21
- /**
22
- * Language selector on login page order
23
- */
24
- loginPageLanguageSelectorOrder?: number;
25
37
  /**
26
38
  * Optional source field to store e.g. file name where it first was captured
27
39
  */
@@ -46,13 +58,6 @@ export interface PluginOptions extends PluginsCommonOptions {
46
58
  * it should be a JSON field (underlyng database type should be TEXT or JSON)
47
59
  */
48
60
  reviewedCheckboxesFieldName?: string;
49
- /**
50
- * Primary language for the application. This is the default language shown to users.
51
- * English is always used as the source language for translations, even if primaryLanguage is different.
52
- * When a translation is missing for the primaryLanguage, English will be shown as fallback.
53
- * Defaults to 'en' if not specified.
54
- */
55
- primaryLanguage?: SupportedLanguage;
56
61
  /**
57
62
  * Ask translator to treat some code from supportedLanguages as exact BCP47 tag. Read docs for details.
58
63
  * key - one of the values form supportedLanguages, value -BCP47 tag