feature-extraction · text (50+ languages) · WASM · ~118 MB
Most embedders on this site speak English. This one is cross-lingual: it was distilled so that a sentence and its translation land at almost the same point in a shared 384-dimensional space. "The weather is nice today", "Il fait beau aujourd'hui" and "今日はいい天気です" get near-identical vectors — so cosine similarity measures meaning, not language. Type lines in any mix of languages to build a cross-language similarity matrix, then search with an English query and watch it surface the matching French or Japanese passage above an unrelated English one. Nothing leaves your device.
| Model | Xenova/paraphrase-multilingual-MiniLM-L12-v2 (ONNX of sentence-transformers) |
|---|---|
| Task / pipeline | feature-extraction |
| Architecture | BERT-style encoder (12 layers, ~118M params) → 384-dimensional sentence embedding |
| Languages | 50+ — trained by multilingual knowledge distillation so translations share one space |
| Pooling | mask-aware mean pooling, then L2-normalize — and no instruction prefix (embed query and doc identically, in any language) |
| Quantization | q8 (8-bit) ONNX |
| Backend | WebAssembly (runs anywhere; no WebGPU needed) |
| Download | ~118 MB, cached after first load |
| License | Apache-2.0 (sentence-transformers) |
| Web APIs | WebAssembly, Web Workers — all Baseline widely available |
Put one sentence per line — mix languages freely. The matrix shows the cosine similarity between every pair (1.00 = identical direction). The 2D map is a PCA projection coloured by language — if the model works, points cluster by meaning, not by colour. Then run the cross-lingual search below.
Green badge = a hit in a different language from your query. That's the whole point: the English query finds its Spanish/French/Japanese answer.
The encoder emits one 384-number vector per token; the model mean-pools them (mask-aware) and L2-normalizes, so every sentence becomes a unit-length arrow and cosine similarity is a plain dot product. Pick a sentence to see its real vector and pre-normalization magnitude.
First 96 of 384 dimensions (blue = positive, orange = negative, brighter = larger magnitude):
Type one sentence and translate it into a few languages (edit the lines). All the vectors should be mutually close — a bright, uniform matrix — because they all mean the same thing. A monolingual embedder would score these near zero; this one keeps them together. The last "distractor" line means something different and should stay dark.
A cross-lingual embedder collapses the "one index per language" problem into a single vector space. You embed everything — questions, documents, product reviews, support tickets — into the same 384-d space regardless of language, and nearest-neighbour search just works across the whole multilingual corpus. No translation round-trip, no per-language model, and the text never leaves the device.
Do a sentence and its translation mean the same thing? One cross-lingual cosine number.
Cross-language semantic search and dedup over a mixed-language corpus.
Cluster mixed-language text by meaning — watch the groups ignore language entirely.
Retrieve cross-lingually, then translate the winning passage to English with M2M100.
Contrast with the English-only MiniLM-L6 and GTE-small: same mean-pool recipe, but this one shares a space across 50+ languages.
Same feature-extraction recipe as any sentence embedder — the difference is entirely in the weights:
import { pipeline } from "@huggingface/transformers";
const extract = await pipeline(
"feature-extraction",
"Xenova/paraphrase-multilingual-MiniLM-L12-v2",
); // downloads + caches ~118 MB once
// Mean pooling, no instruction prefix — embed a query and a doc IN ANY LANGUAGE the same way:
const out = await extract(["I can't sign in", "¿Cómo restablezco mi contraseña?"], {
pooling: "mean",
normalize: true,
});
const [q, d] = out.tolist();
// unit-length vectors → cosine similarity is just the dot product:
const sim = q.reduce((s, x, i) => s + x * d[i], 0); // high — same meaning, different languages
This page asks the worker for the un-normalized pooled vectors so "See inside" can show the real pre-normalization magnitude, then normalizes them in JS. Inference runs in a Web Worker so the matrix, projection and search never jank the page.