Dashboard guide
Import Translations
Bring existing translations into langctl by uploading the files you already have. You see every change before anything is imported.
Supported Import Formats
The dashboard imports:
- JSON (flat or nested) and i18n JSON
- Android XML (
strings.xml) - iOS Strings (
Localizable.strings) - Flutter ARB
- CSV and Excel (
.xlsx,.xls)
The format is detected automatically; you can also pick it yourself.
Importing a File
Open Import & Export in the sidebar (or Import on the Translations page). The import has three steps: Upload, Review, Done.
Step 1: Upload
- Drag and drop a file, or click Browse Files
- Check the detected Format
- Choose the Target Language - each import is for one language. If the file looks like a language the project doesn’t have yet, you can add it right there with Add language
- Optionally set a Module - it’s used for keys that don’t specify a module in the file
Step 2: Review
Every key in the file is listed with its Current value, the Incoming value, and the change:
- New - The key, or this language’s translation, doesn’t exist yet
- Update - The key already has a different translation
- Unchanged - The translation is the same
- Kept - The key already has a translation and overwrite is off, so it stays as it is
Use Overwrite existing translations to decide what happens to existing values:
- Off (default): existing translations are kept; only new keys and missing translations are added
- On: existing translations are replaced with the values from the file
Filter the list by change, and select or deselect individual keys - only selected keys are imported. Then click Import Selected Keys.
Note
New keys are imported as drafts. Review them and publish when they’re ready - drafts aren’t included in exports or langctl pull.
Step 3: Done
The summary shows how many keys were imported, updated and skipped, and the language’s coverage afterwards. From there you can import another file or open the translations to review them.
Warning
Keep the page open until the import finishes. Large files are uploaded in batches.
Format Details
JSON
Flat files use keys exactly as written. Nested files are flattened into dotted keys:
{
"home": {
"welcome": "Welcome!"
},
"auth": {
"login": { "title": "Sign In" }
}
} becomes home.welcome and auth.login.title.
Android XML
Each <string name="…"> becomes a key with that name. Placeholders %1$s, %2$s become {{param1}}, {{param2}}, and %s becomes {{param}}. XML entities are unescaped.
iOS Strings
Each "key" = "value"; line becomes a key. %1$@, %2$@ become {{param1}}, {{param2}}, and %@ becomes {{param}}. Escaped characters (\", \n) are unescaped.
Flutter ARB
Message ids become keys, and descriptions from the @key metadata are imported. {name} placeholders become {{name}}.
CSV and Excel
One key per row, with the columns key, value, description and module (description and module are optional):
key,value,description,module
home.welcome,"Welcome to our app","Welcome message on home screen",home
auth.login,"Login","Login button text",auth The value column is imported into the language you choose. Use Download Sample CSV or Download Sample Excel on the import page for a ready-made template.
Modules
When a key has no module in the file and you didn’t set one, keys with a dot get the first part of their name as module (auth.login.title → auth).
Renaming Generic Parameters
Android and iOS files don’t store placeholder names, so they’re imported as generic names:
Before: "Welcome, {{param1}}!"
After: "Welcome, {{username}}!" Rename them in the key editor (in every language) so they match the names your app passes. If you also have JSON or ARB versions of the same strings, import those instead - they keep the original names.
Importing from the CLI
The CLI imports JSON, Android XML, iOS Strings and ARB files (not CSV or Excel), and can upload every language at once:
langctl import my-app ./old-translations/es.json --language es --dry-run
langctl import my-app ./old-translations/es.json --language es
# with langctl.json set up, upload every language file at once
langctl push -l all See Pull, Push & Import for details.
Troubleshooting
“Failed to parse file”:
- Check for syntax errors (missing commas, brackets, unescaped quotes)
- Make sure the file is UTF-8 encoded
- Pick the format manually instead of auto-detect
“No translation keys were found in this file”:
- Check that the file contains string values in the selected format
- For CSV/Excel, make sure the first row has the
keyandvalueheaders
Language not in the project:
- Add it with Add language on the upload step, or from the Languages page
Existing translations didn’t change:
- Turn on Overwrite existing translations - without it, existing values are kept
Next Steps
- Translation Management - Review and publish imported keys
- Export Translations - Download files for your app
- File Formats - Format reference