lokalise-multi-env-setup
Configure Lokalise across development, staging, and production environments. Use when setting up multi-environment deployments, configuring per-environment secrets, or implementing environment-specific Lokalise configurations. Trigger with phrases like "lokalise environments", "lokalise staging", "lokalise dev prod", "lokalise environment setup", "lokalise config by env".
What this skill does
# Lokalise Multi-Environment Setup
## Overview
Configure Lokalise for isolated development, staging, and production environments. Two strategies are covered: separate Lokalise projects per environment (strongest isolation) and Lokalise branching within a single project (simpler management). Both approaches include secret management, environment-aware configuration, and a promotion workflow that moves translations through the pipeline from dev to production without cross-contamination.
## Prerequisites
- Lokalise Team or Enterprise plan (branching requires Team plan or higher)
- One Lokalise API token per environment, each scoped to minimum required permissions
- Secret management system: GitHub Secrets, AWS Secrets Manager, GCP Secret Manager, or HashiCorp Vault
- Node.js 18+ with `@lokalise/node-api` SDK installed
- Environment variable `NODE_ENV` (or equivalent) set in each deployment target
## Instructions
### Step 1: Choose Your Strategy
**Option A — Separate projects per environment** (recommended for teams > 5 translators or strict compliance):
| Environment | Lokalise Project | Purpose |
|-------------|-----------------|---------|
| Development | `MyApp (Dev)` | Rapid iteration, machine translations OK |
| Staging | `MyApp (Staging)` | QA review, translator proofing |
| Production | `MyApp (Prod)` | Approved translations only |
**Option B — Single project with Lokalise branching** (simpler for small teams):
| Branch | Purpose |
|--------|---------|
| `main` | Production translations |
| `staging` | QA translations under review |
| `dev` | Work-in-progress translations |
### Step 2: Environment-Aware Configuration
Create a configuration module that selects the correct Lokalise project and credentials based on the runtime environment:
```typescript
// src/config/lokalise.ts
interface LokaliseEnvConfig {
environment: string;
apiToken: string;
projectId: string;
branch?: string; // Only used with Option B (branching)
cacheTtlMs: number;
enableOta: boolean;
fallbackLocale: string;
rateLimitPerSec: number;
}
const ENV_CONFIGS: Record<string, Omit<LokaliseEnvConfig, 'apiToken' | 'projectId'>> = {
development: {
environment: 'development',
cacheTtlMs: 0, // No cache in dev — always fetch fresh
enableOta: false,
fallbackLocale: 'en',
rateLimitPerSec: 6,
},
staging: {
environment: 'staging',
cacheTtlMs: 5 * 60_000, // 5 minutes
enableOta: true,
fallbackLocale: 'en',
rateLimitPerSec: 6,
},
production: {
environment: 'production',
cacheTtlMs: 30 * 60_000, // 30 minutes
enableOta: true,
fallbackLocale: 'en',
rateLimitPerSec: 4, // Conservative — leave headroom for other integrations
},
};
export function getLokaliseConfig(): LokaliseEnvConfig {
const env = process.env.NODE_ENV || 'development';
const base = ENV_CONFIGS[env];
if (!base) {
throw new Error(`Unknown environment: ${env}. Expected: ${Object.keys(ENV_CONFIGS).join(', ')}`);
}
const apiToken = process.env.LOKALISE_API_TOKEN;
const projectId = process.env.LOKALISE_PROJECT_ID;
if (!apiToken) {
throw new Error('LOKALISE_API_TOKEN is not set');
}
if (!projectId) {
throw new Error('LOKALISE_PROJECT_ID is not set');
}
return {
...base,
apiToken,
projectId,
branch: process.env.LOKALISE_BRANCH, // Optional: for branching strategy
};
}
```
### Step 3: Secret Management
Store API tokens securely in each environment. Never commit tokens to source control.
**GitHub Actions (CI/CD):**
```yaml
# .github/workflows/deploy.yml
jobs:
deploy-staging:
environment: staging
env:
LOKALISE_API_TOKEN: ${{ secrets.LOKALISE_API_TOKEN_STAGING }}
LOKALISE_PROJECT_ID: ${{ vars.LOKALISE_PROJECT_ID_STAGING }}
steps:
- run: npm run build
deploy-production:
environment: production
env:
LOKALISE_API_TOKEN: ${{ secrets.LOKALISE_API_TOKEN_PROD }}
LOKALISE_PROJECT_ID: ${{ vars.LOKALISE_PROJECT_ID_PROD }}
steps:
- run: npm run build
```
**AWS Secrets Manager:**
```typescript
import { SecretsManagerClient, GetSecretValueCommand } from '@aws-sdk/client-secrets-manager';
async function getLokaliseToken(environment: string): Promise<string> {
const client = new SecretsManagerClient({ region: 'us-east-1' });
const command = new GetSecretValueCommand({
SecretId: `lokalise/${environment}/api-token`,
});
const response = await client.send(command);
return response.SecretString!;
}
```
**GCP Secret Manager:**
```typescript
import { SecretManagerServiceClient } from '@google-cloud/secret-manager';
async function getLokaliseToken(environment: string): Promise<string> {
const client = new SecretManagerServiceClient();
const [version] = await client.accessSecretVersion({
name: `projects/my-project/secrets/lokalise-token-${environment}/versions/latest`,
});
return version.payload!.data!.toString();
}
```
**HashiCorp Vault:**
```bash
# Read token from Vault
vault kv get -field=api_token secret/lokalise/production
```
### Step 4: Lokalise Branching (Option B Alternative)
If using a single project with branching instead of separate projects:
```typescript
import { LokaliseApi } from '@lokalise/node-api';
const lokalise = new LokaliseApi({ apiKey: process.env.LOKALISE_API_TOKEN! });
const projectId = process.env.LOKALISE_PROJECT_ID!;
// Create a branch for a new environment or feature
async function createBranch(branchName: string): Promise<void> {
await lokalise.branches().create({ name: branchName }, { project_id: projectId });
console.log(`Created branch: ${branchName}`);
}
// Download translations from a specific branch
async function downloadFromBranch(branchName: string, outputDir: string): Promise<void> {
const response = await lokalise.files().download(`${projectId}:${branchName}`, {
format: 'json',
original_filenames: true,
directory_prefix: '',
export_empty_as: 'base',
});
console.log(`Download URL: ${response.bundle_url}`);
// Fetch and extract the zip from response.bundle_url into outputDir
}
// Merge a branch into main after QA approval
async function mergeBranch(sourceBranch: string, targetBranch = 'main'): Promise<void> {
await lokalise.branches().merge(
{ project_id: projectId },
{
source_branch_id: sourceBranch,
target_branch_id: targetBranch,
force_conflict_resolve_using: 'source',
}
);
console.log(`Merged ${sourceBranch} → ${targetBranch}`);
}
```
### Step 5: Promotion Workflow (Dev to Staging to Production)
Promote translations through environments with validation at each gate:
```bash
#!/bin/bash
# scripts/promote-translations.sh
# Usage: ./promote-translations.sh staging (promote dev → staging)
# Usage: ./promote-translations.sh production (promote staging → production)
set -euo pipefail
TARGET_ENV="${1:?Usage: promote-translations.sh <staging|production>}"
case "$TARGET_ENV" in
staging)
SOURCE_TOKEN="$LOKALISE_API_TOKEN_DEV"
SOURCE_PROJECT="$LOKALISE_PROJECT_ID_DEV"
TARGET_TOKEN="$LOKALISE_API_TOKEN_STAGING"
TARGET_PROJECT="$LOKALISE_PROJECT_ID_STAGING"
;;
production)
SOURCE_TOKEN="$LOKALISE_API_TOKEN_STAGING"
SOURCE_PROJECT="$LOKALISE_PROJECT_ID_STAGING"
TARGET_TOKEN="$LOKALISE_API_TOKEN_PROD"
TARGET_PROJECT="$LOKALISE_PROJECT_ID_PROD"
;;
*)
echo "Invalid target: $TARGET_ENV (expected staging or production)"
exit 1
;;
esac
TEMP_DIR=$(mktemp -d)
trap 'rm -rf "$TEMP_DIR"' EXIT
echo "=== Step 1: Download from source ==="
lokalise2 file download \
--token "$SOURCE_TOKEN" \
--project-id "$SOURCE_PROJECT" \
--format json \
--original-filenames=true \
--directory-prefix="" \
--export-empty-as=skip \
--unzip-to "$TEMP_DIR/"
echo "=== Step 2: Validate completeness ==="
SOURCE_FILE="$TEMP_DIR/en.json"
if [[ ! -f "$SOURCE_FILE" ]]; then
echo "ERROR: Source locale file not found"
exit 1
fi
SOURCE_KRelated in General
modeling-omnistudio-epc-catalog
IncludedSalesforce Industries CME EPC product-modeling skill for Product2-based catalog creation. Use when creating EPC products, configuring product attributes, building offer bundles with Product Child Items, or reviewing EPC DataPack JSON metadata for product catalog changes. TRIGGER when: user creates or updates Product2 EPC records, AttributeAssignment payloads, AttributeMetadata/AttributeDefaultValues, Offer bundles, or ProductChildItem relationships. DO NOT TRIGGER when: designing OmniScripts/FlexCards/Integration Procedures (use building-omnistudio-omniscript, building-omnistudio-flexcard, or building-omnistudio-integration-procedure), implementing Apex business logic (use generating-apex), or troubleshooting deployment pipelines (use deploying-metadata).
relationship-science-coach
IncludedUse this skill for direct, practical adult relationship coaching: couples conflict, repair, trust, marriage, dating, flirting, attachment patterns, emotional connection, sex, desire differences, eroticism, kink negotiation, affection, love languages, breakups, and long-term passion. Draw on Gottman, EFT and Hold Me Tight, attachment science, modern sex research, Perel, Nagoski, Kerner, Schnarch, Love and Stosny, and flexible love-language tools. Be concrete and low-hedge. Redirect only for imminent danger, abuse, coercive control, minors, non-consent, self-harm, stalking, or medical/legal/psychiatric decisions.
building-sf-integrations
IncludedSalesforce integration architecture and runtime plumbing with 120-point scoring. Use this skill to set up Named Credentials, External Credentials, External Services, REST/SOAP callout patterns, Platform Events, and Change Data Capture. TRIGGER when: user sets up Named Credentials, External Services, REST/SOAP callouts, Platform Events, CDC, or touches .namedCredential-meta.xml files. DO NOT TRIGGER when: Connected App/OAuth config (use configuring-connected-apps), Apex-only logic (use generating-apex), or data import/export (use handling-sf-data).
venue-templates
IncludedAccess comprehensive LaTeX templates, formatting requirements, and submission guidelines for major scientific publication venues (Nature, Science, PLOS, IEEE, ACM), academic conferences (NeurIPS, ICML, CVPR, CHI), research posters, and grant proposals (NSF, NIH, DOE, DARPA). This skill should be used when preparing manuscripts for journal submission, conference papers, research posters, or grant proposals and need venue-specific formatting requirements and templates.
let-fate-decide
IncludedDraws the 12 Houses of the Zodiac Tarot spread to inject entropy into planning when prompts are vague, ambiguous, or casually delegated. Interprets the spread to guide next steps. Use when the user says 'let fate decide', 'YOLO', 'whatever', 'idk', or other nonchalant phrases, makes Yu-Gi-Oh references, or when you are about to arbitrarily pick between multiple reasonable approaches. Prefer over ask-questions-if-underspecified when the user's tone is casual or playful rather than precision-seeking.
net-ops
IncludedCross-platform network troubleshooting (Windows, macOS, Linux) via local or remote shell. Use for: DNS broken, can't resolve hostnames, nslookup/dig works but apps fail, NRPT, WFP, scutil, /etc/resolver, systemd-resolved, /etc/resolv.conf, NetworkManager, VPN DNS leak residue (ProtonVPN/Mullvad/WireGuard/AnyConnect), AV/firewall blocking DNS or DoH, Tailscale DNS interaction, intermittent connectivity, remote diagnostics over SSH.