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

gsheets-i18n

v1.0.3

Published

Generate i18n JSON files from a Google Spreadsheet

Downloads

531

Readme

📊🤌 gsheets-i18n

Manage app translations in Google Sheets. Generate i18n JSON files with one command.

npm version npm downloads License Last commit Node version


1. Overview

gsheets-i18n Overview


2. Why gsheets-i18n?

  • Single source of truth — Translators edit Google Sheets, developers pull JSON
  • Real-time collaboration — No version conflicts, no code required for non-devs
  • Framework-agnostic — Works with i18next, Vue i18n, Angular, etc.
  • Nested keys — Dot notation (modal.title) auto-generates hierarchical JSON
  • Batch processing — Extract from multiple spreadsheets at once
  • Zero production overhead — Generates static JSON, no runtime dependencies

Table of Contents


3. Quick Start

3.1 Copy demo Google Sheet to your Drive

Import the demo spreadsheet into your Google Drive and start right away.

3.2 Install

npm install --save-dev gsheets-i18n

3.3 Set up Google authentication

  1. Go to Google Cloud Console
  2. Create a service account and download the JSON key
  3. Share your spreadsheet with the service account email (grant Viewer access)

3.4 Pull translations

gsheets-i18n sheet \
  --sheet-id YOUR_SHEET_ID \
  --key ./service-account.json \
  --out ./src/locales

Done. Your en.json, fr.json, etc. are ready.

Add to package.json:

{
  "scripts": {
    "i18n:pull": "gsheets-i18n sheet --sheet-id YOUR_ID --key ./service-account.json --out ./src/locales"
  }
}

4. How It Works

4.1 Spreadsheet Format

Spreadsheet Setup GIF

| key | EN | FR | DE | |-----|----|----|-----| | save | Save | Enregistrer | Speichern | | modal.title | Confirm action | Confirmer l'action | Aktion bestätigen | | errors.404 | Not found | Non trouvé | Nicht gefunden |

Rules:

  • Row 1: Language codes (EN, FR, DE, etc. — see supported languages)
  • Column A: Translation keys (dot notation creates nested objects)
  • Other columns: One language per column

4.2 Output

{
  "save": "Save",
  "modal": {
    "title": "Confirm action"
  },
  "errors": {
    "404": "Not found"
  }
}

4.3 Update translations

Update values

4.4 Use Automatic or Static Values

Use static values

4.5 Multiple Tabs = Namespaces

Each tab becomes a top-level namespace:

Sheet tab "actions" + key "save"
  → { "actions": { "save": "..." } }

Sheet tab "errors" + key "404"
  → { "errors": { "404": "..." } }

5. How It Compares

| Feature | gsheets-i18n | Crowdin | Lokalise | Phrase | |---------|------------------|---------|----------|--------| | Setup time | 5 min | 30+ min | 30+ min | Days | | Cost | Free | Freemium | $999+/mo | Enterprise | | Uses Google Sheets | ✅ | ❌ | ❌ | ❌ | | No vendor lock-in | ✅ | ❌ | ❌ | ❌ | | Static JSON output | ✅ | ❌ (SaaS API) | ❌ (SaaS API) | ❌ | | Open source | ✅ | ❌ | ❌ | ❌ | | Works offline | ✅ (JSON files) | ❌ | ❌ | ❌ |


6. CLI Reference

6.1 Single Spreadsheet

gsheets-i18n sheet \
  --sheet-id <spreadsheet-id> \
  --key <path-to-service-account.json> \
  --out <output-dir>

| Flag | Default | Description | |------|---------|-------------| | -s, --sheet-id | — | Required. Spreadsheet ID from URL | | -k, --key | ./service-account.json | Service account JSON key | | -o, --out | ./i18n | Output directory | | -t, --tab-id | all | Extract specific tab only | | --include-empty | false | Include keys with empty values | | --indent | 2 | JSON indentation (2, 4, or "tab") |

Find tab ID: Right-click a sheet tab → Copy link → URL contains #gid=<tabId>

6.2 Multiple Spreadsheets (Folder Mode)

gsheets-i18n folder \
  --folder-id <drive-folder-id> \
  --key <path-to-service-account.json> \
  --out <output-dir>

Recursively extracts all spreadsheets from a Drive folder, creating a nested namespace structure.


7. Programmatic API

import { extract } from "gsheets-i18n";

const result = await extract({
  serviceAccountKey: "./service-account.json",
  source: {
    mode: "sheet",
    spreadsheetId: "YOUR_SHEET_ID",
  },
  outputDir: "./src/locales",
});

console.log(`Generated ${result.files.length} files`);

for (const file of result.files) {
  console.log(`${file.locale}: ${file.keyCount} keys`);
}

8. Supported Languages

Column headers are auto-mapped to language codes using Google's official language codes.

Set languages, automatic update

Common examples:

| Header | Code | Header | Code | |--------|------|--------|------| | EN, English | en | ES, Spanish | es | | EN-GB, English (UK) | en-GB | PT-BR, Portuguese (Brazil) | pt-BR | | FR, French | fr | DE, German | de | | FR-CA, French (Canada) | fr-CA | JA, Japanese | ja | | ZH-CN, Chinese (Simplified) | zh-CN | ZH-TW, Chinese (Traditional) | zh-TW |

Supports 100+ languages. See full list in Google's documentation.


9. Advanced Features

9.1 Skip Tabs & Columns

Prefix with _ to exclude:

  • Tab _notes — ignored entirely
  • Column _dev — excluded from output

If rows have no values, those are skipped as well. Using the template, prefix the key with _ to skip that row.

  • Row with key _ menu — excluded from output.

9.2 Custom Locale Mapping

Create a tab named _keymap to override header-to-locale mapping:

| — | fr | en | |---|------|------| | Français | fr | en | | English | en | en |


10. FAQ

Q: Can non-developers edit translations?
A: Yes. Share the Google Sheet with your team. No coding knowledge needed.

Q: What happens to translations when I pull?
A: New JSON files are generated in your ./src/locales folder. Review and commit to Git.

Q: Can I use this with my existing translations?
A: Yes. Copy your existing JSON structure into Google Sheets (use dot notation for nesting).

Q: Does this work offline?
A: The CLI requires internet to fetch from Google Sheets, but the output JSON works offline.

Q: Can I automate this with CI/CD?
A: Yes. Add the service account key to your repo secrets and call npm run i18n:pull in your GitHub Actions/GitLab CI workflow.

Q: How often should I pull translations?
A: As often as needed. Many teams pull before each deployment, or on every commit to the main branch.

Q: What if a translation is missing?
A: By default, missing translations are skipped. Use --include-empty to include empty cells in output.

Q: How does I support versioning?
A: You can support versioning using google drive versioning feature.

Q: Can I use this for pluralization or complex formatting?
A: Yes. Store JSON-formatted values in your cells, e.g., {"one":"1 item","other":"{{count}} items"}, and they'll be parsed correctly. (This might require an updated mapper or pipe depending on your front end framework)


11. Troubleshooting

11.1 "Permission denied" Error

  • Verify the service account email is Viewer access on the spreadsheet
  • Check the service account key file exists and is readable

11.2 No files generated

  • Verify the first row contains language codes
  • Check that key cells (Column A) are not empty
  • Ensure you have at least one column with translations

11.3 Language code not recognized

Verify the column header matches an official code from Google's language list.


12. Contributing

Contributions welcome! Please open an issue or submit a PR on GitHub.


13. Show Your Support

💡 Enjoying gsheets-i18n? ⭐ Star us on GitHub to show your support!

Found a bug? Open an issue

Have an idea? Start a discussion


14. License

MIT