Topolo Docs Topolo Platform
Open workspace

Update my language preferences

Update the caller's language and/or timezone preference.

Outcome

Update the caller's language and/or timezone preference.

Before you start

  • Verify the same intended caller and credential context before reading or updating preferences. No fixture credential or identity is usable live.
  • The user must authorize the intended preference mutation. Record prior stored values and verify the unchanged planned input before executing.

Discover the action

topolo whoami --json
topolo actions get app_topolo_auth.my_i18n_preferences.update --detail --json

Input fields

FieldRequiredMeaning
localeOptional; at least one preference requiredLocale query override on read; preferred persisted locale field on update. Region and language case are normalized.
languageOptional; at least one preference requiredUpdate alias for locale. A nonempty locale takes precedence when both are supplied.
timezoneOptional; at least one preference requiredStored user timezone recognized by Intl, for example Europe/Paris or UTC. Omission preserves the stored timezone.

Interpret the response

Supply at least one of locale, language or timezone. locale is the preferred language field; when both language fields are nonempty, locale wins. Locale normalization trims, converts underscores to hyphens and normalizes language/region case.

timezone is trimmed and accepted only when the runtime’s Intl formatter recognizes it. An invalid supplied locale or timezone is rejected before either repository write.

Only the supplied values appear in data: locale updates return locale and direction; timezone updates return timezone; combined updates return all three. Unrelated user metadata and omitted preferences are preserved.

The two database writes are not one transaction. A storage failure after the locale write can leave that value committed while timezone remains unchanged. Read the stored state, compare each intended value, and retry only the missing change; never treat a 500 as proof that nothing changed.

This mutation updates the current user’s preferences. It does not select another user, change organization membership, or update organization default language. AUTH_ERROR can also represent a credential-verification dependency failure and occurs before preference writes.

Worked requests and responses

Examples describe synthetic stored state. Headers shown for browser reads are part of that fixture; they are not action input fields. Resolve and use the current credential-scoped contract.

Locale-only update preserves timezone

Actual controller, normalization and repository SQL on minimal isolated SQLite; access-token verification and clock simulated.

Input

{
  "locale": "ar-ae"
}

CLI: save the input as payload.json, then validate and plan the unchanged request. Confirm only an authorized mutation.

topolo actions validate app_topolo_auth.my_i18n_preferences.update --data @payload.json --json
topolo actions plan app_topolo_auth.my_i18n_preferences.update --data @payload.json --confirm --json
topolo actions call app_topolo_auth.my_i18n_preferences.update --data @payload.json --confirm --detail --json

MCP

{
  "tool": "topolo_call_action",
  "arguments": {
    "actionId": "app_topolo_auth.my_i18n_preferences.update",
    "input": {
      "locale": "ar-ae"
    },
    "confirm": true
  }
}

HTTP 200 response

{
  "success": true,
  "message": "I18n preferences updated",
  "data": {
    "locale": "ar-AE",
    "direction": "rtl"
  },
  "timestamp": "2026-10-05T00:00:00.000Z"
}

Locale-only update preserves timezone. This is the disclosed synthetic fixture state, not a live user preference.

Stored fixture preferences after the write

{
  "locale": "ar-AE",
  "timezone": "Europe/Paris",
  "updatedAt": "2026-10-05T00:00:00.000Z"
}

Language alias normalizes to a stored locale

Actual controller, normalization and repository SQL on minimal isolated SQLite; access-token verification and clock simulated.

Input

{
  "language": "en_US"
}

CLI: save the input as payload.json, then validate and plan the unchanged request. Confirm only an authorized mutation.

topolo actions validate app_topolo_auth.my_i18n_preferences.update --data @payload.json --json
topolo actions plan app_topolo_auth.my_i18n_preferences.update --data @payload.json --confirm --json
topolo actions call app_topolo_auth.my_i18n_preferences.update --data @payload.json --confirm --detail --json

MCP

{
  "tool": "topolo_call_action",
  "arguments": {
    "actionId": "app_topolo_auth.my_i18n_preferences.update",
    "input": {
      "language": "en_US"
    },
    "confirm": true
  }
}

HTTP 200 response

{
  "success": true,
  "message": "I18n preferences updated",
  "data": {
    "locale": "en-US",
    "direction": "ltr"
  },
  "timestamp": "2026-10-05T00:00:00.000Z"
}

Language alias normalizes to a stored locale. This is the disclosed synthetic fixture state, not a live user preference.

Stored fixture preferences after the write

{
  "locale": "en-US",
  "timezone": "Europe/Paris",
  "updatedAt": "2026-10-05T00:00:00.000Z"
}

Timezone-only update preserves locale

Actual controller, normalization and repository SQL on minimal isolated SQLite; access-token verification and clock simulated.

Input

{
  "timezone": "  Asia/Makassar  "
}

CLI: save the input as payload.json, then validate and plan the unchanged request. Confirm only an authorized mutation.

topolo actions validate app_topolo_auth.my_i18n_preferences.update --data @payload.json --json
topolo actions plan app_topolo_auth.my_i18n_preferences.update --data @payload.json --confirm --json
topolo actions call app_topolo_auth.my_i18n_preferences.update --data @payload.json --confirm --detail --json

MCP

{
  "tool": "topolo_call_action",
  "arguments": {
    "actionId": "app_topolo_auth.my_i18n_preferences.update",
    "input": {
      "timezone": "  Asia/Makassar  "
    },
    "confirm": true
  }
}

HTTP 200 response

{
  "success": true,
  "message": "I18n preferences updated",
  "data": {
    "timezone": "Asia/Makassar"
  },
  "timestamp": "2026-10-05T00:00:00.000Z"
}

Timezone-only update preserves locale. This is the disclosed synthetic fixture state, not a live user preference.

Stored fixture preferences after the write

{
  "locale": "fr",
  "timezone": "Asia/Makassar",
  "updatedAt": "2026-10-05T00:00:00.000Z"
}

Both independently validated preferences are updated

Actual controller, normalization and repository SQL on minimal isolated SQLite; access-token verification and clock simulated.

Input

{
  "locale": "ar-ae",
  "timezone": "UTC"
}

CLI: save the input as payload.json, then validate and plan the unchanged request. Confirm only an authorized mutation.

topolo actions validate app_topolo_auth.my_i18n_preferences.update --data @payload.json --json
topolo actions plan app_topolo_auth.my_i18n_preferences.update --data @payload.json --confirm --json
topolo actions call app_topolo_auth.my_i18n_preferences.update --data @payload.json --confirm --detail --json

MCP

{
  "tool": "topolo_call_action",
  "arguments": {
    "actionId": "app_topolo_auth.my_i18n_preferences.update",
    "input": {
      "locale": "ar-ae",
      "timezone": "UTC"
    },
    "confirm": true
  }
}

HTTP 200 response

{
  "success": true,
  "message": "I18n preferences updated",
  "data": {
    "locale": "ar-AE",
    "direction": "rtl",
    "timezone": "UTC"
  },
  "timestamp": "2026-10-05T00:00:00.000Z"
}

Both independently validated preferences are updated. This is the disclosed synthetic fixture state, not a live user preference.

Stored fixture preferences after the write

{
  "locale": "ar-AE",
  "timezone": "UTC",
  "updatedAt": "2026-10-05T00:00:00.000Z"
}

Nonempty locale takes precedence over language alias

Actual controller, normalization and repository SQL on minimal isolated SQLite; access-token verification and clock simulated.

Input

{
  "locale": "fr",
  "language": "de"
}

CLI: save the input as payload.json, then validate and plan the unchanged request. Confirm only an authorized mutation.

topolo actions validate app_topolo_auth.my_i18n_preferences.update --data @payload.json --json
topolo actions plan app_topolo_auth.my_i18n_preferences.update --data @payload.json --confirm --json
topolo actions call app_topolo_auth.my_i18n_preferences.update --data @payload.json --confirm --detail --json

MCP

{
  "tool": "topolo_call_action",
  "arguments": {
    "actionId": "app_topolo_auth.my_i18n_preferences.update",
    "input": {
      "locale": "fr",
      "language": "de"
    },
    "confirm": true
  }
}

HTTP 200 response

{
  "success": true,
  "message": "I18n preferences updated",
  "data": {
    "locale": "fr",
    "direction": "ltr"
  },
  "timestamp": "2026-10-05T00:00:00.000Z"
}

Nonempty locale takes precedence over language alias. This is the disclosed synthetic fixture state, not a live user preference.

Stored fixture preferences after the write

{
  "locale": "fr",
  "timezone": "Europe/Paris",
  "updatedAt": "2026-10-05T00:00:00.000Z"
}

Verification

  • Read my_i18n_preferences.get with no locale/lang override and the same credential. Compare data.userLocale and data.timezone against the intended normalized stored values.

Recovery

Read and retain the prior userLocale/timezone before an intentional change. Restore only previously non-null values with a separately reviewed update. There is no preference-clear field; do not invent a null reset. After uncertain writes, read and reconcile before serial retry.

Refusal and failure responses

Missing access credential is refused

HTTP 401

{
  "timezone": "UTC"
}
{
  "success": false,
  "error": {
    "message": "Access token required",
    "code": "AUTH_ERROR",
    "details": null,
    "timestamp": "2026-10-05T00:00:00.000Z"
  }
}

Stored fixture preferences after this response

{
  "locale": "fr",
  "timezone": "Europe/Paris"
}

Verify the same intended identity/context and preserve the structured failure details. AUTH_ERROR alone does not prove expiry: this handler also maps credential-verification dependency failures to 401. If verification storage is unavailable, wait for recovery and repeat the unchanged read; use normal sign-in or credential refresh when credential expiry/refusal is established. Do not substitute another user’s credential.

Credential verification refusal is authoritative

HTTP 401

{
  "timezone": "UTC"
}
{
  "success": false,
  "error": {
    "message": "Synthetic expired credential",
    "code": "AUTH_ERROR",
    "details": null,
    "timestamp": "2026-10-05T00:00:00.000Z"
  }
}

Stored fixture preferences after this response

{
  "locale": "fr",
  "timezone": "Europe/Paris"
}

Verify the same intended identity/context and preserve the structured failure details. AUTH_ERROR alone does not prove expiry: this handler also maps credential-verification dependency failures to 401. If verification storage is unavailable, wait for recovery and repeat the unchanged read; use normal sign-in or credential refresh when credential expiry/refusal is established. Do not substitute another user’s credential.

Credential-verification dependency failure also returns AUTH_ERROR before preference writes

HTTP 401

{
  "timezone": "UTC"
}
{
  "success": false,
  "error": {
    "message": "Synthetic credential-verification storage unavailable",
    "code": "AUTH_ERROR",
    "details": null,
    "timestamp": "2026-10-05T00:00:00.000Z"
  }
}

Stored fixture preferences after this response

{
  "locale": "fr",
  "timezone": "Europe/Paris"
}

Verify the same intended identity/context and preserve the structured failure details. AUTH_ERROR alone does not prove expiry: this handler also maps credential-verification dependency failures to 401. If verification storage is unavailable, wait for recovery and repeat the unchanged read; use normal sign-in or credential refresh when credential expiry/refusal is established. Do not substitute another user’s credential.

Unavailable preference storage returns an error

HTTP 500

{
  "timezone": "UTC"
}
{
  "success": false,
  "error": {
    "message": "Synthetic preference read outage",
    "code": "SERVER_ERROR",
    "details": null,
    "timestamp": "2026-10-05T00:00:00.000Z"
  }
}

Stored fixture preferences after this response

{
  "locale": "fr",
  "timezone": "Europe/Paris"
}

Read preferences with the same credential after storage recovers. Compare stored values and retry only the missing intended change; a combined write can partially commit.

Empty update is refused

HTTP 400

{}
{
  "success": false,
  "error": {
    "message": "locale or timezone required",
    "code": "VALIDATION_ERROR",
    "details": {
      "locale": "locale or timezone required"
    },
    "timestamp": "2026-10-05T00:00:00.000Z"
  }
}

Stored fixture preferences after this response

{
  "locale": "fr",
  "timezone": "Europe/Paris"
}

Supply at least one declared preference field and correct the invalid locale/timezone. Validation refusal occurs before repository writes.

Malformed JSON is refused before writes

HTTP 400

{}

Raw fixture body: "{"

{
  "success": false,
  "error": {
    "message": "locale or timezone required",
    "code": "VALIDATION_ERROR",
    "details": {
      "locale": "locale or timezone required"
    },
    "timestamp": "2026-10-05T00:00:00.000Z"
  }
}

Stored fixture preferences after this response

{
  "locale": "fr",
  "timezone": "Europe/Paris"
}

Supply at least one declared preference field and correct the invalid locale/timezone. Validation refusal occurs before repository writes.

Null body is refused before writes

HTTP 400

null
{
  "success": false,
  "error": {
    "message": "locale or timezone required",
    "code": "VALIDATION_ERROR",
    "details": {
      "locale": "locale or timezone required"
    },
    "timestamp": "2026-10-05T00:00:00.000Z"
  }
}

Stored fixture preferences after this response

{
  "locale": "fr",
  "timezone": "Europe/Paris"
}

Supply at least one declared preference field and correct the invalid locale/timezone. Validation refusal occurs before repository writes.

Invalid locale is refused

HTTP 400

{
  "locale": "../invalid"
}
{
  "success": false,
  "error": {
    "message": "Invalid locale",
    "code": "VALIDATION_ERROR",
    "details": {
      "locale": "Invalid locale"
    },
    "timestamp": "2026-10-05T00:00:00.000Z"
  }
}

Stored fixture preferences after this response

{
  "locale": "fr",
  "timezone": "Europe/Paris"
}

Supply at least one declared preference field and correct the invalid locale/timezone. Validation refusal occurs before repository writes.

Valid locale plus invalid timezone commits neither field

HTTP 400

{
  "locale": "ar-ae",
  "timezone": "Mars/Olympus"
}
{
  "success": false,
  "error": {
    "message": "Invalid timezone",
    "code": "VALIDATION_ERROR",
    "details": {
      "timezone": "Invalid timezone"
    },
    "timestamp": "2026-10-05T00:00:00.000Z"
  }
}

Stored fixture preferences after this response

{
  "locale": "fr",
  "timezone": "Europe/Paris"
}

Supply at least one declared preference field and correct the invalid locale/timezone. Validation refusal occurs before repository writes.

First write failure leaves stored preferences unchanged

HTTP 500

{
  "timezone": "UTC"
}
{
  "success": false,
  "error": {
    "message": "Synthetic preference write outage",
    "code": "SERVER_ERROR",
    "details": null,
    "timestamp": "2026-10-05T00:00:00.000Z"
  }
}

Stored fixture preferences after this response

{
  "locale": "fr",
  "timezone": "Europe/Paris"
}

Read preferences with the same credential after storage recovers. Compare stored values and retry only the missing intended change; a combined write can partially commit.

Second write failure can leave locale committed; read and reconcile before retry

HTTP 500

{
  "locale": "ar-ae",
  "timezone": "UTC"
}
{
  "success": false,
  "error": {
    "message": "Synthetic preference write outage",
    "code": "SERVER_ERROR",
    "details": null,
    "timestamp": "2026-10-05T00:00:00.000Z"
  }
}

Stored fixture preferences after this response

{
  "locale": "ar-AE",
  "timezone": "Europe/Paris",
  "updatedAt": "2026-10-05T00:00:00.000Z"
}

Read preferences with the same credential after storage recovers. Compare stored values and retry only the missing intended change; a combined write can partially commit.

Evidence and limits

Actual isolated preference handlers; no live user preference or credential was changed.

Actual dependencies:

  • HTTP response serialization
  • Locale precedence and normalization
  • Timezone normalization through Intl
  • Existing preference repository SQL evaluated by SQLite

Simulated dependencies:

  • Access credential verification
  • Fixed clock and synthetic fixture records
  • Minimal users/organizations schema is not the complete migration database
  • Deliberate storage failures