
Research
/Security News
TensorLake npm SDK Compromised in ChainDrop Shai-Hulud Credential-Stealing Attack
Tensorlake npm SDK version 0.5.144 was compromised in a ChainDrop / Shai-Hulud attack, delivering credential-stealing malware.
@shipi18n/core
Advanced tools
Translation QA for i18n locale files: placeholder and plural validation, key parity, coverage, and an LLM-as-judge semantic review. Also a structure-preserving translation engine — bring your own OpenAI or Anthropic key.
The engine behind Shipi18n's translation QA — placeholder and plural validation, key parity, coverage and an LLM-as-judge semantic review — plus a structure-preserving translation engine. Open source, bring your own LLM, no account and no hosted API.
npm i @shipi18n/core # checking needs nothing else
npm i @shipi18n/core @anthropic-ai/sdk # add a provider SDK to translate or judge
import { runCheck } from '@shipi18n/core'
// deterministic, no model, no key
const { languages, totals } = runCheck({ input: './locales', source: 'en' })
import { translateJSON } from '@shipi18n/core'
const { result, stats } = await translateJSON({
content: { greeting: 'Hello {{name}}', items: 'You have {{count}} items' },
from: 'en',
to: 'es',
provider: 'anthropic', // 'anthropic' | 'openai' | a custom { complete } adapter
apiKey: process.env.ANTHROPIC_API_KEY, // optional — falls back to the provider's env var
})
console.log(result) // { greeting: 'Hola {{name}}', items: 'Tienes {{count}} elementos' }
console.log(stats) // { translated, reused, placeholderWarnings }
The API key is resolved from apiKey or, if omitted, the provider's env var
(ANTHROPIC_API_KEY / OPENAI_API_KEY). Your key is used to call your LLM directly.
The openai provider also takes a baseURL, which points it at any OpenAI-compatible
endpoint — Ollama (http://localhost:11434/v1, no key needed, fully offline), Gemini's
compatibility endpoint, Groq, Mistral, LM Studio, vLLM, or a corporate gateway:
await translateJSON({
content, from: 'en', to: 'es',
provider: 'openai',
baseURL: 'http://localhost:11434/v1', // Ollama — no apiKey required
model: 'llama3.2',
})
{{name}}, {count}, %s, %d, %1$s, $t(...), %{name}, and HTML tags.existing to reuse prior translations and only translate new/changed keys.const { result } = await translateJSON({
content: source, from: 'en', to: 'fr',
provider: 'anthropic',
existing: previousFrench, // only new/empty keys are sent to the LLM
})
Any object with a complete(prompt, opts) => Promise<string> method works — bring any model:
const myAdapter = {
name: 'my-llm',
async complete(prompt) { /* call your model, return its text */ },
}
await translateJSON({ content, from: 'en', to: 'de', provider: myAdapter })
checkTranslations is the QA half of the engine — deterministic, no model call:
import { checkTranslations } from '@shipi18n/core'
const { findings, stats } = checkTranslations({
source: { greeting: 'Hello {{name}}' },
target: { greeting: 'Hola amigo' }, // dropped {{name}}
targetLang: 'es',
})
// findings[0] → { type: 'placeholder-missing', severity: 'error', path: 'greeting', missing: ['{{name}}'], ... }
// stats → { sourceKeys, targetKeys, missing, errors, warnings, coverage }
Finding types: missing-key, orphan-key, placeholder-missing, placeholder-added,
plural-forms (vue-i18n pipe plurals), plural-category (a plural missing a form the language needs, by CLDR —
ICU plurals and key-based plurals: i18next _one/_few, Rails, Android, .xcstrings), icu-invalid, empty-value,
untranslated, type-mismatch, glossary-violation. All 25 rules, each with
its own page: https://shipi18n.com/docs/cli/commands
reviewTranslations({ source, target, from, to, provider, passes, glossary, cache }) is the
semantic layer: an LLM-as-judge pass (BYO key) with majority voting across passes, strict output
validation, and an incremental cache — unchanged pairs cost zero calls. Judge findings carry
{ path, category, note, votes, passes }.
Format adapters are exported too: parseArbBundle (Flutter ARB), parseXcstrings (Apple String
Catalogs), parseAndroidStrings (Android strings.xml), parsePo (gettext .po/.pot) and
parseXliff (XLIFF 1.2/2.0) normalize those files into plain locale objects that checkTranslations
understands — including %@ / %lld specifiers and plural variations.
translateJSON({ content, from, to, provider, apiKey?, model?, baseURL?, existing? }) → { result, stats }translateStrings(texts, { adapter, from, to, batchSize? }) → string[]flatten(obj) / unflatten(flat)extractPlaceholders(str) / validatePlaceholders(source, translation)getLanguageName(code)anthropicAdapter(config) / openaiAdapter(config) / resolveAdapter(provider, config)Apache-2.0
FAQs
Translation QA for i18n locale files: placeholder and plural validation, key parity, coverage, and an LLM-as-judge semantic review. Also a structure-preserving translation engine — bring your own OpenAI or Anthropic key.
The npm package @shipi18n/core receives a total of 2,223 weekly downloads. As such, @shipi18n/core popularity was classified as popular.
We found that @shipi18n/core demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.

Research
/Security News
Tensorlake npm SDK version 0.5.144 was compromised in a ChainDrop / Shai-Hulud attack, delivering credential-stealing malware.

Research
/Security News
Socket found 16 malicious Firefox extensions designed to steal crypto wallet recovery phrases and private keys using cloned Rabby and OKX interfaces.

Product
Socket now scans VS Code extensions, giving teams early detection of risky behaviors, hidden capabilities, and supply chain threats in developer tools.