Install any skill in seconds. Free to start, no credit card required.
Get Started Free →Create a minimal working Lokalise example. Use when starting a new Lokalise integration, testing your setup, or learning basic Lokalise API patterns. Trigger with phrases like "lokalise hello world", "lokalise example", "lokalise quick start", "simple lokalise code".
.claude/skills/jeremylongshore-lokalise-hello-world/SKILL.md| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-01 | ✗→✓ | ▲ Improved | 16% | 0% |
| case-02 | ✗→✓ | ▲ Improved | 130% | 0% |
| case-03 | ✗→✓ | ▲ Improved | 60% | 0% |
| case-07 | ✗→✓ | ▲ Improved | 11% | 0% |
| case-08 | ✗→✓ | ▲ Improved | 128% | 0% |
End-to-end walkthrough: list projects, create a test project, add keys, set translations across languages, and retrieve them. Covers both the Node SDK (@lokalise/node-api) and the CLI (lokalise2).
LOKALISE_API_TOKEN@lokalise/node-api installed (npm i @lokalise/node-api)brew install lokalise2 or binary releases)typescriptimport { LokaliseApi } from "@lokalise/node-api"; const client = new LokaliseApi({ apiKey: process.env.LOKALISE_API_TOKEN! }); const projects = await client.projects().list({ page: 1, limit: 20 }); for (const p of projects.items) { console.log(`${p.project_id} ${p.name} (${p.statistics.languages} languages)`); }
bashset -euo pipefail lokalise2 --token "$LOKALISE_API_TOKEN" project list
typescriptconst project = await client.projects().create({ name: "hello-world-test", description: "Quick start demo", languages: [ { lang_iso: "en", custom_name: "English" }, { lang_iso: "fr", custom_name: "French" }, { lang_iso: "de", custom_name: "German" }, ], base_language_iso: "en", }); const PROJECT_ID = project.project_id; console.log(`Created project: ${PROJECT_ID}`);
typescriptconst keys = await client.keys().create({ project_id: PROJECT_ID, keys: [ { key_name: { web: "greeting.hello" }, platforms: ["web"], translations: [{ language_iso: "en", translation: "Hello" }], }, { key_name: { web: "greeting.goodbye" }, platforms: ["web"], translations: [{ language_iso: "en", translation: "Goodbye" }], }, { key_name: { web: "app.title" }, platforms: ["web"], translations: [{ language_iso: "en", translation: "My Application" }], }, ], }); console.log(`Created ${keys.items.length} keys`);
typescriptconst allKeys = await client.keys().list({ project_id: PROJECT_ID, limit: 100, }); const translations: Record<string, Record<string, string>> = { "greeting.hello": { fr: "Bonjour", de: "Hallo" }, "greeting.goodbye": { fr: "Au revoir", de: "Auf Wiedersehen" }, "app.title": { fr: "Mon Application", de: "Meine Anwendung" }, }; for (const key of allKeys.items) { const keyName = key.key_name.web; const langs = translations[keyName]; if (!langs) continue; for (const [langIso, value] of Object.entries(langs)) { const existing = key.translations.find( (t: { language_iso: string }) => t.language_iso === langIso ); if (existing) { await client.translations().update(existing.translation_id, { project_id: PROJECT_ID, translation: value, }); } } } console.log("Translations set for fr and de");
typescriptconst result = await client.translations().list({ project_id: PROJECT_ID, page: 1, limit: 100, }); const grouped = new Map<number, { key: string; langs: Record<string, string> }>(); for (const t of result.items) { if (!grouped.has(t.key_id)) { grouped.set(t.key_id, { key: `key:${t.key_id}`, langs: {} }); } grouped.get(t.key_id)!.langs[t.language_iso] = t.translation; } for (const [, entry] of grouped) { console.log(`\n${entry.key}`); for (const [lang, text] of Object.entries(entry.langs)) { console.log(` ${lang}: ${text}`); } }
bashset -euo pipefail PROJECT_ID="YOUR_PROJECT_ID" # List keys lokalise2 --token "$LOKALISE_API_TOKEN" key list \ --project-id "$PROJECT_ID" \ --limit 100 # Export all translations as JSON lokalise2 --token "$LOKALISE_API_TOKEN" file download \ --project-id "$PROJECT_ID" \ --format json \ --original-filenames=false \ --bundle-structure "%LANG_ISO%.json" \ --unzip-to ./locales
./locales/ (if CLI step run)| Error | Cause | Solution | |-------|-------|----------| | 401 Unauthorized | Invalid or expired API token | Verify LOKALISE_API_TOKEN is set and valid | | 400 Bad Request | Missing required fields (e.g., key_name) | Check payload matches API schema | | 404 Not Found | Project ID does not exist | Run project list to get correct ID | | 429 Too Many Requests | Exceeded 6 req/sec rate limit | Add 170ms delay between calls or batch operations | | Cannot find module | SDK not installed | Run npm i @lokalise/node-api |
typescript// hello-lokalise.ts — run with: npx tsx hello-lokalise.ts import { LokaliseApi } from "@lokalise/node-api"; const api = new LokaliseApi({ apiKey: process.env.LOKALISE_API_TOKEN! }); // Create project const proj = await api.projects().create({ name: `demo-${Date.now()}`, languages: [{ lang_iso: "en" }, { lang_iso: "es" }], base_language_iso: "en", }); // Add a key with translations await api.keys().create({ project_id: proj.project_id, keys: [{ key_name: { web: "welcome" }, platforms: ["web"], translations: [ { language_iso: "en", translation: "Welcome" }, { language_iso: "es", translation: "Bienvenido" }, ], }], }); // Read it back const translations = await api.translations().list({ project_id: proj.project_id, limit: 10, }); for (const t of translations.items) { console.log(`[${t.language_iso}] ${t.translation}`); } // Cleanup await api.projects().delete(proj.project_id); console.log("Project deleted");
bashset -euo pipefail # Create project PROJECT=$(lokalise2 --token "$LOKALISE_API_TOKEN" project create \ --name "cli-test-$(date +%s)" \ --base-language-iso en \ --languages '[{"lang_iso":"en"},{"lang_iso":"ja"}]' 2>&1) PROJECT_ID=$(echo "$PROJECT" | grep -oP 'Project ID: \K[^\s]+') # Upload a source file echo '{"hello":"Hello","bye":"Bye"}' > /tmp/en.json lokalise2 --token "$LOKALISE_API_TOKEN" file upload \ --project-id "$PROJECT_ID" \ --file /tmp/en.json \ --lang-iso en \ --poll echo "Project $PROJECT_ID created and source uploaded"
Proceed to lokalise-local-dev-loop for development workflow setup, or lokalise-core-workflow-a for file upload and key management.
| Case | Status | Duration (ms) | Turns | Tokens | Tool calls | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Without | With | Δ | Without | With | Δ | Without | With | Δ | Without | With | Δ | ||
case-01 | fail→pass | 31,652 | 27,632 | -13% | 1 | 1 | 0% | 5,767 | 6,663 | +16% | 0 | 0 | — |
case-02 | fail→pass | 16,780 | 18,225 | +9% | 1 | 1 | 0% | 2,202 | 5,065 | +130% | 0 | 0 | — |
case-03 | fail→pass | 18,817 | 16,485 | -12% | 1 | 1 | 0% | 3,004 | 4,798 | +60% | 0 | 0 | — |
case-04 | fail→fail | 21,159 | 15,047 | -29% | 1 | 1 | 0% | 2,458 | 4,240 | +72% | 0 | 0 | — |
case-05 | fail→fail | 17,618 | 17,543 | -0% | 1 | 1 | 0% | 2,203 | 4,644 | +111% | 0 | 0 | — |
case-06 | fail→fail | 25,118 | 26,475 | +5% | 1 | 1 | 0% | 2,743 | 5,501 | +101% | 0 | 0 | — |
case-11 | pass→pass | 17,260 | 9,236 | -46% | 1 | 1 | 0% | 3,134 | 2,955 | -6% | 0 | 0 | — |
case-07 | fail→pass | 20,154 | 10,395 | -48% | 1 | 1 | 0% | 2,951 | 3,274 | +11% | 0 | 0 | — |
case-08 | fail→pass | 42,654 | 8,191 | -81% | 1 | 1 | 0% | 1,214 | 2,765 | +128% | 0 | 0 | — |
case-09 | fail→pass | 17,249 | 13,523 | -22% | 1 | 1 | 0% | 1,845 | 3,974 | +115% | 0 | 0 | — |
case-10 | fail→pass | 15,291 | 10,093 | -34% | 1 | 1 | 0% | 1,506 | 3,210 | +113% | 0 | 0 | — |
case-21 | pass→pass | 11,267 | 7,043 | -37% | 1 | 1 | 0% | 894 | 2,531 | +183% | 0 | 0 | — |
case-12 | fail→pass | 16,771 | 8,710 | -48% | 1 | 1 | 0% | 1,851 | 2,973 | +61% | 0 | 0 | — |
case-13 | fail→pass | 21,765 | 18,321 | -16% | 1 | 1 | 0% | 2,396 | 4,584 | +91% | 0 | 0 | — |
case-14 | fail→pass | 14,266 | 8,905 | -38% | 1 | 1 | 0% | 1,750 | 3,124 | +79% | 0 | 0 | — |
case-15 | pass→pass | 6,854 | 9,945 | +45% | 1 | 1 | 0% | 1,175 | 3,166 | +169% | 0 | 0 | — |
case-16 | fail→fail | 14,681 | 5,191 | -65% | 1 | 1 | 0% | 1,608 | 3,225 | +101% | 0 | 0 | — |
case-17 | pass→pass | 11,817 | 16,060 | +36% | 1 | 1 | 0% | 2,086 | 3,902 | +87% | 0 | 0 | — |
case-18 | fail→pass | 18,934 | 15,738 | -17% | 1 | 1 | 0% | 1,958 | 4,228 | +116% | 0 | 0 | — |
case-19 | pass→pass | 12,449 | 7,766 | -38% | 1 | 1 | 0% | 1,042 | 2,764 | +165% | 0 | 0 | — |
case-20 | pass→pass | 16,061 | 7,265 | -55% | 1 | 1 | 0% | 1,521 | 2,623 | +72% | 0 | 0 | — |
case-22 | fail→pass | 14,544 | 2,985 | -79% | 1 | 1 | 0% | 1,261 | 2,866 | +127% | 0 | 0 | — |
case-23 | pass→pass | 11,299 | 18,452 | +63% | 1 | 1 | 0% | 2,011 | 4,879 | +143% | 0 | 0 | — |
DecimalAI ran this skill against gemini-3.6-flash twice over the same eval suite — once with the skill loaded and once without — and compared the two runs case by case. 23 cases were attempted. The headline lift of +52 percentage points is the difference between those two pass rates over the 23 comparable cases.
Without the skill loaded, the model failed this case. With it loaded, the same prompt on the same model passed. This is one improved case from the latest verified run; every case, including any that regressed, is in the table above.
Other measured skills in the registry, with their headline benchmark lift.