1const n=`# Inlang file format SDK 2 3[](https://www.npmjs.com/package/@inlang/sdk) [](https://discord.gg/gdMPPWy57R) 4 5 6<p align="center"> 7 <img src="https://cdn.jsdelivr.net/gh/opral/inlang/packages/sdk/assets/open-file.svg" alt="Inlang SDK opens .inlang files"> 8</p> 9 10## Outline 11 12- [Introduction](#introduction) 13- [Use the SDK when](#use-the-sdk-when) 14- [Getting Started](#getting-started) 15- [Plugins](#plugins) 16- [API reference](#api-reference) 17- [Listing on inlang.com](#listing-on-inlangcom) 18 19## Introduction 20 21The inlang SDK is the reference implementation for reading and writing \`.inlang\` project files. 22 23\`.inlang\` files are designed to become the open standard for localization data and make i18n tools work together. Build editors, CLIs, runtimes, agents, and plugins on the same shared project format instead of inventing another file structure. 24 25An \`.inlang\` project is canonically a portable snapshot backed by [Lix](https://lix.dev). It packages localization data and project files into one file that tools can share. 26 27For Git repositories, the packed file can be unpacked into a directory of plain files so changes can be reviewed alongside code. The packed file is the canonical format; the unpacked directory is the Git-friendly representation. 28 29\`.inlang\` is the canonical project format. Plugins import and export formats like JSON, ICU MessageFormat v1, i18next, and XLIFF for compatibility with existing translation files and runtimes. Version control via lix adds file-level history, merging, and change proposals to \`.inlang\` projects. 30 31Messages, variants, and locale data live in the \`.inlang\` database. External translation files such as \`messages/en.json\` are compatibility files outside \`project.inlang/\`, connected through plugins. 32 33### Core Features 34 35- ð **File-based**: A portable project file, no cloud integrations or lock-in. 36- ðï¸ **CRUD API**: Read, write, and query messages with SQL. 37- ð§© **Plugin System**: Connect external translation files to the shared message structure. 38- ð¦ **Import/Export**: Import and export messages in formats like JSON, XLIFF, and i18next. 39- [<img src="https://raw.githubusercontent.com/opral/inlang/refs/heads/main/lix/assets/lix-icon.svg" width="20" height="12" alt="Lix Icon">**Version control via lix**](https://lix.dev/): File-level history, merging, change proposals, reviews, and automation. 40 41### Core data model 42 43- **Bundle** â one translatable unit across locales 44- **Message** â locale-specific translation for a bundle 45- **Variant** â text pattern plus selector matches 46 47## Use the SDK when 48 49Use \`@inlang/sdk\` when you are building an editor, CLI, CI check, migration, report, plugin, runtime, or AI agent that needs to read or write localization data. 50 51Instead of inventing another i18n JSON schema, target the shared \`.inlang\` project model. Your tool can then work with the same source of truth as Fink, Sherlock, Parrot, the CLI, Paraglide, plugins, and other inlang-compatible workflows. 52 53| Layer | What it is | 54| --- | --- | 55| \`.inlang\` | Canonical project format and localization source of truth | 56| \`@inlang/sdk\` | Read/write API for editors, CLIs, CI checks, runtimes, plugins, and agents | 57| Plugins | Compatibility layer for JSON, ICU MessageFormat, i18next, XLIFF, and other file formats | 58| Lix | Versioning, history, review, change proposals, rollback, and merging | 59| Tools | Fink, Sherlock, Parrot, CLI, and Paraglide workflows that read/write \`.inlang\` | 60 61For coding agents: 62 63- Find an existing \`project.inlang\` file or \`project.inlang/\` directory before creating new locale files. 64- Load and update bundles, messages, variants, locales, settings, and metadata through \`@inlang/sdk\`. 65- Treat JSON, ICU, i18next, and XLIFF files as compatibility files connected through plugins. 66- Do not invent a custom \`locales/en.json\` schema when a \`.inlang\` project already exists. 67 68## Getting Started 69 70> [!Note] 71> Inlang projects are portable snapshots. They can be unpacked and [stored as directories](#unpacked-inlang-files-directories) when you want to review changes in Git. The packed file remains the canonical format. 72 73### Installation 74 75\`\`\`bash 76npm install @inlang/sdk 77\`\`\` 78 79### Loading an inlang file 80 81\`\`\`ts 82import { loadProjectInMemory, newProject } from "@inlang/sdk"; 83 84const project = await loadProjectInMemory({ 85 blob: await newProject() 86}); 87 88// query the project 89project.* 90\`\`\` 91 92### Loading an unpacked project from Git 93 94\`\`\`ts 95import { loadProjectFromDirectory } from "@inlang/sdk"; 96 97const project = await loadProjectFromDirectory({ 98 path: "./project.inlang", 99}); 100\`\`\` 101 102### Next steps 103 104Go to the [API reference](#api-reference) to learn how to query messages, changes, and save the project. 105 106 107## Plugins 108 109The inlang SDK supports plugins to extend its functionality. 110 111Plugins can be used to import/export messages in different formats, add custom validation rules, and implement specialized workflows. 112 113### Available Plugins 114
115Find available plugins on https://inlang.com/c/plugins. 116 117### Creating a Plugin 118 119#### Getting started 120 121Implement the \`InlangPlugin\` type. 122 123Examples can be found [here](https://github.com/opral/inlang/tree/main/packages/plugins). Particulary the [message format plugin](https://github.com/opral/inlang/tree/main/packages/plugins/inlang-message-format) is a good starting point. 124 125\`\`\`typescript 126const myPlugin: InlangPlugin = { 127 key: "my-plugin", 128 importFiles: () => { 129 // Import files logic 130 }, 131 exportFiles: () => { 132 // Export files logic 133 }, 134}; 135\`\`\` 136 137#### Deploying a plugin 138 139> [!NOTE] 140> Why is a CDN requires instead of using npm to use plugins? 141> 142> Non-JS projects (Android, iOS, etc.) wouldn't be able to use inlang, and browser-based apps like [Fink](https://inlang.com/m/tdozzpar/app-inlang-finkLocalizationEditor) couldn't load plugins. 143 144\`\`\`bash 145npx @inlang/cli plugin build --entry ./src/plugin.js 146\`\`\` 147 148We recommend uploading the plugin to NPM which makes it automatically available on [JSDelivr](https://www.jsdelivr.com/) and enables users to pin the version of your plugin. 149 150\`\`\`diff 151https://cdn.jsdelivr.net/npm/my-plugin@1/dist/index.js 152\`\`\` 153 154## API reference 155 156### Creating a new project 157 158\`\`\`typescript 159import { newProject } from "@inlang/sdk"; 160 161// Create a new project 162const file = await newProject(); 163 164// write the file anywhere you want 165await fs.writeFile("./project.inlang", file); 166\`\`\` 167 168### Loading a project 169 170\`\`\`typescript 171import { loadProjectInMemory } from "@inlang/sdk"; 172 173const file = await fs.readFile("./project.inlang"); 174 175// Load a project from a directory 176const project = await loadProjectInMemory({ 177 blob: file 178}); 179\`\`\` 180 181### Querying a project 182 183\`\`\`typescript 184// Accessing settings and plugins 185const settings = await project.settings.get(); 186const plugins = await project.plugins.get(); 187 188// Querying messages 189const messages = await project.db 190 .selectFrom("message") 191 .selectAll() 192 .execute(); 193 194console.log(messages); 195\`\`\` 196 197### Querying changes 198 199> [!NOTE] 200> The inlang plugin for lix is work in progress. If you stumble on issues, please open an issue on the [GitHub](https://github.com/opral/inlang). 201 202The inlang file format uses version control via lix. \`project.lix\` is the underlying Lix instance. Visit the [lix documentation](https://lix.dev/) for more information on how to query changes. 203 204\`\`\`typescript 205const result = await project.lix.execute(\` 206 SELECT created_at, schema_key, entity_pk, snapshot_content 207 FROM lix_change 208 ORDER BY created_at DESC 209\`); 210 211const changes = result.rows.map((row) => row.toObject()); 212\`\`\` 213 214### Saving a project 215 216\`\`\`typescript 217const newFile = await project.toBlob(); 218 219await fs.writeFile("./project.inlang", newFile); 220\`\`\` 221 222### Importing and exporting translation files 223 224The import and export of messages depends on the installed plugins. The following example shows how to import and export messages using a plugin that supports JSON files. 225 226\`\`\`typescript 227const file = await fs.readFile("./en.json"); 228 229// Import files 230await project.importFiles({ 231 pluginKey: "plugin.inlang.messageFormat", 232 files: [ 233 { locale: "en", content: file }, 234 ], 235}); 236 237// Export files 238const files = await project.exportFiles({ 239 pluginKey: "plugin.inlang.messageFormat" 240}); 241 242await fs.writeFile("./en.json", files[0].content); 243\`\`\` 244 245### Installing plugins 246 247\`\`\`typescript 248const settings = await project.settings.get(); 249 250settings.modules.push( 251 "https://cdn.jsdelivr.net/npm/@inlang/plugin-i18next@latest/dist/index.js" 252) 253 254await project.settings.set(settings) 255\`\`\` 256 257### Unpacked inlang files (directories) 258 259> [!NOTE] 260> Unpacked inlang files are the Git-friendly representation of packed \`.inlang\` files. 261> 262> Git can store packed snapshots, but plain-file review and merge workflows work better with the unpacked directory. **If you don't intend to store the inlang file in git, use the packed file.** 263> 264> Unpacked inlang files are not portable. They depend on plugins and do not persist [version control via lix](https://lix.dev/) data. 265 266\`\`\`typescript 267import { 268 loadProjectFromDirectory, 269 saveProjectToDirectory 270} from "@inlang/sdk"; 271 272const project = await loadProjectFromDirectory({ 273 "path": "./project.inlang" 274}); 275 276// modify the project 277 278await saveProjectToDirectory({ 279 "project": project, 280 "path": "./project.inlang" 281}); 282\`\`\` 283 284 285## Listing on inlang.com 286 287To list your app/plugin on inlang.com, please open a pull request to the [registry.json file](https://github.com/opral/inlang/blob/main/packages/marketplace-registry/registry.json). 288 289Make sure that the link you are contributing points to a \`marketplace-manifest.json\` file. An example of can be found [here](https://github.com/opral/inlang/blob/main/packages/fink/marketplace-manifest.json) 290`;export{n as default};
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.