From ff6dda94ddd312ebcff816cbb63e74df9857d091 Mon Sep 17 00:00:00 2001 From: Umair Jibran Date: Sat, 14 Dec 2024 16:00:59 +0500 Subject: [PATCH 1/3] feat(location): add list of spoken languages (#3333) * add list of spoken languages * remove dupes * add language definition * add language module * add test case for `language()` * autogenerated supporting code * add languages for urdu * add test to make sure the values are truthy * update seed to match new format * update language list slim them down to a few languages as the long list was not easy to build up * update documentation * update returns * language: convert alpha2 to lowercase * update seed flies * covert alpha3 to lowercase * update seeders * update example * update version * use interface for language * Update index.ts * Revert "Update index.ts" This reverts commit 72a18e99cfee1f4c09d151b27bda1f2c8d1137d8. * Update src/modules/location/index.ts Co-authored-by: ST-DDT * Update src/modules/location/index.ts Co-authored-by: ST-DDT * Update src/definitions/location.ts Co-authored-by: ST-DDT * language semantic Co-authored-by: ST-DDT * add additional test cases * add examples for each property * add languages for the supported locales * update seeds * use example of german instead of english * Update src/definitions/location.ts Co-authored-by: ST-DDT --------- Co-authored-by: ST-DDT --- src/definitions/location.ts | 8 ++ src/locales/en/location/index.ts | 2 + src/locales/en/location/language.ts | 73 +++++++++++++++++++ src/locales/ur/location/index.ts | 2 + src/locales/ur/location/language.ts | 33 +++++++++ src/modules/location/index.ts | 41 +++++++++++ .../__snapshots__/location.spec.ts.snap | 24 ++++++ test/modules/location.spec.ts | 15 ++++ .../verify-jsdoc-tags.spec.ts.snap | 1 + 9 files changed, 199 insertions(+) create mode 100644 src/locales/en/location/language.ts create mode 100644 src/locales/ur/location/language.ts diff --git a/src/definitions/location.ts b/src/definitions/location.ts index 5b4a4bc33d1..6145f2592d8 100644 --- a/src/definitions/location.ts +++ b/src/definitions/location.ts @@ -1,3 +1,4 @@ +import type { Language } from '../modules/location'; import type { LocaleEntry } from './definitions'; /** @@ -147,4 +148,11 @@ export type LocationDefinition = LocaleEntry<{ * @see [IANA Time Zone Database](https://www.iana.org/time-zones) */ time_zone: string[]; + + /** + * A list of spoken languages. + * + * @see [ISO 639-2 Language Code List](https://www.loc.gov/standards/iso639-2/php/code_list.php) + */ + language: Language[]; }>; diff --git a/src/locales/en/location/index.ts b/src/locales/en/location/index.ts index 64ca3268f7d..4dad10fee26 100644 --- a/src/locales/en/location/index.ts +++ b/src/locales/en/location/index.ts @@ -12,6 +12,7 @@ import continent from './continent'; import country from './country'; import county from './county'; import direction from './direction'; +import language from './language'; import postcode from './postcode'; import secondary_address from './secondary_address'; import state from './state'; @@ -31,6 +32,7 @@ const location: LocationDefinition = { country, county, direction, + language, postcode, secondary_address, state, diff --git a/src/locales/en/location/language.ts b/src/locales/en/location/language.ts new file mode 100644 index 00000000000..cddb7b9fd3c --- /dev/null +++ b/src/locales/en/location/language.ts @@ -0,0 +1,73 @@ +export default [ + { name: 'Afrikaans', alpha2: 'af', alpha3: 'afr' }, + { name: 'Azerbaijani', alpha2: 'az', alpha3: 'aze' }, + { name: 'Maldivian', alpha2: 'dv', alpha3: 'div' }, + { name: 'Farsi/Persian', alpha2: 'fa', alpha3: 'fas' }, + { name: 'Latvian', alpha2: 'lv', alpha3: 'lav' }, + { name: 'Indonesian', alpha2: 'id', alpha3: 'ind' }, + { name: 'Nepali', alpha2: 'ne', alpha3: 'nep' }, + { name: 'Thai', alpha2: 'th', alpha3: 'tha' }, + { name: 'Uzbek', alpha2: 'uz', alpha3: 'uzb' }, + { name: 'Yoruba', alpha2: 'yo', alpha3: 'yor' }, + { name: 'Pashto', alpha2: 'ps', alpha3: 'pus' }, + { name: 'English', alpha2: 'en', alpha3: 'eng' }, + { name: 'Urdu', alpha2: 'ur', alpha3: 'urd' }, + { name: 'German', alpha2: 'de', alpha3: 'deu' }, + { name: 'French', alpha2: 'fr', alpha3: 'fra' }, + { name: 'Spanish', alpha2: 'es', alpha3: 'spa' }, + { name: 'Italian', alpha2: 'it', alpha3: 'ita' }, + { name: 'Dutch', alpha2: 'nl', alpha3: 'nld' }, + { name: 'Russian', alpha2: 'ru', alpha3: 'rus' }, + { name: 'Portuguese', alpha2: 'pt', alpha3: 'por' }, + { name: 'Polish', alpha2: 'pl', alpha3: 'pol' }, + { name: 'Arabic', alpha2: 'ar', alpha3: 'ara' }, + { name: 'Japanese', alpha2: 'ja', alpha3: 'jpn' }, + { name: 'Chinese', alpha2: 'zh', alpha3: 'zho' }, + { name: 'Hindi', alpha2: 'hi', alpha3: 'hin' }, + { name: 'Bengali', alpha2: 'bn', alpha3: 'ben' }, + { name: 'Gujarati', alpha2: 'gu', alpha3: 'guj' }, + { name: 'Tamil', alpha2: 'ta', alpha3: 'tam' }, + { name: 'Telugu', alpha2: 'te', alpha3: 'tel' }, + { name: 'Punjabi', alpha2: 'pa', alpha3: 'pan' }, + { name: 'Vietnamese', alpha2: 'vi', alpha3: 'vie' }, + { name: 'Korean', alpha2: 'ko', alpha3: 'kor' }, + { name: 'Turkish', alpha2: 'tr', alpha3: 'tur' }, + { name: 'Swedish', alpha2: 'sv', alpha3: 'swe' }, + { name: 'Greek', alpha2: 'el', alpha3: 'ell' }, + { name: 'Czech', alpha2: 'cs', alpha3: 'ces' }, + { name: 'Hungarian', alpha2: 'hu', alpha3: 'hun' }, + { name: 'Romanian', alpha2: 'ro', alpha3: 'ron' }, + { name: 'Ukrainian', alpha2: 'uk', alpha3: 'ukr' }, + { name: 'Norwegian', alpha2: 'no', alpha3: 'nor' }, + { name: 'Serbian', alpha2: 'sr', alpha3: 'srp' }, + { name: 'Croatian', alpha2: 'hr', alpha3: 'hrv' }, + { name: 'Slovak', alpha2: 'sk', alpha3: 'slk' }, + { name: 'Slovenian', alpha2: 'sl', alpha3: 'slv' }, + { name: 'Icelandic', alpha2: 'is', alpha3: 'isl' }, + { name: 'Finnish', alpha2: 'fi', alpha3: 'fin' }, + { name: 'Danish', alpha2: 'da', alpha3: 'dan' }, + { name: 'Swahili', alpha2: 'sw', alpha3: 'swa' }, + { name: 'Bashkir', alpha2: 'ba', alpha3: 'bak' }, + { name: 'Basque', alpha2: 'eu', alpha3: 'eus' }, + { name: 'Catalan', alpha2: 'ca', alpha3: 'cat' }, + { name: 'Galician', alpha2: 'gl', alpha3: 'glg' }, + { name: 'Esperanto', alpha2: 'eo', alpha3: 'epo' }, + { name: 'Fijian', alpha2: 'fj', alpha3: 'fij' }, + { name: 'Malagasy', alpha2: 'mg', alpha3: 'mlg' }, + { name: 'Maltese', alpha2: 'mt', alpha3: 'mlt' }, + { name: 'Albanian', alpha2: 'sq', alpha3: 'sqi' }, + { name: 'Armenian', alpha2: 'hy', alpha3: 'hye' }, + { name: 'Georgian', alpha2: 'ka', alpha3: 'kat' }, + { name: 'Macedonian', alpha2: 'mk', alpha3: 'mkd' }, + { name: 'Kazakh', alpha2: 'kk', alpha3: 'kaz' }, + { name: 'Haitian Creole', alpha2: 'ht', alpha3: 'hat' }, + { name: 'Mongolian', alpha2: 'mn', alpha3: 'mon' }, + { name: 'Kyrgyz', alpha2: 'ky', alpha3: 'kir' }, + { name: 'Finnish', alpha2: 'fi', alpha3: 'fin' }, + { name: 'Tagalog', alpha2: 'tl', alpha3: 'tgl' }, + { name: 'Malay', alpha2: 'ms', alpha3: 'msa' }, + { name: 'Tajik', alpha2: 'tg', alpha3: 'tgk' }, + { name: 'Swati', alpha2: 'ss', alpha3: 'ssw' }, + { name: 'Tatar', alpha2: 'tt', alpha3: 'tat' }, + { name: 'Zulu', alpha2: 'zu', alpha3: 'zul' }, +]; diff --git a/src/locales/ur/location/index.ts b/src/locales/ur/location/index.ts index ea213fcab40..d278b2d5d5d 100644 --- a/src/locales/ur/location/index.ts +++ b/src/locales/ur/location/index.ts @@ -10,6 +10,7 @@ import city_prefix from './city_prefix'; import city_suffix from './city_suffix'; import country from './country'; import direction from './direction'; +import language from './language'; import postcode from './postcode'; import secondary_address from './secondary_address'; import state from './state'; @@ -26,6 +27,7 @@ const location: LocationDefinition = { city_suffix, country, direction, + language, postcode, secondary_address, state, diff --git a/src/locales/ur/location/language.ts b/src/locales/ur/location/language.ts new file mode 100644 index 00000000000..b6df76574f3 --- /dev/null +++ b/src/locales/ur/location/language.ts @@ -0,0 +1,33 @@ +export default [ + { name: 'پشتو', alpha2: 'ps', alpha3: 'pus' }, + { name: 'اردو', alpha2: 'ur', alpha3: 'urd' }, + { name: 'انگریزی', alpha2: 'en', alpha3: 'eng' }, + { name: 'جرمن', alpha2: 'de', alpha3: 'deu' }, + { name: 'فرانسیسی', alpha2: 'fr', alpha3: 'fra' }, + { name: 'اسپینش', alpha2: 'es', alpha3: 'spa' }, + { name: 'دچ', alpha2: 'nl', alpha3: 'nld' }, + { name: 'روسی', alpha2: 'ru', alpha3: 'rus' }, + { name: 'پرتگالی', alpha2: 'pt', alpha3: 'por' }, + { name: 'پولش', alpha2: 'pl', alpha3: 'pol' }, + { name: 'عربی', alpha2: 'ar', alpha3: 'ara' }, + { name: 'جاپانی', alpha2: 'ja', alpha3: 'jpn' }, + { name: 'چینی', alpha2: 'zh', alpha3: 'zho' }, + { name: 'ہندی', alpha2: 'hi', alpha3: 'hin' }, + { name: 'بنگالی', alpha2: 'bn', alpha3: 'ben' }, + { name: 'تمل', alpha2: 'ta', alpha3: 'tam' }, + { name: 'تلگو', alpha2: 'te', alpha3: 'tel' }, + { name: 'پنجابی', alpha2: 'pa', alpha3: 'pan' }, + { name: 'ترکی', alpha2: 'tr', alpha3: 'tur' }, + { name: 'سویڈش', alpha2: 'sv', alpha3: 'swe' }, + { name: 'یونانی', alpha2: 'el', alpha3: 'ell' }, + { name: 'چیک', alpha2: 'cs', alpha3: 'ces' }, + { name: 'ہنگرین', alpha2: 'hu', alpha3: 'hun' }, + { name: 'نارویجن', alpha2: 'no', alpha3: 'nor' }, + { name: 'کروشیائی', alpha2: 'hr', alpha3: 'hrv' }, + { name: 'سلوواک', alpha2: 'sk', alpha3: 'slk' }, + { name: 'سلووینیائی', alpha2: 'sl', alpha3: 'slv' }, + { name: 'فنش', alpha2: 'fi', alpha3: 'fin' }, + { name: 'دنش', alpha2: 'da', alpha3: 'dan' }, + { name: 'مالٹی', alpha2: 'mt', alpha3: 'mlt' }, + { name: 'تاجک', alpha2: 'tg', alpha3: 'tgk' }, +]; diff --git a/src/modules/location/index.ts b/src/modules/location/index.ts index 4a49e029501..29267eb1a44 100644 --- a/src/modules/location/index.ts +++ b/src/modules/location/index.ts @@ -1,6 +1,26 @@ import { FakerError } from '../../errors/faker-error'; import { ModuleBase } from '../../internal/module-base'; +/** + * Represents a language with its full name, 2 character ISO 639-1 code, and 3 character ISO 639-2 code. + */ +export interface Language { + /** + * The full name for the language (e.g. `English`). + */ + name: string; + + /** + * The 2 character [ISO 639-1](https://en.wikipedia.org/wiki/ISO_639-1) code. + */ + alpha2: string; + + /** + * The 3 character [ISO 639-2](https://en.wikipedia.org/wiki/ISO_639-2) code. + */ + alpha3: string; +} + /** * Module to generate addresses and locations. Prior to Faker 8.0.0, this module was known as `faker.address`. * @@ -628,4 +648,25 @@ export class LocationModule extends ModuleBase { this.faker.definitions.location.time_zone ); } + + /** + * Returns a random spoken language. + * + * @see [ISO 639-1](https://en.wikipedia.org/wiki/ISO_639-1) + * @see [ISO 639-2](https://en.wikipedia.org/wiki/ISO_639-2) + * @see [ISO 639-2 Language Code List](https://www.loc.gov/standards/iso639-2/php/code_list.php) + * + * @example + * faker.location.language() // { alpha2: 'de', alpha3: 'deu', name: 'German' } + * faker.location.language().name // German + * faker.location.language().alpha2 // de + * faker.location.language().alpha3 // deu + * + * @since 9.4.0 + */ + language(): Language { + return this.faker.helpers.arrayElement( + this.faker.definitions.location.language + ); + } } diff --git a/test/modules/__snapshots__/location.spec.ts.snap b/test/modules/__snapshots__/location.spec.ts.snap index a8d24e9a6ef..6116943fd53 100644 --- a/test/modules/__snapshots__/location.spec.ts.snap +++ b/test/modules/__snapshots__/location.spec.ts.snap @@ -32,6 +32,14 @@ exports[`location > 42 > direction > noArgs 1`] = `"South"`; exports[`location > 42 > direction > with abbreviated option 1`] = `"S"`; +exports[`location > 42 > language 1`] = ` +{ + "alpha2": "gu", + "alpha3": "guj", + "name": "Gujarati", +} +`; + exports[`location > 42 > latitude > noArgs 1`] = `-22.5828`; exports[`location > 42 > latitude > with max and min option 1`] = `-2.5092`; @@ -170,6 +178,14 @@ exports[`location > 1211 > direction > noArgs 1`] = `"Southwest"`; exports[`location > 1211 > direction > with abbreviated option 1`] = `"SW"`; +exports[`location > 1211 > language 1`] = ` +{ + "alpha2": "tl", + "alpha3": "tgl", + "name": "Tagalog", +} +`; + exports[`location > 1211 > latitude > noArgs 1`] = `77.1337`; exports[`location > 1211 > latitude > with max and min option 1`] = `8.5704`; @@ -308,6 +324,14 @@ exports[`location > 1337 > direction > noArgs 1`] = `"South"`; exports[`location > 1337 > direction > with abbreviated option 1`] = `"S"`; +exports[`location > 1337 > language 1`] = ` +{ + "alpha2": "ru", + "alpha3": "rus", + "name": "Russian", +} +`; + exports[`location > 1337 > latitude > noArgs 1`] = `-42.8356`; exports[`location > 1337 > latitude > with max and min option 1`] = `-4.7595`; diff --git a/test/modules/location.spec.ts b/test/modules/location.spec.ts index 2be7c4896a3..78b688126dc 100644 --- a/test/modules/location.spec.ts +++ b/test/modules/location.spec.ts @@ -126,6 +126,8 @@ describe('location', () => { t.it('timeZone'); + t.it('language'); + t.describeEach( 'direction', 'cardinalDirection', @@ -415,6 +417,19 @@ describe('location', () => { expect(faker.definitions.location.time_zone).toContain(actual); }); }); + + describe('language()', () => { + it('should return a random language', () => { + const actual = faker.location.language(); + expect(actual.name).toBeTruthy(); + expect(actual.alpha2).toBeTruthy(); + expect(actual.alpha2).toHaveLength(2); + expect(actual.alpha3).toBeTruthy(); + expect(actual.alpha3).toHaveLength(3); + + expect(faker.definitions.location.language).toContain(actual); + }); + }); } ); }); diff --git a/test/scripts/apidocs/__snapshots__/verify-jsdoc-tags.spec.ts.snap b/test/scripts/apidocs/__snapshots__/verify-jsdoc-tags.spec.ts.snap index bc3ee0a01a3..c13b2811a53 100644 --- a/test/scripts/apidocs/__snapshots__/verify-jsdoc-tags.spec.ts.snap +++ b/test/scripts/apidocs/__snapshots__/verify-jsdoc-tags.spec.ts.snap @@ -288,6 +288,7 @@ exports[`check docs completeness > all modules and methods are present 1`] = ` "countryCode", "county", "direction", + "language", "latitude", "longitude", "nearbyGPSCoordinate", From ca52d31859dc7037a6c7ee90eac32eefa7d1ba32 Mon Sep 17 00:00:00 2001 From: ST-DDT Date: Sat, 14 Dec 2024 12:33:01 +0100 Subject: [PATCH 2/3] chore: improve variable naming of helpers module (#3316) --- src/modules/helpers/index.ts | 40 ++++++++++++++++++------------------ 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/src/modules/helpers/index.ts b/src/modules/helpers/index.ts index 52d311dcb05..375e820ca8a 100644 --- a/src/modules/helpers/index.ts +++ b/src/modules/helpers/index.ts @@ -184,18 +184,18 @@ export function legacyReplaceSymbolWithNumber( string: string = '', symbol: string = '#' ): string { - let str = ''; + let result = ''; for (let i = 0; i < string.length; i++) { if (string.charAt(i) === symbol) { - str += faker.number.int(9); + result += faker.number.int(9); } else if (string.charAt(i) === '!') { - str += faker.number.int({ min: 2, max: 9 }); + result += faker.number.int({ min: 2, max: 9 }); } else { - str += string.charAt(i); + result += string.charAt(i); } } - return str; + return result; } /** @@ -270,23 +270,23 @@ export class SimpleHelpersModule extends SimpleModuleBase { 'Y', 'Z', ]; - let str = ''; + let result = ''; for (let i = 0; i < string.length; i++) { if (string.charAt(i) === '#') { - str += this.faker.number.int(9); + result += this.faker.number.int(9); } else if (string.charAt(i) === '?') { - str += this.arrayElement(alpha); + result += this.arrayElement(alpha); } else if (string.charAt(i) === '*') { - str += this.faker.datatype.boolean() + result += this.faker.datatype.boolean() ? this.arrayElement(alpha) : this.faker.number.int(9); } else { - str += string.charAt(i); + result += string.charAt(i); } } - return str; + return result; } /** @@ -700,7 +700,7 @@ export class SimpleHelpersModule extends SimpleModuleBase { /** * Replaces the `{{placeholder}}` patterns in the given string mustache style. * - * @param str The template string to parse. + * @param text The template string to parse. * @param data The data used to populate the placeholders. * This is a record where the key is the template placeholder, * whereas the value is either a string or a function suitable for `String.replace()`. @@ -714,10 +714,10 @@ export class SimpleHelpersModule extends SimpleModuleBase { * @since 2.0.1 */ mustache( - str: string | undefined, + text: string | undefined, data: Record[1]> ): string { - if (str == null) { + if (text == null) { return ''; } @@ -727,13 +727,13 @@ export class SimpleHelpersModule extends SimpleModuleBase { if (typeof value === 'string') { // escape $, source: https://stackoverflow.com/a/6969486/6897682 value = value.replaceAll('$', '$$$$'); - str = str.replace(re, value); + text = text.replace(re, value); } else { - str = str.replace(re, value); + text = text.replace(re, value); } } - return str; + return text; } /** @@ -897,7 +897,7 @@ export class SimpleHelpersModule extends SimpleModuleBase { ); } - const total = array.reduce((acc, { weight }) => acc + weight, 0); + const total = array.reduce((sum, { weight }) => sum + weight, 0); const random = this.faker.number.float({ min: 0, max: total, @@ -1276,10 +1276,10 @@ export class HelpersModule extends SimpleHelpersModule { // Replace the found tag with the returned fake value // We cannot use string.replace here because the result might contain evaluated characters - const res = + const patched = pattern.substring(0, start) + stringified + pattern.substring(end + 2); // return the response recursively until we are done finding all tags - return this.fake(res); + return this.fake(patched); } } From 5436111712afc292004216f25d5e3eec0705cc56 Mon Sep 17 00:00:00 2001 From: ST-DDT Date: Sat, 14 Dec 2024 12:38:07 +0100 Subject: [PATCH 3/3] docs: fix link to randomizer guide (#3332) Currently, the link refers to the same documentation/page it is on. This PR changes the link to point to the guide docs instead. --- src/randomizer.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/randomizer.ts b/src/randomizer.ts index a0bc14bfaae..e52deb8701e 100644 --- a/src/randomizer.ts +++ b/src/randomizer.ts @@ -9,7 +9,7 @@ * Instances are expected to be ready for use before being passed to any Faker constructor, * this includes being `seed()`ed with either a random or fixed value. * - * For more information please refer to the [documentation](https://fakerjs.dev/api/randomizer.html). + * For more information please refer to the [documentation](https://fakerjs.dev/guide/randomizer.html). * * @example * import { Faker, Randomizer, SimpleFaker } from '@faker-js/faker';