Some checks failed
lotteryadmin CI / build (push) Has been cancelled
Updated localization files for English and Nepali, adding new entries and refining existing translations for better clarity. Enhanced the agent management interface with improved delegation features and child agent creation prompts. Improved player management functionalities, including confirmation dialogs for player actions and better handling of player creation and editing processes.
317 lines
24 KiB
JavaScript
317 lines
24 KiB
JavaScript
#!/usr/bin/env node
|
|
/**
|
|
* Merge missing Nepali (ne) i18n keys from translations map.
|
|
* Usage: node scripts/merge-ne-translations.mjs
|
|
*/
|
|
import fs from "fs";
|
|
import path from "path";
|
|
import { fileURLToPath } from "url";
|
|
|
|
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
const root = path.join(__dirname, "..");
|
|
const localesDir = path.join(root, "src/i18n/locales");
|
|
|
|
/** @type {Record<string, Record<string, string>>} */
|
|
const translations = {
|
|
"adminUsers.json": {
|
|
siteRequired: "साइट छान्नुहोस्",
|
|
"table.sites": "बाँधिएका साइटहरू",
|
|
"permissionDialog.site": "साइट",
|
|
"accountDialog.site": "बाँधिएको साइट",
|
|
"accountDialog.sitePlaceholder": "यो खाताले पहुँच पाउने साइट छान्नुहोस्",
|
|
},
|
|
"agents.json": {
|
|
"lineUi.kicker": "क्रेडिट शेयर · एजेन्ट ट्री",
|
|
"lineUi.agentCount": "यो समूहमा {{count}} एजेन्ट",
|
|
"lineUi.searchPlaceholder": "नाम वा लगइन खोज्नुहोस्",
|
|
"lineUi.directChildren": "प्रत्यक्ष अधीनस्थ {{count}}",
|
|
"lineUi.selectAgent": "शेयर र क्रेडिट हेर्न एजेन्ट छान्नुहोस्",
|
|
"lineUi.selectAgentHint":
|
|
"सेटलमेन्ट सीमा एजेन्ट ट्री अनुसार; शेयर, क्रेडिट र रिबेट प्रति नोड कन्फिग गरिन्छ।",
|
|
"lineUi.allocatedCredit": "बाँडिएको",
|
|
"lineUi.availableCredit": "उपलब्ध",
|
|
"lineUi.profileFootnote": "रिबेट सीमा {{rebate}}% · पूर्वनिर्धारित {{defaultRebate}}%",
|
|
"lineUi.tabOverview": "अवलोकन",
|
|
"lineUi.tabProfile": "शेयर र क्रेडिट",
|
|
"lineUi.tabProfileReadOnly": "शेयर र क्रेडिट (पढ्न मात्र)",
|
|
"lineUi.currentSite": "साइट",
|
|
"lineUi.viewAll": "सबै हेर्नुहोस्",
|
|
"lineUi.shareRebateCap": "रिबेट सीमा {{rate}}%",
|
|
"lineUi.overviewDownlineCard": "प्रत्यक्ष अधीनस्थ एजेन्ट हेर्नुहोस् र व्यवस्थापन गर्नुहोस्",
|
|
"lineUi.overviewDownlineCount": "{{count}}",
|
|
"lineUi.overviewPlayersHint": "प्रत्यक्ष खेलाडी र क्रेडिट स्थिति हेर्नुहोस्",
|
|
"lineUi.overviewPlayersSummary": "खेलाडी व्यवस्थापन",
|
|
"lineUi.downlineEmptyTitle": "अहिले प्रत्यक्ष अधीनस्थ छैन",
|
|
"lineUi.editAccount": "खाता र स्थिति",
|
|
"lineUi.saveProfile": "शेयर र क्रेडिट बचत",
|
|
"lineUi.tabDownline": "अधीनस्थ",
|
|
"lineUi.tabPlayers": "खेलाडी",
|
|
"lineUi.noDelegatedTabs":
|
|
"यो एजेन्टले अधीनस्थ एजेन्ट वा खेलाडी सिर्जना गर्न सक्दैन; शेयर र क्रेडिट मात्र लागू हुन्छ।",
|
|
listSearch: "नाम / कोड / लगइन खोज्नुहोस्",
|
|
siteSearch: "साइट नाम खोज्नुहोस्",
|
|
parentAgent: "माथिल्लो",
|
|
childrenCount: "प्रत्यक्ष अधीनस्थ",
|
|
"subnav.provisionHint": "एक पटकको अनबोर्डिङ; दैनिक कामका लागि लाइन र एजेन्ट ट्री प्रयोग गर्नुहोस्",
|
|
"profile.validation.creditBelowAllocated":
|
|
"क्रेडिट सीमा बाँडिएको क्रेडिभन्दा कम हुन सक्दैन (न्यूनतम {{min}})",
|
|
"profile.validation.creditExceedsParentWithMax": "क्रेडिट सीमा {{max}} भन्दा बढी हुन सक्दैन",
|
|
"settlementBills.periodLabel": "अवधि",
|
|
"settlementBills.periodPlaceholder": "अवधि छान्नुहोस्",
|
|
"settlementBills.allPeriods": "सबै अवधि",
|
|
"settlementBills.filteredByPeriodRange": "{{range}} का बिलहरू",
|
|
"settlementBills.emptyNoPeriodsManage":
|
|
"अहिले अवधि वा बिल छैन। अवधि व्यवस्थापनमा छिटो प्रिसेट प्रयोग गर्नुहोस्, त्यसपछि अवधि बन्द गर्नुहोस्।",
|
|
"settlementBills.emptyNoPeriodsAgent":
|
|
"अहिले बिल छैन। तपाईंको माथिल्लो वा प्लेटफर्मले अवधि बन्द गर्छ; मिति प्रविष्ट गर्नु पर्दैन।",
|
|
"settlementBills.emptyNoClosed": "बन्द अवधि छैन। बिल बन्द पछि सिर्जना हुन्छ।",
|
|
"settlementBills.typePlayer": "खेलाडी बिल",
|
|
"settlementBills.typeAgent": "एजेन्ट बिल",
|
|
"settlementBills.columns.period": "अवधि",
|
|
"settlementPeriods.manageTitle": "अवधि व्यवस्थापन",
|
|
"settlementPeriods.manageHint":
|
|
"यहाँ अवधि खोल्नुहोस् र बन्द गर्नुहोस्; माथिका बिल स्वतः अद्यावधिक हुन्छ। छिटो प्रिसेट सामान्यतया पर्याप्त।",
|
|
"settlementPeriods.presetThisWeek": "यो हप्ता",
|
|
"settlementPeriods.presetLastWeek": "गत हप्ता",
|
|
"settlementPeriods.presetThisMonth": "यो महिना",
|
|
"settlementPeriods.openHint": "स्थानीय मिति ({{tz}})",
|
|
"settlementPeriods.startDate": "सुरु मिति",
|
|
"settlementPeriods.endDate": "अन्त्य मिति",
|
|
"settlementPeriods.open": "अवधि खोल्नुहोस्",
|
|
"settlementPeriods.openFailed": "अवधि खोल्न असफल",
|
|
"settlementPeriods.datesRequired": "सुरु र अन्त्य मिति प्रविष्ट गर्नुहोस्",
|
|
"settlementPeriods.invalidRange": "अन्त्य मिति सुरु मितिभन्दा अगाडि हुन सक्दैन",
|
|
"settlementPeriods.statusOpen": "खुला",
|
|
"settlementPeriods.statusClosed": "बन्द",
|
|
"playersPanel.loginRequired": "लगइन प्रयोगकर्ता नाम र प्रारम्भिक पासवर्ड प्रविष्ट गर्नुहोस्",
|
|
"playersPanel.loginUsername": "लगइन प्रयोगकर्ता नाम",
|
|
"playersPanel.initialPassword": "प्रारम्भिक पासवर्ड",
|
|
"playersPanel.externalIdOptional": "बाह्य ID (वैकल्पिक)",
|
|
"playersPanel.externalIdHint": "स्वतः सिर्जनाका लागि खाली राख्नुहोस्",
|
|
"playersPanel.creditLimit": "क्रेडिट सीमा",
|
|
"playersPanel.rebateRate": "रिबेट दर (%)",
|
|
"playersPanel.rebateRateHint": "प्रतिशत लेख्नुहोस्, जस्तै 5 = 5%",
|
|
"playersPanel.availableToGrant": "एजेन्टले दिन सक्ने: {{amount}}",
|
|
"playersPanel.riskTags": "जोखिम ट्याग",
|
|
"playersPanel.riskTagsPlaceholder": "अल्पविरामले छुट्याउनुहोस्",
|
|
"playersPanel.createSuccessNative": "खेलाडी {{name}} सिर्जना भयो — लटरी /login प्रयोग गर्नुहोस्",
|
|
"users.email": "इमेल",
|
|
},
|
|
"common.json": {
|
|
"export.ticketCombinations.filename": "ticket-combinations",
|
|
"export.ticketCombinations.sheetName": "संयोजनहरू",
|
|
"integrationSites.emptyPlatformHint":
|
|
"अहिले एकीकरण साइट छैन। एजेन्ट, खेलाडी वा सेटलमेन्ट व्यवस्थापन अघि साइट सिर्जना गर्नुहोस्।",
|
|
"integrationSites.createSite": "एकीकरण साइट सिर्जना",
|
|
},
|
|
"config.json": {
|
|
"integrationSites.adminAccountCreated": "साइट एडमिन खाता {{username}} सिर्जना भयो",
|
|
"integrationSites.delete": "साइट मेटाउनुहोस्",
|
|
"integrationSites.deleteSuccess": "साइट {{code}} मेटाइयो",
|
|
"integrationSites.deleteFailed": "साइट मेटाउन असफल",
|
|
"integrationSites.deleteConfirmTitle": "यो साइट मेटाउने?",
|
|
"integrationSites.deleteConfirmDescription":
|
|
"यसले साइट {{code}} ({{name}}), यसको एजेन्ट लाइन, सेटलमेन्ट अवधि, खेलाडी र साइट एडमिन खाता स्थायी रूपमा हटाउँछ। पूर्ववत गर्न मिल्दैन।",
|
|
"integrationSites.deleteConfirm": "मेटाउनुहोस्",
|
|
"integrationSites.deleting": "मेटाउँदै…",
|
|
"integrationSites.form.adminUsernameRequired": "साइट एडमिन प्रयोगकर्ता नाम आवश्यक",
|
|
"integrationSites.form.adminNicknameRequired": "साइट एडमिन उपनाम आवश्यक",
|
|
"integrationSites.form.adminPasswordRequired": "प्रारम्भिक साइट एडमिन पासवर्ड कम्तीमा ८ अक्षर",
|
|
"integrationSites.fields.adminUsername": "एडमिन प्रयोगकर्ता नाम",
|
|
"integrationSites.fields.adminNickname": "एडमिन उपनाम",
|
|
"integrationSites.fields.adminPassword": "प्रारम्भिक पासवर्ड",
|
|
"integrationSites.fields.adminEmail": "इमेल (वैकल्पिक)",
|
|
"integrationSites.placeholders.adminUsername": "एडमिन प्रयोगकर्ता नाम लेख्नुहोस्",
|
|
"integrationSites.placeholders.adminNickname": "खाता उपनाम लेख्नुहोस्",
|
|
"integrationSites.placeholders.adminPassword": "कम्तीमा ८ अक्षर",
|
|
"integrationSites.placeholders.adminEmail": "इमेल लेख्नुहोस्",
|
|
"integrationSites.adminAccountSectionTitle": "साइट एडमिन खाता",
|
|
"integrationSites.adminAccountSectionDescription":
|
|
"साइट सिर्जना गर्दा त्यस साइटसँग बाँधिएको एउटा एडमिन खाता पनि सिर्जना हुन्छ।",
|
|
"system.saveDrawSuccess": "ड्र प्यारामिटर बचत भयो",
|
|
"system.saveCurrencyFormatSuccess": "मुद्रा प्रदर्शन ढाँचा बचत भयो",
|
|
"system.saveSettlementSuccess": "सेटलमेन्ट स्वचालन बचत भयो",
|
|
"system.sections.draw": "ड्र तालिका र समीक्षा",
|
|
"system.sections.drawDescription":
|
|
"ड्र समय, बन्द सञ्झ्याल, म्यानुअल समीक्षा र कूलडाउन नियन्त्रण। यो ब्लकमा परिवर्तित फिल्ड मात्र पेश हुन्छ।",
|
|
"system.sections.currencyFormat": "मुद्रा प्रदर्शन ढाँचा",
|
|
"system.sections.currencyFormatDescription":
|
|
"साइटभरि रकमका दशमलव र विभाजक (मुद्रा मास्टर डाटाबाट अलग)।",
|
|
"system.sections.settlement": "सेटलमेन्ट स्वचालन",
|
|
"system.sections.settlementDescription":
|
|
"टिक स्वतः सेटलमेन्ट, अनुमोदन र भुक्तानी चलाउने नियन्त्रण। यो ब्लकमा परिवर्तित फिल्ड मात्र पेश हुन्छ।",
|
|
"system.confirmSaveDrawTitle": "ड्र प्यारामिटर बचत गर्ने?",
|
|
"system.confirmSaveDrawDescription":
|
|
"यसले यो ब्लकमा ड्र समीक्षा, तालिका समय र कूलडाउन मात्र अद्यावधिक गर्छ।",
|
|
"system.confirmSaveCurrencyFormatTitle": "मुद्रा प्रदर्शन ढाँचा बचत गर्ने?",
|
|
"system.confirmSaveCurrencyFormatDescription": "यसले दशमलव स्थान र विभाजक अद्यावधिक गर्छ।",
|
|
"system.confirmSaveSettlementTitle": "सेटलमेन्ट स्वचालन बचत गर्ने?",
|
|
"system.confirmSaveSettlementDescription":
|
|
"यसले स्वतः सेटलमेन्ट, अनुमोदन र भुक्तानी स्विच अद्यावधिक गर्छ।",
|
|
"play.filters.sectionTitle": "खेल फिल्टर",
|
|
"play.filters.sectionDescription":
|
|
"पहिले सूची संकुचित गर्नुहोस्, त्यसपछि ब्याच स्विच वा पङ्क्ति सम्पादन प्रयोग गर्नुहोस्।",
|
|
"play.filters.keyword": "खेल खोज्नुहोस्",
|
|
"play.filters.keywordPlaceholder": "खेल कोड, प्रदर्शन नाम वा श्रेणीले फिल्टर",
|
|
"play.filters.category": "श्रेणी",
|
|
"play.filters.status": "स्थिति",
|
|
"play.filters.allCategories": "सबै श्रेणी",
|
|
"play.filters.allStatuses": "सबै स्थिति",
|
|
"play.filters.uncategorized": "अवर्गीकृत",
|
|
"play.filters.reset": "फिल्टर हटाउनुहोस्",
|
|
"play.filters.empty": "मिल्ने खेल प्रकार छैन",
|
|
"play.filters.groupCount": "{{count}} खेल",
|
|
},
|
|
"dashboard.json": {
|
|
"analytics.summaryShareProfit": "आफ्नो शेयर नाफा",
|
|
"analytics.shareProfitHint":
|
|
"विभाजन पछि तपाईंको शेयर — प्लेटफर्म वा सम्पूर्ण टोलीको कुल नाफा/नोक्सान होइन",
|
|
currentDrawFinanceHint: "तलका चार्ट ड्र {{drawNo}} का लागि",
|
|
"agent.heroEyebrow": "आजको लाइन ककपिट",
|
|
"agent.heroTitle": "{{name}} प्रत्यक्ष सञ्चालन",
|
|
"agent.creditAllocated": "बाँडिएको {{amount}}",
|
|
"agent.creditUsed": "प्रयोग {{amount}}",
|
|
"agent.settlementCycle": "चक्र {{cycle}}",
|
|
"agent.betOrdersToday": "आजका बाजी अर्डर",
|
|
"agent.todayPayout": "आजको भुक्तानी",
|
|
"agent.todayProfit": "आजको नाफा",
|
|
"agent.sevenDayPayout": "भुक्तानी {{amount}}",
|
|
"agent.sevenDayProfit": "नाफा {{amount}}",
|
|
"agent.sevenDayShareProfit": "शेयर नाफा {{amount}}",
|
|
"agent.topMomentum": "आजको बाजी केन्द्र",
|
|
"agent.topMomentumHint": "नाफा {{profit}}",
|
|
"agent.topMomentumPayout": "भुक्तानी {{amount}}",
|
|
"agent.managementFocus": "व्यवस्थापन केन्द्र",
|
|
"agent.focusBet": "आजको बाजी मात्रा निगरानी",
|
|
"agent.focusPlayers": "आजका सक्रिय खेलाडी",
|
|
"agent.focusBills": "पछ्याउन बाँकी बिल",
|
|
"agent.quickStatsTitle": "लाइन अनुमति झलक",
|
|
"agent.canCreateChildAgent": "सन्तान एजेन्ट सिर्जना गर्न सक्छ",
|
|
"agent.canCreatePlayer": "खेलाडी सिर्जना गर्न सक्छ",
|
|
"agent.lineDepth": "लाइन गहिराइ",
|
|
"agent.viewBills": "बिल हेर्नुहोस्",
|
|
"agent.viewLine": "एजेन्ट लाइन",
|
|
"agent.quickLinks.tickets": "टिकट",
|
|
"agent.quickLinks.players": "खेलाडी",
|
|
"agent.quickLinks.reports": "रिपोर्ट",
|
|
"agent.quickLinks.agents": "अधीनस्थ एजेन्ट",
|
|
"agent.quickLinks.bills": "एजेन्ट बिल",
|
|
"warnings.apiResourceMissing":
|
|
"ड्यासबोर्ड विश्लेषण API दर्ता छैन। चलाउनुहोस्: php artisan lottery:admin-auth-sync (वा पछिल्लो माइग्रेसन), त्यसपछि रिफ्रेस।",
|
|
},
|
|
"draws.json": {
|
|
backToList: "ड्र सूचीमा फर्कनुहोस्",
|
|
overviewTitle: "ड्र अवलोकन",
|
|
overviewBetTotal: "कुल बाजी",
|
|
overviewPayoutTotal: "कुल भुक्तानी",
|
|
overviewProfitLoss: "नाफा/नोक्सान",
|
|
reviewQueueHint: "नतिजा सिर्जना पछि समीक्षा र प्रकाशनमा जारी राख्नुहोस्।",
|
|
},
|
|
"players.json": {
|
|
ticketTableHint:
|
|
"यो तालिकाले खेलाडीका हालैका टिकट देखाउँछ। पूर्ण सन्दर्भ र समस्या समाधानका लागि पङ्क्ति कार्यबाट मुख्य टिकट सूचीमा जानुहोस्।",
|
|
tabCreditLedger: "क्रेडिट लेजर",
|
|
filterSite: "साइट",
|
|
filterAllSites: "सबै साइट",
|
|
scopeAllSites: "स्कोप: सबै साइटका सबै खेलाडी (सुपर एडमिन)",
|
|
scopeFilteredSite: "स्कोप: साइट {{site}}",
|
|
scopeAgentLine: "स्कोप: {{site}} · एजेन्ट लाइन “{{name}}” र अधीनस्थ खेलाडी",
|
|
scopeSingleSite: "स्कोप: साइट {{site}}",
|
|
scopeMultiSite: "स्कोप: {{count}} बाँधिएका साइट; संकुचित गर्न फिल्टर प्रयोग गर्नुहोस्",
|
|
fundingMode: "फन्डिङ मोड",
|
|
authSource: "प्रमाणीकरण स्रोत",
|
|
creditSection: "क्रेडिट लाइन",
|
|
usedCredit: "प्रयोग भएको क्रेडिट",
|
|
fundingCredit: "क्रेडिट लाइन",
|
|
fundingWallet: "मुख्य साइट वालेट",
|
|
authMainSite: "मुख्य साइट SSO",
|
|
authNative: "लटरी नेटिभ",
|
|
creditLimit: "क्रेडिट सीमा",
|
|
availableCredit: "उपलब्ध क्रेडिट",
|
|
confirmFreezeTitle: "खेलाडी फ्रिज गर्ने?",
|
|
confirmFreezeDescription: "खेलाडी {{name}} ले बाजी लगाउन सक्ने छैन।",
|
|
confirmUnfreezeTitle: "खेलाडी अनफ्रिज गर्ने?",
|
|
confirmUnfreezeDescription: "खेलाडी {{name}} सामान्य स्थितिमा फर्किनेछ।",
|
|
},
|
|
"reconcile.json": {
|
|
createHint:
|
|
"छानिएको अवधिमा ट्रान्सफर अर्डर स्क्यान गर्छ, लटरी वालेट लेजर तुलना गर्छ, र वालेट API कन्फिग भएमा मुख्य साइट idempotent रेकर्ड जाँच गर्छ।",
|
|
createSuccessEmpty: "स्क्यान सम्पन्न: कुनै समस्या फेला परेन",
|
|
transferNo: "ट्रान्सफर नं.",
|
|
walletTxnNo: "लटरी वालेट लेनदेन",
|
|
mainSiteRef: "मुख्य साइट सन्दर्भ",
|
|
mainSiteCheck: "मुख्य साइट जाँच",
|
|
actions: "कार्य",
|
|
itemMainSiteRecordMissing: "मुख्य साइटमा छैन",
|
|
itemMainSiteFailed: "मुख्य साइटमा असफल",
|
|
mainSiteMatched: "मुख्य साइट ठीक",
|
|
mainSiteNotFound: "मुख्य साइटमा छैन",
|
|
mainSiteFailed: "मुख्य साइट असफल",
|
|
mainSiteUnavailable: "मुख्य साइट उपलब्ध छैन",
|
|
mainSiteSkipped: "जाँच गरिएको छैन",
|
|
},
|
|
"reports.json": {
|
|
"tasks.currentReportHint": "यहाँ हाल छानिएको रिपोर्टका निर्यात कार्य मात्र देखिन्छ।",
|
|
"preview.stats.notQueried": "क्वेरी गरिएको छैन",
|
|
"preview.stats.notSet": "सेट गरिएको छैन",
|
|
},
|
|
"risk.json": {
|
|
"confirm.closeTitle": "नम्बर बन्द गर्ने?",
|
|
"confirm.closeDescription": "नम्बर {{number}} यो ड्रका लागि ब्लक हुनेछ।",
|
|
"confirm.recoverTitle": "नम्बर पुन: खोल्ने?",
|
|
"confirm.recoverDescription": "नम्बर {{number}} फेरि बाजीका लागि खुल्नेछ।",
|
|
},
|
|
"tickets.json": {
|
|
filterSite: "साइट",
|
|
filterAllSites: "सबै साइट",
|
|
viewTicketInList: "यो टिकट हेर्नुहोस्",
|
|
statusSelectedCount: "{{count}} छानिएको",
|
|
},
|
|
"wallet.json": {
|
|
scopeHint:
|
|
"यो क्षेत्र मुख्य साइट वालेट मोड (वालेट लेनदेन र ट्रान्सफर) का लागि हो। क्रेडिट लाइन अवधि सेटलमेन्टका लागि हेर्नुहोस्",
|
|
scopeHintSettlementLink: "सेटलमेन्ट केन्द्र",
|
|
scopeHintSettlement: "सेटलमेन्ट केन्द्र",
|
|
ledgerChannel: "लेजर",
|
|
ledgerCredit: "क्रेडिट लेजर",
|
|
ledgerWallet: "वालेट लेनदेन",
|
|
},
|
|
};
|
|
|
|
function setNested(obj, dotKey, value) {
|
|
const parts = dotKey.split(".");
|
|
let cur = obj;
|
|
for (let i = 0; i < parts.length - 1; i++) {
|
|
if (!(parts[i] in cur) || typeof cur[parts[i]] !== "object" || Array.isArray(cur[parts[i]])) {
|
|
cur[parts[i]] = {};
|
|
}
|
|
cur = cur[parts[i]];
|
|
}
|
|
cur[parts[parts.length - 1]] = value;
|
|
}
|
|
|
|
function sortKeysDeep(value) {
|
|
if (Array.isArray(value)) return value;
|
|
if (value && typeof value === "object") {
|
|
return Object.fromEntries(
|
|
Object.keys(value)
|
|
.sort()
|
|
.map((k) => [k, sortKeysDeep(value[k])]),
|
|
);
|
|
}
|
|
return value;
|
|
}
|
|
|
|
let merged = 0;
|
|
for (const [file, keys] of Object.entries(translations)) {
|
|
const nePath = path.join(localesDir, "ne", file);
|
|
const ne = JSON.parse(fs.readFileSync(nePath, "utf8"));
|
|
for (const [dotKey, neValue] of Object.entries(keys)) {
|
|
setNested(ne, dotKey, neValue);
|
|
merged++;
|
|
}
|
|
fs.writeFileSync(nePath, `${JSON.stringify(sortKeysDeep(ne), null, 2)}\n`, "utf8");
|
|
console.log(`Updated ${file} (+${Object.keys(keys).length} keys)`);
|
|
}
|
|
console.log(`Total merged: ${merged}`);
|