Swiftgen: Allow runtime change of locale/language

Created on 8 May 2018  路  9Comments  路  Source: SwiftGen/SwiftGen

I am allowing users to change the language of my app.

But if I use the L10n enum. The string will be loaded the first time it's needed, which is as it should be.
However, when the user changes the language of the app, the L10n enum should also be reset.

Would that be possible?

Just a custom template away! Easiest way to contribute! question

Most helpful comment

@djbe How about this version of template https://gist.github.com/AndreyLunevich/5c30b116ee12102574eabdc36bfbb6d5 ?

If need to change language:

L10n.bundle = L10n.bundle = Bundle(path: Bundle.main.path(forResource: "by", ofType: "lproj")!)

As a result user will not break compatibility with other templates.

All 9 comments

You can always write your own templates to provide this functionality. For information on how to do so, please check the documentation for this.

A suggestion would be to change the static lets to computed variables:

internal static var footerText: String {
  return L10n.tr("Localizable", "settings.user_profile_section.footer_text")
}

And to change the L10n.tr(...) function to take into account your translation system.

I've made the template. Would like a PR to add it to the main repo?

I'm not sure if this would be a template that would generally be usable? Could you provide a gist of the template & output?

AFAIK you can't simply change the strings language at runtime. It either uses:

  • Hacks with the UserDefaults that almost never work, or
  • You use your own functions to load strings from a specific language bundle. I even wrote a library for this at some point: https://bitbucket.org/djbe/djlocalization

In the latter case (using your own functions for strings), that's something that would be an external dependency for the the generated code, which we (try to) avoid for the built-in templates.

Yeah, you are right. But it was a requirement from my client.

Our solution was to hack the NSBundle, to trick him into read the strings from the specified language bundle.

I've used something similar to this (I converted it to swift mostly):
https://gist.github.com/narikbi/352e93e446e8b1faf283

This is a tricky hack I agree. And perhaps not everyone will want this template.

IMHO there's no added value here for most users, as they won't use hacks to change the functionality of NSLocalizedString, and the default implementation of that function won't change the value at runtime, which is why we use constants.

What could be of interest is adding a parameter stringFunction (or some other name, I'm bad at naming things), that by default has as value NSLocalizedString. If the user provides a custom value, we could automatically switch to generating vars instead of lets, and use it instead of NSLocalizedString. A PR to implement this would be welcome.

@djbe How about this version of template https://gist.github.com/AndreyLunevich/5c30b116ee12102574eabdc36bfbb6d5 ?

If need to change language:

L10n.bundle = L10n.bundle = Bundle(path: Bundle.main.path(forResource: "by", ofType: "lproj")!)

As a result user will not break compatibility with other templates.

The bundled templates in 6.2 have a lookupFunction parameter which, if set, ensure that the generated code does not work with let constants and fetches the translated string on each get access.

See here for an example of generated code: https://github.com/SwiftGen/SwiftGen/blob/stable/Tests/Fixtures/Generated/Strings/structured-swift5/localizable-lookupFunction.swift
And check the template docs here: https://github.com/SwiftGen/SwiftGen/tree/stable/Documentation/templates/strings

Was this page helpful?
0 / 5 - 0 ratings

Related issues

marcelofabri picture marcelofabri  路  6Comments

valerianb picture valerianb  路  7Comments

kacper1703 picture kacper1703  路  3Comments

drjasonharrison picture drjasonharrison  路  5Comments

taykay08 picture taykay08  路  3Comments