|
| 1 | +--- |
| 2 | +applyTo: '**/*.vue' |
| 3 | +--- |
| 4 | + |
| 5 | +You are given a Nuxt/Vue single-file component (.vue). Your task is to convert every hard-coded natural-language string in the <template> into our localization system using @vintl/vintl-nuxt (which wraps FormatJS). |
| 6 | + |
| 7 | +Please follow these rules precisely: |
| 8 | + |
| 9 | +1. Identify translatable strings |
| 10 | + |
| 11 | +- Scan the <template> for all user-visible strings (inner text, alt attributes, placeholders, button labels, etc.). Do not extract dynamic expressions (like {{ user.name }}) or HTML tags. Only extract static human-readable text. |
| 12 | +- There may be strings within the <script> block, e.g dropdown option labels, notifications etc. |
| 13 | + |
| 14 | +2. Create message definitions |
| 15 | + |
| 16 | +- In the <script setup> block, import `defineMessage` or `defineMessages` from `@vintl/vintl`. |
| 17 | +- For each extracted string, define a message with a unique `id` (use a descriptive prefix based on the component path, e.g. `auth.welcome.long-title`) and a `defaultMessage` equal to the original English string. |
| 18 | + Example: |
| 19 | + const messages = defineMessages({ |
| 20 | + welcomeTitle: { id: 'auth.welcome.title', defaultMessage: 'Welcome' }, |
| 21 | + welcomeDescription: { id: 'auth.welcome.description', defaultMessage: 'You’re now part of the community…' }, |
| 22 | + }) |
| 23 | + |
| 24 | +3. Handle variables and ICU formats |
| 25 | + |
| 26 | +- Replace dynamic parts with ICU placeholders: "Hello, ${user.name}!" → `{name}` and defaultMessage: 'Hello, {name}!' |
| 27 | +- For numbers/dates/times, use ICU/FormatJS options (e.g., currency): `{price, number, ::currency/USD}` |
| 28 | +- For plurals/selects, use ICU: `'{count, plural, one {# message} other {# messages}}'` |
| 29 | + |
| 30 | +4. Rich-text messages (links/markup) |
| 31 | + |
| 32 | +- In `defaultMessage`, wrap link/markup ranges with tags, e.g.: |
| 33 | + "By creating an account, you agree to our <terms-link>Terms</terms-link> and <privacy-link>Privacy Policy</privacy-link>." |
| 34 | +- Render rich-text messages with `<IntlFormatted>` from `@vintl/vintl/components` and map tags via `values`: |
| 35 | + <IntlFormatted |
| 36 | + :message="messages.tosLabel" |
| 37 | + :values="{ |
| 38 | + 'terms-link': (chunks) => <NuxtLink to='/terms'>{chunks}</NuxtLink>, |
| 39 | + 'privacy-link': (chunks) => <NuxtLink to='/privacy'>{chunks}</NuxtLink>, |
| 40 | + }" |
| 41 | + /> |
| 42 | +- For simple emphasis: `'Welcome to <strong>Modrinth</strong>!'` and map `'strong': (c) => <strong>{c}</strong>` |
| 43 | + |
| 44 | +5. Formatting in templates |
| 45 | + |
| 46 | +- Import and use `useVIntl()`; prefer `formatMessage` for simple strings: |
| 47 | + `const { formatMessage } = useVIntl()` |
| 48 | + `<button>{{ formatMessage(messages.welcomeTitle) }}</button>` |
| 49 | +- Vue methods like `$formatMessage`, `$formatNumber`, `$formatDate` are also available if needed. |
| 50 | + |
| 51 | +6. Naming conventions and id stability |
| 52 | + |
| 53 | +- Make `id`s descriptive and stable (e.g., `error.generic.default.title`). Group related messages with `defineMessages`. |
| 54 | + |
| 55 | +7. Avoid Vue/ICU delimiter collisions |
| 56 | + |
| 57 | +- If an ICU placeholder would end right before `}}` in a Vue template, insert a space so it becomes `} }` to avoid parsing issues. |
| 58 | + |
| 59 | +8. Update imports and remove literals |
| 60 | + |
| 61 | +- Ensure imports for `defineMessage`/`defineMessages`, `useVIntl`, and `<IntlFormatted>` are present. Replace all hard-coded strings with `formatMessage(...)` or `<IntlFormatted>` and remove the literals. |
| 62 | + |
| 63 | +9. Preserve functionality |
| 64 | + |
| 65 | +- Do not change logic, layout, reactivity, or bindings—only refactor strings into i18n. |
| 66 | + |
| 67 | +Use existing patterns from our codebase: |
| 68 | + |
| 69 | +- Variables/plurals: see `apps/frontend/src/pages/frog.vue` |
| 70 | +- Rich-text link tags: see `apps/frontend/src/pages/auth/welcome.vue` and `apps/frontend/src/error.vue` |
| 71 | + |
| 72 | +When you finish, there should be no hard-coded English strings left in the template—everything comes from `formatMessage` or `<IntlFormatted>`. |
0 commit comments