added language autodiscovery
This commit is contained in:
parent
08b0ec0840
commit
dabbb4304d
8 changed files with 868 additions and 1163 deletions
File diff suppressed because it is too large
Load diff
|
@ -8,6 +8,8 @@
|
||||||
|
|
||||||
/* Begin PBXBuildFile section */
|
/* Begin PBXBuildFile section */
|
||||||
1DDD58160DA1D0A300B32029 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 1DDD58140DA1D0A300B32029 /* MainMenu.xib */; };
|
1DDD58160DA1D0A300B32029 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 1DDD58140DA1D0A300B32029 /* MainMenu.xib */; };
|
||||||
|
1F6C8C521A06A13D004D992E /* pause.png in Resources */ = {isa = PBXBuildFile; fileRef = 1F6C8C501A06A13D004D992E /* pause.png */; };
|
||||||
|
1F6C8C531A06A13D004D992E /* play.png in Resources */ = {isa = PBXBuildFile; fileRef = 1F6C8C511A06A13D004D992E /* play.png */; };
|
||||||
1FA38C49124D27C8004B8852 /* play-icon.png in Resources */ = {isa = PBXBuildFile; fileRef = 1FA38C48124D27C8004B8852 /* play-icon.png */; };
|
1FA38C49124D27C8004B8852 /* play-icon.png in Resources */ = {isa = PBXBuildFile; fileRef = 1FA38C48124D27C8004B8852 /* play-icon.png */; };
|
||||||
1FA38CD3124D4349004B8852 /* Icon.icns in Resources */ = {isa = PBXBuildFile; fileRef = 1FA38CD2124D4349004B8852 /* Icon.icns */; };
|
1FA38CD3124D4349004B8852 /* Icon.icns in Resources */ = {isa = PBXBuildFile; fileRef = 1FA38CD2124D4349004B8852 /* Icon.icns */; };
|
||||||
1FF67B3E12948FDE00CA07A3 /* SpeakerApplication.m in Sources */ = {isa = PBXBuildFile; fileRef = 1FF67B3D12948FDE00CA07A3 /* SpeakerApplication.m */; };
|
1FF67B3E12948FDE00CA07A3 /* SpeakerApplication.m in Sources */ = {isa = PBXBuildFile; fileRef = 1FF67B3D12948FDE00CA07A3 /* SpeakerApplication.m */; };
|
||||||
|
@ -22,6 +24,8 @@
|
||||||
1058C7A1FEA54F0111CA2CBB /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = /System/Library/Frameworks/Cocoa.framework; sourceTree = "<absolute>"; };
|
1058C7A1FEA54F0111CA2CBB /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = /System/Library/Frameworks/Cocoa.framework; sourceTree = "<absolute>"; };
|
||||||
13E42FB307B3F0F600E4EEF1 /* CoreData.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreData.framework; path = /System/Library/Frameworks/CoreData.framework; sourceTree = "<absolute>"; };
|
13E42FB307B3F0F600E4EEF1 /* CoreData.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreData.framework; path = /System/Library/Frameworks/CoreData.framework; sourceTree = "<absolute>"; };
|
||||||
1DDD58150DA1D0A300B32029 /* English */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = English; path = English.lproj/MainMenu.xib; sourceTree = "<group>"; };
|
1DDD58150DA1D0A300B32029 /* English */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = English; path = English.lproj/MainMenu.xib; sourceTree = "<group>"; };
|
||||||
|
1F6C8C501A06A13D004D992E /* pause.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = pause.png; sourceTree = "<group>"; };
|
||||||
|
1F6C8C511A06A13D004D992E /* play.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = play.png; sourceTree = "<group>"; };
|
||||||
1FA38C48124D27C8004B8852 /* play-icon.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "play-icon.png"; sourceTree = "<group>"; };
|
1FA38C48124D27C8004B8852 /* play-icon.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "play-icon.png"; sourceTree = "<group>"; };
|
||||||
1FA38CD2124D4349004B8852 /* Icon.icns */ = {isa = PBXFileReference; lastKnownFileType = image.icns; path = Icon.icns; sourceTree = "<group>"; };
|
1FA38CD2124D4349004B8852 /* Icon.icns */ = {isa = PBXFileReference; lastKnownFileType = image.icns; path = Icon.icns; sourceTree = "<group>"; };
|
||||||
1FF67B3C12948FDE00CA07A3 /* SpeakerApplication.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SpeakerApplication.h; sourceTree = "<group>"; };
|
1FF67B3C12948FDE00CA07A3 /* SpeakerApplication.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SpeakerApplication.h; sourceTree = "<group>"; };
|
||||||
|
@ -109,6 +113,8 @@
|
||||||
29B97317FDCFA39411CA2CEA /* Resources */ = {
|
29B97317FDCFA39411CA2CEA /* Resources */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
|
1F6C8C501A06A13D004D992E /* pause.png */,
|
||||||
|
1F6C8C511A06A13D004D992E /* play.png */,
|
||||||
1FA38CD2124D4349004B8852 /* Icon.icns */,
|
1FA38CD2124D4349004B8852 /* Icon.icns */,
|
||||||
1FA38C48124D27C8004B8852 /* play-icon.png */,
|
1FA38C48124D27C8004B8852 /* play-icon.png */,
|
||||||
8D1107310486CEB800E47090 /* Speaker-Info.plist */,
|
8D1107310486CEB800E47090 /* Speaker-Info.plist */,
|
||||||
|
@ -153,6 +159,8 @@
|
||||||
/* Begin PBXProject section */
|
/* Begin PBXProject section */
|
||||||
29B97313FDCFA39411CA2CEA /* Project object */ = {
|
29B97313FDCFA39411CA2CEA /* Project object */ = {
|
||||||
isa = PBXProject;
|
isa = PBXProject;
|
||||||
|
attributes = {
|
||||||
|
};
|
||||||
buildConfigurationList = C01FCF4E08A954540054247B /* Build configuration list for PBXProject "Speaker" */;
|
buildConfigurationList = C01FCF4E08A954540054247B /* Build configuration list for PBXProject "Speaker" */;
|
||||||
compatibilityVersion = "Xcode 3.1";
|
compatibilityVersion = "Xcode 3.1";
|
||||||
developmentRegion = English;
|
developmentRegion = English;
|
||||||
|
@ -179,8 +187,10 @@
|
||||||
files = (
|
files = (
|
||||||
8D11072B0486CEB800E47090 /* InfoPlist.strings in Resources */,
|
8D11072B0486CEB800E47090 /* InfoPlist.strings in Resources */,
|
||||||
1DDD58160DA1D0A300B32029 /* MainMenu.xib in Resources */,
|
1DDD58160DA1D0A300B32029 /* MainMenu.xib in Resources */,
|
||||||
|
1F6C8C521A06A13D004D992E /* pause.png in Resources */,
|
||||||
1FA38C49124D27C8004B8852 /* play-icon.png in Resources */,
|
1FA38C49124D27C8004B8852 /* play-icon.png in Resources */,
|
||||||
1FA38CD3124D4349004B8852 /* Icon.icns in Resources */,
|
1FA38CD3124D4349004B8852 /* Icon.icns in Resources */,
|
||||||
|
1F6C8C531A06A13D004D992E /* play.png in Resources */,
|
||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
};
|
};
|
||||||
|
|
|
@ -10,29 +10,29 @@
|
||||||
<string>Speaker</string>
|
<string>Speaker</string>
|
||||||
<key>IDESourceControlProjectOriginsDictionary</key>
|
<key>IDESourceControlProjectOriginsDictionary</key>
|
||||||
<dict>
|
<dict>
|
||||||
<key>B3FBBA97-D123-44B8-9654-E8F7B4DE23C0</key>
|
<key>84929CFFB1C126DC09C07F4A0C98501C72BCAF7B</key>
|
||||||
<string>ssh://github.com/jeena/Speaker.git</string>
|
<string>ssh://github.com/jeena/Speaker.git</string>
|
||||||
</dict>
|
</dict>
|
||||||
<key>IDESourceControlProjectPath</key>
|
<key>IDESourceControlProjectPath</key>
|
||||||
<string>Speaker.xcodeproj/project.xcworkspace</string>
|
<string>Speaker.xcodeproj/project.xcworkspace</string>
|
||||||
<key>IDESourceControlProjectRelativeInstallPathDictionary</key>
|
<key>IDESourceControlProjectRelativeInstallPathDictionary</key>
|
||||||
<dict>
|
<dict>
|
||||||
<key>B3FBBA97-D123-44B8-9654-E8F7B4DE23C0</key>
|
<key>84929CFFB1C126DC09C07F4A0C98501C72BCAF7B</key>
|
||||||
<string>../..</string>
|
<string>../..</string>
|
||||||
</dict>
|
</dict>
|
||||||
<key>IDESourceControlProjectURL</key>
|
<key>IDESourceControlProjectURL</key>
|
||||||
<string>ssh://github.com/jeena/Speaker.git</string>
|
<string>ssh://github.com/jeena/Speaker.git</string>
|
||||||
<key>IDESourceControlProjectVersion</key>
|
<key>IDESourceControlProjectVersion</key>
|
||||||
<integer>110</integer>
|
<integer>111</integer>
|
||||||
<key>IDESourceControlProjectWCCIdentifier</key>
|
<key>IDESourceControlProjectWCCIdentifier</key>
|
||||||
<string>B3FBBA97-D123-44B8-9654-E8F7B4DE23C0</string>
|
<string>84929CFFB1C126DC09C07F4A0C98501C72BCAF7B</string>
|
||||||
<key>IDESourceControlProjectWCConfigurations</key>
|
<key>IDESourceControlProjectWCConfigurations</key>
|
||||||
<array>
|
<array>
|
||||||
<dict>
|
<dict>
|
||||||
<key>IDESourceControlRepositoryExtensionIdentifierKey</key>
|
<key>IDESourceControlRepositoryExtensionIdentifierKey</key>
|
||||||
<string>public.vcs.git</string>
|
<string>public.vcs.git</string>
|
||||||
<key>IDESourceControlWCCIdentifierKey</key>
|
<key>IDESourceControlWCCIdentifierKey</key>
|
||||||
<string>B3FBBA97-D123-44B8-9654-E8F7B4DE23C0</string>
|
<string>84929CFFB1C126DC09C07F4A0C98501C72BCAF7B</string>
|
||||||
<key>IDESourceControlWCCName</key>
|
<key>IDESourceControlWCCName</key>
|
||||||
<string>Speaker</string>
|
<string>Speaker</string>
|
||||||
</dict>
|
</dict>
|
||||||
|
|
Binary file not shown.
|
@ -16,12 +16,14 @@
|
||||||
NSSpeechSynthesizer *synth;
|
NSSpeechSynthesizer *synth;
|
||||||
NSRange oldRange;
|
NSRange oldRange;
|
||||||
BOOL isNewLocation;
|
BOOL isNewLocation;
|
||||||
|
NSArray *languages;
|
||||||
}
|
}
|
||||||
|
|
||||||
@property (weak) IBOutlet NSWindow *window;
|
@property (weak) IBOutlet NSWindow *window;
|
||||||
@property (strong, nonatomic) IBOutlet NSTextView *textView;
|
@property (strong, nonatomic) IBOutlet NSTextView *textView;
|
||||||
@property (weak) IBOutlet NSMenu *languageMenu;
|
@property (weak) IBOutlet NSMenu *languageMenu;
|
||||||
@property (weak) IBOutlet NSPopUpButton *languageMenuPopupButton;
|
@property (weak) IBOutlet NSPopUpButton *languageMenuPopupButton;
|
||||||
|
@property (weak) IBOutlet NSToolbarItem *speakButton;
|
||||||
|
|
||||||
-(IBAction)speakAction:(id)sender;
|
-(IBAction)speakAction:(id)sender;
|
||||||
-(IBAction)seekForward:(id)sender;
|
-(IBAction)seekForward:(id)sender;
|
||||||
|
@ -33,4 +35,7 @@
|
||||||
- (void)changeLanguage:(id)sender;
|
- (void)changeLanguage:(id)sender;
|
||||||
- (void)changeVoiceGender:(id)sender;
|
- (void)changeVoiceGender:(id)sender;
|
||||||
|
|
||||||
|
- (NSString *)findLanguageFromString:(NSString *)text;
|
||||||
|
- (void)setVoiceForLanguage:(NSString *)language;
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
|
@ -15,6 +15,7 @@
|
||||||
@implementation SpeakerAppDelegate
|
@implementation SpeakerAppDelegate
|
||||||
@synthesize languageMenu;
|
@synthesize languageMenu;
|
||||||
@synthesize languageMenuPopupButton;
|
@synthesize languageMenuPopupButton;
|
||||||
|
@synthesize speakButton;
|
||||||
|
|
||||||
@synthesize window, textView;
|
@synthesize window, textView;
|
||||||
|
|
||||||
|
@ -24,6 +25,7 @@
|
||||||
synth.delegate = self;
|
synth.delegate = self;
|
||||||
oldRange = NSMakeRange(-1, -1);
|
oldRange = NSMakeRange(-1, -1);
|
||||||
isNewLocation = YES;
|
isNewLocation = YES;
|
||||||
|
languages = nil;
|
||||||
|
|
||||||
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
|
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
|
||||||
NSString *string = [defaults objectForKey:@"text"];
|
NSString *string = [defaults objectForKey:@"text"];
|
||||||
|
@ -41,51 +43,64 @@
|
||||||
- (void)initLanugageMenu
|
- (void)initLanugageMenu
|
||||||
{
|
{
|
||||||
NSString *startName = [[NSUserDefaults standardUserDefaults] stringForKey:@"languageVoiceName"];
|
NSString *startName = [[NSUserDefaults standardUserDefaults] stringForKey:@"languageVoiceName"];
|
||||||
NSMenuItem *startItem = nil;
|
|
||||||
|
|
||||||
NSLocale *currentLocale = [NSLocale currentLocale];
|
NSLocale *currentLocale = [NSLocale currentLocale];
|
||||||
NSArray *voices = [NSSpeechSynthesizer availableVoices];
|
NSArray *voices = [NSSpeechSynthesizer availableVoices];
|
||||||
|
|
||||||
[self.languageMenu removeAllItems];
|
[self.languageMenu removeAllItems];
|
||||||
|
|
||||||
|
NSMutableArray *langs = [NSMutableArray arrayWithCapacity:[voices count]];
|
||||||
|
NSMutableArray *defaultVoices = [[NSUserDefaults standardUserDefaults] mutableArrayValueForKey:@"defaultVoices"];
|
||||||
|
|
||||||
for (NSInteger i = 0; i < [voices count]; i++)
|
for (NSInteger i = 0; i < [voices count]; i++)
|
||||||
{
|
{
|
||||||
NSDictionary *dict = [NSSpeechSynthesizer attributesForVoice:[voices objectAtIndex:i]];
|
NSDictionary *dict = [NSSpeechSynthesizer attributesForVoice:[voices objectAtIndex:i]];
|
||||||
NSString *countryString = [currentLocale displayNameForKey:NSLocaleIdentifier value:[dict objectForKey:@"VoiceLocaleIdentifier"]];
|
NSString *countryString = [currentLocale displayNameForKey:NSLocaleIdentifier value:[dict objectForKey:@"VoiceLocaleIdentifier"]];
|
||||||
|
|
||||||
|
NSMenuItem *item = [[NSMenuItem alloc] initWithTitle:[dict objectForKey:@"VoiceName"] action:@selector(changeLanguage:) keyEquivalent:@""];
|
||||||
NSMenuItem *country = [self.languageMenu itemWithTitle:countryString];
|
NSMenuItem *country = [self.languageMenu itemWithTitle:countryString];
|
||||||
if (!country) {
|
if (!country) {
|
||||||
country = [[NSMenuItem alloc] initWithTitle:countryString action:nil keyEquivalent:@""];
|
country = [[NSMenuItem alloc] initWithTitle:countryString action:nil keyEquivalent:@""];
|
||||||
NSMenu *submenu = [[NSMenu alloc] init];
|
NSMenu *submenu = [[NSMenu alloc] init];
|
||||||
[country setSubmenu:submenu];
|
[country setSubmenu:submenu];
|
||||||
[self.languageMenu addItem:country];
|
[self.languageMenu addItem:country];
|
||||||
|
|
||||||
|
[langs addObject:[[[dict objectForKey:@"VoiceLanguage"] componentsSeparatedByString:@"-"] objectAtIndex:0]];
|
||||||
}
|
}
|
||||||
|
|
||||||
NSMenuItem *item = [[NSMenuItem alloc] initWithTitle:[dict objectForKey:@"VoiceName"] action:@selector(changeLanguage:) keyEquivalent:@""];
|
|
||||||
item.tag = i;
|
item.tag = i;
|
||||||
[[country submenu] addItem:item];
|
[[country submenu] addItem:item];
|
||||||
|
|
||||||
|
if ([defaultVoices indexOfObjectIdenticalTo:item.title] != NSNotFound) {
|
||||||
|
item.state = NSOnState;
|
||||||
|
}
|
||||||
|
|
||||||
if ((![[NSUserDefaults standardUserDefaults] objectForKey:@"languageVoiceIndex"] && [[dict objectForKey:@"VoiceName"] isEqualToString:@"Alex"]) || [item.title isEqualToString:startName])
|
if ((![[NSUserDefaults standardUserDefaults] objectForKey:@"languageVoiceIndex"] && [[dict objectForKey:@"VoiceName"] isEqualToString:@"Alex"]) || [item.title isEqualToString:startName])
|
||||||
{
|
{
|
||||||
startItem = item;
|
//startItem = item;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[self changeLanguage:startItem];
|
languages = langs;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)changeLanguage:(id)sender
|
- (void)changeLanguage:(id)sender
|
||||||
{
|
{
|
||||||
NSMenuItem *item = (NSMenuItem *)sender;
|
NSMenuItem *item = (NSMenuItem *)sender;
|
||||||
|
NSMenuItem *parent = item.parentItem;
|
||||||
// Only if the user doesn't chose the same as it already was.
|
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
|
||||||
if (item.menu != self.languageMenu) {
|
NSMutableArray *defaultVoices = [defaults mutableArrayValueForKey:@"defaultVoices"];
|
||||||
NSString *voice = [[NSSpeechSynthesizer attributesForVoice:[[NSSpeechSynthesizer availableVoices] objectAtIndex:item.tag]] objectForKey:@"VoiceIdentifier"];
|
|
||||||
[synth setVoice:voice];
|
for (NSMenuItem *child in parent.submenu.itemArray) {
|
||||||
|
if (child.state == NSOnState) {
|
||||||
[[NSUserDefaults standardUserDefaults] setObject:item.title forKey:@"languageVoiceName"];
|
[defaultVoices removeObjectIdenticalTo:child.title];
|
||||||
[self.languageMenuPopupButton setTitle:item.title];
|
child.state = NSOffState;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
item.state = NSOnState;
|
||||||
|
[defaultVoices addObject:item.title];
|
||||||
|
[defaults synchronize];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)applicationWillTerminate:(NSNotification *)aNotification {
|
- (void)applicationWillTerminate:(NSNotification *)aNotification {
|
||||||
|
@ -98,8 +113,10 @@
|
||||||
-(IBAction)speakAction:(id)sender {
|
-(IBAction)speakAction:(id)sender {
|
||||||
if ([synth isSpeaking]) {
|
if ([synth isSpeaking]) {
|
||||||
[self stopSpeaking];
|
[self stopSpeaking];
|
||||||
|
speakButton.image = [NSImage imageNamed:@"play.png"];
|
||||||
} else {
|
} else {
|
||||||
[self startSpeaking];
|
[self startSpeaking];
|
||||||
|
speakButton.image = [NSImage imageNamed:@"pause.png"];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -130,6 +147,9 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
[synth stopSpeaking];
|
[synth stopSpeaking];
|
||||||
|
|
||||||
|
[self setVoiceForLanguage:[self findLanguageFromString:text]];
|
||||||
|
|
||||||
[synth startSpeakingString:text];
|
[synth startSpeakingString:text];
|
||||||
|
|
||||||
oldRange = range;
|
oldRange = range;
|
||||||
|
@ -170,5 +190,39 @@
|
||||||
[textView setEditable:YES];
|
[textView setEditable:YES];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (NSString *)findLanguageFromString:(NSString *)text
|
||||||
|
{
|
||||||
|
NSArray *tagschemes = [NSArray arrayWithObjects:NSLinguisticTagSchemeLanguage, nil];
|
||||||
|
NSLinguisticTagger *tagger = [[NSLinguisticTagger alloc] initWithTagSchemes:tagschemes options:0];
|
||||||
|
[tagger setString:text];
|
||||||
|
NSString *language = [tagger tagAtIndex:0 scheme:NSLinguisticTagSchemeLanguage tokenRange:NULL sentenceRange:NULL];
|
||||||
|
|
||||||
|
return language;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setVoiceForLanguage:(NSString *)language
|
||||||
|
{
|
||||||
|
NSMenuItem *item;
|
||||||
|
NSMenuItem *languageItem;
|
||||||
|
for (NSInteger i = 0; i < [languages count]; i++)
|
||||||
|
{
|
||||||
|
if ([[languages objectAtIndex:i] isEqualToString:language]) {
|
||||||
|
languageItem = [[self.languageMenu itemArray] objectAtIndex:i];
|
||||||
|
for (item in [languageItem.submenu itemArray]) {
|
||||||
|
if (item.state == NSOnState) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
item = [[languageItem.submenu itemArray] objectAtIndex:0];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (languageItem && item) {
|
||||||
|
NSString *voice = [[NSSpeechSynthesizer attributesForVoice:[[NSSpeechSynthesizer availableVoices] objectAtIndex:item.tag]] objectForKey:@"VoiceIdentifier"];
|
||||||
|
[synth setVoice:voice];
|
||||||
|
[self.languageMenuPopupButton selectItem:languageItem];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
BIN
pause.png
Normal file
BIN
pause.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 250 B |
BIN
play.png
Normal file
BIN
play.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 377 B |
Loading…
Add table
Add a link
Reference in a new issue