# Internationalization (i18n)

Monetarie NPC Backoffice supports multiple languages through vue-i18n. This document covers the i18n setup, available languages, and how to add translations.

## Overview

The application supports three languages:

| Code | Language | Region |
|------|----------|--------|
| `pt-BR` | Portuguese | Brazil (Default) |
| `en` | English | United States |
| `zh-CN` | Chinese | Simplified |

## Configuration

### Main Setup

```typescript
// src/i18n/index.ts
import { createI18n } from 'vue-i18n'
import ptBR from './locales/pt-BR'
import en from './locales/en'
import zhCN from './locales/zh-CN'

const savedLocale = localStorage.getItem('locale') || 'pt-BR'

const i18n = createI18n({
  legacy: false,           // Use Composition API mode
  locale: savedLocale,     // Current locale
  fallbackLocale: 'pt-BR', // Fallback when translation missing
  messages: {
    'pt-BR': ptBR,
    'en': en,
    'zh-CN': zhCN
  }
})

export default i18n
```

### Available Locales

```typescript
export const availableLocales = [
  { code: 'pt-BR', name: 'Portugues', flag: '' },
  { code: 'en', name: 'English', flag: '' },
  { code: 'zh-CN', name: '', flag: '' }
]
```

### Locale Switching

```typescript
export function setLocale(locale: string) {
  i18n.global.locale.value = locale
  localStorage.setItem('locale', locale)
  document.documentElement.setAttribute('lang', locale)
}
```

## Translation Files

### Portuguese (pt-BR)

```typescript
// src/i18n/locales/pt-BR.ts
export default {
  common: {
    search: 'Buscar',
    notifications: 'Notificacoes',
    logout: 'Sair',
    changeAvatar: 'Alterar avatar',
    language: 'Idioma',
    save: 'Salvar',
    cancel: 'Cancelar',
    confirm: 'Confirmar',
    delete: 'Excluir',
    edit: 'Editar',
    create: 'Criar',
    close: 'Fechar',
    back: 'Voltar',
    loading: 'Carregando...',
    noData: 'Nenhum dado encontrado',
    actions: 'Acoes'
  },
  auth: {
    title: 'Entrar',
    email: 'E-mail',
    password: 'Senha',
    submit: 'Entrar',
    invalidCredentials: 'Credenciais invalidas',
    welcomeBack: 'Bem-vindo de volta!'
  },
  dashboard: {
    title: 'Painel',
    health: 'Saude do Sistema',
    online: 'Online',
    offline: 'Offline',
    lastCheck: 'Ultima verificacao',
    sisbajudOrders: 'Ordens SISBAJUD',
    orderId: 'ID da Ordem',
    orderType: 'Tipo',
    orderAccount: 'Conta',
    orderValue: 'Valor',
    orderStatus: 'Status',
    orderDate: 'Data',
    pending: 'Pendente',
    executed: 'Executada',
    rejected: 'Rejeitada'
  },
  sidebar: {
    accounts: 'Contas',
    accountsCreate: 'Criar Conta',
    accountsEdit: 'Editar Conta',
    accountsClose: 'Encerrar Conta',
    settings: 'Configuracoes',
    users: 'Usuarios',
    collapse: 'Recolher',
    expand: 'Expandir'
  },
  rightPanel: {
    rssFeed: 'Feed RSS',
    pendingNotifications: 'Notificacoes Pendentes',
    viewMore: 'Ver mais',
    markAsRead: 'Marcar como lida',
    highPriority: 'Alta prioridade',
    mediumPriority: 'Media prioridade',
    lowPriority: 'Baixa prioridade'
  },
  serena: {
    title: 'Serena IA',
    placeholder: 'Digite sua mensagem...',
    greeting: 'Ola! Sou a Serena, sua assistente virtual. Como posso ajudar?',
    fallback: 'Desculpe, nao entendi. Pode reformular a pergunta?',
    tooltip: 'Assistente Virtual Serena'
  },
  accounts: {
    title: 'Contas',
    create: {
      title: 'Criar Nova Conta',
      accountHolder: 'Titular da Conta',
      accountType: 'Tipo de Conta',
      branch: 'Agencia',
      accountNumber: 'Numero da Conta',
      initialBalance: 'Saldo Inicial',
      success: 'Conta criada com sucesso!'
    },
    edit: {
      title: 'Editar Conta',
      success: 'Conta atualizada com sucesso!'
    },
    close: {
      title: 'Encerrar Conta',
      warning: 'Atencao: Esta acao nao pode ser desfeita.',
      reason: 'Motivo do encerramento',
      success: 'Conta encerrada com sucesso!'
    }
  },
  settings: {
    title: 'Configuracoes',
    spb: {
      title: 'SPB - Sistema de Pagamentos Brasileiro',
      endpoint: 'Endpoint',
      timeout: 'Timeout (ms)',
      retries: 'Tentativas'
    },
    spi: {
      title: 'SPI - Sistema de Pagamentos Instantaneos',
      endpoint: 'Endpoint',
      pixKey: 'Chave PIX'
    },
    sta: {
      title: 'STA - Sistema de Transferencia de Arquivos',
      endpoint: 'Endpoint',
      schedule: 'Agendamento'
    },
    nuclea: {
      title: 'Nuclea',
      endpoint: 'Endpoint',
      certificate: 'Certificado'
    },
    sisbajud: {
      title: 'SISBAJUD',
      endpoint: 'Endpoint',
      courtId: 'ID do Tribunal'
    },
    users: {
      title: 'Usuarios',
      name: 'Nome',
      email: 'E-mail',
      role: 'Funcao',
      status: 'Status',
      active: 'Ativo',
      inactive: 'Inativo',
      admin: 'Administrador',
      user: 'Usuario'
    }
  }
}
```

## Usage in Components

### Composition API

```vue
<script setup lang="ts">
import { useI18n } from 'vue-i18n'

const { t, locale } = useI18n()

// Access translations
const title = t('dashboard.title')

// Change locale
function changeLanguage(newLocale: string) {
  locale.value = newLocale
}
</script>

<template>
  <h1>{{ t('dashboard.title') }}</h1>
  <p>{{ t('common.loading') }}</p>
</template>
```

### Template Syntax

```vue
<template>
  <!-- Simple translation -->
  <span>{{ $t('common.save') }}</span>

  <!-- With interpolation -->
  <span>{{ $t('greeting', { name: user.name }) }}</span>

  <!-- Pluralization -->
  <span>{{ $tc('items', count) }}</span>
</template>
```

### Interpolation

Define translations with placeholders:

```typescript
// locale file
{
  greeting: 'Ola, {name}!',
  items: 'Voce tem {count} item | Voce tem {count} itens'
}
```

Use in components:

```vue
<template>
  <p>{{ t('greeting', { name: 'Maria' }) }}</p>
  <!-- Output: "Ola, Maria!" -->

  <p>{{ t('items', { count: itemCount }, itemCount) }}</p>
  <!-- Output: "Voce tem 5 itens" -->
</template>
```

## Switching Languages

### Language Selector Component

```vue
<script setup lang="ts">
import { useI18n } from 'vue-i18n'
import { availableLocales, setLocale } from '@/i18n'

const { locale } = useI18n()
</script>

<template>
  <v-select
    v-model="locale"
    :items="availableLocales"
    item-title="name"
    item-value="code"
    @update:model-value="setLocale"
  >
    <template #selection="{ item }">
      {{ item.raw.flag }} {{ item.raw.name }}
    </template>
    <template #item="{ item, props }">
      <v-list-item v-bind="props">
        <template #prepend>
          {{ item.raw.flag }}
        </template>
      </v-list-item>
    </template>
  </v-select>
</template>
```

### Button Toggle

```vue
<template>
  <v-btn-toggle v-model="selectedLocale" mandatory>
    <v-btn
      v-for="loc in availableLocales"
      :key="loc.code"
      :value="loc.code"
      @click="setLocale(loc.code)"
    >
      {{ loc.flag }} {{ loc.code.split('-')[0].toUpperCase() }}
    </v-btn>
  </v-btn-toggle>
</template>
```

## Adding a New Language

### 1. Create Locale File

```typescript
// src/i18n/locales/es.ts
export default {
  common: {
    search: 'Buscar',
    notifications: 'Notificaciones',
    logout: 'Salir',
    // ... complete all translations
  },
  auth: {
    title: 'Iniciar sesion',
    email: 'Correo electronico',
    // ...
  },
  // ... all other sections
}
```

### 2. Register in i18n Config

```typescript
// src/i18n/index.ts
import es from './locales/es'

const i18n = createI18n({
  // ...
  messages: {
    'pt-BR': ptBR,
    'en': en,
    'zh-CN': zhCN,
    'es': es  // Add new locale
  }
})
```

### 3. Add to Available Locales

```typescript
export const availableLocales = [
  { code: 'pt-BR', name: 'Portugues', flag: '' },
  { code: 'en', name: 'English', flag: '' },
  { code: 'zh-CN', name: '', flag: '' },
  { code: 'es', name: 'Espanol', flag: '' }  // Add new locale
]
```

## Date and Number Formatting

### Date Formatting

```typescript
// i18n config
const i18n = createI18n({
  datetimeFormats: {
    'pt-BR': {
      short: {
        year: 'numeric',
        month: '2-digit',
        day: '2-digit'
      },
      long: {
        year: 'numeric',
        month: 'long',
        day: 'numeric',
        weekday: 'long'
      }
    },
    'en': {
      short: {
        year: 'numeric',
        month: 'short',
        day: 'numeric'
      }
    }
  }
})
```

Usage:

```vue
<template>
  <span>{{ d(new Date(), 'short') }}</span>
  <!-- pt-BR: "03/02/2024" -->
  <!-- en: "Feb 3, 2024" -->
</template>

<script setup>
import { useI18n } from 'vue-i18n'
const { d } = useI18n()
</script>
```

### Number Formatting

```typescript
// i18n config
const i18n = createI18n({
  numberFormats: {
    'pt-BR': {
      currency: {
        style: 'currency',
        currency: 'BRL'
      },
      decimal: {
        style: 'decimal',
        minimumFractionDigits: 2
      }
    },
    'en': {
      currency: {
        style: 'currency',
        currency: 'USD'
      }
    }
  }
})
```

Usage:

```vue
<template>
  <span>{{ n(1234.56, 'currency') }}</span>
  <!-- pt-BR: "R$ 1.234,56" -->
  <!-- en: "$1,234.56" -->
</template>

<script setup>
import { useI18n } from 'vue-i18n'
const { n } = useI18n()
</script>
```

## Best Practices

### 1. Consistent Key Naming

Use dot notation for nested keys:

```typescript
{
  'feature.section.element': 'Translation'
}
// Better:
{
  feature: {
    section: {
      element: 'Translation'
    }
  }
}
```

### 2. Avoid HTML in Translations

Instead of:

```typescript
{ message: '<strong>Important</strong> message' }
```

Use:

```typescript
{ message: '{important} message' }
```

```vue
<i18n-t keypath="message">
  <template #important>
    <strong>Important</strong>
  </template>
</i18n-t>
```

### 3. Use Named Interpolation

Instead of:

```typescript
{ message: 'Hello {0}!' }
```

Use:

```typescript
{ message: 'Hello {name}!' }
```

### 4. Keep Translations Complete

Ensure all locales have the same keys to avoid fallback issues.

## Testing Translations

```typescript
import { createI18n } from 'vue-i18n'
import { mount } from '@vue/test-utils'

const i18n = createI18n({
  locale: 'en',
  messages: {
    en: { greeting: 'Hello' },
    'pt-BR': { greeting: 'Ola' }
  }
})

describe('Component', () => {
  it('renders in English', () => {
    const wrapper = mount(Component, {
      global: { plugins: [i18n] }
    })
    expect(wrapper.text()).toContain('Hello')
  })

  it('renders in Portuguese', () => {
    i18n.global.locale.value = 'pt-BR'
    const wrapper = mount(Component, {
      global: { plugins: [i18n] }
    })
    expect(wrapper.text()).toContain('Ola')
  })
})
```

## Related Documentation

- [Authentication](/guide/authentication) - Login form localization
- [Dashboard](/guide/dashboard) - Dashboard translations
- [Pinia Stores](/api/stores) - State management
