which-dialect 0.5.9 → 0.5.11

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
@@ -66,7 +66,7 @@ export function createDictionary(options) {
66
66
  // Missing shards simply mean no words start with those letters, so they aren't requested.
67
67
  async function shard(kind, term) {
68
68
  const m = await meta();
69
- const key = shardKey(term, m.shardLength);
69
+ const key = shardKey(term, kind === 'forms' ? (m.forms?.shardLength ?? m.shardLength) : m.shardLength);
70
70
  return m.shards[kind]?.includes(key) ? loadOnce(`${kind}/${key}.json`) : null;
71
71
  }
72
72
  // An inflected form from the forms index as an entry: one sense, "first-person singular present
@@ -110,6 +110,26 @@ export function createDictionary(options) {
110
110
  const m = await meta();
111
111
  return m.syllables ? loadOnce('syllables.json') : {};
112
112
  };
113
+ // Each shard's keys by their plain lowercase form, built once per shard: Spanish forms/de.json has ~49k
114
+ // keys, and stripping accents from all of them on every call ran the checker out of CPU time.
115
+ const plainIndexes = new WeakMap();
116
+ function plainIndex(file) {
117
+ let index = plainIndexes.get(file);
118
+ if (!index) {
119
+ index = new Map();
120
+ for (const key of Object.keys(file)) {
121
+ const lower = key.toLowerCase();
122
+ const p = plain(lower);
123
+ const list = index.get(p);
124
+ if (!list)
125
+ index.set(p, [lower]);
126
+ else if (!list.includes(lower))
127
+ list.push(lower);
128
+ }
129
+ plainIndexes.set(file, index);
130
+ }
131
+ return index;
132
+ }
113
133
  // Variants for languages written in words: other headwords and inflected forms with the same letters
114
134
  // once accents are dropped. Shards are keyed without accents, so they're all in the word's own shards.
115
135
  async function wordVariants(word, limit) {
@@ -119,11 +139,10 @@ export function createDictionary(options) {
119
139
  return [];
120
140
  const [data, forms] = await Promise.all([shard('words', written), shard('forms', written)]);
121
141
  const candidates = new Set();
122
- for (const key of [...Object.keys(data ?? {}), ...Object.keys(forms ?? {})]) {
123
- const lower = key.toLowerCase();
124
- if (lower !== written && plain(lower) === target)
125
- candidates.add(lower);
126
- }
142
+ for (const file of [data, forms])
143
+ for (const lower of file ? plainIndex(file).get(target) ?? [] : [])
144
+ if (lower !== written)
145
+ candidates.add(lower);
127
146
  const found = await Promise.all([...candidates].map(async (c) => ({ word: c, entries: await lookup(c) })));
128
147
  const frequency = (entries) => {
129
148
  const known = entries.map((e) => e.frequency).filter((f) => f !== undefined);
@@ -109,8 +109,9 @@ export function createPhrasebook(options = {}) {
109
109
  if (last < frame.text.length)
110
110
  parts.push({ text: frame.text.slice(last), kind: 'fixed' });
111
111
  let text = tidy(parts.map((p) => p.text).join(''));
112
+ // The first letter, after any opening mark (Spanish "¿quieres…" → "¿Quieres…").
112
113
  if (!frame.clause)
113
- text = text.charAt(0).toUpperCase() + text.slice(1);
114
+ text = text.replace(/^([¿¡]?)(\p{L})/u, (_, mark, c) => mark + c.toUpperCase());
114
115
  const slots = Object.entries(frame.slots).map(([name, pos]) => ({ name, pos }));
115
116
  const en = Object.keys(frame.slots).reduce((s, name) => (typeof values[name] === 'string' ? s.replace(`{${name}}`, values[name]) : s), frame.en[0]);
116
117
  return {
package/dist/types.d.ts CHANGED
@@ -123,11 +123,14 @@ export type LanguageMeta = {
123
123
  * The language's inflected forms are in a compact index (forms/<shard>.json, see FormShard) rather than
124
124
  * stored as entries: Spanish's conjugations and plurals are most of its source and would triple its
125
125
  * data. `descriptions` are what each form is, with "{}" where the lemma goes ("first-person singular
126
- * present indicative of {}"); a stored form points into it.
126
+ * present indicative of {}"); a stored form points into it. `shardLength`: letters per forms/ shard key
127
+ * when it differs from the words' (Spanish uses 3: two-letter form shards reached 2 MB, too much to
128
+ * parse per word in a serverless function).
127
129
  */
128
130
  forms?: {
129
131
  descriptions: string[];
130
132
  count: number;
133
+ shardLength?: number;
131
134
  };
132
135
  };
133
136
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "which-dialect",
3
- "version": "0.5.9",
3
+ "version": "0.5.11",
4
4
  "description": "Translate words between languages and dialects, meaning by meaning, starting with Vietnamese (Northern, Central, Southern), Spanish (by country) and English, with Wiktionary data loaded on demand. More languages are planned.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",