langsys-js-typescript 0.6.2 → 0.6.4

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.mjs CHANGED
@@ -287,14 +287,76 @@ function warnUnmatchedParams(source, texts, params, context) {
287
287
  }
288
288
  function interpolate(template, params, locale) {
289
289
  if (isICU(template)) {
290
- try {
291
- return new IntlMessageFormat(template, locale || "en").format(params);
292
- } catch {
293
- return simpleInterpolate(template, params, locale);
290
+ const resolved = locale || "en";
291
+ const hasNullParam = !!params && Object.values(params).some((value) => value === null);
292
+ if (!hasNullParam) {
293
+ try {
294
+ return new IntlMessageFormat(template, resolved).format(params);
295
+ } catch {
296
+ }
297
+ }
298
+ {
299
+ try {
300
+ const ast = new IntlMessageFormat(template, resolved).ast;
301
+ if (!Array.isArray(ast)) return simpleInterpolate(template, params, locale);
302
+ const recovered = _recoverMissingArgs(JSON.parse(JSON.stringify(ast)), params);
303
+ return new IntlMessageFormat(recovered, resolved).format(params);
304
+ } catch {
305
+ return simpleInterpolate(template, params, locale);
306
+ }
294
307
  }
295
308
  }
296
309
  return simpleInterpolate(template, params, locale);
297
310
  }
311
+ var ICU_LITERAL = 0;
312
+ var ICU_ARGUMENT = 1;
313
+ var ICU_NUMBER = 2;
314
+ var ICU_DATE = 3;
315
+ var ICU_TIME = 4;
316
+ var ICU_SELECT = 5;
317
+ var ICU_PLURAL = 6;
318
+ var ICU_POUND = 7;
319
+ var ICU_TAG = 8;
320
+ function _recoverMissingArgs(nodes, params) {
321
+ const out = [];
322
+ for (const node of nodes) {
323
+ const name = node.value;
324
+ const value = name !== void 0 && name in params ? params[name] : void 0;
325
+ const supplied = value !== void 0 && value !== null;
326
+ if (node.type === ICU_TAG) {
327
+ out.push({ ...node, children: _recoverMissingArgs(node.children ?? [], params) });
328
+ continue;
329
+ }
330
+ if (node.type === ICU_SELECT || node.type === ICU_PLURAL) {
331
+ if (supplied) {
332
+ const options = {};
333
+ for (const [key, branch2] of Object.entries(node.options ?? {})) {
334
+ options[key] = { value: _recoverMissingArgs(branch2.value, params) };
335
+ }
336
+ out.push({ ...node, options });
337
+ continue;
338
+ }
339
+ const other = node.options?.other;
340
+ if (!other) {
341
+ out.push(node);
342
+ continue;
343
+ }
344
+ const branch = _recoverMissingArgs(other.value, params);
345
+ out.push(
346
+ ...branch.map(
347
+ (child) => child.type === ICU_POUND ? { type: ICU_LITERAL, value: `{${name}}` } : child
348
+ )
349
+ );
350
+ continue;
351
+ }
352
+ if (!supplied && (node.type === ICU_ARGUMENT || node.type === ICU_NUMBER || node.type === ICU_DATE || node.type === ICU_TIME)) {
353
+ out.push({ type: ICU_LITERAL, value: `{${name}}` });
354
+ continue;
355
+ }
356
+ out.push(node);
357
+ }
358
+ return out;
359
+ }
298
360
  function simpleInterpolate(template, params, locale) {
299
361
  return template.replace(/\{([^{},]+)\}/g, (match, rawKey) => {
300
362
  const key = rawKey.trim();
@@ -1074,8 +1136,14 @@ var TRANSLATABLE_ATTRIBUTES = [
1074
1136
  "placeholder",
1075
1137
  "alt",
1076
1138
  "title",
1139
+ "label",
1140
+ // <option>, <optgroup>, <track> — the text a user reads in the picker
1077
1141
  "aria-label",
1078
1142
  "aria-placeholder",
1143
+ "aria-description",
1144
+ "aria-valuetext",
1145
+ // the spoken value of a slider/meter
1146
+ "aria-roledescription",
1079
1147
  "data-error",
1080
1148
  "data-error-message",
1081
1149
  "data-validation-message",
@@ -1192,9 +1260,15 @@ async function registerContentBlock(contentBlock) {
1192
1260
  function tokenizeElement(element) {
1193
1261
  const tokens = [];
1194
1262
  const clone = element.cloneNode(true);
1195
- _walkForTokens(element, Array.from(clone.childNodes), tokens, []);
1263
+ _walkForTokens(element, Array.from(clone.childNodes), tokens, [], false, true);
1196
1264
  return { tokens, content: normalizeMarkupPlaceholders(clone.outerHTML) };
1197
1265
  }
1266
+ function legacyTokenizeElement(element) {
1267
+ const tokens = [];
1268
+ const clone = element.cloneNode(true);
1269
+ _walkForTokens(element, Array.from(clone.childNodes), tokens, [], true, false);
1270
+ return tokens;
1271
+ }
1198
1272
  function _writeKnownContentBlockToCache(category, customId) {
1199
1273
  const lookupCat = category || "__uncategorized__";
1200
1274
  sTranslations.update((current) => {
@@ -1208,18 +1282,18 @@ function _writeKnownContentBlockToCache(category, customId) {
1208
1282
  return { ...current };
1209
1283
  });
1210
1284
  }
1211
- function _walkForTokens(liveRoot, cloneNodes, tokens, indices) {
1285
+ function _walkForTokens(liveRoot, cloneNodes, tokens, indices, duplicateSelectOptions, applyStyles) {
1212
1286
  cloneNodes.forEach((node, index) => {
1213
1287
  if (node.nodeType === Node.ELEMENT_NODE) {
1214
1288
  const el = node;
1215
1289
  if (isTranslationExcluded(el)) return;
1216
1290
  if (isPhraseMarked(el)) return;
1217
1291
  }
1218
- if (node.hasChildNodes()) {
1292
+ if (applyStyles && node.hasChildNodes()) {
1219
1293
  _applyStylesToClone(liveRoot, node, [...indices, index]);
1220
1294
  }
1221
1295
  if (node.nodeType === Node.ELEMENT_NODE) {
1222
- _tokenizeAttributes(node, tokens);
1296
+ _tokenizeAttributes(node, tokens, duplicateSelectOptions);
1223
1297
  }
1224
1298
  const contentToken = node.nodeValue?.replace(/\s+/g, " ").trim();
1225
1299
  if (node.nodeType === Node.TEXT_NODE && contentToken) {
@@ -1227,10 +1301,10 @@ function _walkForTokens(liveRoot, cloneNodes, tokens, indices) {
1227
1301
  return;
1228
1302
  }
1229
1303
  if (!node.hasChildNodes()) return;
1230
- _walkForTokens(liveRoot, Array.from(node.childNodes), tokens, [...indices, index]);
1304
+ _walkForTokens(liveRoot, Array.from(node.childNodes), tokens, [...indices, index], duplicateSelectOptions, applyStyles);
1231
1305
  });
1232
1306
  }
1233
- function _tokenizeAttributes(element, tokens) {
1307
+ function _tokenizeAttributes(element, tokens, duplicateSelectOptions) {
1234
1308
  const tagName = element.tagName.toLowerCase();
1235
1309
  if (tagName === "img") {
1236
1310
  const img = element;
@@ -1251,7 +1325,7 @@ function _tokenizeAttributes(element, tokens) {
1251
1325
  if (value) tokens.push(normalizeMarkupPlaceholders(value));
1252
1326
  }
1253
1327
  }
1254
- if (tagName === "select") {
1328
+ if (duplicateSelectOptions && tagName === "select") {
1255
1329
  const options = element.querySelectorAll("option");
1256
1330
  options.forEach((option) => {
1257
1331
  const optionText = option.textContent?.trim();
@@ -1377,9 +1451,15 @@ var Translate = class {
1377
1451
  return;
1378
1452
  }
1379
1453
  if (derivedId) {
1380
- const legacyId = generateLegacyCustomId(contentBlock.category, contentBlock.tokens);
1381
- if (legacyId !== this.custom_id && isContentBlockKnown(contentBlock.category, legacyId)) {
1382
- this.custom_id = legacyId;
1454
+ const legacyTokens = legacyTokenizeElement(this.element);
1455
+ const candidates = [
1456
+ generateCustomId(contentBlock.category, legacyTokens),
1457
+ generateLegacyCustomId(contentBlock.category, legacyTokens)
1458
+ ];
1459
+ for (const candidate of candidates) {
1460
+ if (candidate === this.custom_id) continue;
1461
+ if (!isContentBlockKnown(contentBlock.category, candidate)) continue;
1462
+ this.custom_id = candidate;
1383
1463
  if (this.tokens.length > 1 && this.element) {
1384
1464
  this.translate(Array.from(this.element.childNodes));
1385
1465
  this.lastTranslatedLocale = currentlyLoadedLocale.get();
@@ -1643,6 +1723,6 @@ var t = ((phrase, ...rest) => {
1643
1723
  });
1644
1724
  var tSignal = LangsysApp.Translations.tSignal;
1645
1725
 
1646
- export { LangsysApp, LangsysAppAPI, Logger, PHRASE_MARKER_ATTR, PHRASE_MARKER_ATTRS, Phrase, Translate, Translations, canonicalizeLocale, createSignal, currentlyLoadedLocale, encodeRichText, findUnusedParamKeys, generateCustomId, generateLegacyCustomId, getValue, interpolate, isContentBlockKnown, isEmpty, isICU, isPhraseMarked, isTranslationExcluded, logger, markupTokenValues, md5, md5Legacy, normalizeMarkupPlaceholders, persist, reconstitute, registerContentBlock, sTranslations, stripSentinels, t, tSignal, tokenizeElement };
1726
+ export { LangsysApp, LangsysAppAPI, Logger, PHRASE_MARKER_ATTR, PHRASE_MARKER_ATTRS, Phrase, Translate, Translations, canonicalizeLocale, createSignal, currentlyLoadedLocale, encodeRichText, findUnusedParamKeys, generateCustomId, generateLegacyCustomId, getValue, interpolate, isContentBlockKnown, isEmpty, isICU, isPhraseMarked, isTranslationExcluded, legacyTokenizeElement, logger, markupTokenValues, md5, md5Legacy, normalizeMarkupPlaceholders, persist, reconstitute, registerContentBlock, sTranslations, stripSentinels, t, tSignal, tokenizeElement };
1647
1727
  //# sourceMappingURL=index.mjs.map
1648
1728
  //# sourceMappingURL=index.mjs.map