Skip to content

Data Providers

Lexis uses a provider system for loading translation data from various sources.

ProviderIDCapabilitiesUse Case
JSONjsonRead, Write, Offline, SyncDefault, version control friendly
CSVcsvRead, Write, Offline, SyncSpreadsheet workflows
POpoRead, Write, Offline, SyncGNU Gettext compatibility
Google SheetsgooglesheetsRead, Write*Collaborative translation

*Write capability requires API key; public sheets are read-only.

The Google Sheets provider enables collaborative translation workflows by loading translations directly from a Google Spreadsheet. There are two access modes with different requirements.

Access Modes

ModeRequirementBest For
Public (Published to Web)Sheet must be published to webQuick setup, no API key needed
API KeyGoogle Cloud API keyPrivate sheets, full metadata access

Important

"Shared with anyone with the link" is NOT the same as "Published to web". Public access without an API key requires the sheet to be published to the web.

Option 1: Public Access (No API Key)

For quick setup without API credentials, publish your sheet to the web:

How to Publish a Google Sheet:

  1. Open your Google Sheet in the browser
  2. Go to File → Share → Publish to web
  3. In the dialog:
    • Select Entire Document or specific sheets
    • Choose Web page or CSV format (either works)
  4. Click Publish
  5. Confirm when prompted

Limitations of Public Access:

  • Sheet must remain published (anyone with URL can view)
  • Cannot enumerate all sheet names automatically (uses common defaults: Sheet1, Translations, Localization, Strings)
  • No push/write support - public access is read-only; use an API key for push operations

Inspector Setup:

  1. In LocalizationSettings, set Provider to Google Sheets
  2. Enter your Spreadsheet ID (from the URL)
  3. Check Is Public
  4. Click Fetch to load available sheets
  5. Select your sheet from the dropdown

Option 2: API Key Access

For private sheets or full functionality, use a Google Cloud API key:

How to Get an API Key:

  1. Go to Google Cloud Console
  2. Create a new project or select existing
  3. Enable the Google Sheets API:
    • Go to APIs & Services → Library
    • Search for "Google Sheets API"
    • Click Enable
  4. Create an API key:
    • Go to APIs & Services → Credentials
    • Click Create Credentials → API Key
    • (Recommended) Restrict the key to Google Sheets API only
  5. Copy the API key

Benefits of API Key:

  • Works with private sheets (shared with specific users)
  • Full sheet name enumeration in the Fetch dropdown
  • Push/write support for syncing translations back to Google Sheets

Inspector Setup:

  1. In LocalizationSettings, set Provider to Google Sheets
  2. Enter your Spreadsheet ID (from the URL)
  3. Uncheck Is Public (or leave unchecked)
  4. Enter your API Key in the API Key field
  5. Click Fetch to load all available sheets
  6. Select your sheet from the dropdown

Security Warning Never commit API keys to version control. The API key field in the Inspector stores keys in EditorPrefs (not in the asset). For CI/CD pipelines, set the LEXIS_GOOGLE_API_KEY environment variable.

Multi-Sheet Configuration

Lexis supports syncing multiple Google Sheets tabs, where each tab maps to a StringTable by its TableId.

How Sheet-to-Table Mapping Works:

  • Google Sheet tab "UI" → StringTable with TableId "UI"
  • Google Sheet tab "Dialogues" → StringTable with TableId "Dialogues"
  • If no matching StringTable exists, one is created automatically during sync

Configuring Multiple Sheets:

  1. API Key Mode (Recommended):

    • Enter your Spreadsheet ID and API Key
    • Click Fetch to load available sheets
    • Check the boxes next to sheets you want to sync
  2. Public Mode:

    • Enter your Spreadsheet ID
    • Use the + Add Sheet button to add sheet names
    • Enter each sheet name manually (must match exactly)

Inspector UI:

Sheet Names (each sheet maps to a StringTable by TableId)
├── [x] UI
├── [x] Dialogues
├── [ ] Metadata (unchecked = not synced)
└── [x] Tutorials

Sync Operations

Pull Selected Table:

  • Pulls from the sheet matching the selected StringTable's TableId
  • Performs true sync: adds new entries, updates modified entries, and deletes entries that no longer exist in the source
  • Shows a consent dialog if changes are detected

Pull All Sheets:

  • Pulls from all configured sheets at once
  • Creates new StringTables for sheets without matches
  • Shows a consent dialog for each table with changes
  • Options: Cancel, Skip, Overwrite, Overwrite All

Push Selected Table:

  • Pushes the current StringTable to the configured provider
  • For Google Sheets, requires an API key (not supported for public sheets)

Push All Tables:

  • Pushes all StringTables to the configured provider
  • Useful for backing up or exporting all translations

Important

Push operations to Google Sheets require an API key with write permissions. Pushing to public (published-to-web) sheets is not supported because public access is read-only.

Consent Dialog: Before applying changes, Lexis shows a diff preview:

  • Number of new entries to add (green)
  • Number of entries to modify with before/after preview (yellow)
  • Number of entries to delete (red) - entries that exist locally but not in the source

Sync Menu (gear icon dropdown in String Table Browser toolbar):

  • Pull Selected Table - Sync current table from its matching sheet
  • Pull All Sheets - Sync all configured sheets
  • Push Selected Table - Push current table to the provider
  • Push All Tables - Push all tables to the provider
  • Configure Provider... - Open provider settings

Expected Sheet Format

Your Google Sheet should follow this structure:

KeyendefrComment
ui.welcomeWelcome!Willkommen!Bienvenue!Main menu greeting
ui.startStart GameSpiel startenDémarrer
ui.quitQuitBeendenQuitter
  • First column: Translation keys
  • Header row: Locale codes (en, de, fr, etc.)
  • Optional: Comment column for translator notes

Troubleshooting Google Sheets

ErrorCauseSolution
"Access denied"Sheet not published or wrong sharingPublish to web (File → Share → Publish to web)
"Sheet must be published to web"Using public mode but sheet is only sharedPublish to web, or provide an API key
"Invalid API key"API key is incorrect or expiredVerify key in Google Cloud Console
"Could not detect sheet names"Sheet name doesn't match defaultsEnter sheet name manually, or use API key
Empty data returnedSheet has no contentAdd data to your spreadsheet
"No Sheets Configured"SheetNames list is emptyAdd at least one sheet name in provider settings
Pull creates wrong tableSheet name doesn't match TableIdRename sheet tab or StringTable.TableId to match
Consent dialog keeps appearingChanges detected between sheet and localClick "Overwrite All" to apply to all remaining
"Push not supported"Trying to push to public sheetPush requires an API key; configure API Key mode
Entries unexpectedly deletedPull performs true sync with deletionsThis is expected behavior; entries not in source are removed
FlagDescription
ReadCan load translations
WriteCan save translations
LazyLoadLoad individual keys on demand
WatchDetect external file changes
OfflineWorks without network
SyncSupports synchronous operations
BatchWriteEfficient bulk saves
json
{
    "localeCode": "en",
    "entries": {
        "ui.welcome": {
            "value": "Welcome!",
            "comment": "Main menu greeting",
            "maxLength": 50,
            "tags": ["ui", "menu"]
        },
        "ui.start": {
            "value": "Start Game"
        }
    }
}
csv
Key,en,de,Comment,MaxLength
ui.welcome,Welcome!,Willkommen!,Main menu,50
ui.start,Start Game,Spiel starten,,
po
# Translator comment
#: source/menu.cs:42
msgctxt "menu"
msgid "Start"
msgstr "Starten"

msgid "One item"
msgid_plural "%d items"
msgstr[0] "Ein Element"
msgstr[1] "%d Elemente"

Implement ILocalizationProvider for custom data sources:

csharp
public interface ILocalizationProvider
{
    string ProviderId { get; }
    string DisplayName { get; }
    ProviderCapabilities Capabilities { get; }

    UniTask InitializeAsync(ProviderConfig config);
    UniTask<LocaleData> LoadLocaleAsync(string localeCode);
    UniTask<string> GetTranslationAsync(string key, string localeCode);
    UniTask SaveLocaleAsync(string localeCode, LocaleData data);
    UniTask<string[]> GetAvailableLocalesAsync();
}

Professional Unity Development Tools