> ## Documentation Index
> Fetch the complete documentation index at: https://sonamu.cartanova.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Localized DB Columns

> Handling localized columns such as name_ko, name_en or locale maps

When you need to store multilingual values in the database, you can use locale-specific columns like `name`, `name_ko`, `name_en`, or a locale map like `name: { ko: "...", en: "..." }`. Sonamu automatically selects the appropriate value for the current locale using the `localizedColumn()` function.

## localizedColumn Function

```typescript theme={null}
import { localizedColumn } from "../i18n/sd.generated";

const tag = {
  id: 1,
  name: "default",
  name_ko: "태그",
  name_en: "Tag",
};

const nestedTag = {
  id: 2,
  name: {
    ko: "태그",
    en: "Tag",
  },
};

// When Context locale is "ko"
localizedColumn(tag, "name"); // "태그"
localizedColumn(nestedTag, "name"); // "태그"

// When Context locale is "en"
localizedColumn(tag, "name"); // "Tag"
localizedColumn(nestedTag, "name"); // "Tag"

// When Context locale is "fr" (unsupported locale)
localizedColumn(tag, "name"); // "태그" (uses the default locale)
```

## Priority Order

`localizedColumn()` looks for values in the following order:

| Current locale | Priority                       |
| -------------- | ------------------------------ |
| `ko`           | `name_ko` → `name` → `name_en` |
| `en`           | `name_en` → `name` → `name_ko` |

When suffix columns and a locale map both exist, the suffix column for the current locale is checked first, then the locale map value. Empty strings (`""`) and `null` are skipped, and the next priority is checked.

## Entity Definition

Example of an Entity with multilingual columns:

```json theme={null}
{
  "id": "Tag",
  "table": "tags",
  "props": [
    { "name": "id", "type": "integer" },
    { "name": "name", "type": "string", "length": 100, "desc": "Default name" },
    { "name": "name_ko", "type": "string", "length": 100, "nullable": true, "desc": "Korean name" },
    { "name": "name_en", "type": "string", "length": 100, "nullable": true, "desc": "English name" }
  ]
}
```

## Using in Models

### Processing in Subset

You can use `localizedColumn` in a Subset's enhancer to deliver only a single `name` field to the client:

```typescript theme={null}
import { localizedColumn } from "../i18n/sd.generated";

class TagModelClass extends BaseModelClass {
  async findMany<T extends TagSubsetKey>(subset: T, params: TagListParams) {
    // ...

    const enhancers = this.createEnhancers({
      A: (row) => ({
        ...row,
        // Replace with locale-appropriate name
        displayName: localizedColumn(row, "name"),
      }),
    });

    return this.executeSubsetQuery({ subset, qb, params, enhancers });
  }
}
```

### Using in API Response

```typescript theme={null}
@api({ httpMethod: "GET" })
async getTagOptions(): Promise<{ id: number; label: string }[]> {
  const tags = await this.findMany("A", { num: 100 });

  return tags.rows.map(tag => ({
    id: tag.id,
    label: localizedColumn(tag, "name") ?? tag.name,
  }));
}
```

## Using in Frontend

The same function can be used in the frontend (exported from web's sd.generated.ts):

```tsx theme={null}
import { localizedColumn } from "@/i18n/sd.generated";

function TagBadge({ tag }: { tag: Tag }) {
  return <span className="badge">{localizedColumn(tag, "name")}</span>;
}
```

## Supported Value Shapes

`localizedColumn()` supports two storage shapes:

| Shape          | Example                             | Description                                             |
| -------------- | ----------------------------------- | ------------------------------------------------------- |
| Suffix columns | `name`, `name_ko`, `name_en`        | Store one column per locale.                            |
| Locale map     | `{ name: { ko: "태그", en: "Tag" } }` | Store locale-specific values in the base column object. |

The selected value can be a `string` or `string[]`. `string[]` values are returned as arrays and are not stringified. For suffix columns or base columns, scalar values such as `number`, `boolean`, or `bigint` are stringified for backward compatibility.

## Suffix Column Naming Patterns

| Base column   | Locale columns                     | Description |
| ------------- | ---------------------------------- | ----------- |
| `name`        | `name_ko`, `name_en`               | Name        |
| `title`       | `title_ko`, `title_en`             | Title       |
| `description` | `description_ko`, `description_en` | Description |
| `content`     | `content_ko`, `content_en`         | Content     |

<Note>
  When using suffix columns, use the `{base_column}_{locale}` format. When using a locale map, the base column value can store the locale-specific object.
</Note>

## Important Notes

* `localizedColumn` is simply a function that selects column values. Query optimization (SELECTing only necessary columns) must be handled separately.
* If all locale columns are `null` and the base column is also empty, `undefined` is returned.
* If locale is not set in Context, `defaultLocale` is used.
* If Context locale is unsupported, values are resolved from `defaultLocale`.

<CardGroup cols={2}>
  <Card title="i18n Setup" icon="gear" href="/en/advanced-features/i18n/setup">
    Initial i18n configuration
  </Card>

  <Card title="Using the SD Function" icon="code" href="/en/advanced-features/i18n/dictionary">
    Writing and using dictionaries
  </Card>
</CardGroup>
