Localizing a modern xib-based Mac application

后端 未结 4 619
野性不改
野性不改 2020-12-23 10:53

Ours is an open-source Mac application localized by volunteers. These volunteers will do their work on special localization builds of the software (with unstripped nibs), th

4条回答
  •  轮回少年
    2020-12-23 11:17

    Where I used to work, we had this issue as well. Our app was getting translated into 10 different languages.

    At first, we tried doing what Wil suggested, which is to make everything super wide and fit in every language. Unfortunately, "online backup" might be pretty short in English, but in other languages (especially Spanish), it's really long ("copia de seguridad" just means "backup"). Widening our UI made everything look pretty terrible.

    One day, I was playing around with some Core Animation stuff and discovered the CAConstraint class. CAConstraint is basically a way to define a layout relationship between two CALayers. You give one layer a name (like "layerA") and then say "layerB is constrained [in such-and-such a way] to a sibling layer called layerA". Then, whenever the layer named layerA is repositioned or resized, layerB automatically moves as well. It's really neat, and it's just what we were looking for.

    After a couple of days of work, I came up with what is now CHLayoutManager. It's basically a re-make of CAConstraint and friends, but for NSViews. Here's a simple example of how it works:

    CHLayoutConstraint * centerHorizontal = [CHLayoutConstraint constraintWithAttribute:CHLayoutConstraintAttributeMidX relativeTo:@"superview" attribute:CHLayoutConstraintAttributeMidX];
    CHLayoutConstraint * centerVertical = [CHLayoutConstraint constraintWithAttribute:CHLayoutConstraintAttributeMidY relativeTo:@"superview" attribute:CHLayoutConstraintAttributeMidY];
    [aView addConstraint:centerHorizontal];
    [aView addConstraint:centerVertical];
    

    This will keep aView centered in its superview, regardless of how the superview is resized. Here's another:

    [button1 setLayoutName:@"button1"];
    [button2 addConstraint:[CHLayoutConstraint constraintWithAttribute:CHLayoutConstraintAttributeMinX relativeTo:@"button1" attribute:CHLayoutConstraintAttributeMaxX]];
    [button2 addConstraint:[CHLayoutConstraint constraintWithAttribute:CHLayoutConstraintAttributeMaxY relativeTo:@"button1" attribute:CHLayoutConstraintAttributeMaxY]];
    [button2 addConstraint:[CHLayoutConstraint constraintWithAttribute:CHLayoutConstraintAttributeWidth relativeTo:@"button1" attribute:CHLayoutConstraintAttributeWidth]];
    

    This will keep button2 anchored to the right edge of button1, as well as keeping button2's Y position and width the same as button1's.

    Internally, CHLayoutManager uses an NSValueTransformer to calculate the new positioning information. Some of the CHLayoutConstraint initializers accept an NSValueTransformer, so you can create arbitrarily complex layout manipulations.

    We used this for constraining and laying out the entire UI, and then doing all of the localization in code (and subsequently calling -sizeToFit, with some modifications). Our UI would just flow into its final layout. It turned out to be extremely convenient. We'd just package up our .strings files, send them off to the translators, and then drop them in to place when we got them back, and our app would instantly be localized for that language.

    CHLayoutManager isn't perfect. It doesn't resolve conflicts, but simply applies constraints in the order they're added. So you can constrain (for example) the MinX of a view 42 different ways, but only the last one will be used. Also, if you constrain the MinX and the MaxX, they'll also be applied in the order they're added and will not end up stretching or shrinking the width. In other words, constraining one attribute of a view will not affect the other attributes. It's compatible with 10.5+ (GC and non). However, due to some changes in Lion, it's unlikely that I'll address the shortcomings.

    Despite these shortcomings, it's an extremely flexible framework, and (IMO) some pretty nifty code. (Plus, I swizzle -[NSView dealloc]! Yay!)


    Update

    Now that AppKit has this same functionality (via NSLayoutConstraint), I recommend using that system instead of CHLayoutManager. It is far more robust.

提交回复
热议问题