├── android
├── src
│ └── main
│ │ ├── AndroidManifest.xml
│ │ └── java
│ │ └── io
│ │ └── fixd
│ │ └── rctlocale
│ │ ├── RCTLocalePackage.java
│ │ └── RCTLocaleModule.java
└── build.gradle
├── ios
├── RCTLocale.xcodeproj
│ ├── project.xcworkspace
│ │ └── contents.xcworkspacedata
│ └── project.pbxproj
└── RCTLocale
│ ├── RCTLocale.h
│ └── RCTLocale.m
├── package.json
├── index.android.js
├── index.ios.js
├── react-native-locale.podspec
├── LocaleBaseClass.js
├── .gitignore
└── README.md
/android/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/ios/RCTLocale.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "react-native-locale",
3 | "version": "0.0.19",
4 | "description": "Simple locale information and methods for react native",
5 | "repository": {
6 | "type": "git",
7 | "url": "https://github.com/fixdio/react-native-locale.git"
8 | },
9 | "author": "Fixd",
10 | "license": "MIT"
11 | }
12 |
--------------------------------------------------------------------------------
/ios/RCTLocale/RCTLocale.h:
--------------------------------------------------------------------------------
1 | //
2 | // RCTLocale.h
3 | // RCTLocale
4 | //
5 |
6 | #import
7 | #import "React/RCTBridgeModule.h"
8 | #import "React/RCTLog.h"
9 | #import "React/RCTConvert.h"
10 |
11 | @interface RCTConvert (NSDateFormatterStyle)
12 | + (NSDateFormatterStyle)NSDateFormatterStyle:(id)json;
13 | @end
14 |
15 | @interface RCTLocale : NSObject
16 | @end
17 |
--------------------------------------------------------------------------------
/index.android.js:
--------------------------------------------------------------------------------
1 | const LocaleBaseClass = require('./LocaleBaseClass');
2 |
3 | class Locale extends LocaleBaseClass {
4 |
5 | /**
6 | * Android can't pass Long's as ReactMethod arguments so send a string that is parsed
7 | */
8 | static dateFormat(date : Date, dateStyle : string, timeStyle : string) {
9 | return LocaleBaseClass.dateFormat(''+date.getTime(), dateStyle, timeStyle);
10 | }
11 |
12 | }
13 |
14 | module.exports = Locale;
15 |
--------------------------------------------------------------------------------
/index.ios.js:
--------------------------------------------------------------------------------
1 | import {NativeModules} from 'react-native';
2 | const NativeLocale = NativeModules.Locale;
3 | const LocaleBaseClass = require('./LocaleBaseClass');
4 |
5 | class Locale extends LocaleBaseClass {
6 | static currencyStyle(number : number) {
7 | return NativeLocale.currencyStyle(number);
8 | }
9 | static percentStyle(number : number) {
10 | return NativeLocale.percentStyle(number);
11 | }
12 | static scientificStyle(number : number) {
13 | return NativeLocale.scientificStyle(number);
14 | }
15 | static spelloutStyle(number : number) {
16 | return NativeLocale.scientificStyle(number);
17 | }
18 | }
19 |
20 | module.exports = Locale;
21 |
--------------------------------------------------------------------------------
/react-native-locale.podspec:
--------------------------------------------------------------------------------
1 | require 'json'
2 |
3 | package = JSON.parse(File.read(File.join(__dir__, 'package.json')))
4 |
5 | Pod::Spec.new do |s|
6 | s.name = package['name']
7 | s.version = package['version']
8 | s.summary = package['description']
9 | s.description = package['description']
10 | s.license = package['license']
11 | s.author = package['author']
12 | s.homepage = package['repository']['url']
13 | s.source = { :git => 'https://github.com/fixdio/react-native-locale.git', :tag => s.version }
14 |
15 | s.requires_arc = true
16 | s.platform = :ios, '7.0'
17 |
18 | s.preserve_paths = 'README.md', 'package.json', 'index.ios.js'
19 | s.source_files = 'ios/RCTLocale/*.{h,m}'
20 |
21 | s.dependency 'React'
22 | end
23 |
--------------------------------------------------------------------------------
/android/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.library'
2 |
3 | def safeExtGet(prop, fallback) {
4 | rootProject.ext.has(prop) ? rootProject.ext.get(prop) : fallback
5 | }
6 |
7 | android {
8 | compileSdkVersion safeExtGet('compileSdkVersion', 23)
9 | buildToolsVersion safeExtGet('buildToolsVersion', "23.0.1")
10 |
11 | defaultConfig {
12 | minSdkVersion safeExtGet('minSdkVersion', 16)
13 | targetSdkVersion safeExtGet('targetSdkVersion', 22)
14 | versionCode 1
15 | versionName "1.0"
16 | }
17 | lintOptions {
18 | abortOnError false
19 | }
20 | }
21 |
22 | repositories {
23 | mavenCentral()
24 | }
25 |
26 | dependencies {
27 | implementation 'com.facebook.react:react-native:0.17.+'
28 | }
--------------------------------------------------------------------------------
/LocaleBaseClass.js:
--------------------------------------------------------------------------------
1 | import { Platform, NativeModules } from 'react-native';
2 | const NativeLocale = NativeModules.Locale;
3 | const warning = require('fbjs/lib/warning');
4 |
5 | class LocaleBaseClass {
6 |
7 | static constants() {
8 | return NativeLocale;
9 | }
10 |
11 | static numberFromDecimalString(number : string) {
12 | return NativeLocale.numberFromDecimalString(number);
13 | }
14 |
15 | static decimalStyle(number : number) {
16 | return NativeLocale.decimalStyle(number);
17 | }
18 |
19 | static validateDateFormatStyle(style : string) {
20 | let valid = ['full', 'long', 'medium', 'short', 'none'];
21 | if(Platform.OS == 'ios')
22 | valid.push('default');
23 | return valid.indexOf(style) >= 0;
24 | }
25 |
26 | static dateFormat(date, dateStyle : string, timeStyle : string) {
27 | warning(LocaleBaseClass.validateDateFormatStyle(dateStyle), 'Locale: DateStyle must be one of [full/long/medium/short/none]');
28 | warning(LocaleBaseClass.validateDateFormatStyle(timeStyle), 'Locale: TimeStyle must be one of [full/long/medium/short/none]');
29 | return NativeLocale.dateFormat(date, dateStyle, timeStyle);
30 | }
31 |
32 | }
33 |
34 | module.exports = LocaleBaseClass;
35 |
--------------------------------------------------------------------------------
/android/src/main/java/io/fixd/rctlocale/RCTLocalePackage.java:
--------------------------------------------------------------------------------
1 | package io.fixd.rctlocale;
2 |
3 | import android.app.Activity;
4 |
5 | import com.facebook.react.ReactPackage;
6 | import com.facebook.react.bridge.JavaScriptModule;
7 | import com.facebook.react.bridge.NativeModule;
8 | import com.facebook.react.bridge.ReactApplicationContext;
9 | import com.facebook.react.uimanager.ViewManager;
10 |
11 | import java.util.Arrays;
12 | import java.util.Collections;
13 | import java.util.List;
14 | import java.util.ArrayList;
15 |
16 | public class RCTLocalePackage implements ReactPackage {
17 |
18 | private Activity mActivity = null;
19 |
20 | @Override
21 | public List createNativeModules(ReactApplicationContext reactContext) {
22 | List modules = new ArrayList<>();
23 | modules.add(new RCTLocaleModule(reactContext));
24 | return modules;
25 | }
26 |
27 | // Deprecated in React Native 0.47
28 | public List> createJSModules() {
29 | return Collections.emptyList();
30 | }
31 |
32 | @Override
33 | public List createViewManagers(ReactApplicationContext reactContext) {
34 | return Collections.emptyList();
35 | }
36 | }
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 |
2 | # Created by https://www.gitignore.io/api/xcode,node
3 |
4 | ### Xcode ###
5 | # Xcode
6 | #
7 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore
8 |
9 | ## Build generated
10 | build/
11 | DerivedData
12 |
13 | ## Various settings
14 | *.pbxuser
15 | !default.pbxuser
16 | *.mode1v3
17 | !default.mode1v3
18 | *.mode2v3
19 | !default.mode2v3
20 | *.perspectivev3
21 | !default.perspectivev3
22 | xcuserdata
23 |
24 | ## Other
25 | *.xccheckout
26 | *.moved-aside
27 | *.xcuserstate
28 |
29 |
30 | ### Node ###
31 | # Logs
32 | logs
33 | *.log
34 | npm-debug.log*
35 |
36 | # Runtime data
37 | pids
38 | *.pid
39 | *.seed
40 |
41 | # Directory for instrumented libs generated by jscoverage/JSCover
42 | lib-cov
43 |
44 | # Coverage directory used by tools like istanbul
45 | coverage
46 |
47 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
48 | .grunt
49 |
50 | # node-waf configuration
51 | .lock-wscript
52 |
53 | # Compiled binary addons (http://nodejs.org/api/addons.html)
54 | build/Release
55 |
56 | # Dependency directory
57 | # https://docs.npmjs.com/misc/faq#should-i-check-my-node-modules-folder-into-git
58 | node_modules
59 |
60 | # Optional npm cache directory
61 | .npm
62 |
63 | # Optional REPL history
64 | .node_repl_history
65 | .DS_Store
66 | /.idea
67 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # react-native-locale
2 |
3 | Formats data based on locale settings.
4 |
5 | https://developer.apple.com/library/ios/documentation/MacOSX/Conceptual/BPInternational/InternationalizingLocaleData/InternationalizingLocaleData.html
6 |
7 | ### RN < 0.47.0
8 |
9 | Please use `0.0.17` for any version of RN before `0.47.0`
10 |
11 | `npm install react-native-locale@0.0.17 --save`
12 |
13 | ### RN < 0.40.0
14 |
15 | Please use `0.0.13` for any version of RN before `0.40.0`
16 |
17 | `npm install react-native-locale@0.0.13 --save`
18 |
19 | ## Installation
20 |
21 | - `npm install react-native-locale --save`
22 | - `react-native link react-native-locale`
23 |
24 | ### Add libraries manually
25 |
26 | #### iOS
27 |
28 | - Link manually
29 | - Add RCTLocale.xcodeproj to Libraries and add libRCTLocale.a to Link Binary With Libraries under Build Phases.
30 | - Cocoapods
31 | - Add following to your `Podfile`
32 |
33 | ```ruby
34 | # Podfile
35 | pod 'react-native-locale', :path => './node_modules/react-native-locale'
36 | ```
37 |
38 | #### Android
39 |
40 | ```
41 | // file: android/settings.gradle
42 | ...
43 |
44 | include ':react-native-locale'
45 | project(':react-native-locale').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-locale/android')
46 | ```
47 |
48 | ```
49 | // file: android/app/build.gradle
50 | ...
51 |
52 | dependencies {
53 | ...
54 | compile project(':react-native-locale') // <- Add this
55 | }
56 | ```
57 |
58 | ```
59 | // file: android/app/source/main/java/com/{projectName}.MainApplication.java
60 | ...
61 | import io.fixd.rctlocale.RCTLocalePackage;
62 | ...
63 | public class MainApplication extends Application implements ReactApplication {
64 | // ...
65 | @Override
66 | protected List getPackages() {
67 | return Arrays.asList(
68 | new MainReactPackage(),
69 | new RCTLocalePackage() // add package
70 | );
71 | }
72 | ...
73 | ```
74 |
75 | ## Usage
76 |
77 | For locale information:
78 |
79 | `var Locale = require('react-native-locale');`
80 |
81 | ### Constants
82 |
83 | `Locale.constants()` Returns an object of (Danish locale):
84 |
85 | ```js
86 | {
87 | "localeIdentifier":"en_DK",
88 | "decimalSeparator":",",
89 | "quotationBeginDelimiterKey":"“",
90 | "quotationEndDelimiterKey":"”",
91 | "currencySymbol":"DKK",
92 | "currencyCode":"DKK",
93 | "groupingSeparator":".",
94 | // ios only:
95 | "usesMetricSystem":true,
96 | "localeLanguageCode":"en",
97 | "countryCode":"DK",
98 | "calendar":"gregorian",
99 | "collatorIdentifier":"en-DK",
100 | "alternateQuotationBeginDelimiterKey":"‘",
101 | "alternateQuotationEndDelimiterKey":"’",
102 | "measurementSystem":"Metric",
103 | "preferredLanguages":["en-DK"]
104 | }
105 | ```
106 |
107 | USA Locale:
108 |
109 | ```js
110 | {
111 | "localeIdentifier":"en_US",
112 | "decimalSeparator":".",
113 | "quotationBeginDelimiterKey":"“",
114 | "quotationEndDelimiterKey":"”",
115 | "currencySymbol":"$",
116 | "currencyCode":"USD",
117 | // ios only:
118 | "usesMetricSystem":false,
119 | "localeLanguageCode":"en",
120 | "countryCode":"US",
121 | "calendar":"gregorian",
122 | "groupingSeparator":",",
123 | "collatorIdentifier":"en-US",
124 | "alternateQuotationBeginDelimiterKey":"‘",
125 | "alternateQuotationEndDelimiterKey":"’",
126 | "measurementSystem":"U.S.",
127 | "preferredLanguages":["en-US"]
128 |
129 | ```
130 |
131 | ### Numerical formatting
132 |
133 |
134 | ```js
135 | Locale.decimalStyle(12501.50).then((response) => {
136 | console.log(response);
137 | });
138 | Locale.numberFromDecimalString('125.01,10').then((response) => {
139 | console.log('then', response);
140 | });
141 |
142 | // ios only
143 | Locale.currencyStyle(12501.50).then((response) => {
144 | console.log(response);
145 | });
146 | Locale.percentStyle(125.50).then((response) => {
147 | console.log(response);
148 | });
149 | Locale.scientificStyle(12501.50).then((response) => {
150 | console.log(response);
151 | });
152 | Locale.spelloutStyle(12501.50).then((response) => {
153 | console.log(response);
154 | });
155 | ```
156 |
157 | In Danish locale this returns:
158 |
159 | ```
160 | 12.501,5
161 | 12.501,50 DKK
162 | 12.550 %
163 | 1,25015E4
164 | twelve thousand five hundred one point five
165 | 125010.1
166 | ```
167 |
168 | ### Date formatting
169 |
170 | Note: iOS will allow `timestamp` to be either a timestamp, or an ISO-8601 string, the Android java however, won't. The module will try to handle this for you.
171 |
172 | ```js
173 | l.dateFormat(DateObject, DateFormatStyle, TimeFormatStyle)
174 | l.dateFormat(Date, enum('full', 'long', 'medium', 'short', 'none'), enum('full', 'long', 'medium', 'short', 'none'))
175 | ``
176 |
177 | Danish:
178 | ```js
179 | let date = new Date(2016, 4, 26, 16, 38, 22);
180 | l.dateFormat(date.getTime(), 'full', 'full').then((date) => { // Thursday 26 May 2016 at 16 h 38 min 22 s Central European Summer Time
181 | console.log(date);
182 | });
183 |
184 | l.dateFormat(date.getTime(), 'long', 'long').then((date) => { // 26 May 2016 at 16:38:22 GMT+2
185 | console.log(date);
186 | });
187 |
188 | l.dateFormat(date.getTime(), 'medium', 'medium').then((date) => { //26 May 2016 16:38:22
189 | console.log(date);
190 | });
191 |
192 | l.dateFormat(date.getTime(), 'short', 'short').then((date) => { // 26/05/16 16:38
193 | console.log(date);
194 | });
195 |
196 | l.dateFormat(date.getTime(), 'short', 'none').then((date) => { // 26/05/16
197 | console.log(date);
198 | });
199 | ```
200 |
201 | USA:
202 | ```
203 | Thursday, May 26, 2016 at 4:38:22 PM Central European Summer Time
204 | May 26, 2016 at 4:38:22 PM GMT+2
205 | May 26, 2016, 4:38:22 PM
206 | 5/26/16, 4:38 PM
207 | 5/26/16
208 | ```
209 |
210 | Android in 24hr Denmark with timezone set to EDT:
211 |
212 | ```
213 | Thursday, May 26, 2016 3:38:22 PM Eastern Daylight Time
214 | May 26, 2016 3:38:22 PM EDT
215 | May 26, 2016 15:38:22
216 | 5/26/16 15:38
217 | 5/26/16
218 | ```
219 |
--------------------------------------------------------------------------------
/ios/RCTLocale/RCTLocale.m:
--------------------------------------------------------------------------------
1 | //
2 | // RCTLocale.m
3 | // RCTLocale
4 | //
5 |
6 | #import "RCTLocale.h"
7 | #import "React/RCTUtils.h"
8 |
9 | @implementation RCTConvert (NSDateFormatterStyle)
10 | RCT_ENUM_CONVERTER(NSDateFormatterStyle, (@{
11 | @"none": @(NSDateFormatterNoStyle),
12 | @"full": @(NSDateFormatterFullStyle),
13 | @"long": @(NSDateFormatterLongStyle),
14 | @"medium": @(NSDateFormatterMediumStyle),
15 | @"short": @(NSDateFormatterShortStyle),
16 | }), NSDateFormatterFullStyle, integerValue);
17 | @end
18 |
19 | @interface RCTLocale ()
20 | @end
21 |
22 | @implementation RCTLocale
23 | RCT_EXPORT_MODULE();
24 |
25 | + (BOOL)requiresMainQueueSetup
26 | {
27 | return YES;
28 | }
29 |
30 | RCT_EXPORT_METHOD(decimalStyle:(nonnull NSNumber *)myNumber
31 | resolver:(RCTPromiseResolveBlock)resolve
32 | rejecter:(RCTPromiseRejectBlock)reject){
33 | resolve([NSNumberFormatter localizedStringFromNumber:myNumber numberStyle:NSNumberFormatterDecimalStyle]);
34 | }
35 |
36 | RCT_EXPORT_METHOD(currencyStyle:(nonnull NSNumber *)myNumber
37 | resolver:(RCTPromiseResolveBlock)resolve
38 | rejecter:(RCTPromiseRejectBlock)reject){
39 | resolve([NSNumberFormatter localizedStringFromNumber:myNumber numberStyle:NSNumberFormatterCurrencyStyle]);
40 | }
41 |
42 | RCT_EXPORT_METHOD(percentStyle:(nonnull NSNumber *)myNumber
43 | resolver:(RCTPromiseResolveBlock)resolve
44 | rejecter:(RCTPromiseRejectBlock)reject){
45 | resolve([NSNumberFormatter localizedStringFromNumber:myNumber numberStyle:NSNumberFormatterPercentStyle]);
46 | }
47 |
48 | RCT_EXPORT_METHOD(scientificStyle:(nonnull NSNumber *)myNumber
49 | resolver:(RCTPromiseResolveBlock)resolve
50 | rejecter:(RCTPromiseRejectBlock)reject){
51 | resolve([NSNumberFormatter localizedStringFromNumber:myNumber numberStyle:NSNumberFormatterScientificStyle]);
52 | }
53 |
54 | RCT_EXPORT_METHOD(spelloutStyle:(nonnull NSNumber *)myNumber
55 | resolver:(RCTPromiseResolveBlock)resolve
56 | rejecter:(RCTPromiseRejectBlock)reject){
57 | resolve([NSNumberFormatter localizedStringFromNumber:myNumber numberStyle:NSNumberFormatterSpellOutStyle]);
58 | }
59 |
60 | RCT_EXPORT_METHOD(numberFromDecimalString:(nonnull NSString *)inputString
61 | resolver:(RCTPromiseResolveBlock)resolve
62 | rejecter:(RCTPromiseRejectBlock)reject){
63 | NSNumberFormatter *numberFormatter = [NSNumberFormatter new];
64 | numberFormatter.numberStyle = NSNumberFormatterDecimalStyle;
65 | numberFormatter.lenient = YES;
66 | NSNumber *number = [numberFormatter numberFromString:inputString];
67 | if(number) {
68 | resolve(number);
69 | } else {
70 | reject(nil, nil, nil);
71 | }
72 | }
73 |
74 | RCT_EXPORT_METHOD(dateFormat:(nonnull NSDate *)date
75 | dateStyle:(NSDateFormatterStyle)dateStyle
76 | timeStyle:(NSDateFormatterStyle)timeStyle
77 | resolver:(RCTPromiseResolveBlock)resolve
78 | rejecter:(RCTPromiseRejectBlock)reject){
79 |
80 | NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
81 | dateFormatter.dateStyle = dateStyle;
82 | dateFormatter.timeStyle = timeStyle;
83 |
84 | resolve([dateFormatter stringFromDate:date]);
85 | }
86 |
87 | static id ObjectOrNull(id object)
88 | {
89 | return object ?: [NSNull null];
90 | }
91 |
92 | - (NSDictionary *)constantsToExport
93 | {
94 |
95 | NSLocale *locale = [NSLocale currentLocale];
96 | NSCalendar *cal = [locale objectForKey:NSLocaleCalendar];
97 |
98 | NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
99 | dateFormatter.dateStyle = NSDateFormatterFullStyle;
100 | NSMutableDictionary *formats = [[NSMutableDictionary alloc]initWithCapacity:4];
101 | [formats setObject:dateFormatter.dateFormat forKey:@"full"];
102 | dateFormatter.dateStyle = NSDateFormatterLongStyle;
103 | [formats setObject:dateFormatter.dateFormat forKey:@"long"];
104 | dateFormatter.dateStyle = NSDateFormatterMediumStyle;
105 | [formats setObject:dateFormatter.dateFormat forKey:@"medium"];
106 | dateFormatter.dateStyle = NSDateFormatterShortStyle;
107 | [formats setObject:dateFormatter.dateFormat forKey:@"short"];
108 |
109 | return @{
110 | @"localeIdentifier": ObjectOrNull([locale objectForKey:NSLocaleIdentifier]),
111 | @"localeLanguageCode": ObjectOrNull([locale objectForKey:NSLocaleLanguageCode]),
112 | @"countryCode": ObjectOrNull([locale objectForKey:NSLocaleCountryCode]),
113 | @"calendar": ObjectOrNull(cal.calendarIdentifier),
114 | @"usesMetricSystem": ObjectOrNull([locale objectForKey:NSLocaleUsesMetricSystem]),
115 | @"measurementSystem": ObjectOrNull([locale objectForKey:NSLocaleMeasurementSystem]),
116 | @"decimalSeparator": ObjectOrNull([locale objectForKey:NSLocaleDecimalSeparator]),
117 | @"groupingSeparator": ObjectOrNull([locale objectForKey:NSLocaleGroupingSeparator]),
118 | @"currencySymbol": ObjectOrNull([locale objectForKey:NSLocaleCurrencySymbol]),
119 | @"currencyCode": ObjectOrNull([locale objectForKey:NSLocaleCurrencyCode]),
120 | @"collatorIdentifier": ObjectOrNull([locale objectForKey:NSLocaleCollatorIdentifier]),
121 | @"quotationBeginDelimiterKey": ObjectOrNull([locale objectForKey:NSLocaleQuotationBeginDelimiterKey]),
122 | @"quotationEndDelimiterKey": ObjectOrNull([locale objectForKey:NSLocaleQuotationEndDelimiterKey]),
123 | @"alternateQuotationBeginDelimiterKey": ObjectOrNull([locale objectForKey:NSLocaleAlternateQuotationBeginDelimiterKey]),
124 | @"alternateQuotationEndDelimiterKey": ObjectOrNull([locale objectForKey:NSLocaleAlternateQuotationEndDelimiterKey]),
125 | @"preferredLanguages": ObjectOrNull([NSLocale preferredLanguages]),
126 | @"localeDateFormats": ObjectOrNull(formats)
127 | };
128 | }
129 | @end
130 |
--------------------------------------------------------------------------------
/android/src/main/java/io/fixd/rctlocale/RCTLocaleModule.java:
--------------------------------------------------------------------------------
1 | package io.fixd.rctlocale;
2 |
3 | import com.facebook.react.bridge.NativeModule;
4 | import com.facebook.react.bridge.ReactApplicationContext;
5 | import com.facebook.react.bridge.ReactContext;
6 | import com.facebook.react.bridge.ReactContextBaseJavaModule;
7 | import com.facebook.react.bridge.ReactMethod;
8 | import com.facebook.react.bridge.Promise;
9 |
10 | import java.lang.String;
11 | import java.lang.IllegalArgumentException;
12 | import java.text.DateFormat;
13 | import java.util.Map;
14 | import java.util.HashMap;
15 | import java.util.Locale;
16 | import java.util.Date;
17 | import java.util.Currency;
18 | import java.text.DecimalFormatSymbols;
19 | import java.text.NumberFormat;
20 | import java.text.DecimalFormat;
21 | import java.lang.Long;
22 | import java.text.SimpleDateFormat;
23 |
24 | public class RCTLocaleModule extends ReactContextBaseJavaModule {
25 |
26 | private ReactApplicationContext mContext;
27 |
28 | public RCTLocaleModule(ReactApplicationContext reactContext) {
29 | super(reactContext);
30 | mContext = reactContext;
31 | }
32 |
33 | @Override
34 | public String getName() {
35 | return "RCTLocale";
36 | }
37 |
38 | @Override
39 | public Map getConstants() {
40 |
41 | Locale current = getLocale();
42 | DecimalFormatSymbols formatterSymbols = getDecimalFormat().getDecimalFormatSymbols();
43 | Currency currency = null;
44 | try {
45 | currency = Currency.getInstance(current);
46 | } catch (IllegalArgumentException e) {
47 | // Exception is ignorable because it means the locale doesn't have a currency
48 | // associated with it.
49 | }
50 |
51 | final Map constants = new HashMap<>();
52 | constants.put("localeIdentifier", current.toString());
53 | constants.put("countryCode", current.getCountry());
54 | constants.put("decimalSeparator", String.valueOf(formatterSymbols.getDecimalSeparator()));
55 | constants.put("groupingSeparator", String.valueOf(formatterSymbols.getGroupingSeparator()));
56 | constants.put("usesMetricSystem", !current.getISO3Country().equalsIgnoreCase("usa"));
57 | constants.put("currencySymbol", currency != null ? currency.getSymbol() : null);
58 | constants.put("currencyCode", currency!= null ? currency.getCurrencyCode() : null);
59 |
60 | final Map formats = new HashMap<>();
61 | DateFormat dateFormatter;
62 | dateFormatter = DateFormat.getDateInstance(DateFormat.FULL, getLocale());
63 | formats.put("full", ((SimpleDateFormat) dateFormatter).toLocalizedPattern());
64 | dateFormatter = DateFormat.getDateInstance(DateFormat.LONG, getLocale());
65 | formats.put("long", ((SimpleDateFormat) dateFormatter).toLocalizedPattern());
66 | dateFormatter = DateFormat.getDateInstance(DateFormat.MEDIUM, getLocale());
67 | formats.put("medium", ((SimpleDateFormat) dateFormatter).toLocalizedPattern());
68 | dateFormatter = DateFormat.getDateInstance(DateFormat.SHORT, getLocale());
69 | formats.put("short", ((SimpleDateFormat) dateFormatter).toLocalizedPattern());
70 | constants.put("localeDateFormats", formats);
71 |
72 | return constants;
73 | }
74 |
75 | @ReactMethod
76 | public void decimalStyle(Double number, Promise promise) {
77 | try {
78 | NumberFormat nf = NumberFormat.getNumberInstance(getLocale());
79 | nf.setGroupingUsed(true);
80 | promise.resolve(nf.format(number));
81 | } catch (Exception e) {
82 | promise.reject(e.getMessage());
83 | }
84 | }
85 |
86 | @ReactMethod
87 | public void numberFromDecimalString(String numberString, Promise promise) {
88 | try {
89 | NumberFormat nf = NumberFormat.getInstance(getLocale());
90 | promise.resolve(nf.parse(numberString).doubleValue());
91 | } catch (Exception e) {
92 | promise.reject(e.getMessage());
93 | }
94 | }
95 |
96 | @ReactMethod
97 | public void dateFormat(String timestamp, String dateStyle, String timeStyle, Promise promise) {
98 | try {
99 | Date date = new Date(Long.parseLong(timestamp));
100 |
101 | int dateStyleInt = this.getDateFormatIntFromString(dateStyle);
102 | int timeStyleInt = this.getDateFormatIntFromString(timeStyle);
103 |
104 | DateFormat dateFormatter;
105 | if(!dateStyle.equals("none") && !timeStyle.equals("none")) {
106 | dateFormatter = DateFormat.getDateTimeInstance(dateStyleInt, timeStyleInt, getLocale());
107 | } else if(!dateStyle.equals("none") && timeStyle.equals("none")) {
108 | dateFormatter = DateFormat.getDateInstance(dateStyleInt, getLocale());
109 | } else {
110 | dateFormatter = DateFormat.getTimeInstance(timeStyleInt, getLocale());
111 | }
112 |
113 | promise.resolve(dateFormatter.format(date));
114 |
115 | } catch (Exception e) {
116 | promise.reject(e.getMessage());
117 | }
118 | }
119 |
120 | private int getDateFormatIntFromString(String stringStyle) {
121 | int dateFormatStyleint;
122 | switch(stringStyle) {
123 | case "long":
124 | dateFormatStyleint = DateFormat.LONG;
125 | break;
126 | case "medium":
127 | dateFormatStyleint = DateFormat.MEDIUM;
128 | break;
129 | case "short":
130 | dateFormatStyleint = DateFormat.SHORT;
131 | break;
132 | case "default":
133 | dateFormatStyleint = DateFormat.DEFAULT;
134 | break;
135 | default:
136 | dateFormatStyleint = DateFormat.FULL;
137 | break;
138 | }
139 | return dateFormatStyleint;
140 | }
141 |
142 | private Locale getLocale() {
143 | Locale current = mContext.getResources().getConfiguration().locale;
144 | return current;
145 | }
146 |
147 | private DecimalFormat getDecimalFormat() {
148 | DecimalFormat formatter = (DecimalFormat) DecimalFormat.getInstance(getLocale());
149 | return formatter;
150 | }
151 | }
152 |
--------------------------------------------------------------------------------
/ios/RCTLocale.xcodeproj/project.pbxproj:
--------------------------------------------------------------------------------
1 | // !$*UTF8*$!
2 | {
3 | archiveVersion = 1;
4 | classes = {
5 | };
6 | objectVersion = 46;
7 | objects = {
8 |
9 | /* Begin PBXBuildFile section */
10 | DB248BF51C18396500105A5D /* RCTLocale.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = DB248BF41C18396500105A5D /* RCTLocale.h */; };
11 | DB248BF71C18396500105A5D /* RCTLocale.m in Sources */ = {isa = PBXBuildFile; fileRef = DB248BF61C18396500105A5D /* RCTLocale.m */; };
12 | /* End PBXBuildFile section */
13 |
14 | /* Begin PBXCopyFilesBuildPhase section */
15 | DB248BF01C18396500105A5D /* CopyFiles */ = {
16 | isa = PBXCopyFilesBuildPhase;
17 | buildActionMask = 2147483647;
18 | dstPath = "include/$(PRODUCT_NAME)";
19 | dstSubfolderSpec = 16;
20 | files = (
21 | DB248BF51C18396500105A5D /* RCTLocale.h in CopyFiles */,
22 | );
23 | runOnlyForDeploymentPostprocessing = 0;
24 | };
25 | /* End PBXCopyFilesBuildPhase section */
26 |
27 | /* Begin PBXFileReference section */
28 | DB248BF21C18396500105A5D /* libRCTLocale.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libRCTLocale.a; sourceTree = BUILT_PRODUCTS_DIR; };
29 | DB248BF41C18396500105A5D /* RCTLocale.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RCTLocale.h; sourceTree = ""; };
30 | DB248BF61C18396500105A5D /* RCTLocale.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = RCTLocale.m; sourceTree = ""; };
31 | /* End PBXFileReference section */
32 |
33 | /* Begin PBXFrameworksBuildPhase section */
34 | DB248BEF1C18396500105A5D /* Frameworks */ = {
35 | isa = PBXFrameworksBuildPhase;
36 | buildActionMask = 2147483647;
37 | files = (
38 | );
39 | runOnlyForDeploymentPostprocessing = 0;
40 | };
41 | /* End PBXFrameworksBuildPhase section */
42 |
43 | /* Begin PBXGroup section */
44 | DB0CBAD11C1831B200168F2E = {
45 | isa = PBXGroup;
46 | children = (
47 | DB9768661C183ADA00042D1A /* Products */,
48 | DB248BF31C18396500105A5D /* RCTLocale */,
49 | );
50 | sourceTree = "";
51 | };
52 | DB248BF31C18396500105A5D /* RCTLocale */ = {
53 | isa = PBXGroup;
54 | children = (
55 | DB248BF41C18396500105A5D /* RCTLocale.h */,
56 | DB248BF61C18396500105A5D /* RCTLocale.m */,
57 | );
58 | path = RCTLocale;
59 | sourceTree = "";
60 | };
61 | DB9768661C183ADA00042D1A /* Products */ = {
62 | isa = PBXGroup;
63 | children = (
64 | DB248BF21C18396500105A5D /* libRCTLocale.a */,
65 | );
66 | name = Products;
67 | sourceTree = "";
68 | };
69 | /* End PBXGroup section */
70 |
71 | /* Begin PBXNativeTarget section */
72 | DB248BF11C18396500105A5D /* RCTLocale */ = {
73 | isa = PBXNativeTarget;
74 | buildConfigurationList = DB248BF81C18396500105A5D /* Build configuration list for PBXNativeTarget "RCTLocale" */;
75 | buildPhases = (
76 | DB248BEE1C18396500105A5D /* Sources */,
77 | DB248BEF1C18396500105A5D /* Frameworks */,
78 | DB248BF01C18396500105A5D /* CopyFiles */,
79 | );
80 | buildRules = (
81 | );
82 | dependencies = (
83 | );
84 | name = RCTLocale;
85 | productName = RCTLocale;
86 | productReference = DB248BF21C18396500105A5D /* libRCTLocale.a */;
87 | productType = "com.apple.product-type.library.static";
88 | };
89 | /* End PBXNativeTarget section */
90 |
91 | /* Begin PBXProject section */
92 | DB0CBAD21C1831B200168F2E /* Project object */ = {
93 | isa = PBXProject;
94 | attributes = {
95 | LastUpgradeCheck = 0710;
96 | TargetAttributes = {
97 | DB248BF11C18396500105A5D = {
98 | CreatedOnToolsVersion = 7.1.1;
99 | };
100 | };
101 | };
102 | buildConfigurationList = DB0CBAD51C1831B200168F2E /* Build configuration list for PBXProject "RCTLocale" */;
103 | compatibilityVersion = "Xcode 3.2";
104 | developmentRegion = English;
105 | hasScannedForEncodings = 0;
106 | knownRegions = (
107 | en,
108 | );
109 | mainGroup = DB0CBAD11C1831B200168F2E;
110 | productRefGroup = DB0CBAD11C1831B200168F2E;
111 | projectDirPath = "";
112 | projectRoot = "";
113 | targets = (
114 | DB248BF11C18396500105A5D /* RCTLocale */,
115 | );
116 | };
117 | /* End PBXProject section */
118 |
119 | /* Begin PBXSourcesBuildPhase section */
120 | DB248BEE1C18396500105A5D /* Sources */ = {
121 | isa = PBXSourcesBuildPhase;
122 | buildActionMask = 2147483647;
123 | files = (
124 | DB248BF71C18396500105A5D /* RCTLocale.m in Sources */,
125 | );
126 | runOnlyForDeploymentPostprocessing = 0;
127 | };
128 | /* End PBXSourcesBuildPhase section */
129 |
130 | /* Begin XCBuildConfiguration section */
131 | DB0CBAD61C1831B200168F2E /* Debug */ = {
132 | isa = XCBuildConfiguration;
133 | buildSettings = {
134 | HEADER_SEARCH_PATHS = (
135 | "$(SRCROOT)/../../React/**",
136 | "$(SRCROOT)/../../react-native/React/**",
137 | "$(SRCROOT)/node_modules/react-native/React/**",
138 | );
139 | };
140 | name = Debug;
141 | };
142 | DB0CBAD71C1831B200168F2E /* Release */ = {
143 | isa = XCBuildConfiguration;
144 | buildSettings = {
145 | HEADER_SEARCH_PATHS = (
146 | "$(SRCROOT)/../../React/**",
147 | "$(SRCROOT)/../../react-native/React/**",
148 | "$(SRCROOT)/node_modules/react-native/React/**",
149 | );
150 | };
151 | name = Release;
152 | };
153 | DB248BF91C18396500105A5D /* Debug */ = {
154 | isa = XCBuildConfiguration;
155 | buildSettings = {
156 | ALWAYS_SEARCH_USER_PATHS = NO;
157 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
158 | CLANG_CXX_LIBRARY = "libc++";
159 | CLANG_ENABLE_MODULES = YES;
160 | CLANG_ENABLE_OBJC_ARC = YES;
161 | CLANG_WARN_BOOL_CONVERSION = YES;
162 | CLANG_WARN_CONSTANT_CONVERSION = YES;
163 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
164 | CLANG_WARN_EMPTY_BODY = YES;
165 | CLANG_WARN_ENUM_CONVERSION = YES;
166 | CLANG_WARN_INT_CONVERSION = YES;
167 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
168 | CLANG_WARN_UNREACHABLE_CODE = YES;
169 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
170 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
171 | COPY_PHASE_STRIP = NO;
172 | DEBUG_INFORMATION_FORMAT = dwarf;
173 | ENABLE_STRICT_OBJC_MSGSEND = YES;
174 | ENABLE_TESTABILITY = YES;
175 | GCC_C_LANGUAGE_STANDARD = gnu99;
176 | GCC_DYNAMIC_NO_PIC = NO;
177 | GCC_NO_COMMON_BLOCKS = YES;
178 | GCC_OPTIMIZATION_LEVEL = 0;
179 | GCC_PREPROCESSOR_DEFINITIONS = (
180 | "DEBUG=1",
181 | "$(inherited)",
182 | );
183 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
184 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
185 | GCC_WARN_UNDECLARED_SELECTOR = YES;
186 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
187 | GCC_WARN_UNUSED_FUNCTION = YES;
188 | GCC_WARN_UNUSED_VARIABLE = YES;
189 | IPHONEOS_DEPLOYMENT_TARGET = 9.1;
190 | MTL_ENABLE_DEBUG_INFO = YES;
191 | ONLY_ACTIVE_ARCH = YES;
192 | OTHER_LDFLAGS = "-ObjC";
193 | PRODUCT_NAME = "$(TARGET_NAME)";
194 | SDKROOT = iphoneos;
195 | SKIP_INSTALL = YES;
196 | };
197 | name = Debug;
198 | };
199 | DB248BFA1C18396500105A5D /* Release */ = {
200 | isa = XCBuildConfiguration;
201 | buildSettings = {
202 | ALWAYS_SEARCH_USER_PATHS = NO;
203 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
204 | CLANG_CXX_LIBRARY = "libc++";
205 | CLANG_ENABLE_MODULES = YES;
206 | CLANG_ENABLE_OBJC_ARC = YES;
207 | CLANG_WARN_BOOL_CONVERSION = YES;
208 | CLANG_WARN_CONSTANT_CONVERSION = YES;
209 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
210 | CLANG_WARN_EMPTY_BODY = YES;
211 | CLANG_WARN_ENUM_CONVERSION = YES;
212 | CLANG_WARN_INT_CONVERSION = YES;
213 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
214 | CLANG_WARN_UNREACHABLE_CODE = YES;
215 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
216 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
217 | COPY_PHASE_STRIP = NO;
218 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
219 | ENABLE_NS_ASSERTIONS = NO;
220 | ENABLE_STRICT_OBJC_MSGSEND = YES;
221 | GCC_C_LANGUAGE_STANDARD = gnu99;
222 | GCC_NO_COMMON_BLOCKS = YES;
223 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
224 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
225 | GCC_WARN_UNDECLARED_SELECTOR = YES;
226 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
227 | GCC_WARN_UNUSED_FUNCTION = YES;
228 | GCC_WARN_UNUSED_VARIABLE = YES;
229 | IPHONEOS_DEPLOYMENT_TARGET = 9.1;
230 | MTL_ENABLE_DEBUG_INFO = NO;
231 | OTHER_LDFLAGS = "-ObjC";
232 | PRODUCT_NAME = "$(TARGET_NAME)";
233 | SDKROOT = iphoneos;
234 | SKIP_INSTALL = YES;
235 | VALIDATE_PRODUCT = YES;
236 | };
237 | name = Release;
238 | };
239 | /* End XCBuildConfiguration section */
240 |
241 | /* Begin XCConfigurationList section */
242 | DB0CBAD51C1831B200168F2E /* Build configuration list for PBXProject "RCTLocale" */ = {
243 | isa = XCConfigurationList;
244 | buildConfigurations = (
245 | DB0CBAD61C1831B200168F2E /* Debug */,
246 | DB0CBAD71C1831B200168F2E /* Release */,
247 | );
248 | defaultConfigurationIsVisible = 0;
249 | defaultConfigurationName = Release;
250 | };
251 | DB248BF81C18396500105A5D /* Build configuration list for PBXNativeTarget "RCTLocale" */ = {
252 | isa = XCConfigurationList;
253 | buildConfigurations = (
254 | DB248BF91C18396500105A5D /* Debug */,
255 | DB248BFA1C18396500105A5D /* Release */,
256 | );
257 | defaultConfigurationIsVisible = 0;
258 | defaultConfigurationName = Release;
259 | };
260 | /* End XCConfigurationList section */
261 | };
262 | rootObject = DB0CBAD21C1831B200168F2E /* Project object */;
263 | }
264 |
--------------------------------------------------------------------------------