Easily convert files into many formats with Lokalise

Converting and working with different file formats is a pretty typical task these days. For instance, you might need to convert your JSON file into a CSV or XLSX, or turn an XML into a JSON while preserving all the content and making sure the output is valid. On top of that, you might need to edit the content before converting or even translate it for multiple languages and perform quality assurance. Is there a solution that can help with all these tasks? The answer is yes!

Today I’m going to show you how to easily convert your files into many formats with the help of Lokalise, a translation management system for agile teams. With Lokalise, you can:

  • Convert JSON to CSV and vice versa, convert JSON to XML and XML to XLSX, as well as perform conversion between many other file formats supported by the system, including YAML, INI, XLIFF, and RESX.
  • Customize conversion, filter content, and preview the results.
  • Edit the content easily with the graphical interface, and invite additional team members for collaboration.
  • Translate content into dozens of locales with ease. You can translate manually, use machine translation, employ artificial intelligence, or hire human professionals.
  • Use AI for quality assurance.
  • Automate conversion using the Lokalise API.

So, the sky’s the limit. In this tutorial, we are going to learn how to get started with Lokalise, import and export content, edit texts, and write automation scripts. Let’s dive in!

Special thanks to my colleague Alex Terehov for sharing the idea for this article.

    Getting started with Lokalise

    To get started with format conversion, grab your free two-week trial on the sign-up page (no credit card is needed!).

    After confirming your email, click Create your team (unless you’re already a part of a Lokalise team, that is).

    Next, follow the wizard’s instructions and provide your project name:

    Choose your base (or source) language. This is the original language of your content:

    If you are planning to translate your file contents into other locales, pick one or more target languages. If you plan to work only with the source language, you’ll still need to select any target language but it does not really matter which one. For instance, I’m going to pick French.

    On the next screen, you’ll be asked to create a new translation key. You can simply click Continue as we’ll upload a custom file instead.

    On the last screen, choose any platform and hit Get started:

    We are not going to discuss platforms as this feature is not relevant to this tutorial.

    Now you can close the wizard and click Editor in the top menu:

    Let’s then delete the sample key added by the wizard:

    Uploading files for conversion

    To upload one or multiple files, click on the corresponding button:

    Then choose your files:

    Let’s suppose we’d like to convert JSON to XML or JSON to CSV. We’ll therefore upload a JSON file with the following content:

    {
    	"welcome": "Welcome to the app, {{username}}!",
    	"sign_up": "Sign up",
    	"apples": {
    		"one": "I have one apple",
    		"other": "I have {{count}} apples"
    	}
    }

    Once the file is chosen, it’ll be added to the list:

    You can add more files as needed, regardless of the content language (any missing project languages will be added automatically).

    Now just press the Import files button or adjust some settings for more fine-grained control:

    You can find detailed information about these settings in our docs, but here are some options that might come in really handy:

    • Replace \n with line break — it’s usually safe to keep this option enabled. Any line breaks will be converted back to \n by default once you export content back.
    • Convert to universal placeholders — if your content contains any placeholders, you’ll definitely want to enable this option. For example, in the JSON file I’m going to upload there are two placeholders: {{username}} and {{count}}. Thing is, other file formats might use different placeholders, and the universal placeholders feature will help you lessen those differences.
    • Detect ICU plurals — if you are using plurals in the ICU format, enable this option. Typically such plurals are used in XLIFF files. If you don’t know what an ICU is, you most likely don’t use it.
    • Tag keys — this option might be very useful if you are uploading multiple files and would like to somehow differentiate your texts. Actually, with Lokalise you can easily filter texts by the file name, but by using tags, even more fine-grained control is possible.

    Importing will take place in the background, so you might need to wait a bit.

    Editing the uploaded content

    Once the upload process is complete, you can return to the editor and check out your content:

    To the left you can see your keys, and to the right are the corresponding values. The [%1$s:count] is the universal placeholder that was inserted by Lokalise because I enabled the Universal placeholders option. Don’t worry: these universal placeholders will be replaced with the platform-specific ones upon export. In fact, Lokalise even allows you to create custom placeholders as explained in the documentation.

    Now what? Well, you have a bunch of options.

    First, you can simply proceed to the Download page and export your content in a different format.

    Second, you can upload more files or even add content manually by clicking Add key:

    Learn more about adding keys in the docs.

    Third, you can translate your content into multiple locales with ease. For example, simply click Google-translate empty values under a key to add a French translation:

    Fourth, you can edit existing texts by clicking on them:

    Fifth, you can take advantage of artificial intelligence to translate the content for you:

    In fact, it’s also possible to use artificial intelligence to translate the whole project in one go by employing AI Translation tasks.

    But there’s much more: it’s possible to add more contributors to the project, assign tasks to them, hire professional translators, use Lokalise AI to review your texts, connect with third-party services, and exchange content with apps like Figma or Adobe XD. So yeah, Lokalise has lots to offer.

    Converting into multiple formats

    Anyways, let’s head to the Download page:

    Choose the target file format from the dropdown. For example, let’s convert from JSON to CSV:

    You might notice that these formats are separated into four categories: Android, iOS, Web, and Other. While it’s not too important for this tutorial, you should make a note of the category that the source and the target format belong to. If the categories are different, make sure to check the Include all platform keys option (otherwise no content will be exported):

    Now pick one or more languages to download:

    If needed, you can further adjust what content should be exported (for instance, you can filter your keys by tags or by file names):

    In the Advanced settings, you may further adjust how the keys should be sorted, how many spaces should be used for indentation, which placeholder format should be utilized, and much more. It’s not mandatory to adjust or understand all these settings, but it’s nice to know that you’re in full control:

    Finally, click Build and download or Preview to view the file contents in the browser:

    Here’s the preview of my JSON file converted to a CSV:

    Note that the universal placeholders have been properly replaced with the platform-specific ones. If the placeholders do not suit you, simply adjust the Placeholder format under Advanced settings.

    The downloaded archive will contain your content in the chosen format. If the file structure does not work for you, it’s possible to adjust the File structure setting on the Download page. You can learn more about all the download options in the docs.

    And so, this is basically it: we’ve just converted our JSON file to the CSV format—great job! Feel free to explore other formats that Lokalise supports along with its additional features as it can really make your life much simpler.

    Using the Lokalise API

    If you are a developer, you might be interested in learning how to write a script to convert files into different formats. To achieve this, you can take advantage of the Lokalise API. The detailed tutorial on the API can be found in my other blog post (it features examples in JS, Python, and Ruby), but let me quickly explain how to perform file uploads and downloads.

    API token and Project ID

    First, open Lokalise, click on the avatar in the bottom left corner, and choose Profile settings:

    Switch to the API tokens section and click Generate a token:

    Make sure to create a read/write token and copy-paste it into your script. Don’t publicly expose this token!

    Now, return to the Lokalise project that we created at the beginning of this tutorial and proceed to More > Settings:

    Make a note of the Project ID:

    Now you can start using the API!

    Writing a file uploading script

    The simplest way to test its functionality is by using our API playground, which enables you to send real requests with the help of a graphical interface. But, of course, we provide SDKs for the major programming languages.

    For instance, to send API requests with JS/TS, install the node-lokalise-api in your project:

    npm install @lokalise/node-api

    Then import it and initialize the client:

    import { LokaliseApi } from "@lokalise/node-api";
    
    async function main() {
      const lokaliseApi = new LokaliseApi({ apiKey: "YOUR API KEY HERE" });
    }
    
    main()
      .then(() => process.exit(0))
      .catch((error) => {
        console.error(error)
        process.exit(1)
      });

    To upload your file, add the following code:

    import { LokaliseApi } from "@lokalise/node-api";
    import path from "path";
    import fs from "fs/promises";
    import {fileURLToPath} from 'url';
    
    async function main() {
      const lokaliseApi = new LokaliseApi({ apiKey: "YOUR API KEY HERE" });
    
      // These two lines are needed only if you're using ESM:
      const __filename = fileURLToPath(import.meta.url);
      const __dirname = path.dirname(__filename);
    
      const i18nFolder = path.resolve(__dirname, 'i18n');
      const i18nFile = path.join(i18nFolder, 'en.json');
      const data = await fs.readFile(i18nFile, 'utf8');
      const buff = Buffer.from(data, 'utf8');
      const base64I18n = buff.toString('base64');
    
      const base64I18n = buff.toString('base64');
      const bgProcess = await lokaliseApi.files().upload(projectId, {
        data: base64I18n,
        filename: "en.json",
        lang_iso: "en",
      });
    
      await waitUntilUploadingDone(lokaliseApi, bgProcess.process_id, projectId);
    }
    
    main()
      .then(() => process.exit(0))
      .catch((error) => {
        console.error(error)
        process.exit(1)
      });

    Please note that the lang_iso option in the upload method should be replaced with your content’s actual locale.

    Also add the waitUntilUploadingDone() function:

    async function waitUntilUploadingDone(
      lokaliseApi: LokaliseApi,
      processId: string,
      projectId: string,
    ): Promise<string> {
      return new Promise<string>((resolve, reject) => {
        const interval = setInterval(async () => {
          try {
            const reloadedProcess = await lokaliseApi
              .queuedProcesses()
              .get(processId, {
                project_id: projectId,
              });
            if (reloadedProcess.status === "finished") {
              clearInterval(interval);
              resolve(reloadedProcess.status);
            }
          } catch (error) {
            clearInterval(interval);
            console.error("An error occurred:", error);
            reject("error");
          }
        }, 1000);
      });
    }

    That’s it!

    Converting and downloading content

    Now, in order to download your file back, you should install the adm-zip library (because the downloaded bundle is always an archive):

    npm install adm-zip

    Also, we’ll need a solution to make HTTP requests (it can be Axios, Got, Fetch, and so on). I’ll be using the Node Fetch API.

    Here’s the download script:

    import AdmZip from "adm-zip";
    
    // ...
    
    const downloadResponse = await lokaliseApi.files().download("YOUR PROJECT ID", {
      format: "json",
      original_filenames: true,
      directory_prefix: '',
      filter_langs: ['en'],
      indentation: '2sp',
    });
    
    const translationsUrl = downloadResponse.bundle_url;
    const zip = new AdmZip(await zipBuffer(translationsUrl));
    zip.extractAllTo(i18nFolder, true); // we use the variable from the "upload" script

    Use the format setting to adjust the output format and add the proper locale code for the filter_langs.

    Finally, code the zipBuffer() function:

    async function zipBuffer(translationsUrl: string): Promise<Buffer> {
      const response = await fetch(translationsUrl);
      const arrayBuffer = await response.arrayBuffer();
      return Buffer.from(new Uint8Array(arrayBuffer));
    }

    And, done!

    Find more sample apps working with the Lokalise API on our Developer Hub. Also note that Lokalise allows you to perform custom processing when uploading and downloading files. Examples can of this be found in the Developer Hub, too.

    Conclusion

    So, in this article we have seen how to easily convert files into many formats with the help of Lokalise. We’ve also discussed using the Lokalise API to automate this process.

    That’s it for today—I thank you for staying with me, and until the next time!

    Talk to one of our localization specialists

    Book a call with one of our localization specialists and get a tailored consultation that can guide you on your localization path.

    Get a demo

    Related posts

    Learn something new every two weeks

    Get the latest in localization delivered straight to your inbox.

    Related articles
    Localization made easy. Why wait?