# How to Set Up Nuxt 4 with Pinia, UnoCSS, and i18n for TypeWords

> Learn to set up Nuxt 4 with Pinia, UnoCSS, and i18n following the TypeWords repository structure. Install packages, configure stores, and streamline your internationalized app development.

- Repository: [Zyronon/TypeWords](https://github.com/zyronon/TypeWords)
- Tags: how-to-guide
- Published: 2026-09-03

---

**You can set up Nuxt 4 with Pinia, UnoCSS, and i18n by installing `@pinia/nuxt`, `@unocss/nuxt`, and `@nuxtjs/i18n`, then registering them in [`nuxt.config.ts`](https://github.com/zyronon/TypeWords/blob/main/nuxt.config.ts) and configuring stores, CSS shortcuts, and locale files according to the TypeWords repository structure.**

The **TypeWords** project by zyronon demonstrates a production-ready Nuxt 4 architecture that combines type-safe state management, utility-first styling, and multilingual routing. This guide walks you through the exact implementation used in the source code to configure these three core modules, referencing specific file paths and methods from `zyronon/TypeWords`.

## Install the Required Dependencies

First, add the three Nuxt modules to your project. The TypeWords repository uses `pnpm` as its package manager.

```bash
pnpm i @pinia/nuxt @unocss/nuxt @nuxtjs/i18n

```

- `@pinia/nuxt` integrates Pinia with Nuxt’s auto-import system, replacing the legacy Vuex store.
- `@unocss/nuxt` brings the UnoCSS engine, preset icons, and directive transformers.
- `@nuxtjs/i18n` adds locale-aware routing and translation loading capabilities.

## Configure the Nuxt 4 Modules

### Register Modules in nuxt.config.ts

In the TypeWords project, [`nuxt.config.ts`](https://github.com/zyronon/TypeWords/blob/main/nuxt.config.ts) registers all three modules in the `modules` array. This enables auto-importing for Pinia stores, UnoCSS utilities, and i18n composables across your application.

```typescript
// nuxt.config.ts
export default defineNuxtConfig({
  modules: [
    '@pinia/nuxt',      // State management
    '@unocss/nuxt',     // Utility-first CSS
    '@nuxtjs/i18n',     // Internationalization
    // ...other modules
  ],
})

```

### Configure i18n Settings

The i18n configuration in [`nuxt.config.ts`](https://github.com/zyronon/TypeWords/blob/main/nuxt.config.ts) defines available locales, default language, and routing strategy. TypeWords uses a `no_prefix` strategy to serve different languages without changing the URL structure.

```typescript
// nuxt.config.ts
export default defineNuxtConfig({
  i18n: {
    locales: [
      { code: 'en', file: 'en.json', name: 'English' },
      { code: 'zh', file: 'zh.json', name: '中文' },
    ],
    defaultLocale: 'zh',
    strategy: 'no_prefix',
  },
})

```

Translation files are stored in the `i18n/locales/` directory (e.g., [`en.json`](https://github.com/zyronon/TypeWords/blob/main/en.json), [`zh.json`](https://github.com/zyronon/TypeWords/blob/main/zh.json)) and automatically loaded by the module.

## Set Up Pinia Stores

Pinia stores in TypeWords live under `app/core/stores/` and use the `defineStore` function from `pinia`. The [`setting.ts`](https://github.com/zyronon/TypeWords/blob/main/setting.ts) store demonstrates reactive state management with persistence capabilities.

```typescript
// app/core/stores/setting.ts
import { defineStore } from 'pinia'

export const useSettingStore = defineStore('setting', {
  state: () => ({
    soundType: 'us',
    theme: 'auto',
    // additional state properties
  }),
  actions: {
    setState(obj) {
      this.$patch(obj)
    },
    async init() {
      // Loads persisted settings from IndexedDB
    },
  },
})

```

The `$patch` method efficiently updates multiple state properties, while the `init` action handles client-side hydration of stored user preferences.

## Configure UnoCSS with Custom Shortcuts

UnoCSS configuration resides in [`uno.config.ts`](https://github.com/zyronon/TypeWords/blob/main/uno.config.ts) at the project root. The TypeWords setup defines **shortcuts**—custom utility classes that expand to multiple CSS rules—and configures presets for icons and attributify mode.

```typescript
// uno.config.ts
import { defineConfig } from 'unocss'

export default defineConfig({
  shortcuts: {
    'bg-primary': 'bg-[var(--color-primary)]',
    'card': 'rounded-xl p-4 mb-8 shadow-lg box-border relative bg-second',
  },
  // presets, theme, and transformers follow
})

```

These shortcuts allow you to write `<div class="card">` in templates, which UnoCSS expands to the full set of utility classes at build time.

## Use the Stack in Vue Components

With all three modules configured, you can access Pinia state, i18n translations, and UnoCSS utilities simultaneously in your Vue Single File Components.

```vue
<script setup lang="ts">
import { useSettingStore } from '~/app/core/stores/setting'
import { useI18n } from 'vue-i18n'

const setting = useSettingStore()
const { locale, t } = useI18n()

function changeLang(lang: string) {
  locale.value = lang
}
</script>

<template>
  <div class="card bg-primary">
    <h1 class="text-2xl font-bold">{{ $t('welcome') }}</h1>
    <p>Current theme: {{ setting.theme }}</p>
    <button @click="changeLang('en')">{{ t('button.en') }}</button>
    <button @click="changeLang('zh')">{{ t('button.zh') }}</button>
  </div>
</template>

```

The `$t` function provides global access to translations, while `useSettingStore()` delivers reactive, type-safe state. UnoCSS processes the `card` and `bg-primary` classes using the shortcuts defined in [`uno.config.ts`](https://github.com/zyronon/TypeWords/blob/main/uno.config.ts).

## Summary

- **Install** `@pinia/nuxt`, `@unocss/nuxt`, and `@nuxtjs/i18n` via your package manager to enable the three core features.
- **Register** all three modules in [`nuxt.config.ts`](https://github.com/zyronon/TypeWords/blob/main/nuxt.config.ts) modules array to activate auto-imports and plugin injection.
- **Define** Pinia stores in `app/core/stores/` using `defineStore` for centralized, type-safe state management.
- **Configure** UnoCSS shortcuts in [`uno.config.ts`](https://github.com/zyronon/TypeWords/blob/main/uno.config.ts) to create reusable utility classes like `card` and `bg-primary`.
- **Store** translation JSON files in `i18n/locales/` and reference them in the [`nuxt.config.ts`](https://github.com/zyronon/TypeWords/blob/main/nuxt.config.ts) i18n configuration.
- **Access** global utilities like `$t` through the client-side plugin at [`app/plugins/02.init.client.ts`](https://github.com/zyronon/TypeWords/blob/main/app/plugins/02.init.client.ts) or via `useI18n()` composable.

## Frequently Asked Questions

### What is the difference between Pinia and Vuex in the TypeWords setup?

Pinia replaces Vuex as the official state management solution for Vue 3 and Nuxt 4, offering better TypeScript inference and a simpler API with `defineStore`. In [`app/core/stores/setting.ts`](https://github.com/zyronon/TypeWords/blob/main/app/core/stores/setting.ts), Pinia's `$patch` method allows partial state updates that Vuex mutations handled more verbosely.

### How does UnoCSS differ from Tailwind CSS in this configuration?

While Tailwind requires a full CSS purge and JIT compiler, UnoCSS generates utilities on-demand based on detected class names, resulting in zero-config builds and smaller bundles. The [`uno.config.ts`](https://github.com/zyronon/TypeWords/blob/main/uno.config.ts) file in TypeWords uses `shortcuts` to create semantic tokens like `card`, combining multiple utilities into single, maintainable classes without writing custom CSS.

### Why does TypeWords use the `no_prefix` i18n strategy?

The `no_prefix` strategy serves different languages from the same URL path (e.g., `/dashboard` remains `/dashboard` for both English and Chinese users), relying on cookies or browser detection instead of URL segments. This preserves SEO value for single-language deployments while still allowing runtime language switching via the `locale` reactive property from `useI18n()`.

### How do I access Pinia stores inside Nuxt plugins?

You can access Pinia stores in client-side plugins like [`app/plugins/02.init.client.ts`](https://github.com/zyronon/TypeWords/blob/main/app/plugins/02.init.client.ts) by importing the store composable after the Pinia instance initializes. Since `@pinia/nuxt` auto-registers the Pinia plugin, calling `useSettingStore()` inside a plugin that runs after application initialization provides full access to state and actions for setting up global utilities or hydration logic.