Skip to content
Merged

canary #7016

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions android/app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -167,12 +167,12 @@ android {
dimension "environment"
applicationId "me.tinykitten.trainlcd.dev"
versionNameSuffix "-dev"
versionCode 100000779
versionCode 100000781
versionName "10.15.1"
}
prod {
dimension "environment"
versionCode 100000779
versionCode 100000781
versionName "10.15.1"
}
// ストア配信する dev (Canary) と applicationId を分けた、ローカル検証専用のフレーバー。
Expand All @@ -183,7 +183,7 @@ android {
dimension "environment"
applicationId "me.tinykitten.trainlcd.local"
versionNameSuffix "-local"
versionCode 100000779
versionCode 100000781
versionName "10.15.1"
}
}
Expand Down
6 changes: 3 additions & 3 deletions android/wearable/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -85,12 +85,12 @@ android {
dimension = "environment"
applicationIdSuffix = ".dev"
versionNameSuffix = "-dev"
versionCode = 100000780
versionCode = 100000782
versionName = "10.15.1"
}
create("prod") {
dimension = "environment"
versionCode = 100000780
versionCode = 100000782
versionName = "10.15.1"
}
// :app の local フレーバーと対になるローカル検証専用フレーバー。Wear の Data Layer は
Expand All @@ -100,7 +100,7 @@ android {
dimension = "environment"
applicationIdSuffix = ".local"
versionNameSuffix = "-local"
versionCode = 100000780
versionCode = 100000782
versionName = "10.15.1"
}
}
Expand Down
4 changes: 2 additions & 2 deletions app.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ export default {
userInterfaceStyle: 'automatic',
// Expo SDK 57 の各モジュール(expo / expo-modules-core ほか)は podspec で iOS 16.4 以上を要求する
deploymentTarget: '16.4',
buildNumber: '2919',
buildNumber: '2920',
scheme: IS_DEV ? 'CanaryTrainLCD' : 'ProdTrainLCD',
bundleIdentifier: IS_DEV
? 'me.tinykitten.trainlcd.dev'
Expand All @@ -71,7 +71,7 @@ export default {
? 'me.tinykitten.trainlcd.dev'
: 'me.tinykitten.trainlcd',
permissions: [],
versionCode: 100000779,
versionCode: 100000781,
},
owner: 'trainlcd',
experiments: {
Expand Down
36 changes: 18 additions & 18 deletions ios/TrainLCD.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -2562,7 +2562,7 @@
CODE_SIGN_ENTITLEMENTS = ProdTrainLCD.entitlements;
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 2919;
CURRENT_PROJECT_VERSION = 2920;
DEAD_CODE_STRIPPING = YES;
DEVELOPMENT_TEAM = E6R2G33Z36;
INFOPLIST_FILE = TrainLCD/Schemes/Prod/Info.plist;
Expand Down Expand Up @@ -2602,7 +2602,7 @@
CODE_SIGN_ENTITLEMENTS = ProdTrainLCD.entitlements;
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 2919;
CURRENT_PROJECT_VERSION = 2920;
DEVELOPMENT_TEAM = E6R2G33Z36;
INFOPLIST_FILE = TrainLCD/Schemes/Prod/Info.plist;
INFOPLIST_KEY_CFBundleDisplayName = TrainLCD;
Expand Down Expand Up @@ -2661,7 +2661,7 @@
CODE_SIGN_ENTITLEMENTS = TrainLCD/trainlcd.entitlements;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
COPY_PHASE_STRIP = NO;
CURRENT_PROJECT_VERSION = 2919;
CURRENT_PROJECT_VERSION = 2920;
CXX = "$(REACT_NATIVE_PATH)/scripts/xcode/ccache-clang++.sh";
ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_TESTABILITY = YES;
Expand Down Expand Up @@ -2768,7 +2768,7 @@
CODE_SIGN_ENTITLEMENTS = TrainLCD/trainlcd.entitlements;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
COPY_PHASE_STRIP = YES;
CURRENT_PROJECT_VERSION = 2919;
CURRENT_PROJECT_VERSION = 2920;
CXX = "$(REACT_NATIVE_PATH)/scripts/xcode/ccache-clang++.sh";
ENABLE_NS_ASSERTIONS = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
Expand Down Expand Up @@ -2849,7 +2849,7 @@
CODE_SIGN_ENTITLEMENTS = CanaryTrainLCD.entitlements;
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 2919;
CURRENT_PROJECT_VERSION = 2920;
DEAD_CODE_STRIPPING = YES;
DEVELOPMENT_TEAM = E6R2G33Z36;
INFOPLIST_FILE = TrainLCD/Schemes/Dev/Info.plist;
Expand Down Expand Up @@ -2889,7 +2889,7 @@
CODE_SIGN_ENTITLEMENTS = CanaryTrainLCD.entitlements;
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 2919;
CURRENT_PROJECT_VERSION = 2920;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
DEVELOPMENT_TEAM = E6R2G33Z36;
INFOPLIST_FILE = TrainLCD/Schemes/Dev/Info.plist;
Expand Down Expand Up @@ -3101,7 +3101,7 @@
CODE_SIGN_ENTITLEMENTS = RideSessionActivity/CanaryRideSessionActivity.entitlements;
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 2919;
CURRENT_PROJECT_VERSION = 2920;
DEBUG_INFORMATION_FORMAT = dwarf;
DEVELOPMENT_TEAM = E6R2G33Z36;
GCC_C_LANGUAGE_STANDARD = gnu11;
Expand Down Expand Up @@ -3153,7 +3153,7 @@
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
COPY_PHASE_STRIP = NO;
CURRENT_PROJECT_VERSION = 2919;
CURRENT_PROJECT_VERSION = 2920;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
DEVELOPMENT_TEAM = E6R2G33Z36;
GCC_C_LANGUAGE_STANDARD = gnu11;
Expand Down Expand Up @@ -3204,7 +3204,7 @@
CODE_SIGN_ENTITLEMENTS = WatchWidget/ProdWatchWidget.entitlements;
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 2919;
CURRENT_PROJECT_VERSION = 2920;
DEBUG_INFORMATION_FORMAT = dwarf;
DEVELOPMENT_TEAM = E6R2G33Z36;
ENABLE_USER_SCRIPT_SANDBOXING = YES;
Expand Down Expand Up @@ -3262,7 +3262,7 @@
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
COPY_PHASE_STRIP = NO;
CURRENT_PROJECT_VERSION = 2919;
CURRENT_PROJECT_VERSION = 2920;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
DEVELOPMENT_TEAM = E6R2G33Z36;
ENABLE_USER_SCRIPT_SANDBOXING = YES;
Expand Down Expand Up @@ -3313,7 +3313,7 @@
CODE_SIGN_ENTITLEMENTS = WatchWidget/CanaryWatchWidget.entitlements;
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 2919;
CURRENT_PROJECT_VERSION = 2920;
DEBUG_INFORMATION_FORMAT = dwarf;
DEVELOPMENT_TEAM = E6R2G33Z36;
ENABLE_USER_SCRIPT_SANDBOXING = YES;
Expand Down Expand Up @@ -3370,7 +3370,7 @@
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
COPY_PHASE_STRIP = NO;
CURRENT_PROJECT_VERSION = 2919;
CURRENT_PROJECT_VERSION = 2920;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
DEVELOPMENT_TEAM = E6R2G33Z36;
ENABLE_USER_SCRIPT_SANDBOXING = YES;
Expand Down Expand Up @@ -3419,7 +3419,7 @@
CODE_SIGN_ENTITLEMENTS = RideSessionActivity/ProdRideSessionActivity.entitlements;
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 2919;
CURRENT_PROJECT_VERSION = 2920;
DEBUG_INFORMATION_FORMAT = dwarf;
DEVELOPMENT_TEAM = E6R2G33Z36;
GCC_C_LANGUAGE_STANDARD = gnu11;
Expand Down Expand Up @@ -3471,7 +3471,7 @@
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
COPY_PHASE_STRIP = NO;
CURRENT_PROJECT_VERSION = 2919;
CURRENT_PROJECT_VERSION = 2920;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
DEVELOPMENT_TEAM = E6R2G33Z36;
GCC_C_LANGUAGE_STANDARD = gnu11;
Expand Down Expand Up @@ -3690,7 +3690,7 @@
CODE_SIGN_ENTITLEMENTS = ProdAppClip/ProdAppClip.entitlements;
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 2919;
CURRENT_PROJECT_VERSION = 2920;
DEBUG_INFORMATION_FORMAT = dwarf;
DEVELOPMENT_TEAM = E6R2G33Z36;
ENABLE_USER_SCRIPT_SANDBOXING = NO;
Expand Down Expand Up @@ -3746,7 +3746,7 @@
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
COPY_PHASE_STRIP = NO;
CURRENT_PROJECT_VERSION = 2919;
CURRENT_PROJECT_VERSION = 2920;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
DEVELOPMENT_TEAM = E6R2G33Z36;
ENABLE_USER_SCRIPT_SANDBOXING = NO;
Expand Down Expand Up @@ -3796,7 +3796,7 @@
CODE_SIGN_ENTITLEMENTS = CanaryAppClip/CanaryAppClip.entitlements;
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 2919;
CURRENT_PROJECT_VERSION = 2920;
DEBUG_INFORMATION_FORMAT = dwarf;
DEVELOPMENT_TEAM = E6R2G33Z36;
ENABLE_USER_SCRIPT_SANDBOXING = NO;
Expand Down Expand Up @@ -3854,7 +3854,7 @@
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
COPY_PHASE_STRIP = NO;
CURRENT_PROJECT_VERSION = 2919;
CURRENT_PROJECT_VERSION = 2920;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
DEVELOPMENT_TEAM = E6R2G33Z36;
ENABLE_USER_SCRIPT_SANDBOXING = NO;
Expand Down
33 changes: 33 additions & 0 deletions src/utils/englishReading.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,10 +34,43 @@ describe('fixEnglishReading', () => {
);
});

it('「Mine」を英語 TTS が「みね」と読む表記へ置換する', () => {
expect(fixEnglishReading('Change here for the Mine Line.')).toBe(
'Change here for the Me-nay Line.'
);
expect(fixEnglishReading('The next station is MINE.')).toBe(
'The next station is Me-nay.'
);
expect(fixEnglishReading('The next station is Nishi-Mine.')).toBe(
'The next station is Nishi-Me-nay.'
);
});

it('語中の「mine」も前後にハイフンを挟んで置換する', () => {
expect(fixEnglishReading('The next station is Tsurugamine.')).toBe(
'The next station is Tsuruga-me-nay.'
);
expect(fixEnglishReading('Mitsumineguchi')).toBe('Mitsu-me-nay-guchi');
expect(fixEnglishReading('Minenobu')).toBe('Me-nay-nobu');
expect(fixEnglishReading('Takamine')).toBe('Taka-me-nay');
// マクロン付きの文字も語の一部として扱う
expect(fixEnglishReading('Minami-Ōmine')).toBe('Minami-Ō-me-nay');
});

it('二重に適用しても結果が変わらない', () => {
expect(fixEnglishReading(fixEnglishReading('Mine Line'))).toBe(
'Me-nay Line'
);
expect(fixEnglishReading(fixEnglishReading('Tsurugamine'))).toBe(
'Tsuruga-me-nay'
);
});

it('別語の一部は置換しない', () => {
expect(fixEnglishReading('Keiseibus')).toBe('Keiseibus');
// 西武園 (Seibuen) は 1 語なので語単位の一致では対象外
expect(fixEnglishReading('Seibuen')).toBe('Seibuen');
expect(fixEnglishReading('Minami-Urawa')).toBe('Minami-Urawa');
});

it('対象を含まないテキストはそのまま返す', () => {
Expand Down
33 changes: 29 additions & 4 deletions src/utils/englishReading.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,28 @@
// 表示用テキストには適用しないこと (TTS 生成時専用)。

type EnglishReadingRule = {
// 置換対象。ASCII 英字の単語境界 (`\b`) で囲み、`Keisei-Ueno` のような
// ハイフン連結の駅名でも語単位で一致させる。
// 置換対象。原則は ASCII 英字の単語境界 (`\b`) で囲み、`Keisei-Ueno` のような
// ハイフン連結の駅名でも語単位で一致させる。語中も置換する場合 (Mine) は
// reading を関数にして、前後の文字との区切りを補う。
pattern: RegExp;
reading: string;
reading: string | ((match: string, offset: number, text: string) => string);
};

// ローマ字表記の文字か。端末内蔵 TTS 向けの経路ではマクロンを除去しないため、
// 「Ō」などのラテン拡張文字も語の一部として扱う。
const isRomanLetter = (char: string | undefined): boolean =>
char !== undefined && /[A-Za-z\u00C0-\u024F]/.test(char);

// 「mine」を読み替え先へ置換する。Tsurugamine のように語中にある場合も置換し、
// 前後の文字とつながって別の綴りとして読まれないよう、接する側にハイフンを挟む。
// 先頭の大文字・小文字は元の綴りに合わせる (Mine → Me-nay, Takamine → Taka-me-nay)。
// TrainLCD/functions の normalizeRomanText (replaceMine) と同じ置換にして、
// リモート TTS が無効な回とも読みを揃える。
const toMineReading = (match: string, offset: number, text: string) => {
const before = isRomanLetter(text[offset - 1]) ? '-' : '';
const after = isRomanLetter(text[offset + match.length]) ? '-' : '';
const head = /[A-Z]/.test(match.charAt(0)) ? 'Me' : 'me';
return `${before}${head}-nay${after}`;
};

// NOTE: 読み替え先は必ず英語の辞書語 (か、辞書語のハイフン連結) にする。
Expand All @@ -20,13 +38,20 @@ const ENGLISH_READING_RULES: readonly EnglishReadingRule[] = [
// 「Seibu (西武)」も同じく "ei" を /aɪ/ と推定して「さいぶ」と読むため、
// "Say" + "boo" で /seɪ.buː/ (せいぶ) を確定させる。
{ pattern: /\bSeibu\b/gi, reading: 'Say-boo' },
// 「Mine (美祢・峰など)」は英語 TTS が英単語 "mine" (まいん) として読むため、
// "Me" + "nay" で /mi.neɪ/ (みね) に寄せる。Tsurugamine・Mitsumineguchi の
// ように語中にある場合も対象にするため、単語境界では区切らない。
{ pattern: /mine/gi, reading: toMineReading },
];

/**
* 英語の読み上げ用テキスト内の固有名詞を、TTS エンジンが正しく読める表記へ置換する。
*/
export const fixEnglishReading = (text: string): string =>
ENGLISH_READING_RULES.reduce(
(acc, { pattern, reading }) => acc.replace(pattern, reading),
(acc, { pattern, reading }) =>
typeof reading === 'string'
? acc.replace(pattern, reading)
: acc.replace(pattern, reading),
text
);
Loading