Skip to content
Permalink
Browse files
Add localized accessibility strings to React Core pod (#27995)
Summary:
The accessibility roles and states description strings are not able to be localized on iOS platform. Those strings are exposed to the end users so it should be localized. This PR is to add localized strings as a resource bundle to the React Core Pod so that any React Native app integrating the React Native dependencies using CocoaPods can get the localized accessibility roles and states description.

## Changelog

[iOS] [Added] - Add localized accessibility strings to React Core pod
Pull Request resolved: #27995

Test Plan: Verified with RNTester app.

Differential Revision: D19975587

Pulled By: PeteTheHeat

fbshipit-source-id: f8eb4e25194f0cd603c98a6221ec87503a2826ed
  • Loading branch information
xuelgong authored and facebook-github-bot committed Feb 20, 2020
1 parent 24e0bad commit aebf54aee41cc892198b055a7a546743297412bd
Show file tree
Hide file tree
Showing 3 changed files with 77 additions and 39 deletions.
@@ -44,6 +44,7 @@ Pod::Spec.new do |s|
s.author = "Facebook, Inc. and its affiliates"
s.platforms = { :ios => "10.0", :tvos => "10.0" }
s.source = source
s.resource_bundle = { "AccessibilityResources" => ["React/AccessibilityResources/*.lproj"]}
s.compiler_flags = folly_compiler_flags + ' ' + boost_compiler_flags
s.header_dir = "React"
s.framework = "JavaScriptCore"
@@ -0,0 +1,26 @@
/*
Localizable.strings
React
*/
"alert"="alert";
"checkbox"="checkbox";
"combobox"="combo box";
"menu"="menu";
"menubar"="menu bar";
"menuitem"="menu item";
"progressbar"="progress bar";
"radio"="radio button";
"radiogroup"="radio group";
"scrollbar"="scroll bar";
"spinbutton"="spin button";
"switch"="switch";
"tab"="tab description";
"tablist"="tab list";
"timer"="timer";
"toolbar"="tool bar";
"checked"="checked";
"unchecked"="not checked";
"busy"="busy";
"expanded"="expanded";
"collapsed"="collapsed";
"mixed"="mixed";
@@ -202,6 +202,51 @@ - (BOOL)didActivateAccessibilityCustomAction:(UIAccessibilityCustomAction *)acti

- (NSString *)accessibilityValue
{
static dispatch_once_t onceToken;
static NSDictionary<NSString *, NSString *> *rolesAndStatesDescription = nil;

dispatch_once(&onceToken, ^{
NSString *bundlePath = [[NSBundle mainBundle]pathForResource:@"AccessibilityResources" ofType:@"bundle"];
NSBundle *bundle = [NSBundle bundleWithPath:bundlePath];

if (bundle) {
NSURL *url = [bundle URLForResource:@"Localizable" withExtension:@"strings"];
if (@available(iOS 11.0, *)) {
rolesAndStatesDescription = [NSDictionary dictionaryWithContentsOfURL:url error:nil];
} else {
// Fallback on earlier versions
rolesAndStatesDescription = [NSDictionary dictionaryWithContentsOfURL:url];
}
}
if (rolesAndStatesDescription == nil) {
NSLog(@"Cannot load localized accessibility strings.");
rolesAndStatesDescription = @{
@"alert" : @"alert",
@"checkbox" : @"checkbox",
@"combobox" : @"combo box",
@"menu" : @"menu",
@"menubar" : @"menu bar",
@"menuitem" : @"menu item",
@"progressbar" : @"progress bar",
@"radio" : @"radio button",
@"radiogroup" : @"radio group",
@"scrollbar" : @"scroll bar",
@"spinbutton" : @"spin button",
@"switch" : @"switch",
@"tab" : @"tab",
@"tablist" : @"tab list",
@"timer" : @"timer",
@"toolbar" : @"tool bar",
@"checked" : @"checked",
@"unchecked" : @"not checked",
@"busy" : @"busy",
@"expanded" : @"expanded",
@"collapsed" : @"collapsed",
@"mixed": @"mixed",
};
}
});

if ((self.accessibilityTraits & SwitchAccessibilityTrait) == SwitchAccessibilityTrait) {
for (NSString *state in self.accessibilityState) {
id val = self.accessibilityState[state];
@@ -214,41 +259,7 @@ - (NSString *)accessibilityValue
}
}
NSMutableArray *valueComponents = [NSMutableArray new];
static NSDictionary<NSString *, NSString *> *roleDescriptions = nil;
static dispatch_once_t onceToken1;
dispatch_once(&onceToken1, ^{
roleDescriptions = @{
@"alert" : @"alert",
@"checkbox" : @"checkbox",
@"combobox" : @"combo box",
@"menu" : @"menu",
@"menubar" : @"menu bar",
@"menuitem" : @"menu item",
@"progressbar" : @"progress bar",
@"radio" : @"radio button",
@"radiogroup" : @"radio group",
@"scrollbar" : @"scroll bar",
@"spinbutton" : @"spin button",
@"switch" : @"switch",
@"tab" : @"tab",
@"tablist" : @"tab list",
@"timer" : @"timer",
@"toolbar" : @"tool bar",
};
});
static NSDictionary<NSString *, NSString *> *stateDescriptions = nil;
static dispatch_once_t onceToken2;
dispatch_once(&onceToken2, ^{
stateDescriptions = @{
@"checked" : @"checked",
@"unchecked" : @"not checked",
@"busy" : @"busy",
@"expanded" : @"expanded",
@"collapsed" : @"collapsed",
@"mixed": @"mixed",
};
});
NSString *roleDescription = self.accessibilityRole ? roleDescriptions[self.accessibilityRole]: nil;
NSString *roleDescription = self.accessibilityRole ? rolesAndStatesDescription[self.accessibilityRole]: nil;
if (roleDescription) {
[valueComponents addObject:roleDescription];
}
@@ -259,16 +270,16 @@ - (NSString *)accessibilityValue
}
if ([state isEqualToString:@"checked"]) {
if ([val isKindOfClass:[NSNumber class]]) {
[valueComponents addObject:stateDescriptions[[val boolValue] ? @"checked" : @"unchecked"]];
[valueComponents addObject:rolesAndStatesDescription[[val boolValue] ? @"checked" : @"unchecked"]];
} else if ([val isKindOfClass:[NSString class]] && [val isEqualToString:@"mixed"]) {
[valueComponents addObject:stateDescriptions[@"mixed"]];
[valueComponents addObject:rolesAndStatesDescription[@"mixed"]];
}
}
if ([state isEqualToString:@"expanded"] && [val isKindOfClass:[NSNumber class]]) {
[valueComponents addObject:stateDescriptions[[val boolValue] ? @"expanded" : @"collapsed"]];
[valueComponents addObject:rolesAndStatesDescription[[val boolValue] ? @"expanded" : @"collapsed"]];
}
if ([state isEqualToString:@"busy"] && [val isKindOfClass:[NSNumber class]] && [val boolValue]) {
[valueComponents addObject:stateDescriptions[@"busy"]];
[valueComponents addObject:rolesAndStatesDescription[@"busy"]];
}
}

0 comments on commit aebf54a

Please sign in to comment.