i18n-google-sheets
v0.3.0
Published
Translations fetcher from Google Sheets with automatic TypeScript type generation for react-intl
Maintainers
Readme
Install
npm install i18n-google-sheets --save-devGoogle spreadsheet example
Sheet named "controls" | key | en | es | | ----- | ----- | ----- | | ready | ready | listo |
Sheet named "root" (or "all") | key | en | es | | --- | --- | --- | | yes | yes | si |
Both sheets will be fetched and processed into the following files:
en.json
{
"controls": {
"ready": "ready"
},
"yes": "yes"
}es.json
{
"controls": {
"ready": "listo"
},
"yes": "si"
}Google API Credentials
Create an API key or service account with API key on google cloud
Enable the google sheets API for your project
Create a .env file with the GOOGLE API CREDENTIALS
### If you're using a service account to access translations set the path to the credentials:
### Don't forget to give your service account at least view permission
GOOGLE_APPLICATION_CREDENTIALS='./credentionals.json'
### If you're using an API KEY set the following:
### Don't forget to share your google sheet
GOOGLE_API_KEY=<api_key>
SPREADSHEET_ID=<spreadsheet id from url>
### Optional: Set the base language for TypeScript type generation (defaults to 'en')
BASE_LANGUAGE=enRun with npx
npx i18n-google-sheetsRun with npm
Add the following command to package.json
"scripts": {
"i18n": "i18n-google-sheets"
}and
npm run i18nTypeScript Support
Auto-Generated Types
This package automatically generates TypeScript types for your translations using FormatJS official TypeScript support, providing full type safety when using react-intl.
After running the command, you'll find a generated type definition file in your translations folder:
translations/
├── en.json # Your translation files
├── es.json
├── index.d.ts # 🆕 Generated TypeScript types (FormatJS global augmentation)
└── flatten.ts # 🆕 Utility to flatten nested messagesThe generated index.d.ts uses FormatJS official approach to augment global types, which means you use standard react-intl directly - no wrappers needed!
Using Typed Translations with React-Intl
Basic Setup
Important: Since FormatJS expects flat keys when using typed IDs, you need to flatten nested JSON:
import { IntlProvider } from 'react-intl';
import enMessages from './translations/en.json';
import { flattenMessages } from './translations/flatten';
function App() {
return (
<IntlProvider
messages={flattenMessages(enMessages)}
locale="en"
defaultLocale="en"
>
<YourApp />
</IntlProvider>
);
}The flattenMessages utility converts nested structure like { title: { main: "Hello" } } into flat structure like { "title.main": "Hello" } which FormatJS expects.
Using Standard React-Intl with Type Safety
Simply import the generated types and use standard react-intl components and hooks:
// Import once in your app to enable types
import './translations/index.d.ts';
// Then use standard react-intl everywhere
import { FormattedMessage, useIntl } from 'react-intl';
function MyComponent() {
const intl = useIntl();
return (
<div>
{/* ✅ Full autocomplete and type checking */}
<FormattedMessage id="controls.ready" />
{/* ✅ Typed formatMessage with autocomplete */}
{intl.formatMessage({ id: "yes" })}
{/* ❌ TypeScript error: invalid key */}
<FormattedMessage id="invalid.key" />
</div>
);
}No wrappers, no custom hooks - just standard react-intl with full type safety!
Features
- 🎯 Full Type Safety: Catch translation key errors at compile time, not runtime
- ✨ IntelliSense: Get autocomplete for all available translation keys
- 🔄 Auto-Generated: Types update automatically when you sync translations
- 📦 Official FormatJS Approach: Uses FormatJS TypeScript support
- 🚫 No Wrappers: Works directly with standard
<FormattedMessage>anduseIntl() - 🌍 Locale Types: Automatically types available locales too
- 🌳 Nested Keys Support: Full support for nested translations (e.g.,
"controls.ready") - ⚠️ Key Validation: Warnings for keys with spaces or special characters
Configuration
Set the base language for type generation in your .env file:
BASE_LANGUAGE=en # defaults to 'en' if not specifiedThe base language is used as the source of truth for generating TypeScript types.
Notes on Translation Keys
- Nested keys use dot notation:
"controls.ready"for{ "controls": { "ready": "..." } } - Keys with spaces are supported but will show warnings:
"controls.not ready"- Consider using camelCase (
notReady) or underscores (not_ready) instead
- Consider using camelCase (
- Special characters in keys are allowed but may trigger validation warnings
