我正在制作一个仅使用自定义图形和旁白的交互式 child 故事。
我有英语和西类牙语的所有图形。
我在任何地方都没有任何非自定义按钮,没有文本字段,也没有单个“标准”Apple 应用程序 UI 元素。一切都是自定义 PNG 文件。
我只是在寻找一种允许用户从英语切换为西类牙语或反之亦然的方法。
我已经创建了一个自定义的英语和西类牙语按钮,按下时会突出显示。
该应用程序将(根据我的阅读需要重新启动),然后该应用程序将显示其西类牙语页面(以及嵌入 PNG 中的西类牙语文本)。西类牙旁白将随之而来。
用户可以随时选择点击英语语言按钮,并在需要时返回英语。
Tabtale 的“美人鱼公主”应用程序在这方面做得非常好,远远超出我的需要,但它是我所追求的一个很好的例子。您单击一个按钮,更改您的区域,应用程序重新启动,并且您选择的区域的所有自定义文本和旁白结果。
我只有两个地区(语言),所以我的需求要简单得多。
但是究竟如何才能真正做到这一点呢?
干杯!
最佳答案
好吧,这比我想象的要难得多......
基本上,我通过使用 NSBundle 上的一个类别和一种名为 isa-swizzeling 的技术来交换将由 NSLocalizedString(…) 调用的 NSBundle 方法
NSBundle+Language.h
#import <Foundation/Foundation.h>
@interface NSBundle (Language)
+(void)setLanguage:(NSString*)language;
@end
NSBundle+Language.m
#import "NSBundle+Language.h"
#import <objc/runtime.h>
static const char associatedLanguageBundle=0;
@interface PrivateBundle : NSBundle
@end
@implementation PrivateBundle
-(NSString*)localizedStringForKey:(NSString *)key
value:(NSString *)value
table:(NSString *)tableName
{
NSBundle* bundle=objc_getAssociatedObject(self, &associatedLanguageBundle);
return bundle ? [bundle localizedStringForKey:key
value:value
table:tableName] : [super localizedStringForKey:key
value:value
table:tableName];
}
@end
@implementation NSBundle (Language)
+(void)setLanguage:(NSString*)language
{
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
object_setClass([NSBundle mainBundle],[PrivateBundle class]);
});
objc_setAssociatedObject([NSBundle mainBundle], &associatedLanguageBundle, language ?
[NSBundle bundleWithPath:[[NSBundle mainBundle] pathForResource:language ofType:@"lproj"]] : nil, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
@end
AppDelegate 将监听 LANGUAGE_WILL_CHANGE 通知,设置语言并广播通知 LANGUAGE_DID_CHANGE
AppDelegate.m
#import "AppDelegate.h"
#import "NSBundle+Language.h"
@interface AppDelegate ()
@end
@implementation AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(languageWillChange:) name:@"LANGUAGE_WILL_CHANGE" object:nil];
NSString *targetLang = [[NSUserDefaults standardUserDefaults] objectForKey:@"selectedLanguage"];
[NSBundle setLanguage:targetLang?:@"en"];
return YES;
}
-(void)languageWillChange:(NSNotification *) noti
{
NSString *targetLang = [noti object];
[[NSUserDefaults standardUserDefaults] setObject:targetLang forKey:@"selectedLanguage"];
[NSBundle setLanguage:targetLang];
[[NSNotificationCenter defaultCenter] postNotificationName:@"LANGUAGE_DID_CHANGE" object:targetLang];
}
@end
BaseViewController 将发送 LANGUAGE_WILL_CHANGE 并监听 LANGUAGE_DID_CHANGE
BaseViewController.h
#import <UIKit/UIKit.h>
@interface BaseViewController : UIViewController
-(void) languageDidChange;
- (IBAction)switchLanguage:(id)sender;
@end
BaseViewController.m
#import "BaseViewController.h"
@interface BaseViewController ()
@property (weak, nonatomic) IBOutlet UIButton *englishButton;
@property (weak, nonatomic) IBOutlet UIButton *spanishButton;
@end
@implementation BaseViewController
- (void)viewDidLoad {
[super viewDidLoad];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(languageDidChangeNotification:) name:@"LANGUAGE_DID_CHANGE" object:nil];
}
- (IBAction)switchLanguage:(id)sender {
NSString *localString;
if (self.englishButton == sender) {
localString = @"en";
} else if(self.spanishButton == sender){
localString = @"es";
}
if (localString) {
[[NSNotificationCenter defaultCenter] postNotificationName:@"LANGUAGE_WILL_CHANGE" object:localString];
}
}
-(void)languageDidChangeNotification:(NSNotification *)notification
{
[self languageDidChange];
}
-(void)languageDidChange
{
}
@end
现在任何子类 BaseViewController 的 View Controller 都可以实现 languageDidChange 来调用 NSLocalizedString。
ViewController.m
#import "ViewController.h"
@interface ViewController ()
@property (weak, nonatomic) IBOutlet UILabel *label;
@property (weak, nonatomic) IBOutlet UIImageView *imageView;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
[self languageDidChange];
}
-(void)languageDidChange
{
self.label.text = NSLocalizedString(@"Hello World", nil);
self.imageView.image = [UIImage imageNamed:NSLocalizedString(@"image.png", nil)];
}
@end
你看,我只是简单地本地化图像名称,我将图像 en_image.png 和 es_image.png 添加到图像 Assets 包中,并将它们映射到可本地化的字符串
"image.png" = "en_image.png";
和
"image.png" = "es_image.png";
结果
您可以在此处找到此示例代码:https://github.com/vikingosegundo/ImmidiateLanguageChange
关于iOS - 通过按钮更改用户的语言,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29872222/
如何正确创建Rails迁移,以便将表更改为MySQL中的MyISAM?目前是InnoDB。运行原始执行语句会更改表,但它不会更新db/schema.rb,因此当在测试环境中重新创建表时,它会返回到InnoDB并且我的全文搜索失败。我如何着手更改/添加迁移,以便将现有表修改为MyISAM并更新schema.rb,以便我的数据库和相应的测试数据库得到相应更新? 最佳答案 我没有找到执行此操作的好方法。您可以像有人建议的那样更改您的schema.rb,然后运行:rakedb:schema:load,但是,这将覆盖您的数据。我的做法是(假设
我正在寻找执行以下操作的正确语法(在Perl、Shell或Ruby中):#variabletoaccessthedatalinesappendedasafileEND_OF_SCRIPT_MARKERrawdatastartshereanditcontinues. 最佳答案 Perl用__DATA__做这个:#!/usr/bin/perlusestrict;usewarnings;while(){print;}__DATA__Texttoprintgoeshere 关于ruby-如何将脚
尝试通过RVM将RubyGems升级到版本1.8.10并出现此错误:$rvmrubygemslatestRemovingoldRubygemsfiles...Installingrubygems-1.8.10forruby-1.9.2-p180...ERROR:Errorrunning'GEM_PATH="/Users/foo/.rvm/gems/ruby-1.9.2-p180:/Users/foo/.rvm/gems/ruby-1.9.2-p180@global:/Users/foo/.rvm/gems/ruby-1.9.2-p180:/Users/foo/.rvm/gems/rub
我正在使用puppet为ruby程序提供一组常量。我需要提供一组主机名,我的程序将对其进行迭代。在我之前使用的bash脚本中,我只是将它作为一个puppet变量hosts=>"host1,host2"我将其提供给bash脚本作为HOSTS=显然这对ruby不太适用——我需要它的格式hosts=["host1","host2"]自从phosts和putsmy_array.inspect提供输出["host1","host2"]我希望使用其中之一。不幸的是,我终其一生都无法弄清楚如何让它发挥作用。我尝试了以下各项:我发现某处他们指出我需要在函数调用前放置“function_”……这
我正在编写一个gem,我必须在其中fork两个启动两个webrick服务器的进程。我想通过基类的类方法启动这个服务器,因为应该只有这两个服务器在运行,而不是多个。在运行时,我想调用这两个服务器上的一些方法来更改变量。我的问题是,我无法通过基类的类方法访问fork的实例变量。此外,我不能在我的基类中使用线程,因为在幕后我正在使用另一个不是线程安全的库。所以我必须将每个服务器派生到它自己的进程。我用类变量试过了,比如@@server。但是当我试图通过基类访问这个变量时,它是nil。我读到在Ruby中不可能在分支之间共享类变量,对吗?那么,还有其他解决办法吗?我考虑过使用单例,但我不确定这是
我的最终目标是安装当前版本的RubyonRails。我在OSXMountainLion上运行。到目前为止,这是我的过程:已安装的RVM$\curl-Lhttps://get.rvm.io|bash-sstable检查已知(我假设已批准)安装$rvmlistknown我看到当前的稳定版本可用[ruby-]2.0.0[-p247]输入命令安装$rvminstall2.0.0-p247注意:我也试过这些安装命令$rvminstallruby-2.0.0-p247$rvminstallruby=2.0.0-p247我很快就无处可去了。结果:$rvminstall2.0.0-p247Search
我在我的Rails项目中使用Pow和powifygem。现在我尝试升级我的ruby版本(从1.9.3到2.0.0,我使用RVM)当我切换ruby版本、安装所有gem依赖项时,我通过运行railss并访问localhost:3000确保该应用程序正常运行以前,我通过使用pow访问http://my_app.dev来浏览我的应用程序。升级后,由于错误Bundler::RubyVersionMismatch:YourRubyversionis1.9.3,butyourGemfilespecified2.0.0,此url不起作用我尝试过的:重新创建pow应用程序重启pow服务器更新战俘
我将应用程序升级到Rails4,一切正常。我可以登录并转到我的编辑页面。也更新了观点。使用标准View时,用户会更新。但是当我添加例如字段:name时,它不会在表单中更新。使用devise3.1.1和gem'protected_attributes'我需要在设备或数据库上运行某种更新命令吗?我也搜索过这个地方,找到了许多不同的解决方案,但没有一个会更新我的用户字段。我没有添加任何自定义字段。 最佳答案 如果您想允许额外的参数,您可以在ApplicationController中使用beforefilter,因为Rails4将参数
我尝试使用不同的ssh_options在同一阶段运行capistranov.3任务。我的production.rb说:set:stage,:productionset:user,'deploy'set:ssh_options,{user:'deploy'}通过此配置,capistrano与用户deploy连接,这对于其余的任务是正确的。但是我需要将它连接到服务器中配置良好的an_other_user以完成一项特定任务。然后我的食谱说:...taskswithoriginaluser...task:my_task_with_an_other_userdoset:user,'an_othe
我在理解Enumerator.new方法的工作原理时遇到了一些困难。假设文档中的示例:fib=Enumerator.newdo|y|a=b=1loopdoy[1,1,2,3,5,8,13,21,34,55]循环中断条件在哪里,它如何知道循环应该迭代多少次(因为它没有任何明确的中断条件并且看起来像无限循环)? 最佳答案 Enumerator使用Fibers在内部。您的示例等效于:require'fiber'fiber=Fiber.newdoa=b=1loopdoFiber.yieldaa,b=b,a+bendend10.times.m