├── .babelrc ├── .gitignore ├── .npmignore ├── .vscode └── settings.json ├── LICENSE ├── README.md ├── ReactNativeLocalization.podspec ├── android ├── build.gradle └── src │ └── main │ ├── AndroidManifest.xml │ ├── java │ └── com │ │ └── babisoft │ │ └── ReactNativeLocalization │ │ ├── ReactNativeLocalization.java │ │ └── ReactNativeLocalizationPackage.java │ └── res │ └── values │ └── styles.xml ├── ios ├── ReactLocalization.h ├── ReactLocalization.m └── ReactNativeLocalization.xcodeproj │ ├── project.pbxproj │ ├── project.xcworkspace │ ├── contents.xcworkspacedata │ ├── xcshareddata │ │ ├── IDEWorkspaceChecks.plist │ │ └── ReactNativeLocalization.xccheckout │ └── xcuserdata │ │ └── stefano.xcuserdatad │ │ └── UserInterfaceState.xcuserstate │ └── xcuserdata │ └── stefano.xcuserdatad │ └── xcschemes │ ├── ReactNativeLocalization.xcscheme │ └── xcschememanagement.plist ├── lib ├── LocalizedStrings.d.ts └── LocalizedStrings.js ├── package.json ├── src └── LocalizedStrings.js └── windows └── ReactNativeLocalization ├── .gitignore ├── Properties ├── AssemblyInfo.cs └── ReactNativeLocalization.rd.xml ├── RNLocalizationModule.cs ├── RNLocalizationPackage.cs ├── ReactNativeLocalization.csproj └── ReactNativeLocalization.sln /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | [ 4 | "env", 5 | [ 6 | "es2015", 7 | { 8 | "modules": true 9 | } 10 | ] 11 | ] 12 | ] 13 | } 14 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | npm-instructions.txt 2 | # Android/IJ 3 | .idea/workspace.xml 4 | .idea/libraries 5 | .gradle 6 | local.properties 7 | *.iml 8 | build 9 | node_modules 10 | npm-instructions.txt 11 | .idea -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | # Android/IJ 2 | .idea/workspace.xml 3 | .idea/libraries 4 | local.properties 5 | *.iml 6 | build 7 | /src 8 | .babelrc 9 | npm-instructions.txt -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "git.ignoreLimitWarning": true 3 | } -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Stefano Falda 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ReactNativeLocalization 2 | 3 | Class to localize the ReactNative interface. 4 | 5 | Use [react-localization](https://github.com/stefalda/react-localization) if you want to share code with a React project or the [localized-strings](https://github.com/stefalda/localized-strings) for a generic javascript solution. 6 | 7 | ### Note about version 1.x 8 | This library has been refactored to use the newly created [localized-strings package](https://github.com/stefalda/localized-strings), now added as a dependency, so to unify the code and make it easier to mantain 9 | 10 | All the basic code is now in the localized-strings project and in the react-localization version that adds support for embedding JSX code in the formatted strings, by overriding the formatString method. 11 | 12 | This version adds a custom version of the `getInterfaceLanguage` to retrieve the interface language from the native OS. 13 | 14 | **To simplify Android versions' configuration, versions 2.0 and up are compatible only with ReactNative >= 0.56.0** 15 | 16 | ## What it does 17 | 18 | I just needed a dead simple way to internationalize my first React Native app. 19 | 20 | At the beginning I thought I'd expose the native iOS internationalization API (NSLocalizedString macro) to React Native, but then I've opted for a solution that seems, at least to me, more in the spirit of React (and I hope better performance wise). 21 | 22 | In this implementation we can keep the localized strings in the same file of the React View in a similar way of how Styles are implemented (I don't deny that this approach could lead to some duplications in the translated strings, but it could be feasible to create a CommonJS module to use as common source of the strings, requiring it in the different views). 23 | 24 | 25 | **Beware *Expo* created apps need to be ejected before integrating native plugins like this one.** 26 | **So if you've used the Create React Native app shortcut you should eject the app as detailed here here.** 27 | 28 | ## How it works 29 | 30 | The Javascript library uses a native library (ReactLocalization) to get the current interface language, then it loads and displays the strings matching the current interface locale or the default language (the first one if a match is not found) if a specific localization can't be found. 31 | 32 | It's possible to force a language different from the interface one. 33 | 34 | ## Installation 35 | The easiest way to install is to type just 2 commands inside your react-native project folder and you are ready to go: 36 | 37 | ``` 38 | yarn add react-native-localization 39 | 40 | or 41 | 42 | npm i react-native-localization 43 | 44 | #react-native >= 0.60 45 | cd ios && pod install && cd .. 46 | 47 | #react-native < 0.60 48 | react-native link react-native-localization 49 | ``` 50 | 51 | 52 | Don´t forget to restart the app / node server or you will see an error. 53 | 54 | If you're installing for Android and still experiencing problems check if 55 | step 4 of "Manual installation Android" has been automatically executed by the linker. 56 | 57 | Check this [article](https://github.com/react-native-community/cli/blob/master/docs/autolinking.md) about the new linking behaviour in react-native since version 0.60. 58 | 59 | Windows platform doesn't support automatic installation by linker. Only manual installation is supported. 60 | 61 | ### Manual installation iOS 62 | 63 | 1. `npm install --save react-native-localization` 64 | 2. In the XCode's "Project navigator", right click on Libraries folder under your project ➜ `Add Files to <...>` 65 | 3. Go to `node_modules` ➜ `react-native-localization` and add the `ReactNativeLocalization.xcodeproj` file 66 | 4. Add libReactNativeLocalization.a to Build Phases -> Link Binary With Libraries 67 | 5. Build and run 68 | 69 | ### Manual installation Android 70 | 1. `npm install --save react-native-localization` 71 | 2. In `android/setting.gradle` 72 | 73 | ```gradle 74 | ... 75 | include ':react-native-localization', ':app' 76 | project(':react-native-localization').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-localization/android') 77 | ``` 78 | 79 | 3. In `android/app/build.gradle` 80 | 81 | ```gradle 82 | ... 83 | dependencies { 84 | ... 85 | compile project(':react-native-localization') 86 | } 87 | ``` 88 | 89 | 4. register module (in MainApplication.java) 90 | 91 | ```java 92 | import com.babisoft.ReactNativeLocalization.ReactNativeLocalizationPackage; // <--- import 93 | 94 | public class MainApplication extends Application implements ReactApplication { 95 | ...... 96 | @Override 97 | protected List getPackages() { 98 | return Arrays.asList( 99 | new MainReactPackage(), 100 | new ReactNativeLocalizationPackage() 101 | ); 102 | } 103 | ...... 104 | } 105 | ``` 106 | 107 | (Thanks to @rebeccahughes for showing by example how to create an android module for React Native) 108 | 109 | ### Manual installation windows 110 | 111 | Full process is documented in official [React Native plugin for Universal Windows](https://github.com/Microsoft/react-native-windows/blob/master/docs/LinkingLibrariesWindows.md) repo: https://github.com/Microsoft/react-native-windows/blob/master/docs/LinkingLibrariesWindows.md 112 | 113 | 1. Run `npm install --save react-native-localization` 114 | 2. Open your Visual Studio solution. 115 | 3. Right-click the solution in the Solution Explorer 116 | 4. Select Add -> Existing Project 117 | 5. Choose the `.csproj` of the dependency from the Explorer window. Dependency will be in `node_modules\react-native-localization\windows\ReactNativeLocalization` 118 | 6. Right-click the Universal Windows App project in the Solution Explorer 119 | 7. Select Add -> Reference 120 | 8. Choose the `ReactNativeLocalization` project. 121 | 9. Open MainPage.cs 122 | 10. Add the `new ReactNativeLocalization.RNLocalizationPackage()` to the `Packages` list in MainPage.cs 123 | 124 | ## Usage 125 | 126 | In the React class that you want to localize require the library and define the strings object passing to the constructor a simple object containing a language key (i.e. en, it, fr..) and then a list of key-value pairs with the needed localized strings. 127 | 128 | ```js 129 | // ES6 module syntax 130 | import LocalizedStrings from 'react-native-localization'; 131 | 132 | // CommonJS syntax 133 | // let LocalizedStrings = require ('react-native-localization'); 134 | 135 | let strings = new LocalizedStrings({ 136 | "en-US":{ 137 | how:"How do you want your egg today?", 138 | boiledEgg:"Boiled egg", 139 | softBoiledEgg:"Soft-boiled egg", 140 | choice:"How to choose the egg" 141 | }, 142 | en:{ 143 | how:"How do you want your egg today?", 144 | boiledEgg:"Boiled egg", 145 | softBoiledEgg:"Soft-boiled egg", 146 | choice:"How to choose the egg" 147 | }, 148 | it: { 149 | how:"Come vuoi il tuo uovo oggi?", 150 | boiledEgg:"Uovo sodo", 151 | softBoiledEgg:"Uovo alla coque", 152 | choice:"Come scegliere l'uovo" 153 | } 154 | }); 155 | ``` 156 | 157 | Then use the `strings` object literal directly in the render method accessing the key of the localized string. 158 | 159 | ```js 160 | 161 | {strings.how} 162 | 163 | ``` 164 | 165 | The first language is considered the default one, so if a translation is missing for the selected language, the default one is shown and a line is written to the log as a reminder. 166 | 167 | #### Update / Overwrite Locale 168 | 169 | You might have default localized in the build but then download the latest localization strings from a server. Use setContent to overwrite the whole object. **NOTE** that this will remove all other localizations if used. 170 | 171 | ```js 172 | strings.setContent({ 173 | en:{ 174 | how:"How do you want your egg todajsie?", 175 | boiledEgg:"Boiled eggsie", 176 | softBoiledEgg:"Soft-boiled egg", 177 | choice:"How to choose the egg" 178 | } 179 | }) 180 | ``` 181 | 182 | You can also only overwrite a specific language using 183 | 184 | ```js 185 | strings.setContent(Object.assign({},strings.getContent(), 186 | { 187 | en:{ 188 | how:"How do you want your egg todajsie?", 189 | boiledEgg:"Boiled eggsie", 190 | softBoiledEgg:"Soft-boiled egg", 191 | choice:"How to choose the egg" 192 | } 193 | })); 194 | ``` 195 | 196 | ## Typescript 197 | For TypeScript, your `tsconfig.json` should be something like this: 198 | ```json 199 | { 200 | "compilerOptions": { 201 | "target": "es2015", 202 | "module": "es2015", 203 | "jsx": "react-native", 204 | "moduleResolution": "node", 205 | "allowSyntheticDefaultImports": true 206 | } 207 | } 208 | ``` 209 | 210 | Where `"module": "es2015"` is the most important setting for being able to import the module properly. 211 | 212 | Import should be done like this: 213 | 214 | ```ts 215 | import LocalizedString from "react-native-localization"; 216 | ``` 217 | 218 | ## API 219 | 220 | * setLanguage(languageCode) - to force manually a particular language 221 | * getLanguage() - to get the current displayed language 222 | * getInterfaceLanguage() - to get the current device interface language 223 | * formatString() - to format the passed string replacing its placeholders with the other arguments strings 224 | 225 | ```js 226 | en:{ 227 | bread:"bread", 228 | butter:"butter", 229 | question:"I'd like {0} and {1}, or just {0}" 230 | } 231 | ... 232 | strings.formatString(strings.question, strings.bread, strings.butter) 233 | ``` 234 | **Beware: do not define a string key as `formatString` or `language`!** 235 | * getAvailableLanguages() - to get an array of the languages passed in the constructor 236 | 237 | ## Examples 238 | To force a particular language use something like this: 239 | 240 | ```js 241 | _onSetLanguageToItalian() { 242 | strings.setLanguage('it'); 243 | this.setState({}); 244 | } 245 | ``` 246 | 247 | It's also possible to set the language directly in your Xcode project using the following code snippet: 248 | 249 | ```objective-c 250 | [[NSUserDefaults standardUserDefaults] setObject:[NSArray arrayWithObjects:@"de", nil] forKey:@"AppleLanguages"]; 251 | ``` 252 | 253 | Replace `de` with a [supported locale identifier](https://gist.github.com/pjc-is/49971b36db38fdeae6fc) to test. 254 | 255 | Check out the [WIKI page](https://github.com/stefalda/ReactNativeLocalization/wiki) for additional informations. 256 | 257 | ## Questions or suggestions? 258 | Feel free to contact me on [Twitter](https://twitter.com/talpaz) or [open an issue](https://github.com/stefalda/ReactNativeLocalization/issues/new). 259 | -------------------------------------------------------------------------------- /ReactNativeLocalization.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 = "ReactNativeLocalization" 7 | s.version = package['version'] 8 | s.summary = package['description'] 9 | s.homepage = "https://github.com/stefalda/ReactNativeLocalization" 10 | s.license = package['license'] 11 | s.author = package['author'] 12 | s.source = { :git => package['repository']['url'], :tag => "v#{s.version}" } 13 | 14 | s.ios.deployment_target = '8.0' 15 | s.tvos.deployment_target = '10.0' 16 | s.osx.deployment_target = '10.10' 17 | 18 | s.preserve_paths = 'README.md', 'LICENSE', 'package.json', 'lib' 19 | s.source_files = "ios/*.{h,m}" 20 | 21 | s.dependency 'React-Core' 22 | end 23 | -------------------------------------------------------------------------------- /android/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.library' 2 | def DEFAULT_COMPILE_SDK_VERSION = 26 3 | def DEFAULT_BUILD_TOOLS_VERSION = "26.0.3" 4 | def DEFAULT_MIN_SDK_VERSION = 16 5 | def DEFAULT_TARGET_SDK_VERSION = 26 6 | 7 | def safeExtGet(prop, fallback) { 8 | rootProject.ext.has(prop) ? rootProject.ext.get(prop) : fallback 9 | } 10 | 11 | android { 12 | compileSdkVersion safeExtGet('compileSdkVersion', DEFAULT_COMPILE_SDK_VERSION) 13 | buildToolsVersion safeExtGet('buildToolsVersion', DEFAULT_BUILD_TOOLS_VERSION) 14 | 15 | defaultConfig { 16 | minSdkVersion safeExtGet('minSdkVersion', DEFAULT_MIN_SDK_VERSION) 17 | targetSdkVersion safeExtGet('targetSdkVersion', DEFAULT_TARGET_SDK_VERSION) 18 | versionCode 1 19 | versionName "1.0" 20 | ndk { 21 | abiFilters "armeabi-v7a", "x86" 22 | } 23 | } 24 | } 25 | 26 | dependencies { implementation 'com.facebook.react:react-native:+' } 27 | -------------------------------------------------------------------------------- /android/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | -------------------------------------------------------------------------------- /android/src/main/java/com/babisoft/ReactNativeLocalization/ReactNativeLocalization.java: -------------------------------------------------------------------------------- 1 | package com.babisoft.ReactNativeLocalization; 2 | 3 | import android.content.Context; 4 | import android.content.SharedPreferences; 5 | 6 | import com.facebook.react.bridge.Callback; 7 | import com.facebook.react.bridge.ReactApplicationContext; 8 | import com.facebook.react.bridge.ReactContextBaseJavaModule; 9 | import com.facebook.react.bridge.ReactMethod; 10 | 11 | import java.util.HashMap; 12 | import java.util.Locale; 13 | import java.util.Map; 14 | 15 | /** 16 | * Created by stefano on 20/09/15. 17 | */ 18 | public class ReactNativeLocalization extends ReactContextBaseJavaModule { 19 | 20 | /** 21 | * Name of the exported variable 22 | */ 23 | private static final String LANGUAGE = "language"; 24 | 25 | public ReactNativeLocalization(ReactApplicationContext reactContext) { 26 | super(reactContext); 27 | } 28 | 29 | @Override 30 | public String getName() { 31 | return "ReactLocalization"; 32 | } 33 | 34 | /** 35 | * Return the current language 36 | * 37 | * @return 38 | */ 39 | private String getCurrentLanguage() { 40 | 41 | // user locale takes precedence 42 | String userLocale = this.getUserLocale(); 43 | if (userLocale != null) { 44 | return userLocale; 45 | } 46 | 47 | Locale current = getReactApplicationContext().getResources().getConfiguration().locale; 48 | return current.getLanguage() + "-" + current.getCountry(); 49 | } 50 | 51 | 52 | public String getUserLocale() { 53 | return getPreferences().getString("locale_override", null); 54 | } 55 | 56 | 57 | /** 58 | * Export to Javascript the variable language containing the current language 59 | * 60 | * @return 61 | */ 62 | @Override 63 | public Map getConstants() { 64 | final Map constants = new HashMap<>(); 65 | constants.put(LANGUAGE, getCurrentLanguage()); 66 | return constants; 67 | } 68 | 69 | /** 70 | * Export a method callable from javascript that returns the current language 71 | * 72 | * @param callback 73 | */ 74 | @ReactMethod 75 | public void getLanguage(Callback callback) { 76 | String language = getCurrentLanguage(); 77 | System.out.println("The current language is " + language); 78 | callback.invoke(null, language); 79 | } 80 | 81 | /** 82 | * SharedPreferences 83 | */ 84 | private SharedPreferences getPreferences() { 85 | return getReactApplicationContext().getSharedPreferences("react-native", Context.MODE_PRIVATE); 86 | } 87 | private SharedPreferences.Editor getEditor() { 88 | return getPreferences().edit(); 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /android/src/main/java/com/babisoft/ReactNativeLocalization/ReactNativeLocalizationPackage.java: -------------------------------------------------------------------------------- 1 | package com.babisoft.ReactNativeLocalization; 2 | 3 | import com.facebook.react.ReactPackage; 4 | import com.facebook.react.bridge.JavaScriptModule; 5 | import com.facebook.react.bridge.NativeModule; 6 | import com.facebook.react.bridge.ReactApplicationContext; 7 | import com.facebook.react.uimanager.ViewManager; 8 | 9 | import java.util.ArrayList; 10 | import java.util.Arrays; 11 | import java.util.Collections; 12 | import java.util.List; 13 | 14 | /** 15 | * Created by stefano on 21/09/15. 16 | */ 17 | public class ReactNativeLocalizationPackage implements ReactPackage { 18 | @Override 19 | public List createNativeModules( 20 | ReactApplicationContext reactContext) { 21 | List modules = new ArrayList<>(); 22 | 23 | modules.add(new ReactNativeLocalization(reactContext)); 24 | return modules; 25 | } 26 | 27 | // Deprecated RN 0.47 28 | public List> createJSModules() { 29 | return Collections.emptyList(); 30 | } 31 | 32 | @Override 33 | public List createViewManagers(ReactApplicationContext reactContext) { 34 | return Arrays.asList(); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /android/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /ios/ReactLocalization.h: -------------------------------------------------------------------------------- 1 | // 2 | // The MIT License (MIT) 3 | // 4 | // Copyright (c) 2015 Stefano Falda (stefano.falda@gmail.com) 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a copy 7 | // of this software and associated documentation files (the "Software"), to deal 8 | // in the Software without restriction, including without limitation the rights 9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | // copies of the Software, and to permit persons to whom the Software is 11 | // furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in all 14 | // copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | // SOFTWARE. 23 | 24 | #import 25 | #import 26 | #import 27 | #import 28 | @interface ReactLocalization : NSObject 29 | 30 | @end 31 | -------------------------------------------------------------------------------- /ios/ReactLocalization.m: -------------------------------------------------------------------------------- 1 | // 2 | // The MIT License (MIT) 3 | // 4 | // Copyright (c) 2015 Stefano Falda (stefano.falda@gmail.com) 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a copy 7 | // of this software and associated documentation files (the "Software"), to deal 8 | // in the Software without restriction, including without limitation the rights 9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | // copies of the Software, and to permit persons to whom the Software is 11 | // furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in all 14 | // copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | // SOFTWARE. 23 | 24 | #import "ReactLocalization.h" 25 | 26 | @interface ReactLocalization () 27 | -(NSString*) getCurrentLanguage; 28 | -(NSString*) getUserLocale; 29 | @end 30 | 31 | @implementation ReactLocalization 32 | RCT_EXPORT_MODULE(); 33 | /* 34 | * Private implementation - return the language and the region like 'en-US' if iOS >= 10 otherwise just the language 35 | */ 36 | -(NSString*) getCurrentLanguage{ 37 | if (!@available(iOS 10.0, *)) { 38 | NSString *userLocale = [self getUserLocale]; 39 | if (userLocale) { 40 | return userLocale; 41 | } 42 | } 43 | 44 | // Fallback 45 | return [[NSLocale preferredLanguages] objectAtIndex:0]; 46 | } 47 | 48 | -(NSString*) getUserLocale { 49 | NSArray* locales = [[NSUserDefaults standardUserDefaults] objectForKey:@"AppleLanguages"]; 50 | if (locales == nil ) { return nil; } 51 | if ([locales count] == 0) { return nil; } 52 | 53 | NSString* userLocale = locales[0]; 54 | return userLocale; 55 | } 56 | 57 | 58 | 59 | /* 60 | * Method called from javascript with a callback in case of success 61 | */ 62 | RCT_EXPORT_METHOD(getLanguage:(RCTResponseSenderBlock)callback){ 63 | NSString * language = [self getCurrentLanguage]; 64 | NSLog(@"Language: %@", language); 65 | callback(@[[NSNull null], language]); 66 | } 67 | 68 | /* 69 | * Expose the language directly to javascript avoiding the callback 70 | */ 71 | - (NSDictionary *)constantsToExport 72 | { 73 | return @{ @"language": [self getCurrentLanguage]}; 74 | } 75 | 76 | +(BOOL)requiresMainQueueSetup 77 | { 78 | return YES; 79 | } 80 | @end 81 | -------------------------------------------------------------------------------- /ios/ReactNativeLocalization.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 7B5D9D291B6AD51800CF3A83 /* ReactLocalization.m in Sources */ = {isa = PBXBuildFile; fileRef = 7B5D9D281B6AD51800CF3A83 /* ReactLocalization.m */; }; 11 | /* End PBXBuildFile section */ 12 | 13 | /* Begin PBXCopyFilesBuildPhase section */ 14 | 7B5D9D081B6AD0EA00CF3A83 /* CopyFiles */ = { 15 | isa = PBXCopyFilesBuildPhase; 16 | buildActionMask = 2147483647; 17 | dstPath = "include/$(PRODUCT_NAME)"; 18 | dstSubfolderSpec = 16; 19 | files = ( 20 | ); 21 | runOnlyForDeploymentPostprocessing = 0; 22 | }; 23 | /* End PBXCopyFilesBuildPhase section */ 24 | 25 | /* Begin PBXFileReference section */ 26 | 7B5D9D0A1B6AD0EA00CF3A83 /* libReactNativeLocalization.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libReactNativeLocalization.a; sourceTree = BUILT_PRODUCTS_DIR; }; 27 | 7B5D9D271B6AD51800CF3A83 /* ReactLocalization.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ReactLocalization.h; sourceTree = ""; }; 28 | 7B5D9D281B6AD51800CF3A83 /* ReactLocalization.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ReactLocalization.m; sourceTree = ""; }; 29 | /* End PBXFileReference section */ 30 | 31 | /* Begin PBXFrameworksBuildPhase section */ 32 | 7B5D9D071B6AD0EA00CF3A83 /* Frameworks */ = { 33 | isa = PBXFrameworksBuildPhase; 34 | buildActionMask = 2147483647; 35 | files = ( 36 | ); 37 | runOnlyForDeploymentPostprocessing = 0; 38 | }; 39 | /* End PBXFrameworksBuildPhase section */ 40 | 41 | /* Begin PBXGroup section */ 42 | 7B5D9D011B6AD0EA00CF3A83 = { 43 | isa = PBXGroup; 44 | children = ( 45 | 7B5D9D271B6AD51800CF3A83 /* ReactLocalization.h */, 46 | 7B5D9D281B6AD51800CF3A83 /* ReactLocalization.m */, 47 | 7B5D9D0B1B6AD0EA00CF3A83 /* Products */, 48 | ); 49 | sourceTree = ""; 50 | }; 51 | 7B5D9D0B1B6AD0EA00CF3A83 /* Products */ = { 52 | isa = PBXGroup; 53 | children = ( 54 | 7B5D9D0A1B6AD0EA00CF3A83 /* libReactNativeLocalization.a */, 55 | ); 56 | name = Products; 57 | sourceTree = ""; 58 | }; 59 | /* End PBXGroup section */ 60 | 61 | /* Begin PBXNativeTarget section */ 62 | 7B5D9D091B6AD0EA00CF3A83 /* ReactNativeLocalization */ = { 63 | isa = PBXNativeTarget; 64 | buildConfigurationList = 7B5D9D1E1B6AD0EA00CF3A83 /* Build configuration list for PBXNativeTarget "ReactNativeLocalization" */; 65 | buildPhases = ( 66 | 7B5D9D061B6AD0EA00CF3A83 /* Sources */, 67 | 7B5D9D071B6AD0EA00CF3A83 /* Frameworks */, 68 | 7B5D9D081B6AD0EA00CF3A83 /* CopyFiles */, 69 | ); 70 | buildRules = ( 71 | ); 72 | dependencies = ( 73 | ); 74 | name = ReactNativeLocalization; 75 | productName = ReactNativeLocalization; 76 | productReference = 7B5D9D0A1B6AD0EA00CF3A83 /* libReactNativeLocalization.a */; 77 | productType = "com.apple.product-type.library.static"; 78 | }; 79 | /* End PBXNativeTarget section */ 80 | 81 | /* Begin PBXProject section */ 82 | 7B5D9D021B6AD0EA00CF3A83 /* Project object */ = { 83 | isa = PBXProject; 84 | attributes = { 85 | LastUpgradeCheck = 1020; 86 | ORGANIZATIONNAME = "Stefano Falda"; 87 | TargetAttributes = { 88 | 7B5D9D091B6AD0EA00CF3A83 = { 89 | CreatedOnToolsVersion = 6.4; 90 | }; 91 | }; 92 | }; 93 | buildConfigurationList = 7B5D9D051B6AD0EA00CF3A83 /* Build configuration list for PBXProject "ReactNativeLocalization" */; 94 | compatibilityVersion = "Xcode 3.2"; 95 | developmentRegion = en; 96 | hasScannedForEncodings = 0; 97 | knownRegions = ( 98 | en, 99 | Base, 100 | ); 101 | mainGroup = 7B5D9D011B6AD0EA00CF3A83; 102 | productRefGroup = 7B5D9D0B1B6AD0EA00CF3A83 /* Products */; 103 | projectDirPath = ""; 104 | projectRoot = ""; 105 | targets = ( 106 | 7B5D9D091B6AD0EA00CF3A83 /* ReactNativeLocalization */, 107 | ); 108 | }; 109 | /* End PBXProject section */ 110 | 111 | /* Begin PBXSourcesBuildPhase section */ 112 | 7B5D9D061B6AD0EA00CF3A83 /* Sources */ = { 113 | isa = PBXSourcesBuildPhase; 114 | buildActionMask = 2147483647; 115 | files = ( 116 | 7B5D9D291B6AD51800CF3A83 /* ReactLocalization.m in Sources */, 117 | ); 118 | runOnlyForDeploymentPostprocessing = 0; 119 | }; 120 | /* End PBXSourcesBuildPhase section */ 121 | 122 | /* Begin XCBuildConfiguration section */ 123 | 7B5D9D1C1B6AD0EA00CF3A83 /* Debug */ = { 124 | isa = XCBuildConfiguration; 125 | buildSettings = { 126 | ALWAYS_SEARCH_USER_PATHS = NO; 127 | CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; 128 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 129 | CLANG_CXX_LIBRARY = "libc++"; 130 | CLANG_ENABLE_MODULES = YES; 131 | CLANG_ENABLE_OBJC_ARC = YES; 132 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 133 | CLANG_WARN_BOOL_CONVERSION = YES; 134 | CLANG_WARN_COMMA = YES; 135 | CLANG_WARN_CONSTANT_CONVERSION = YES; 136 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 137 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 138 | CLANG_WARN_EMPTY_BODY = YES; 139 | CLANG_WARN_ENUM_CONVERSION = YES; 140 | CLANG_WARN_INFINITE_RECURSION = YES; 141 | CLANG_WARN_INT_CONVERSION = YES; 142 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 143 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 144 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 145 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 146 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 147 | CLANG_WARN_STRICT_PROTOTYPES = YES; 148 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 149 | CLANG_WARN_UNREACHABLE_CODE = YES; 150 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 151 | COPY_PHASE_STRIP = NO; 152 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 153 | ENABLE_STRICT_OBJC_MSGSEND = YES; 154 | ENABLE_TESTABILITY = YES; 155 | GCC_C_LANGUAGE_STANDARD = gnu99; 156 | GCC_DYNAMIC_NO_PIC = NO; 157 | GCC_NO_COMMON_BLOCKS = YES; 158 | GCC_OPTIMIZATION_LEVEL = 0; 159 | GCC_PREPROCESSOR_DEFINITIONS = ( 160 | "DEBUG=1", 161 | "$(inherited)", 162 | ); 163 | GCC_SYMBOLS_PRIVATE_EXTERN = NO; 164 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 165 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 166 | GCC_WARN_UNDECLARED_SELECTOR = YES; 167 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 168 | GCC_WARN_UNUSED_FUNCTION = YES; 169 | GCC_WARN_UNUSED_VARIABLE = YES; 170 | HEADER_SEARCH_PATHS = ( 171 | "$(inherited)", 172 | /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include, 173 | "$(SRCROOT)/../react-native/React/**", 174 | "$(SRCROOT)/../../React/**", 175 | "$(SRCROOT)/node_modules/react-native/React", 176 | ); 177 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 178 | MTL_ENABLE_DEBUG_INFO = YES; 179 | ONLY_ACTIVE_ARCH = YES; 180 | SDKROOT = iphoneos; 181 | SKIP_INSTALL = YES; 182 | }; 183 | name = Debug; 184 | }; 185 | 7B5D9D1D1B6AD0EA00CF3A83 /* Release */ = { 186 | isa = XCBuildConfiguration; 187 | buildSettings = { 188 | ALWAYS_SEARCH_USER_PATHS = NO; 189 | CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; 190 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 191 | CLANG_CXX_LIBRARY = "libc++"; 192 | CLANG_ENABLE_MODULES = YES; 193 | CLANG_ENABLE_OBJC_ARC = YES; 194 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 195 | CLANG_WARN_BOOL_CONVERSION = YES; 196 | CLANG_WARN_COMMA = YES; 197 | CLANG_WARN_CONSTANT_CONVERSION = YES; 198 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 199 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 200 | CLANG_WARN_EMPTY_BODY = YES; 201 | CLANG_WARN_ENUM_CONVERSION = YES; 202 | CLANG_WARN_INFINITE_RECURSION = YES; 203 | CLANG_WARN_INT_CONVERSION = YES; 204 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 205 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 206 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 207 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 208 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 209 | CLANG_WARN_STRICT_PROTOTYPES = YES; 210 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 211 | CLANG_WARN_UNREACHABLE_CODE = YES; 212 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 213 | COPY_PHASE_STRIP = NO; 214 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 215 | ENABLE_NS_ASSERTIONS = NO; 216 | ENABLE_STRICT_OBJC_MSGSEND = YES; 217 | GCC_C_LANGUAGE_STANDARD = gnu99; 218 | GCC_NO_COMMON_BLOCKS = YES; 219 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 220 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 221 | GCC_WARN_UNDECLARED_SELECTOR = YES; 222 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 223 | GCC_WARN_UNUSED_FUNCTION = YES; 224 | GCC_WARN_UNUSED_VARIABLE = YES; 225 | HEADER_SEARCH_PATHS = ( 226 | "$(inherited)", 227 | /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include, 228 | "$(SRCROOT)/../react-native/React/**", 229 | "$(SRCROOT)/../../React/**", 230 | "$(SRCROOT)/node_modules/react-native/React", 231 | ); 232 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 233 | MTL_ENABLE_DEBUG_INFO = NO; 234 | SDKROOT = iphoneos; 235 | SKIP_INSTALL = YES; 236 | VALIDATE_PRODUCT = YES; 237 | }; 238 | name = Release; 239 | }; 240 | 7B5D9D1F1B6AD0EA00CF3A83 /* Debug */ = { 241 | isa = XCBuildConfiguration; 242 | buildSettings = { 243 | OTHER_LDFLAGS = "-ObjC"; 244 | PRODUCT_NAME = "$(TARGET_NAME)"; 245 | SKIP_INSTALL = YES; 246 | }; 247 | name = Debug; 248 | }; 249 | 7B5D9D201B6AD0EA00CF3A83 /* Release */ = { 250 | isa = XCBuildConfiguration; 251 | buildSettings = { 252 | OTHER_LDFLAGS = "-ObjC"; 253 | PRODUCT_NAME = "$(TARGET_NAME)"; 254 | SKIP_INSTALL = YES; 255 | }; 256 | name = Release; 257 | }; 258 | /* End XCBuildConfiguration section */ 259 | 260 | /* Begin XCConfigurationList section */ 261 | 7B5D9D051B6AD0EA00CF3A83 /* Build configuration list for PBXProject "ReactNativeLocalization" */ = { 262 | isa = XCConfigurationList; 263 | buildConfigurations = ( 264 | 7B5D9D1C1B6AD0EA00CF3A83 /* Debug */, 265 | 7B5D9D1D1B6AD0EA00CF3A83 /* Release */, 266 | ); 267 | defaultConfigurationIsVisible = 0; 268 | defaultConfigurationName = Release; 269 | }; 270 | 7B5D9D1E1B6AD0EA00CF3A83 /* Build configuration list for PBXNativeTarget "ReactNativeLocalization" */ = { 271 | isa = XCConfigurationList; 272 | buildConfigurations = ( 273 | 7B5D9D1F1B6AD0EA00CF3A83 /* Debug */, 274 | 7B5D9D201B6AD0EA00CF3A83 /* Release */, 275 | ); 276 | defaultConfigurationIsVisible = 0; 277 | defaultConfigurationName = Release; 278 | }; 279 | /* End XCConfigurationList section */ 280 | }; 281 | rootObject = 7B5D9D021B6AD0EA00CF3A83 /* Project object */; 282 | } 283 | -------------------------------------------------------------------------------- /ios/ReactNativeLocalization.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /ios/ReactNativeLocalization.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /ios/ReactNativeLocalization.xcodeproj/project.xcworkspace/xcshareddata/ReactNativeLocalization.xccheckout: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDESourceControlProjectFavoriteDictionaryKey 6 | 7 | IDESourceControlProjectIdentifier 8 | 81A0085F-DDFD-451B-A882-43549A511F8F 9 | IDESourceControlProjectName 10 | ReactNativeLocalization 11 | IDESourceControlProjectOriginsDictionary 12 | 13 | B7FD525F96D7EA8A0653E405FC9D642AE5C5FFE4 14 | https://github.com/stefalda/ReactNativeLocalization.git 15 | 16 | IDESourceControlProjectPath 17 | ReactNativeLocalization.xcodeproj 18 | IDESourceControlProjectRelativeInstallPathDictionary 19 | 20 | B7FD525F96D7EA8A0653E405FC9D642AE5C5FFE4 21 | ../.. 22 | 23 | IDESourceControlProjectURL 24 | https://github.com/stefalda/ReactNativeLocalization.git 25 | IDESourceControlProjectVersion 26 | 111 27 | IDESourceControlProjectWCCIdentifier 28 | B7FD525F96D7EA8A0653E405FC9D642AE5C5FFE4 29 | IDESourceControlProjectWCConfigurations 30 | 31 | 32 | IDESourceControlRepositoryExtensionIdentifierKey 33 | public.vcs.git 34 | IDESourceControlWCCIdentifierKey 35 | B7FD525F96D7EA8A0653E405FC9D642AE5C5FFE4 36 | IDESourceControlWCCName 37 | react-native-localization 38 | 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /ios/ReactNativeLocalization.xcodeproj/project.xcworkspace/xcuserdata/stefano.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stefalda/ReactNativeLocalization/1bfb1ebc97b783359f86b147c45cfadcc603f73b/ios/ReactNativeLocalization.xcodeproj/project.xcworkspace/xcuserdata/stefano.xcuserdatad/UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /ios/ReactNativeLocalization.xcodeproj/xcuserdata/stefano.xcuserdatad/xcschemes/ReactNativeLocalization.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 29 | 35 | 36 | 37 | 38 | 39 | 44 | 45 | 47 | 53 | 54 | 55 | 56 | 57 | 63 | 64 | 65 | 66 | 67 | 68 | 78 | 79 | 85 | 86 | 87 | 88 | 89 | 90 | 96 | 97 | 103 | 104 | 105 | 106 | 108 | 109 | 112 | 113 | 114 | -------------------------------------------------------------------------------- /ios/ReactNativeLocalization.xcodeproj/xcuserdata/stefano.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | ReactNativeLocalization.xcscheme 8 | 9 | orderHint 10 | 0 11 | 12 | 13 | SuppressBuildableAutocreation 14 | 15 | 7B5D9D091B6AD0EA00CF3A83 16 | 17 | primary 18 | 19 | 20 | 7B5D9D141B6AD0EA00CF3A83 21 | 22 | primary 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /lib/LocalizedStrings.d.ts: -------------------------------------------------------------------------------- 1 | declare module 'react-native-localization' { 2 | type Formatted = number | string | JSX.Element; 3 | type FormatObject = { [key: string]: U }; 4 | 5 | export interface GlobalStrings { 6 | [language: string]: T; 7 | } 8 | 9 | export interface LocalizedStringsMethods { 10 | /** 11 | * Can be used from outside the class to force a particular language 12 | * independently from the interface one 13 | * @param language 14 | */ 15 | setLanguage(language: string): void; 16 | 17 | /** 18 | * The current language displayed (could differ from the interface language 19 | * if it has been forced manually and a matching translation has been found) 20 | */ 21 | getLanguage(): string; 22 | 23 | /** 24 | * The current interface language (could differ from the language displayed) 25 | */ 26 | getInterfaceLanguage(): string; 27 | 28 | /** 29 | * Format the passed string replacing the numbered placeholders 30 | * i.e. I'd like some {0} and {1}, or just {0} 31 | * Use example: 32 | * strings.formatString(strings.question, strings.bread, strings.butter) 33 | */ 34 | formatString(str: string, ...values: Array>): Array | string; 35 | 36 | /** 37 | * Return an array containing the available languages passed as props in the constructor 38 | */ 39 | getAvailableLanguages(): string[]; 40 | 41 | /** 42 | * Return a string with the passed key in a different language 43 | * @param key 44 | * @param language 45 | */ 46 | getString(key: string, language?: string): string; 47 | 48 | 49 | /** 50 | * Replace the NamedLocalization object without reinstantiating the object 51 | * @param props 52 | */ 53 | setContent(props: any): void; 54 | } 55 | 56 | export type LocalizedStrings = LocalizedStringsMethods & T; 57 | 58 | interface LocalizedStringsFactory { 59 | new (props: GlobalStrings): LocalizedStrings; 60 | } 61 | 62 | const LocalizedStrings: LocalizedStringsFactory 63 | 64 | export default LocalizedStrings 65 | } 66 | -------------------------------------------------------------------------------- /lib/LocalizedStrings.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Class to localize the ReactNative interface 3 | * 4 | * Originally developed by Stefano Falda (stefano.falda@gmail.com) 5 | * 6 | * It uses a native library (ReactLocalization) to get the current interface language, 7 | * then display the correct language strings or the default language (the first 8 | * one if a match is not found). 9 | * 10 | * How to use: 11 | * Check the instructions at: 12 | * https://github.com/stefalda/ReactNativeLocalization 13 | */ 14 | "use strict"; 15 | 16 | Object.defineProperty(exports, "__esModule", { 17 | value: true 18 | }); 19 | 20 | var _reactNative = require("react-native"); 21 | 22 | var _reactLocalization = require("react-localization"); 23 | 24 | var _reactLocalization2 = _interopRequireDefault(_reactLocalization); 25 | 26 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } 27 | 28 | function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } 29 | 30 | function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } 31 | 32 | function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } 33 | 34 | /** 35 | * Import the native module 36 | */ 37 | var localization = _reactNative.NativeModules.ReactLocalization; 38 | /** 39 | * Check if the native module has been correctly initialized 40 | */ 41 | if (!localization) { 42 | console.error("Something went wrong initializing the native ReactNativeLocalization module.\nPlease check your configuration.\nDid you run 'react-native link'?"); 43 | } 44 | 45 | /** 46 | * Custom Interface Language method returned by native code 47 | */ 48 | function getInterfaceLanguage() { 49 | return localization.language.replace(/_/g, "-"); 50 | } 51 | 52 | /** 53 | * Extend the react-localization class overriding the getInterfaceLanguage method 54 | * to use the native module 55 | */ 56 | 57 | var LocalizedStrings = function (_LocalizedStringsCore) { 58 | _inherits(LocalizedStrings, _LocalizedStringsCore); 59 | 60 | function LocalizedStrings(props) { 61 | _classCallCheck(this, LocalizedStrings); 62 | 63 | return _possibleConstructorReturn(this, (LocalizedStrings.__proto__ || Object.getPrototypeOf(LocalizedStrings)).call(this, props, { customLanguageInterface: getInterfaceLanguage })); 64 | } 65 | 66 | return LocalizedStrings; 67 | }(_reactLocalization2.default); 68 | 69 | exports.default = LocalizedStrings; -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "react-native-localization", 3 | "version": "2.3.2", 4 | "description": "Simple module to localize the ReactNative interface", 5 | "main": "./lib/LocalizedStrings.js", 6 | "types": "./lib/LocalizedStrings.d.ts", 7 | "scripts": { 8 | "test": "echo \"Error: no test specified\" && exit 1", 9 | "build": "babel src --out-dir lib" 10 | }, 11 | "repository": { 12 | "type": "git", 13 | "url": "https://github.com/stefalda/ReactNativeLocalization.git" 14 | }, 15 | "keywords": [ 16 | "localization", 17 | "internationalization", 18 | "javascript", 19 | "typescript", 20 | "ios", 21 | "android", 22 | "react", 23 | "react-native", 24 | "react-component" 25 | ], 26 | "author": "Stefano Falda (http://www.babisoft.com)", 27 | "license": "MIT", 28 | "bugs": { 29 | "url": "https://github.com/stefalda/ReactNativeLocalization/issues" 30 | }, 31 | "homepage": "https://github.com/stefalda/ReactNativeLocalization", 32 | "dependencies": { 33 | "react-localization": "^1.0.17" 34 | }, 35 | "devDependencies": { 36 | "babel-cli": "^6.26.0", 37 | "babel-preset-env": "^1.6.1" 38 | }, 39 | "peerDependencies": { 40 | "react-native": ">0.64", 41 | "react-native-windows": ">0.64", 42 | "react": ">15.6.0" 43 | }, 44 | "peerDependenciesMeta": { 45 | "react-native-windows": { 46 | "optional": true 47 | } 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/LocalizedStrings.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Class to localize the ReactNative interface 3 | * 4 | * Originally developed by Stefano Falda (stefano.falda@gmail.com) 5 | * 6 | * It uses a native library (ReactLocalization) to get the current interface language, 7 | * then display the correct language strings or the default language (the first 8 | * one if a match is not found). 9 | * 10 | * How to use: 11 | * Check the instructions at: 12 | * https://github.com/stefalda/ReactNativeLocalization 13 | */ 14 | "use strict"; 15 | import { NativeModules } from "react-native"; 16 | import LocalizedStringsCore from "react-localization"; 17 | /** 18 | * Import the native module 19 | */ 20 | const localization = NativeModules.ReactLocalization; 21 | /** 22 | * Check if the native module has been correctly initialized 23 | */ 24 | if (!localization) { 25 | console.error( 26 | "Something went wrong initializing the native ReactNativeLocalization module.\nPlease check your configuration.\nDid you run 'react-native link'?" 27 | ); 28 | } 29 | 30 | /** 31 | * Custom Interface Language method returned by native code 32 | */ 33 | function getInterfaceLanguage() { 34 | return localization.language.replace(/_/g, "-"); 35 | } 36 | 37 | /** 38 | * Extend the react-localization class overriding the getInterfaceLanguage method 39 | * to use the native module 40 | */ 41 | export default class LocalizedStrings extends LocalizedStringsCore { 42 | constructor(props) { 43 | super(props, { customLanguageInterface: getInterfaceLanguage }); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /windows/ReactNativeLocalization/.gitignore: -------------------------------------------------------------------------------- 1 | *AppPackages* 2 | *BundleArtifacts* 3 | 4 | #OS junk files 5 | [Tt]humbs.db 6 | *.DS_Store 7 | 8 | #Visual Studio files 9 | *.[Oo]bj 10 | *.user 11 | *.aps 12 | *.pch 13 | *.vspscc 14 | *.vssscc 15 | *_i.c 16 | *_p.c 17 | *.ncb 18 | *.suo 19 | *.tlb 20 | *.tlh 21 | *.bak 22 | *.[Cc]ache 23 | *.ilk 24 | *.log 25 | *.lib 26 | *.sbr 27 | *.sdf 28 | *.opensdf 29 | *.opendb 30 | *.unsuccessfulbuild 31 | ipch/ 32 | [Oo]bj/ 33 | [Bb]in 34 | [Dd]ebug*/ 35 | [Rr]elease*/ 36 | Ankh.NoLoad 37 | 38 | # Visual C++ cache files 39 | ipch/ 40 | *.aps 41 | *.ncb 42 | *.opendb 43 | *.opensdf 44 | *.sdf 45 | *.cachefile 46 | *.VC.db 47 | *.VC.VC.opendb 48 | 49 | #MonoDevelop 50 | *.pidb 51 | *.userprefs 52 | 53 | #Tooling 54 | _ReSharper*/ 55 | *.resharper 56 | [Tt]est[Rr]esult* 57 | *.sass-cache 58 | 59 | #Project files 60 | [Bb]uild/ 61 | 62 | #Subversion files 63 | .svn 64 | 65 | # Office Temp Files 66 | ~$* 67 | 68 | # vim Temp Files 69 | *~ 70 | 71 | #NuGet 72 | packages/ 73 | *.nupkg 74 | 75 | #ncrunch 76 | *ncrunch* 77 | *crunch*.local.xml 78 | 79 | # visual studio database projects 80 | *.dbmdl 81 | 82 | #Test files 83 | *.testsettings 84 | 85 | #Other files 86 | *.DotSettings 87 | .vs/ 88 | *project.lock.json 89 | 90 | #production manifest and association 91 | *_pkginfo.txt -------------------------------------------------------------------------------- /windows/ReactNativeLocalization/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("ReactNativeLocalization")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("ReactNativeLocalization")] 13 | [assembly: AssemblyCopyright("Copyright © 2018")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Version information for an assembly consists of the following four values: 18 | // 19 | // Major Version 20 | // Minor Version 21 | // Build Number 22 | // Revision 23 | // 24 | // You can specify all the values or you can default the Build and Revision Numbers 25 | // by using the '*' as shown below: 26 | // [assembly: AssemblyVersion("1.0.*")] 27 | [assembly: AssemblyVersion("1.0.0.0")] 28 | [assembly: AssemblyFileVersion("1.0.0.0")] 29 | [assembly: ComVisible(false)] -------------------------------------------------------------------------------- /windows/ReactNativeLocalization/Properties/ReactNativeLocalization.rd.xml: -------------------------------------------------------------------------------- 1 | 2 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /windows/ReactNativeLocalization/RNLocalizationModule.cs: -------------------------------------------------------------------------------- 1 | using ReactNative.Bridge; 2 | using ReactNative.Bridge.Queue; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Linq; 6 | using System.Text; 7 | using System.Threading.Tasks; 8 | 9 | namespace ReactNativeLocalization 10 | { 11 | public class RNLocalizationModule : ReactContextNativeModuleBase, ILifecycleEventListener 12 | { 13 | private const String LANGUAGE = "language"; 14 | 15 | public RNLocalizationModule(ReactContext reactContext) 16 | : base(reactContext) 17 | { 18 | 19 | } 20 | 21 | public override string Name => "ReactLocalization"; 22 | 23 | public override IReadOnlyDictionary Constants => new Dictionary() 24 | { 25 | { LANGUAGE, GetCurrentLanguage() } 26 | }; 27 | 28 | public void OnSuspend() 29 | { 30 | } 31 | 32 | public void OnResume() 33 | { 34 | } 35 | 36 | public void OnDestroy() 37 | { 38 | } 39 | 40 | private string GetCurrentLanguage() 41 | { 42 | return Windows.Globalization.Language.CurrentInputMethodLanguageTag; 43 | } 44 | 45 | [ReactMethod] 46 | public void getLanguage(ICallback callback) 47 | { 48 | var language = GetCurrentLanguage(); 49 | 50 | if (callback != null) 51 | { 52 | callback.Invoke(null, language); 53 | } 54 | } 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /windows/ReactNativeLocalization/RNLocalizationPackage.cs: -------------------------------------------------------------------------------- 1 | using ReactNative.Bridge; 2 | using ReactNative.Modules.Core; 3 | using ReactNative.UIManager; 4 | using System; 5 | using System.Collections.Generic; 6 | using System.Linq; 7 | using System.Text; 8 | using System.Threading.Tasks; 9 | 10 | namespace ReactNativeLocalization 11 | { 12 | public class RNLocalizationPackage : IReactPackage 13 | { 14 | public IReadOnlyList CreateNativeModules(ReactContext reactContext) 15 | { 16 | return new List() 17 | { 18 | new RNLocalizationModule(reactContext) 19 | }; 20 | } 21 | 22 | public IReadOnlyList CreateViewManagers(ReactContext reactContext) 23 | { 24 | return new List(); 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /windows/ReactNativeLocalization/ReactNativeLocalization.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {CBC14812-59A5-4BFA-B1DF-E910AE6C92A2} 8 | Library 9 | Properties 10 | ReactNativeLocalization 11 | ReactNativeLocalization 12 | en-US 13 | UAP 14 | 10.0.16299.0 15 | 10.0.10240.0 16 | 14 17 | 512 18 | {A5A43C5B-DE2A-4C0C-9213-0A381AF9435A};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} 19 | 20 | 21 | AnyCPU 22 | true 23 | full 24 | false 25 | bin\Debug\ 26 | DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP 27 | prompt 28 | 4 29 | 30 | 31 | AnyCPU 32 | pdbonly 33 | true 34 | bin\Release\ 35 | TRACE;NETFX_CORE;WINDOWS_UWP 36 | prompt 37 | 4 38 | 39 | 40 | x86 41 | true 42 | bin\x86\Debug\ 43 | DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP 44 | ;2008 45 | full 46 | x86 47 | false 48 | prompt 49 | 50 | 51 | x86 52 | bin\x86\Release\ 53 | TRACE;NETFX_CORE;WINDOWS_UWP 54 | true 55 | ;2008 56 | pdbonly 57 | x86 58 | false 59 | prompt 60 | 61 | 62 | ARM 63 | true 64 | bin\ARM\Debug\ 65 | DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP 66 | ;2008 67 | full 68 | ARM 69 | false 70 | prompt 71 | 72 | 73 | ARM 74 | bin\ARM\Release\ 75 | TRACE;NETFX_CORE;WINDOWS_UWP 76 | true 77 | ;2008 78 | pdbonly 79 | ARM 80 | false 81 | prompt 82 | 83 | 84 | x64 85 | true 86 | bin\x64\Debug\ 87 | DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP 88 | ;2008 89 | full 90 | x64 91 | false 92 | prompt 93 | 94 | 95 | x64 96 | bin\x64\Release\ 97 | TRACE;NETFX_CORE;WINDOWS_UWP 98 | true 99 | ;2008 100 | pdbonly 101 | x64 102 | false 103 | prompt 104 | 105 | 106 | PackageReference 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 6.0.6 117 | 118 | 119 | 120 | 121 | {c7673ad5-e3aa-468c-a5fd-fa38154e205c} 122 | ReactNative 123 | 124 | 125 | 126 | 14.0 127 | 128 | 129 | 136 | -------------------------------------------------------------------------------- /windows/ReactNativeLocalization/ReactNativeLocalization.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 15 4 | VisualStudioVersion = 15.0.27130.2027 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ReactNativeLocalization", "ReactNativeLocalization.csproj", "{CBC14812-59A5-4BFA-B1DF-E910AE6C92A2}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|Any CPU = Debug|Any CPU 11 | Debug|ARM = Debug|ARM 12 | Debug|x64 = Debug|x64 13 | Debug|x86 = Debug|x86 14 | Release|Any CPU = Release|Any CPU 15 | Release|ARM = Release|ARM 16 | Release|x64 = Release|x64 17 | Release|x86 = Release|x86 18 | EndGlobalSection 19 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 20 | {CBC14812-59A5-4BFA-B1DF-E910AE6C92A2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 21 | {CBC14812-59A5-4BFA-B1DF-E910AE6C92A2}.Debug|Any CPU.Build.0 = Debug|Any CPU 22 | {CBC14812-59A5-4BFA-B1DF-E910AE6C92A2}.Debug|ARM.ActiveCfg = Debug|ARM 23 | {CBC14812-59A5-4BFA-B1DF-E910AE6C92A2}.Debug|ARM.Build.0 = Debug|ARM 24 | {CBC14812-59A5-4BFA-B1DF-E910AE6C92A2}.Debug|x64.ActiveCfg = Debug|x64 25 | {CBC14812-59A5-4BFA-B1DF-E910AE6C92A2}.Debug|x64.Build.0 = Debug|x64 26 | {CBC14812-59A5-4BFA-B1DF-E910AE6C92A2}.Debug|x86.ActiveCfg = Debug|x86 27 | {CBC14812-59A5-4BFA-B1DF-E910AE6C92A2}.Debug|x86.Build.0 = Debug|x86 28 | {CBC14812-59A5-4BFA-B1DF-E910AE6C92A2}.Release|Any CPU.ActiveCfg = Release|Any CPU 29 | {CBC14812-59A5-4BFA-B1DF-E910AE6C92A2}.Release|Any CPU.Build.0 = Release|Any CPU 30 | {CBC14812-59A5-4BFA-B1DF-E910AE6C92A2}.Release|ARM.ActiveCfg = Release|ARM 31 | {CBC14812-59A5-4BFA-B1DF-E910AE6C92A2}.Release|ARM.Build.0 = Release|ARM 32 | {CBC14812-59A5-4BFA-B1DF-E910AE6C92A2}.Release|x64.ActiveCfg = Release|x64 33 | {CBC14812-59A5-4BFA-B1DF-E910AE6C92A2}.Release|x64.Build.0 = Release|x64 34 | {CBC14812-59A5-4BFA-B1DF-E910AE6C92A2}.Release|x86.ActiveCfg = Release|x86 35 | {CBC14812-59A5-4BFA-B1DF-E910AE6C92A2}.Release|x86.Build.0 = Release|x86 36 | EndGlobalSection 37 | GlobalSection(SolutionProperties) = preSolution 38 | HideSolutionNode = FALSE 39 | EndGlobalSection 40 | GlobalSection(ExtensibilityGlobals) = postSolution 41 | SolutionGuid = {C5164E80-0E31-48A1-B9B4-6789CC706D24} 42 | EndGlobalSection 43 | EndGlobal 44 | --------------------------------------------------------------------------------