Next.jsnext-intli18n

Why We Use getI18n with Object Structures Instead of JSON Files in next-intl

While next-intl encourages using JSON files for translation, we found object-based structures loaded via getI18n to be more flexible and maintainable—especially for dynamic content like FAQs and service lists.

RaytonX
2 min read

When working with next-intl for internationalization in a Next.js project, the common approach is to store translations in flat JSON files like this:

// messages/en.json
{
  "faq.q1": "What is your service?",
  "faq.a1": "We provide..."
}

However, in our production projects, we’ve shifted to using structured TypeScript objects, loaded dynamically via getI18n(locale):

// i18n/en.ts
export const en = {
  faq: {
    items: [
      { question: "What is your service?", answer: "We provide..." },
      ...
    ]
  }
}

Why We Prefer Object-Based Translations Over JSON

1. Better for Structured Content (FAQs, Lists, Services)

When dealing with a list of items—such as FAQs—JSON requires naming keys like q1, a1, q2, a2, etc. Adding a new entry means:

  • Updating multiple JSON files (e.g., en.json, zh.json)
  • Updating the React component logic to handle new keys

With object-based arrays, you simply add a new item to the list. No component changes needed.

2. Improved Developer Experience

With TypeScript, object-based translations offer:

  • Autocompletion and type safety
  • Early error detection for missing or incorrect keys
  • Clear structure when working with nested or grouped content

3. Easier to Maintain and Scale

Large JSON files can become hard to navigate and manage. Object-based files allow:

  • Modular organization by page or feature (faq.ts, home.ts, etc.)
  • Better version control and collaboration across teams

4. Cleaner Component Logic

With structured content, components don’t need to map or manually resolve keys:

{t.faq.items.map((item, index) => (
  <FaqItem key={index} question={item.question} answer={item.answer} />
))}

This is simpler and more maintainable than hardcoding t('faq.q1'), t('faq.a1'), etc.

Conclusion

While JSON-based translation files are standard, we’ve found that using structured objects with getI18n(locale) provides better flexibility, especially for dynamic, list-based content.

For complex websites and multilingual SaaS platforms, this approach dramatically improves maintainability, scalability, and developer experience.