Closed Ewg777 closed 8 years ago
Thanks for this interesting suggestion! Could you explain a little bit more about your vision on how this would work?
I think lot of developers type something like NSLocalizedString("Please login when you're ready!", comment: "Login screen header")
and then extract that to a .strings
file. That's not a case where R.swift would be really handy I think.
When using keys in localized strings maybe it's handier? A concrete example of how you would like it to work would be nice!
For example like this http://developer.android.com/guide/topics/resources/string-resource.html
Yeah, I get you're inspired by the Android way. I believe we should think a little more about how this works out and integrates into the daily workflow of developers, but I definitly like the idea!
Ah nice example! Thanks for posting it here! :)
Definitely something to look into and implement in R.swift.
After talking with @tomlokhorst about this; I think that it will be hard to get a good solution that fits within the workflow. For example the SwiftGen style of working with string doesn't really show how they add new strings.
@mac-cain13 Could you generate string code like this:
struct string {
static var bar_title: String? { return CustomLocalizedString("bar_title") }
}
Then, create one file to implement function CustomLocalizedString
, and developer can modify this file.
public func CustomLocalizedString(key: String) -> String {
// DEV coding ....
return NSLocalizedString(key, comment: "");
}
JiriTrecak/Laurine also does this trick
Let's not forget strings dictionaries if we do that :)
I'm all for localised string generation, but I think there should be a way to access the string key separately so we can still use NSLocalizedString(). It's very useful to keep the macro/method as Xcode has tools that generate files based on it and it allows you to add more context to what you are using the text for.
I haven't tested it yet, but Xcode 7.3 also has string localisation testing in the static analyser, so thats another reason to keep the string keys available for reference.
In my opinion there are two basic approaches to doing localized strings in Xcode:
genstring
to create a Localizable.strings file.
This is where you have code like this: NSLocalizedString("Please login when you're ready!", comment: "Login screen header")
NSLocalizedString("login_screen.header_notice", comment: "")
I don't think R.swift can do much to support the first approach. However, it can definitely support the second approach.
The generated struct in R.strings.*
can include the hierarchy in keys, like login_screen.header_notice
.
Comments in the Localizable.strings file can be included as comments in the generated structs.
Also see "Programming Resources" at https://developer.apple.com/internationalization/
I currently work on a team that uses R.swift for every resource but colors and localized strings. For those two, we are using SwiftGen, like mentioned above. I feel that R.swift has the opportunity to offer a more convenient and well-integrated solution for teams because it is offered through CocoaPods, making it trivial to integrate with an Xcode project without the need to have a tool installed on each team members' local machine (which is why I love R.swift to begin with!!!).
@mac-cain13 I was wondering if you could elaborate more on what you mean by finding it hard to get a good solution that fits within the workflow. I feel like the workflow for developers would be the same as with the other aspects of R.swift. For example, a developer creates a storyboard file using Xcode's tools,, then uses R.swift with access parts of that storyboard in code. I envision the same workflow with strings, where the developer creates / adds strings to their Localizable.string file, then uses R.swift to access those strings in code. Is this not the workflow you were referring to?
I agree with @tomlokhorst latest comment and also with your approach @renrawnalon. I was overcomplicating and overthinking the problem a bit earlier.
It's clear that we should read strings files, probably combine those if there are multiple?! (Is that possible, how does that exactly work?) And then output them to R.strings.*
as @tomlokhorst proposes. As a developer you update the *.strings
file and R.swift will pick up the new key.
And as a reminder to self:
Let's not forget strings dictionaries if we do that :)
Yeah, that's exactly what I had in mind.
Regarding multiple Localizable.strings files, ideally, there would be some sort of validation to ensure that all of the language files contain all of the same keys.
For example, this would be a valid set of .strings files:
/* en.lproj/Localizable.strings */
"myString.one" = "One";
"myString.two" = "Two: %@";
/* es.lproj/Localizable.strings */
"myString.one" = "Uno";
"myString.two" = "Dos: %@";
This is valid because when you call NSLocalizedString("myString.one", comment: "")
there is a valid mapping for each language.
However,
/* en.lproj/Localizable.strings */
"myString.one" = "One";
/* es.lproj/Localizable.strings */
"myString.two" = "Dos: %@";
This would fail validation, either throwing a warning, but more likely an error? because there are missing mappings.
With this strict compile-time and/or run-time validation, the developer could be sure that all keys have valid mappings, removing the possible error of accidentally forgetting to add a translation in a certain language. This is surprisingly easy to forget when you are working with lots of localization files because Xcode doesn't warn you about it.
The resulting output from the above input would ideally look something like this (implementation details aside):
struct R: Rswift.Validatable {
...
struct string {
static let myStringOne = LocalizedString("myString.one")
static let myStringTwo = { (value1: String) in LocalizedString("myString.one", value1) }
}
...
}
This is only slightly related to this issue, but maybe also interesting to consider:
@renrawnalon Could you elaborate on how you use colors from SwiftGen?
I don't understand the benefit of writing a colors.txt file:
Cyan : 0xff66ccff
ArticleTitle : #33fe66
Couldn't you just as easily write Colors.swift?
struct Colors {
static let Cyan = UIColor(hex: 0xFF66CCFF)
static let ArticleTitle = UIColor(hex: 0x33FE66)
}
For localization, using Localizable.strings seems obvious because it's already part of the ecosystem. But I don't see this for colors?
@tomlokhorst I actually use swiftgen colors
with color palette files (.clr) which support was recently added for, not with .txt files. Using a .clr file in combination with SwiftGen, my team is able to manage colors in Interface Builder with a custom color palette, then use those color definitions in code as well. Another nice thing about .clr files is that they can be shared across mac applications, including Photoshop, Illustrator, and likely Sketch, so the design team can keep the .clr file for a project up to date, and the development team, can use that file to implement design in IB or in code for dynamic UIs.
Here is a quick read about how custom color palettes can be created and shared with your team, if you are not familiar with them.
As for using swiftgen colors
with a text file, I don't think there is much benefit, other than that you might be able to share that text file with (or have it populated by) other members of your project that are not familiar with Swift, like your design team. I personally haven't tried this, and in practice, it might not prove to be useful.
If you don't use Storyboards to create your UI or you don't work on a team, and you arethe sole designer and developer for your apps, then I don't think it would make sense to use SwiftGen for colors, but it's quick convenient when working on a team.
@renrawnalon Right, I see. That makes sense. Thanks!
I've created an issue for discussing R.colors further: https://github.com/mac-cain13/R.swift/issues/169
+1 for adding localized string support similar to SwiftGen
I've created a pull request that is the first step in solving this issue. So far, I have only implemented parsing with Localization.strings keys without printf style formatting support or .stringsdict support. I figured the PR would have been to large if I included all of these at once, but I am already working on figuring out how to do the format parsing. I'm thinking a regex should be sufficient, but if anyone has any suggestions, I'm all ears. However, I believe that this PR is plenty useful as is, and I think releasing this version, then later adding support for printf formatting and .stringsdict file would work out nicely.
One potential problem with this approach would be that when printf formatting support is added, it would break existing code by change this:
R.string.myFormattedKey
to this:
R.string.myFormattedKey(value)
This might be a welcome breaking change, but this is definitely something that needs to be taken into consideration.
@mac-cain13 I know you've been busy recently, but I would appreciate it if you could take a look at this when you have time and let me know what you think about both the PR and the problem that I presented above.
Thanks!
Thanks to @tomlokhorst and @renrawnalon localized strings have landed in R.swift! 🛬
It's a big feature and I think a lot of people will be very happy with this. Enjoy! 🎉
Is there a reason why R.swift contrary to Laurine did not use nested structs for accessing parts of localized strings which are separated by a .
?
E.g. Laurine allows to write things like Localizations.Profile.NavigationBar.Items.Done
which looks very nice.
No there is no specific reason for this other then that it's in line with all other name conversions we have in the codebase. I agree it would be nice to have this behaviour, we also use this dot-pattern a lot in our own strings files and the conversion R.swift applies now makes it less convenient to read.
I think it would be a change to consider. I'll create a separate issue for this improvement so we can discuss/implement it!
Add new feature parsing .strings file