GitHub Actions for content exchange

We provide a collection of ready-to-use GitHub actions that help you exchange translation files between Lokalise "Web and mobile" projects and GitHub repositories. These actions include:

  • Push: Upload new or updated translation files (for the base language) from GitHub to Lokalise.
  • Pull: Download translation files from Lokalise to GitHub as a pull request.

These actions are lightweight and do not require installing the GitHub app for Lokalise.

Scenario overview: Push and pull with tags

This is the simplest and recommended approach for managing translation files. It relies on using key tags in Lokalise to map translations to the corresponding branch in GitHub.

  • Using the hub branch: In GitHub, designate a specific branch to manage your translations. We'll refer to this branch as the "hub." This branch serves as the central point for translation updates and synchronization between Lokalise and GitHub.
  • Pushing translation files to Lokalise: To send updated translation files from GitHub to Lokalise, manually trigger the "Push to Lokalise" workflow from the hub branch. When you do this, any new or updated keys in Lokalise are tagged with the name of the hub branch that initiated the workflow.
  • Pulling translation files from Lokalise: To bring translation files from Lokalise back into GitHub, manually trigger the "Pull from Lokalise" workflow from the hub branch. This workflow filters the translation keys by the tag matching the hub branch’s name. Once filtered, a pull request with the updated translation files is created for the hub branch. After merging this pull request, your hub branch will be up-to-date with the latest translation files.

This approach allows you to manage your translation process in a dedicated branch, giving you the flexibility to merge updates into your main branch whenever needed.

Getting started with GitHub Actions for Lokalise

General setup overview

Every action from this collection requires some general setup. In this section, we'll summarize general configuration options. Later, we'll show where and how these values should be provided.

Lokalise API token

To start, generate a read/write Lokalise API token and securely pass it to the action. Do not paste your token directly into the workflow configurations. Instead, store it as a repository secret:

  1. Open your repository's Settings.
  2. Navigate to Secrets and variables > Actions.
  3. Under Repository secrets, click New repository secret.
  4. Enter LOKALISE_API_TOKEN in the Name field.
  5. Paste your API token into the Secret field.
  6. That's it! Your token is securely stored in GitHub and won't be exposed during workflow runs. We'll reference this token when configuring the push and pull workflows.

Mandatory workflow parameters

Every workflow requires the following parameters. These can be set as environment variables, repository secrets, or passed directly in the workflow YAML file.

  • api_token — Lokalise API token. See the section above for setup instructions.
  • project_id — Your Lokalise project ID. If you don’t have a project yet, create a "Web and mobile" project on Lokalise and note its ID.
  • translations_path — One or more paths to your translation files. For example, if your translations are stored in the locales folder at the project root, use locales (omit leading and trailing slashes).
  • file_format — The format of your translation files. For example, use json for JSON files (no leading dot).
  • base_lang — The base language of your Lokalise project (e.g., en for English). Be mindful of regional codes! For example:
    • If your base language is French Canada (fr_CA), provide the exact value (fr_CA) for base_lang.
    • Ensure the folder structure under translations_path matches the regional code (e.g., locales/fr_CA).

🔐

Providing workflow parameters

  • Always provide the Lokalise API token as a GitHub repository secret for security.
  • Other parameters (e.g., project_id, base_lang) can be set:
    • Directly in the YAML file, e.g., base_lang: en.
    • Via repository variables or secrets, e.g., project_id: ${{ vars.PROJECT_ID }}.
  • If using repository variables, ensure they are named clearly and referenced correctly.

Running the workflows

To run a workflow:

  1. Open your GitHub repository and go to Actions.
  2. Select a workflow from the left pane.
  3. Find the Run workflow dropdown on the right side.
  4. Choose a hub branch to trigger the workflow for.
  5. Click Run workflow.

Push and pull with key tags

Creating the hub branch and setting up Push action

Suppose your project uses the main branch, but you want to manage translations in a dedicated branch. To achieve this, you’ll create a new branch, which we’ll refer to as the "lokalise-hub" branch. However, before that, you’ll need to set up a workflow in the main branch of your repository.

  1. Create the Push action:

Switch to the main branch of your repository and create a new file at .github/workflows/push.yml.

name: Push to Lokalise  
on:  
  workflow_dispatch:

jobs:  
  build:  
    runs-on: ubuntu-latest
    steps:
      - name: Checkout Repo
        uses: actions/checkout@v4
        with:
          fetch-depth: 0

      - name: Push files to Lokalise
        uses: lokalise/[email protected]
        with:
          api_token: ${{ secrets.LOKALISE_API_TOKEN }}
          project_id: LOKALISE_PROJECT_ID
          file_format: FILE_FORMAT
          translations_path: |
            TRANSLATIONS_PATH1
            TRANSLATIONS_PATH2
          base_lang: BASE_LANG_ISO

The following parameters are used in this example (note that we’re not covering all supported parameters here):

  • api_token: A secret variable containing your read/write Lokalise API token. Refer to the Lokalise API token section for setup instructions.
  • project_id: Your Lokalise project ID.
  • file_format: Specifies the format of your translation files, such as json. Do not include a leading dot.
  • translations_path: One or more directories in the project root containing your translation files without leading or trailing slashes (e.g., locales).
    • The full path to the translation files is built as TRANSLATIONS_PATH/LOCALE/**/**.FILE_FORMAT. Refer to the Translation files section for more details on file organization.
    • If your files are not nested under additional folders but instead stored directly in the translations_path (e.g., locales/en.json or i18n/fr.json), set the flat_naming parameter to true.
  • base_lang: The base language of your Lokalise project (e.g., en). Be mindful of regional codes! For example, if your base language is fr_CA, provide exactly that value.
    • Ensure that the translations_path includes a folder named after the base language. For instance, if your translations_path is set to locales and base_lang is en, the workflow expects to find translation files under the /locales/en/ folder. If this folder or the necessary files don’t exist yet, you’ll add them in step 3.

📘

How changes are detected

  • The Push action detects changes in translation files by comparing the latest commit with the one directly before it. This approach ensures the action processes only the most recent updates, rather than scanning the entire repository.
  • If there are no changes between these two commits, the action will not upload any files to Lokalise. To ensure your updates are processed, make sure the most recent commit includes all intended changes to your translation files.
  1. Create and switch to the lokalise-hub branch:
git checkout -b lokalise-hub
  1. Set up the translation folder and files:
    In this branch, create a folder for your translations if you haven't already done so. The folder name should match the translations_path you configured in step 1.
    1. For example, if your base language on Lokalise is English (en), create a folder called locales and inside it, an en directory. Place your base language translation files in this directory. For this demo, we’ll use the JSON format.
      Your folder structure should look like this:
locales/  
├── en/  
│   ├── main.json  
│   └── en.json
  1. Push the new branch to your GitHub repository:
git add .  
git commit -m "Added translation files for English (base)"  
git push origin lokalise-hub

Additional parameters for the Push action

The Push action supports several optional parameters for further customization. These parameters provide flexibility when handling specific workflows or addressing edge cases.

  • additional_params: Extra parameters to pass to the Lokalise CLI when pushing files. For example, you can use --convert-placeholders to handle placeholders. Multiple CLI arguments can be included as needed. Defaults to an empty string.

  • flat_naming: Use flat naming convention. Set this to true if your translation files follow a flat naming pattern, such as locales/en.json, instead of being organized in nested folders like locales/en/file.json. Defaults to false.

  • max_retries: The maximum number of retries in case of rate limit errors (HTTP 429). Defaults to 3.

  • sleep_on_retry: The number of seconds to wait before retrying after a rate limit error. Defaults to 1.

  • upload_timeout: The timeout for the upload operation, in seconds. This defines the maximum time allowed for a file upload before it is considered a failure. Defaults to 120.

  • upload_poll_timeout: The timeout for polling the upload status, in seconds. This defines the maximum time to wait for an upload process to complete before retrying. Defaults to 120.

Pushing translations to Lokalise

Now that everything is set up, you're ready to push translations from GitHub to Lokalise.

  1. Go to the Actions tab in your GitHub repository.
  2. Open the Push to Lokalise workflow. From the branch dropdown, select the lokalise-hub branch.
  1. Click Run workflow.
  2. The workflow will take a few moments to complete. Once finished, you’ll see the confirmation that the workflow has been successfully completed.

What if I already had translation files in my main branch?

If you already have translation files in your main branch before switching to the lokalise-hub branch, there’s no need to worry. The Push action only processes translation files that have been created or changed since the most recent commit. Files already in your version control history will not be treated as “new,” so they won’t be uploaded again unless modified.

When no changes are detected between the last two commits, the action checks if it is running for the first time on the current branch by searching for a lokalise-upload-complete tag:

  1. If the tag exists, it means the initial upload has already occurred, and the action will exit without uploading anything.
  2. If the tag is missing, the action will upload all translation files for the base language to Lokalise. After completing the upload, it creates the lokalise-upload-complete tag to indicate that the initial setup is finished.

Recommendation: After the initial run, pull the tag into your local repository using git pull to ensure your local copy reflects this setup.

If you have additional translation files for other (non-base) languages that you want to upload, you’ll need to do this manually in Lokalise. When uploading these files, ensure the filenames match the structure expected by Lokalise. For example, if your base language files are stored in locales/%LANG_ISO%/main.json, ensure that files for other languages follow the same structure (e.g., locales/fr/main.json for French or locales/de/main.json for German).

Editing translations on Lokalise

Once you're set up, you can head over to your Lokalise project and start managing translations. You'll notice that your translation keys are tagged with the lokalise-hub tag (or another tag named after the hub branch).

It's important to keep this tag intact to maintain the connection with your GitHub branch. If you need to add other tags, feel free to do so, but be careful not to remove the lokalise-hub tag. If it's accidentally removed, you can easily add it back using the Lokalise UI.

In Lokalise, you can add one or more target languages to your project and manage translations as usual.

Pulling translations from Lokalise

After editing your translations or creating new keys in Lokalise, you can sync these changes back to your hub branch.

  1. Create the Pull action
    Start by switching to the main branch of your repository. Then, create a .github/workflows/pull.yml file and add the pull action configuration to it.
name: Pull from Lokalise

on:
  workflow_dispatch:

jobs:
  build:
    runs-on: ubuntu-latest

    steps:
      - name: Checkout Repo
        uses: actions/checkout@v4
        with:
          fetch-depth: 0

      - name: Pull from Lokalise
        uses: lokalise/[email protected]
        with:
          api_token: ${{ secrets.LOKALISE_API_TOKEN }}
          project_id: LOKALISE_PROJECT_ID
          translations_path: |
            TRANSLATIONS_PATH1
            TRANSLATIONS_PATH2
          base_lang: BASE_LANG_ISO
          file_format: FILE_FORMAT

❗️

Filtering data based on translation status

  • By default, this action pulls all keys with the assigned tag, regardless of translation status.
  • To control this, use the additional_params option with the --filter-data parameter.
    • This parameter accepts the following values: translated, untranslated, reviewed, reviewed_only, last_reviewed_only, verified, and nonhidden.
    • For example: additional_params: "--filter-data translated".

The following parameters are used in this example (note that we’re not covering all supported parameters here):

  • api_token: Secret variable containing your read/write API token. Refer to the Lokalise API token section for setup instructions.
  • project_id: Your Lokalise project ID.
  • translations_path: One or more directories in the project root containing your translation files without leading or trailing slashes (e.g., locales).
    • The full path to the translation files is constructed as TRANSLATIONS_PATH/LOCALE/**/**.FILE_FORMAT. Check the Translation files section for more details on file organization.
    • If your files are not nested under additional folders and instead stored directly in the translations_path (e.g., locales/en.json or i18n/fr.json), set the flat_naming parameter to true.
  • base_lang: The base language of your Lokalise project (e.g., en). Be mindful of regional codes! For example:
    • If your base language is fr_CA, provide exactly that value.
    • Ensure the translations_path includes a folder named after the base language. For instance, if your translations_path is set to locales and base_lang is en, the workflow expects translation files under the /locales/en/ folder.
  • file_format: Specifies the format of your translation files, such as json. Do not include a leading dot.
  1. Push your newly created action to the main branch on GitHub.
  2. Grant proper permissions to the actions. To achieve that:
    1. Go to your GitHub repository's Settings.
    2. Navigate to Actions > General.
    3. Under Workflow permissions, set the permissions to Read and write permissions.
    4. Enable Allow GitHub Actions to create and approve pull requests on the same page (under "Choose whether GitHub Actions can create pull requests or submit approving pull request reviews").

❗️

Assigning Lokalise filenames and tags

Before running this action, ensure that your translation keys on Lokalise are correctly assigned with appropriate filenames and tags.

If you are running this action from the hub branch on GitHub, the action will download only the keys that have the hub tag assigned. If no such keys are found, the action will halt execution.

If you specify locales as the translations_path, your keys must include filenames that align with this structure, such as:

  • locales/%LANG_ISO%.json
  • locales/%LANG_ISO%/main.xml

If the filenames do not include the correct directory prefix (like locales/), the action will fail to compare the downloaded files with the existing files in your translations_path. In this case, the workflow logs will show the message: "No changes detected in translation files.".

  1. Head back to your GitHub repository and navigate to the Actions tab.
  2. Select the Pull from Lokalise action.
  3. Make sure you choose the hub branch as the trigger for this workflow.
  1. Once the workflow completes, switch to the Pull requests tab. You should see a new pull request created.
  1. In the pull request, you'll notice it's created for the lokalise-hub branch, originating from a temporary branch. The name of this branch starts with the prefix lok, followed by the hub branch name.
  2. Review the changed files to see the updates. You may notice that your translations have been reordered and the indentation level updated. This behavior can be adjusted by setting additional parameters.
  1. When you're satisfied with the changes, go ahead and merge the pull request. After merging, you can safely delete the temporary branch.

This process can be repeated as often as needed. If no changes are detected in the translations (meaning the translations in Lokalise match those in the hub branch), a pull request won’t be created.

📘

Tracking changes to the base language

By default, the Pull action does not track changes to the base language files. To include these files, set the always_pull_base option to true when configuring the action.

Additional parameters for the Pull action

The Pull action supports several optional parameters for further customization. These parameters allow you to tailor the workflow to your specific needs.

  • additional_params: Extra parameters to pass to the Lokalise CLI when pulling files. For example, you can use --indentation 2sp to manage indentation. Multiple CLI arguments can be added, such as --indentation 2sp --placeholder-format icu. Defaults to an empty string.

  • temp_branch_prefix: A prefix for the temporary branch used to create the pull request. For example, using lok will result in a branch name starting with lok. Defaults to lok.

  • always_pull_base: By default, changes in the base language translation files (as defined by the base_lang option) are ignored when checking for updates. Set this option to true to include changes in the base language translations in the pull request. Defaults to false.

  • flat_naming: Use flat naming convention. Set this to true if your translation files follow a flat naming pattern like locales/en.json instead of being organized in nested folders like locales/en/file.json. Defaults to false.

  • skip_include_tags — Skip setting the --include-tags argument during download. This will download all translation keys for the specified format, regardless of tags. You can also provide custom filtering options via additional_params, for example --include-tags staging,dev.

  • max_retries: The maximum number of retries on rate limit errors (HTTP 429). Defaults to 3.

  • sleep_on_retry: The number of seconds to sleep before retrying on rate limit errors. Defaults to 1.

  • download_timeout: The timeout for the download operation, in seconds. This defines the maximum time allowed for downloading files before the operation is considered a failure. Defaults to 120.

Assumptions and defaults

Translation files

This workflow assumes that the translations_path option can include one or more directories where your translation files are stored. By default, each folder specified in translations_path should contain subfolders named after your project locales. For example, if your base language is en, there should be a folder named en inside each specified path. Here's an example directory structure:

locales/
├── en/
│   ├── main.json
│   └── admin.json
└── fr/
    ├── main.json
    └── admin.json

When managing translation keys on Lokalise, ensure the filenames match your repository structure. If you store translations under translations_path/%LANG_ISO%/, the filenames assigned to the keys must follow this pattern: translations_path/%LANG_ISO%/TRANSLATION_FILE_NAME.

Nested files

Nested folders are fully supported. For example, you can organize files like this: locales/en/nested_folder/main.json.

Flat naming convention

If your translation files are stored directly in the translations_path without locale-specific subfolders (e.g., locales/en.json or locales/fr.json), set the flat_naming parameter to true. Here's an example of a flat naming structure:

locales/
├── en.json
├── fr.json
└── de.json

Tags

Every translation key uploaded to Lokalise via the Push action is automatically tagged with the name of the branch that triggered the workflow. For example, if the workflow is triggered by the lokalise-hub branch, all affected keys will receive a lokalise-hub tag.

When running the Pull action, the workflow filters keys by the tag matching the branch name. For instance, if you run the Pull action from the lokalise-hub branch, only keys tagged with lokalise-hub will be downloaded, while other keys will be ignored.

To ensure all relevant keys are included in the workflow, it’s essential to retain these tags. If a tag is removed by mistake, you can reassign it manually via the Lokalise UI.

Ignoring tags on pull

If you need to pull all keys regardless of the assigned tags, set the skip_include_tags option to true. You can also provide custom filtering options via additional_params, for example --include-tags staging,dev.

Note on cron jobs

You can easily schedule your workflows using cron (POSIX syntax). To do that, add a new schedule event.

on:
  schedule:
    - cron: "0 0 * * *"

In this example, the workflow will run every day at midnight. If you need help creating the right schedule, check out this cron expression generator.

A few things to keep in mind:

  • Scheduled workflows always run on the latest commit from the default or base branch.
  • The minimum interval for running scheduled workflows is every 5 minutes.
  • You can use if conditions to skip specific times: if: github.event.schedule != '30 5 * * 1,3'.
  • Watch out for GitHub Actions quotas. On the Free plan, you get 2000 minutes per month.