Claude-skill-registry lokalise-cost-tuning

install
source · Clone the upstream repo
git clone https://github.com/majiayu000/claude-skill-registry
Claude Code · Install into ~/.claude/skills/
T=$(mktemp -d) && git clone --depth=1 https://github.com/majiayu000/claude-skill-registry "$T" && mkdir -p ~/.claude/skills && cp -r "$T/skills/data/lokalise-cost-tuning" ~/.claude/skills/majiayu000-claude-skill-registry-lokalise-cost-tuning && rm -rf "$T"
manifest: skills/data/lokalise-cost-tuning/SKILL.md
source content

Lokalise Cost Tuning

Overview

Optimize Lokalise costs through smart plan selection, usage monitoring, and efficient workflows.

Prerequisites

  • Access to Lokalise billing dashboard
  • Understanding of current usage patterns
  • Database for usage tracking (optional)
  • Alerting system configured (optional)

Lokalise Pricing Overview

Plans (2025)

PlanPriceIncludedBest For
Free$01 project, 500 keysPersonal/testing
Essential$120/moUnlimited projects, 2K keys/projectSmall teams
Pro$400/moUnlimited keys, OTA, FigmaGrowing teams
EnterpriseCustomSSO, dedicated support, SLALarge organizations

Key Cost Factors

  • Number of translation keys
  • Number of target languages
  • Machine translation usage
  • Professional translation orders
  • OTA bandwidth (mobile apps)

Instructions

Step 1: Analyze Current Usage

import { LokaliseApi } from "@lokalise/node-api";

async function analyzeUsage(): Promise<UsageReport> {
  const client = new LokaliseApi({
    apiKey: process.env.LOKALISE_API_TOKEN!,
  });

  const projects = await client.projects().list();
  const usage: UsageReport = {
    totalProjects: projects.items.length,
    totalKeys: 0,
    totalLanguages: 0,
    projectDetails: [],
  };

  for (const project of projects.items) {
    const stats = project.statistics;

    usage.totalKeys += stats.keys_total;
    usage.totalLanguages += stats.languages;

    usage.projectDetails.push({
      name: project.name,
      projectId: project.project_id,
      keys: stats.keys_total,
      languages: stats.languages,
      baseWords: stats.base_words,
      progress: stats.progress_total,
    });
  }

  return usage;
}

interface UsageReport {
  totalProjects: number;
  totalKeys: number;
  totalLanguages: number;
  projectDetails: Array<{
    name: string;
    projectId: string;
    keys: number;
    languages: number;
    baseWords: number;
    progress: number;
  }>;
}

Step 2: Identify Cost Optimization Opportunities

function analyzeOptimizations(usage: UsageReport): Recommendation[] {
  const recommendations: Recommendation[] = [];

  // Check for unused projects
  for (const project of usage.projectDetails) {
    if (project.keys < 10) {
      recommendations.push({
        type: "unused_project",
        severity: "low",
        message: `Project "${project.name}" has only ${project.keys} keys. Consider archiving.`,
        potentialSavings: "Reduce clutter, potential plan downgrade",
      });
    }

    // Check for duplicate/similar keys
    if (project.keys > 1000) {
      recommendations.push({
        type: "key_audit",
        severity: "medium",
        message: `Project "${project.name}" has ${project.keys} keys. Review for duplicates.`,
        potentialSavings: "5-15% key reduction typical",
      });
    }

    // Check for low-progress languages
    if (project.progress < 50 && project.languages > 3) {
      recommendations.push({
        type: "unused_languages",
        severity: "medium",
        message: `Project "${project.name}" has ${project.languages} languages at ${project.progress}% progress.`,
        potentialSavings: "Remove unused target languages",
      });
    }
  }

  // Plan recommendation
  if (usage.totalKeys < 2000 && usage.totalProjects <= 3) {
    recommendations.push({
      type: "plan_downgrade",
      severity: "high",
      message: "Current usage fits Essential plan",
      potentialSavings: "Potential $280/mo savings vs Pro",
    });
  }

  return recommendations;
}

Step 3: Implement Usage Monitoring

interface UsageMetrics {
  date: Date;
  keysCreated: number;
  keysDeleted: number;
  translationsUpdated: number;
  mtCharacters: number;  // Machine translation
  apiCalls: number;
}

class LokaliseUsageMonitor {
  private metrics: UsageMetrics[] = [];

  trackApiCall(operation: string, details?: any) {
    // Track API usage
    console.log({
      timestamp: new Date().toISOString(),
      operation,
      details,
    });
  }

  async getMonthlyReport(): Promise<MonthlyReport> {
    const client = new LokaliseApi({
      apiKey: process.env.LOKALISE_API_TOKEN!,
    });

    const projects = await client.projects().list();

    let totalKeys = 0;
    let totalMTCharacters = 0;

    for (const project of projects.items) {
      totalKeys += project.statistics.keys_total;
      // Note: MT usage requires checking orders/billing API
    }

    return {
      month: new Date().toISOString().slice(0, 7),
      totalKeys,
      estimatedCost: this.estimateCost(totalKeys),
    };
  }

  private estimateCost(keys: number): number {
    // Simplified estimation based on plan tiers
    if (keys <= 500) return 0;  // Free tier
    if (keys <= 2000) return 120;  // Essential
    return 400;  // Pro
  }
}

Step 4: Clean Up Unused Resources

async function cleanupUnusedKeys(projectId: string, dryRun = true) {
  const client = new LokaliseApi({
    apiKey: process.env.LOKALISE_API_TOKEN!,
  });

  // Find archived keys
  const archivedKeys = await client.keys().list({
    project_id: projectId,
    filter_archived: "include",
    limit: 500,
  });

  const toDelete = archivedKeys.items.filter(k => k.is_archived);
  console.log(`Found ${toDelete.length} archived keys`);

  if (dryRun) {
    console.log("DRY RUN - would delete:", toDelete.map(k => k.key_name.web));
    return { deleted: 0, archived: toDelete.length };
  }

  // Actually delete
  for (const key of toDelete) {
    await client.keys().delete(key.key_id, { project_id: projectId });
  }

  return { deleted: toDelete.length };
}

async function removeUnusedLanguages(projectId: string, threshold = 10) {
  const client = new LokaliseApi({
    apiKey: process.env.LOKALISE_API_TOKEN!,
  });

  const languages = await client.languages().list({ project_id: projectId });

  const unused = languages.items.filter(
    lang => (lang.statistics?.progress ?? 0) < threshold && !lang.is_default
  );

  console.log(`Languages below ${threshold}% progress:`,
    unused.map(l => `${l.lang_name} (${l.statistics?.progress}%)`));

  // Don't auto-delete - just report
  return unused;
}

Output

  • Usage analysis complete
  • Cost optimization recommendations
  • Usage monitoring implemented
  • Cleanup scripts for unused resources

Error Handling

IssueCauseSolution
Unexpected chargesUntracked MT usageMonitor orders API
Key limit exceededOrganic growthArchive or delete unused
Overage feesWrong planUpgrade before hitting limits
Budget exceededNo monitoringSet up usage alerts

Examples

Quick Usage Check

const report = await analyzeUsage();
console.log(`Total Projects: ${report.totalProjects}`);
console.log(`Total Keys: ${report.totalKeys}`);
console.log(`Estimated Plan: ${report.totalKeys < 500 ? 'Free' : report.totalKeys < 2000 ? 'Essential' : 'Pro'}`);

Machine Translation Cost Estimate

// Lokalise MT pricing varies by provider and language pair
function estimateMTCost(
  characters: number,
  provider: "google" | "deepl" | "amazon" = "google"
): number {
  const rates: Record<string, number> = {
    google: 0.02,  // $20 per million characters
    deepl: 0.025,  // $25 per million characters
    amazon: 0.015, // $15 per million characters
  };

  return (characters / 1_000_000) * rates[provider];
}

Budget Alert Script

async function checkBudget(budgetKeys: number): Promise<boolean> {
  const usage = await analyzeUsage();

  if (usage.totalKeys > budgetKeys * 0.9) {
    console.warn(`WARNING: Approaching key limit (${usage.totalKeys}/${budgetKeys})`);

    // Send alert
    await sendSlackAlert({
      channel: "#billing",
      text: `Lokalise key usage at ${Math.round((usage.totalKeys / budgetKeys) * 100)}%`,
    });

    return false;
  }

  return true;
}

Cost Comparison Report

## Lokalise Cost Analysis

### Current Usage
- Projects: 5
- Total Keys: 3,500
- Languages: 8

### Current Plan: Pro ($400/mo)

### Recommendations
1. Archive 2 unused projects (-500 keys)
2. Remove 3 low-progress languages
3. Delete 200 archived keys
4. **Potential: Essential plan at $120/mo**

### Annual Savings: $3,360

Resources

Next Steps

For architecture patterns, see

lokalise-reference-architecture
.