Error: translations are not being consumed when using Custom File Format importer

Hi Team, I hope you’re doing great.

I’m reaching since we’re having the same issue that we faced before with the Custom File Format (CFF) tool that we reported in this ticket from Jul 2025: Error when importing translations when using Custom File Format

We haven’t made any change to the importer code and now the translations are not being imported for new files.

Our project (ID: 732337) is already configured with 3 languages (en, es-ES, jp) and the CFF importer and exporter are correctly setup as per the documentation. When uploading the file (using the UI: Project > Sources > Add file), the source (english) is uploaded without issues, but the translations are empty despite them being present in the imported file, as you can see in the following screenshot:

We tried everything we tried before, and also using different configurations and options with the CLI, but it seems that the strings.translations array is not being consumed by the CFF parser despite it’s being set correctly (we know it’s set since we send the whole entry to the strings.context as JSON.stringify (see our code below and previous image too) .

Also, we noticed the targetLanguages global variable is not set with the languages we configured in the project. We recieve it as empty ([]), so that’s why we are using a forcedLanguages list to build the strings.translations as required. But it’s not working either way to solve the issue.

Could you please help us figure out what could be happening?


Here’s an example of a string that is pushed to the strings env variable (you can see it on the previous screenshot too):

{
  "identifier": "pm01_01-start.00",
  "text": "Good morning! I'm the new employee, Mizugaki\\nTsukasa!",
  "context": "Original Text: おはようございます! 新入社員の、水柿ツカサと言います!",
  "labels": [
    "character:Tsukasa",
    "scene-type:default",
    "scene-label:start",
    "scene-title:「はじめてのパートナー」",
    "filename:pm01_01.txt"
  ],
  "isHidden": false,
  "customData": "character:Tsukasa",
  "translations": {
    "en": {
      "text": "Ah, good morning.",
      "status": "approved"
    },
    "ja": {
      "text": "おはようございます! 新入社員の、水柿ツカサと言います!",
      "status": "approved"
    },
    "es-ES": {
      "text": "",
      "status": "untranslated"
    }
  },
  "targetLanguages": []
}

cff.importer.js

/**
 * Crowdin - Custom file importer
 *
 * @see https://store.crowdin.com/cff
 * @see https://support.crowdin.com/developer/crowdin-apps-module-custom-file-format/#strings-array-structure
 */
const contentObj = JSON.parse(content);
const forcedTargetLanguages = [
  {id: 'en'},
  {id: 'ja'},
  {id: 'es-ES'},
];

for (const scene of Object.values(contentObj['texts'])) {
  for (const textId in scene) {

    const item = scene[textId];
    let stringObj = {
      identifier: textId,
      text: item.text,
      context: item.context,
      labels: item.labels,
      isHidden: item.isHidden || false,

      // Max 4k of custom data
      customData: item.customData,

      // Translations per lang
      translations: {}
    };


    // If importing translations
    // Note: forcing target languages `targetLanguages` is sent empty
    let contextTranslations = {};
    // const languages = targetLanguages || [];
    const languages = forcedTargetLanguages || [];

    if (languages.length > 0) {

      stringObj.translations = {};
      for (const lang of languages) {

        // Continue if target translation doesn't exist
        if (!Object.keys(item.translations).includes(lang.id)) {
          continue;
        }

        const translation = item.translations[lang.id];
        stringObj.translations[lang.id] = {
          text: translation.text,
          status: translation.status || 'untranslated' // Default status
        };

        contextTranslations[lang.id] = stringObj.translations[lang.id];
      }
    }

    contextTranslations['item'] = item;
    
    // here we're pushing the `targetLanguages` value to the context
    // and using `context` as way to debug what is being built in the
    // importer script
    stringObj['targetLanguages'] = targetLanguages || 'empty'; 
    stringObj['context'] = JSON.stringify(stringObj);

    strings.push(stringObj);
  }
}

crowdin.yml

project_id: "732337" # plastic-memories-vn
# api_token: XYZ    # token should be put in $HOME/.crowdin.yml

base_path: "."
base_url: "https://api.crowdin.com"

preserve_hierarchy: true

files:
  - source: "translations-manager/texts/for-crowdin/*.txt_crowdin.json"
    dest: "%original_file_name%"
    translation: "translations-manager/texts/for-crowdin/%original_file_name%"
    scheme: crowndefined
    crowdin_format: custom_multilingual
    languages_mapping:
      two_letters_code:
        en: en
        es-ES: es-ES
        ja: ja

file-to-import.json

{
  "filename": "pm01_01.txt",
  "labels": [
    "filename:pm01_01.txt"
  ],
  "texts": {
    "start": {
      "pm01_01-start.00": {
        "text": "Good morning! I'm the new employee, Mizugaki\\nTsukasa!",
        "translations": {
          "ja": {
            "text": "おはようございます! 新入社員の、水柿ツカサと言います!",
            "status": "approved"
          },
          "en": {
            "text": "Ah, good morning.",
            "status": "approved"
          },
          "es-ES": {
            "text": "",
            "status": "untranslated"
          }
        },
        "context": "Original Text: おはようございます! 新入社員の、水柿ツカサと言います!",
        "character": "Tsukasa",
        "isHidden": false,
        "labels": [
          "character:Tsukasa",
          "scene-type:default",
          "scene-label:start",
          "scene-title:「はじめてのパートナー」",
          "filename:pm01_01.txt"
        ],
        "customData": "character:Tsukasa"
      },
      "pm01_01-start.01": {
        "text": "Ah, good morning.",
        "translations": {
          "ja": {
            "text": "はい、おはようございます",
            "status": "approved"
          },
          "en": {
            "text": "Ah, good morning.",
            "status": "approved"
          },
          "es-ES": {
            "text": "",
            "status": "untranslated"
          }
        },
        "context": "Original Text: はい、おはようございます",
        "character": "Receptionist",
        "isHidden": false,
        "labels": [
          "character:Receptionist",
          "scene-type:default",
          "scene-label:start",
          "scene-title:「はじめてのパートナー」",
          "filename:pm01_01.txt"
        ],
        "customData": "character:Receptionist"
      }
    }
  }
}

crowdin CLI - Output

$> crowdin language list
◇  Project info fetched
◆  es-ES Spanish
◆  ja Japanese
◆  en English

$> crowdin upload sources
◇  Project info fetched
◇  Project files fetched
◆  File 'pm01_01.txt_crowdin.json'

Thank you Team for your help!

Hi @enoshima.memo.team, thank you for the detailed description, let us please kindly re-check everything and come back once we have some news

1 Like