如何为 UILabel 指定日语编码?

How to specify Japanese encoding for a UILabel?

当我尝试在 iOS 上的 UILabel 中显示日文字符串时,它使用中文编码而不是日文显示。

这两种编码几乎相同,除了少数特定情况。例如,字符直 (Unicode U+76F4) 在中文(上)与日文(下)中的呈现方式如下:

(更多示例参见here

只有当用户的系统区域设置为 ja-jp(日本)时,日语字符串才能正确呈现,但我希望它在 all 中呈现为日语用户。

有没有办法强制使用日文编码? Android 有 TextView.TextLocale,但我在 [=43= 上没有看到类似的东西] UILabel

(。我将此标记为 Swift/Objective-C,因为虽然我正在寻找 Xamarin.iOS 解决方案,但 API 几乎是相同)

我发现了一个非常 似乎有效的解决方案。然而,没有办法简单地设置标签的区域设置似乎很荒谬,所以如果有人发现我遗漏的东西,请 post 回答。


这个技巧依赖于 Hiragino 字体默认使用日文编码而不是中文编码显示汉字这一事实。但是,对于英文文本,字体看起来很糟糕,所以我必须在每个标签中的每个字符串中搜索日文子字符串,并使用 NSMutableAttributedString 手动更改字体。字体也是 所以我不得不找到另一个解决方法来解决这个问题。

[assembly: ExportRenderer(typeof(Label), typeof(RingotanLabelRenderer))]
namespace MyApp
{
    public class MyLabelRenderer : LabelRenderer
    {
        private readonly UIFont HIRAGINO_FONT = UIFont.FromName("HiraginoSans-W6", 1); // Size gets updated later

        protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            base.OnElementPropertyChanged(sender, e);

            // BUGFIX: Chinese encoding is shown by default. Switch to Hiragino font, which correctly shows Japanese characters
            // Taken from 
            if (Control?.Text != null && e.PropertyName == "Text")
            {
                var kanjiRanges = GetJapaneseRanges(Control.Text).ToList();
                if (kanjiRanges.Count > 0)
                {
                    var font = HIRAGINO_FONT.WithSize((nfloat)Element.FontSize);
                    var attributedString = Control.AttributedText == null
                        ? new NSMutableAttributedString(Control.Text)
                        : new NSMutableAttributedString(Control.AttributedText);

                    // Search through string for all instances of Japanese characters and update the font
                    foreach (var (start, end) in kanjiRanges)
                    {
                        int length = end - start + 1;
                        var range = new NSRange(start, length);
                        attributedString.AddAttribute(UIStringAttributeKey.Font, font, range);

                        // Bugfix: Hiragino font is broken ( so needs to be adjusted upwards
                        // jesus christ Apple
                        attributedString.AddAttribute(UIStringAttributeKey.BaselineOffset, (NSNumber)(Element.FontSize/10), range);
                    }

                    Control.AttributedText = attributedString;
                }
            }
        }

        // Returns all (start,end) ranges in the string which contain only Japanese strings
        private IEnumerable<(int,int)> GetJapaneseRanges(string str)
        {
            for (int i = 0; i < str.Length; i++)
            {
                if (IsJapanese(str[i]))
                {
                    int start = i;
                    while (i < str.Length - 1 && KanjiHelper.IsJapanese(str[i]))
                    {
                        i++;
                    }
                    int end = i;
                    yield return (start, end);
                }
            }
        }

        private static bool IsJapanese(char character)
        {
            // An approximation. See https://github.com/caguiclajmg/WanaKanaSharp/blob/792f45a27d6e543d1b484d6825a9f22a803027fd/WanaKanaSharp/CharacterConstants.cs#L110-L118
            // for a more accurate version
            return character >= '\u3000' && character <= '\u9FFF' 
                || character >= '\uFF00';
        }
    }
}

您只需要为属性字符串指定语言标识符,例如

let label = UILabel()
let text = NSAttributedString(string: "直", attributes: [
    .languageIdentifier: "ja",                            // << this !! 
    .font: UIFont.systemFont(ofSize: 64)
])
label.attributedText = text

测试 Xcode 13.2 / iOS 15.2