IntlPull
Technical
11 min read

Handling Gender & Grammatical Agreements in i18n: Developer Guide

Master grammatical gender in internationalization: ICU select format, gender-neutral strategies, and handling Romance, Slavic, and Arabic language gender systems in modern applications.

IntlPull Team
IntlPull Team
Feb 12, 2026
On this page
Summary

Master grammatical gender in internationalization: ICU select format, gender-neutral strategies, and handling Romance, Slavic, and Arabic language gender systems in modern applications.

Grammatical gender is one of the most complex challenges in internationalization. Unlike English, which uses gender primarily for pronouns, many languages assign grammatical gender to all nouns and require agreement across adjectives, articles, and verb forms. This guide covers everything developers need to know about handling gender in i18n, from Romance and Slavic systems to gender-neutral strategies.

Understanding Grammatical Gender Systems

Grammatical gender is a linguistic feature where nouns are classified into categories (masculine, feminine, neuter, or others) that affect surrounding words. This classification is often arbitrary and unrelated to biological gender.

Two-Gender Systems (Romance Languages)

Languages like Spanish, French, Italian, and Portuguese use masculine and feminine genders:

Spanish Example:

  • "El usuario está conectado" (The user [masc] is connected [masc])
  • "La usuaria está conectada" (The user [fem] is connected [fem])

French Example:

  • "Le développeur est expérimenté" (The developer [masc] is experienced [masc])
  • "La développeuse est expérimentée" (The developer [fem] is experienced [fem])

Three-Gender Systems (Slavic Languages)

Russian, Polish, Czech, and other Slavic languages add neuter gender:

Russian Example:

  • "Пользователь (masc) подключён (masc)" (User is connected)
  • "Пользовательница (fem) подключена (fem)" (User is connected)
  • "Подключение (neut) завершено (neut)" (Connection is completed)

Complex Gender Systems (Arabic)

Arabic has masculine and feminine, but with additional complexity:

  • Dual forms for exactly two items
  • Broken plurals with unpredictable gender
  • Different agreement rules for human vs. non-human plurals

Arabic Example:

  • "المستخدم متصل" (The user [masc] connected [masc])
  • "المستخدمة متصلة" (The user [fem] connected [fem])
  • "المستخدمون متصلون" (The users [masc pl] connected [masc pl])
  • "المستخدمات متصلات" (The users [fem pl] connected [fem pl])

The ICU MessageFormat Select Solution

The Industry's standard solution for grammatical gender is the ICU MessageFormat select format, which allows conditional text based on a variable value.

Basic Select Syntax

JavaScript
1const message = "{gender, select, " +
2  "male {He is connected} " +
3  "female {She is connected} " +
4  "other {They are connected}" +
5"}";
6
7// Usage
8formatMessage(message, { gender: 'female' });
9// Output: "She is connected"

Multi-Level Agreement

Real-world applications often require multiple agreements in a single sentence:

JavaScript
1// Spanish: Agreement on article, noun, adjective, and participle
2const welcomeMessage = "{gender, select, " +
3  "male {Bienvenido al sistema. Tu cuenta ha sido activada.} " +
4  "female {Bienvenida al sistema. Tu cuenta ha sido activada.} " +
5  "other {Bienvenido/a al sistema. Tu cuenta ha sido activada.}" +
6"}";

Nested Select for Complex Scenarios

JavaScript
1// French: Different agreement for singular vs plural
2const statusMessage = "{count, plural, " +
3  "one {{gender, select, " +
4    "male {L'utilisateur est connecté} " +
5    "female {L'utilisatrice est connectée} " +
6    "other {L'utilisateur·rice est connecté·e}" +
7  "}} " +
8  "other {{gender, select, " +
9    "male {Les utilisateurs sont connectés} " +
10    "female {Les utilisatrices sont connectées} " +
11    "other {Les utilisateur·rice·s sont connecté·e·s}" +
12  "}}" +
13"}";

Implementation Patterns

Storing User Gender Preference

TypeScript
1interface UserProfile {
2  id: string;
3  displayName: string;
4  preferredLanguage: string;
5  // Gender for grammatical agreement only
6  grammaticalGender?: 'male' | 'female' | 'neutral' | 'unspecified';
7}
8
9// Database schema
10CREATE TABLE user_profiles (
11  id UUID PRIMARY KEY,
12  display_name TEXT NOT NULL,
13  preferred_language TEXT NOT NULL,
14  grammatical_gender TEXT CHECK (
15    grammatical_gender IN ('male', 'female', 'neutral', 'unspecified')
16  ),
17  created_at TIMESTAMP DEFAULT NOW()
18);

React Implementation

TypeScript
1import { useIntl } from 'react-intl';
2
3interface WelcomeProps {
4  user: UserProfile;
5}
6
7function WelcomeMessage({ user }: WelcomeProps) {
8  const intl = useIntl();
9
10  const message = intl.formatMessage(
11    { id: 'welcome.greeting' },
12    {
13      gender: user.grammaticalGender || 'other',
14      name: user.displayName
15    }
16  );
17
18  return <h1>{message}</h1>;
19}
20
21// Translation file (en.json)
22{
23  "welcome.greeting": "{name}, you are connected"
24}
25
26// Translation file (es.json)
27{
28  "welcome.greeting": "{gender, select, male {{name}, estás conectado} female {{name}, estás conectada} other {{name}, estás conectado/a}}"
29}

Backend API Design

GO
1// Go backend example
2type UserPreferences struct {
3    LanguageCode      string  `json:"language_code"`
4    GrammaticalGender *string `json:"grammatical_gender,omitempty"`
5}
6
7func (h *Handler) GetLocalizedMessage(w http.ResponseWriter, r *http.Request) {
8    user := getUserFromContext(r.Context())
9
10    params := map[string]interface{}{
11        "gender": getGenderOrDefault(user.Preferences.GrammaticalGender),
12        "name":   user.DisplayName,
13    }
14
15    message := h.i18n.Localize(user.Preferences.LanguageCode, "welcome.greeting", params)
16
17    json.NewEncoder(w).Write(map[string]string{
18        "message": message,
19    })
20}
21
22func getGenderOrDefault(gender *string) string {
23    if gender == nil {
24        return "other"
25    }
26    return *gender
27}

Gender-Neutral Strategies

Many applications are moving toward gender-neutral language to be more inclusive and to simplify localization.

English Gender-Neutral Patterns

JavaScript
1// Instead of: "He/She is connected"
2// Use: "You are connected" (second person)
3// Use: "Connected" (status without subject)
4// Use: "This user is connected" (demonstrative + noun)
5// Use: "They are connected" (singular they)

Romance Language Strategies

1. Inclusive Morphemes (Spanish/French):

Spanish: "Bienvenido/a" or "Bienvenid@" or "Bienvenidx"
French: "Bienvenu·e" or "Bienvenu.e"

2. Collective Nouns:

Instead of: "Los usuarios" (the users [masc])
Use: "Las personas usuarias" (the user persons [fem collective])

3. Passive Voice:

Instead of: "El usuario ha sido conectado" (requires gender)
Use: "La conexión ha sido establecida" (connection established, no gender)

German Gender-Neutral Solutions

Traditional: "Benutzer" (masc) / "Benutzerin" (fem)
Gender-neutral: "Benutzende" (using participle form)
Inclusive: "Benutzer*in" or "Benutzer:in" or "Benutzer_in"

Slavic Language Challenges

Slavic languages have fewer gender-neutral options due to extensive agreement:

JavaScript
1// Russian: Limited options, often requires explicit selection
2const russianMessage = "{gender, select, " +
3  "male {Вы подключены} " +     // You [masc] are connected
4  "female {Вы подключены} " +   // You [fem] are connected
5  "other {Вы подключены}" +     // Plural form (neutral)
6"}";

Avoiding Gender Assumptions in UI

Profile Setup Best Practices

TypeScript
1// Good: Optional gender field with clear purpose
2interface ProfileForm {
3  displayName: string;
4  email: string;
5  // Optional: Only for grammatical purposes
6  grammaticalGender?: {
7    value: 'male' | 'female' | 'neutral' | 'unspecified';
8    label: string; // Explain why you're asking
9  };
10}
11
12// UI Component
13function GenderField() {
14  return (
15    <fieldset>
16      <legend>
17        Grammatical Gender (Optional)
18        <Tooltip>
19          Used only to display messages correctly in your language.
20          This does not affect your identity or profile visibility.
21        </Tooltip>
22      </legend>
23
24      <label>
25        <input type="radio" name="gender" value="male" />
26        Masculine forms
27      </label>
28
29      <label>
30        <input type="radio" name="gender" value="female" />
31        Feminine forms
32      </label>
33
34      <label>
35        <input type="radio" name="gender" value="neutral" />
36        Neutral/inclusive forms
37      </label>
38
39      <label>
40        <input type="radio" name="gender" value="unspecified" checked />
41        No preference
42      </label>
43    </fieldset>
44  );
45}

Default to Neutral Language

JavaScript
1// Translation keys should default to neutral forms
2{
3  // Bad: Assumes gender
4  "profile.greeting": "Welcome back, {name}! You are logged in.",
5
6  // Good: Gender-neutral by default
7  "profile.greeting": "Welcome back, {name}! Your session is active.",
8
9  // If gender is needed, make it explicit
10  "profile.greeting_gendered": "{gender, select, male {Welcome back, {name}! You are logged in.} female {Welcome back, {name}! You are logged in.} other {Welcome back, {name}! Your session is active.}}"
11}

Testing Gender Agreements

TypeScript
1import { render, screen } from '@testing-library/react';
2import { IntlProvider } from 'react-intl';
3
4describe('Gender Agreement Tests', () => {
5  it('should display correct Spanish gender agreement (masculine)', () => {
6    const messages = {
7      'welcome.message': '{gender, select, male {Bienvenido} female {Bienvenida} other {Bienvenido/a}}'
8    };
9
10    render(
11      <IntlProvider locale="es" messages={messages}>
12        <WelcomeMessage user={{ grammaticalGender: 'male' }} />
13      </IntlProvider>
14    );
15
16    expect(screen.getByText(/Bienvenido$/)).toBeInTheDocument();
17  });
18
19  it('should display correct Spanish gender agreement (feminine)', () => {
20    const messages = {
21      'welcome.message': '{gender, select, male {Bienvenido} female {Bienvenida} other {Bienvenido/a}}'
22    };
23
24    render(
25      <IntlProvider locale="es" messages={messages}>
26        <WelcomeMessage user={{ grammaticalGender: 'female' }} />
27      </IntlProvider>
28    );
29
30    expect(screen.getByText(/Bienvenida$/)).toBeInTheDocument();
31  });
32
33  it('should handle unspecified gender with neutral form', () => {
34    const messages = {
35      'welcome.message': '{gender, select, male {Bienvenido} female {Bienvenida} other {Bienvenido/a}}'
36    };
37
38    render(
39      <IntlProvider locale="es" messages={messages}>
40        <WelcomeMessage user={{ grammaticalGender: undefined }} />
41      </IntlProvider>
42    );
43
44    expect(screen.getByText(/Bienvenido/a$/)).toBeInTheDocument();
45  });
46});

IntlPull's Gender Handling Features

IntlPull provides specialized support for grammatical gender management:

1. ICU MessageFormat Support

All ICU select formats are fully supported with visual preview:

JavaScript
1// IntlPull editor shows live preview for each variant
2{
3  "user.status": "{gender, select, male {Connected} female {Connected} other {Connected}}"
4}

2. Gender Variant Testing

IntlPull's translation interface allows testers to preview all gender variants:

  • Switch between male/female/other variants instantly
  • See all agreements in context
  • Flag inconsistencies across related keys

3. Translation Memory with Gender Context

IntlPull's TM system understands gender context:

Source: "You are connected"
Spanish (male): "Estás conectado"
Spanish (female): "Estás conectada"
Spanish (neutral): "Estás conectado/a"

// TM suggests appropriate variant based on gender parameter

4. Validation Rules

Set validation rules to ensure gender agreements:

YAML
1validation:
2  - rule: gender_consistency
3    description: "All gender variants must be present"
4    applies_to: ["es", "fr", "de", "ru"]
5    severity: error

Real-World Implementation Examples

Example 1: Notification System

TypeScript
1// Notification with multiple gender agreements
2const notificationMessages = {
3  en: {
4    'notification.comment': '{commenterName} commented on your post'
5  },
6  es: {
7    'notification.comment': '{gender, select, ' +
8      'male {{commenterName} comentó en tu publicación} ' +
9      'female {{commenterName} comentó en tu publicación} ' +
10      'other {{commenterName} comentó en tu publicación}' +
11    '}'
12  },
13  fr: {
14    'notification.comment': '{gender, select, ' +
15      'male {{commenterName} a commenté votre publication} ' +
16      'female {{commenterName} a commenté votre publication} ' +
17      'other {{commenterName} a commenté votre publication}' +
18    '}'
19  }
20};
21
22// Usage
23function sendNotification(recipient: User, commenter: User) {
24  const message = formatMessage(
25    'notification.comment',
26    {
27      commenterName: commenter.displayName,
28      gender: commenter.grammaticalGender || 'other'
29    },
30    recipient.preferredLanguage
31  );
32
33  // Send notification
34}

Example 2: Email Templates

TypeScript
1// Email subject with gender agreement
2const emailSubjects = {
3  en: {
4    'email.welcome.subject': 'Welcome to our platform, {name}!'
5  },
6  de: {
7    'email.welcome.subject': '{gender, select, ' +
8      'male {Willkommen auf unserer Plattform, {name}!} ' +
9      'female {Willkommen auf unserer Plattform, {name}!} ' +
10      'other {Willkommen auf unserer Plattform, {name}!}' +
11    '}'
12  }
13};
14
15// Email body with multiple agreements
16const emailBodies = {
17  de: {
18    'email.welcome.body': '{gender, select, ' +
19      'male {Lieber {name},
20
21Sie wurden als Benutzer registriert.} ' +
22      'female {Liebe {name},
23
24Sie wurden als Benutzerin registriert.} ' +
25      'other {Hallo {name},
26
27Sie wurden registriert.}' +
28    '}'
29  }
30};

Example 3: Status Messages

TypeScript
1// Status display with agreement
2const statusMessages = {
3  ru: {
4    'status.online': '{gender, select, ' +
5      'male {Вы онлайн} ' +
6      'female {Вы онлайн} ' +
7      'other {Вы онлайн}' +
8    '}',
9    'status.verified': '{gender, select, ' +
10      'male {Вы подтверждены} ' +
11      'female {Вы подтверждены} ' +
12      'other {Вы подтверждены}' +
13    '}'
14  }
15};

Frequently Asked Questions

Q: Should I ask users for their gender?

Only if necessary for grammatical purposes in languages with gender agreement. Always make it optional, explain why you're asking, and provide neutral options. Many apps avoid this entirely by using gender-neutral language patterns.

Q: What's the difference between grammatical gender and gender identity?

Grammatical gender is a linguistic feature for proper sentence construction. Gender identity is personal identity. They may not align. Always clarify you're asking about language preference, not identity.

Q: How do I handle gender in languages I don't speak?

Use ICU MessageFormat select and work with native speakers or professional translators. Don't guess gender agreements—they're complex and errors are noticeable to native speakers.

Q: Can I use machine translation for gender variants?

Machine translation often struggles with gender agreement across entire sentences. Use it for drafts only, then have native speakers review all variants.

Q: What if a language has no gender?

Languages like Turkish, Finnish, Hungarian, and Chinese don't have grammatical gender. Your ICU select messages will simply return the same text for all variants, which is fine—the overhead is minimal.

Q: How do I test gender agreement bugs?

Create test users with different grammatical gender preferences. Test all UI strings that reference the user. Use automated tests to verify each variant renders correctly.

Q: Should I support more than male/female/other?

For grammatical purposes, most languages have 2-3 genders. Supporting other as a neutral fallback covers inclusive cases. Don't create gender categories beyond what the language requires grammatically.

Q: How does IntlPull help with gender agreement?

IntlPull provides ICU MessageFormat support, variant preview, translation memory with gender context, and validation rules to ensure all gender variants are complete and consistent.

Conclusion

Handling grammatical gender in i18n requires understanding linguistic systems, using ICU MessageFormat select, and implementing inclusive patterns. Key takeaways:

  1. Use ICU select for languages with grammatical gender
  2. Make gender preference optional and explain its purpose
  3. Default to gender-neutral language when possible
  4. Test all variants with native speakers
  5. Validate consistency across related strings

Tools like IntlPull simplify gender management with built-in ICU support, variant testing, and validation rules—helping you build inclusive, grammatically correct multilingual applications.

Tags
gender
grammar
i18n
inclusive
localization
icu
select
IntlPull Team
IntlPull Team
Engineering

Building tools to help teams ship products globally. Follow us for more insights on localization and i18n.