forked from stefalda/ReactNativeLocalization
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathLocalizedStrings.js
151 lines (139 loc) · 5.2 KB
/
LocalizedStrings.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
/**
* Class to localize the ReactNative interface
*
* Originally developed by Stefano Falda ([email protected])
*
* It uses a native library (ReactLocalization) to get the current interface language,
* then display the correct language strings or the default language (the first
* one if a match is not found).
*
* How to use:
* Check the instructions at:
* https://github.com/stefalda/ReactNativeLocalization
*/
'use strict';
var localization = require('react-native').NativeModules.ReactLocalization;
var interfaceLanguage = localization.language.replace(/_/g,'-');
class LocalizedStrings{
_getBestMatchingLanguage(language, props){
//If an object with the passed language key exists return it
if (props[language]) return language;
//if the string is multiple tags, try to match without the final tag
//(en-US --> en, zh-Hans-CN --> zh-Hans)
let idx = language.lastIndexOf("-");
if (idx>=0) {
language = language.substring(0,idx);
return this._getBestMatchingLanguage(language, props)
}
//Return the default language (the first coded)
return Object.keys(props)[0];
}
constructor(props) {
//Store locally the passed strings
this.props = props;
//Set language to its default value (the interface)
this.setLanguage(interfaceLanguage);
}
//Can be used from ouside the class to force a particular language
//indipendently from the interface one
setLanguage(language){
//Check if exists a translation for the current language or if the default
//should be used
var bestLanguage = this._getBestMatchingLanguage(language, this.props);
this.language = bestLanguage;
//Associate the language object to the this object
if (this.props[bestLanguage]){
//console.log("There are strings for the language:"+language);
var localizedStrings = this.props[this.language];
for (var key in localizedStrings){
//console.log("Checking property:"+key);
if (localizedStrings.hasOwnProperty(key)) {
//console.log("Associating property:"+key);
this[key] = localizedStrings[key];
}
}
//Now add any string missing from the translation but existing in the default language
var defaultLanguage = Object.keys(this.props)[0];
if (defaultLanguage!==this.language){
localizedStrings = this.props[defaultLanguage];
this._fallbackValues(localizedStrings, this);
}
}
}
//Load fallback values for missing translations
_fallbackValues(defaultStrings, strings){
for (var key in defaultStrings){
if (defaultStrings.hasOwnProperty(key) && !strings[key]) {
strings[key]=defaultStrings[key];
console.log("Missing localization for language '"+this.language+"' and key '"+key+"'.");
}
else {
if (typeof strings[key]!="string"){
//Si tratta di un oggetto
this._fallbackValues(defaultStrings[key], strings[key]);
}
}
}
}
//The current language displayed (could differ from the interface language
// if it has been forced manually and a matching translation has been found)
getLanguage(){
return this.language;
}
//The current interface language (could differ from the language displayed)
getInterfaceLanguage(){
return interfaceLanguage;
}
//Return an array containing the available languages passed as props in the constructor
getAvailableLanguages(){
if (!this.availableLanguages){
this.availableLanguages = [];
for(let language in this.props){
this.availableLanguages.push(language);
}
}
return this.availableLanguages;
}
//Format the passed string replacing the numbered placeholders
//i.e. I'd like some {0} and {1}, or just {0}
//Use example:
// strings.formatString(strings.question, strings.bread, strings.butter)
formatString(str, ...values){
var res = str;
for (let i=0; i<values.length;i++){
res = this._replaceAll("{"+i+"}", values[i], res);
}
return res;
}
//Return a string with the passed key in a different language
getString(key, language){
try{
return this.props[language][key];
} catch(ex){
console.log("No localization found for key "+ key +" and language " + language);
}
return null;
}
//Replace all occorrencies of a string in another using RegExp
_replaceAll(original, replacement, str) {
original = original.replace(/([.*+?^=!:${}()|\[\]\/\\])/g, "\\$1");
replacement = `${replacement}`.replace(/([$])/g, '$$$$');
return str.replace(new RegExp(original, 'g'), replacement);
}
//Can be used to retrieve the interface language
//but now it's useless because that value is exposed directly
//in a dictionary from the ReactLocalization class
//I leave it as an example but it's now deprecated
/*
_getLanguage(){
var deferred = Q.defer();
localization.getLanguage((error, deviceLanguage)=>{
var language = deviceLanguage;
console.log("Language in js:"+language);
deferred.resolve(language);
});
return deferred.promise;
}
*/
}
module.exports = LocalizedStrings;