# Custom Multilingual File Format > Use custom code to import and export your multilingual proprietary file format. URL: https://store.crowdin.com/cmff Category: File Formats Type: App Author: Awesome Crowdin This app allows you to import and export proprietary or uncommon **(multilingual)** file formats into Crowdin. It ensures that your file's structure, metadata and contextual information are preserved throughout the translation process. Check the Crowdin Store for the custom file app format if you need to [translate a single language file](https://store.crowdin.com/cff). ## Configuration Requirements Important: The app must be properly configured for it to function as expected. If the configuration is missing, it won’t be able to process files. The app may cause errors during import/export if used without the appropriate configuration. ## Key Features - Import/Export Custom Formats: Directly handle your unique file formats within Crowdin, with no need for manual conversion. - Preserve File Structure: Maintain your file’s original structure, including comments and metadata, to ensure context is available for translators. - Language Mapping: Map non-standard language codes in your files to Crowdin’s standard codes for compatibility (should be done in your code). - User-Defined Parsing: Define how your files are parsed and reconstructed, allowing Crowdin to support virtually any file format. ## Custom code To use this app, you will need to provide two code snippets: one for importing your file format into Crowdin and another for exporting translations back into the original format. You can use this [GPT](https://chatgpt.com/g/g-sswU8ps5H-custom-file-format-for-crowdin-code-writer) to generate the necessary code, tailored specifically to your file format. If you need assistance, the Crowdin Support team is available to help you create these code snippets, ensuring a smooth integration process. ## Screenshot ![Custom multilingual file translation with Crowdin](https://developers.app.crowdin.net/api/media/file/66306cc4-0126-4918-b6e3-e174afd49f89.png) ## Sample Import Code This is the importer and exporter for a JSON file like the following: ```json { "en": { "key1": "string", "key2": "string 2", "key3": "string 3" }, "de": { "key1": "Zeichenkette", "key2": "Zeichenkette 2", "key3": "Zeichenkette 3" }, "fr": { "key1": "string", "key2": "string 2", "key3": "string 3" } } ``` ```javascript const languagesMapping = { en: 'en', de: 'de', fr: 'fr' }; try { const contentJson = JSON.parse(content); for (const key in contentJson.en) { let stringObject = { identifier: key, text: contentJson.en[key], translations: {} }; for (const langCode in contentJson) { if (langCode !== 'en' && contentJson[langCode][key]) { const crowdinLangCode = languagesMapping[langCode]; stringObject.translations[crowdinLangCode] = { text: contentJson[langCode][key], status: 'translated' }; } } strings.push(stringObject); } } catch (e) { error = `Failed to parse content: ${e.message}`; } ``` ### Sample Export Code ```javascript const languagesMapping = { en: 'en', de: 'de', fr: 'fr' }; try { let contentJson = JSON.parse(content); for (const stringObj of strings) { const key = stringObj.identifier; // Update source text in the "en" section if (!contentJson.en) contentJson.en = {}; contentJson.en[key] = stringObj.text; // Update translations for (const [langCode, translation] of Object.entries(stringObj.translations)) { const fileLangCode = Object.keys(languagesMapping).find(k => languagesMapping[k] === langCode); if (!contentJson[fileLangCode]) contentJson[fileLangCode] = {}; contentJson[fileLangCode][key] = translation.text; } } content = JSON.stringify(contentJson, null, 4); } catch (e) { error = `Failed to process strings: ${e.message}`; } ``` ## Guide for Developing Custom File Format Code for Crowdin 1. **Importer Code**: Transforms the source file into an array of Crowdin string objects. 2. **Exporter Code**: Converts an array of Crowdin string objects back into a file that can be consumed by the user, including translations. ### Writing the Importer Code Your importer code should convert the file content into an array of Crowdin string objects. Here’s an example structure: ```javascript [ { "identifier": "string-key-1", "context": "Some context", // optional "maxLength": 10, // optional, default null "isHidden": false, // optional, default null "labels": ["label-one", "label-two"], // optional, default [] "text": "String source text", // required "translations": { "uk": { "text": "Переклад стрічки", // required "status": "untranslated | translated | approved" // optional, default "translated" } } } ] ``` ### Environment Variables Available in Import Code - **strings**: A global variable, an empty array where your code should populate Crowdin string objects. - **content**: Contains the source file content in UTF-8 encoding. - **error**: Set this variable to a string if your code encounters an error and cannot form the `strings` array. - **fileName**: The name of the source file (e.g., 'source-file.json'). - **filePath**: The file path within the Crowdin project (e.g., '/main/source-file.json'). - **fileId**: The unique ID for the file in Crowdin. - **targetLanguages**: An array of objects containing details about each target language. ### Writing the Exporter Code The exporter code should convert Crowdin string objects back into the original file format, with translations included. You will need to: - Read the source file content from the content variable. - Update the `content` variable with the new translated content before the code exits.