Skip to content

Commit

Permalink
fixed japanese and korean name formatting
Browse files Browse the repository at this point in the history
  • Loading branch information
mikegarfinkle committed Feb 8, 2024
1 parent b2d6b22 commit b2cfd3b
Show file tree
Hide file tree
Showing 8 changed files with 54 additions and 21 deletions.
5 changes: 5 additions & 0 deletions .changeset/wet-hotels-shake.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@shopify/name': patch
---

Fixed japanese and korean name formatting.
5 changes: 2 additions & 3 deletions packages/name/src/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,14 @@ export enum UnicodeCharacterSet {
Thai = '[\u0E01-\u0E3A\u0E40-\u0E5B]',
}

export const FAMILY_NAME_GIVEN_NAME_ORDERING = new Map([
export const FAMILY_NAME_GIVEN_NAME_ORDERING_INDEXED_BY_LANGUAGE = new Map([
['ko', defaultFamilyNameGivenNameOrderingFormatter],
[
'ja',
(givenName: string, familyName: string, full: boolean) =>
full ? `${familyName}${givenName}` : `${familyName}様`,
],
['zh-CN', defaultFamilyNameGivenNameOrderingFormatter],
['zh-TW', defaultFamilyNameGivenNameOrderingFormatter],
['zh', defaultFamilyNameGivenNameOrderingFormatter],
]);

function defaultFamilyNameGivenNameOrderingFormatter(
Expand Down
8 changes: 6 additions & 2 deletions packages/name/src/formatName.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import {FAMILY_NAME_GIVEN_NAME_ORDERING} from './constants';
import {FAMILY_NAME_GIVEN_NAME_ORDERING_INDEXED_BY_LANGUAGE} from './constants';
import {languageFromLocale} from './utilities';

// Note: A similar Ruby implementation of this function also exists at https://github.com/Shopify/shopify-i18n/blob/main/lib/shopify-i18n/name_formatter.rb.
export function formatName({
Expand All @@ -19,7 +20,10 @@ export function formatName({

const isFullName = Boolean(options && options.full);

const customNameFormatter = FAMILY_NAME_GIVEN_NAME_ORDERING.get(locale);
const customNameFormatter =
FAMILY_NAME_GIVEN_NAME_ORDERING_INDEXED_BY_LANGUAGE.get(
languageFromLocale(locale),
);

if (customNameFormatter) {
return customNameFormatter(name.givenName, name.familyName, isFullName);
Expand Down
7 changes: 5 additions & 2 deletions packages/name/src/hasFamilyNameGivenNameOrdering.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
import {FAMILY_NAME_GIVEN_NAME_ORDERING} from './constants';
import {FAMILY_NAME_GIVEN_NAME_ORDERING_INDEXED_BY_LANGUAGE} from './constants';
import {languageFromLocale} from './utilities';

export function hasFamilyNameGivenNameOrdering(locale: string) {
const familyNameGivenNameOrdering =
FAMILY_NAME_GIVEN_NAME_ORDERING.get(locale);
FAMILY_NAME_GIVEN_NAME_ORDERING_INDEXED_BY_LANGUAGE.get(
languageFromLocale(locale),
);
return Boolean(familyNameGivenNameOrdering);
}
38 changes: 26 additions & 12 deletions packages/name/src/tests/formatName.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,13 @@ import {formatName} from '../formatName';
describe('#formatName()', () => {
it('returns an empty string when nothing is defined', () => {
const name = {givenName: undefined, familyName: undefined};
const locale = 'en';
const locale = 'en-CA';
expect(formatName({name, locale})).toBe('');
});

it('returns only the givenName when familyName is missing', () => {
const name = {givenName: 'first'};
const locale = 'en';
const locale = 'en-CA';
expect(
formatName({
name,
Expand All @@ -20,7 +20,7 @@ describe('#formatName()', () => {

it('returns only the familyName when givenName is missing', () => {
const name = {familyName: 'last'};
const locale = 'en';
const locale = 'en-CA';
expect(
formatName({
name,
Expand Down Expand Up @@ -53,7 +53,7 @@ describe('#formatName()', () => {

it('returns givenName for English', () => {
const name = {givenName: 'first', familyName: 'last'};
const locale = 'en';
const locale = 'en-CA';
expect(
formatName({
name,
Expand All @@ -64,7 +64,7 @@ describe('#formatName()', () => {

it('returns custom name for Japanese', () => {
const name = {givenName: 'first', familyName: 'last'};
const locale = 'ja';
const locale = 'ja-JP';
expect(
formatName({
name,
Expand Down Expand Up @@ -96,7 +96,7 @@ describe('#formatName()', () => {
});

it('returns only the givenName when familyName is missing using full', () => {
const locale = 'en';
const locale = 'en-CA';
const options = {full: true};

let name: {givenName?: string; familyName?: string} = {
Expand All @@ -123,7 +123,7 @@ describe('#formatName()', () => {

it('returns only the familyName when givenName is missing using full', () => {
const name = {givenName: '', familyName: 'last'};
const locale = 'en';
const locale = 'en-CA';
const options = {full: true};

expect(
Expand All @@ -137,7 +137,7 @@ describe('#formatName()', () => {

it('returns a string when familyName is undefined using full', () => {
const name = {givenName: '', familyName: undefined};
const locale = 'en';
const locale = 'en-CA';
const options = {full: true};

expect(
Expand All @@ -151,7 +151,7 @@ describe('#formatName()', () => {

it('returns a string when givenName and familyName are missing using full', () => {
const name = {givenName: undefined, familyName: undefined};
const locale = 'en';
const locale = 'en-CA';
const options = {full: true};

expect(
Expand Down Expand Up @@ -193,7 +193,7 @@ describe('#formatName()', () => {

it('returns givenName first for English using full', () => {
const name = {givenName: 'first', familyName: 'last'};
const locale = 'en';
const locale = 'en-CA';
const options = {full: true};

expect(
Expand All @@ -207,7 +207,7 @@ describe('#formatName()', () => {

it('returns familyName first and no space for Japanese', () => {
const name = {givenName: 'first', familyName: 'last'};
const locale = 'ja';
const locale = 'ja-JP';
const options = {full: true};

expect(
Expand All @@ -221,7 +221,7 @@ describe('#formatName()', () => {

it('returns familyName first and no space for Korean', () => {
const name = {givenName: 'first', familyName: 'last'};
const locale = 'ko';
const locale = 'ko-KR';
const options = {full: true};

expect(
Expand Down Expand Up @@ -260,4 +260,18 @@ describe('#formatName()', () => {
}),
).toBe('lastfirst');
});

it('behaves similarly if we pass language instead of locale', () => {
const name = {givenName: 'first', familyName: 'last'};
const locale = 'zh';
const options = {full: true};

expect(
formatName({
name,
locale,
options,
}),
).toBe('lastfirst');
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,14 @@ import {hasFamilyNameGivenNameOrdering} from '../hasFamilyNameGivenNameOrdering'

describe('#hasFamilyNameGivenNameOrdering()', () => {
it('returns true if defaultFamilyNameGivenNameOrderingFormatter exists', () => {
expect(hasFamilyNameGivenNameOrdering('ja')).toBe(true);
expect(hasFamilyNameGivenNameOrdering('ja-JP')).toBe(true);
});

it('returns false if defaultFamilyNameGivenNameOrderingFormatter does not exist', () => {
expect(hasFamilyNameGivenNameOrdering('en')).toBe(false);
expect(hasFamilyNameGivenNameOrdering('en-CA')).toBe(false);
});

it('behaves similarly if we pass language instead of locale', () => {
expect(hasFamilyNameGivenNameOrdering('ja')).toBe(true);
});
});
1 change: 1 addition & 0 deletions packages/name/src/utilities/index.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
export {getGraphemes} from './getGraphemes';
export {identifyScripts} from './identifyScripts';
export {languageFromLocale} from './languageFromLocale';
3 changes: 3 additions & 0 deletions packages/name/src/utilities/languageFromLocale.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export function languageFromLocale(locale: string) {
return locale.split('-')[0].toLowerCase();
}

0 comments on commit b2cfd3b

Please sign in to comment.