faker icon indicating copy to clipboard operation
faker copied to clipboard

Add the concept of order for `firstName` and `lastName` in `name.fullName`

Open satoc0629 opened this issue 2 years ago • 10 comments

Clear and concise description of the problem

The sequence of Japanese names is lastName followed by firstName in the Japanese-speaking world. ex: YAMADA TARO. YAMADA is lastName. TARO is firstName. I would like to incorporate this into faker as well.

// This sentence relies on machine translation.

Suggested solution

Add full_name_order to NameDefinitions. The full_name_order is as follows.

export type FullNameOrder = 'normal' | 'reverse';

Add the ordering process using this to fullName in src/modules/name/index.ts.

    if (this.faker.definitions.name.full_name_order === 'reverse') {
      nameParts.push(lastName);
      nameParts.push(firstName);
    } else {
      nameParts.push(firstName);
      nameParts.push(lastName);
    }

Alternative

I do not understand Faker or programming that deeply, so the best approach may be something else.

Additional context

In addition to this, we would like to add a collection of first names for Japanese men and a collection of first names for Japanese women.

satoc0629 avatar Jul 30 '22 15:07 satoc0629

The suggested solution you provided sounds reasonable to me. Other locales could gain value from this as well.

In my opinion, we should call the property in the definition default_full_name_order. Additionally, I would suggest adding an option to name.fullName() that allows overriding of the default behavior for the current locale:

// en version, but that doesn't matter
import { faker } from '@faker-js/faker';

console.log(faker.definitions.name.full_name_order); // 'normal'

// call with no params resolves to the current value of the locale definition (in this case 'normal')
console.log(faker.name.fullName()); // Lexie Bernie

// explicitly set the order, but this doesn't do anything in this case as it's the same as the definitions
console.log(faker.name.fullName({ order: 'normal' })); // Lexie Bernie

// explicitly set the order and override the default value
console.log(faker.name.fullName({ order: 'reverse' })); // Bernie Lexie

xDivisionByZerox avatar Jul 30 '22 15:07 xDivisionByZerox

The suggested solution you provided sounds reasonable to me. Other locales could gain value from this as well.

In my opinion, we should call the property in the definition default_full_name_order. Additionally, I would suggest adding an option to name.fullName() that allows overriding of the default behavior for the current locale:

// en version, but that doesn't matter
import { faker } from '@faker-js/faker';

console.log(faker.definitions.name.full_name_order); // 'normal'

// call with no params resolves to the current value of the locale definition (in this case 'normal')
console.log(faker.name.fullName()); // Lexie Bernie

// explicitly set the order, but this doesn't do anything in this case as it's the same as the definitions
console.log(faker.name.fullName({ order: 'normal' })); // Lexie Bernie

// explicitly set the order and override the default value
console.log(faker.name.fullName({ order: 'reverse' })); // Bernie Lexie

Yep, Chinese is also "lastname firstname".

import-brain avatar Jul 30 '22 16:07 import-brain

I like the idea, but I wont name it normal and reversed as this is just "our" "western" normal, but in asian countries the "normal" is our "reversed" :thinking:

Shinigami92 avatar Jul 30 '22 17:07 Shinigami92

Hasn't Spanish(?) some entirely different naming scheme? E.g. The full name consists also of the parents name?

Currently in Spain, people bear a single or composite given name (nombre in Spanish) and two surnames (apellidos in Spanish).

Source: https://en.wikipedia.org/wiki/Spanish_naming_customs

ST-DDT avatar Jul 30 '22 18:07 ST-DDT

Maybe we can use parameters by country name liked this

import { faker } from '@faker-js/faker';

console.log(faker.name.fullName()); // Lexie Bernie

console.log(faker.name.fullName({ country: 'Japan' })); // Bernie Lexie

Minozzzi avatar Jul 30 '22 18:07 Minozzzi

Maybe we can use parameters by country name liked this

import { faker } from '@faker-js/faker';

console.log(faker.name.fullName()); // Lexie Bernie

console.log(faker.name.fullName({ country: 'Japan' })); // Bernie Lexie

If you want Japanese you are most likely using the jp locale. In that case, you expect all faker results to return values that align with the Japanese language.

import { faker } from '@faker-js/faker';
faker.setLocale('jp'); // I'm expecting faker to return Japanese values across all modules

// your suggestion
console.log(faker.name.fullName({ country: 'Japan' }));
// why would I need to set the country to 'Japan' here? I'm already using the Japanese locale.

Your suggestion has another flaw. If you provide a country you would have to support all (or most) of the 195 countries there are and most of them would have overlapped for the "format". This would lead to really hard-to-maintain code because of the introduced redundancy.

xDivisionByZerox avatar Jul 30 '22 18:07 xDivisionByZerox

Talvez possamos usar parâmetros por nome de país como este

import { faker } from '@faker-js/faker';

console.log(faker.name.fullName()); // Lexie Bernie

console.log(faker.name.fullName({ country: 'Japan' })); // Bernie Lexie

Se você quiser japonês, provavelmente está usando a jplocalidade. Nesse caso, você espera que todos os resultados falsos retornem valores alinhados ao idioma japonês.

import { faker } from '@faker-js/faker';
faker.setLocale('jp'); // I'm expecting faker to return Japanese values across all modules

// your suggestion
console.log(faker.name.fullName({ country: 'Japan' }));
// why would I need to set the country to 'Japan' here? I'm already using the Japanese locale.

Sua sugestão tem outra falha. Se você fornecer um country, terá que apoiar todos (ou a maioria) dos 195 países que existem e a maioria deles teria sobreposto para o "formato". Isso levaria a um código realmente difícil de manter por causa da redundância introduzida.

That makes sense.

Minozzzi avatar Jul 31 '22 00:07 Minozzzi

Thank you all for your input. I have considered the following. First, I thought that this issue is a cultural trait rooted in some countries and should not be generalized as a parameter. I think FullName in each locale should be possible during the localization process. I think this can be enumerated as full_name_pattern.ts. That is, for locales where this is configured, it would be honored, and if not configured, it would provide the same behavior as before. I have expressed my concept in a Pull Request.

Translated with www.DeepL.com/Translator (free version)

satoc0629 avatar Jul 31 '22 08:07 satoc0629

We are changing our policy to take advantage of legacy templates as you have indicated.

And we are considering the following modifications to the fullName function.

  fullName(
    options: {
      firstName?: string;
      lastName?: string;
      gender?: GenderType;
    } = {}
  ): string {
    const {
      gender = this.faker.helpers.arrayElement(['female', 'male']),
      firstName = this.firstName(gender),
      lastName = this.lastName(gender),
    } = options;

    const prefix = this.faker.helpers.maybe(() => this.prefix(gender), {
      probability: 0.125,
    });

    const suffix = this.faker.helpers.maybe(() => this.suffix(), {
      probability: 0.125,
    });

    const nameParts = [];
    if (prefix) {
      nameParts.push(prefix);
    }
    nameParts.push(firstName);
    nameParts.push(lastName);
    if (suffix) {
      nameParts.push(suffix);
    }
    const defaultName = nameParts.join(' ');

    if (
      !this.faker.definitions.name.name ||
      this.faker.definitions.name.name.length === 0
    ) {
      return defaultName;
    }
    // if (gender || firstName || lastName) {
    //   return defaultName;
    // }

    const fullNamePattern = this.faker.helpers.arrayElement(
      this.faker.definitions.name.name
    );

    const fullName = this.faker.helpers.mustache(fullNamePattern, {
      'name.gender': () => this.gender(),
      'name.binary_gender': () => this.gender(true),
      'name.prefix': () => this.prefix(gender),
      'name.female_prefix': () => this.prefix(gender),
      'name.male_prefix': () => this.prefix(gender),
      'name.first_name': () => (firstName ? firstName : this.firstName(gender)),
      'name.female_first_name': () =>
        firstName ? firstName : this.firstName(gender ? gender : 'female'),
      'name.male_first_name': () =>
        firstName ? firstName : this.firstName(gender ? gender : 'male'),
      'name.middle_name': () => this.middleName(gender),
      'name.female_middle_name': () =>
        this.middleName(gender ? gender : 'female'),
      'name.male_middle_name': () => this.middleName(gender ? gender : 'male'),
      'name.last_name': () => (lastName ? lastName : this.lastName(gender)),
      'name.female_last_name': () =>
        lastName ? lastName : this.lastName(gender ? gender : 'female'),
      'name.male_last_name': () =>
        lastName ? lastName : this.lastName(gender ? gender : 'male'),
      'name.suffix': () => (suffix ? suffix : this.suffix()),
    });

    return fullName;
  }

Retrieve the template from the legacy NameDefinitions.name and convert it.

Do you have a better idea about this? I have done my best to write it, but I feel something is missing.

Thanks for reading.

satoc0629 avatar Jul 31 '22 23:07 satoc0629

Just to note, there's not always a space between the "last" (family) name and first name.

For example in zh-CN you'd want "{{last_name}}{{first_name}}"

matthewmayer avatar Aug 17 '22 02:08 matthewmayer

Team decision

We want the full name patterns.

ST-DDT avatar Jan 26 '23 17:01 ST-DDT