fhirsmith 0.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/CHANGELOG.md +42 -0
- package/FHIRsmith.png +0 -0
- package/README.md +277 -0
- package/config-template.json +144 -0
- package/library/folder-setup.js +58 -0
- package/library/html-server.js +166 -0
- package/library/html.js +835 -0
- package/library/i18nsupport.js +259 -0
- package/library/languages.js +779 -0
- package/library/logger-telnet.js +205 -0
- package/library/logger.js +279 -0
- package/library/package-manager.js +876 -0
- package/library/utilities.js +196 -0
- package/library/version-utilities.js +1056 -0
- package/npmprojector/config-example.json +13 -0
- package/npmprojector/indexer.js +394 -0
- package/npmprojector/npmprojector.js +395 -0
- package/npmprojector/readme.md +174 -0
- package/npmprojector/watcher.js +335 -0
- package/package.json +119 -0
- package/packages/package-crawler.js +846 -0
- package/packages/packages-template.html +126 -0
- package/packages/packages.js +2838 -0
- package/passwords.ini +2 -0
- package/publisher/publisher-template.html +208 -0
- package/publisher/publisher.js +2167 -0
- package/publisher/task-draft.js +458 -0
- package/registry/api.js +735 -0
- package/registry/crawler.js +637 -0
- package/registry/model.js +513 -0
- package/registry/readme.md +243 -0
- package/registry/registry-data.json +121015 -0
- package/registry/registry-template.html +126 -0
- package/registry/registry.js +1395 -0
- package/registry/test-runner.js +237 -0
- package/root-template.html +124 -0
- package/server.js +524 -0
- package/shl/private-key.pem +5 -0
- package/shl/public-key.pem +18 -0
- package/shl/shl.js +1125 -0
- package/shl/vhl.js +69 -0
- package/static/FHIRsmith128.png +0 -0
- package/static/FHIRsmith16.png +0 -0
- package/static/FHIRsmith32.png +0 -0
- package/static/FHIRsmith64.png +0 -0
- package/static/assets/css/bootstrap-fhir.css +5302 -0
- package/static/assets/css/bootstrap-glyphicons.css +2 -0
- package/static/assets/css/bootstrap.css +4097 -0
- package/static/assets/css/jquery-ui.css +523 -0
- package/static/assets/css/jquery-ui.structure.css +863 -0
- package/static/assets/css/jquery-ui.structure.min.css +5 -0
- package/static/assets/css/jquery-ui.theme.css +439 -0
- package/static/assets/css/jquery-ui.theme.min.css +5 -0
- package/static/assets/css/jquery.ui.all.css +7 -0
- package/static/assets/css/modules.css +18 -0
- package/static/assets/css/project.css +367 -0
- package/static/assets/css/pygments-manni.css +66 -0
- package/static/assets/css/tags.css +74 -0
- package/static/assets/css/xml.css +2 -0
- package/static/assets/fonts/glyphiconshalflings-regular.eot +0 -0
- package/static/assets/fonts/glyphiconshalflings-regular.otf +0 -0
- package/static/assets/fonts/glyphiconshalflings-regular.svg +175 -0
- package/static/assets/fonts/glyphiconshalflings-regular.ttf +0 -0
- package/static/assets/fonts/glyphiconshalflings-regular.woff +0 -0
- package/static/assets/ico/apple-touch-icon-114-precomposed.png +0 -0
- package/static/assets/ico/apple-touch-icon-144-precomposed.png +0 -0
- package/static/assets/ico/apple-touch-icon-57-precomposed.png +0 -0
- package/static/assets/ico/apple-touch-icon-72-precomposed.png +0 -0
- package/static/assets/ico/favicon.ico +0 -0
- package/static/assets/ico/favicon.png +0 -0
- package/static/assets/images/fhir-logo-www.png +0 -0
- package/static/assets/images/fhir-logo.png +0 -0
- package/static/assets/images/hl7-logo.png +0 -0
- package/static/assets/images/logo_ansinew.jpg +0 -0
- package/static/assets/images/search.png +0 -0
- package/static/assets/images/stripe.png +0 -0
- package/static/assets/images/target.png +0 -0
- package/static/assets/images/tx-registry-root.gif +0 -0
- package/static/assets/images/tx-registry.png +0 -0
- package/static/assets/images/tx-server.png +0 -0
- package/static/assets/images/tx-version.png +0 -0
- package/static/assets/js/bootstrap.min.js +6 -0
- package/static/assets/js/fhir-gw.js +259 -0
- package/static/assets/js/fhir.js +2 -0
- package/static/assets/js/html5shiv.js +8 -0
- package/static/assets/js/jcookie.js +96 -0
- package/static/assets/js/jquery-ui.min.js +6 -0
- package/static/assets/js/jquery.js +10716 -0
- package/static/assets/js/jquery.min.js +2 -0
- package/static/assets/js/jquery.ui.core.js +314 -0
- package/static/assets/js/jquery.ui.draggable.js +825 -0
- package/static/assets/js/jquery.ui.mouse.js +162 -0
- package/static/assets/js/jquery.ui.resizable.js +842 -0
- package/static/assets/js/jquery.ui.widget.js +268 -0
- package/static/assets/js/json2.js +487 -0
- package/static/assets/js/jtip.js +97 -0
- package/static/assets/js/respond.min.js +6 -0
- package/static/assets/js/statuspage.js +70 -0
- package/static/assets/js/xml.js +2 -0
- package/static/dist/js/bootstrap.js +1964 -0
- package/static/favicon.png +0 -0
- package/static/fhir.css +626 -0
- package/static/icon-fhir-16.png +0 -0
- package/static/images/ui-bg_diagonals-thick_18_b81900_40x40.png +0 -0
- package/static/images/ui-bg_diagonals-thick_20_666666_40x40.png +0 -0
- package/static/images/ui-bg_flat_10_000000_40x100.png +0 -0
- package/static/images/ui-bg_glass_100_f6f6f6_1x400.png +0 -0
- package/static/images/ui-bg_glass_100_fdf5ce_1x400.png +0 -0
- package/static/images/ui-bg_glass_65_ffffff_1x400.png +0 -0
- package/static/images/ui-bg_gloss-wave_35_f6a828_500x100.png +0 -0
- package/static/images/ui-bg_highlight-soft_100_eeeeee_1x100.png +0 -0
- package/static/images/ui-bg_highlight-soft_75_ffe45c_1x100.png +0 -0
- package/static/images/ui-icons_222222_256x240.png +0 -0
- package/static/images/ui-icons_228ef1_256x240.png +0 -0
- package/static/images/ui-icons_ef8c08_256x240.png +0 -0
- package/static/images/ui-icons_ffd27a_256x240.png +0 -0
- package/static/images/ui-icons_ffffff_256x240.png +0 -0
- package/static/js/jquery.effects.blind.js +49 -0
- package/static/js/jquery.effects.bounce.js +78 -0
- package/static/js/jquery.effects.clip.js +54 -0
- package/static/js/jquery.effects.core.js +763 -0
- package/static/js/jquery.effects.drop.js +50 -0
- package/static/js/jquery.effects.explode.js +79 -0
- package/static/js/jquery.effects.fade.js +32 -0
- package/static/js/jquery.effects.fold.js +56 -0
- package/static/js/jquery.effects.highlight.js +50 -0
- package/static/js/jquery.effects.pulsate.js +51 -0
- package/static/js/jquery.effects.scale.js +178 -0
- package/static/js/jquery.effects.shake.js +57 -0
- package/static/js/jquery.effects.slide.js +50 -0
- package/static/js/jquery.effects.transfer.js +45 -0
- package/static/js/jquery.ui.accordion.js +611 -0
- package/static/js/jquery.ui.autocomplete.js +612 -0
- package/static/js/jquery.ui.button.js +416 -0
- package/static/js/jquery.ui.datepicker.js +1823 -0
- package/static/js/jquery.ui.dialog.js +878 -0
- package/static/js/jquery.ui.droppable.js +296 -0
- package/static/js/jquery.ui.position.js +252 -0
- package/static/js/jquery.ui.progressbar.js +109 -0
- package/static/js/jquery.ui.selectable.js +266 -0
- package/static/js/jquery.ui.slider.js +666 -0
- package/static/js/jquery.ui.sortable.js +1077 -0
- package/static/js/jquery.ui.tabs.js +758 -0
- package/stats.js +80 -0
- package/test-cache/vsac/vsac-valuesets.db +0 -0
- package/token/nginx_passport_setup.md +383 -0
- package/token/security_guide.md +294 -0
- package/token/token-template.html +330 -0
- package/token/token.js +1300 -0
- package/translations/Messages.properties +1510 -0
- package/translations/Messages_ar.properties +1399 -0
- package/translations/Messages_de.properties +836 -0
- package/translations/Messages_es.properties +737 -0
- package/translations/Messages_fr.properties +1 -0
- package/translations/Messages_ja.properties +893 -0
- package/translations/Messages_nl.properties +1357 -0
- package/translations/Messages_pt.properties +1302 -0
- package/translations/Messages_ru.properties +1 -0
- package/translations/Messages_uz.properties +1 -0
- package/translations/Messages_zh.properties +1 -0
- package/translations/rendering-phrases.properties +1128 -0
- package/translations/rendering-phrases_ar.properties +1091 -0
- package/translations/rendering-phrases_de.properties +6 -0
- package/translations/rendering-phrases_es.properties +6 -0
- package/translations/rendering-phrases_fr.properties +624 -0
- package/translations/rendering-phrases_ja.properties +21 -0
- package/translations/rendering-phrases_nl.properties +970 -0
- package/translations/rendering-phrases_pt.properties +1020 -0
- package/translations/rendering-phrases_ru.properties +1094 -0
- package/translations/rendering-phrases_uz.properties +1 -0
- package/translations/rendering-phrases_zh.properties +1 -0
- package/tx/README.md +418 -0
- package/tx/cm/cm-api.js +110 -0
- package/tx/cm/cm-database.js +735 -0
- package/tx/cm/cm-package.js +325 -0
- package/tx/cs/cs-api.js +789 -0
- package/tx/cs/cs-areacode.js +615 -0
- package/tx/cs/cs-country.js +1110 -0
- package/tx/cs/cs-cpt.js +785 -0
- package/tx/cs/cs-cs.js +1579 -0
- package/tx/cs/cs-currency.js +539 -0
- package/tx/cs/cs-db.js +1321 -0
- package/tx/cs/cs-hgvs.js +329 -0
- package/tx/cs/cs-lang.js +465 -0
- package/tx/cs/cs-loinc.js +1485 -0
- package/tx/cs/cs-mimetypes.js +238 -0
- package/tx/cs/cs-ndc.js +704 -0
- package/tx/cs/cs-omop.js +1025 -0
- package/tx/cs/cs-provider-api.js +43 -0
- package/tx/cs/cs-provider-list.js +37 -0
- package/tx/cs/cs-rxnorm.js +808 -0
- package/tx/cs/cs-snomed.js +1102 -0
- package/tx/cs/cs-ucum.js +514 -0
- package/tx/cs/cs-unii.js +271 -0
- package/tx/cs/cs-uri.js +218 -0
- package/tx/cs/cs-usstates.js +305 -0
- package/tx/dev.fhir.org.yml +14 -0
- package/tx/fixtures/test-cases-setup.json +18 -0
- package/tx/fixtures/test-cases.yml +16 -0
- package/tx/html/codesystem-operations.liquid +25 -0
- package/tx/html/home-metrics.liquid +247 -0
- package/tx/html/operations-form.liquid +148 -0
- package/tx/html/search-form.liquid +62 -0
- package/tx/html/tx-template.html +133 -0
- package/tx/html/valueset-operations.liquid +54 -0
- package/tx/importers/atc-to-fhir.js +316 -0
- package/tx/importers/import-loinc.module.js +1536 -0
- package/tx/importers/import-ndc.module.js +1088 -0
- package/tx/importers/import-rxnorm.module.js +898 -0
- package/tx/importers/import-sct.module.js +2457 -0
- package/tx/importers/import-unii.module.js +601 -0
- package/tx/importers/readme.md +453 -0
- package/tx/importers/subset-loinc.module.js +1081 -0
- package/tx/importers/subset-rxnorm.module.js +938 -0
- package/tx/importers/tx-import-base.js +351 -0
- package/tx/importers/tx-import-settings.js +310 -0
- package/tx/importers/tx-import.js +357 -0
- package/tx/library/canonical-resource.js +88 -0
- package/tx/library/capabilitystatement.js +292 -0
- package/tx/library/codesystem.js +774 -0
- package/tx/library/conceptmap.js +568 -0
- package/tx/library/designations.js +932 -0
- package/tx/library/errors.js +77 -0
- package/tx/library/extensions.js +117 -0
- package/tx/library/namingsystem.js +322 -0
- package/tx/library/operation-outcome.js +127 -0
- package/tx/library/parameters.js +105 -0
- package/tx/library/renderer.js +1559 -0
- package/tx/library/terminologycapabilities.js +418 -0
- package/tx/library/ucum-parsers.js +1029 -0
- package/tx/library/ucum-service.js +370 -0
- package/tx/library/ucum-types.js +1099 -0
- package/tx/library/valueset.js +543 -0
- package/tx/library.js +676 -0
- package/tx/ocl/cm-ocl.js +106 -0
- package/tx/ocl/cs-ocl.js +39 -0
- package/tx/ocl/vs-ocl.js +105 -0
- package/tx/operation-context.js +568 -0
- package/tx/params.js +613 -0
- package/tx/provider.js +403 -0
- package/tx/sct/ecl.js +1560 -0
- package/tx/sct/expressions.js +2077 -0
- package/tx/sct/structures.js +1396 -0
- package/tx/tx-html.js +1063 -0
- package/tx/tx.fhir.org.yml +39 -0
- package/tx/tx.js +927 -0
- package/tx/vs/vs-api.js +112 -0
- package/tx/vs/vs-database.js +786 -0
- package/tx/vs/vs-package.js +358 -0
- package/tx/vs/vs-vsac.js +366 -0
- package/tx/workers/batch-validate.js +129 -0
- package/tx/workers/batch.js +361 -0
- package/tx/workers/closure.js +32 -0
- package/tx/workers/expand.js +1845 -0
- package/tx/workers/lookup.js +407 -0
- package/tx/workers/metadata.js +467 -0
- package/tx/workers/operations.js +34 -0
- package/tx/workers/read.js +164 -0
- package/tx/workers/search.js +384 -0
- package/tx/workers/subsumes.js +334 -0
- package/tx/workers/translate.js +492 -0
- package/tx/workers/validate.js +2504 -0
- package/tx/workers/worker.js +904 -0
- package/tx/xml/capabilitystatement-xml.js +63 -0
- package/tx/xml/codesystem-xml.js +62 -0
- package/tx/xml/conceptmap-xml.js +65 -0
- package/tx/xml/namingsystem-xml.js +65 -0
- package/tx/xml/operationoutcome-xml.js +127 -0
- package/tx/xml/parameters-xml.js +312 -0
- package/tx/xml/terminologycapabilities-xml.js +64 -0
- package/tx/xml/valueset-xml.js +64 -0
- package/tx/xml/xml-base.js +603 -0
- package/vcl/vcl-parser.js +1098 -0
- package/vcl/vcl.js +253 -0
- package/windows-install.js +19 -0
- package/xig/xig-template.html +124 -0
- package/xig/xig.js +3049 -0
|
@@ -0,0 +1,259 @@
|
|
|
1
|
+
const path = require("path");
|
|
2
|
+
const fs = require("fs");
|
|
3
|
+
const { getProperties } = require("properties-file");
|
|
4
|
+
const {validateParameter} = require("./utilities");
|
|
5
|
+
const {LanguageDefinitions} = require("./languages");
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Internationalization support for loading Java properties files
|
|
9
|
+
*/
|
|
10
|
+
class I18nSupport {
|
|
11
|
+
constructor(translationsPath, languageDefinitions) {
|
|
12
|
+
validateParameter(translationsPath, "translationsPath", String);
|
|
13
|
+
validateParameter(languageDefinitions, "languageDefinitions", LanguageDefinitions);
|
|
14
|
+
this.translationsPath = translationsPath;
|
|
15
|
+
this.languageDefinitions = languageDefinitions;
|
|
16
|
+
this.bundles = new Map(); // Cache for loaded message bundles by language code
|
|
17
|
+
this.phrases = new Map(); // Cache for loaded message bundles by language code
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Load all available message bundles from the translations directory
|
|
22
|
+
*/
|
|
23
|
+
async load() {
|
|
24
|
+
await this._loadResourceBundle(this.bundles, 'Messages');
|
|
25
|
+
await this._loadResourceBundle(this.phrases, 'rendering-phrases');
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
async _loadResourceBundle(bundles, name) {
|
|
29
|
+
// Load default Messages.properties first
|
|
30
|
+
await this._loadBundle(bundles, 'en', name+'.properties');
|
|
31
|
+
|
|
32
|
+
// Scan for Messages_*.properties files
|
|
33
|
+
try {
|
|
34
|
+
const files = fs.readdirSync(this.translationsPath);
|
|
35
|
+
const messageFiles = files.filter(file =>
|
|
36
|
+
file.startsWith(name+'_') && file.endsWith('.properties')
|
|
37
|
+
);
|
|
38
|
+
|
|
39
|
+
for (const file of messageFiles) {
|
|
40
|
+
// Extract language code from filename: Messages_fr_FR.properties -> fr-FR
|
|
41
|
+
const langCode = file
|
|
42
|
+
.substring(name+'_'.length, file.length - '.properties'.length)
|
|
43
|
+
.replace(/_/g, '-');
|
|
44
|
+
|
|
45
|
+
await this._loadBundle(bundles, langCode, file);
|
|
46
|
+
}
|
|
47
|
+
} catch (error) {
|
|
48
|
+
throw new Error(`Failed to scan translations directory: ${error.message}`);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Load a specific message bundle file
|
|
54
|
+
*/
|
|
55
|
+
async _loadBundle(bundles, langCode, filename) {
|
|
56
|
+
try {
|
|
57
|
+
const filePath = path.join(this.translationsPath, filename);
|
|
58
|
+
const content = fs.readFileSync(filePath, 'utf8');
|
|
59
|
+
const properties = getProperties(content);
|
|
60
|
+
|
|
61
|
+
bundles.set(langCode, properties);
|
|
62
|
+
} catch (error) {
|
|
63
|
+
// Don't throw for missing files - just skip them
|
|
64
|
+
console.warn(`Warning: Could not load ${filename}: ${error.message}`);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Format a message with parameter substitution
|
|
70
|
+
* @param {Languages} languages - Languages object with preference order
|
|
71
|
+
* @param {string} messageId - Message key from properties file
|
|
72
|
+
* @param {Array} parameters - Parameters for {0}, {1}, etc. substitution
|
|
73
|
+
* @returns {string} Formatted message
|
|
74
|
+
*/
|
|
75
|
+
formatMessage(languages, messageId, parameters = []) {
|
|
76
|
+
return this._formatMessageFromBundle(this.bundles, languages, messageId, parameters);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
translate(messageId, languages, parameters = []) {
|
|
80
|
+
return this.formatMessage(languages, messageId, parameters);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
translatePlural(count, messageId, languages, parameters = []) {
|
|
84
|
+
return this.formatMessagePlural(languages, messageId, count, parameters);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Format a message with pluralization support
|
|
89
|
+
* @param {Languages} languages - Languages object with preference order
|
|
90
|
+
* @param {string} messageId - Base message key from properties file
|
|
91
|
+
* @param {number} count - Count for pluralization (becomes {0} in final message)
|
|
92
|
+
* @param {Array} parameters - Additional parameters for {1}, {2}, etc. substitution
|
|
93
|
+
* @returns {string} Formatted message
|
|
94
|
+
*/
|
|
95
|
+
formatMessagePlural(languages, messageId, count, parameters = []) {
|
|
96
|
+
return this._formatMessagePluralFromBundle(this.bundles, languages, messageId, count, parameters);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* Format a message with parameter substitution
|
|
101
|
+
* @param {Languages} languages - Languages object with preference order
|
|
102
|
+
* @param {string} messageId - Message key from properties file
|
|
103
|
+
* @param {Array} parameters - Parameters for {0}, {1}, etc. substitution
|
|
104
|
+
* @returns {string} Formatted message
|
|
105
|
+
*/
|
|
106
|
+
formatPhrase(messageId, languages, parameters = []) {
|
|
107
|
+
return this._formatMessageFromBundle(this.phrases, languages, messageId, parameters);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
translatePhrase(messageId, languages, parameters = []) {
|
|
111
|
+
return this.formatPhrase(languages, messageId, parameters);
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
translatePhrasePlural(count, messageId, languages, parameters = []) {
|
|
115
|
+
return this.formatPhrasePlural(languages, messageId, count, parameters);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* Format a message with pluralization support
|
|
120
|
+
* @param {Languages} languages - Languages object with preference order
|
|
121
|
+
* @param {string} messageId - Base message key from properties file
|
|
122
|
+
* @param {number} count - Count for pluralization (becomes {0} in final message)
|
|
123
|
+
* @param {Array} parameters - Additional parameters for {1}, {2}, etc. substitution
|
|
124
|
+
* @returns {string} Formatted message
|
|
125
|
+
*/
|
|
126
|
+
formatPhrasePlural(messageId, languages, count, parameters = []) {
|
|
127
|
+
return this._formatMessagePluralFromBundle(this.phrases, languages, messageId, count, parameters);
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
_formatMessageFromBundle(bundles, languages, messageId, parameters = []) {
|
|
131
|
+
// Find the best language bundle that has this message
|
|
132
|
+
const message = this._findMessage(bundles, languages, messageId);
|
|
133
|
+
|
|
134
|
+
if (!message) {
|
|
135
|
+
return messageId; // Fallback to message ID if not found
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
// Substitute parameters {0}, {1}, etc.
|
|
139
|
+
return this._substituteParameters(message.trim(), parameters).replaceAll("''", "'");
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
_formatMessagePluralFromBundle(bundles, languages, messageId, count, parameters = []) {
|
|
143
|
+
// Determine plural form suffix
|
|
144
|
+
const pluralSuffix = count === 1 ? '_one' : '_other';
|
|
145
|
+
const pluralMessageId = messageId + pluralSuffix;
|
|
146
|
+
|
|
147
|
+
// Try to find the plural-specific message first
|
|
148
|
+
let message = this._findMessage(bundles, languages, pluralMessageId);
|
|
149
|
+
|
|
150
|
+
// If not found, fall back to the base message
|
|
151
|
+
if (!message) {
|
|
152
|
+
message = this._findMessage(bundles, languages, messageId);
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
if (!message) {
|
|
156
|
+
return messageId; // Fallback to message ID if not found
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
// Prepend count as parameter 0, shift other parameters
|
|
160
|
+
const allParameters = [count.toString(), ...parameters];
|
|
161
|
+
|
|
162
|
+
// Substitute parameters {0}, {1}, etc.
|
|
163
|
+
return this._substituteParameters(message, allParameters).replaceAll("''", "'");
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
/**
|
|
167
|
+
* Find message in language bundles with fallback logic
|
|
168
|
+
*/
|
|
169
|
+
_findMessage(bundles, languages, messageId) {
|
|
170
|
+
// Try each language in preference order
|
|
171
|
+
if (languages) {
|
|
172
|
+
for (const language of languages) {
|
|
173
|
+
const message = this._getMessageForLanguage(bundles, language.code, messageId);
|
|
174
|
+
if (message) {
|
|
175
|
+
return message;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
// Try language without region (e.g., 'fr' for 'fr-FR')
|
|
179
|
+
if (language.language && language.language !== language.code) {
|
|
180
|
+
const message = this._getMessageForLanguage(bundles, language.language, messageId);
|
|
181
|
+
if (message) {
|
|
182
|
+
return message;
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
// Final fallback to English
|
|
189
|
+
return this._getMessageForLanguage(bundles,'en', messageId);
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
/**
|
|
193
|
+
* Get message for specific language code
|
|
194
|
+
*/
|
|
195
|
+
_getMessageForLanguage(bundles, langCode, messageId) {
|
|
196
|
+
const bundle = bundles.get(langCode);
|
|
197
|
+
return bundle ? bundle[messageId] : null;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
/**
|
|
201
|
+
* Substitute parameters in message string
|
|
202
|
+
* Replaces {0}, {1}, etc. with provided parameters
|
|
203
|
+
*/
|
|
204
|
+
_substituteParameters(message, parameters) {
|
|
205
|
+
if (!parameters || parameters.length === 0) {
|
|
206
|
+
return message;
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
return message.replace(/\{(\d+)\}/g, (match, index) => {
|
|
210
|
+
const paramIndex = parseInt(index);
|
|
211
|
+
return paramIndex < parameters.length ? parameters[paramIndex] : match;
|
|
212
|
+
});
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
/**
|
|
216
|
+
* Get all available language codes
|
|
217
|
+
*/
|
|
218
|
+
getAvailableLanguages() {
|
|
219
|
+
return Array.from(this.bundles.keys());
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
/**
|
|
223
|
+
* Check if a message exists for any language
|
|
224
|
+
*/
|
|
225
|
+
hasMessage(messageId) {
|
|
226
|
+
for (const bundle of this.bundles.values()) {
|
|
227
|
+
if (bundle[messageId]) {
|
|
228
|
+
return true;
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
return false;
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
/**
|
|
235
|
+
* Check if a message exists for any language
|
|
236
|
+
*/
|
|
237
|
+
hasPhrase(messageId) {
|
|
238
|
+
for (const bundle of this.phrases.values()) {
|
|
239
|
+
if (bundle[messageId]) {
|
|
240
|
+
return true;
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
return false;
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
/**
|
|
247
|
+
* Create a linked copy of this I18nSupport instance
|
|
248
|
+
*/
|
|
249
|
+
link() {
|
|
250
|
+
const copy = new I18nSupport(this.translationsPath, this.languageDefinitions);
|
|
251
|
+
copy.bundles = new Map(this.bundles); // Shallow copy of bundles map
|
|
252
|
+
copy.phrases = new Map(this.phrases); // Shallow copy of bundles map
|
|
253
|
+
return copy;
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
module.exports = {
|
|
258
|
+
I18nSupport
|
|
259
|
+
};
|