Skip to main content

Output Directory

The CLI outputs data from Ditto by writing files to disk. By default, these files are written to a ./ditto  folder relative to the current working directory, but the location of the output files can be customized by defining the outDir property in your config.yml file or by setting the environment variable DITTO_OUT_DIR.

./ditto Directory

By default, this directory houses the configuration file (./ditto/config.yml) used by the CLI and is also the default write destination for any output files the CLI writes to disk. You can override the default location of the config file by using the --config flag when running any command or by setting the environment variable DITTO_PROJECT_CONFIG_FILE . Legacy Ditto users can use the config override path to support maintaining separate config files for the legacy and current versions of Ditto within the same application. If you run the CLI and the resolved config file does not exist, the CLI will automatically create a default config.yml file at the path specified.

String File Naming Conventions

All string files created will generally adhere to the following template:
{project_id}___{variant_id}.{extension}
  • project_id: the Developer ID of the project.
  • variant_id: the Developer ID of a variant or base for files generated for non-variant text
  • extension: the file extension that corresponds to the configured format(s) (e.g., json, xml, strings, stringsdict)
If components is included in the config, a single, combined file for all fetched components will also be created for each variant with the format components__{variant_id}.{extension}. To keep cross-platform behavior consistent, file names will be fully lowercase, have whitespace replaced with hyphens, and have non-word characters (with the exception of - and _) removed.

Format-specific Files

JSON

If one or more JSON string formats are configured, a series of json files will be generated, on a project-variant/components-variant pair basis. Generally each file will follow the shown format:
{
  "text-item-developer-id": "string with {{variableId}} variables escaped",
  ...,
  "text-item-with-plural-dev-id": "string with {{count}} characters",
  "text-item-with-plural-dev-id_other": "string with {{count}} characters",
  "text-item-with-plural-dev-id_one": "string with a character",
	...,
  "welcome": "Hello {{userFirstName}}!"
}
Additionally, a variables.json file will be generated that contains information about any variables used within the fetched text. The file has the following format:
{
  "text-variable-id": {
    "example": "example_value",
    "fallback": "default_value"
  },
  "number-variable-id": {
    "example": "1",
    "fallback": "10"
  },
  "link-variable-id": {
    "text": "URL display text",
    "url": "https://dittowords.com"
  },
  "list-variable-id": ["value1", "value2", "value3"],
  "map-variable-id": {
    "key1": "value1",
    "key2": "value2",
    "key3": "value3"
  }
}

Android XML

If android format is configured for an output, a series of .xml files will be generated, on a project-variant/components-variant pair basis. Generally each file will follow the shown format:
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
  <string name="text-item-developer-id" ditto_api_id="text-item-developer-id">string with <xliff:g id="variableId" example="example_value">%1$s</xliff:g> variables</string>
  <string name="continue" ditto_api_id="continue">Continue</string>
  <string name="email" ditto_api_id="email">Email</string>
  <string name="hello" ditto_api_id="hello">Hello, <xliff:g id="FirstName" example="John">%1$s</xliff:g></string>
  <string name="log-in" ditto_api_id="log-in">Log In</string>
  <string name="save" ditto_api_id="save">Save</string>
  <string name="submit" ditto_api_id="submit">Submit</string>
  <plurals name="the_one_ring" ditto_api_id="the-one-ring">
    <item quantity="many">The <xliff:g id="count__1" example="4">%1$s</xliff:g> rings to rule them all</item>
    <item quantity="few">A few rings to rule them all</item>
  </plurals>
  <string name="welcome" ditto_api_id="welcome">Welcome, <xliff:g id="FirstName" example="John">%1$s</xliff:g>!</string>
</resources>

iOS Strings

If iOS Strings format is configured, a series of .strings files will be generated, on a project-variant/components-variant pair basis. Generally each file will follow the shown format:
"text-item-developer-id" = "string with %1$@ variables";

"continue" = "Continue";

"email" = "Email";

"hello" = "Hello, %1$@";

"log-in" = "Log In";

"save" = "Save";

"submit" = "Submit";

"welcome" = "Welcome, %1$@!";

iOS StringsDict

If iOS StringsDict format is configured, a series of .stringsdict files will be generated, on a project-variant/components-variant pair basis. Generally each file will follow the shown format:
<?xml version="1.0" encoding="utf-8"?>
<plist version="1.0">
  <dict>
    <key>the-one-ring</key>
    <dict>
        <key>NSStringLocalizedFormatKey</key>
        <string>%1$#@count@</string>
        <key>count</key>
        <dict>
            <key>NSStringFormatSpecTypeKey</key>
            <string>NSStringPluralRuleType</string>
            <key>NSStringFormatValueTypeKey</key>
            <string>d</string>
            <key>one</key>
            <string>The one ring to rule them all</string>
            <key>other</key>
            <string>The %2$@ rings to rule them all</string>
        </dict>
    </dict>
  </dict>
</plist>

Framework-specific Files

Within each output format, an optional framework can be provided. The framework generates additional helper files to assist with using the output strings files with common third party libraries. Currently, we support two frameworks: i18next and vue-i18n .

i18next

Formats supported: JSON Supported Properties:

type: “commonjs” | “module” (default “commonjs”)

By default, additional javascript files will be generated using commonjs syntax. This property configures the output to use commonjs or module syntax in the generated files. Details: Generates an additional javascript file that imports the generated strings files, and exports an object with the json strings grouped by their variants. If included, components will always be applied last.
// CommonJS
const exampleProject1Base = require("./example-project-1__root__base.json");
const exampleProject1Spanish = require("./example-project-1__root__spanish.json");
const exampleProject2Base = require("./example-project-2__base.json");
const exampleProject2Spanish = require("./example-project-2__spanish.json");
const componentsBase = require("./components__base.json");
const componentsSpanish = require("./components__spanish.json");

module.exports = {
  base: {
    ...exampleProject1Base,
    ...exampleProject2Base,
    ...componentsBase,
  },
  spanish: {
    ...exampleProject1Spanish,
    ...exampleProject2Spanish,
    ...componentsSpanish,
  },
};

// ESM
import exampleProject1Base from "./example-project-1__root__base.json";
import exampleProject1Spanish from "./example-project-1__root__spanish.json";
import exampleProject2Base from "./example-project-2__base.json";
import exampleProject2Spanish from "./example-project-2__spanish.json";
import componentsBase from "./components__base.json";
import componentsSpanish from "./components__spanish.json";

export default {
  base: {
    ...exampleProject1Base,
    ...exampleProject2Base,
    ...componentsBase,
  },
  spanish: {
    ...exampleProject1Spanish,
    ...exampleProject2Spanish,
    ...componentsSpanish,
  },
};

vue-i18n

Formats supported: JSON Functions very similarly and accepts all the same config properties as the i18next framework. The main difference is variable interpolation uses single brackets instead of double.
{
	"text-item-developer-id": "string with {variableId} variables escaped",
	...,
	"welcome": "Hello {userFirstName}!"
}

Ditto-generated Files

Ditto.swift

If iosLocales is configured at the root level of the project config, a Ditto.swift file will be auto-generated in conjunction with the respective locale .lproj directories.
import SwiftUI

struct Ditto {
    static func getBundle(_ locale: String? = nil) -> Bundle {
        var bundle: Bundle? = nil
        if (locale != nil) {
            let path = Bundle.main.path(forResource: locale, ofType: "lproj")
            if (path != nil) {
                bundle = Bundle(path: path!)
            }
        }
        return bundle ?? Bundle.main
    }

    /// [Open component in Ditto](http://app.dittowords.com/library?selectedLibraryComponentIds=<component-id>)
    ///
    /// - Returns: The localized string for the Ditto identifier "continue"
    public static func continue(_ localeOverride: String? = nil) -> String {
        String.localizedStringWithFormat(NSLocalizedString("continue", tableName: "components", bundle: getBundle(localeOverride), comment: ""))
    }

    /// [Open component in Ditto](http://app.dittowords.com/library/<folder-id>?selectedLibraryComponentIds=<component-id>)
    ///
    /// - Returns: The localized string for the Ditto identifier "hello"
    public static func hello(_ localeOverride: String? = nil, FirstName: String) -> String {
        String.localizedStringWithFormat(NSLocalizedString("hello", tableName: "components", bundle: getBundle(localeOverride), comment: ""), FirstName)
    }

    struct myDittoProject {
        /// [Open text item in Ditto](http://app.dittowords.com/projects-beta/<project-id>?viewState=text&selectedTextItemIds=<text-item-id>)
        ///
        /// - Returns: The localized string for the Ditto identifier "email"
        public static func email(_ localeOverride: String? = nil) -> String {
            String.localizedStringWithFormat(NSLocalizedString("email", tableName: "my-ditto-project", bundle: Ditto.getBundle(localeOverride), comment: ""))
        }

        /// [Open text item in Ditto](http://app.dittowords.com/projects-beta/<project-id>?viewState=text&selectedTextItemIds=<text-item-id>)
        ///
        /// - Returns: The localized string for the Ditto identifier "submit"
        public static func submit(_ localeOverride: String? = nil) -> String {
            String.localizedStringWithFormat(NSLocalizedString("submit", tableName: "my-ditto-project", bundle: Ditto.getBundle(localeOverride), comment: ""))
        }
    }
}