
NSLocalizedString family. We have created a set of similar methods BPFLocalizedString (the BPF prefix means Badoo Platform Foundation) and use them throughout the application. "Under the hood" BPFLocalizedString uses a localization service that contains all the data and implements the basic functionality. We save all updates from the server in a separate bundle. When the client code requests a localized string, we look for the necessary message in this bundle and, if necessary, return to the default localization bundle. public func localizedStringForKey(_ key: String) - > String { let str = self.localizationsBundle.localizedString(forKey: key) return str == key ? Bundle.main.localizedString(forKey: key, value: nil, table: nil) : str } BPFLocalizedString API for BPFLocalizedString looks like this: NSString * __nonnull BPFLocalizedString(NSString * __nonnull key, NSString * __nullable comment); public func BPFLocalizedString(_ key: String) - > String { return BPFGlobals.shared().localizedStringsService.localizedStringForKey( key) } NSLocalizedString with the corresponding BPFLocalizedString . Fortunately, this task can be easily solved using automatic scripts. Another limitation is the impossibility of applying BPFLocalizedString directly to statically packaged user interface elements (XIB and Storyboard). This is a completely natural limitation, since we replace the static localization with the dynamic one.Resources is part of the Context interface. Resources provides the configuration of the current device (location, screen size, orientation, and so on). One solution is to replace all Resources.getString() with our own custom implementation, as in iOS. But we chose a more elegant way.Resources instead of the system one? Fortunately, this is possible! Take the Activity class, write its successor, and apply it everywhere: public abstract class BaseActivity extends Activity { private Resources mResources; public Resources getResources() { if (mResources == null) { Resources r = super.getResources(); mResources = new ResourceWrapper(this, r); } return mResources; } } Resources to retrieve the updated values ​​of the tokens: public class ResourceWrapper extends Resources { private final Resources mResources; private final LexemeProvider mLexemeProvider; public ResourceWrapper(Context context, Resources r) { super(r.getAssets(), r.getDisplayMetrics(), r.getConfiguration()); mResources = resources; mLexemeProvider = new LexemeProvider(...); } @Override public String getString(@StringRes int id) throws NotFoundException{ String hotString = mLexemeProvider.getString(id); if (hotString == null) { return mResources.getString(id); } else { return hotString; } // Override each method and return corresponding value from mResources @Override public boolean getBoolean(int id) throws NotFoundException { return mResources.getBoolean(id); } } ResourceWrapper to this particular implementation ( mResources in our case).TextView calls context.getTheme (). ObtainStyledAttributes (...) .getText (...) to get the corresponding values, in which case our replacement for Resources no longer works.LocalizationProvider here too. public class DynamicLexemeInflater { private static void applyDynamicLexems(View view, String name, Context context, AttributeSet attrs) { if (view instanceof TextView) { TextView textView = (TextView) view; TypedArray typedArray = context.obtainStyledAttributes(attrs, new int[] { android.R.attr.text, android.R.attr.hint }); int textResourceId = typedArray.getResourceId(0, -1); if (textResourceId != -1) { String dispatchedString = context.getString(textResourceId); textView.setText(dispatchedString); } int hintResourceId = typedArray.getResourceId(1, -1); if (hintResourceId != -1) { String dispatchedString = context.getString(hintResourceId); textView.setHint(dispatchedString); } typedArray.recycle(); } } InflaterFactory to add “post-processing” “inflated” views in which text values ​​are specified.AppResources class (or you can give it any other name), which contains static getters for all strings used in the application. Here is what is inside these getters: public static string ApplicationTitle { get { return ResourceManager.GetString("ApplicationTitle", resourceCulture); } } ResourceManager property is used here, defined as public static global::System.Resources.ResourceManager ResourceManager { get { if (object.ReferenceEquals(resourceMan, null)) { global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("PhoneApp.Resources.AppResources", typeof (AppResources).Assembly); resourceMan = temp; } return resourceMan; } } System.Resources.ResourceManager is a central component of the localization API, it takes all the hard work of loading current string values. Fortunately, in the overloaded method it has an extension point:public virtual string GetString(string name, CultureInfo culture) . That is what we need to implement our machinery and to supplement the means provided by the system. It is necessary only to inherit from this class and overload the GetString method: public class UpdateableResourceManager: ResourceManager { public override string GetString(string name, CultureInfo culture) { var lexemesHandler = _localizationService.GetLexemesHandler(culture); return lexemesHandler?.GetLexeme(name)?.Value?.Text ?? base.GetString(name, culture); } } UpdateableResourceManager instead of what is used by default in the AppResources class. But since this class is automatically generated, you also need to gain control over the generation in order to add your data to the resulting file. This is usually done every time you open the AppResources file in Visual Studio, but you can do it manually (or automatically in the script) using the RESGen tool, as in this PowerShell example: $resgenPath = “C:\Program Files (x86)\Microsoft SDKs\Windows\v10.0A\bin\NETFX 4.6 Tools\ResGen.exe” & $resgenPath AppResources.resx to_delete.txt “/str:cs,Badoo.Is.Ponies.Namespace,AppResources,AppResources.Designer.cs” / publicclass Remove — Item “to_delete.txt” System.Resources.ResourceManager line in our Badoo.Next.Big.Thing.UpdateableResourceManager . The rest is processed in a separate LocalizationService, which is responsible for all the work with the network, data storage and retrieval.Source: https://habr.com/ru/post/348350/
All Articles