npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@exuus/locales

v1.1.0

Published

A powerful CLI tool to synchronize translation files with Google Sheets, enabling collaborative translation management with automatic change detection and visual highlighting.

Readme

@exuus/locales

A powerful CLI tool to synchronize translation files with Google Sheets, enabling collaborative translation management with automatic change detection and visual highlighting.

✨ Features

  • 🔄 Automatic Synchronization - Sync translation files with Google Sheets
  • 🎯 Smart Detection - Only adds new keys, skips existing ones
  • 🎨 Visual Highlighting - Highlight new additions in your sheet
  • 📁 Multiple Formats - Support for .js, .json, .ts translation files
  • 🔍 Dry Run Mode - Preview changes before applying them
  • 📊 Sheet Management - Support for multiple sheets in one spreadsheet
  • 🚀 CLI & API - Use via command line or programmatically

📦 Installation

Global Installation

npm install -g @exuus/locales

Local Installation

npm install --save-dev @exuus/locales

Using without Installation (npx)

npx @exuus/locales sync [options]

🚀 Quick Start

1. Set up Google Sheets API

  1. Go to Google Cloud Console
  2. Create a new project or select existing one
  3. Enable Google Sheets API
  4. Create a service account:
    • Go to "IAM & Admin" > "Service Accounts"
    • Click "Create Service Account"
    • Download the JSON key file
  5. Share your Google Sheet with the service account email (found in the JSON key file)

2. Prepare Your Google Sheet

Create a Google Sheet with the following structure:

| key | en | rw | context | |-----|----|----|---------| | hello | Hello | Muraho | Greeting | | welcome | Welcome | Murakaze neza | Welcome message | | goodbye | Goodbye | Murabeho | Farewell |

3. Create Translation Files

Create your translation files in any supported format:

ES Module format (.mjs or .js with "type": "module"):

export default {
  "hello": "Hello",
  "welcome": "Welcome",
  "goodbye": "Goodbye"
};

CommonJS format (.js):

module.exports = {
  "hello": "Hello",
  "welcome": "Welcome",
  "goodbye": "Goodbye"
};

JSON format (.json):

{
  "hello": "Hello",
  "welcome": "Welcome",
  "goodbye": "Goodbye"
}

TypeScript format (.ts):

export default {
  "hello": "Hello",
  "welcome": "Welcome",
  "goodbye": "Goodbye"
} as const;

4. Run Synchronization

exuus-locales sync --id YOUR_SHEET_ID -k ./service-key.json -e ./en.js -r ./rw.js

📋 CLI Usage

Basic Sync Command

exuus-locales sync --id <sheet-id> -k <key-path> -e <en-path> -r <rw-path>

Options

  • --id <id> - Google Sheet ID (required)
  • -k, --key <path> - Path to service account key JSON file (required)
  • -e, --en <path> - Path to English translation file (required)
  • -r, --rw <path> - Path to Kinyarwanda translation file (required)
  • -s, --sheet <name> - Sheet name (optional, defaults to first sheet)
  • --dry-run - Preview changes without writing to sheet
  • --highlight - Highlight new rows in the sheet
  • --no-highlight - Do not highlight new rows (default)

Examples

Sync with specific sheet name

exuus-locales sync --id YOUR_SHEET_ID -k ./service-key.json -e ./en.js -r ./rw.js -s "Translations"

Dry run to preview changes

exuus-locales sync --id YOUR_SHEET_ID -k ./service-key.json -e ./en.js -r ./rw.js --dry-run

Sync with highlighting

exuus-locales sync --id YOUR_SHEET_ID -k ./service-key.json -e ./en.js -r ./rw.js --highlight

Using npx (without installation)

npx @exuus/locales sync --id YOUR_SHEET_ID -k ./service-key.json -e ./en.js -r ./rw.js

💻 Programmatic API

ES Modules

import { syncTranslations } from '@exuus/locales';

const result = await syncTranslations(
  './service-key.json',
  './locales/en.js',
  './locales/rw.js',
  {
    spreadsheetId: 'YOUR_SHEET_ID',
    sheetName: 'Translations',
    highlightNewRows: true,
    dryRun: false
  }
);

console.log(`Added ${result.newKeysAdded} new translations`);
console.log(`Total keys: ${result.totalKeys}`);
console.log(`New keys: ${result.newKeys.join(', ')}`);

CommonJS

const { syncTranslations } = require('@exuus/locales');

async function sync() {
  const result = await syncTranslations(
    './service-key.json',
    './locales/en.js',
    './locales/rw.js',
    {
      spreadsheetId: 'YOUR_SHEET_ID',
      sheetName: 'Translations',
      highlightNewRows: true,
      dryRun: false
    }
  );
  
  console.log(`Added ${result.newKeysAdded} new translations`);
}

sync();

TypeScript

import { syncTranslations, SyncOptions, SyncResult } from '@exuus/locales';

const options: SyncOptions = {
  spreadsheetId: 'YOUR_SHEET_ID',
  sheetName: 'Translations',
  highlightNewRows: true,
  highlightColor: {
    red: 1,
    green: 0.9,
    blue: 0.8,
    alpha: 1
  },
  dryRun: false
};

const result: SyncResult = await syncTranslations(
  './service-key.json',
  './locales/en.ts',
  './locales/rw.ts',
  options
);

if (result.success) {
  console.log(`Successfully added ${result.newKeysAdded} translations`);
} else {
  console.error(`Error: ${result.error}`);
}

📚 API Reference

syncTranslations(serviceKeyPath, enPath, rwPath, options)

Parameters

  • serviceKeyPath (string) - Path to Google service account key JSON file
  • enPath (string) - Path to English translation file
  • rwPath (string) - Path to Kinyarwanda translation file
  • options (SyncOptions) - Configuration options

SyncOptions

interface SyncOptions {
  spreadsheetId?: string;      // Google Sheet ID
  sheetName?: string;          // Sheet name (optional)
  dryRun?: boolean;           // Preview mode without writing
  defaultContext?: string;     // Default context for new entries
  highlightNewRows?: boolean;  // Enable row highlighting
  highlightColor?: {          // Custom highlight color
    red?: number;   // 0-1
    green?: number; // 0-1
    blue?: number;  // 0-1
    alpha?: number; // 0-1
  };
}

Return Value (SyncResult)

interface SyncResult {
  success: boolean;           // Operation success status
  newKeysAdded: number;      // Number of new keys added
  existingKeys: number;      // Number of existing keys
  totalKeys: number;         // Total keys in files
  newKeys: string[];         // List of new keys added
  skippedKeys: string[];     // List of skipped existing keys
  error?: string;            // Error message if failed
  message: string;           // Status message
}

🔧 Troubleshooting

Common Issues

Permission Denied

  • Problem: "Permission denied. Please check if the service account has access to the sheet."
  • Solution: Share your Google Sheet with the service account email address found in your service key JSON file

Authentication Failed

  • Problem: "Service account key file not found" or "Invalid JSON in service account key file"
  • Solution: Verify the path to your service account key file and ensure it's valid JSON

Sheet Not Found

  • Problem: "Sheet not found. Please verify the spreadsheet ID"
  • Solution:
    • Check that the spreadsheet ID is correct (found in the sheet URL)
    • Ensure the sheet name is spelled correctly if using -s option

Empty Translations

  • Problem: Some translations show as empty in the sheet
  • Solution: This is normal when a key exists in one language but not the other. Add the missing translations to your files.

File Loading Errors

  • Problem: "Failed to load translation file"
  • Solution:
    • Check file paths are correct
    • Ensure files export objects with string key-value pairs
    • Verify file format matches one of the supported formats

Getting the Sheet ID

The Google Sheet ID can be found in the URL:

https://docs.google.com/spreadsheets/d/[SHEET_ID_HERE]/edit

Example:

https://docs.google.com/spreadsheets/d/1ABC123def456/edit
                                       ^^^^^^^^^^^^^^
                                       This is your Sheet ID

🤝 Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

📄 License

ISC © 2024

🔗 Links